diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/printing/print_preview_message_handler.cc | 28 | ||||
-rw-r--r-- | chrome/browser/printing/print_preview_message_handler.h | 5 | ||||
-rw-r--r-- | chrome/browser/resources/print_preview/page_settings.js | 16 | ||||
-rw-r--r-- | chrome/browser/resources/print_preview/print_preview.js | 77 | ||||
-rw-r--r-- | chrome/common/print_messages.h | 13 | ||||
-rw-r--r-- | chrome/renderer/mock_printer.cc | 4 | ||||
-rw-r--r-- | chrome/renderer/mock_printer.h | 3 | ||||
-rw-r--r-- | chrome/renderer/mock_render_thread.cc | 29 | ||||
-rw-r--r-- | chrome/renderer/mock_render_thread.h | 2 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper.cc | 143 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper.h | 44 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_browsertest.cc | 77 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_linux.cc | 24 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_mac.mm | 87 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_win.cc | 31 |
15 files changed, 406 insertions, 177 deletions
diff --git a/chrome/browser/printing/print_preview_message_handler.cc b/chrome/browser/printing/print_preview_message_handler.cc index 11be054..e853e81 100644 --- a/chrome/browser/printing/print_preview_message_handler.cc +++ b/chrome/browser/printing/print_preview_message_handler.cc @@ -82,9 +82,11 @@ void PrintPreviewMessageHandler::OnRequestPrintPreview() { PrintPreviewTabController::PrintPreview(tab_contents()); } -void PrintPreviewMessageHandler::OnDidGetPreviewPageCount(int document_cookie, - int page_count, - bool is_modifiable) { +void PrintPreviewMessageHandler::OnDidGetPreviewPageCount( + int document_cookie, + int page_count, + bool is_modifiable, + bool clear_preview_data) { if (page_count <= 0) return; @@ -94,6 +96,10 @@ void PrintPreviewMessageHandler::OnDidGetPreviewPageCount(int document_cookie, PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(print_preview_tab->web_ui()); + + if (!is_modifiable || clear_preview_data) + print_preview_ui->ClearAllPreviewData(); + print_preview_ui->OnDidGetPreviewPageCount( document_cookie, page_count, is_modifiable); } @@ -119,12 +125,7 @@ void PrintPreviewMessageHandler::OnDidPreviewPage( return; } - int requested_preview_page_index = INVALID_PAGE_INDEX; int page_number = params.page_number; - - if (page_number == FIRST_PAGE_INDEX) - print_preview_ui->ClearAllPreviewData(); - if (page_number >= FIRST_PAGE_INDEX && params.data_size) { RefCountedBytes* data_bytes = GetDataFromHandle(params.metafile_data_handle, params.data_size); @@ -132,15 +133,12 @@ void PrintPreviewMessageHandler::OnDidPreviewPage( print_preview_ui->SetPrintPreviewDataForIndex(page_number, data_bytes); print_preview_ui->OnDidPreviewPage(page_number); - // TODO(kmadhusu): Query |PrintPreviewUI| and update - // |requested_preview_page_index| accordingly. } - rvh->Send(new PrintMsg_ContinuePreview(rvh->routing_id(), - requested_preview_page_index)); + rvh->Send(new PrintMsg_ContinuePreview(rvh->routing_id())); } -void PrintPreviewMessageHandler::OnPagesReadyForPreview( +void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( const PrintHostMsg_DidPreviewDocument_Params& params) { StopWorker(params.document_cookie); @@ -218,8 +216,8 @@ bool PrintPreviewMessageHandler::OnMessageReceived( OnDidGetPreviewPageCount) IPC_MESSAGE_HANDLER(PrintHostMsg_DidPreviewPage, OnDidPreviewPage) - IPC_MESSAGE_HANDLER(PrintHostMsg_PagesReadyForPreview, - OnPagesReadyForPreview) + IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting, + OnMetafileReadyForPrinting) IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed, OnPrintPreviewFailed) IPC_MESSAGE_UNHANDLED(handled = false) diff --git a/chrome/browser/printing/print_preview_message_handler.h b/chrome/browser/printing/print_preview_message_handler.h index ff56b01..cd056e7 100644 --- a/chrome/browser/printing/print_preview_message_handler.h +++ b/chrome/browser/printing/print_preview_message_handler.h @@ -33,10 +33,11 @@ class PrintPreviewMessageHandler : public TabContentsObserver { void OnRequestPrintPreview(); void OnDidGetPreviewPageCount(int document_cookie, int page_count, - bool is_modifiable); + bool is_modifiable, + bool clear_preview_data); // |page_number| is 0-based. void OnDidPreviewPage(const PrintHostMsg_DidPreviewPage_Params& params); - void OnPagesReadyForPreview( + void OnMetafileReadyForPrinting( const PrintHostMsg_DidPreviewDocument_Params& params); void OnPrintPreviewFailed(int document_cookie); diff --git a/chrome/browser/resources/print_preview/page_settings.js b/chrome/browser/resources/print_preview/page_settings.js index 48210c6..28f70bf 100644 --- a/chrome/browser/resources/print_preview/page_settings.js +++ b/chrome/browser/resources/print_preview/page_settings.js @@ -177,9 +177,8 @@ cr.define('print_preview', function() { /** * Updates |this.previouslySelectedPages_| with the currently selected * pages. - * @private */ - updatePageSelection_: function() { + updatePageSelection: function() { this.previouslySelectedPages_ = this.selectedPagesSet; }, @@ -194,6 +193,14 @@ cr.define('print_preview', function() { }, /** + * Checks if the page selection has changed and is valid. + * @return {boolean} true if the page selection is changed and is valid. + */ + hasPageSelectionChangedAndIsValid: function() { + return this.isPageSelectionValid() && this.hasPageSelectionChanged_(); + }, + + /** * Validates the contents of |this.selectedPagesTextfield|. * * @return {boolean} true if the text is valid. @@ -212,8 +219,8 @@ cr.define('print_preview', function() { * @return {boolean} true if a new preview was requested. */ requestPrintPreviewIfNeeded: function() { - if (this.isPageSelectionValid() && this.hasPageSelectionChanged_()) { - this.updatePageSelection_(); + if (this.hasPageSelectionChangedAndIsValid()) { + this.updatePageSelection(); requestPrintPreview(); return true; } @@ -274,7 +281,6 @@ cr.define('print_preview', function() { cr.dispatchSimpleEvent(document, 'updatePrintButton'); return; } - this.previouslySelectedPages_ = this.selectedPagesSet; requestPrintPreview(); }, diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js index 47c455d..4a92c1d 100644 --- a/chrome/browser/resources/print_preview/print_preview.js +++ b/chrome/browser/resources/print_preview/print_preview.js @@ -23,6 +23,7 @@ const MANAGE_LOCAL_PRINTERS = 'manageLocalPrinters'; const MORE_PRINTERS = 'morePrinters'; const SIGN_IN = 'signIn'; const PRINT_TO_PDF = 'Print to PDF'; +const COMPLETE_PREVIEW_DATA_INDEX = -1; // State of the print preview settings. var printSettings = new PrintSettings(); @@ -62,6 +63,11 @@ var showingSystemDialog = false; var firstCloudPrintOptionPos = 0; var lastCloudPrintOptionPos = firstCloudPrintOptionPos; +// Store the current previewUid. +var currentPreviewUid = ''; + +// True if we need to generate draft preview data. +var generateDraftData = true; // TODO(abodenha@chromium.org) A lot of cloud print specific logic has // made its way into this file. Refactor to create a cleaner boundary @@ -311,7 +317,8 @@ function getSettings() { 'landscape': layoutSettings.isLandscape(), 'color': colorSettings.isColor(), 'printToPDF': printToPDF, - 'requestID': 0}; + 'requestID': 0, + 'generateDraftData': generateDraftData}; var printerList = $('printer-list'); var selectedPrinter = printerList.selectedIndex; @@ -421,15 +428,42 @@ function sendPrintDocumentRequest() { } /** + * Loads the selected preview pages. + */ +function loadSelectedPages() { + hasPendingPreviewRequest = false; + pageSettings.updatePageSelection(); + var pageSet = pageSettings.previouslySelectedPages; + var pageCount = pageSet.length; + if (pageCount == 0 || currentPreviewUid == '') + return; + + for (var i = 0; i < pageCount; i++) + onDidPreviewPage(pageSet[i] - 1, currentPreviewUid); + addEventListeners(); +} + +/** * Asks the browser to generate a preview PDF based on current print settings. */ function requestPrintPreview() { hasPendingPreviewRequest = true; removeEventListeners(); printSettings.save(); + generateDraftData = true; if (!isTabHidden) showLoadingAnimation(); + if (previewModifiable && hasOnlyPageSettingsChanged()) { + loadSelectedPages(); + generateDraftData = false; + } else { + pageSettings.updatePageSelection(); + } + + if (!previewModifiable && pageSettings.totalPageCount > 0) + generateDraftData = false; + var settings = getSettings(); settings.requestID = generatePreviewRequestID(); chrome.send('getPreview', [JSON.stringify(settings)]); @@ -829,12 +863,16 @@ function onDidPreviewPage(pageNumber, previewUid) { if (!previewModifiable) return; - var pageIndex = pageSettings.previouslySelectedPages.indexOf(pageNumber + 1); - if (checkIfSettingsChangedAndRegeneratePreview()) return; + + var pageIndex = pageSettings.previouslySelectedPages.indexOf(pageNumber + 1); + if (pageIndex == -1) + return; + + currentPreviewUid = previewUid; if (pageIndex == 0) - createPDFPlugin(previewUid); + createPDFPlugin(pageNumber); $('pdf-viewer').loadPreviewPage( getPageSrcURL(previewUid, pageNumber), pageIndex); @@ -864,7 +902,8 @@ function updatePrintPreview(jobTitle, if (!previewModifiable) { // If the preview is not modifiable the plugin has not been created yet. - createPDFPlugin(previewUid); + currentPreviewUid = previewUid; + createPDFPlugin(COMPLETE_PREVIEW_DATA_INDEX); } cr.dispatchSimpleEvent(document, 'updateSummary'); @@ -898,28 +937,41 @@ function checkIfSettingsChangedAndRegeneratePreview() { } /** + * Check if only page selection has been changed since the last preview request + * and is valid. + * @return {boolean} true if the new page selection is valid. + */ +function hasOnlyPageSettingsChanged() { + var tempPrintSettings = new PrintSettings(); + tempPrintSettings.save(); + + return !!(printSettings.deviceName == tempPrintSettings.deviceName && + printSettings.isLandscape == tempPrintSettings.isLandscape && + pageSettings.hasPageSelectionChangedAndIsValid()); +} + +/** * Create the PDF plugin or reload the existing one. - * @param {string} previewUid Preview unique identifier. + * @param {number} srcDataIndex Preview data source index. */ -function createPDFPlugin(previewUid) { +function createPDFPlugin(srcDataIndex) { var pdfViewer = $('pdf-viewer'); + var srcURL = getPageSrcURL(currentPreviewUid, srcDataIndex); if (pdfViewer) { // Need to call this before the reload(), where the plugin resets its // internal page count. pdfViewer.goToPage('0'); + pdfViewer.resetPrintPreviewUrl(srcURL); pdfViewer.reload(); pdfViewer.grayscale(!colorSettings.isColor()); return; } - // Get the complete preview document. - var dataIndex = previewModifiable ? '0' : '-1'; - pdfViewer = document.createElement('embed'); pdfViewer.setAttribute('id', 'pdf-viewer'); pdfViewer.setAttribute('type', 'application/x-google-chrome-print-preview-pdf'); - pdfViewer.setAttribute('src', getPageSrcURL(previewUid, dataIndex)); + pdfViewer.setAttribute('src', srcURL); pdfViewer.setAttribute('aria-live', 'polite'); pdfViewer.setAttribute('aria-atomic', 'true'); $('mainview').appendChild(pdfViewer); @@ -937,7 +989,8 @@ function checkCompatiblePluginExists() { dummyPlugin.goToPage && dummyPlugin.removePrintButton && dummyPlugin.loadPreviewPage && - dummyPlugin.printPreviewPageCount); + dummyPlugin.printPreviewPageCount && + dummyPlugin.resetPrintPreviewUrl); } window.addEventListener('DOMContentLoaded', onLoad); diff --git a/chrome/common/print_messages.h b/chrome/common/print_messages.h index 618ece5..e9d24e3 100644 --- a/chrome/common/print_messages.h +++ b/chrome/common/print_messages.h @@ -187,11 +187,7 @@ IPC_MESSAGE_ROUTED0(PrintMsg_PrintForSystemDialog) IPC_MESSAGE_ROUTED0(PrintMsg_ResetScriptedPrintCount) // Tells a renderer to continue generating the print preview. -// Use |requested_preview_page_index| to request a specific preview page data. -// |requested_preview_page_index| is 1-based or |printing::INVALID_PAGE_INDEX| -// to render the next page. -IPC_MESSAGE_ROUTED1(PrintMsg_ContinuePreview, - int /* requested_preview_page_index */) +IPC_MESSAGE_ROUTED0(PrintMsg_ContinuePreview) // Tells a renderer to abort the print preview and reset all state. IPC_MESSAGE_ROUTED0(PrintMsg_AbortPreview) @@ -259,10 +255,11 @@ IPC_MESSAGE_CONTROL1(PrintHostMsg_TempFileForPrintingWritten, IPC_MESSAGE_ROUTED0(PrintHostMsg_RequestPrintPreview) // Notify the browser the number of pages in the print preview document. -IPC_MESSAGE_ROUTED3(PrintHostMsg_DidGetPreviewPageCount, +IPC_MESSAGE_ROUTED4(PrintHostMsg_DidGetPreviewPageCount, int /* document cookie */, int /* page count */, - bool /* is modifiable */) + bool /* is modifiable */, + bool /* clear all preview data */) // Notify the browser a print preview page has been rendered. IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPreviewPage, @@ -271,7 +268,7 @@ IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPreviewPage, // Sends back to the browser the complete rendered document for print preview // that was requested by a PrintMsg_PrintPreview message. The memory handle in // this message is already valid in the browser process. -IPC_MESSAGE_ROUTED1(PrintHostMsg_PagesReadyForPreview, +IPC_MESSAGE_ROUTED1(PrintHostMsg_MetafileReadyForPrinting, PrintHostMsg_DidPreviewDocument_Params /* params */) // Tell the browser printing failed. diff --git a/chrome/renderer/mock_printer.cc b/chrome/renderer/mock_printer.cc index 6fa65cc..20bb28c 100644 --- a/chrome/renderer/mock_printer.cc +++ b/chrome/renderer/mock_printer.cc @@ -94,10 +94,12 @@ void MockPrinter::ScriptedPrint(int cookie, } void MockPrinter::UpdateSettings(int cookie, - PrintMsg_PrintPages_Params* params) { + PrintMsg_PrintPages_Params* params, + const std::vector<int>& pages) { EXPECT_EQ(document_cookie_, cookie); memset(params, 0, sizeof(PrintMsg_PrintPages_Params)); + params->pages = pages; SetPrintParams(&(params->params)); printer_status_ = PRINTER_PRINTING; } diff --git a/chrome/renderer/mock_printer.h b/chrome/renderer/mock_printer.h index 1c2994c..09fc466 100644 --- a/chrome/renderer/mock_printer.h +++ b/chrome/renderer/mock_printer.h @@ -75,7 +75,8 @@ class MockPrinter { int expected_pages_count, bool has_selection, PrintMsg_PrintPages_Params* settings); - void UpdateSettings(int cookie, PrintMsg_PrintPages_Params* params); + void UpdateSettings(int cookie, PrintMsg_PrintPages_Params* params, + const std::vector<int>& page_range_array); void SetPrintedPagesCount(int cookie, int number_pages); void PrintPage(const PrintHostMsg_DidPrintPage_Params& params); diff --git a/chrome/renderer/mock_render_thread.cc b/chrome/renderer/mock_render_thread.cc index aac7156..1a66d41 100644 --- a/chrome/renderer/mock_render_thread.cc +++ b/chrome/renderer/mock_render_thread.cc @@ -16,6 +16,7 @@ #include "ipc/ipc_message_utils.h" #include "ipc/ipc_sync_message.h" #include "printing/print_job_constants.h" +#include "printing/page_range.h" #include "testing/gtest/include/gtest/gtest.h" MockRenderThread::MockRenderThread() @@ -213,7 +214,8 @@ void MockRenderThread::OnDidPrintPage( void MockRenderThread::OnDidGetPreviewPageCount(int document_cookie, int number_pages, - bool is_modifiable) { + bool is_modifiable, + bool clear_preview_data) { print_preview_pages_remaining_ = number_pages; } @@ -242,8 +244,29 @@ void MockRenderThread::OnUpdatePrintSettings( } // Just return the default settings. - if (printer_.get()) - printer_->UpdateSettings(document_cookie, params); + if (printer_.get()) { + ListValue* page_range_array = new ListValue(); + printing::PageRanges new_ranges; + if (job_settings.GetList(printing::kSettingPageRange, &page_range_array)) { + for (size_t index = 0; index < page_range_array->GetSize(); ++index) { + DictionaryValue* dict; + if (!page_range_array->GetDictionary(index, &dict)) + continue; + printing::PageRange range; + if (!dict->GetInteger(printing::kSettingPageRangeFrom, &range.from) || + !dict->GetInteger(printing::kSettingPageRangeTo, &range.to)) { + continue; + } + // Page numbers are 1-based in the dictionary. + // Page numbers are 0-based for the printing context. + range.from--; + range.to--; + new_ranges.push_back(range); + } + } + std::vector<int> pages(printing::PageRange::GetPages(new_ranges)); + printer_->UpdateSettings(document_cookie, params, pages); + } } void MockRenderThread::set_print_dialog_user_response(bool response) { diff --git a/chrome/renderer/mock_render_thread.h b/chrome/renderer/mock_render_thread.h index 5eb7ad3..eac4e41 100644 --- a/chrome/renderer/mock_render_thread.h +++ b/chrome/renderer/mock_render_thread.h @@ -126,7 +126,7 @@ class MockRenderThread : public RenderThreadBase { void OnDidGetPrintedPagesCount(int cookie, int number_pages); void OnDidPrintPage(const PrintHostMsg_DidPrintPage_Params& params); void OnDidGetPreviewPageCount(int document_cookie, int number_pages, - bool is_modifiable); + bool is_modifiable, bool clear_preview_data); void OnDidPreviewPage(const PrintHostMsg_DidPreviewPage_Params& params); // For print preview, PrintWebViewHelper will update settings. diff --git a/chrome/renderer/print_web_view_helper.cc b/chrome/renderer/print_web_view_helper.cc index b065f31..948fd6e 100644 --- a/chrome/renderer/print_web_view_helper.cc +++ b/chrome/renderer/print_web_view_helper.cc @@ -177,6 +177,7 @@ PrintWebViewHelper::PrintWebViewHelper(RenderView* render_view) RenderViewObserverTracker<PrintWebViewHelper>(render_view), print_web_view_(NULL), is_preview_(switches::IsPrintPreviewEnabled()), + is_print_ready_metafile_sent_(false), user_cancelled_scripted_print_count_(0), notify_browser_of_print_failure_(true) { } @@ -313,7 +314,6 @@ void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) { NOTREACHED(); return; } - if (!UpdatePrintSettings(settings)) { DidFinishPrinting(FAIL_PREVIEW); return; @@ -334,14 +334,24 @@ void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) { preview_params.preview_request_id = print_pages_params_->params.preview_request_id; - Send(new PrintHostMsg_PagesReadyForPreview(routing_id(), preview_params)); + Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), + preview_params)); return; } // Always clear |old_print_pages_params_| before rendering the pages. old_print_pages_params_.reset(); + is_print_ready_metafile_sent_ = false; // PDF printer device supports alpha blending. print_pages_params_->params.supports_alpha_blend = true; + + bool generate_draft_pages; + if (!settings.GetBoolean(printing::kSettingGenerateDraftData, + &generate_draft_pages)) { + NOTREACHED(); + } + print_preview_context_.set_generate_draft_pages(generate_draft_pages); + if (!CreatePreviewDocument()) DidFinishPrinting(FAIL_PREVIEW); } @@ -354,38 +364,39 @@ bool PrintWebViewHelper::CreatePreviewDocument() { int page_count = print_preview_context_.total_page_count(); bool is_modifiable = print_preview_context_.IsModifiable(); int document_cookie = print_pages_params_->params.document_cookie; - Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), document_cookie, - page_count, is_modifiable)); + Send(new PrintHostMsg_DidGetPreviewPageCount( + routing_id(), + document_cookie, + page_count, + is_modifiable, + print_preview_context_.generate_draft_pages())); PreviewPageRendered(printing::INVALID_PAGE_INDEX, NULL); return true; } -void PrintWebViewHelper::OnContinuePreview(int requested_preview_page_index) { +void PrintWebViewHelper::OnContinuePreview() { // Spurious message. We already finished/cancelled/aborted the print preview. if (!print_preview_context_.IsBusy()) return; - int page_number; -#if defined(USE_SKIA) - if (requested_preview_page_index >= printing::FIRST_PAGE_INDEX) { - page_number = requested_preview_page_index; - } else -#endif - { - page_number = print_preview_context_.GetNextPageNumber(); - } + int page_number = print_preview_context_.GetNextPageNumber(); if (page_number >= printing::FIRST_PAGE_INDEX) { // Continue generating the print preview. RenderPreviewPage(page_number); - return; } - // Finished generating preview. Finalize the document. - if (FinalizePreviewDocument()) { + if (print_preview_context_.IsFinalPageRendered()) + print_preview_context_.AllPagesRendered(); + + if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) { + // Finished generating preview. Finalize the document. + if (!FinalizePrintReadyDocument()) + DidFinishPrinting(FAIL_PREVIEW); + } + + if (page_number == printing::INVALID_PAGE_INDEX) { print_preview_context_.Finished(); DidFinishPrinting(OK); - } else { - DidFinishPrinting(FAIL_PREVIEW); } } @@ -394,8 +405,9 @@ void PrintWebViewHelper::OnAbortPreview() { return; } -bool PrintWebViewHelper::FinalizePreviewDocument() { - print_preview_context_.FinalizePreviewDocument(); +bool PrintWebViewHelper::FinalizePrintReadyDocument() { + DCHECK(!is_print_ready_metafile_sent_); + print_preview_context_.FinalizePrintReadyDocument(); // Get the size of the resulting metafile. printing::PreviewMetafile* metafile = print_preview_context_.metafile(); @@ -417,7 +429,9 @@ bool PrintWebViewHelper::FinalizePreviewDocument() { &(preview_params.metafile_data_handle))) { return false; } - Send(new PrintHostMsg_PagesReadyForPreview(routing_id(), preview_params)); + is_print_ready_metafile_sent_ = true; + + Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params)); return true; } @@ -911,7 +925,8 @@ void PrintWebViewHelper::PreviewPageRendered(int page_number, printing::Metafile* metafile) { if ((page_number == printing::INVALID_PAGE_INDEX && metafile) || (page_number >= printing::FIRST_PAGE_INDEX && !metafile && - print_preview_context_.IsModifiable())) { + print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages())) { NOTREACHED(); DidFinishPrinting(FAIL_PREVIEW); return; @@ -937,8 +952,9 @@ void PrintWebViewHelper::PreviewPageRendered(int page_number, PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext() : frame_(NULL), total_page_count_(0), - actual_page_count_(0), - current_page_number_(0), + render_page_list_index_(-1), + generate_draft_pages_(true), + print_ready_metafile_page_count_(0), state_(UNINITIALIZED) { } @@ -992,23 +1008,23 @@ bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument( if (total_page_count_ == 0) return false; - current_page_number_ = 0; - if (pages.empty()) { - actual_page_count_ = total_page_count_; - rendered_pages_ = std::vector<PreviewPageInfo>(total_page_count_, - std::make_pair(false, -1)); - } else { - actual_page_count_ = pages.size(); - rendered_pages_ = std::vector<PreviewPageInfo>(total_page_count_, - std::make_pair(true, -1)); - for (int i = 0; i < actual_page_count_; ++i) { - int page_number = pages[i]; - if (page_number < printing::FIRST_PAGE_INDEX || - page_number >= total_page_count_) { - return false; + int selected_page_count = pages.size(); + render_page_list_index_ = -1; + print_ready_metafile_page_count_ = pages.empty() ? total_page_count_ : + selected_page_count; + render_page_list_ = pages; + if (selected_page_count == 0) { + // Render all pages. + for (int i = 0; i < total_page_count_; i++) + render_page_list_.push_back(i); + } else if (generate_draft_pages_) { + int pages_index = 0; + for (int i = 0; i < total_page_count_; i++) { + if (pages_index < selected_page_count && i == pages[pages_index]) { + pages_index++; + continue; } - rendered_pages_[page_number].first = false; - rendered_pages_[page_number].second = i; + render_page_list_.push_back(i); } } @@ -1025,16 +1041,20 @@ void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage( UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time); } -void PrintWebViewHelper::PrintPreviewContext::FinalizePreviewDocument() { +void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() { DCHECK_EQ(RENDERING, state_); state_ = DONE; + prep_frame_view_->FinishPrinting(); +} - base::TimeTicks begin_time = base::TimeTicks::Now(); +void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() { + if (state_ != DONE && state_ != RENDERING) + NOTREACHED(); - prep_frame_view_->FinishPrinting(); + base::TimeTicks begin_time = base::TimeTicks::Now(); metafile_->FinishDocument(); - if (actual_page_count_ <= 0) { + if (print_ready_metafile_page_count_ <= 0) { NOTREACHED(); return; } @@ -1046,7 +1066,7 @@ void PrintWebViewHelper::PrintPreviewContext::FinalizePreviewDocument() { UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime", total_time); UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage", - total_time / actual_page_count_); + total_time / render_page_list_.size()); } void PrintWebViewHelper::PrintPreviewContext::Finished() { @@ -1069,15 +1089,10 @@ void PrintWebViewHelper::PrintPreviewContext::Abort() { int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() { DCHECK_EQ(RENDERING, state_); - for (int i = 0; i < total_page_count_; i++) { - if (!rendered_pages_[current_page_number_].first) - break; - current_page_number_ = (current_page_number_ + 1) % total_page_count_; - } - if (rendered_pages_[current_page_number_].first) + if (IsFinalPageRendered()) return printing::INVALID_PAGE_INDEX; - rendered_pages_[current_page_number_].first = true; - return current_page_number_; + render_page_list_index_++; + return render_page_list_[render_page_list_index_]; } bool PrintWebViewHelper::PrintPreviewContext::IsReadyToRender() const { @@ -1098,6 +1113,20 @@ bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() const { return mime != "application/pdf"; } +bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile() + const { + return render_page_list_index_ == print_ready_metafile_page_count_ - 1; +} + +bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const { + return (size_t)(render_page_list_index_ + 1) == render_page_list_.size(); +} + +void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages( + bool generate_draft_pages) { + generate_draft_pages_ = generate_draft_pages; +} + WebKit::WebFrame* PrintWebViewHelper::PrintPreviewContext::frame() const { return frame_; } @@ -1110,6 +1139,10 @@ int PrintWebViewHelper::PrintPreviewContext::total_page_count() const { return total_page_count_; } +bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() { + return generate_draft_pages_; +} + printing::PreviewMetafile* PrintWebViewHelper::PrintPreviewContext::metafile() const { return metafile_.get(); @@ -1128,5 +1161,5 @@ PrintWebViewHelper::PrintPreviewContext::GetPrintCanvasSize() const { void PrintWebViewHelper::PrintPreviewContext::ClearContext() { prep_frame_view_.reset(); metafile_.reset(); - rendered_pages_.clear(); + render_page_list_.clear(); } diff --git a/chrome/renderer/print_web_view_helper.h b/chrome/renderer/print_web_view_helper.h index 0407c85..9826c83 100644 --- a/chrome/renderer/print_web_view_helper.h +++ b/chrome/renderer/print_web_view_helper.h @@ -6,7 +6,6 @@ #define CHROME_RENDERER_PRINT_WEB_VIEW_HELPER_H_ #pragma once -#include <utility> #include <vector> #include "base/memory/scoped_ptr.h" @@ -110,6 +109,8 @@ class PrintWebViewHelper : public RenderViewObserver, OnPrintForPrintPreview); FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperPreviewTest, OnPrintForPrintPreviewFail); + FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperPreviewTest, + OnPrintPreviewForSelectedPages); #if defined(OS_WIN) || defined(OS_MACOSX) FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, PrintLayoutTest); @@ -136,14 +137,12 @@ class PrintWebViewHelper : public RenderViewObserver, // Initialize the print preview document. bool CreatePreviewDocument(); - // Continue generating the print preview. |requested_preview_page_index| - // specifies the browser requested preview page index. It is 1-based or - // |printing::INVALID_PAGE_INDEX| to continue with next page. - void OnContinuePreview(int requested_preview_page_index); + // Continue generating the print preview. + void OnContinuePreview(); // Renders a print preview page. |page_number| is 0-based. void RenderPreviewPage(int page_number); - // Finalize the print preview document. - bool FinalizePreviewDocument(); + // Finalize the print ready preview document. + bool FinalizePrintReadyDocument(); // Abort the preview to put |print_preview_context_| into the 'UNINITIALIZED' // state. @@ -298,6 +297,7 @@ class PrintWebViewHelper : public RenderViewObserver, scoped_ptr<PrintMsg_PrintPages_Params> print_pages_params_; bool is_preview_; + bool is_print_ready_metafile_sent_; // Used for scripted initiated printing blocking. base::Time last_cancelled_script_print_; @@ -331,8 +331,11 @@ class PrintWebViewHelper : public RenderViewObserver, // rendering took. void RenderedPreviewPage(const base::TimeDelta& page_time); - // Finalizes the print preview document. - void FinalizePreviewDocument(); + // Updates the print preview context when the required pages are rendered. + void AllPagesRendered(); + + // Finalizes the print ready preview document. + void FinalizePrintReadyDocument(); // Cleanup after print preview finishes. void Finished(); @@ -348,11 +351,17 @@ class PrintWebViewHelper : public RenderViewObserver, bool IsReadyToRender() const; bool IsBusy() const; bool IsModifiable() const; + bool IsLastPageOfPrintReadyMetafile() const; + bool IsFinalPageRendered() const; + + // Setters + void set_generate_draft_pages(bool generate_draft_pages); // Getters WebKit::WebFrame* frame() const; WebKit::WebNode* node() const; int total_page_count() const; + bool generate_draft_pages(); printing::PreviewMetafile* metafile() const; const PrintMsg_Print_Params& print_params() const; const gfx::Size& GetPrintCanvasSize() const; @@ -379,16 +388,17 @@ class PrintWebViewHelper : public RenderViewObserver, // Total page count in the renderer. int total_page_count_; - // Number of pages to render. - int actual_page_count_; + // List of page indices that need to be rendered. + std::vector<int> render_page_list_; + + // Specifies the current list index. + int render_page_list_index_; - // The current page to render. - int current_page_number_; + // True, when draft pages needs to be generated. + bool generate_draft_pages_; - // |rendered_pages_| tracks which pages need to be printed as well as - // the page slot it should be printed in. See GetPageSlotForPage. - typedef std::pair<bool, int> PreviewPageInfo; - std::vector<PreviewPageInfo> rendered_pages_; + // Specifies the total number of pages in the print ready metafile. + int print_ready_metafile_page_count_; base::TimeDelta document_render_time_; base::TimeTicks begin_time_; diff --git a/chrome/renderer/print_web_view_helper_browsertest.cc b/chrome/renderer/print_web_view_helper_browsertest.cc index d897736..b50493c 100644 --- a/chrome/renderer/print_web_view_helper_browsertest.cc +++ b/chrome/renderer/print_web_view_helper_browsertest.cc @@ -42,6 +42,7 @@ void CreatePrintSettingsDictionary(DictionaryValue* dict) { dict->SetInteger(printing::kSettingCopies, 1); dict->SetString(printing::kSettingDeviceName, "dummy"); dict->SetInteger(printing::kPreviewRequestID, 12345); + dict->SetBoolean(printing::kSettingGenerateDraftData, true); } } // namespace @@ -320,12 +321,12 @@ class PrintWebViewHelperPreviewTest : public PrintWebViewHelperTestBase { void VerifyPrintPreviewGenerated(bool generated_preview) { const IPC::Message* preview_msg = render_thread_.sink().GetUniqueMessageMatching( - PrintHostMsg_PagesReadyForPreview::ID); + PrintHostMsg_MetafileReadyForPrinting::ID); bool did_get_preview_msg = (NULL != preview_msg); ASSERT_EQ(generated_preview, did_get_preview_msg); if (did_get_preview_msg) { - PrintHostMsg_PagesReadyForPreview::Param preview_param; - PrintHostMsg_PagesReadyForPreview::Read(preview_msg, &preview_param); + PrintHostMsg_MetafileReadyForPrinting::Param preview_param; + PrintHostMsg_MetafileReadyForPrinting::Read(preview_msg, &preview_param); EXPECT_NE(0, preview_param.a.document_cookie); EXPECT_NE(0, preview_param.a.expected_pages_count); EXPECT_NE(0U, preview_param.a.data_size); @@ -338,6 +339,28 @@ class PrintWebViewHelperPreviewTest : public PrintWebViewHelperTestBase { EXPECT_EQ(did_fail, print_failed); } + // |page_number| is 0-based. + void VerifyDidPreviewPage(bool generate_draft_pages, int page_number) { + bool msg_found = false; + size_t msg_count = render_thread_.sink().message_count(); + for (size_t i = 0; i < msg_count; ++i) { + const IPC::Message* msg = render_thread_.sink().GetMessageAt(i); + if (msg->type() == PrintHostMsg_DidPreviewPage::ID) { + PrintHostMsg_DidPreviewPage::Param page_param; + PrintHostMsg_DidPreviewPage::Read(msg, &page_param); + if (page_param.a.page_number == page_number) { + msg_found = true; + if (generate_draft_pages) + EXPECT_NE(0U, page_param.a.data_size); + else + EXPECT_EQ(0U, page_param.a.data_size); + break; + } + } + } + ASSERT_EQ(true, msg_found); + } + DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelperPreviewTest); }; @@ -354,10 +377,50 @@ TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreview) { // Need to finish simulating print preview. // Generate the page and finalize it. - PrintWebViewHelper::Get(view_)->OnContinuePreview( - printing::INVALID_PAGE_INDEX); - PrintWebViewHelper::Get(view_)->OnContinuePreview( - printing::INVALID_PAGE_INDEX); + PrintWebViewHelper::Get(view_)->OnContinuePreview(); + + // Verify that we did create the draft metafile for the first page. + VerifyDidPreviewPage(true, 0); + PrintWebViewHelper::Get(view_)->OnContinuePreview(); + + EXPECT_EQ(0, render_thread_.print_preview_pages_remaining()); + VerifyPrintPreviewFailed(false); + VerifyPrintPreviewGenerated(true); + VerifyPagesPrinted(false); +} + +// Test to verify that complete metafile is generated for a subset of pages +// without creating draft pages. +TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreviewForSelectedPages) { + LoadHTML(kHelloWorldHTML); + + PrintWebViewHelper::Get(view_)->OnInitiatePrintPreview(); + // Fill in some dummy values. + DictionaryValue dict; + CreatePrintSettingsDictionary(&dict); + + // Set a page range and update the dictionary to generate only the complete + // metafile with the selected pages. Page numbers used in the dictionary + // are 1-based. + DictionaryValue* page_range = new DictionaryValue(); + page_range->SetInteger(printing::kSettingPageRangeFrom, 1); + page_range->SetInteger(printing::kSettingPageRangeTo, 1); + + ListValue* page_range_array = new ListValue(); + page_range_array->Append(page_range); + + dict.Set(printing::kSettingPageRange, page_range_array); + dict.SetBoolean(printing::kSettingGenerateDraftData, false); + + PrintWebViewHelper::Get(view_)->OnPrintPreview(dict); + + // Need to finish simulating print preview. + // Generate the page and finalize it. + PrintWebViewHelper::Get(view_)->OnContinuePreview(); + + // Verify that we did not create the draft metafile for the first page. + VerifyDidPreviewPage(false, 0); + PrintWebViewHelper::Get(view_)->OnContinuePreview(); EXPECT_EQ(0, render_thread_.print_preview_pages_remaining()); VerifyPrintPreviewFailed(false); diff --git a/chrome/renderer/print_web_view_helper_linux.cc b/chrome/renderer/print_web_view_helper_linux.cc index 0915681..33e9321 100644 --- a/chrome/renderer/print_web_view_helper_linux.cc +++ b/chrome/renderer/print_web_view_helper_linux.cc @@ -29,21 +29,29 @@ void PrintWebViewHelper::RenderPreviewPage(int page_number) { PrintMsg_PrintPage_Params page_params; page_params.params = print_preview_context_.print_params(); page_params.page_number = page_number; + scoped_ptr<printing::Metafile> draft_metafile; + printing::Metafile* initial_render_metafile = + print_preview_context_.metafile(); + if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { + draft_metafile.reset(new printing::PreviewMetafile); + initial_render_metafile = draft_metafile.get(); + } base::TimeTicks begin_time = base::TimeTicks::Now(); PrintPageInternal(page_params, print_preview_context_.GetPrintCanvasSize(), - print_preview_context_.frame(), - print_preview_context_.metafile()); - + print_preview_context_.frame(), initial_render_metafile); print_preview_context_.RenderedPreviewPage( base::TimeTicks::Now() - begin_time); - scoped_ptr<printing::Metafile> page_metafile; - if (print_preview_context_.IsModifiable()) { - page_metafile.reset( + if (draft_metafile.get()) { + draft_metafile->FinishDocument(); + } else if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()){ + DCHECK(!draft_metafile.get()); + draft_metafile.reset( print_preview_context_.metafile()->GetMetafileForCurrentPage()); } - PreviewPageRendered(page_number, page_metafile.get()); + PreviewPageRendered(page_number, draft_metafile.get()); } bool PrintWebViewHelper::PrintPages(const PrintMsg_PrintPages_Params& params, @@ -207,6 +215,8 @@ void PrintWebViewHelper::PrintPageInternal( SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device); canvas->unref(); // SkRefPtr and new both took a reference. printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile); + printing::MetafileSkiaWrapper::SetDraftMode(canvas.get(), + is_print_ready_metafile_sent_); frame->printPage(params.page_number, canvas.get()); // TODO(myhuang): We should render the header and the footer. diff --git a/chrome/renderer/print_web_view_helper_mac.mm b/chrome/renderer/print_web_view_helper_mac.mm index 95ccb7e..0f46239 100644 --- a/chrome/renderer/print_web_view_helper_mac.mm +++ b/chrome/renderer/print_web_view_helper_mac.mm @@ -66,19 +66,30 @@ void PrintWebViewHelper::RenderPreviewPage(int page_number) { printParams.printable_size.width(), printParams.printable_size.height()); + scoped_ptr<printing::Metafile> draft_metafile; printing::Metafile* initial_render_metafile = print_preview_context_.metafile(); - scoped_ptr<printing::PreviewMetafile> draft_metafile; -#if !defined(USE_SKIA) - if (print_preview_context_.IsModifiable()) { - draft_metafile.reset(new printing::PreviewMetafile); + +#if defined(USE_SKIA) + bool need_draft_metafile = print_preview_context_.IsModifiable() && + is_print_ready_metafile_sent_; +#else + bool need_draft_metafile = print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages(); + // NOTE: If the rendering page need to be in draft metafile and print ready + // metafile, we should always render to the draft metafile first and then + // copy that into the print ready metafile because CG does not allow us to do + // it in the other order. +#endif + + if (need_draft_metafile) { + draft_metafile.reset(new printing::PreviewMetafile()); if (!draft_metafile->Init()) { DidFinishPrinting(FAIL_PREVIEW); return; } initial_render_metafile = draft_metafile.get(); } -#endif base::TimeTicks begin_time = base::TimeTicks::Now(); RenderPage(printParams.page_size, content_area, scale_factor, page_number, @@ -86,38 +97,44 @@ void PrintWebViewHelper::RenderPreviewPage(int page_number) { print_preview_context_.RenderedPreviewPage( base::TimeTicks::Now() - begin_time); - if (print_preview_context_.IsModifiable()) { -#if defined(USE_SKIA) - DCHECK(!draft_metafile.get()); - draft_metafile.reset( - print_preview_context_.metafile()->GetMetafileForCurrentPage()); -#else + if (draft_metafile.get()) { draft_metafile->FinishDocument(); - - // With CG, we rendered into a new metafile so we could get it as a draft - // document. Now we need to add it to complete document. But the document - // has already been scaled and adjusted for margins, so do a 1:1 drawing. - printing::Metafile* complete_metafile = print_preview_context_.metafile(); - bool success = complete_metafile->StartPage( - printParams.page_size, gfx::Rect(printParams.page_size), 1.0); - DCHECK(success); - // StartPage unconditionally flips the content over, flip it back since it - // was already flipped in |draft_metafile|. - CGContextTranslateCTM(complete_metafile->context(), 0, - printParams.page_size.height()); - CGContextScaleCTM(complete_metafile->context(), 1.0, -1.0); - - draft_metafile->RenderPage(1, - complete_metafile->context(), - draft_metafile->GetPageBounds(1).ToCGRect(), - false /* shrink_to_fit */, - false /* stretch_to_fit */, - true /* center_horizontally */, - true /* center_vertically */); - complete_metafile->FinishPage(); +#if !defined(USE_SKIA) + if (!is_print_ready_metafile_sent_) { + // With CG, we rendered into a new metafile so we could get it as a draft + // document. Now we need to add it to print ready document. But the + // document has already been scaled and adjusted for margins, so do a 1:1 + // drawing. + printing::Metafile* print_ready_metafile = + print_preview_context_.metafile(); + bool success = print_ready_metafile->StartPage( + printParams.page_size, gfx::Rect(printParams.page_size), 1.0); + DCHECK(success); + // StartPage unconditionally flips the content over, flip it back since it + // was already flipped in |draft_metafile|. + CGContextTranslateCTM(print_ready_metafile->context(), 0, + printParams.page_size.height()); + CGContextScaleCTM(print_ready_metafile->context(), 1.0, -1.0); + draft_metafile->RenderPage(1, + print_ready_metafile->context(), + draft_metafile->GetPageBounds(1).ToCGRect(), + false /* shrink_to_fit */, + false /* stretch_to_fit */, + true /* center_horizontally */, + true /* center_vertically */); + print_ready_metafile->FinishPage(); + } +#endif + } else { +#if defined(USE_SKIA) + if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()) { + DCHECK(!draft_metafile.get()); + draft_metafile.reset( + print_preview_context_.metafile()->GetMetafileForCurrentPage()); + } #endif } - PreviewPageRendered(page_number, draft_metafile.get()); } @@ -137,6 +154,8 @@ void PrintWebViewHelper::RenderPage( canvas->unref(); // SkRefPtr and new both took a reference. WebKit::WebCanvas* canvasPtr = canvas.get(); printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvasPtr, metafile); + printing::MetafileSkiaWrapper::SetDraftMode(canvasPtr, + is_print_ready_metafile_sent_); #else bool success = metafile->StartPage(page_size, content_area, scale_factor); DCHECK(success); diff --git a/chrome/renderer/print_web_view_helper_win.cc b/chrome/renderer/print_web_view_helper_win.cc index b43c22f..25d226d 100644 --- a/chrome/renderer/print_web_view_helper_win.cc +++ b/chrome/renderer/print_web_view_helper_win.cc @@ -126,24 +126,34 @@ void PrintWebViewHelper::RenderPreviewPage(int page_number) { // Calculate the dpi adjustment. float scale_factor = static_cast<float>(print_params.desired_dpi / print_params.dpi); + scoped_ptr<Metafile> draft_metafile; + printing::Metafile* initial_render_metafile = + print_preview_context_.metafile(); + + if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { + draft_metafile.reset(new printing::PreviewMetafile); + initial_render_metafile = draft_metafile.get(); + } base::TimeTicks begin_time = base::TimeTicks::Now(); printing::Metafile* render_page_result = RenderPage(print_params, &scale_factor, page_number, true, - print_preview_context_.frame(), - print_preview_context_.metafile()); - // In the preview flow, RenderPage will never return a new metafile. - DCHECK_EQ(render_page_result, print_preview_context_.metafile()); + print_preview_context_.frame(), initial_render_metafile); + // In the preview flow, RenderPage will never return a new metafile. + DCHECK_EQ(render_page_result, initial_render_metafile); print_preview_context_.RenderedPreviewPage( base::TimeTicks::Now() - begin_time); - scoped_ptr<printing::Metafile> page_metafile; - if (print_preview_context_.IsModifiable()) { - page_metafile.reset( + if (draft_metafile.get()) { + draft_metafile->FinishDocument(); + } else if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()){ + DCHECK(!draft_metafile.get()); + draft_metafile.reset( print_preview_context_.metafile()->GetMetafileForCurrentPage()); } - PreviewPageRendered(page_number, page_metafile.get()); + PreviewPageRendered(page_number, draft_metafile.get()); } Metafile* PrintWebViewHelper::RenderPage( @@ -183,8 +193,11 @@ Metafile* PrintWebViewHelper::RenderPage( // can't be a stack object. SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device); canvas->unref(); // SkRefPtr and new both took a reference. - if (is_preview) + if (is_preview) { printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile); + printing::MetafileSkiaWrapper::SetDraftMode(canvas.get(), + is_print_ready_metafile_sent_); + } float webkit_scale_factor = frame->printPage(page_number, canvas.get()); if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |