Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Unified Diff: chrome/renderer/print_web_view_helper.cc

Issue 7365003: Print Preview: Make preview generation event driven to eliminate synchronous messages. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix broken test, add more DCHECKs Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/print_web_view_helper.cc
===================================================================
--- chrome/renderer/print_web_view_helper.cc (revision 92494)
+++ chrome/renderer/print_web_view_helper.cc (working copy)
@@ -18,7 +18,7 @@
#include "chrome/renderer/prerender/prerender_helper.h"
#include "content/renderer/render_view.h"
#include "grit/generated_resources.h"
-#include "printing/metafile.h"
+#include "printing/metafile_impl.h"
#include "printing/print_job_constants.h"
#include "printing/units.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h"
@@ -154,11 +154,8 @@
: RenderViewObserver(render_view),
RenderViewObserverTracker<PrintWebViewHelper>(render_view),
print_web_view_(NULL),
- script_initiated_preview_frame_(NULL),
- context_menu_preview_node_(NULL),
user_cancelled_scripted_print_count_(0),
- notify_browser_of_print_failure_(true),
- preview_page_count_(0) {
+ notify_browser_of_print_failure_(true) {
is_preview_ = switches::IsPrintPreviewEnabled();
}
@@ -179,8 +176,7 @@
IncrementScriptedPrintCount();
if (is_preview_) {
- script_initiated_preview_frame_ = frame;
- context_menu_preview_node_.reset();
+ print_preview_context_.InitWithFrame(frame);
RequestPrintPreview();
} else {
Print(frame, NULL);
@@ -201,6 +197,12 @@
IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone)
IPC_MESSAGE_HANDLER(PrintMsg_ResetScriptedPrintCount,
ResetScriptedPrintCount)
+ IPC_MESSAGE_HANDLER(PrintMsg_ContinuePreview,
+ OnContinuePreview)
kmadhusu 2011/07/15 01:22:46 nit: This argument will fit in the previous line.
Lei Zhang 2011/07/15 01:48:02 Done.
+ IPC_MESSAGE_HANDLER(PrintMsg_CancelPreview,
+ OnCancelPreview)
kmadhusu 2011/07/15 01:22:46 same here
Lei Zhang 2011/07/15 01:48:02 Done.
+ IPC_MESSAGE_HANDLER(PrintMsg_AbortPreview,
+ OnAbortPreview)
kmadhusu 2011/07/15 01:22:46 same here
Lei Zhang 2011/07/15 01:48:02 Done.
IPC_MESSAGE_HANDLER(PrintMsg_PreviewPrintingRequestCancelled,
DisplayPrintJobError)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -268,23 +270,116 @@
void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) {
DCHECK(is_preview_);
- DCHECK(!context_menu_preview_node_.get() || !script_initiated_preview_frame_);
+ print_preview_context_.OnPrintPreview();
- if (script_initiated_preview_frame_) {
- // Script initiated print preview.
- PrintPreview(script_initiated_preview_frame_, NULL, settings);
- } else if (context_menu_preview_node_.get()) {
- // User initiated - print node under context menu.
- PrintPreview(context_menu_preview_node_->document().frame(),
- context_menu_preview_node_.get(), settings);
- } else {
- // User initiated - normal print preview.
- WebFrame* frame;
- if (GetPrintFrame(&frame))
- PrintPreview(frame, NULL, settings);
+ if (!InitPrintSettings(print_preview_context_.frame(),
+ print_preview_context_.node())) {
+ NOTREACHED();
+ return;
}
+
+ if (!UpdatePrintSettings(settings)) {
+ DidFinishPrinting(FAIL_PREVIEW);
+ return;
+ }
+
+ if (print_pages_params_->params.preview_request_id != 0 &&
+ old_print_pages_params_.get() &&
+ PrintMsg_Print_Params_IsEqual(*old_print_pages_params_,
+ *print_pages_params_)) {
+ PrintHostMsg_DidPreviewDocument_Params preview_params;
+ preview_params.reuse_existing_data = true;
+ preview_params.data_size = 0;
+ preview_params.document_cookie =
+ print_pages_params_->params.document_cookie;
+ preview_params.expected_pages_count = print_preview_context_.page_count();
+ preview_params.modifiable = print_preview_context_.IsModifiable();
+ preview_params.preview_request_id =
+ print_pages_params_->params.preview_request_id;
+
+ Send(new PrintHostMsg_PagesReadyForPreview(routing_id(), preview_params));
+ return;
+ }
+
+ // PDF printer device supports alpha blending.
+ print_pages_params_->params.supports_alpha_blend = true;
+ if (!CreatePreviewDocument())
+ DidFinishPrinting(FAIL_PREVIEW);
}
+bool PrintWebViewHelper::CreatePreviewDocument() {
+ PrintMsg_Print_Params printParams = print_pages_params_->params;
+ UpdatePrintableSizeInPrintParameters(print_preview_context_.frame(),
+ print_preview_context_.node(),
+ &printParams);
+
+ const std::vector<int>& pages = print_pages_params_->pages;
+ if (!print_preview_context_.CreatePreviewDocument(printParams, pages))
+ return false;
+ int page_count = print_preview_context_.page_count();
+ Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), page_count));
+ PreviewPageRendered(-1);
+ return true;
+}
+
+void PrintWebViewHelper::OnContinuePreview() {
+ // Spurious message. We already finished/cancelled/aborted the print preview.
+ if (!print_preview_context_.IsBusy())
+ return;
+
+ int page_number = -1;
+ if (!print_preview_context_.GetNextPage(&page_number)) {
+ // Continue generating the print preview.
+ RenderPreviewPage(page_number);
+ return;
+ }
+
+ // Finished generating preview. Finalize the document.
+ if (!FinalizePreviewDocument())
+ DidFinishPrinting(FAIL_PREVIEW);
+}
+
+void PrintWebViewHelper::OnCancelPreview() {
+ DidFinishPrinting(CANCEL_PREVIEW);
+ return;
+}
+
+void PrintWebViewHelper::OnAbortPreview() {
+ DidFinishPrinting(ABORT_PREVIEW);
+ return;
+}
+
+bool PrintWebViewHelper::FinalizePreviewDocument() {
+ print_preview_context_.FinalizePreviewDocument();
+
+ // Get the size of the resulting metafile.
+ printing::Metafile* metafile = print_preview_context_.metafile();
+ uint32 buf_size = metafile->GetDataSize();
+ DCHECK_GT(buf_size, 0u);
kmadhusu 2011/07/15 01:22:46 http://codereview.chromium.org/7365003/diff/9001/c
Lei Zhang 2011/07/15 01:48:02 That was a copy and paste from the Windows EMF pri
+
+ PrintHostMsg_DidPreviewDocument_Params preview_params;
+ preview_params.reuse_existing_data = false;
+ preview_params.data_size = buf_size;
+ preview_params.document_cookie = print_pages_params_->params.document_cookie;
+ preview_params.expected_pages_count = print_preview_context_.page_count();
+ preview_params.modifiable = print_preview_context_.IsModifiable();
+ preview_params.preview_request_id =
+ print_pages_params_->params.preview_request_id;
+
+ // Ask the browser to create the shared memory for us.
+ if (!CopyMetafileDataToSharedMem(metafile,
+ &(preview_params.metafile_data_handle))) {
+ return false;
+ }
+#if defined(OS_WIN)
+ Send(new PrintHostMsg_DuplicateSection(routing_id(),
+ preview_params.metafile_data_handle,
+ &preview_params.metafile_data_handle));
+#endif
+ Send(new PrintHostMsg_PagesReadyForPreview(routing_id(), preview_params));
+ return true;
+}
+
void PrintWebViewHelper::OnPrintingDone(bool success) {
notify_browser_of_print_failure_ = false;
DidFinishPrinting(success ? OK : FAIL_PRINT);
@@ -300,8 +395,7 @@
// Make a copy of the node, in case RenderView::OnContextMenuClosed resets
// its |context_menu_node_|.
if (is_preview_) {
- context_menu_preview_node_.reset(new WebNode(context_menu_node));
- script_initiated_preview_frame_ = NULL;
+ print_preview_context_.InitWithNode(context_menu_node);
RequestPrintPreview();
} else {
WebNode duplicate_node(context_menu_node);
@@ -311,8 +405,9 @@
void PrintWebViewHelper::OnInitiatePrintPreview() {
DCHECK(is_preview_);
- script_initiated_preview_frame_ = NULL;
- context_menu_preview_node_.reset();
+ WebFrame* frame;
+ if (GetPrintFrame(&frame))
kmadhusu 2011/07/15 01:22:46 Handle the else case.
Lei Zhang 2011/07/15 01:48:02 The else case is to do nothing. I changed this to
+ print_preview_context_.InitWithFrame(frame);
RequestPrintPreview();
}
@@ -357,44 +452,6 @@
ResetScriptedPrintCount();
}
-void PrintWebViewHelper::PrintPreview(WebKit::WebFrame* frame,
- WebKit::WebNode* node,
- const DictionaryValue& settings) {
- DCHECK(is_preview_);
-
- if (!InitPrintSettings(frame, node)) {
- NOTREACHED() << "Failed to initialize print page settings";
- return;
- }
-
- if (!UpdatePrintSettings(settings)) {
- DidFinishPrinting(FAIL_PREVIEW);
- return;
- }
-
- if (print_pages_params_->params.preview_request_id != 0 &&
- old_print_pages_params_.get() &&
- PrintMsg_Print_Params_IsEqual(*old_print_pages_params_,
- *print_pages_params_)) {
- PrintHostMsg_DidPreviewDocument_Params preview_params;
- preview_params.reuse_existing_data = true;
- preview_params.data_size = 0;
- preview_params.document_cookie =
- print_pages_params_->params.document_cookie;
- preview_params.expected_pages_count = preview_page_count_;
- preview_params.modifiable = IsModifiable(frame, node);
- preview_params.preview_request_id =
- print_pages_params_->params.preview_request_id;
-
- Send(new PrintHostMsg_PagesReadyForPreview(routing_id(), preview_params));
- return;
- }
-
- // Render Pages for preview.
- if (!RenderPagesForPreview(frame, node))
- DidFinishPrinting(FAIL_PREVIEW);
-}
-
void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
bool store_print_pages_params = true;
if (result == FAIL_PRINT) {
@@ -405,13 +462,21 @@
Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
}
} else if (result == FAIL_PREVIEW) {
+ DCHECK(is_preview_);
+ store_print_pages_params = false;
int cookie = print_pages_params_->params.document_cookie;
+ Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie));
+ print_preview_context_.Abort();
+ } else if (result == CANCEL_PREVIEW) {
+ DCHECK(is_preview_);
store_print_pages_params = false;
- if (notify_browser_of_print_failure_) {
- Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie));
- } else {
- Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie));
- }
+ print_preview_context_.Cancel();
+ } else if (result == ABORT_PREVIEW) {
+ DCHECK(is_preview_);
+ store_print_pages_params = false;
+ print_preview_context_.Abort();
+ } else if (result == OK && is_preview_) {
+ print_preview_context_.Finished();
}
if (print_web_view_) {
@@ -575,16 +640,6 @@
ConvertPixelsToPointDouble(margin_left_in_pixels);
}
-bool PrintWebViewHelper::IsModifiable(WebKit::WebFrame* frame,
- WebKit::WebNode* node) {
- if (node)
- return false;
- std::string mime(frame->dataSource()->response().mimeType().utf8());
- if (mime == "application/pdf")
- return false;
- return true;
-}
-
void PrintWebViewHelper::UpdatePrintableSizeInPrintParameters(
WebFrame* frame,
WebNode* node,
@@ -751,42 +806,6 @@
}
}
-bool PrintWebViewHelper::RenderPagesForPreview(WebKit::WebFrame* frame,
- WebKit::WebNode* node) {
- PrintMsg_PrintPages_Params print_settings = *print_pages_params_;
- // PDF printer device supports alpha blending.
- print_settings.params.supports_alpha_blend = true;
- // TODO(kmadhusu): Handle print selection.
- return CreatePreviewDocument(print_settings, frame, node);
-}
-
-base::TimeTicks PrintWebViewHelper::ReportPreviewPageRenderTime(
- base::TimeTicks start_time) {
- base::TimeTicks now = base::TimeTicks::Now();
- UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", now - start_time);
- return now;
-}
-
-void PrintWebViewHelper::ReportTotalPreviewGenerationTime(
- int selected_pages_length, int total_pages,
- base::TimeDelta render_time, base::TimeDelta total_time) {
- if (selected_pages_length == 0)
- selected_pages_length = total_pages;
-
- if (selected_pages_length <= 0) {
- // This shouldn't happen, but this makes sure it doesn't affect the
- // statistics if it does.
- return;
- }
-
- UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
- render_time);
- UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
- total_time);
- UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
- total_time / selected_pages_length);
-}
-
#if defined(OS_POSIX)
bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
printing::Metafile* metafile,
@@ -812,6 +831,7 @@
WebKit::WebFrame* frame) {
const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 32;
+ bool too_frequent = false;
kmadhusu 2011/07/15 01:22:46 Declare this variable after the comments
Lei Zhang 2011/07/15 01:48:02 I don't think it helps with readability.
// Check if there is script repeatedly trying to print and ignore it if too
// frequent. The first 3 times, we use a constant wait time, but if this
@@ -829,15 +849,21 @@
kMaxSecondsToIgnoreJavascriptInitiatedPrint);
}
if (diff.InSeconds() < min_wait_seconds) {
- WebString message(WebString::fromUTF8(
- "Ignoring too frequent calls to print()."));
- frame->addMessageToConsole(WebConsoleMessage(
- WebConsoleMessage::LevelWarning,
- message));
- return true;
+ too_frequent = true;
}
}
- return false;
+
+ if (!too_frequent && print_preview_context_.IsBusy())
+ too_frequent = true;
+
+ if (!too_frequent)
+ return false;
+
+ WebString message(WebString::fromUTF8(
+ "Ignoring too frequent calls to print()."));
+ frame->addMessageToConsole(WebConsoleMessage(WebConsoleMessage::LevelWarning,
+ message));
+ return true;
}
void PrintWebViewHelper::ResetScriptedPrintCount() {
@@ -865,10 +891,192 @@
Send(new PrintHostMsg_RequestPrintPreview(routing_id()));
}
-bool PrintWebViewHelper::PreviewPageRendered(int page_number) {
- bool cancel = false;
- Send(new PrintHostMsg_DidPreviewPage(routing_id(), page_number, &cancel));
- if (cancel)
- notify_browser_of_print_failure_ = false;
- return !cancel;
+void PrintWebViewHelper::PreviewPageRendered(int page_number) {
+ int cookie = print_pages_params_->params.document_cookie;
+ Send(new PrintHostMsg_DidPreviewPage(routing_id(), page_number, cookie));
}
+
+PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
+ : frame_(NULL),
+ page_count_(0),
+ actual_page_count_(0),
+ current_page_(0),
+ state_(UNINITIALIZED) {
+}
+
+void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
+ WebKit::WebFrame* web_frame) {
+ DCHECK(web_frame);
+ if (IsInitialized())
+ return;
+ state_ = INITIALIZED;
+ frame_ = web_frame;
+ node_.reset();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
+ const WebKit::WebNode& web_node) {
+ DCHECK(!web_node.isNull());
+ if (IsInitialized())
+ return;
+ state_ = INITIALIZED;
+ frame_ = web_node.document().frame();
+ node_.reset(new WebNode(web_node));
+}
+
+void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
+ DCHECK(IsInitialized());
+ Reset();
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
+ const PrintMsg_Print_Params& printParams,
+ const std::vector<int>& pages) {
+ DCHECK(IsInitialized());
kmadhusu 2011/07/15 01:22:46 If (!IsInitialized()) return false; is better t
Lei Zhang 2011/07/15 01:48:02 The DCHECK should never fail. If it fails in a rel
+ state_ = PRINTING;
+
+ print_params_.reset(new PrintMsg_Print_Params(printParams));
+
+ metafile_.reset(new printing::PreviewMetafile);
+ if (!metafile_->Init())
+ return false;
+
+ // Need to make sure old object gets destroyed first.
+ prep_frame_view_.reset(new PrepareFrameAndViewForPrint(printParams,
+ frame(),
kmadhusu 2011/07/15 01:22:46 nit: frame() can fit in the previous line.
Lei Zhang 2011/07/15 01:48:02 Done.
+ node(),
+ frame()->view()));
+ page_count_ = prep_frame_view_->GetExpectedPageCount();
+ if (page_count_ == 0)
+ return false;
+
+ current_page_ = 0;
+ if (pages.empty()) {
kmadhusu 2011/07/15 01:22:46 How about: actual_page_count = pages.empty()? pag
Lei Zhang 2011/07/15 01:48:02 Your logic is wrong.
kmadhusu 2011/07/15 19:25:46 oops.. I meant if (actual_page_count_ == page_coun
+ actual_page_count_ = page_count_;
+ rendered_pages_ = std::vector<bool>(page_count_, false);
+ } else {
+ actual_page_count_ = pages.size();
+ rendered_pages_ = std::vector<bool>(page_count_, true);
+ for (size_t i = 0; i < pages.size(); ++i) {
kmadhusu 2011/07/15 01:22:46 "i < actual_page_count_"
Lei Zhang 2011/07/15 01:48:02 Done.
+ int page_number = pages[i];
+ if (page_number < 0 || page_number >= page_count_)
+ return false;
+ rendered_pages_[page_number] = false;
+ }
+ }
+
+ document_render_time_ = base::TimeDelta();
+ begin_time_ = base::TimeTicks::Now();
+
+ return true;
+}
+
+void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
+ const base::TimeDelta& page_time) {
+ DCHECK_EQ(PRINTING, state_);
+ document_render_time_ += page_time;
+ UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
+}
+
+void PrintWebViewHelper::PrintPreviewContext::FinalizePreviewDocument() {
+ DCHECK_EQ(PRINTING, state_);
+ state_ = DONE;
+
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+
+ prep_frame_view_->FinishPrinting();
kmadhusu 2011/07/15 01:22:46 Please retain the previous comment. http://codere
Lei Zhang 2011/07/15 01:48:02 We have the comment on Windows only, but not Linux
+ metafile_->FinishDocument();
kmadhusu 2011/07/15 01:22:46 if (!metafile->FinishDocument) NOTREACHED();
Lei Zhang 2011/07/15 01:48:02 Again, we don't have it on Mac/Linux.
kmadhusu 2011/07/15 19:25:46 At least on linux, we should have handled this cas
+
+ if (actual_page_count_ <= 0) {
+ NOTREACHED();
+ return;
+ }
+
+ UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
+ document_render_time_);
+ base::TimeDelta total_time = (base::TimeTicks::Now() - begin_time) +
+ document_render_time_;
kmadhusu 2011/07/15 01:22:46 nit: Fix indentation.
Lei Zhang 2011/07/15 01:48:02 Done.
+ UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
+ total_time);
+ UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
+ total_time / actual_page_count_);
+}
+
+void PrintWebViewHelper::PrintPreviewContext::Finished() {
+ DCHECK_EQ(DONE, state_);
+ Reset();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::Abort() {
+ state_ = UNINITIALIZED;
+ Reset();
+ frame_ = NULL;
+ node_.reset();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::Cancel() {
+ DCHECK(IsInitialized());
+ state_ = DONE;
+ Reset();
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::GetNextPage(
+ int* page_number) {
+ DCHECK_EQ(PRINTING, state_);
+ while (current_page_ < page_count_ && rendered_pages_[current_page_])
+ ++current_page_;
+ if (current_page_ == page_count_)
+ return true;
+ rendered_pages_[current_page_] = true;
+ *page_number = current_page_++;
+ return false;
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsInitialized() const {
kmadhusu 2011/07/15 01:22:46 I was expecting "return state_ == INITIALIZED;" as
Lei Zhang 2011/07/15 01:48:02 Changed to "IsReadyToRender()"
+ return state_ != UNINITIALIZED;
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsBusy() const {
kmadhusu 2011/07/15 01:22:46 This function needs a better name. state PRINTIN
Lei Zhang 2011/07/15 01:48:02 I can't think of a better name. "Busy" is relative
+ return state_ == INITIALIZED || state_ == PRINTING;
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() const {
+ if (node())
+ return false;
+ std::string mime(frame()->dataSource()->response().mimeType().utf8());
+ if (mime == "application/pdf")
kmadhusu 2011/07/15 01:22:46 Instead of lines 1047-1049, use return mime != "
Lei Zhang 2011/07/15 01:48:02 Done.
+ return false;
+ return true;
+}
+
+WebKit::WebFrame* PrintWebViewHelper::PrintPreviewContext::frame() const {
+ return frame_;
+}
+
+WebKit::WebNode* PrintWebViewHelper::PrintPreviewContext::node() const {
+ return node_.get();
+}
+
+int PrintWebViewHelper::PrintPreviewContext::page_count() const {
+ return page_count_;
+}
+
+printing::Metafile* PrintWebViewHelper::PrintPreviewContext::metafile() const {
+ return metafile_.get();
+}
+
+const PrintMsg_Print_Params&
+PrintWebViewHelper::PrintPreviewContext::print_params() const {
+ return *print_params_;
+}
+
+const gfx::Size&
+PrintWebViewHelper::PrintPreviewContext::GetPrintCanvasSize() const {
+ return prep_frame_view_->GetPrintCanvasSize();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::Reset() {
+ prep_frame_view_.reset();
+ metafile_.reset();
+ rendered_pages_.clear();
+}

Powered by Google App Engine
This is Rietveld 408576698