diff options
author | kmadhusu@chromium.org <kmadhusu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-16 20:32:14 +0000 |
---|---|---|
committer | kmadhusu@chromium.org <kmadhusu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-16 20:32:14 +0000 |
commit | 7a3439b3d169047c1c07f28a6f9cda341328980b (patch) | |
tree | 7589ad8ea788020fdc8e1bd1a1b00d4717bd3a32 | |
parent | 5d7e3c449d8c0ec806ef03187983f7c49889a9aa (diff) | |
download | chromium_src-7a3439b3d169047c1c07f28a6f9cda341328980b.zip chromium_src-7a3439b3d169047c1c07f28a6f9cda341328980b.tar.gz chromium_src-7a3439b3d169047c1c07f28a6f9cda341328980b.tar.bz2 |
[Print Preview]: Added code to support pdf fit to page functionality.
BUG=85132
TEST=none
Review URL: https://chromiumcodereview.appspot.com/10083060
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137498 0039d316-1c4b-4281-b951-d872f2087c98
20 files changed, 530 insertions, 49 deletions
diff --git a/chrome/browser/printing/print_preview_message_handler.cc b/chrome/browser/printing/print_preview_message_handler.cc index b97fbd9..c4d896a 100644 --- a/chrome/browser/printing/print_preview_message_handler.cc +++ b/chrome/browser/printing/print_preview_message_handler.cc @@ -214,6 +214,13 @@ void PrintPreviewMessageHandler::OnInvalidPrinterSettings(int document_cookie) { print_preview_ui->OnInvalidPrinterSettings(); } +void PrintPreviewMessageHandler::OnPrintPreviewScalingDisabled() { + PrintPreviewUI* print_preview_ui = GetPrintPreviewUI(); + if (!print_preview_ui) + return; + print_preview_ui->OnPrintPreviewScalingDisabled(); +} + bool PrintPreviewMessageHandler::OnMessageReceived( const IPC::Message& message) { bool handled = true; @@ -234,6 +241,8 @@ bool PrintPreviewMessageHandler::OnMessageReceived( OnPrintPreviewCancelled) IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewInvalidPrinterSettings, OnInvalidPrinterSettings) + IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewScalingDisabled, + OnPrintPreviewScalingDisabled) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; diff --git a/chrome/browser/printing/print_preview_message_handler.h b/chrome/browser/printing/print_preview_message_handler.h index b4773ed..b5aa5f4 100644 --- a/chrome/browser/printing/print_preview_message_handler.h +++ b/chrome/browser/printing/print_preview_message_handler.h @@ -60,6 +60,7 @@ class PrintPreviewMessageHandler : public content::WebContentsObserver { void OnPrintPreviewFailed(int document_cookie); void OnPrintPreviewCancelled(int document_cookie); void OnInvalidPrinterSettings(int document_cookie); + void OnPrintPreviewScalingDisabled(); DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); }; diff --git a/chrome/browser/resources/print_preview/fit_to_page_settings.js b/chrome/browser/resources/print_preview/fit_to_page_settings.js new file mode 100644 index 0000000..6747127 --- /dev/null +++ b/chrome/browser/resources/print_preview/fit_to_page_settings.js @@ -0,0 +1,114 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +cr.define('print_preview', function() { + 'use strict'; + + /** + * Creates a |FitToPageSettings| object. This object encapsulates all + * settings and logic related to the fit to page checkbox. + * @constructor + */ + function FitToPageSettings() { + // @type {HTMLDivElement} This represents fit to page div element. + this.fitToPageOption_ = $('fit-to-page-option'); + + // @type {HTMLInputElement} This represents fit to page input element. + this.fitToPageCheckbox_ = $('fit-to-page'); + + // @type {boolean} True if fit to page option applies for the selected + // user options. Fit to Page options applies only if we are previewing + // a PDF and the current destination printer is actually a physcial + // printer. + this.fitToPageApplies_ = true; + + this.addEventListeners_(); + } + + cr.addSingletonGetter(FitToPageSettings); + + FitToPageSettings.prototype = { + /** + * Returns true if we need to fit the page contents to printable area. + * @return {boolean} true if Fit to page is checked. + */ + hasFitToPage: function() { + return previewModifiable || this.fitToPageCheckbox_.checked; + }, + + /** + * Updates |this.fitToPageApplies_| depending on the selected printer and + * preview data source type. + * @param {!string} printerName Selected printer name. + * @private + */ + resetState_: function(printerName) { + if (!previewModifiable) + isPrintReadyMetafileReady = false; + var printToPDF = printerName == PRINT_TO_PDF; + this.fitToPageApplies_ = !previewModifiable && !printToPDF; + }, + + /** + * Print scaling is disabled for preview source plugin. Uncheck the fit to + * page option. + */ + onPrintScalingDisabled: function() { + this.fitToPageCheckbox_.checked = false; + }, + + /** + * Adding listeners to fit to page control. + * @private + */ + addEventListeners_: function() { + this.fitToPageCheckbox_.onclick = + this.onFitToPageCheckboxClicked_.bind(this); + document.addEventListener(customEvents.PDF_LOADED, + this.onPDFLoaded_.bind(this)); + document.addEventListener(customEvents.PRINTER_SELECTION_CHANGED, + this.onPrinterSelectionChanged_.bind(this)); + }, + + /** + * Listener executing when a |customEvents.PRINTER_SELECTION_CHANGED| event + * occurs. + * @param {cr.Event} event The event that triggered this listener. + * @private + */ + onPrinterSelectionChanged_: function(event) { + this.resetState_(event.selectedPrinter); + this.updateVisibility_(); + }, + + /** + * Listener executing when the user selects or de-selects the fit to page + * option. + * @private + */ + onFitToPageCheckboxClicked_: function() { + requestPrintPreview(); + }, + + /** + * Listener executing when a |customEvents.PDF_LOADED| event occurs. + * @private + */ + onPDFLoaded_: function() { + this.updateVisibility_(); + }, + + /** + * Hides or shows |this.fitToPageOption_|. + * @private + */ + updateVisibility_: function() { + this.fitToPageOption_.style.display = + this.fitToPageApplies_ ? 'block' : 'none'; + } + }; + + return { + FitToPageSettings: FitToPageSettings + }; +}); diff --git a/chrome/browser/resources/print_preview/header_footer_settings.html b/chrome/browser/resources/print_preview/header_footer_settings.html deleted file mode 100644 index 7459bf0..0000000 --- a/chrome/browser/resources/print_preview/header_footer_settings.html +++ /dev/null @@ -1,7 +0,0 @@ -<div id="header-footer-option" class="two-column visible"> - <h1 i18n-content="optionsLabel"></h1> - <div class="right-column checkbox"><label> - <input id="header-footer" type="checkbox" /> - <span i18n-content="optionHeaderFooter"></span> - </label></div> -</div> diff --git a/chrome/browser/resources/print_preview/header_footer_settings.js b/chrome/browser/resources/print_preview/header_footer_settings.js index 882829b..df74c67 100644 --- a/chrome/browser/resources/print_preview/header_footer_settings.js +++ b/chrome/browser/resources/print_preview/header_footer_settings.js @@ -76,6 +76,10 @@ cr.define('print_preview', function() { } } this.setVisible_(headerFooterApplies); + var headerFooterEvent = new cr.Event( + customEvents.HEADER_FOOTER_VISIBILITY_CHANGED); + headerFooterEvent.headerFooterApplies = headerFooterApplies; + document.dispatchEvent(headerFooterEvent); }, /** @@ -108,17 +112,14 @@ cr.define('print_preview', function() { }, /** - * Hides or shows |this.headerFooterOption|. - * @param {boolean} visible True if |this.headerFooterOption| should be + * Hides or shows |this.headerFooterOption_|. + * @param {boolean} visible True if |this.headerFooterOption_| should be * shown. * @private */ setVisible_: function(visible) { - if (visible) - fadeInOption(this.headerFooterOption_); - else - fadeOutOption(this.headerFooterOption_); - } + this.headerFooterOption_.style.display = visible ? 'block' : 'none'; + }, }; return { diff --git a/chrome/browser/resources/print_preview/more_options.html b/chrome/browser/resources/print_preview/more_options.html new file mode 100644 index 0000000..c6032554 --- /dev/null +++ b/chrome/browser/resources/print_preview/more_options.html @@ -0,0 +1,17 @@ +<div id="more-options" class="two-column visible"> + <h1 i18n-content="optionsLabel"></h1> + <div class="right-column"> + <div id="header-footer-option"> + <label> + <input id="header-footer" type="checkbox" checked> + <span i18n-content="optionHeaderFooter"></span> + </label> + </div> + <div id="fit-to-page-option"> + <label> + <input id="fit-to-page" type="checkbox" checked> + <span i18n-content="optionFitToPage"></span> + </label> + </div> + </div> +</div> diff --git a/chrome/browser/resources/print_preview/more_options.js b/chrome/browser/resources/print_preview/more_options.js new file mode 100644 index 0000000..68957af --- /dev/null +++ b/chrome/browser/resources/print_preview/more_options.js @@ -0,0 +1,93 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('print_preview', function() { + 'use strict'; + + /** + * Creates a MoreOptions object. This object encapsulates all + * settings and logic related to the more options section. + * @constructor + */ + function MoreOptions() { + // @type {HTMLDivElement} HTML element representing more options. + this.moreOptions_ = $('more-options'); + + // @type {boolean} True if header footer option is hidden. + this.hideHeaderFooterOption_ = true; + + // @type {boolean} True if fit to page option should be hidden. + this.hideFitToPageOption_ = true; + + this.addEventListeners_(); + } + + cr.addSingletonGetter(MoreOptions); + + MoreOptions.prototype = { + /** + * Adding listeners to more options section. + * @private + */ + addEventListeners_: function() { + document.addEventListener(customEvents.PDF_LOADED, + this.onPDFLoaded_.bind(this)); + document.addEventListener( + customEvents.HEADER_FOOTER_VISIBILITY_CHANGED, + this.onHeaderFooterVisibilityChanged_.bind(this)); + document.addEventListener(customEvents.PRINTER_SELECTION_CHANGED, + this.onPrinterSelectionChanged_.bind(this)); + }, + + /** + * Listener executing when a |customEvents.HEADER_FOOTER_VISIBILITY_CHANGED| + * event occurs. + * @param {cr.Event} event The event that triggered this listener. + * @private + */ + onHeaderFooterVisibilityChanged_: function(event) { + this.hideHeaderFooterOption_ = !event.headerFooterApplies; + this.updateVisibility_(); + }, + + /** + * Listener executing when a |customEvents.PRINTER_SEELCTION_CHANGED| event + * occurs. + * @param {cr.Event} event The event that triggered this listener. + * @private + */ + onPrinterSelectionChanged_: function(event) { + if (previewModifiable) + return; + this.hideFitToPageOption_ = event.selectedPrinter == PRINT_TO_PDF; + this.updateVisibility_(); + }, + + /** + * Listener executing when a |customEvents.PDF_LOADED| event occurs. + * @private + */ + onPDFLoaded_: function() { + if (previewModifiable) + this.hideHeaderFooterOption_ = false; + else + this.hideFitToPageOption_ = false; + }, + + /** + * Hides or shows |this.moreOptions_|. + * @private + */ + updateVisibility_: function() { + if (this.hideFitToPageOption_ && this.hideHeaderFooterOption_) + fadeOutOption(this.moreOptions_); + else + fadeInOption(this.moreOptions_); + } + }; + + return { + MoreOptions: MoreOptions + }; +}); diff --git a/chrome/browser/resources/print_preview/preview_area.js b/chrome/browser/resources/print_preview/preview_area.js index e2e6a1e9..ed5e92c 100644 --- a/chrome/browser/resources/print_preview/preview_area.js +++ b/chrome/browser/resources/print_preview/preview_area.js @@ -171,7 +171,7 @@ cr.define('print_preview', function() { * Resets the state variables of |this|. */ resetState: function() { - if (this.pdfPlugin_) { + if (this.pdfPlugin_ && previewModifiable) { this.zoomLevel_ = this.pdfPlugin_.getZoomLevel(); this.pageOffset_ = { x: this.pdfPlugin_.pageXOffset(), diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html index f8624d7..a4cdc2b 100644 --- a/chrome/browser/resources/print_preview/print_preview.html +++ b/chrome/browser/resources/print_preview/print_preview.html @@ -43,7 +43,7 @@ <include src="layout_settings.html"></include> <include src="color_settings.html"></include> <include src="margin_settings.html"></include> - <include src="header_footer_settings.html"></include> + <include src="more_options.html"></include> <div> <if expr="pp_ifdef('chromeos')"> <button id="system-dialog-link" diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js index 6cf5f4c..f47cb29 100644 --- a/chrome/browser/resources/print_preview/print_preview.js +++ b/chrome/browser/resources/print_preview/print_preview.js @@ -80,6 +80,13 @@ var marginSettings; // related settings. var headerFooterSettings; +// @type {print_preview.FitToPageSettings} Holds all the fit to page related +// settings. +var fitToPageSettings; + +// @type {print_preview.MoreOptions} Holds the more options implementation. +var moreOptions; + // @type {print_preview.ColorSettings} Holds all the color related settings. var colorSettings; @@ -119,6 +126,8 @@ var addedCloudPrinters = {}; // Names of all the custom events used. var customEvents = { + // Fired when the header footer option visibility changed. + HEADER_FOOTER_VISIBILITY_CHANGED: 'headerFooterVisibilityChanged', // Fired when the mouse moves while a margin line is being dragged. MARGIN_LINE_DRAG: 'marginLineDrag', // Fired when a mousedown event occurs on a margin line. @@ -133,6 +142,8 @@ var customEvents = { PDF_LOADED: 'PDFLoaded', // Fired when the selected printer capabilities change. PRINTER_CAPABILITIES_UPDATED: 'printerCapabilitiesUpdated', + // Fired when the destination printer is changed. + PRINTER_SELECTION_CHANGED: 'printerSelectionChanged', // Fired when the print button needs to be updated. UPDATE_PRINT_BUTTON: 'updatePrintButton', // Fired when the print summary needs to be updated. @@ -178,6 +189,8 @@ function onLoad() { layoutSettings = print_preview.LayoutSettings.getInstance(); marginSettings = print_preview.MarginSettings.getInstance(); headerFooterSettings = print_preview.HeaderFooterSettings.getInstance(); + fitToPageSettings = print_preview.FitToPageSettings.getInstance(); + moreOptions = print_preview.MoreOptions.getInstance(); colorSettings = print_preview.ColorSettings.getInstance(); $('printer-list').onchange = updateControlsWithSelectedPrinterCapabilities; @@ -278,6 +291,16 @@ function launchNativePrintDialog() { } /** + * Notifies listeners of |customEvents.PRINTER_SELECTION_CHANGED| event about + * the current selected printer. + */ +function dispatchPrinterSelectionChangedEvent() { + var customEvent = cr.Event(customEvents.PRINTER_SELECTION_CHANGED); + customEvent.selectedPrinter = getSelectedPrinterName(); + document.dispatchEvent(customEvent); +} + +/** * Gets the selected printer capabilities and updates the controls accordingly. */ function updateControlsWithSelectedPrinterCapabilities() { @@ -289,6 +312,7 @@ function updateControlsWithSelectedPrinterCapabilities() { $('open-pdf-in-preview-link').disabled = false; var skip_refresh = false; + var selectedPrinterChanged = true; var selectedValue = printerList.options[selectedIndex].value; if (cloudprint.isCloudPrint(printerList.options[selectedIndex])) { cloudprint.updatePrinterCaps(printerList.options[selectedIndex], @@ -300,6 +324,7 @@ function updateControlsWithSelectedPrinterCapabilities() { printerList.selectedIndex = lastSelectedPrinterIndex; chrome.send(selectedValue); skip_refresh = true; + selectedPrinterChanged = false; } else if (selectedValue == PRINT_TO_PDF || selectedValue == PRINT_WITH_CLOUD_PRINT) { updateWithPrinterCapabilities({ @@ -316,6 +341,9 @@ function updateControlsWithSelectedPrinterCapabilities() { // function. chrome.send('getPrinterCapabilities', [selectedValue]); } + if (selectedPrinterChanged) + dispatchPrinterSelectionChangedEvent(); + if (!skip_refresh) { lastSelectedPrinterIndex = selectedIndex; @@ -394,6 +422,16 @@ function finishedCloudPrinting() { } /** + * Updates the fit to page option state based on the print scaling option of + * source pdf. PDF's have an option to enable/disable print scaling. When we + * find out that the print scaling option is disabled for the source pdf, we + * uncheck the fit to page checkbox. This function is called from C++ code. + */ +function printScalingDisabledForSourcePDF() { + fitToPageSettings.onPrintScalingDisabled(); +} + +/** * Checks whether the specified settings are valid. * * @return {boolean} true if settings are valid, false if not. @@ -431,6 +469,7 @@ function getSettings() { 'marginsType': marginSettings.selectedMarginsValue, 'requestID': -1, 'generateDraftData': generateDraftData, + 'fitToPageEnabled': fitToPageSettings.hasFitToPage(), 'previewModifiable': previewModifiable}; if (marginSettings.isCustomMarginsSelected()) @@ -579,9 +618,9 @@ function loadSelectedPages() { } /** - * Asks the browser to generate a preview PDF based on current print settings. + * Updates the variables states for preview. */ -function requestPrintPreview() { +function updateStateForPreview() { if (!isTabHidden) previewArea.showLoadingAnimation(); @@ -604,8 +643,15 @@ function requestPrintPreview() { var totalPageCount = pageSettings.totalPageCount; if (!previewModifiable && totalPageCount > 0) generateDraftData = false; +} - var pageCount = totalPageCount != undefined ? totalPageCount : -1; +/** + * Asks the browser to generate a preview PDF based on current print settings. + */ +function requestPrintPreview() { + updateStateForPreview(); + var totalPageCount = pageSettings.totalPageCount; + var pageCount = totalPageCount || -1; chrome.send('getPreview', [JSON.stringify(getSettingsWithRequestID()), pageCount, previewModifiable]); @@ -828,6 +874,10 @@ function invalidPrinterSettings() { function onPDFLoad() { if (previewModifiable) { setPluginPreviewPageCount(); + } else { + // If the source is pdf, print ready metafile is available only after + // loading the pdf in the plugin. + isPrintReadyMetafileReady = true; } // Instruct the plugin which page numbers to display in the page number // indicator. @@ -911,6 +961,8 @@ function reloadPreviewPages(previewUid, previewResponseId) { if (!isExpectedPreviewResponse(previewResponseId)) return; + if (!previewModifiable) + previewArea.createOrReloadPDFPlugin(PRINT_READY_DATA_INDEX); cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON); checkAndHideOverlayLayerIfValid(); var pageSet = pageSettings.previouslySelectedPages; @@ -974,13 +1026,14 @@ function onDidPreviewPage(pageNumber, previewUid, previewResponseId) { function updatePrintPreview(previewUid, previewResponseId) { if (!isExpectedPreviewResponse(previewResponseId)) return; - isPrintReadyMetafileReady = true; if (!previewModifiable) { // If the preview is not modifiable the plugin has not been created yet. currentPreviewUid = previewUid; hasPendingPreviewRequest = false; previewArea.createOrReloadPDFPlugin(PRINT_READY_DATA_INDEX); + } else { + isPrintReadyMetafileReady = true; } cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON); @@ -1203,6 +1256,7 @@ window.addEventListener('keydown', onKeyDown); <include src="page_settings.js"/> <include src="copies_settings.js"/> <include src="header_footer_settings.js"/> +<include src="fit_to_page_settings.js"/> <include src="layout_settings.js"/> <include src="color_settings.js"/> <include src="margin_settings.js"/> @@ -1210,4 +1264,5 @@ window.addEventListener('keydown', onKeyDown); <include src="margin_utils.js"/> <include src="margins_ui.js"/> <include src="margins_ui_pair.js"/> +<include src="more_options.js"/> <include src="preview_area.js"/> diff --git a/chrome/browser/ui/webui/print_preview/print_preview_data_source.cc b/chrome/browser/ui/webui/print_preview/print_preview_data_source.cc index aec7143..3d53c1c 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_data_source.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_data_source.cc @@ -122,6 +122,8 @@ void PrintPreviewDataSource::Init() { AddLocalizedString("optionsLabel", IDS_PRINT_PREVIEW_OPTIONS_LABEL); AddLocalizedString("optionHeaderFooter", IDS_PRINT_PREVIEW_OPTION_HEADER_FOOTER); + AddLocalizedString("optionFitToPage", + IDS_PRINT_PREVIEW_OPTION_FIT_TO_PAGE); AddLocalizedString("marginsLabel", IDS_PRINT_PREVIEW_MARGINS_LABEL); AddLocalizedString("defaultMargins", IDS_PRINT_PREVIEW_DEFAULT_MARGINS); AddLocalizedString("noMargins", IDS_PRINT_PREVIEW_NO_MARGINS); diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index 6d1eea9..ef91c9d 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc @@ -321,3 +321,7 @@ void PrintPreviewUI::OnClosePrintPreviewTab() { void PrintPreviewUI::OnReloadPrintersList() { web_ui()->CallJavascriptFunction("reloadPrintersList"); } + +void PrintPreviewUI::OnPrintPreviewScalingDisabled() { + web_ui()->CallJavascriptFunction("printScalingDisabledForSourcePDF"); +} diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h index 8d08676..85e9e6c 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h @@ -140,6 +140,10 @@ class PrintPreviewUI : public ConstrainedWebDialogUI { // Reload the printers list. void OnReloadPrintersList(); + // Notifies the WebUI that the pdf print scaling option is disabled by + // default. + void OnPrintPreviewScalingDisabled(); + private: friend class PrintPreviewHandlerTest; FRIEND_TEST_ALL_PREFIXES(PrintPreviewHandlerTest, StickyMarginsCustom); diff --git a/chrome/common/print_messages.cc b/chrome/common/print_messages.cc index 5ec17d2..4e225f4 100644 --- a/chrome/common/print_messages.cc +++ b/chrome/common/print_messages.cc @@ -24,7 +24,7 @@ PrintMsg_Print_Params::PrintMsg_Print_Params() preview_ui_addr(), preview_request_id(0), is_first_request(false), - fit_to_paper_size(true), + fit_to_paper_size(false), print_to_pdf(false), display_header_footer(false), date(), @@ -50,7 +50,7 @@ void PrintMsg_Print_Params::Reset() { preview_ui_addr = std::string(); preview_request_id = 0; is_first_request = false; - fit_to_paper_size = true; + fit_to_paper_size = false; print_to_pdf = false; display_header_footer = false; date = string16(); diff --git a/chrome/common/print_messages.h b/chrome/common/print_messages.h index 126e3f6..0b14260 100644 --- a/chrome/common/print_messages.h +++ b/chrome/common/print_messages.h @@ -416,3 +416,7 @@ IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintPreviewInvalidPrinterSettings, // window.print() finishes. IPC_SYNC_MESSAGE_ROUTED1_0(PrintHostMsg_ScriptedPrintPreview, bool /* is_modifiable */) + +// Notify the browser that the PDF in the initiator renderer has disabled print +// scaling option. +IPC_MESSAGE_ROUTED0(PrintHostMsg_PrintPreviewScalingDisabled) diff --git a/chrome/renderer/print_web_view_helper.cc b/chrome/renderer/print_web_view_helper.cc index 106caa4..cab76b0 100644 --- a/chrome/renderer/print_web_view_helper.cc +++ b/chrome/renderer/print_web_view_helper.cc @@ -345,6 +345,15 @@ printing::MarginType GetMarginsForPdf(WebFrame* frame, const WebNode& node) { return printing::PRINTABLE_AREA_MARGINS; } +bool FitToPageEnabled(const DictionaryValue& job_settings) { + bool fit_to_paper_size = false; + if (!job_settings.GetBoolean(printing::kSettingFitToPageEnabled, + &fit_to_paper_size)) { + NOTREACHED(); + } + return fit_to_paper_size; +} + // Get the (x, y) coordinate from where printing of the current text should // start depending on the horizontal alignment (LEFT, RIGHT, CENTER) and // vertical alignment (TOP, BOTTOM). @@ -899,6 +908,36 @@ bool PrintWebViewHelper::IsPrintToPdfRequested( return print_to_pdf; } +bool PrintWebViewHelper::IsFitToPaperSizeRequested( + bool source_is_html, const DictionaryValue& job_settings, + const PrintMsg_Print_Params& params) { + DCHECK(!print_for_preview_); + + // Do not fit to paper size when the user is saving the print contents as pdf. + if (params.print_to_pdf) + return false; + + if (!source_is_html) { + if (!FitToPageEnabled(job_settings)) + return false; + + // Get the print scaling option for the initiator renderer pdf. + bool print_scaling_disabled_for_plugin = + print_preview_context_.frame()->isPrintScalingDisabledForPlugin( + print_preview_context_.node()); + + // If this is the first preview request, UI doesn't know about the print + // scaling option of the plugin. Therefore, check the print scaling option + // and update the print params accordingly. + // + // If this is not the first preview request, update print params based on + // preview job settings. + if (params.is_first_request && print_scaling_disabled_for_plugin) + return false; + } + return true; +} + void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) { DCHECK(is_preview_enabled_); print_preview_context_.OnPrintPreview(); @@ -933,6 +972,16 @@ void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) { preview_params)); return; } + + // If we are previewing a pdf and the print scaling is disabled, send a + // message to browser. + if (print_pages_params_->params.is_first_request && + !print_preview_context_.IsModifiable() && + print_preview_context_.frame()->isPrintScalingDisabledForPlugin( + print_preview_context_.node())) { + Send(new PrintHostMsg_PrintPreviewScalingDisabled(routing_id())); + } + // Always clear |old_print_pages_params_| before rendering the pages. old_print_pages_params_.reset(); is_print_ready_metafile_sent_ = false; @@ -1375,26 +1424,8 @@ bool PrintWebViewHelper::UpdatePrintSettings( modified_job_settings.MergeDictionary(job_settings); modified_job_settings.SetBoolean(printing::kSettingHeaderFooterEnabled, false); - - // - On Windows, we don't add a margin until we turn it into an EMF when - // printing for print preview (We could add it in the plugin). - // - On Mac with Skia, we don't add a margin until we send it to the printer - // using the CG PDF class (We could add it in the plugin). - // - On Mac with CG, we can add a margin when generating the preview. - // - On Linux, we never add a margin (We Could add it in the plugin). -#if defined(OS_MACOSX) && !defined(USE_SKIA) - bool get_margins_from_pdf = !source_is_html && !print_for_preview_; -#elif defined(OS_WIN) || defined(OS_MACOSX) - bool get_margins_from_pdf = !source_is_html && print_for_preview_; -#else - bool get_margins_from_pdf = false; -#endif - - printing::MarginType margin_type = printing::NO_MARGINS; - if (get_margins_from_pdf) - margin_type = GetMarginsForPdf(frame, node); modified_job_settings.SetInteger(printing::kSettingMarginsType, - margin_type); + printing::NO_MARGINS); job_settings = &modified_job_settings; } @@ -1445,12 +1476,10 @@ bool PrintWebViewHelper::UpdatePrintSettings( } settings.params.print_to_pdf = IsPrintToPdfRequested(*job_settings); + settings.params.fit_to_paper_size = IsFitToPaperSizeRequested( + source_is_html, *job_settings, settings.params); UpdateFrameMarginsCssInfo(*job_settings); - // Fit to paper size. - settings.params.fit_to_paper_size = source_is_html && - !IsPrintToPdfRequested(*job_settings); - // Header/Footer: Set |header_footer_info_|. if (settings.params.display_header_footer) { header_footer_info_.reset(new DictionaryValue()); @@ -1490,12 +1519,18 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(WebKit::WebFrame* frame, Send(new PrintHostMsg_DidShowPrintDialog(routing_id())); + // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the + // value before and restore it afterwards. + bool fit_to_paper_size = print_pages_params_->params.fit_to_paper_size; + print_pages_params_.reset(); IPC::SyncMessage* msg = new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings); msg->EnableMessagePumping(); Send(msg); print_pages_params_.reset(new PrintMsg_PrintPages_Params(print_settings)); + + print_pages_params_->params.fit_to_paper_size = fit_to_paper_size; return (print_settings.params.dpi && print_settings.params.document_cookie); } diff --git a/chrome/renderer/print_web_view_helper.h b/chrome/renderer/print_web_view_helper.h index 55a2e6b..86dc95d 100644 --- a/chrome/renderer/print_web_view_helper.h +++ b/chrome/renderer/print_web_view_helper.h @@ -160,6 +160,17 @@ class PrintWebViewHelper // Returns true if the current destination printer is PRINT_TO_PDF. bool IsPrintToPdfRequested(const base::DictionaryValue& settings); + // Returns false if + // (1) The current destination printer is SAVE_AS_PDF or + // (2) Source is PDF. This is the first preview request and print scaling + // option is disabled for initiator renderer plugin. + // (3) Source is PDF and the user has requested not to fit to printable area + // via |job_settings|. + // In all other cases returns true to fit the print contents in paper size. + bool IsFitToPaperSizeRequested(bool source_is_html, + const base::DictionaryValue& job_settings, + const PrintMsg_Print_Params& params); + // Initiate print preview. void OnInitiatePrintPreview(); diff --git a/chrome/test/data/webui/print_preview.js b/chrome/test/data/webui/print_preview.js index 70a0f03..4bf1114 100644 --- a/chrome/test/data/webui/print_preview.js +++ b/chrome/test/data/webui/print_preview.js @@ -23,6 +23,7 @@ PrintPreviewWebUITest.prototype = { * Register a mock handler to ensure expectations are met and print preview * behaves correctly. * @type {Function} + * @this {PrintPreviewWebUITest} * @override */ preLoad: function() { @@ -120,6 +121,7 @@ PrintPreviewWebUITest.prototype = { * empty methods, which are used by testing and that would be provided by the * HTMLEmbedElement when the PDF plugin exists. * @param {number} srcDataIndex Preview data source index. + * @this {PrintPreviewWebUITest} */ createOrReloadPDFPlugin: function(srcDataIndex) { var pdfViewer = $('pdf-viewer'); @@ -193,6 +195,13 @@ var fooIndex = 0; */ var barIndex = 1; +/** + * The expected "Save as PDF" option text returned by the stubbed handler. + * @type {string} + * @const + */ +var saveAsPDFOptionStr = 'Save as PDF'; + // Test some basic assumptions about the print preview WebUI. TEST_F('PrintPreviewWebUITest', 'TestPrinterList', function() { var printerList = $('printer-list'); @@ -250,6 +259,16 @@ function checkSectionVisible(section, visible) { 'section=' + section); } +/** + * Verify that |section| style display matches |value|. + * @param {HTMLDivElement} section The section to check. + * @param {string} value The expected display style value. + */ +function checkSectionDisplayStyle(section, value) { + assertNotEquals(null, section); + expectEquals(section.style.display, value, 'section=' + section); +} + // Test that disabled settings hide the disabled sections. TEST_F('PrintPreviewWebUITest', 'TestSectionsDisabled', function() { this.mockHandler.expects(once()).getPrinterCapabilities('FooDevice'). @@ -270,6 +289,120 @@ TEST_F('PrintPreviewWebUITest', 'TestSectionsDisabled', function() { checkSectionVisible(copiesSettings.copiesOption_, false); }); +// When the source is 'PDF' and 'Save as PDF' option is selected, we hide the +// fit to page option. +TEST_F('PrintPreviewWebUITest', 'PrintToPDFSelectedHideFitToPageOption', + function() { + var savedArgs = new SaveMockArguments(); + this.mockHandler.expects(once()).getPreview(savedArgs.match(ANYTHING)). + will(callFunctionWithSavedArgs(savedArgs, function(args) { + updatePrintPreview(2, JSON.parse(args[0]).requestID); + })); + + this.mockGlobals.expects(once()).updateWithPrinterCapabilities( + savedArgs.match(ANYTHING)). + will(callGlobalWithSavedArgs( + savedArgs, 'updateWithPrinterCapabilities')); + + setInitialSettings({previewModifiable: false}); + var printerList = $('printer-list'); + assertNotEquals(null, printerList, 'printerList'); + assertGE(printerList.options.length, printerListMinLength); + for (var i = 0; i < printerList.options.length; i++) { + if (printerList.options[i].text == saveAsPDFOptionStr && + printerList.options[i].value == saveAsPDFOptionStr) { + printerList.selectedIndex = i; + break; + } + } + updateControlsWithSelectedPrinterCapabilities(); + checkSectionDisplayStyle(fitToPageSettings.fitToPageOption_, 'none'); +}); + +// When the source is 'HTML', we always hide the fit to page option. +TEST_F('PrintPreviewWebUITest', 'SourceIsHTMLHideFitToPageOption', function() { + var savedArgs = new SaveMockArguments(); + this.mockHandler.expects(once()).getPreview(savedArgs.match(ANYTHING)). + will(callFunctionWithSavedArgs(savedArgs, function(args) { + updatePrintPreview(2, JSON.parse(args[0]).requestID); + })); + + this.mockGlobals.expects(once()).updateWithPrinterCapabilities( + savedArgs.match(ANYTHING)). + will(callGlobalWithSavedArgs( + savedArgs, 'updateWithPrinterCapabilities')); + + setInitialSettings({previewModifiable: true}); + var printerList = $('printer-list'); + assertNotEquals(null, printerList, 'printerList'); + assertGE(printerList.options.length, printerListMinLength); + updateControlsWithSelectedPrinterCapabilities(); + checkSectionDisplayStyle(fitToPageSettings.fitToPageOption_, 'none'); + expectTrue(fitToPageSettings.hasFitToPage()); +}); + +// When the source is "PDF", depending on the selected destination printer, we +// show/hide the fit to page option. +TEST_F('PrintPreviewWebUITest', 'SourceIsPDFShowFitToPageOption', function() { + var savedArgs = new SaveMockArguments(); + this.mockHandler.expects(once()).getPreview(savedArgs.match(ANYTHING)). + will(callFunctionWithSavedArgs(savedArgs, function(args) { + updatePrintPreview(2, JSON.parse(args[0]).requestID); + })); + + this.mockGlobals.expects(once()).updateWithPrinterCapabilities( + savedArgs.match(ANYTHING)). + will(callGlobalWithSavedArgs( + savedArgs, 'updateWithPrinterCapabilities')); + + setInitialSettings({previewModifiable: false}); + var printerList = $('printer-list'); + assertNotEquals(null, printerList, 'printerList'); + assertGE(printerList.options.length, printerListMinLength); + var saveAsPDFOptionSelected = false; + var selectedPrinterOption = printerList.options[printerList.selectedIndex]; + if (selectedPrinterOption.text == saveAsPDFOptionStr && + selectedPrinterOption.value == saveAsPDFOptionStr) { + saveAsPDFOptionSelected = true; + } + updateControlsWithSelectedPrinterCapabilities(); + checkSectionDisplayStyle(fitToPageSettings.fitToPageOption_, + saveAsPDFOptionSelected ? 'none' : 'block'); + expectTrue(fitToPageSettings.hasFitToPage()); +}); + +// When the print scaling is disabled for the source "PDF", we show the fit +// to page option but the state is unchecked by default. +TEST_F('PrintPreviewWebUITest', 'PrintScalingDisabledForPlugin', function() { + var savedArgs = new SaveMockArguments(); + this.mockHandler.expects(once()).getPreview(savedArgs.match(ANYTHING)). + will(callFunctionWithSavedArgs(savedArgs, function(args) { + updatePrintPreview(2, JSON.parse(args[0]).requestID); + })); + + this.mockGlobals.expects(once()).updateWithPrinterCapabilities( + savedArgs.match(ANYTHING)). + will(callGlobalWithSavedArgs( + savedArgs, 'updateWithPrinterCapabilities')); + + setInitialSettings({previewModifiable: false}); + var printerList = $('printer-list'); + assertNotEquals(null, printerList, 'printerList'); + assertGE(printerList.options.length, printerListMinLength); + var saveAsPDFOptionSelected = false; + var selectedPrinterOption = printerList.options[printerList.selectedIndex]; + if (selectedPrinterOption.text == saveAsPDFOptionStr && + selectedPrinterOption.value == saveAsPDFOptionStr) { + saveAsPDFOptionSelected = true; + } + updateControlsWithSelectedPrinterCapabilities(); + printScalingDisabledForSourcePDF(); + checkSectionDisplayStyle(fitToPageSettings.fitToPageOption_, + saveAsPDFOptionSelected ? 'none' : 'block'); + // Make sure the fit to page checkbox is unchecked. + expectFalse(fitToPageSettings.hasFitToPage()); +}); + // Page layout has zero margins. Hide header and footer option. TEST_F('PrintPreviewWebUITest', 'PageLayoutHasNoMarginsHideHeaderFooter', function() { @@ -278,7 +411,7 @@ TEST_F('PrintPreviewWebUITest', 'PageLayoutHasNoMarginsHideHeaderFooter', contentWidth: 100, contentHeight: 200, marginLeft: 0, marginRight: 0, marginTop: 0, marginBottom: 0, printableAreaX: 0, printableAreaY: 0, printableAreaWidth: 100, printableAreaHeight: 200}, true); - checkSectionVisible(headerFooterSettings.headerFooterOption_, false); + checkSectionDisplayStyle(headerFooterSettings.headerFooterOption_, 'none'); }); // Page layout has non-zero margins. Show header and footer option. @@ -289,7 +422,7 @@ TEST_F('PrintPreviewWebUITest', 'PageLayoutHasMarginsShowHeaderFooter', contentWidth: 100, contentHeight: 200, marginLeft: 3, marginRight: 2, marginTop: 4, marginBottom: 1, printableAreaX: 1, printableAreaY: 1, printableAreaWidth: 103, printableAreaHeight: 203}, true); - checkSectionVisible(headerFooterSettings.headerFooterOption_, true); + checkSectionDisplayStyle(headerFooterSettings.headerFooterOption_, 'block'); }); // Page layout has zero top and bottom margins. Hide header and footer option. @@ -300,7 +433,7 @@ TEST_F('PrintPreviewWebUITest', 'ZeroTopAndBottomMarginsHideHeaderFooter', contentWidth: 100, contentHeight: 200, marginLeft: 3, marginRight: 2, marginTop: 0, marginBottom: 0, printableAreaX: 1, printableAreaY: 1, printableAreaWidth: 98, printableAreaHeight: 198}, false); - checkSectionVisible(headerFooterSettings.headerFooterOption_, false); + checkSectionDisplayStyle(headerFooterSettings.headerFooterOption_, 'none'); }); // Page layout has zero top and non-zero bottom margin. Show header and footer @@ -312,7 +445,7 @@ TEST_F('PrintPreviewWebUITest', 'ZeroTopAndNonZeroBottomMarginShowHeaderFooter', contentWidth: 100, contentHeight: 200, marginLeft: 6, marginRight: 4, marginTop: 0, marginBottom: 3, printableAreaX: 1, printableAreaY: 1, printableAreaWidth: 103, printableAreaHeight: 208}, false); - checkSectionVisible(headerFooterSettings.headerFooterOption_, true); + checkSectionDisplayStyle(headerFooterSettings.headerFooterOption_, 'block'); }); // Test that the color settings are set according to the printer capabilities. diff --git a/printing/print_job_constants.cc b/printing/print_job_constants.cc index c5f0105..5448d26 100644 --- a/printing/print_job_constants.cc +++ b/printing/print_job_constants.cc @@ -42,6 +42,10 @@ const char kSettingDeviceName[] = "deviceName"; // Print job duplex mode. const char kSettingDuplexMode[] = "duplex"; +// Option to fit source page contents to printer paper size: true if +// selected else false. +const char kSettingFitToPageEnabled[] = "fitToPageEnabled"; + // True, when a new set of draft preview data is required. const char kSettingGenerateDraftData[] = "generateDraftData"; diff --git a/printing/print_job_constants.h b/printing/print_job_constants.h index 5f63f8f..b57495b 100644 --- a/printing/print_job_constants.h +++ b/printing/print_job_constants.h @@ -22,6 +22,7 @@ PRINTING_EXPORT extern const char kSettingContentWidth[]; PRINTING_EXPORT extern const char kSettingCopies[]; PRINTING_EXPORT extern const char kSettingDeviceName[]; PRINTING_EXPORT extern const char kSettingDuplexMode[]; +PRINTING_EXPORT extern const char kSettingFitToPageEnabled[]; PRINTING_EXPORT extern const char kSettingGenerateDraftData[]; PRINTING_EXPORT extern const char kSettingHeaderFooterEnabled[]; PRINTING_EXPORT extern const int kSettingHeaderFooterCharacterSpacing; |