Home | History | Annotate | Download | only in print_preview
      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.
      4 
      5 cr.define('print_preview', function() {
      6   'use strict';
      7 
      8   /**
      9    * An interface to the native Chromium printing system layer.
     10    * @constructor
     11    * @extends {cr.EventTarget}
     12    */
     13   function NativeLayer() {
     14     cr.EventTarget.call(this);
     15 
     16     // Bind global handlers
     17     global['setInitialSettings'] = this.onSetInitialSettings_.bind(this);
     18     global['setUseCloudPrint'] = this.onSetUseCloudPrint_.bind(this);
     19     global['setPrinters'] = this.onSetPrinters_.bind(this);
     20     global['updateWithPrinterCapabilities'] =
     21         this.onUpdateWithPrinterCapabilities_.bind(this);
     22     global['failedToGetPrinterCapabilities'] =
     23         this.onFailedToGetPrinterCapabilities_.bind(this);
     24     global['failedToGetPrivetPrinterCapabilities'] =
     25       this.onFailedToGetPrivetPrinterCapabilities_.bind(this);
     26     global['reloadPrintersList'] = this.onReloadPrintersList_.bind(this);
     27     global['printToCloud'] = this.onPrintToCloud_.bind(this);
     28     global['fileSelectionCancelled'] =
     29         this.onFileSelectionCancelled_.bind(this);
     30     global['fileSelectionCompleted'] =
     31         this.onFileSelectionCompleted_.bind(this);
     32     global['printPreviewFailed'] = this.onPrintPreviewFailed_.bind(this);
     33     global['invalidPrinterSettings'] =
     34         this.onInvalidPrinterSettings_.bind(this);
     35     global['onDidGetDefaultPageLayout'] =
     36         this.onDidGetDefaultPageLayout_.bind(this);
     37     global['onDidGetPreviewPageCount'] =
     38         this.onDidGetPreviewPageCount_.bind(this);
     39     global['onDidPreviewPage'] = this.onDidPreviewPage_.bind(this);
     40     global['updatePrintPreview'] = this.onUpdatePrintPreview_.bind(this);
     41     global['printScalingDisabledForSourcePDF'] =
     42         this.onPrintScalingDisabledForSourcePDF_.bind(this);
     43     global['onDidGetAccessToken'] = this.onDidGetAccessToken_.bind(this);
     44     global['autoCancelForTesting'] = this.autoCancelForTesting_.bind(this);
     45     global['onPrivetPrinterChanged'] = this.onPrivetPrinterChanged_.bind(this);
     46     global['onPrivetPrinterSearchDone'] =
     47       this.onPrivetPrinterSearchDone_.bind(this);
     48     global['onPrivetCapabilitiesSet'] =
     49       this.onPrivetCapabilitiesSet_.bind(this);
     50     global['onPrivetPrintFailed'] = this.onPrivetPrintFailed_.bind(this);
     51   };
     52 
     53   /**
     54    * Event types dispatched from the Chromium native layer.
     55    * @enum {string}
     56    * @const
     57    */
     58   NativeLayer.EventType = {
     59     ACCESS_TOKEN_READY: 'print_preview.NativeLayer.ACCESS_TOKEN_READY',
     60     CAPABILITIES_SET: 'print_preview.NativeLayer.CAPABILITIES_SET',
     61     CLOUD_PRINT_ENABLE: 'print_preview.NativeLayer.CLOUD_PRINT_ENABLE',
     62     DESTINATIONS_RELOAD: 'print_preview.NativeLayer.DESTINATIONS_RELOAD',
     63     DISABLE_SCALING: 'print_preview.NativeLayer.DISABLE_SCALING',
     64     FILE_SELECTION_CANCEL: 'print_preview.NativeLayer.FILE_SELECTION_CANCEL',
     65     FILE_SELECTION_COMPLETE:
     66         'print_preview.NativeLayer.FILE_SELECTION_COMPLETE',
     67     GET_CAPABILITIES_FAIL: 'print_preview.NativeLayer.GET_CAPABILITIES_FAIL',
     68     INITIAL_SETTINGS_SET: 'print_preview.NativeLayer.INITIAL_SETTINGS_SET',
     69     LOCAL_DESTINATIONS_SET: 'print_preview.NativeLayer.LOCAL_DESTINATIONS_SET',
     70     PAGE_COUNT_READY: 'print_preview.NativeLayer.PAGE_COUNT_READY',
     71     PAGE_LAYOUT_READY: 'print_preview.NativeLayer.PAGE_LAYOUT_READY',
     72     PAGE_PREVIEW_READY: 'print_preview.NativeLayer.PAGE_PREVIEW_READY',
     73     PREVIEW_GENERATION_DONE:
     74         'print_preview.NativeLayer.PREVIEW_GENERATION_DONE',
     75     PREVIEW_GENERATION_FAIL:
     76         'print_preview.NativeLayer.PREVIEW_GENERATION_FAIL',
     77     PRINT_TO_CLOUD: 'print_preview.NativeLayer.PRINT_TO_CLOUD',
     78     SETTINGS_INVALID: 'print_preview.NativeLayer.SETTINGS_INVALID',
     79     PRIVET_PRINTER_CHANGED: 'print_preview.NativeLayer.PRIVET_PRINTER_CHANGED',
     80     PRIVET_PRINTER_SEARCH_DONE:
     81         'print_preview.NativeLayer.PRIVET_PRINTER_SEARCH_DONE',
     82     PRIVET_CAPABILITIES_SET:
     83         'print_preview.NativeLayer.PRIVET_CAPABILITIES_SET',
     84     PRIVET_PRINT_FAILED: 'print_preview.NativeLayer.PRIVET_PRINT_FAILED'
     85   };
     86 
     87   /**
     88    * Constant values matching printing::DuplexMode enum.
     89    * @enum {number}
     90    */
     91   NativeLayer.DuplexMode = {
     92     SIMPLEX: 0,
     93     LONG_EDGE: 1,
     94     UNKNOWN_DUPLEX_MODE: -1
     95   };
     96 
     97   /**
     98    * Enumeration of color modes used by Chromium.
     99    * @enum {number}
    100    * @private
    101    */
    102   NativeLayer.ColorMode_ = {
    103     GRAY: 1,
    104     COLOR: 2
    105   };
    106 
    107   /**
    108    * Version of the serialized state of the print preview.
    109    * @type {number}
    110    * @const
    111    * @private
    112    */
    113   NativeLayer.SERIALIZED_STATE_VERSION_ = 1;
    114 
    115   NativeLayer.prototype = {
    116     __proto__: cr.EventTarget.prototype,
    117 
    118     /**
    119      * Requests access token for cloud print requests.
    120      * @param {string} authType type of access token.
    121      */
    122     startGetAccessToken: function(authType) {
    123       chrome.send('getAccessToken', [authType]);
    124     },
    125 
    126     /** Gets the initial settings to initialize the print preview with. */
    127     startGetInitialSettings: function() {
    128       chrome.send('getInitialSettings');
    129     },
    130 
    131     /**
    132      * Requests the system's local print destinations. A LOCAL_DESTINATIONS_SET
    133      * event will be dispatched in response.
    134      */
    135     startGetLocalDestinations: function() {
    136       chrome.send('getPrinters');
    137     },
    138 
    139     /**
    140      * Requests the network's privet print destinations. A number of
    141      * PRIVET_PRINTER_CHANGED events will be fired in response, followed by a
    142      * PRIVET_SEARCH_ENDED.
    143      */
    144     startGetPrivetDestinations: function() {
    145       chrome.send('getPrivetPrinters');
    146     },
    147 
    148     /**
    149      * Requests the privet destination's printing capabilities. A
    150      * PRIVET_CAPABILITIES_SET event will be dispatched in response.
    151      * @param {string} destinationId ID of the destination.
    152      */
    153     startGetPrivetDestinationCapabilities: function(destinationId) {
    154       chrome.send('getPrivetPrinterCapabilities', [destinationId]);
    155     },
    156 
    157     /**
    158      * Requests the destination's printing capabilities. A CAPABILITIES_SET
    159      * event will be dispatched in response.
    160      * @param {string} destinationId ID of the destination.
    161      */
    162     startGetLocalDestinationCapabilities: function(destinationId) {
    163       chrome.send('getPrinterCapabilities', [destinationId]);
    164     },
    165 
    166     /**
    167      * Requests that a preview be generated. The following events may be
    168      * dispatched in response:
    169      *   - PAGE_COUNT_READY
    170      *   - PAGE_LAYOUT_READY
    171      *   - PAGE_PREVIEW_READY
    172      *   - PREVIEW_GENERATION_DONE
    173      *   - PREVIEW_GENERATION_FAIL
    174      * @param {print_preview.Destination} destination Destination to print to.
    175      * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
    176      *     state of the print ticket.
    177      * @param {!print_preview.DocumentInfo} documentInfo Document data model.
    178      * @param {number} ID of the preview request.
    179      */
    180     startGetPreview: function(
    181         destination, printTicketStore, documentInfo, requestId) {
    182       assert(printTicketStore.isTicketValidForPreview(),
    183              'Trying to generate preview when ticket is not valid');
    184 
    185       var ticket = {
    186         'pageRange': printTicketStore.pageRange.getDocumentPageRanges(),
    187         'landscape': printTicketStore.landscape.getValue(),
    188         'color': printTicketStore.color.getValue() ?
    189             NativeLayer.ColorMode_.COLOR : NativeLayer.ColorMode_.GRAY,
    190         'headerFooterEnabled': printTicketStore.headerFooter.getValue(),
    191         'marginsType': printTicketStore.marginsType.getValue(),
    192         'isFirstRequest': requestId == 0,
    193         'requestID': requestId,
    194         'previewModifiable': documentInfo.isModifiable,
    195         'printToPDF':
    196             destination != null &&
    197             destination.id ==
    198                 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
    199         'printWithCloudPrint': destination != null && !destination.isLocal,
    200         'printWithPrivet': destination != null && destination.isPrivet,
    201         'deviceName': destination == null ? 'foo' : destination.id,
    202         'generateDraftData': documentInfo.isModifiable,
    203         'fitToPageEnabled': printTicketStore.fitToPage.getValue(),
    204 
    205         // NOTE: Even though the following fields don't directly relate to the
    206         // preview, they still need to be included.
    207         'duplex': printTicketStore.duplex.getValue() ?
    208             NativeLayer.DuplexMode.LONG_EDGE : NativeLayer.DuplexMode.SIMPLEX,
    209         'copies': printTicketStore.copies.getValueAsNumber(),
    210         'collate': printTicketStore.collate.getValue(),
    211         'shouldPrintBackgrounds': printTicketStore.cssBackground.getValue(),
    212         'shouldPrintSelectionOnly': printTicketStore.selectionOnly.getValue()
    213       };
    214 
    215       // Set 'cloudPrintID' only if the destination is not local.
    216       if (destination && !destination.isLocal) {
    217         ticket['cloudPrintID'] = destination.id;
    218       }
    219 
    220       if (printTicketStore.marginsType.isCapabilityAvailable() &&
    221           printTicketStore.marginsType.getValue() ==
    222               print_preview.ticket_items.MarginsType.Value.CUSTOM) {
    223         var customMargins = printTicketStore.customMargins.getValue();
    224         var orientationEnum =
    225             print_preview.ticket_items.CustomMargins.Orientation;
    226         ticket['marginsCustom'] = {
    227           'marginTop': customMargins.get(orientationEnum.TOP),
    228           'marginRight': customMargins.get(orientationEnum.RIGHT),
    229           'marginBottom': customMargins.get(orientationEnum.BOTTOM),
    230           'marginLeft': customMargins.get(orientationEnum.LEFT)
    231         };
    232       }
    233 
    234       chrome.send(
    235           'getPreview',
    236           [JSON.stringify(ticket),
    237            requestId > 0 ? documentInfo.pageCount : -1,
    238            documentInfo.isModifiable]);
    239     },
    240 
    241     /**
    242      * Requests that the document be printed.
    243      * @param {!print_preview.Destination} destination Destination to print to.
    244      * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
    245      *     state of the print ticket.
    246      * @param {print_preview.CloudPrintInterface} cloudPrintInterface Interface
    247      *     to Google Cloud Print.
    248      * @param {!print_preview.DocumentInfo} documentInfo Document data model.
    249      * @param {boolean=} opt_isOpenPdfInPreview Whether to open the PDF in the
    250      *     system's preview application.
    251      */
    252     startPrint: function(destination, printTicketStore, cloudPrintInterface,
    253                          documentInfo, opt_isOpenPdfInPreview) {
    254       assert(printTicketStore.isTicketValid(),
    255              'Trying to print when ticket is not valid');
    256 
    257       var ticket = {
    258         'pageRange': printTicketStore.pageRange.getDocumentPageRanges(),
    259         'pageCount': printTicketStore.pageRange.getPageNumberSet().size,
    260         'landscape': printTicketStore.landscape.getValue(),
    261         'color': printTicketStore.color.getValue() ?
    262             NativeLayer.ColorMode_.COLOR : NativeLayer.ColorMode_.GRAY,
    263         'headerFooterEnabled': printTicketStore.headerFooter.getValue(),
    264         'marginsType': printTicketStore.marginsType.getValue(),
    265         'generateDraftData': true, // TODO(rltoscano): What should this be?
    266         'duplex': printTicketStore.duplex.getValue() ?
    267             NativeLayer.DuplexMode.LONG_EDGE : NativeLayer.DuplexMode.SIMPLEX,
    268         'copies': printTicketStore.copies.getValueAsNumber(),
    269         'collate': printTicketStore.collate.getValue(),
    270         'shouldPrintBackgrounds': printTicketStore.cssBackground.getValue(),
    271         'shouldPrintSelectionOnly': printTicketStore.selectionOnly.getValue(),
    272         'previewModifiable': documentInfo.isModifiable,
    273         'printToPDF': destination.id ==
    274             print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
    275         'printWithCloudPrint': !destination.isLocal,
    276         'printWithPrivet': destination.isPrivet,
    277         'deviceName': destination.id,
    278         'isFirstRequest': false,
    279         'requestID': -1,
    280         'fitToPageEnabled': printTicketStore.fitToPage.getValue(),
    281         'pageWidth': documentInfo.pageSize.width,
    282         'pageHeight': documentInfo.pageSize.height,
    283       };
    284 
    285       if (!destination.isLocal) {
    286         // We can't set cloudPrintID if the destination is "Print with Cloud
    287         // Print" because the native system will try to print to Google Cloud
    288         // Print with this ID instead of opening a Google Cloud Print dialog.
    289         ticket['cloudPrintID'] = destination.id;
    290       }
    291 
    292       if (printTicketStore.marginsType.isCapabilityAvailable() &&
    293           printTicketStore.marginsType.isValueEqual(
    294               print_preview.ticket_items.MarginsType.Value.CUSTOM)) {
    295         var customMargins = printTicketStore.customMargins.getValue();
    296         var orientationEnum =
    297             print_preview.ticket_items.CustomMargins.Orientation;
    298         ticket['marginsCustom'] = {
    299           'marginTop': customMargins.get(orientationEnum.TOP),
    300           'marginRight': customMargins.get(orientationEnum.RIGHT),
    301           'marginBottom': customMargins.get(orientationEnum.BOTTOM),
    302           'marginLeft': customMargins.get(orientationEnum.LEFT)
    303         };
    304       }
    305 
    306       if (destination.isPrivet) {
    307         ticket['ticket'] = printTicketStore.createPrintTicket(destination);
    308       }
    309 
    310       if (opt_isOpenPdfInPreview) {
    311         ticket['OpenPDFInPreview'] = true;
    312       }
    313 
    314       chrome.send('print', [JSON.stringify(ticket)]);
    315     },
    316 
    317     /** Requests that the current pending print request be cancelled. */
    318     startCancelPendingPrint: function() {
    319       chrome.send('cancelPendingPrintRequest');
    320     },
    321 
    322     /** Shows the system's native printing dialog. */
    323     startShowSystemDialog: function() {
    324       chrome.send('showSystemDialog');
    325     },
    326 
    327     /** Shows Google Cloud Print's web-based print dialog.
    328      * @param {number} pageCount Number of pages to print.
    329      */
    330     startShowCloudPrintDialog: function(pageCount) {
    331       chrome.send('printWithCloudPrintDialog', [pageCount]);
    332     },
    333 
    334     /** Closes the print preview dialog. */
    335     startCloseDialog: function() {
    336       chrome.send('closePrintPreviewDialog');
    337       chrome.send('DialogClose');
    338     },
    339 
    340     /** Hide the print preview dialog and allow the native layer to close it. */
    341     startHideDialog: function() {
    342       chrome.send('hidePreview');
    343     },
    344 
    345     /**
    346      * Opens the Google Cloud Print sign-in dialog. The DESTINATIONS_RELOAD
    347      * event will be dispatched in response.
    348      */
    349     startCloudPrintSignIn: function() {
    350       chrome.send('signIn');
    351     },
    352 
    353     /** Navigates the user to the system printer settings interface. */
    354     startManageLocalDestinations: function() {
    355       chrome.send('manageLocalPrinters');
    356     },
    357 
    358     /** Navigates the user to the Google Cloud Print management page. */
    359     startManageCloudDestinations: function() {
    360       chrome.send('manageCloudPrinters');
    361     },
    362 
    363     /** Forces browser to open a new tab with the given URL address. */
    364     startForceOpenNewTab: function(url) {
    365       chrome.send('forceOpenNewTab', [url]);
    366     },
    367 
    368     /**
    369      * @param {!Object} initialSettings Object containing all initial settings.
    370      */
    371     onSetInitialSettings_: function(initialSettings) {
    372       var numberFormatSymbols =
    373           print_preview.MeasurementSystem.parseNumberFormat(
    374               initialSettings['numberFormat']);
    375       var unitType = print_preview.MeasurementSystem.UnitType.IMPERIAL;
    376       if (initialSettings['measurementSystem'] != null) {
    377         unitType = initialSettings['measurementSystem'];
    378       }
    379 
    380       var nativeInitialSettings = new print_preview.NativeInitialSettings(
    381           initialSettings['printAutomaticallyInKioskMode'] || false,
    382           initialSettings['hidePrintWithSystemDialogLink'] || false,
    383           numberFormatSymbols[0] || ',',
    384           numberFormatSymbols[1] || '.',
    385           unitType,
    386           initialSettings['previewModifiable'] || false,
    387           initialSettings['initiatorTitle'] || '',
    388           initialSettings['documentHasSelection'] || false,
    389           initialSettings['shouldPrintSelectionOnly'] || false,
    390           initialSettings['printerName'] || null,
    391           initialSettings['appState'] || null);
    392 
    393       var initialSettingsSetEvent = new Event(
    394           NativeLayer.EventType.INITIAL_SETTINGS_SET);
    395       initialSettingsSetEvent.initialSettings = nativeInitialSettings;
    396       this.dispatchEvent(initialSettingsSetEvent);
    397     },
    398 
    399     /**
    400      * Turn on the integration of Cloud Print.
    401      * @param {string} cloudPrintURL The URL to use for cloud print servers.
    402      * @private
    403      */
    404     onSetUseCloudPrint_: function(cloudPrintURL) {
    405       var cloudPrintEnableEvent = new Event(
    406           NativeLayer.EventType.CLOUD_PRINT_ENABLE);
    407       cloudPrintEnableEvent.baseCloudPrintUrl = cloudPrintURL;
    408       this.dispatchEvent(cloudPrintEnableEvent);
    409     },
    410 
    411     /**
    412      * Updates the print preview with local printers.
    413      * Called from PrintPreviewHandler::SetupPrinterList().
    414      * @param {Array} printers Array of printer info objects.
    415      * @private
    416      */
    417     onSetPrinters_: function(printers) {
    418       var localDestsSetEvent = new Event(
    419           NativeLayer.EventType.LOCAL_DESTINATIONS_SET);
    420       localDestsSetEvent.destinationInfos = printers;
    421       this.dispatchEvent(localDestsSetEvent);
    422     },
    423 
    424     /**
    425      * Called when native layer gets settings information for a requested local
    426      * destination.
    427      * @param {Object} settingsInfo printer setting information.
    428      * @private
    429      */
    430     onUpdateWithPrinterCapabilities_: function(settingsInfo) {
    431       var capsSetEvent = new Event(NativeLayer.EventType.CAPABILITIES_SET);
    432       capsSetEvent.settingsInfo = settingsInfo;
    433       this.dispatchEvent(capsSetEvent);
    434     },
    435 
    436     /**
    437      * Called when native layer gets settings information for a requested local
    438      * destination.
    439      * @param {string} printerId printer affected by error.
    440      * @private
    441      */
    442     onFailedToGetPrinterCapabilities_: function(destinationId) {
    443       var getCapsFailEvent = new Event(
    444           NativeLayer.EventType.GET_CAPABILITIES_FAIL);
    445       getCapsFailEvent.destinationId = destinationId;
    446       getCapsFailEvent.destinationOrigin =
    447           print_preview.Destination.Origin.LOCAL;
    448       this.dispatchEvent(getCapsFailEvent);
    449     },
    450 
    451     /**
    452      * Called when native layer gets settings information for a requested privet
    453      * destination.
    454      * @param {string} printerId printer affected by error.
    455      * @private
    456      */
    457     onFailedToGetPrivetPrinterCapabilities_: function(destinationId) {
    458       var getCapsFailEvent = new Event(
    459           NativeLayer.EventType.GET_CAPABILITIES_FAIL);
    460       getCapsFailEvent.destinationId = destinationId;
    461       getCapsFailEvent.destinationOrigin =
    462           print_preview.Destination.Origin.PRIVET;
    463       this.dispatchEvent(getCapsFailEvent);
    464     },
    465 
    466     /** Reloads the printer list. */
    467     onReloadPrintersList_: function() {
    468       cr.dispatchSimpleEvent(this, NativeLayer.EventType.DESTINATIONS_RELOAD);
    469     },
    470 
    471     /**
    472      * Called from the C++ layer.
    473      * Take the PDF data handed to us and submit it to the cloud, closing the
    474      * print preview dialog once the upload is successful.
    475      * @param {string} data Data to send as the print job.
    476      * @private
    477      */
    478     onPrintToCloud_: function(data) {
    479       var printToCloudEvent = new Event(
    480           NativeLayer.EventType.PRINT_TO_CLOUD);
    481       printToCloudEvent.data = data;
    482       this.dispatchEvent(printToCloudEvent);
    483     },
    484 
    485     /**
    486      * Called from PrintPreviewUI::OnFileSelectionCancelled to notify the print
    487      * preview dialog regarding the file selection cancel event.
    488      * @private
    489      */
    490     onFileSelectionCancelled_: function() {
    491       cr.dispatchSimpleEvent(this, NativeLayer.EventType.FILE_SELECTION_CANCEL);
    492     },
    493 
    494     /**
    495      * Called from PrintPreviewUI::OnFileSelectionCompleted to notify the print
    496      * preview dialog regarding the file selection completed event.
    497      * @private
    498      */
    499     onFileSelectionCompleted_: function() {
    500       // If the file selection is completed and the dialog is not already closed
    501       // it means that a pending print to pdf request exists.
    502       cr.dispatchSimpleEvent(
    503           this, NativeLayer.EventType.FILE_SELECTION_COMPLETE);
    504     },
    505 
    506     /**
    507      * Display an error message when print preview fails.
    508      * Called from PrintPreviewMessageHandler::OnPrintPreviewFailed().
    509      * @private
    510      */
    511     onPrintPreviewFailed_: function() {
    512       cr.dispatchSimpleEvent(
    513           this, NativeLayer.EventType.PREVIEW_GENERATION_FAIL);
    514     },
    515 
    516     /**
    517      * Display an error message when encountered invalid printer settings.
    518      * Called from PrintPreviewMessageHandler::OnInvalidPrinterSettings().
    519      * @private
    520      */
    521     onInvalidPrinterSettings_: function() {
    522       cr.dispatchSimpleEvent(this, NativeLayer.EventType.SETTINGS_INVALID);
    523     },
    524 
    525     /**
    526      * @param {{contentWidth: number, contentHeight: number, marginLeft: number,
    527      *          marginRight: number, marginTop: number, marginBottom: number,
    528      *          printableAreaX: number, printableAreaY: number,
    529      *          printableAreaWidth: number, printableAreaHeight: number}}
    530      *          pageLayout Specifies default page layout details in points.
    531      * @param {boolean} hasCustomPageSizeStyle Indicates whether the previewed
    532      *     document has a custom page size style.
    533      * @private
    534      */
    535     onDidGetDefaultPageLayout_: function(pageLayout, hasCustomPageSizeStyle) {
    536       var pageLayoutChangeEvent = new Event(
    537           NativeLayer.EventType.PAGE_LAYOUT_READY);
    538       pageLayoutChangeEvent.pageLayout = pageLayout;
    539       pageLayoutChangeEvent.hasCustomPageSizeStyle = hasCustomPageSizeStyle;
    540       this.dispatchEvent(pageLayoutChangeEvent);
    541     },
    542 
    543     /**
    544      * Update the page count and check the page range.
    545      * Called from PrintPreviewUI::OnDidGetPreviewPageCount().
    546      * @param {number} pageCount The number of pages.
    547      * @param {number} previewResponseId The preview request id that resulted in
    548      *      this response.
    549      * @private
    550      */
    551     onDidGetPreviewPageCount_: function(pageCount, previewResponseId) {
    552       var pageCountChangeEvent = new Event(
    553           NativeLayer.EventType.PAGE_COUNT_READY);
    554       pageCountChangeEvent.pageCount = pageCount;
    555       pageCountChangeEvent.previewResponseId = previewResponseId;
    556       this.dispatchEvent(pageCountChangeEvent);
    557     },
    558 
    559     /**
    560      * Notification that a print preview page has been rendered.
    561      * Check if the settings have changed and request a regeneration if needed.
    562      * Called from PrintPreviewUI::OnDidPreviewPage().
    563      * @param {number} pageNumber The page number, 0-based.
    564      * @param {number} previewUid Preview unique identifier.
    565      * @param {number} previewResponseId The preview request id that resulted in
    566      *     this response.
    567      * @private
    568      */
    569     onDidPreviewPage_: function(pageNumber, previewUid, previewResponseId) {
    570       var pagePreviewGenEvent = new Event(
    571           NativeLayer.EventType.PAGE_PREVIEW_READY);
    572       pagePreviewGenEvent.pageIndex = pageNumber;
    573       pagePreviewGenEvent.previewUid = previewUid;
    574       pagePreviewGenEvent.previewResponseId = previewResponseId;
    575       this.dispatchEvent(pagePreviewGenEvent);
    576     },
    577 
    578     /**
    579      * Notification that access token is ready.
    580      * @param {string} authType Type of access token.
    581      * @param {string} accessToken Access token.
    582      * @private
    583      */
    584     onDidGetAccessToken_: function(authType, accessToken) {
    585       var getAccessTokenEvent = new Event(
    586           NativeLayer.EventType.ACCESS_TOKEN_READY);
    587       getAccessTokenEvent.authType = authType;
    588       getAccessTokenEvent.accessToken = accessToken;
    589       this.dispatchEvent(getAccessTokenEvent);
    590     },
    591 
    592     /**
    593      * Update the print preview when new preview data is available.
    594      * Create the PDF plugin as needed.
    595      * Called from PrintPreviewUI::PreviewDataIsAvailable().
    596      * @param {number} previewUid Preview unique identifier.
    597      * @param {number} previewResponseId The preview request id that resulted in
    598      *     this response.
    599      * @private
    600      */
    601     onUpdatePrintPreview_: function(previewUid, previewResponseId) {
    602       var previewGenDoneEvent = new Event(
    603           NativeLayer.EventType.PREVIEW_GENERATION_DONE);
    604       previewGenDoneEvent.previewUid = previewUid;
    605       previewGenDoneEvent.previewResponseId = previewResponseId;
    606       this.dispatchEvent(previewGenDoneEvent);
    607     },
    608 
    609     /**
    610      * Updates the fit to page option state based on the print scaling option of
    611      * source pdf. PDF's have an option to enable/disable print scaling. When we
    612      * find out that the print scaling option is disabled for the source pdf, we
    613      * uncheck the fitToPage_ to page checkbox. This function is called from C++
    614      * code.
    615      * @private
    616      */
    617     onPrintScalingDisabledForSourcePDF_: function() {
    618       cr.dispatchSimpleEvent(this, NativeLayer.EventType.DISABLE_SCALING);
    619     },
    620 
    621     /**
    622      * Simulates a user click on the print preview dialog cancel button. Used
    623      * only for testing.
    624      * @private
    625      */
    626     autoCancelForTesting_: function() {
    627       var properties = {view: window, bubbles: true, cancelable: true};
    628       var click = new MouseEvent('click', properties);
    629       document.querySelector('#print-header .cancel').dispatchEvent(click);
    630     },
    631 
    632     /**
    633      * @param {{serviceName: string, name: string}} printer Specifies
    634      *     information about the printer that was added.
    635      * @private
    636      */
    637     onPrivetPrinterChanged_: function(printer) {
    638       var privetPrinterChangedEvent =
    639             new Event(NativeLayer.EventType.PRIVET_PRINTER_CHANGED);
    640       privetPrinterChangedEvent.printer = printer;
    641       this.dispatchEvent(privetPrinterChangedEvent);
    642     },
    643 
    644     /**
    645      * Called when the privet printer search is over.
    646      * @private
    647      */
    648     onPrivetPrinterSearchDone_: function() {
    649       var privetPrinterSearchDoneEvent =
    650             new Event(NativeLayer.EventType.PRIVET_PRINTER_SEARCH_DONE);
    651       this.dispatchEvent(privetPrinterSearchDoneEvent);
    652     },
    653 
    654     /**
    655      * @param {Object} printer Specifies information about the printer that was
    656      *    added.
    657      * @private
    658      */
    659     onPrivetCapabilitiesSet_: function(printer, capabilities) {
    660       var privetCapabilitiesSetEvent =
    661             new Event(NativeLayer.EventType.PRIVET_CAPABILITIES_SET);
    662       privetCapabilitiesSetEvent.printer = printer;
    663       privetCapabilitiesSetEvent.capabilities = capabilities;
    664       this.dispatchEvent(privetCapabilitiesSetEvent);
    665     },
    666 
    667     /**
    668      * @param {string} http_error The HTTP response code or -1 if not an HTTP
    669      *    error.
    670      * @private
    671      */
    672     onPrivetPrintFailed_: function(http_error) {
    673       var privetPrintFailedEvent =
    674             new Event(NativeLayer.EventType.PRIVET_PRINT_FAILED);
    675       privetPrintFailedEvent.httpError = http_error;
    676       this.dispatchEvent(privetPrintFailedEvent);
    677     }
    678   };
    679 
    680   /**
    681    * Initial settings retrieved from the native layer.
    682    * @param {boolean} isInKioskAutoPrintMode Whether the print preview should be
    683    *     in auto-print mode.
    684    * @param {string} thousandsDelimeter Character delimeter of thousands digits.
    685    * @param {string} decimalDelimeter Character delimeter of the decimal point.
    686    * @param {!print_preview.MeasurementSystem.UnitType} unitType Unit type of
    687    *     local machine's measurement system.
    688    * @param {boolean} isDocumentModifiable Whether the document to print is
    689    *     modifiable.
    690    * @param {string} documentTitle Title of the document.
    691    * @param {boolean} documentHasSelection Whether the document has selected
    692    *     content.
    693    * @param {boolean} selectionOnly Whether only selected content should be
    694    *     printed.
    695    * @param {?string} systemDefaultDestinationId ID of the system default
    696    *     destination.
    697    * @param {?string} serializedAppStateStr Serialized app state.
    698    * @constructor
    699    */
    700   function NativeInitialSettings(
    701       isInKioskAutoPrintMode,
    702       hidePrintWithSystemDialogLink,
    703       thousandsDelimeter,
    704       decimalDelimeter,
    705       unitType,
    706       isDocumentModifiable,
    707       documentTitle,
    708       documentHasSelection,
    709       selectionOnly,
    710       systemDefaultDestinationId,
    711       serializedAppStateStr) {
    712 
    713     /**
    714      * Whether the print preview should be in auto-print mode.
    715      * @type {boolean}
    716      * @private
    717      */
    718     this.isInKioskAutoPrintMode_ = isInKioskAutoPrintMode;
    719 
    720     /**
    721      * Whether we should hide the link which shows the system print dialog.
    722      * @type {boolean}
    723      * @private
    724      */
    725     this.hidePrintWithSystemDialogLink_ = hidePrintWithSystemDialogLink;
    726 
    727     /**
    728      * Character delimeter of thousands digits.
    729      * @type {string}
    730      * @private
    731      */
    732     this.thousandsDelimeter_ = thousandsDelimeter;
    733 
    734     /**
    735      * Character delimeter of the decimal point.
    736      * @type {string}
    737      * @private
    738      */
    739     this.decimalDelimeter_ = decimalDelimeter;
    740 
    741     /**
    742      * Unit type of local machine's measurement system.
    743      * @type {string}
    744      * @private
    745      */
    746     this.unitType_ = unitType;
    747 
    748     /**
    749      * Whether the document to print is modifiable.
    750      * @type {boolean}
    751      * @private
    752      */
    753     this.isDocumentModifiable_ = isDocumentModifiable;
    754 
    755     /**
    756      * Title of the document.
    757      * @type {string}
    758      * @private
    759      */
    760     this.documentTitle_ = documentTitle;
    761 
    762     /**
    763      * Whether the document has selection.
    764      * @type {string}
    765      * @private
    766      */
    767     this.documentHasSelection_ = documentHasSelection;
    768 
    769     /**
    770      * Whether selection only should be printed.
    771      * @type {string}
    772      * @private
    773      */
    774     this.selectionOnly_ = selectionOnly;
    775 
    776     /**
    777      * ID of the system default destination.
    778      * @type {?string}
    779      * @private
    780      */
    781     this.systemDefaultDestinationId_ = systemDefaultDestinationId;
    782 
    783     /**
    784      * Serialized app state.
    785      * @type {?string}
    786      * @private
    787      */
    788     this.serializedAppStateStr_ = serializedAppStateStr;
    789   };
    790 
    791   NativeInitialSettings.prototype = {
    792     /**
    793      * @return {boolean} Whether the print preview should be in auto-print mode.
    794      */
    795     get isInKioskAutoPrintMode() {
    796       return this.isInKioskAutoPrintMode_;
    797     },
    798 
    799     /**
    800      * @return {boolean} Whether we should hide the link which shows the
    801            system print dialog.
    802      */
    803     get hidePrintWithSystemDialogLink() {
    804       return this.hidePrintWithSystemDialogLink_;
    805     },
    806 
    807     /** @return {string} Character delimeter of thousands digits. */
    808     get thousandsDelimeter() {
    809       return this.thousandsDelimeter_;
    810     },
    811 
    812     /** @return {string} Character delimeter of the decimal point. */
    813     get decimalDelimeter() {
    814       return this.decimalDelimeter_;
    815     },
    816 
    817     /**
    818      * @return {!print_preview.MeasurementSystem.UnitType} Unit type of local
    819      *     machine's measurement system.
    820      */
    821     get unitType() {
    822       return this.unitType_;
    823     },
    824 
    825     /** @return {boolean} Whether the document to print is modifiable. */
    826     get isDocumentModifiable() {
    827       return this.isDocumentModifiable_;
    828     },
    829 
    830     /** @return {string} Document title. */
    831     get documentTitle() {
    832       return this.documentTitle_;
    833     },
    834 
    835     /** @return {bool} Whether the document has selection. */
    836     get documentHasSelection() {
    837       return this.documentHasSelection_;
    838     },
    839 
    840     /** @return {bool} Whether selection only should be printed. */
    841     get selectionOnly() {
    842       return this.selectionOnly_;
    843     },
    844 
    845     /** @return {?string} ID of the system default destination. */
    846     get systemDefaultDestinationId() {
    847       return this.systemDefaultDestinationId_;
    848     },
    849 
    850     /** @return {?string} Serialized app state. */
    851     get serializedAppStateStr() {
    852       return this.serializedAppStateStr_;
    853     }
    854   };
    855 
    856   // Export
    857   return {
    858     NativeInitialSettings: NativeInitialSettings,
    859     NativeLayer: NativeLayer
    860   };
    861 });
    862