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

Unified Diff: chrome/renderer/print_web_view_helper_mac.mm

Issue 276004: Wire up printing on the Mac (Closed)
Patch Set: Created 11 years, 2 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_mac.mm
diff --git a/chrome/renderer/print_web_view_helper_mac.mm b/chrome/renderer/print_web_view_helper_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..4ac3a47c4a1297444907a5ed7b6f2e21107370cb
--- /dev/null
+++ b/chrome/renderer/print_web_view_helper_mac.mm
@@ -0,0 +1,238 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/renderer/print_web_view_helper.h"
+
+#import <AppKit/AppKit.h>
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/process_util.h"
+#include "base/scoped_cftyperef.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/render_view.h"
+#include "grit/generated_resources.h"
+#include "printing/native_metafile.h"
+#include "webkit/api/public/WebFrame.h"
+#include "webkit/api/public/WebCanvas.h"
+#include "webkit/api/public/WebConsoleMessage.h"
+
+using WebKit::WebFrame;
+using WebKit::WebCanvas;
+using WebKit::WebConsoleMessage;
+using WebKit::WebString;
+
+// TODO(stuartmorgan): There's a fair amount of code here that is duplicated
+// from _win that should instead be shared. Once Linux has a real print settings
+// implementation, it's likely that this whole method can just be moved to the
+// cross-platform file, and the slight divergences resolved/ifdef'd.
pink (ping after 24hrs) 2009/10/13 21:04:51 file a bug?
pink (ping after 24hrs) 2009/10/13 21:04:51 is it possible to highlight the parts that are mac
stuartmorgan 2009/10/13 22:07:43 Will do.
stuartmorgan 2009/10/13 22:07:43 That seems prone to getting out of date if tweaks
+void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) {
+ const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
+ const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 2 * 60; // 2 Minutes.
+
+ // If still not finished with earlier print request simply ignore.
+ if (IsPrinting())
+ return;
+
+ // TODO(maruel): Move this out of platform specific code.
+ // Check if there is script repeatedly trying to print and ignore it if too
+ // frequent. We use exponential wait time so for a page that calls print() in
+ // a loop the user will need to cancel the print dialog after 2 seconds, 4
+ // seconds, 8, ... up to the maximum of 2 minutes.
+ // This gives the user time to navigate from the page.
+ if (script_initiated && (user_cancelled_scripted_print_count_ > 0)) {
+ base::TimeDelta diff = base::Time::Now() - last_cancelled_script_print_;
+ int min_wait_seconds = std::min(
+ kMinSecondsToIgnoreJavascriptInitiatedPrint <<
+ (user_cancelled_scripted_print_count_ - 1),
+ kMaxSecondsToIgnoreJavascriptInitiatedPrint);
+ if (diff.InSeconds() < min_wait_seconds) {
+ WebString message(WebString::fromUTF8(
+ "Ignoring too frequent calls to print()."));
+ frame->addMessageToConsole(WebConsoleMessage(
+ WebConsoleMessage::LevelWarning,
+ message));
+ return;
+ }
+ }
+
+ // Retrieve the default print settings to calculate the expected number of
+ // pages.
+ ViewMsg_Print_Params default_settings;
+ bool user_cancelled_print = false;
+
+ IPC::SyncMessage* msg =
+ new ViewHostMsg_GetDefaultPrintSettings(routing_id(), &default_settings);
+ if (Send(msg)) {
+ msg = NULL;
+ if (default_settings.IsEmpty()) {
+ NOTREACHED() << "Couldn't get default print settings";
+ return;
+ }
+
+ // Continue only if the settings are valid.
+ if (default_settings.dpi && default_settings.document_cookie) {
+ int expected_pages_count = 0;
+
+ // Prepare once to calculate the estimated page count. This must be in
+ // a scope for itself (see comments on PrepareFrameAndViewForPrint).
+ {
+ PrepareFrameAndViewForPrint prep_frame_view(default_settings,
+ frame,
+ frame->view());
+ expected_pages_count = prep_frame_view.GetExpectedPageCount();
+ DCHECK(expected_pages_count);
+ }
+
+ // Ask the browser to show UI to retrieve the final print settings.
+ ViewMsg_PrintPages_Params print_settings;
+
+ ViewHostMsg_ScriptedPrint_Params params;
+
+ // The routing id is sent across as it is needed to look up the
+ // corresponding RenderViewHost instance to signal and reset the
+ // pump messages event.
+ params.routing_id = routing_id();
+ // host_window_ may be NULL at this point if the current window is a popup
+ // and the print() command has been issued from the parent. The receiver
+ // of this message has to deal with this.
+ params.host_window_id = render_view_->host_window();
+ params.cookie = default_settings.document_cookie;
+ params.has_selection = frame->hasSelection();
+ params.expected_pages_count = expected_pages_count;
+
+ msg = new ViewHostMsg_ScriptedPrint(params, &print_settings);
+ // TODO(stuartmorgan): This should use SendAndRunNestedMessageLoop, as on
+ // Windows, to prevent getting a "hung renderer" dialog, but if we do we
+ // never actually break out of the nested loop and continue with printing.
+ // Once that's fixed, switch back to SendAndRunNestedMessageLoop.
+ //if (render_view_->SendAndRunNestedMessageLoop(msg)) {
+ if (render_view_->Send(msg)) {
+ msg = NULL;
+
+ // If the settings are invalid, early quit.
+ if (print_settings.params.dpi &&
+ print_settings.params.document_cookie) {
+ if (print_settings.params.selection_only) {
+ CopyAndPrint(print_settings, frame);
+ } else {
+ // TODO: Always copy before printing.
+ PrintPages(print_settings, frame);
+ }
+
+ // Reset cancel counter on first successful print.
+ user_cancelled_scripted_print_count_ = 0;
+ return; // All went well.
+ } else {
+ user_cancelled_print = true;
+ }
+ } else {
+ // Send() failed.
+ NOTREACHED();
+ }
+ } else {
+ // Failed to get default settings.
+ NOTREACHED();
+ }
+ } else {
+ // Send() failed.
+ NOTREACHED();
+ }
+ if (script_initiated && user_cancelled_print) {
+ ++user_cancelled_scripted_print_count_;
+ last_cancelled_script_print_ = base::Time::Now();
+ }
+ // When |user_cancelled_print| is true, we treat it as success so that
+ // DidFinishPrinting() won't show any error alert.
+ // If |user_cancelled_print| is false and we reach here, there must be
+ // something wrong and hence is not success, DidFinishPrinting() should show
+ // an error alert.
+ // In both cases, we have to call DidFinishPrinting() here to release
+ // printing resources, since we don't need them anymore.
+ DidFinishPrinting(user_cancelled_print);
+}
+
+void PrintWebViewHelper::PrintPages(const ViewMsg_PrintPages_Params& params,
+ WebKit::WebFrame* frame) {
+ PrepareFrameAndViewForPrint prep_frame_view(params.params,
+ frame,
+ frame->view());
+ int page_count = prep_frame_view.GetExpectedPageCount();
+
+ Send(new ViewHostMsg_DidGetPrintedPagesCount(routing_id(),
+ params.params.document_cookie,
+ page_count));
+ if (!page_count)
+ return;
+
+ const gfx::Size& canvas_size = prep_frame_view.GetPrintCanvasSize();
+ ViewMsg_PrintPage_Params page_params;
+ page_params.params = params.params;
+ if (params.pages.empty()) {
+ for (int i = 0; i < page_count; ++i) {
+ page_params.page_number = i;
+ PrintPage(page_params, canvas_size, frame);
+ }
+ } else {
+ for (size_t i = 0; i < params.pages.size(); ++i) {
+ if (params.pages[i] >= page_count)
+ break;
+ page_params.page_number = params.pages[i];
+ PrintPage(page_params, canvas_size, frame);
+ }
+ }
+}
+
+void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params,
+ const gfx::Size& canvas_size,
+ WebFrame* frame) {
+ printing::NativeMetafile metafile;
+ CGContextRef context = metafile.Init();
+
+ float scale_factor = frame->getPrintPageShrink(params.page_number);
+ metafile.StartPage(canvas_size.width(), canvas_size.height(), scale_factor);
+
+ // printPage can create autoreleased references to |canvas|. PDF contexts
+ // don't write all their data until they are destroyed, so we need to make
+ // certain that there are no lingering references.
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ frame->printPage(params.page_number, context);
+ [pool release];
+
+ metafile.FinishPage();
+ metafile.Close();
+
+ // Get the size of the compiled metafile.
+ ViewHostMsg_DidPrintPage_Params page_params;
+ page_params.data_size = 0;
+ page_params.page_number = params.page_number;
+ page_params.document_cookie = params.params.document_cookie;
+ page_params.actual_shrink = scale_factor;
+ base::SharedMemory shared_buf;
+
+ // Ask the browser to create the shared memory for us.
+ unsigned int buf_size = metafile.GetDataSize();
+ base::SharedMemoryHandle shared_mem_handle;
+ if (Send(new ViewHostMsg_AllocatePDFTransport(routing_id(), buf_size,
+ &shared_mem_handle))) {
+ if (base::SharedMemory::IsHandleValid(shared_mem_handle)) {
+ base::SharedMemory shared_buf(shared_mem_handle, false);
+ if (shared_buf.Map(buf_size)) {
+ metafile.GetData(shared_buf.memory(), buf_size);
+ page_params.data_size = buf_size;
+ shared_buf.GiveToProcess(base::GetCurrentProcessHandle(),
+ &(page_params.metafile_data_handle));
+ } else {
+ NOTREACHED() << "Map failed";
+ }
+ } else {
+ NOTREACHED() << "Browser failed to allocate shared memory";
+ }
+ } else {
+ NOTREACHED() << "Browser allocation request message failed";
+ }
+
+ Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params));
+}
+

Powered by Google App Engine
This is Rietveld 408576698