OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 <include src="../../../../ui/webui/resources/js/util.js"> | 7 <include src="../../../../ui/webui/resources/js/util.js"> |
| 8 <include src="pdf_scripting_api.js"> |
8 <include src="viewport.js"> | 9 <include src="viewport.js"> |
9 <include src="pdf_scripting_api.js"> | |
10 | 10 |
11 /** | 11 /** |
12 * @return {number} Width of a scrollbar in pixels | 12 * @return {number} Width of a scrollbar in pixels |
13 */ | 13 */ |
14 function getScrollbarWidth() { | 14 function getScrollbarWidth() { |
15 var div = document.createElement('div'); | 15 var div = document.createElement('div'); |
16 div.style.visibility = 'hidden'; | 16 div.style.visibility = 'hidden'; |
17 div.style.overflow = 'scroll'; | 17 div.style.overflow = 'scroll'; |
18 div.style.width = '50px'; | 18 div.style.width = '50px'; |
19 div.style.height = '50px'; | 19 div.style.height = '50px'; |
(...skipping 27 matching lines...) Expand all Loading... |
47 this.viewportChangedCallback_.bind(this), | 47 this.viewportChangedCallback_.bind(this), |
48 getScrollbarWidth()); | 48 getScrollbarWidth()); |
49 | 49 |
50 // Create the plugin object dynamically so we can set its src. The plugin | 50 // Create the plugin object dynamically so we can set its src. The plugin |
51 // element is sized to fill the entire window and is set to be fixed | 51 // element is sized to fill the entire window and is set to be fixed |
52 // positioning, acting as a viewport. The plugin renders into this viewport | 52 // positioning, acting as a viewport. The plugin renders into this viewport |
53 // according to the scroll position of the window. | 53 // according to the scroll position of the window. |
54 this.plugin_ = document.createElement('object'); | 54 this.plugin_ = document.createElement('object'); |
55 this.plugin_.id = 'plugin'; | 55 this.plugin_.id = 'plugin'; |
56 this.plugin_.type = 'application/x-google-chrome-pdf'; | 56 this.plugin_.type = 'application/x-google-chrome-pdf'; |
57 this.plugin_.addEventListener('message', this.handleMessage_.bind(this), | 57 this.plugin_.addEventListener('message', this.handlePluginMessage_.bind(this), |
58 false); | 58 false); |
59 | 59 |
| 60 // Handle scripting messages from outside the extension that wish to interact |
| 61 // with it. We also send a message indicating that extension has loaded and |
| 62 // is ready to receive messages. |
| 63 window.addEventListener('message', this.handleScriptingMessage_.bind(this), |
| 64 false); |
| 65 this.sendScriptingMessage_({type: 'readyToReceive'}); |
| 66 |
60 // If the viewer is started from a MIME type request, there will be a | 67 // If the viewer is started from a MIME type request, there will be a |
61 // background page and stream details object with the details of the request. | 68 // background page and stream details object with the details of the request. |
62 // Otherwise, we take the query string of the URL to indicate the URL of the | 69 // Otherwise, we take the query string of the URL to indicate the URL of the |
63 // PDF to load. This is used for print preview in particular. | 70 // PDF to load. This is used for print preview in particular. |
64 var streamDetails; | 71 var streamDetails; |
65 if (chrome.extension.getBackgroundPage && | 72 if (chrome.extension.getBackgroundPage && |
66 chrome.extension.getBackgroundPage()) { | 73 chrome.extension.getBackgroundPage()) { |
67 streamDetails = chrome.extension.getBackgroundPage().popStreamDetails(); | 74 streamDetails = chrome.extension.getBackgroundPage().popStreamDetails(); |
68 } | 75 } |
69 | 76 |
70 if (!streamDetails) { | 77 if (!streamDetails) { |
71 // The URL of this page will be of the form | 78 // The URL of this page will be of the form |
72 // "chrome-extension://<extension id>?<pdf url>". We pull out the <pdf url> | 79 // "chrome-extension://<extension id>?<pdf url>". We pull out the <pdf url> |
73 // part here. | 80 // part here. |
74 var url = window.location.search.substring(1); | 81 var url = window.location.search.substring(1); |
75 streamDetails = { | 82 streamDetails = { |
76 streamUrl: url, | 83 streamUrl: url, |
77 originalUrl: url | 84 originalUrl: url |
78 }; | 85 }; |
79 } | 86 } |
80 | 87 |
81 this.plugin_.setAttribute('src', streamDetails.streamUrl); | 88 this.plugin_.setAttribute('src', streamDetails.streamUrl); |
82 document.body.appendChild(this.plugin_); | 89 document.body.appendChild(this.plugin_); |
83 | 90 |
84 this.messagingHost_ = new PDFMessagingHost(window, this); | |
85 | |
86 this.setupEventListeners_(streamDetails); | 91 this.setupEventListeners_(streamDetails); |
87 } | 92 } |
88 | 93 |
89 PDFViewer.prototype = { | 94 PDFViewer.prototype = { |
90 /** | 95 /** |
91 * @private | 96 * @private |
92 * Sets up event listeners for key shortcuts and also the UI buttons. | 97 * Sets up event listeners for key shortcuts and also the UI buttons. |
93 * @param {Object} streamDetails the details of the original HTTP request for | 98 * @param {Object} streamDetails the details of the original HTTP request for |
94 * the PDF. | 99 * the PDF. |
95 */ | 100 */ |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 this.sizer_.style.display = 'none'; | 206 this.sizer_.style.display = 'none'; |
202 this.toolbar_.style.visibility = 'hidden'; | 207 this.toolbar_.style.visibility = 'hidden'; |
203 if (this.passwordScreen_.active) { | 208 if (this.passwordScreen_.active) { |
204 this.passwordScreen_.deny(); | 209 this.passwordScreen_.deny(); |
205 this.passwordScreen_.active = false; | 210 this.passwordScreen_.active = false; |
206 } | 211 } |
207 } else if (progress == 100) { | 212 } else if (progress == 100) { |
208 // Document load complete. | 213 // Document load complete. |
209 var loadEvent = new Event('pdfload'); | 214 var loadEvent = new Event('pdfload'); |
210 window.dispatchEvent(loadEvent); | 215 window.dispatchEvent(loadEvent); |
211 // TODO(raymes): Replace this and other callbacks with events. | 216 this.sendScriptingMessage_({ |
212 this.messagingHost_.documentLoaded(); | 217 type: 'documentLoaded' |
| 218 }); |
213 if (this.lastViewportPosition_) | 219 if (this.lastViewportPosition_) |
214 this.viewport_.position = this.lastViewportPosition_; | 220 this.viewport_.position = this.lastViewportPosition_; |
215 } | 221 } |
216 }, | 222 }, |
217 | 223 |
218 /** | 224 /** |
219 * @private | 225 * @private |
220 * An event handler for handling password-submitted events. These are fired | 226 * An event handler for handling password-submitted events. These are fired |
221 * when an event is entered into the password screen. | 227 * when an event is entered into the password screen. |
222 * @param {Object} event a password-submitted event. | 228 * @param {Object} event a password-submitted event. |
223 */ | 229 */ |
224 onPasswordSubmitted_: function(event) { | 230 onPasswordSubmitted_: function(event) { |
225 this.plugin_.postMessage({ | 231 this.plugin_.postMessage({ |
226 type: 'getPasswordComplete', | 232 type: 'getPasswordComplete', |
227 password: event.detail.password | 233 password: event.detail.password |
228 }); | 234 }); |
229 }, | 235 }, |
230 | 236 |
231 /** | 237 /** |
232 * @private | 238 * @private |
233 * An event handler for handling message events received from the plugin. | 239 * An event handler for handling message events received from the plugin. |
234 * @param {MessageObject} message a message event. | 240 * @param {MessageObject} message a message event. |
235 */ | 241 */ |
236 handleMessage_: function(message) { | 242 handlePluginMessage_: function(message) { |
237 switch (message.data.type.toString()) { | 243 switch (message.data.type.toString()) { |
238 case 'documentDimensions': | 244 case 'documentDimensions': |
239 this.documentDimensions_ = message.data; | 245 this.documentDimensions_ = message.data; |
240 this.viewport_.setDocumentDimensions(this.documentDimensions_); | 246 this.viewport_.setDocumentDimensions(this.documentDimensions_); |
241 this.toolbar_.style.visibility = 'visible'; | 247 this.toolbar_.style.visibility = 'visible'; |
242 // If we received the document dimensions, the password was good so we | 248 // If we received the document dimensions, the password was good so we |
243 // can dismiss the password screen. | 249 // can dismiss the password screen. |
244 if (this.passwordScreen_.active) | 250 if (this.passwordScreen_.active) |
245 this.passwordScreen_.accept(); | 251 this.passwordScreen_.accept(); |
246 | 252 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 | 303 |
298 var hasScrollbars = this.viewport_.documentHasScrollbars(); | 304 var hasScrollbars = this.viewport_.documentHasScrollbars(); |
299 var scrollbarWidth = this.viewport_.scrollbarWidth; | 305 var scrollbarWidth = this.viewport_.scrollbarWidth; |
300 // Offset the toolbar position so that it doesn't move if scrollbars appear. | 306 // Offset the toolbar position so that it doesn't move if scrollbars appear. |
301 var toolbarRight = hasScrollbars.vertical ? 0 : scrollbarWidth; | 307 var toolbarRight = hasScrollbars.vertical ? 0 : scrollbarWidth; |
302 var toolbarBottom = hasScrollbars.horizontal ? 0 : scrollbarWidth; | 308 var toolbarBottom = hasScrollbars.horizontal ? 0 : scrollbarWidth; |
303 this.toolbar_.style.right = toolbarRight + 'px'; | 309 this.toolbar_.style.right = toolbarRight + 'px'; |
304 this.toolbar_.style.bottom = toolbarBottom + 'px'; | 310 this.toolbar_.style.bottom = toolbarBottom + 'px'; |
305 | 311 |
306 // Update the page indicator. | 312 // Update the page indicator. |
307 this.pageIndicator_.index = this.viewport_.getMostVisiblePage(); | 313 var visiblePage = this.viewport_.getMostVisiblePage(); |
| 314 this.pageIndicator_.index = visiblePage; |
308 if (this.documentDimensions_.pageDimensions.length > 1 && | 315 if (this.documentDimensions_.pageDimensions.length > 1 && |
309 hasScrollbars.vertical) { | 316 hasScrollbars.vertical) { |
310 this.pageIndicator_.style.visibility = 'visible'; | 317 this.pageIndicator_.style.visibility = 'visible'; |
311 } else { | 318 } else { |
312 this.pageIndicator_.style.visibility = 'hidden'; | 319 this.pageIndicator_.style.visibility = 'hidden'; |
313 } | 320 } |
314 | 321 |
315 this.messagingHost_.viewportChanged(); | |
316 | |
317 var position = this.viewport_.position; | 322 var position = this.viewport_.position; |
318 var zoom = this.viewport_.zoom; | 323 var zoom = this.viewport_.zoom; |
319 // Notify the plugin of the viewport change. | 324 // Notify the plugin of the viewport change. |
320 this.plugin_.postMessage({ | 325 this.plugin_.postMessage({ |
321 type: 'viewport', | 326 type: 'viewport', |
322 zoom: zoom, | 327 zoom: zoom, |
323 xOffset: position.x, | 328 xOffset: position.x, |
324 yOffset: position.y | 329 yOffset: position.y |
325 }); | 330 }); |
| 331 |
| 332 var visiblePageDimensions = this.viewport_.getPageScreenRect(visiblePage); |
| 333 var size = this.viewport_.size; |
| 334 this.sendScriptingMessage_({ |
| 335 type: 'viewport', |
| 336 pageX: visiblePageDimensions.x, |
| 337 pageY: visiblePageDimensions.y, |
| 338 pageWidth: visiblePageDimensions.width, |
| 339 viewportWidth: size.width, |
| 340 viewportHeight: size.height, |
| 341 }); |
326 }, | 342 }, |
327 | 343 |
328 /** | 344 /** |
329 * Resets the viewer into print preview mode, which is used for Chrome print | 345 * @private |
330 * preview. | 346 * Handle a scripting message from outside the extension (typically sent by |
331 * @param {string} url the url of the pdf to load. | 347 * PDFScriptingAPI in a page containing the extension) to interact with the |
332 * @param {boolean} grayscale true if the pdf should be displayed in | 348 * plugin. |
333 * grayscale, false otherwise. | 349 * @param {MessageObject} message the message to handle. |
334 * @param {Array.<number>} pageNumbers an array of the number to label each | |
335 * page in the document. | |
336 * @param {boolean} modifiable whether the PDF is modifiable or not. | |
337 */ | 350 */ |
338 resetPrintPreviewMode: function(url, | 351 handleScriptingMessage_: function(message) { |
339 grayscale, | 352 switch (message.data.type.toString()) { |
340 pageNumbers, | 353 case 'resetPrintPreviewMode': |
341 modifiable) { | 354 if (!this.inPrintPreviewMode_) { |
342 if (!this.inPrintPreviewMode_) { | 355 this.inPrintPreviewMode_ = true; |
343 this.inPrintPreviewMode_ = true; | 356 this.viewport_.fitToPage(); |
344 this.viewport_.fitToPage(); | 357 } |
| 358 |
| 359 // Stash the scroll location so that it can be restored when the new |
| 360 // document is loaded. |
| 361 this.lastViewportPosition_ = this.viewport_.position; |
| 362 |
| 363 // TODO(raymes): Disable these properly in the plugin. |
| 364 var printButton = $('print-button'); |
| 365 if (printButton) |
| 366 printButton.parentNode.removeChild(printButton); |
| 367 var saveButton = $('save-button'); |
| 368 if (saveButton) |
| 369 saveButton.parentNode.removeChild(saveButton); |
| 370 |
| 371 this.pageIndicator_.pageLabels = message.data.pageNumbers; |
| 372 |
| 373 this.plugin_.postMessage({ |
| 374 type: 'resetPrintPreviewMode', |
| 375 url: message.data.url, |
| 376 grayscale: message.data.grayscale, |
| 377 // If the PDF isn't modifiable we send 0 as the page count so that no |
| 378 // blank placeholder pages get appended to the PDF. |
| 379 pageCount: (message.data.modifiable ? |
| 380 message.data.pageNumbers.length : 0) |
| 381 }); |
| 382 break; |
| 383 case 'loadPreviewPage': |
| 384 this.plugin_.postMessage(message.data); |
| 385 break; |
345 } | 386 } |
346 | 387 |
347 // Stash the scroll location so that it can be restored when the new | |
348 // document is loaded. | |
349 this.lastViewportPosition_ = this.viewport_.position; | |
350 | |
351 // TODO(raymes): Disable these properly in the plugin. | |
352 var printButton = $('print-button'); | |
353 if (printButton) | |
354 printButton.parentNode.removeChild(printButton); | |
355 var saveButton = $('save-button'); | |
356 if (saveButton) | |
357 saveButton.parentNode.removeChild(saveButton); | |
358 | |
359 this.pageIndicator_.pageLabels = pageNumbers; | |
360 | |
361 this.plugin_.postMessage({ | |
362 type: 'resetPrintPreviewMode', | |
363 url: url, | |
364 grayscale: grayscale, | |
365 // If the PDF isn't modifiable we send 0 as the page count so that no | |
366 // blank placeholder pages get appended to the PDF. | |
367 pageCount: (modifiable ? pageNumbers.length : 0) | |
368 }); | |
369 }, | 388 }, |
370 | 389 |
371 /** | 390 /** |
372 * Load a page into the document while in print preview mode. | 391 * @private |
373 * @param {string} url the url of the pdf page to load. | 392 * Send a scripting message outside the extension (typically to |
374 * @param {number} index the index of the page to load. | 393 * PDFScriptingAPI in a page containing the extension). |
| 394 * @param {Object} message the message to send. |
375 */ | 395 */ |
376 loadPreviewPage: function(url, index) { | 396 sendScriptingMessage_: function(message) { |
377 this.plugin_.postMessage({ | 397 window.parent.postMessage(message, '*'); |
378 type: 'loadPreviewPage', | |
379 url: url, | |
380 index: index | |
381 }); | |
382 }, | 398 }, |
383 | 399 |
384 /** | 400 /** |
385 * @type {Viewport} the viewport of the PDF viewer. | 401 * @type {Viewport} the viewport of the PDF viewer. |
386 */ | 402 */ |
387 get viewport() { | 403 get viewport() { |
388 return this.viewport_; | 404 return this.viewport_; |
389 } | 405 } |
390 }; | 406 }; |
391 | 407 |
392 var viewer = new PDFViewer(); | 408 var viewer = new PDFViewer(); |
OLD | NEW |