1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr
.define('print_preview', function() {
9 * Creates a PreviewArea object. It represents the area where the preview
10 * document is displayed.
11 * @param {!print_preview.DestinationStore} destinationStore Used to get the
12 * currently selected destination.
13 * @param {!print_preview.PrintTicketStore} printTicketStore Used to get
14 * information about how the preview should be displayed.
15 * @param {!print_preview.NativeLayer} nativeLayer Needed to communicate with
16 * Chromium's preview generation system.
17 * @param {!print_preview.DocumentInfo} documentInfo Document data model.
19 * @extends {print_preview.Component}
22 destinationStore
, printTicketStore
, nativeLayer
, documentInfo
) {
23 print_preview
.Component
.call(this);
24 // TODO(rltoscano): Understand the dependencies of printTicketStore needed
25 // here, and add only those here (not the entire print ticket store).
28 * Used to get the currently selected destination.
29 * @type {!print_preview.DestinationStore}
32 this.destinationStore_
= destinationStore
;
35 * Used to get information about how the preview should be displayed.
36 * @type {!print_preview.PrintTicketStore}
39 this.printTicketStore_
= printTicketStore
;
42 * Used to contruct the preview generator.
43 * @type {!print_preview.NativeLayer}
46 this.nativeLayer_
= nativeLayer
;
49 * Document data model.
50 * @type {!print_preview.DocumentInfo}
53 this.documentInfo_
= documentInfo
;
56 * Used to read generated page previews.
57 * @type {print_preview.PreviewGenerator}
60 this.previewGenerator_
= null;
63 * The embedded pdf plugin object. It's value is null if not yet loaded.
64 * @type {HTMLEmbedElement}
70 * Custom margins component superimposed on the preview plugin.
71 * @type {!print_preview.MarginControlContainer}
74 this.marginControlContainer_
= new print_preview
.MarginControlContainer(
76 this.printTicketStore_
.marginsType
,
77 this.printTicketStore_
.customMargins
,
78 this.printTicketStore_
.measurementSystem
);
79 this.addChild(this.marginControlContainer_
);
82 * Current zoom level as a percentage.
86 this.zoomLevel_
= null;
89 * Current page offset which can be used to calculate scroll amount.
90 * @type {print_preview.Coordinate2d}
93 this.pageOffset_
= null;
96 * Whether the plugin has finished reloading.
100 this.isPluginReloaded_
= false;
103 * Whether the document preview is ready.
107 this.isDocumentReady_
= false;
110 * Timeout object used to display a loading message if the preview is taking
111 * a long time to generate.
115 this.loadingTimeout_
= null;
119 * @type {HTMLElement}
122 this.overlayEl_
= null;
125 * The "Open system dialog" button.
126 * @type {HTMLButtonElement}
129 this.openSystemDialogButton_
= null;
133 * Event types dispatched by the preview area.
136 PreviewArea
.EventType
= {
137 // Dispatched when the "Open system dialog" button is clicked.
138 OPEN_SYSTEM_DIALOG_CLICK
:
139 'print_preview.PreviewArea.OPEN_SYSTEM_DIALOG_CLICK',
141 // Dispatched when the document preview is complete.
142 PREVIEW_GENERATION_DONE
:
143 'print_preview.PreviewArea.PREVIEW_GENERATION_DONE',
145 // Dispatched when the document preview failed to be generated.
146 PREVIEW_GENERATION_FAIL
:
147 'print_preview.PreviewArea.PREVIEW_GENERATION_FAIL',
149 // Dispatched when a new document preview is being generated.
150 PREVIEW_GENERATION_IN_PROGRESS
:
151 'print_preview.PreviewArea.PREVIEW_GENERATION_IN_PROGRESS'
155 * CSS classes used by the preview area.
159 PreviewArea
.Classes_
= {
160 COMPATIBILITY_OBJECT
: 'preview-area-compatibility-object',
161 OUT_OF_PROCESS_COMPATIBILITY_OBJECT
:
162 'preview-area-compatibility-object-out-of-process',
163 CUSTOM_MESSAGE_TEXT
: 'preview-area-custom-message-text',
164 MESSAGE
: 'preview-area-message',
165 INVISIBLE
: 'invisible',
166 OPEN_SYSTEM_DIALOG_BUTTON
: 'preview-area-open-system-dialog-button',
167 OPEN_SYSTEM_DIALOG_BUTTON_THROBBER
:
168 'preview-area-open-system-dialog-button-throbber',
169 OVERLAY
: 'preview-area-overlay-layer'
173 * Enumeration of IDs shown in the preview area.
177 PreviewArea
.MessageId_
= {
180 PREVIEW_FAILED
: 'preview-failed'
184 * Enumeration of PDF plugin types for print preview.
188 PreviewArea
.PluginType_
= {
189 // TODO(raymes): Remove all references to the IN_PROCESS plugin once it is
191 IN_PROCESS
: 'in-process',
192 OUT_OF_PROCESS
: 'out-of-process',
197 * Maps message IDs to the CSS class that contains them.
198 * @type {object.<PreviewArea.MessageId_, string>}
201 PreviewArea
.MessageIdClassMap_
= {};
202 PreviewArea
.MessageIdClassMap_
[PreviewArea
.MessageId_
.CUSTOM
] =
203 'preview-area-custom-message';
204 PreviewArea
.MessageIdClassMap_
[PreviewArea
.MessageId_
.LOADING
] =
205 'preview-area-loading-message';
206 PreviewArea
.MessageIdClassMap_
[PreviewArea
.MessageId_
.PREVIEW_FAILED
] =
207 'preview-area-preview-failed-message';
210 * Amount of time in milliseconds to wait after issueing a new preview before
211 * the loading message is shown.
216 PreviewArea
.LOADING_TIMEOUT_
= 200;
218 PreviewArea
.prototype = {
219 __proto__
: print_preview
.Component
.prototype,
222 * Should only be called after calling this.render().
223 * @return {boolean} Whether the preview area has a compatible plugin to
224 * display the print preview in.
226 get hasCompatiblePlugin() {
227 return this.previewGenerator_
!= null;
231 * Processes a keyboard event that could possibly be used to change state of
232 * the preview plugin.
233 * @param {MouseEvent} e Mouse event to process.
235 handleDirectionalKeyEvent: function(e
) {
236 // Make sure the PDF plugin is there.
237 // We only care about: PageUp, PageDown, Left, Up, Right, Down.
238 // If the user is holding a modifier key, ignore.
240 !arrayContains([33, 34, 37, 38, 39, 40], e
.keyCode
) ||
241 e
.metaKey
|| e
.altKey
|| e
.shiftKey
|| e
.ctrlKey
) {
245 // Don't handle the key event for these elements.
246 var tagName
= document
.activeElement
.tagName
;
247 if (arrayContains(['INPUT', 'SELECT', 'EMBED'], tagName
)) {
251 // For the most part, if any div of header was the last clicked element,
252 // then the active element is the body. Starting with the last clicked
253 // element, and work up the DOM tree to see if any element has a
254 // scrollbar. If there exists a scrollbar, do not handle the key event
256 var element
= e
.target
;
258 if (element
.scrollHeight
> element
.clientHeight
||
259 element
.scrollWidth
> element
.clientWidth
) {
262 element
= element
.parentElement
;
265 // No scroll bar anywhere, or the active element is something else, like a
266 // button. Note: buttons have a bigger scrollHeight than clientHeight.
267 this.plugin_
.sendKeyEvent(e
.keyCode
);
272 * Shows a custom message on the preview area's overlay.
273 * @param {string} message Custom message to show.
275 showCustomMessage: function(message
) {
276 this.showMessage_(PreviewArea
.MessageId_
.CUSTOM
, message
);
280 enterDocument: function() {
281 print_preview
.Component
.prototype.enterDocument
.call(this);
283 this.openSystemDialogButton_
,
285 this.onOpenSystemDialogButtonClick_
.bind(this));
288 this.printTicketStore_
,
289 print_preview
.PrintTicketStore
.EventType
.INITIALIZE
,
290 this.onTicketChange_
.bind(this));
292 this.printTicketStore_
,
293 print_preview
.PrintTicketStore
.EventType
.TICKET_CHANGE
,
294 this.onTicketChange_
.bind(this));
296 this.printTicketStore_
,
297 print_preview
.PrintTicketStore
.EventType
.CAPABILITIES_CHANGE
,
298 this.onTicketChange_
.bind(this));
300 this.printTicketStore_
,
301 print_preview
.PrintTicketStore
.EventType
.DOCUMENT_CHANGE
,
302 this.onTicketChange_
.bind(this));
305 this.printTicketStore_
.color
,
306 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
307 this.onTicketChange_
.bind(this));
309 this.printTicketStore_
.cssBackground
,
310 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
311 this.onTicketChange_
.bind(this));
313 this.printTicketStore_
.customMargins
,
314 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
315 this.onTicketChange_
.bind(this));
317 this.printTicketStore_
.fitToPage
,
318 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
319 this.onTicketChange_
.bind(this));
321 this.printTicketStore_
.headerFooter
,
322 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
323 this.onTicketChange_
.bind(this));
325 this.printTicketStore_
.landscape
,
326 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
327 this.onTicketChange_
.bind(this));
329 this.printTicketStore_
.marginsType
,
330 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
331 this.onTicketChange_
.bind(this));
333 this.printTicketStore_
.pageRange
,
334 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
335 this.onTicketChange_
.bind(this));
337 this.printTicketStore_
.selectionOnly
,
338 print_preview
.ticket_items
.TicketItem
.EventType
.CHANGE
,
339 this.onTicketChange_
.bind(this));
341 this.pluginType_
= this.getPluginType_();
342 if (this.pluginType_
!= PreviewArea
.PluginType_
.NONE
) {
343 this.previewGenerator_
= new print_preview
.PreviewGenerator(
344 this.destinationStore_
,
345 this.printTicketStore_
,
349 this.previewGenerator_
,
350 print_preview
.PreviewGenerator
.EventType
.PREVIEW_START
,
351 this.onPreviewStart_
.bind(this));
353 this.previewGenerator_
,
354 print_preview
.PreviewGenerator
.EventType
.PAGE_READY
,
355 this.onPagePreviewReady_
.bind(this));
357 this.previewGenerator_
,
358 print_preview
.PreviewGenerator
.EventType
.FAIL
,
359 this.onPreviewGenerationFail_
.bind(this));
361 this.previewGenerator_
,
362 print_preview
.PreviewGenerator
.EventType
.DOCUMENT_READY
,
363 this.onDocumentReady_
.bind(this));
365 this.showCustomMessage(localStrings
.getString('noPlugin'));
370 exitDocument: function() {
371 print_preview
.Component
.prototype.exitDocument
.call(this);
372 if (this.previewGenerator_
) {
373 this.previewGenerator_
.removeEventListeners();
375 this.overlayEl_
= null;
376 this.openSystemDialogButton_
= null;
380 decorateInternal: function() {
381 this.marginControlContainer_
.decorate(this.getElement());
382 this.overlayEl_
= this.getElement().getElementsByClassName(
383 PreviewArea
.Classes_
.OVERLAY
)[0];
384 this.openSystemDialogButton_
= this.getElement().getElementsByClassName(
385 PreviewArea
.Classes_
.OPEN_SYSTEM_DIALOG_BUTTON
)[0];
389 * Checks to see if a suitable plugin for rendering the preview exists. If
390 * one does not exist, then an error message will be displayed.
391 * @return {string} A string constant indicating whether Chromium has a
392 * plugin for rendering the preview.
393 * PreviewArea.PluginType_.IN_PROCESS for an in-process plugin
394 * PreviewArea.PluginType_.OUT_OF_PROCESS for an out-of-process plugin
395 * PreviewArea.PluginType_.NONE if no plugin is available.
398 getPluginType_: function() {
399 // TODO(raymes): Remove the in-process check after we remove the
400 // in-process plugin. Change this function back to
401 // checkPluginCompatibility_().
402 var compatObj
= this.getElement().getElementsByClassName(
403 PreviewArea
.Classes_
.COMPATIBILITY_OBJECT
)[0];
406 compatObj
.goToPage
&&
407 compatObj
.removePrintButton
&&
408 compatObj
.loadPreviewPage
&&
409 compatObj
.printPreviewPageCount
&&
410 compatObj
.resetPrintPreviewUrl
&&
411 compatObj
.onPluginSizeChanged
&&
412 compatObj
.onScroll
&&
413 compatObj
.pageXOffset
&&
414 compatObj
.pageYOffset
&&
415 compatObj
.setZoomLevel
&&
416 compatObj
.setPageNumbers
&&
417 compatObj
.setPageXOffset
&&
418 compatObj
.setPageYOffset
&&
419 compatObj
.getHorizontalScrollbarThickness
&&
420 compatObj
.getVerticalScrollbarThickness
&&
421 compatObj
.getPageLocationNormalized
&&
422 compatObj
.getHeight
&&
424 compatObj
.parentElement
.removeChild(compatObj
);
426 // TODO(raymes): It's harder to test compatibility of the out of process
427 // plugin because it's asynchronous. We could do a better job at some
429 var oopCompatObj
= this.getElement().getElementsByClassName(
430 PreviewArea
.Classes_
.OUT_OF_PROCESS_COMPATIBILITY_OBJECT
)[0];
431 var isOOPCompatible
= oopCompatObj
.postMessage
;
432 oopCompatObj
.parentElement
.removeChild(oopCompatObj
);
435 return PreviewArea
.PluginType_
.IN_PROCESS
;
437 return PreviewArea
.PluginType_
.OUT_OF_PROCESS
;
438 return PreviewArea
.PluginType_
.NONE
;
442 * Shows a given message on the overlay.
443 * @param {!print_preview.PreviewArea.MessageId_} messageId ID of the
445 * @param {string=} opt_message Optional message to show that can be used
446 * by some message IDs.
449 showMessage_: function(messageId
, opt_message
) {
450 // Hide all messages.
451 var messageEls
= this.getElement().getElementsByClassName(
452 PreviewArea
.Classes_
.MESSAGE
);
453 for (var i
= 0, messageEl
; messageEl
= messageEls
[i
]; i
++) {
454 setIsVisible(messageEl
, false);
456 // Disable jumping animation to conserve cycles.
457 var jumpingDotsEl
= this.getElement().querySelector(
458 '.preview-area-loading-message-jumping-dots');
459 jumpingDotsEl
.classList
.remove('jumping-dots');
461 // Show specific message.
462 if (messageId
== PreviewArea
.MessageId_
.CUSTOM
) {
463 var customMessageTextEl
= this.getElement().getElementsByClassName(
464 PreviewArea
.Classes_
.CUSTOM_MESSAGE_TEXT
)[0];
465 customMessageTextEl
.textContent
= opt_message
;
466 } else if (messageId
== PreviewArea
.MessageId_
.LOADING
) {
467 jumpingDotsEl
.classList
.add('jumping-dots');
469 var messageEl
= this.getElement().getElementsByClassName(
470 PreviewArea
.MessageIdClassMap_
[messageId
])[0];
471 setIsVisible(messageEl
, true);
474 this.overlayEl_
.classList
.remove(PreviewArea
.Classes_
.INVISIBLE
);
478 * Hides the message overlay.
481 hideOverlay_: function() {
482 this.overlayEl_
.classList
.add(PreviewArea
.Classes_
.INVISIBLE
);
483 // Disable jumping animation to conserve cycles.
484 var jumpingDotsEl
= this.getElement().querySelector(
485 '.preview-area-loading-message-jumping-dots');
486 jumpingDotsEl
.classList
.remove('jumping-dots');
490 * Creates a preview plugin and adds it to the DOM.
491 * @param {string} srcUrl Initial URL of the plugin.
494 createPlugin_: function(srcUrl
) {
496 console
.warn('Pdf preview plugin already created');
500 if (this.pluginType_
== PreviewArea
.PluginType_
.IN_PROCESS
) {
501 this.plugin_
= document
.createElement('embed');
502 this.plugin_
.setAttribute(
503 'type', 'application/x-google-chrome-print-preview-pdf');
504 this.plugin_
.setAttribute('src', srcUrl
);
506 this.plugin_
= PDFCreateOutOfProcessPlugin(srcUrl
);
509 this.plugin_
.setAttribute('class', 'preview-area-plugin');
510 this.plugin_
.setAttribute('aria-live', 'polite');
511 this.plugin_
.setAttribute('aria-atomic', 'true');
512 // NOTE: The plugin's 'id' field must be set to 'pdf-viewer' since
513 // chrome/renderer/printing/print_web_view_helper.cc actually references
515 this.plugin_
.setAttribute('id', 'pdf-viewer');
516 this.getChildElement('.preview-area-plugin-wrapper').
517 appendChild(this.plugin_
);
520 if (this.pluginType_
== PreviewArea
.PluginType_
.OUT_OF_PROCESS
) {
522 this.printTicketStore_
.pageRange
.getPageNumberSet().asArray();
523 var grayscale
= !this.printTicketStore_
.color
.getValue();
524 this.plugin_
.setLoadCallback(this.onPluginLoad_
.bind(this));
525 this.plugin_
.setViewportChangedCallback(
526 this.onPreviewVisualStateChange_
.bind(this));
527 this.plugin_
.resetPrintPreviewMode(srcUrl
, grayscale
, pageNumbers
,
528 this.documentInfo_
.isModifiable
);
530 global
['onPreviewPluginLoad'] = this.onPluginLoad_
.bind(this);
531 this.plugin_
.onload('onPreviewPluginLoad()');
533 global
['onPreviewPluginVisualStateChange'] =
534 this.onPreviewVisualStateChange_
.bind(this);
535 this.plugin_
.onScroll('onPreviewPluginVisualStateChange()');
536 this.plugin_
.onPluginSizeChanged('onPreviewPluginVisualStateChange()');
538 this.plugin_
.removePrintButton();
539 this.plugin_
.grayscale(!this.printTicketStore_
.color
.getValue());
544 * Dispatches a PREVIEW_GENERATION_DONE event if all conditions are met.
547 dispatchPreviewGenerationDoneIfReady_: function() {
548 if (this.isDocumentReady_
&& this.isPluginReloaded_
) {
549 cr
.dispatchSimpleEvent(
550 this, PreviewArea
.EventType
.PREVIEW_GENERATION_DONE
);
551 this.marginControlContainer_
.showMarginControlsIfNeeded();
556 * Called when the open-system-dialog button is clicked. Disables the
557 * button, shows the throbber, and dispatches the OPEN_SYSTEM_DIALOG_CLICK
559 * @param {number} pageX the x-coordinate of the page relative to the
561 * @param {number} pageY the y-coordinate of the page relative to the
563 * @param {number} pageWidth the width of the page on the screen.
564 * @param {number} viewportWidth the width of the viewport.
565 * @param {number} viewportHeight the height of the viewport.
568 onOpenSystemDialogButtonClick_: function() {
569 this.openSystemDialogButton_
.disabled
= true;
570 var openSystemDialogThrobber
= this.getElement().getElementsByClassName(
571 PreviewArea
.Classes_
.OPEN_SYSTEM_DIALOG_BUTTON_THROBBER
)[0];
572 setIsVisible(openSystemDialogThrobber
, true);
573 cr
.dispatchSimpleEvent(
574 this, PreviewArea
.EventType
.OPEN_SYSTEM_DIALOG_CLICK
);
578 * Called when the print ticket changes. Updates the preview.
581 onTicketChange_: function() {
582 if (this.previewGenerator_
&& this.previewGenerator_
.requestPreview()) {
583 cr
.dispatchSimpleEvent(
584 this, PreviewArea
.EventType
.PREVIEW_GENERATION_IN_PROGRESS
);
585 if (this.loadingTimeout_
== null) {
586 this.loadingTimeout_
= setTimeout(
587 this.showMessage_
.bind(this, PreviewArea
.MessageId_
.LOADING
),
588 PreviewArea
.LOADING_TIMEOUT_
);
591 this.marginControlContainer_
.showMarginControlsIfNeeded();
596 * Called when the preview generator begins loading the preview.
597 * @param {Event} Contains the URL to initialize the plugin to.
600 onPreviewStart_: function(event
) {
601 this.isDocumentReady_
= false;
602 this.isPluginReloaded_
= false;
604 this.createPlugin_(event
.previewUrl
);
606 if (this.pluginType_
== PreviewArea
.PluginType_
.OUT_OF_PROCESS
) {
607 var grayscale
= !this.printTicketStore_
.color
.getValue();
609 this.printTicketStore_
.pageRange
.getPageNumberSet().asArray();
610 var url
= event
.previewUrl
;
611 this.plugin_
.resetPrintPreviewMode(url
, grayscale
, pageNumbers
,
612 this.documentInfo_
.isModifiable
);
613 } else if (this.pluginType_
== PreviewArea
.PluginType_
.IN_PROCESS
) {
614 this.plugin_
.goToPage('0');
615 this.plugin_
.resetPrintPreviewUrl(event
.previewUrl
);
616 this.plugin_
.reload();
617 this.plugin_
.grayscale(!this.printTicketStore_
.color
.getValue());
620 cr
.dispatchSimpleEvent(
621 this, PreviewArea
.EventType
.PREVIEW_GENERATION_IN_PROGRESS
);
625 * Called when a page preview has been generated. Updates the plugin with
627 * @param {Event} event Contains information about the page preview.
630 onPagePreviewReady_: function(event
) {
631 this.plugin_
.loadPreviewPage(event
.previewUrl
, event
.previewIndex
);
635 * Called when the preview generation is complete and the document is ready
639 onDocumentReady_: function(event
) {
640 this.isDocumentReady_
= true;
641 this.dispatchPreviewGenerationDoneIfReady_();
645 * Called when the generation of a preview fails. Shows an error message.
648 onPreviewGenerationFail_: function() {
649 if (this.loadingTimeout_
) {
650 clearTimeout(this.loadingTimeout_
);
651 this.loadingTimeout_
= null;
653 this.showMessage_(PreviewArea
.MessageId_
.PREVIEW_FAILED
);
654 cr
.dispatchSimpleEvent(
655 this, PreviewArea
.EventType
.PREVIEW_GENERATION_FAIL
);
659 * Called when the plugin loads. This is a consequence of calling
660 * plugin.reload(). Certain plugin state can only be set after the plugin
664 onPluginLoad_: function() {
665 if (this.loadingTimeout_
) {
666 clearTimeout(this.loadingTimeout_
);
667 this.loadingTimeout_
= null;
670 if (this.pluginType_
== PreviewArea
.PluginType_
.IN_PROCESS
) {
671 // Setting the plugin's page count can only be called after the plugin
672 // is loaded and the document must be modifiable.
673 if (this.documentInfo_
.isModifiable
) {
674 this.plugin_
.printPreviewPageCount(
675 this.printTicketStore_
.pageRange
.getPageNumberSet().size
);
677 this.plugin_
.setPageNumbers(JSON
.stringify(
678 this.printTicketStore_
.pageRange
.getPageNumberSet().asArray()));
679 if (this.zoomLevel_
!= null && this.pageOffset_
!= null) {
680 this.plugin_
.setZoomLevel(this.zoomLevel_
);
681 this.plugin_
.setPageXOffset(this.pageOffset_
.x
);
682 this.plugin_
.setPageYOffset(this.pageOffset_
.y
);
684 this.plugin_
.fitToHeight();
688 this.isPluginReloaded_
= true;
689 this.dispatchPreviewGenerationDoneIfReady_();
693 * Called when the preview plugin's visual state has changed. This is a
694 * consequence of scrolling or zooming the plugin. Updates the custom
695 * margins component if shown.
698 onPreviewVisualStateChange_: function(pageX
,
703 if (this.pluginType_
== PreviewArea
.PluginType_
.IN_PROCESS
) {
704 if (this.isPluginReloaded_
) {
705 this.zoomLevel_
= this.plugin_
.getZoomLevel();
706 this.pageOffset_
= new print_preview
.Coordinate2d(
707 this.plugin_
.pageXOffset(), this.plugin_
.pageYOffset());
710 var pageLocationNormalizedStr
=
711 this.plugin_
.getPageLocationNormalized();
712 if (!pageLocationNormalizedStr
) {
715 var normalized
= pageLocationNormalizedStr
.split(';');
716 var pluginWidth
= this.plugin_
.getWidth();
717 var pluginHeight
= this.plugin_
.getHeight();
718 var verticalScrollbarThickness
=
719 this.plugin_
.getVerticalScrollbarThickness();
720 var horizontalScrollbarThickness
=
721 this.plugin_
.getHorizontalScrollbarThickness();
723 var translationTransform
= new print_preview
.Coordinate2d(
724 parseFloat(normalized
[0]) * pluginWidth
,
725 parseFloat(normalized
[1]) * pluginHeight
);
726 this.marginControlContainer_
.updateTranslationTransform(
727 translationTransform
);
728 var pageWidthInPixels
= parseFloat(normalized
[2]) * pluginWidth
;
729 this.marginControlContainer_
.updateScaleTransform(
730 pageWidthInPixels
/ this.documentInfo_
.pageSize
.width
);
731 this.marginControlContainer_
.updateClippingMask(
732 new print_preview
.Size(
733 pluginWidth
- verticalScrollbarThickness
,
734 pluginHeight
- horizontalScrollbarThickness
));
735 } else if (this.pluginType_
== PreviewArea
.PluginType_
.OUT_OF_PROCESS
) {
736 this.marginControlContainer_
.updateTranslationTransform(
737 new print_preview
.Coordinate2d(pageX
, pageY
));
738 this.marginControlContainer_
.updateScaleTransform(
739 pageWidth
/ this.documentInfo_
.pageSize
.width
);
740 this.marginControlContainer_
.updateClippingMask(
741 new print_preview
.Size(viewportWidth
, viewportHeight
));
748 PreviewArea
: PreviewArea