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.onPrivetCapabilitiesSet =
     47         this.onPrivetCapabilitiesSet_.bind(this);
     48     global.onPrivetPrintFailed = this.onPrivetPrintFailed_.bind(this);
     49     global.onEnableManipulateSettingsForTest =
     50         this.onEnableManipulateSettingsForTest_.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     MANIPULATE_SETTINGS_FOR_TEST:
     71         'print_preview.NativeLayer.MANIPULATE_SETTINGS_FOR_TEST',
     72     PAGE_COUNT_READY: 'print_preview.NativeLayer.PAGE_COUNT_READY',
     73     PAGE_LAYOUT_READY: 'print_preview.NativeLayer.PAGE_LAYOUT_READY',
     74     PAGE_PREVIEW_READY: 'print_preview.NativeLayer.PAGE_PREVIEW_READY',
     75     PREVIEW_GENERATION_DONE:
     76         'print_preview.NativeLayer.PREVIEW_GENERATION_DONE',
     77     PREVIEW_GENERATION_FAIL:
     78         'print_preview.NativeLayer.PREVIEW_GENERATION_FAIL',
     79     PRINT_TO_CLOUD: 'print_preview.NativeLayer.PRINT_TO_CLOUD',
     80     SETTINGS_INVALID: 'print_preview.NativeLayer.SETTINGS_INVALID',
     81     PRIVET_PRINTER_CHANGED: 'print_preview.NativeLayer.PRIVET_PRINTER_CHANGED',
     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 that the privet print stack stop searching for privet print
    150      * destinations.
    151      */
    152     stopGetPrivetDestinations: function() {
    153       chrome.send('stopGetPrivetPrinters');
    154     },
    155 
    156     /**
    157      * Requests the privet destination's printing capabilities. A
    158      * PRIVET_CAPABILITIES_SET event will be dispatched in response.
    159      * @param {string} destinationId ID of the destination.
    160      */
    161     startGetPrivetDestinationCapabilities: function(destinationId) {
    162       chrome.send('getPrivetPrinterCapabilities', [destinationId]);
    163     },
    164 
    165     /**
    166      * Requests the destination's printing capabilities. A CAPABILITIES_SET
    167      * event will be dispatched in response.
    168      * @param {string} destinationId ID of the destination.
    169      */
    170     startGetLocalDestinationCapabilities: function(destinationId) {
    171       chrome.send('getPrinterCapabilities', [destinationId]);
    172     },
    173 
    174     /**
    175      * @param {!print_preview.Destination} destination Destination to print to.
    176      * @param {!print_preview.ticket_items.Color} color Color ticket item.
    177      * @return {number} Native layer color model.
    178      * @private
    179      */
    180     getNativeColorModel_: function(destination, color) {
    181       // For non-local printers native color model is ignored anyway.
    182       var option = destination.isLocal ? color.getSelectedOption() : null;
    183       var nativeColorModel = parseInt(option ? option.vendor_id : null);
    184       if (isNaN(nativeColorModel)) {
    185         return color.getValue() ?
    186             NativeLayer.ColorMode_.COLOR : NativeLayer.ColorMode_.GRAY;
    187       }
    188       return nativeColorModel;
    189     },
    190 
    191     /**
    192      * Requests that a preview be generated. The following events may be
    193      * dispatched in response:
    194      *   - PAGE_COUNT_READY
    195      *   - PAGE_LAYOUT_READY
    196      *   - PAGE_PREVIEW_READY
    197      *   - PREVIEW_GENERATION_DONE
    198      *   - PREVIEW_GENERATION_FAIL
    199      * @param {print_preview.Destination} destination Destination to print to.
    200      * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
    201      *     state of the print ticket.
    202      * @param {!print_preview.DocumentInfo} documentInfo Document data model.
    203      * @param {number} requestId ID of the preview request.
    204      */
    205     startGetPreview: function(
    206         destination, printTicketStore, documentInfo, requestId) {
    207       assert(printTicketStore.isTicketValidForPreview(),
    208              'Trying to generate preview when ticket is not valid');
    209 
    210       var ticket = {
    211         'pageRange': printTicketStore.pageRange.getDocumentPageRanges(),
    212         'mediaSize': printTicketStore.mediaSize.getValue(),
    213         'landscape': printTicketStore.landscape.getValue(),
    214         'color': this.getNativeColorModel_(destination, printTicketStore.color),
    215         'headerFooterEnabled': printTicketStore.headerFooter.getValue(),
    216         'marginsType': printTicketStore.marginsType.getValue(),
    217         'isFirstRequest': requestId == 0,
    218         'requestID': requestId,
    219         'previewModifiable': documentInfo.isModifiable,
    220         'printToPDF':
    221             destination != null &&
    222             destination.id ==
    223                 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
    224         'printWithCloudPrint': destination != null && !destination.isLocal,
    225         'printWithPrivet': destination != null && destination.isPrivet,
    226         'deviceName': destination == null ? 'foo' : destination.id,
    227         'generateDraftData': documentInfo.isModifiable,
    228         'fitToPageEnabled': printTicketStore.fitToPage.getValue(),
    229 
    230         // NOTE: Even though the following fields don't directly relate to the
    231         // preview, they still need to be included.
    232         'duplex': printTicketStore.duplex.getValue() ?
    233             NativeLayer.DuplexMode.LONG_EDGE : NativeLayer.DuplexMode.SIMPLEX,
    234         'copies': printTicketStore.copies.getValueAsNumber(),
    235         'collate': printTicketStore.collate.getValue(),
    236         'shouldPrintBackgrounds': printTicketStore.cssBackground.getValue(),
    237         'shouldPrintSelectionOnly': printTicketStore.selectionOnly.getValue()
    238       };
    239 
    240       // Set 'cloudPrintID' only if the destination is not local.
    241       if (destination && !destination.isLocal) {
    242         ticket['cloudPrintID'] = destination.id;
    243       }
    244 
    245       if (printTicketStore.marginsType.isCapabilityAvailable() &&
    246           printTicketStore.marginsType.getValue() ==
    247               print_preview.ticket_items.MarginsType.Value.CUSTOM) {
    248         var customMargins = printTicketStore.customMargins.getValue();
    249         var orientationEnum =
    250             print_preview.ticket_items.CustomMargins.Orientation;
    251         ticket['marginsCustom'] = {
    252           'marginTop': customMargins.get(orientationEnum.TOP),
    253           'marginRight': customMargins.get(orientationEnum.RIGHT),
    254           'marginBottom': customMargins.get(orientationEnum.BOTTOM),
    255           'marginLeft': customMargins.get(orientationEnum.LEFT)
    256         };
    257       }
    258 
    259       chrome.send(
    260           'getPreview',
    261           [JSON.stringify(ticket),
    262            requestId > 0 ? documentInfo.pageCount : -1,
    263            documentInfo.isModifiable]);
    264     },
    265 
    266     /**
    267      * Requests that the document be printed.
    268      * @param {!print_preview.Destination} destination Destination to print to.
    269      * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
    270      *     state of the print ticket.
    271      * @param {print_preview.CloudPrintInterface} cloudPrintInterface Interface
    272      *     to Google Cloud Print.
    273      * @param {!print_preview.DocumentInfo} documentInfo Document data model.
    274      * @param {boolean=} opt_isOpenPdfInPreview Whether to open the PDF in the
    275      *     system's preview application.
    276      * @param {boolean=} opt_showSystemDialog Whether to open system dialog for
    277      *     advanced settings.
    278      */
    279     startPrint: function(destination, printTicketStore, cloudPrintInterface,
    280                          documentInfo, opt_isOpenPdfInPreview,
    281                          opt_showSystemDialog) {
    282       assert(printTicketStore.isTicketValid(),
    283              'Trying to print when ticket is not valid');
    284 
    285       assert(!opt_showSystemDialog || (cr.isWindows && destination.isLocal),
    286              'Implemented for Windows only');
    287 
    288       var ticket = {
    289         'pageRange': printTicketStore.pageRange.getDocumentPageRanges(),
    290         'mediaSize': printTicketStore.mediaSize.getValue(),
    291         'pageCount': printTicketStore.pageRange.getPageNumberSet().size,
    292         'landscape': printTicketStore.landscape.getValue(),
    293         'color': this.getNativeColorModel_(destination, printTicketStore.color),
    294         'headerFooterEnabled': printTicketStore.headerFooter.getValue(),
    295         'marginsType': printTicketStore.marginsType.getValue(),
    296         'generateDraftData': true, // TODO(rltoscano): What should this be?
    297         'duplex': printTicketStore.duplex.getValue() ?
    298             NativeLayer.DuplexMode.LONG_EDGE : NativeLayer.DuplexMode.SIMPLEX,
    299         'copies': printTicketStore.copies.getValueAsNumber(),
    300         'collate': printTicketStore.collate.getValue(),
    301         'shouldPrintBackgrounds': printTicketStore.cssBackground.getValue(),
    302         'shouldPrintSelectionOnly': printTicketStore.selectionOnly.getValue(),
    303         'previewModifiable': documentInfo.isModifiable,
    304         'printToPDF': destination.id ==
    305             print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
    306         'printWithCloudPrint': !destination.isLocal,
    307         'printWithPrivet': destination.isPrivet,
    308         'deviceName': destination.id,
    309         'isFirstRequest': false,
    310         'requestID': -1,
    311         'fitToPageEnabled': printTicketStore.fitToPage.getValue(),
    312         'pageWidth': documentInfo.pageSize.width,
    313         'pageHeight': documentInfo.pageSize.height,
    314         'showSystemDialog': opt_showSystemDialog
    315       };
    316 
    317       if (!destination.isLocal) {
    318         // We can't set cloudPrintID if the destination is "Print with Cloud
    319         // Print" because the native system will try to print to Google Cloud
    320         // Print with this ID instead of opening a Google Cloud Print dialog.
    321         ticket['cloudPrintID'] = destination.id;
    322       }
    323 
    324       if (printTicketStore.marginsType.isCapabilityAvailable() &&
    325           printTicketStore.marginsType.isValueEqual(
    326               print_preview.ticket_items.MarginsType.Value.CUSTOM)) {
    327         var customMargins = printTicketStore.customMargins.getValue();
    328         var orientationEnum =
    329             print_preview.ticket_items.CustomMargins.Orientation;
    330         ticket['marginsCustom'] = {
    331           'marginTop': customMargins.get(orientationEnum.TOP),
    332           'marginRight': customMargins.get(orientationEnum.RIGHT),
    333           'marginBottom': customMargins.get(orientationEnum.BOTTOM),
    334           'marginLeft': customMargins.get(orientationEnum.LEFT)
    335         };
    336       }
    337 
    338       if (destination.isPrivet) {
    339         ticket['ticket'] = printTicketStore.createPrintTicket(destination);
    340         ticket['capabilities'] = JSON.stringify(destination.capabilities);
    341       }
    342 
    343       if (opt_isOpenPdfInPreview) {
    344         ticket['OpenPDFInPreview'] = true;
    345       }
    346 
    347       chrome.send('print', [JSON.stringify(ticket)]);
    348     },
    349 
    350     /** Requests that the current pending print request be cancelled. */
    351     startCancelPendingPrint: function() {
    352       chrome.send('cancelPendingPrintRequest');
    353     },
    354 
    355     /** Shows the system's native printing dialog. */
    356     startShowSystemDialog: function() {
    357       assert(!cr.isWindows);
    358       chrome.send('showSystemDialog');
    359     },
    360 
    361     /** Shows Google Cloud Print's web-based print dialog.
    362      * @param {number} pageCount Number of pages to print.
    363      */
    364     startShowCloudPrintDialog: function(pageCount) {
    365       chrome.send('printWithCloudPrintDialog', [pageCount]);
    366     },
    367 
    368     /** Closes the print preview dialog. */
    369     startCloseDialog: function() {
    370       chrome.send('closePrintPreviewDialog');
    371       chrome.send('dialogClose');
    372     },
    373 
    374     /** Hide the print preview dialog and allow the native layer to close it. */
    375     startHideDialog: function() {
    376       chrome.send('hidePreview');
    377     },
    378 
    379     /**
    380      * Opens the Google Cloud Print sign-in tab. The DESTINATIONS_RELOAD event
    381      *     will be dispatched in response.
    382      * @param {boolean} addAccount Whether to open an 'add a new account' or
    383      *     default sign in page.
    384      */
    385     startCloudPrintSignIn: function(addAccount) {
    386       chrome.send('signIn', [addAccount]);
    387     },
    388 
    389     /** Navigates the user to the system printer settings interface. */
    390     startManageLocalDestinations: function() {
    391       chrome.send('manageLocalPrinters');
    392     },
    393 
    394     /** Navigates the user to the Google Cloud Print management page. */
    395     startManageCloudDestinations: function() {
    396       chrome.send('manageCloudPrinters');
    397     },
    398 
    399     /** Forces browser to open a new tab with the given URL address. */
    400     startForceOpenNewTab: function(url) {
    401       chrome.send('forceOpenNewTab', [url]);
    402     },
    403 
    404     /**
    405      * @param {!Object} initialSettings Object containing all initial settings.
    406      */
    407     onSetInitialSettings_: function(initialSettings) {
    408       var numberFormatSymbols =
    409           print_preview.MeasurementSystem.parseNumberFormat(
    410               initialSettings['numberFormat']);
    411       var unitType = print_preview.MeasurementSystem.UnitType.IMPERIAL;
    412       if (initialSettings['measurementSystem'] != null) {
    413         unitType = initialSettings['measurementSystem'];
    414       }
    415 
    416       var nativeInitialSettings = new print_preview.NativeInitialSettings(
    417           initialSettings['printAutomaticallyInKioskMode'] || false,
    418           initialSettings['appKioskMode'] || false,
    419           initialSettings['hidePrintWithSystemDialogLink'] || false,
    420           numberFormatSymbols[0] || ',',
    421           numberFormatSymbols[1] || '.',
    422           unitType,
    423           initialSettings['previewModifiable'] || false,
    424           initialSettings['initiatorTitle'] || '',
    425           initialSettings['documentHasSelection'] || false,
    426           initialSettings['shouldPrintSelectionOnly'] || false,
    427           initialSettings['printerName'] || null,
    428           initialSettings['appState'] || null);
    429 
    430       var initialSettingsSetEvent = new Event(
    431           NativeLayer.EventType.INITIAL_SETTINGS_SET);
    432       initialSettingsSetEvent.initialSettings = nativeInitialSettings;
    433       this.dispatchEvent(initialSettingsSetEvent);
    434     },
    435 
    436     /**
    437      * Turn on the integration of Cloud Print.
    438      * @param {{cloudPrintURL: string, appKioskMode: string}} settings
    439      *     cloudPrintUrl: The URL to use for cloud print servers.
    440      * @private
    441      */
    442     onSetUseCloudPrint_: function(settings) {
    443       var cloudPrintEnableEvent = new Event(
    444           NativeLayer.EventType.CLOUD_PRINT_ENABLE);
    445       cloudPrintEnableEvent.baseCloudPrintUrl = settings['cloudPrintUrl'] || '';
    446       cloudPrintEnableEvent.appKioskMode = settings['appKioskMode'] || false;
    447       this.dispatchEvent(cloudPrintEnableEvent);
    448     },
    449 
    450     /**
    451      * Updates the print preview with local printers.
    452      * Called from PrintPreviewHandler::SetupPrinterList().
    453      * @param {Array} printers Array of printer info objects.
    454      * @private
    455      */
    456     onSetPrinters_: function(printers) {
    457       var localDestsSetEvent = new Event(
    458           NativeLayer.EventType.LOCAL_DESTINATIONS_SET);
    459       localDestsSetEvent.destinationInfos = printers;
    460       this.dispatchEvent(localDestsSetEvent);
    461     },
    462 
    463     /**
    464      * Called when native layer gets settings information for a requested local
    465      * destination.
    466      * @param {Object} settingsInfo printer setting information.
    467      * @private
    468      */
    469     onUpdateWithPrinterCapabilities_: function(settingsInfo) {
    470       var capsSetEvent = new Event(NativeLayer.EventType.CAPABILITIES_SET);
    471       capsSetEvent.settingsInfo = settingsInfo;
    472       this.dispatchEvent(capsSetEvent);
    473     },
    474 
    475     /**
    476      * Called when native layer gets settings information for a requested local
    477      * destination.
    478      * @param {string} destinationId Printer affected by error.
    479      * @private
    480      */
    481     onFailedToGetPrinterCapabilities_: function(destinationId) {
    482       var getCapsFailEvent = new Event(
    483           NativeLayer.EventType.GET_CAPABILITIES_FAIL);
    484       getCapsFailEvent.destinationId = destinationId;
    485       getCapsFailEvent.destinationOrigin =
    486           print_preview.Destination.Origin.LOCAL;
    487       this.dispatchEvent(getCapsFailEvent);
    488     },
    489 
    490     /**
    491      * Called when native layer gets settings information for a requested privet
    492      * destination.
    493      * @param {string} destinationId Printer affected by error.
    494      * @private
    495      */
    496     onFailedToGetPrivetPrinterCapabilities_: function(destinationId) {
    497       var getCapsFailEvent = new Event(
    498           NativeLayer.EventType.GET_CAPABILITIES_FAIL);
    499       getCapsFailEvent.destinationId = destinationId;
    500       getCapsFailEvent.destinationOrigin =
    501           print_preview.Destination.Origin.PRIVET;
    502       this.dispatchEvent(getCapsFailEvent);
    503     },
    504 
    505     /** Reloads the printer list. */
    506     onReloadPrintersList_: function() {
    507       cr.dispatchSimpleEvent(this, NativeLayer.EventType.DESTINATIONS_RELOAD);
    508     },
    509 
    510     /**
    511      * Called from the C++ layer.
    512      * Take the PDF data handed to us and submit it to the cloud, closing the
    513      * print preview dialog once the upload is successful.
    514      * @param {string} data Data to send as the print job.
    515      * @private
    516      */
    517     onPrintToCloud_: function(data) {
    518       var printToCloudEvent = new Event(
    519           NativeLayer.EventType.PRINT_TO_CLOUD);
    520       printToCloudEvent.data = data;
    521       this.dispatchEvent(printToCloudEvent);
    522     },
    523 
    524     /**
    525      * Called from PrintPreviewUI::OnFileSelectionCancelled to notify the print
    526      * preview dialog regarding the file selection cancel event.
    527      * @private
    528      */
    529     onFileSelectionCancelled_: function() {
    530       cr.dispatchSimpleEvent(this, NativeLayer.EventType.FILE_SELECTION_CANCEL);
    531     },
    532 
    533     /**
    534      * Called from PrintPreviewUI::OnFileSelectionCompleted to notify the print
    535      * preview dialog regarding the file selection completed event.
    536      * @private
    537      */
    538     onFileSelectionCompleted_: function() {
    539       // If the file selection is completed and the dialog is not already closed
    540       // it means that a pending print to pdf request exists.
    541       cr.dispatchSimpleEvent(
    542           this, NativeLayer.EventType.FILE_SELECTION_COMPLETE);
    543     },
    544 
    545     /**
    546      * Display an error message when print preview fails.
    547      * Called from PrintPreviewMessageHandler::OnPrintPreviewFailed().
    548      * @private
    549      */
    550     onPrintPreviewFailed_: function() {
    551       cr.dispatchSimpleEvent(
    552           this, NativeLayer.EventType.PREVIEW_GENERATION_FAIL);
    553     },
    554 
    555     /**
    556      * Display an error message when encountered invalid printer settings.
    557      * Called from PrintPreviewMessageHandler::OnInvalidPrinterSettings().
    558      * @private
    559      */
    560     onInvalidPrinterSettings_: function() {
    561       cr.dispatchSimpleEvent(this, NativeLayer.EventType.SETTINGS_INVALID);
    562     },
    563 
    564     /**
    565      * @param {{contentWidth: number, contentHeight: number, marginLeft: number,
    566      *          marginRight: number, marginTop: number, marginBottom: number,
    567      *          printableAreaX: number, printableAreaY: number,
    568      *          printableAreaWidth: number, printableAreaHeight: number}}
    569      *          pageLayout Specifies default page layout details in points.
    570      * @param {boolean} hasCustomPageSizeStyle Indicates whether the previewed
    571      *     document has a custom page size style.
    572      * @private
    573      */
    574     onDidGetDefaultPageLayout_: function(pageLayout, hasCustomPageSizeStyle) {
    575       var pageLayoutChangeEvent = new Event(
    576           NativeLayer.EventType.PAGE_LAYOUT_READY);
    577       pageLayoutChangeEvent.pageLayout = pageLayout;
    578       pageLayoutChangeEvent.hasCustomPageSizeStyle = hasCustomPageSizeStyle;
    579       this.dispatchEvent(pageLayoutChangeEvent);
    580     },
    581 
    582     /**
    583      * Update the page count and check the page range.
    584      * Called from PrintPreviewUI::OnDidGetPreviewPageCount().
    585      * @param {number} pageCount The number of pages.
    586      * @param {number} previewResponseId The preview request id that resulted in
    587      *      this response.
    588      * @private
    589      */
    590     onDidGetPreviewPageCount_: function(pageCount, previewResponseId) {
    591       var pageCountChangeEvent = new Event(
    592           NativeLayer.EventType.PAGE_COUNT_READY);
    593       pageCountChangeEvent.pageCount = pageCount;
    594       pageCountChangeEvent.previewResponseId = previewResponseId;
    595       this.dispatchEvent(pageCountChangeEvent);
    596     },
    597 
    598     /**
    599      * Notification that a print preview page has been rendered.
    600      * Check if the settings have changed and request a regeneration if needed.
    601      * Called from PrintPreviewUI::OnDidPreviewPage().
    602      * @param {number} pageNumber The page number, 0-based.
    603      * @param {number} previewUid Preview unique identifier.
    604      * @param {number} previewResponseId The preview request id that resulted in
    605      *     this response.
    606      * @private
    607      */
    608     onDidPreviewPage_: function(pageNumber, previewUid, previewResponseId) {
    609       var pagePreviewGenEvent = new Event(
    610           NativeLayer.EventType.PAGE_PREVIEW_READY);
    611       pagePreviewGenEvent.pageIndex = pageNumber;
    612       pagePreviewGenEvent.previewUid = previewUid;
    613       pagePreviewGenEvent.previewResponseId = previewResponseId;
    614       this.dispatchEvent(pagePreviewGenEvent);
    615     },
    616 
    617     /**
    618      * Notification that access token is ready.
    619      * @param {string} authType Type of access token.
    620      * @param {string} accessToken Access token.
    621      * @private
    622      */
    623     onDidGetAccessToken_: function(authType, accessToken) {
    624       var getAccessTokenEvent = new Event(
    625           NativeLayer.EventType.ACCESS_TOKEN_READY);
    626       getAccessTokenEvent.authType = authType;
    627       getAccessTokenEvent.accessToken = accessToken;
    628       this.dispatchEvent(getAccessTokenEvent);
    629     },
    630 
    631     /**
    632      * Update the print preview when new preview data is available.
    633      * Create the PDF plugin as needed.
    634      * Called from PrintPreviewUI::PreviewDataIsAvailable().
    635      * @param {number} previewUid Preview unique identifier.
    636      * @param {number} previewResponseId The preview request id that resulted in
    637      *     this response.
    638      * @private
    639      */
    640     onUpdatePrintPreview_: function(previewUid, previewResponseId) {
    641       var previewGenDoneEvent = new Event(
    642           NativeLayer.EventType.PREVIEW_GENERATION_DONE);
    643       previewGenDoneEvent.previewUid = previewUid;
    644       previewGenDoneEvent.previewResponseId = previewResponseId;
    645       this.dispatchEvent(previewGenDoneEvent);
    646     },
    647 
    648     /**
    649      * Updates the fit to page option state based on the print scaling option of
    650      * source pdf. PDF's have an option to enable/disable print scaling. When we
    651      * find out that the print scaling option is disabled for the source pdf, we
    652      * uncheck the fitToPage_ to page checkbox. This function is called from C++
    653      * code.
    654      * @private
    655      */
    656     onPrintScalingDisabledForSourcePDF_: function() {
    657       cr.dispatchSimpleEvent(this, NativeLayer.EventType.DISABLE_SCALING);
    658     },
    659 
    660     /**
    661      * Simulates a user click on the print preview dialog cancel button. Used
    662      * only for testing.
    663      * @private
    664      */
    665     autoCancelForTesting_: function() {
    666       var properties = {view: window, bubbles: true, cancelable: true};
    667       var click = new MouseEvent('click', properties);
    668       document.querySelector('#print-header .cancel').dispatchEvent(click);
    669     },
    670 
    671     /**
    672      * @param {{serviceName: string, name: string}} printer Specifies
    673      *     information about the printer that was added.
    674      * @private
    675      */
    676     onPrivetPrinterChanged_: function(printer) {
    677       var privetPrinterChangedEvent =
    678             new Event(NativeLayer.EventType.PRIVET_PRINTER_CHANGED);
    679       privetPrinterChangedEvent.printer = printer;
    680       this.dispatchEvent(privetPrinterChangedEvent);
    681     },
    682 
    683     /**
    684      * @param {Object} printer Specifies information about the printer that was
    685      *    added.
    686      * @private
    687      */
    688     onPrivetCapabilitiesSet_: function(printer, capabilities) {
    689       var privetCapabilitiesSetEvent =
    690             new Event(NativeLayer.EventType.PRIVET_CAPABILITIES_SET);
    691       privetCapabilitiesSetEvent.printer = printer;
    692       privetCapabilitiesSetEvent.capabilities = capabilities;
    693       this.dispatchEvent(privetCapabilitiesSetEvent);
    694     },
    695 
    696     /**
    697      * @param {string} http_error The HTTP response code or -1 if not an HTTP
    698      *    error.
    699      * @private
    700      */
    701     onPrivetPrintFailed_: function(http_error) {
    702       var privetPrintFailedEvent =
    703             new Event(NativeLayer.EventType.PRIVET_PRINT_FAILED);
    704       privetPrintFailedEvent.httpError = http_error;
    705       this.dispatchEvent(privetPrintFailedEvent);
    706     },
    707 
    708     /**
    709      * Allows for onManipulateSettings to be called
    710      * from the native layer.
    711      * @private
    712      */
    713     onEnableManipulateSettingsForTest_: function() {
    714       global.onManipulateSettingsForTest =
    715           this.onManipulateSettingsForTest_.bind(this);
    716     },
    717 
    718     /**
    719      * Dispatches an event to print_preview.js to change
    720      * a particular setting for print preview.
    721      * @param {!Object} settings Object containing the value to be
    722      *     changed and that value should be set to.
    723      * @private
    724      */
    725     onManipulateSettingsForTest_: function(settings) {
    726       var manipulateSettingsEvent =
    727           new Event(NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST);
    728       manipulateSettingsEvent.settings = settings;
    729       this.dispatchEvent(manipulateSettingsEvent);
    730     },
    731 
    732     /**
    733      * Sends a message to the test, letting it know that an
    734      * option has been set to a particular value and that the change has
    735      * finished modifying the preview area.
    736      */
    737     previewReadyForTest: function() {
    738       if (global.onManipulateSettingsForTest)
    739         chrome.send('UILoadedForTest');
    740     },
    741 
    742     /**
    743      * Notifies the test that the option it tried to change
    744      * had not been changed successfully.
    745      */
    746     previewFailedForTest: function() {
    747       if (global.onManipulateSettingsForTest)
    748         chrome.send('UIFailedLoadingForTest');
    749     }
    750   };
    751 
    752   /**
    753    * Initial settings retrieved from the native layer.
    754    * @param {boolean} isInKioskAutoPrintMode Whether the print preview should be
    755    *     in auto-print mode.
    756    * @param {boolean} isInAppKioskMode Whether the print preview is in App Kiosk
    757    *     mode.
    758    * @param {string} thousandsDelimeter Character delimeter of thousands digits.
    759    * @param {string} decimalDelimeter Character delimeter of the decimal point.
    760    * @param {!print_preview.MeasurementSystem.UnitType} unitType Unit type of
    761    *     local machine's measurement system.
    762    * @param {boolean} isDocumentModifiable Whether the document to print is
    763    *     modifiable.
    764    * @param {string} documentTitle Title of the document.
    765    * @param {boolean} documentHasSelection Whether the document has selected
    766    *     content.
    767    * @param {boolean} selectionOnly Whether only selected content should be
    768    *     printed.
    769    * @param {?string} systemDefaultDestinationId ID of the system default
    770    *     destination.
    771    * @param {?string} serializedAppStateStr Serialized app state.
    772    * @constructor
    773    */
    774   function NativeInitialSettings(
    775       isInKioskAutoPrintMode,
    776       isInAppKioskMode,
    777       hidePrintWithSystemDialogLink,
    778       thousandsDelimeter,
    779       decimalDelimeter,
    780       unitType,
    781       isDocumentModifiable,
    782       documentTitle,
    783       documentHasSelection,
    784       selectionOnly,
    785       systemDefaultDestinationId,
    786       serializedAppStateStr) {
    787 
    788     /**
    789      * Whether the print preview should be in auto-print mode.
    790      * @type {boolean}
    791      * @private
    792      */
    793     this.isInKioskAutoPrintMode_ = isInKioskAutoPrintMode;
    794 
    795     /**
    796      * Whether the print preview should switch to App Kiosk mode.
    797      * @type {boolean}
    798      * @private
    799      */
    800     this.isInAppKioskMode_ = isInAppKioskMode;
    801 
    802     /**
    803      * Whether we should hide the link which shows the system print dialog.
    804      * @type {boolean}
    805      * @private
    806      */
    807     this.hidePrintWithSystemDialogLink_ = hidePrintWithSystemDialogLink;
    808 
    809     /**
    810      * Character delimeter of thousands digits.
    811      * @type {string}
    812      * @private
    813      */
    814     this.thousandsDelimeter_ = thousandsDelimeter;
    815 
    816     /**
    817      * Character delimeter of the decimal point.
    818      * @type {string}
    819      * @private
    820      */
    821     this.decimalDelimeter_ = decimalDelimeter;
    822 
    823     /**
    824      * Unit type of local machine's measurement system.
    825      * @type {string}
    826      * @private
    827      */
    828     this.unitType_ = unitType;
    829 
    830     /**
    831      * Whether the document to print is modifiable.
    832      * @type {boolean}
    833      * @private
    834      */
    835     this.isDocumentModifiable_ = isDocumentModifiable;
    836 
    837     /**
    838      * Title of the document.
    839      * @type {string}
    840      * @private
    841      */
    842     this.documentTitle_ = documentTitle;
    843 
    844     /**
    845      * Whether the document has selection.
    846      * @type {string}
    847      * @private
    848      */
    849     this.documentHasSelection_ = documentHasSelection;
    850 
    851     /**
    852      * Whether selection only should be printed.
    853      * @type {string}
    854      * @private
    855      */
    856     this.selectionOnly_ = selectionOnly;
    857 
    858     /**
    859      * ID of the system default destination.
    860      * @type {?string}
    861      * @private
    862      */
    863     this.systemDefaultDestinationId_ = systemDefaultDestinationId;
    864 
    865     /**
    866      * Serialized app state.
    867      * @type {?string}
    868      * @private
    869      */
    870     this.serializedAppStateStr_ = serializedAppStateStr;
    871   };
    872 
    873   NativeInitialSettings.prototype = {
    874     /**
    875      * @return {boolean} Whether the print preview should be in auto-print mode.
    876      */
    877     get isInKioskAutoPrintMode() {
    878       return this.isInKioskAutoPrintMode_;
    879     },
    880 
    881     /**
    882      * @return {boolean} Whether the print preview should switch to App Kiosk
    883      *     mode.
    884      */
    885     get isInAppKioskMode() {
    886       return this.isInAppKioskMode_;
    887     },
    888 
    889     /**
    890      * @return {boolean} Whether we should hide the link which shows the
    891            system print dialog.
    892      */
    893     get hidePrintWithSystemDialogLink() {
    894       return this.hidePrintWithSystemDialogLink_;
    895     },
    896 
    897     /** @return {string} Character delimeter of thousands digits. */
    898     get thousandsDelimeter() {
    899       return this.thousandsDelimeter_;
    900     },
    901 
    902     /** @return {string} Character delimeter of the decimal point. */
    903     get decimalDelimeter() {
    904       return this.decimalDelimeter_;
    905     },
    906 
    907     /**
    908      * @return {!print_preview.MeasurementSystem.UnitType} Unit type of local
    909      *     machine's measurement system.
    910      */
    911     get unitType() {
    912       return this.unitType_;
    913     },
    914 
    915     /** @return {boolean} Whether the document to print is modifiable. */
    916     get isDocumentModifiable() {
    917       return this.isDocumentModifiable_;
    918     },
    919 
    920     /** @return {string} Document title. */
    921     get documentTitle() {
    922       return this.documentTitle_;
    923     },
    924 
    925     /** @return {bool} Whether the document has selection. */
    926     get documentHasSelection() {
    927       return this.documentHasSelection_;
    928     },
    929 
    930     /** @return {bool} Whether selection only should be printed. */
    931     get selectionOnly() {
    932       return this.selectionOnly_;
    933     },
    934 
    935     /** @return {?string} ID of the system default destination. */
    936     get systemDefaultDestinationId() {
    937       return this.systemDefaultDestinationId_;
    938     },
    939 
    940     /** @return {?string} Serialized app state. */
    941     get serializedAppStateStr() {
    942       return this.serializedAppStateStr_;
    943     }
    944   };
    945 
    946   // Export
    947   return {
    948     NativeInitialSettings: NativeInitialSettings,
    949     NativeLayer: NativeLayer
    950   };
    951 });
    952