Move Webstore URL concepts to //extensions and out
[chromium-blink-merge.git] / chrome / browser / resources / print_preview / previewarea / preview_area.js
blobec764e7132a9f104deb40df93422cf8c4d345302
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() {
6 'use strict';
8 /**
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.
18 * @constructor
19 * @extends {print_preview.Component}
21 function PreviewArea(
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).
27 /**
28 * Used to get the currently selected destination.
29 * @type {!print_preview.DestinationStore}
30 * @private
32 this.destinationStore_ = destinationStore;
34 /**
35 * Used to get information about how the preview should be displayed.
36 * @type {!print_preview.PrintTicketStore}
37 * @private
39 this.printTicketStore_ = printTicketStore;
41 /**
42 * Used to contruct the preview generator.
43 * @type {!print_preview.NativeLayer}
44 * @private
46 this.nativeLayer_ = nativeLayer;
48 /**
49 * Document data model.
50 * @type {!print_preview.DocumentInfo}
51 * @private
53 this.documentInfo_ = documentInfo;
55 /**
56 * Used to read generated page previews.
57 * @type {print_preview.PreviewGenerator}
58 * @private
60 this.previewGenerator_ = null;
62 /**
63 * The embedded pdf plugin object. It's value is null if not yet loaded.
64 * @type {HTMLEmbedElement}
65 * @private
67 this.plugin_ = null;
69 /**
70 * Custom margins component superimposed on the preview plugin.
71 * @type {!print_preview.MarginControlContainer}
72 * @private
74 this.marginControlContainer_ = new print_preview.MarginControlContainer(
75 this.documentInfo_,
76 this.printTicketStore_.marginsType,
77 this.printTicketStore_.customMargins,
78 this.printTicketStore_.measurementSystem);
79 this.addChild(this.marginControlContainer_);
81 /**
82 * Current zoom level as a percentage.
83 * @type {?number}
84 * @private
86 this.zoomLevel_ = null;
88 /**
89 * Current page offset which can be used to calculate scroll amount.
90 * @type {print_preview.Coordinate2d}
91 * @private
93 this.pageOffset_ = null;
95 /**
96 * Whether the plugin has finished reloading.
97 * @type {boolean}
98 * @private
100 this.isPluginReloaded_ = false;
103 * Whether the document preview is ready.
104 * @type {boolean}
105 * @private
107 this.isDocumentReady_ = false;
110 * Timeout object used to display a loading message if the preview is taking
111 * a long time to generate.
112 * @type {?number}
113 * @private
115 this.loadingTimeout_ = null;
118 * Overlay element.
119 * @type {HTMLElement}
120 * @private
122 this.overlayEl_ = null;
125 * The "Open system dialog" button.
126 * @type {HTMLButtonElement}
127 * @private
129 this.openSystemDialogButton_ = null;
133 * Event types dispatched by the preview area.
134 * @enum {string}
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.
156 * @enum {string}
157 * @private
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.
174 * @enum {string}
175 * @private
177 PreviewArea.MessageId_ = {
178 CUSTOM: 'custom',
179 LOADING: 'loading',
180 PREVIEW_FAILED: 'preview-failed'
184 * Enumeration of PDF plugin types for print preview.
185 * @enum {string}
186 * @private
188 PreviewArea.PluginType_ = {
189 // TODO(raymes): Remove all references to the IN_PROCESS plugin once it is
190 // removed.
191 IN_PROCESS: 'in-process',
192 OUT_OF_PROCESS: 'out-of-process',
193 NONE: 'none'
197 * Maps message IDs to the CSS class that contains them.
198 * @type {object.<PreviewArea.MessageId_, string>}
199 * @private
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.
212 * @type {number}
213 * @const
214 * @private
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.
239 if (!this.plugin_ ||
240 !arrayContains([33, 34, 37, 38, 39, 40], e.keyCode) ||
241 e.metaKey || e.altKey || e.shiftKey || e.ctrlKey) {
242 return;
245 // Don't handle the key event for these elements.
246 var tagName = document.activeElement.tagName;
247 if (arrayContains(['INPUT', 'SELECT', 'EMBED'], tagName)) {
248 return;
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
255 // here.
256 var element = e.target;
257 while (element) {
258 if (element.scrollHeight > element.clientHeight ||
259 element.scrollWidth > element.clientWidth) {
260 return;
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);
268 e.preventDefault();
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);
279 /** @override */
280 enterDocument: function() {
281 print_preview.Component.prototype.enterDocument.call(this);
282 this.tracker.add(
283 this.openSystemDialogButton_,
284 'click',
285 this.onOpenSystemDialogButtonClick_.bind(this));
287 this.tracker.add(
288 this.printTicketStore_,
289 print_preview.PrintTicketStore.EventType.INITIALIZE,
290 this.onTicketChange_.bind(this));
291 this.tracker.add(
292 this.printTicketStore_,
293 print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
294 this.onTicketChange_.bind(this));
295 this.tracker.add(
296 this.printTicketStore_,
297 print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
298 this.onTicketChange_.bind(this));
299 this.tracker.add(
300 this.printTicketStore_,
301 print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
302 this.onTicketChange_.bind(this));
304 this.tracker.add(
305 this.printTicketStore_.color,
306 print_preview.ticket_items.TicketItem.EventType.CHANGE,
307 this.onTicketChange_.bind(this));
308 this.tracker.add(
309 this.printTicketStore_.cssBackground,
310 print_preview.ticket_items.TicketItem.EventType.CHANGE,
311 this.onTicketChange_.bind(this));
312 this.tracker.add(
313 this.printTicketStore_.customMargins,
314 print_preview.ticket_items.TicketItem.EventType.CHANGE,
315 this.onTicketChange_.bind(this));
316 this.tracker.add(
317 this.printTicketStore_.fitToPage,
318 print_preview.ticket_items.TicketItem.EventType.CHANGE,
319 this.onTicketChange_.bind(this));
320 this.tracker.add(
321 this.printTicketStore_.headerFooter,
322 print_preview.ticket_items.TicketItem.EventType.CHANGE,
323 this.onTicketChange_.bind(this));
324 this.tracker.add(
325 this.printTicketStore_.landscape,
326 print_preview.ticket_items.TicketItem.EventType.CHANGE,
327 this.onTicketChange_.bind(this));
328 this.tracker.add(
329 this.printTicketStore_.marginsType,
330 print_preview.ticket_items.TicketItem.EventType.CHANGE,
331 this.onTicketChange_.bind(this));
332 this.tracker.add(
333 this.printTicketStore_.pageRange,
334 print_preview.ticket_items.TicketItem.EventType.CHANGE,
335 this.onTicketChange_.bind(this));
336 this.tracker.add(
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_,
346 this.nativeLayer_,
347 this.documentInfo_);
348 this.tracker.add(
349 this.previewGenerator_,
350 print_preview.PreviewGenerator.EventType.PREVIEW_START,
351 this.onPreviewStart_.bind(this));
352 this.tracker.add(
353 this.previewGenerator_,
354 print_preview.PreviewGenerator.EventType.PAGE_READY,
355 this.onPagePreviewReady_.bind(this));
356 this.tracker.add(
357 this.previewGenerator_,
358 print_preview.PreviewGenerator.EventType.FAIL,
359 this.onPreviewGenerationFail_.bind(this));
360 this.tracker.add(
361 this.previewGenerator_,
362 print_preview.PreviewGenerator.EventType.DOCUMENT_READY,
363 this.onDocumentReady_.bind(this));
364 } else {
365 this.showCustomMessage(localStrings.getString('noPlugin'));
369 /** @override */
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;
379 /** @override */
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.
396 * @private
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];
404 var isCompatible =
405 compatObj.onload &&
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 &&
423 compatObj.getWidth;
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
428 // point.
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);
434 if (isCompatible)
435 return PreviewArea.PluginType_.IN_PROCESS;
436 if (isOOPCompatible)
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
444 * message to show.
445 * @param {string=} opt_message Optional message to show that can be used
446 * by some message IDs.
447 * @private
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);
473 // Show overlay.
474 this.overlayEl_.classList.remove(PreviewArea.Classes_.INVISIBLE);
478 * Hides the message overlay.
479 * @private
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.
492 * @private
494 createPlugin_: function(srcUrl) {
495 if (this.plugin_) {
496 console.warn('Pdf preview plugin already created');
497 return;
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);
505 } else {
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
514 // it.
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) {
521 var pageNumbers =
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);
529 } else {
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.
545 * @private
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
558 * event.
559 * @param {number} pageX the x-coordinate of the page relative to the
560 * screen.
561 * @param {number} pageY the y-coordinate of the page relative to the
562 * screen.
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.
566 * @private
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.
579 * @private
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_);
590 } else {
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.
598 * @private
600 onPreviewStart_: function(event) {
601 this.isDocumentReady_ = false;
602 this.isPluginReloaded_ = false;
603 if (!this.plugin_) {
604 this.createPlugin_(event.previewUrl);
605 } else {
606 if (this.pluginType_ == PreviewArea.PluginType_.OUT_OF_PROCESS) {
607 var grayscale = !this.printTicketStore_.color.getValue();
608 var pageNumbers =
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
626 * the new page.
627 * @param {Event} event Contains information about the page preview.
628 * @private
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
636 * to print.
637 * @private
639 onDocumentReady_: function(event) {
640 this.isDocumentReady_ = true;
641 this.dispatchPreviewGenerationDoneIfReady_();
645 * Called when the generation of a preview fails. Shows an error message.
646 * @private
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
661 * has loaded.
662 * @private
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);
683 } else {
684 this.plugin_.fitToHeight();
687 this.hideOverlay_();
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.
696 * @private
698 onPreviewVisualStateChange_: function(pageX,
699 pageY,
700 pageWidth,
701 viewportWidth,
702 viewportHeight) {
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) {
713 return;
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));
746 // Export
747 return {
748 PreviewArea: PreviewArea