summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authordgn <dgn@chromium.org>2015-01-13 10:13:07 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-13 18:14:48 +0000
commit445b5974445aa9a0f8afc87214f9dff090d5255c (patch)
tree318fead70b2289c088af7e16b144ea14472967b5 /components
parent8d4511585ca0bba6364a53dcf6c2e2b5c4015d49 (diff)
downloadchromium_src-445b5974445aa9a0f8afc87214f9dff090d5255c.zip
chromium_src-445b5974445aa9a0f8afc87214f9dff090d5255c.tar.gz
chromium_src-445b5974445aa9a0f8afc87214f9dff090d5255c.tar.bz2
Moving files from //chrome to //components/printing
Other changes: - Modifying #includes and .gypi to target the new paths - Modifying DEPS files to allow the new paths - New gn, gypi, DEPS and OWNERS files for the new //components/printing BUG=444883 Review URL: https://codereview.chromium.org/811563008 Cr-Commit-Position: refs/heads/master@{#311293}
Diffstat (limited to 'components')
-rw-r--r--components/OWNERS5
-rw-r--r--components/components.gyp7
-rw-r--r--components/printing.gypi49
-rw-r--r--components/printing/DEPS7
-rw-r--r--components/printing/OWNERS4
-rw-r--r--components/printing/README3
-rw-r--r--components/printing/common/BUILD.gn18
-rw-r--r--components/printing/common/OWNERS14
-rw-r--r--components/printing/common/print_messages.cc92
-rw-r--r--components/printing/common/print_messages.h479
-rw-r--r--components/printing/renderer/BUILD.gn31
-rw-r--r--components/printing/renderer/DEPS6
-rw-r--r--components/printing/renderer/print_web_view_helper.cc2037
-rw-r--r--components/printing/renderer/print_web_view_helper.h499
-rw-r--r--components/printing/renderer/print_web_view_helper_android.cc7
-rw-r--r--components/printing/renderer/print_web_view_helper_linux.cc191
-rw-r--r--components/printing/renderer/print_web_view_helper_mac.mm145
-rw-r--r--components/printing/renderer/print_web_view_helper_pdf_win.cc233
-rw-r--r--components/printing/resources/print_preview_page.html117
-rw-r--r--components/resources/components_resources.grd1
-rw-r--r--components/resources/printing_resources.grdp6
21 files changed, 3951 insertions, 0 deletions
diff --git a/components/OWNERS b/components/OWNERS
index 2758535..6b7cd48 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -160,6 +160,11 @@ per-file pdf.gypi=thestig@chromium.org
per-file precache*=bengr@chromium.org
per-file precache*=sclittle@chromium.org
+per-file printing*=alekseys@chromium.org
+per-file printing*=gene@chromium.org
+per-file printing*=thestig@chromium.org
+per-file printing*=vitalybuka@chromium.org
+
per-file policy*=mnissler@chromium.org
per-file policy*=bartfab@chromium.org
per-file policy*=atwilson@chromium.org
diff --git a/components/components.gyp b/components/components.gyp
index 6d3fb3e..0972d45 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -140,6 +140,13 @@
'webdata_services.gypi',
],
}],
+ ['android_webview_build == 0 and OS != "ios"', {
+ 'includes': [
+ # TODO(dgn) move it to a condition based on whether print is enabled
+ # once the duplicates have been removed from webview.
+ 'printing.gypi',
+ ],
+ }],
['enable_plugins==1', {
'includes': [
'pdf.gypi',
diff --git a/components/printing.gypi b/components/printing.gypi
new file mode 100644
index 0000000..442df52
--- /dev/null
+++ b/components/printing.gypi
@@ -0,0 +1,49 @@
+# Copyright 2015 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.
+
+{
+ 'targets': [
+ {
+ # GN: //components/printing/common:printing_common
+ 'target_name': 'printing_common',
+ 'type': 'static_library',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/ipc/ipc.gyp:ipc',
+ '<(DEPTH)/printing/printing.gyp:printing',
+ '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ ],
+ 'sources': [
+ "printing/common/print_messages.cc",
+ "printing/common/print_messages.h",
+ ],
+ },{
+ # GN: //components/printing/common:printing_renderer
+ 'target_name': 'printing_renderer',
+ 'type': 'static_library',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/content/content.gyp:content_common',
+ '<(DEPTH)/content/content.gyp:content_renderer',
+ '<(DEPTH)/net/net.gyp:net',
+ '<(DEPTH)/printing/printing.gyp:printing',
+ '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
+ '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
+ 'components_resources.gyp:components_resources',
+ 'printing_common',
+ ],
+ 'sources': [
+ 'printing/renderer/print_web_view_helper.cc',
+ 'printing/renderer/print_web_view_helper.h',
+ 'printing/renderer/print_web_view_helper_android.cc',
+ 'printing/renderer/print_web_view_helper_linux.cc',
+ 'printing/renderer/print_web_view_helper_mac.mm',
+ 'printing/renderer/print_web_view_helper_pdf_win.cc',
+ ],
+ # TODO(dgn): C4267: http://crbug.com/167187 size_t -> int
+ 'msvs_disabled_warnings': [ 4267 ],
+ },
+ ],
+}
diff --git a/components/printing/DEPS b/components/printing/DEPS
new file mode 100644
index 0000000..057bda2
--- /dev/null
+++ b/components/printing/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+content/public",
+ "+ipc",
+ "+printing",
+ "+third_party/WebKit/public",
+ "+ui/gfx"
+]
diff --git a/components/printing/OWNERS b/components/printing/OWNERS
new file mode 100644
index 0000000..4406a70
--- /dev/null
+++ b/components/printing/OWNERS
@@ -0,0 +1,4 @@
+alekseys@chromium.org
+gene@chromium.org
+thestig@chromium.org
+vitalybuka@chromium.org
diff --git a/components/printing/README b/components/printing/README
new file mode 100644
index 0000000..7e036f5
--- /dev/null
+++ b/components/printing/README
@@ -0,0 +1,3 @@
+Printing is a work in progress component. It is introduced to allow chrome
+and webview to share the common printing-related code. When completed, it will
+contain the code necessary for using basic printing in content-based clients.
diff --git a/components/printing/common/BUILD.gn b/components/printing/common/BUILD.gn
new file mode 100644
index 0000000..3110072
--- /dev/null
+++ b/components/printing/common/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2015 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.
+
+static_library("printing_common") {
+ sources = [
+ "print_messages.cc",
+ "print_messages.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ipc",
+ "//printing",
+ "//third_party/WebKit/public:blink",
+ "//ui/gfx",
+ ]
+}
diff --git a/components/printing/common/OWNERS b/components/printing/common/OWNERS
new file mode 100644
index 0000000..cbc9bc9
--- /dev/null
+++ b/components/printing/common/OWNERS
@@ -0,0 +1,14 @@
+# Changes to IPC messages require a security review to avoid introducing
+# new sandbox escapes.
+per-file *messages*.h=set noparent
+per-file *messages*.h=dcheng@chromium.org
+per-file *messages*.h=inferno@chromium.org
+per-file *messages*.h=jln@chromium.org
+per-file *messages*.h=jorgelo@chromium.org
+per-file *messages*.h=jschuh@chromium.org
+per-file *messages*.h=kenrb@chromium.org
+per-file *messages*.h=mkwst@chromium.org
+per-file *messages*.h=nasko@chromium.org
+per-file *messages*.h=palmer@chromium.org
+per-file *messages*.h=tsepez@chromium.org
+per-file *messages*.h=wfh@chromium.org
diff --git a/components/printing/common/print_messages.cc b/components/printing/common/print_messages.cc
new file mode 100644
index 0000000..3a5cddd
--- /dev/null
+++ b/components/printing/common/print_messages.cc
@@ -0,0 +1,92 @@
+// 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.
+
+#include "components/printing/common/print_messages.h"
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "ui/gfx/geometry/size.h"
+
+PrintMsg_Print_Params::PrintMsg_Print_Params()
+ : page_size(),
+ content_size(),
+ printable_area(),
+ margin_top(0),
+ margin_left(0),
+ dpi(0),
+ min_shrink(0),
+ max_shrink(0),
+ desired_dpi(0),
+ document_cookie(0),
+ selection_only(false),
+ supports_alpha_blend(false),
+ preview_ui_id(-1),
+ preview_request_id(0),
+ is_first_request(false),
+ print_scaling_option(blink::WebPrintScalingOptionSourceSize),
+ print_to_pdf(false),
+ display_header_footer(false),
+ title(),
+ url(),
+ should_print_backgrounds(false) {
+}
+
+PrintMsg_Print_Params::~PrintMsg_Print_Params() {}
+
+void PrintMsg_Print_Params::Reset() {
+ page_size = gfx::Size();
+ content_size = gfx::Size();
+ printable_area = gfx::Rect();
+ margin_top = 0;
+ margin_left = 0;
+ dpi = 0;
+ min_shrink = 0;
+ max_shrink = 0;
+ desired_dpi = 0;
+ document_cookie = 0;
+ selection_only = false;
+ supports_alpha_blend = false;
+ preview_ui_id = -1;
+ preview_request_id = 0;
+ is_first_request = false;
+ print_scaling_option = blink::WebPrintScalingOptionSourceSize;
+ print_to_pdf = false;
+ display_header_footer = false;
+ title = base::string16();
+ url = base::string16();
+ should_print_backgrounds = false;
+}
+
+PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params()
+ : pages() {
+}
+
+PrintMsg_PrintPages_Params::~PrintMsg_PrintPages_Params() {}
+
+void PrintMsg_PrintPages_Params::Reset() {
+ params.Reset();
+ pages = std::vector<int>();
+}
+
+PrintHostMsg_RequestPrintPreview_Params::
+ PrintHostMsg_RequestPrintPreview_Params()
+ : is_modifiable(false),
+ webnode_only(false),
+ has_selection(false),
+ selection_only(false) {
+}
+
+PrintHostMsg_RequestPrintPreview_Params::
+ ~PrintHostMsg_RequestPrintPreview_Params() {}
+
+PrintHostMsg_SetOptionsFromDocument_Params::
+ PrintHostMsg_SetOptionsFromDocument_Params()
+ : is_scaling_disabled(false),
+ copies(0),
+ duplex(printing::UNKNOWN_DUPLEX_MODE) {
+}
+
+PrintHostMsg_SetOptionsFromDocument_Params::
+ ~PrintHostMsg_SetOptionsFromDocument_Params() {
+}
diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h
new file mode 100644
index 0000000..effc2f24
--- /dev/null
+++ b/components/printing/common/print_messages.h
@@ -0,0 +1,479 @@
+// 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.
+
+// IPC messages for printing.
+// Multiply-included message file, hence no include guard.
+
+#include <string>
+#include <vector>
+
+#include "base/memory/shared_memory.h"
+#include "base/values.h"
+#include "ipc/ipc_message_macros.h"
+#include "printing/page_range.h"
+#include "printing/page_size_margins.h"
+#include "printing/print_job_constants.h"
+#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/ipc/gfx_param_traits.h"
+#include "ui/gfx/native_widget_types.h"
+
+#ifndef COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
+#define COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
+
+struct PrintMsg_Print_Params {
+ PrintMsg_Print_Params();
+ ~PrintMsg_Print_Params();
+
+ // Resets the members of the struct to 0.
+ void Reset();
+
+ gfx::Size page_size;
+ gfx::Size content_size;
+ gfx::Rect printable_area;
+ int margin_top;
+ int margin_left;
+ double dpi;
+ double min_shrink;
+ double max_shrink;
+ int desired_dpi;
+ int document_cookie;
+ bool selection_only;
+ bool supports_alpha_blend;
+ int32 preview_ui_id;
+ int preview_request_id;
+ bool is_first_request;
+ blink::WebPrintScalingOption print_scaling_option;
+ bool print_to_pdf;
+ bool display_header_footer;
+ base::string16 title;
+ base::string16 url;
+ bool should_print_backgrounds;
+};
+
+struct PrintMsg_PrintPages_Params {
+ PrintMsg_PrintPages_Params();
+ ~PrintMsg_PrintPages_Params();
+
+ // Resets the members of the struct to 0.
+ void Reset();
+
+ PrintMsg_Print_Params params;
+ std::vector<int> pages;
+};
+
+struct PrintHostMsg_RequestPrintPreview_Params {
+ PrintHostMsg_RequestPrintPreview_Params();
+ ~PrintHostMsg_RequestPrintPreview_Params();
+ bool is_modifiable;
+ bool webnode_only;
+ bool has_selection;
+ bool selection_only;
+};
+
+struct PrintHostMsg_SetOptionsFromDocument_Params {
+ PrintHostMsg_SetOptionsFromDocument_Params();
+ ~PrintHostMsg_SetOptionsFromDocument_Params();
+
+ bool is_scaling_disabled;
+ int copies;
+ printing::DuplexMode duplex;
+ printing::PageRanges page_ranges;
+};
+
+#endif // COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
+
+#define IPC_MESSAGE_START PrintMsgStart
+
+IPC_ENUM_TRAITS_MAX_VALUE(printing::MarginType,
+ printing::MARGIN_TYPE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption,
+ blink::WebPrintScalingOptionLast)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(printing::DuplexMode,
+ printing::UNKNOWN_DUPLEX_MODE,
+ printing::SHORT_EDGE)
+
+// Parameters for a render request.
+IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
+ // Physical size of the page, including non-printable margins,
+ // in pixels according to dpi.
+ IPC_STRUCT_TRAITS_MEMBER(page_size)
+
+ // In pixels according to dpi_x and dpi_y.
+ IPC_STRUCT_TRAITS_MEMBER(content_size)
+
+ // Physical printable area of the page in pixels according to dpi.
+ IPC_STRUCT_TRAITS_MEMBER(printable_area)
+
+ // The y-offset of the printable area, in pixels according to dpi.
+ IPC_STRUCT_TRAITS_MEMBER(margin_top)
+
+ // The x-offset of the printable area, in pixels according to dpi.
+ IPC_STRUCT_TRAITS_MEMBER(margin_left)
+
+ // Specifies dots per inch.
+ IPC_STRUCT_TRAITS_MEMBER(dpi)
+
+ // Minimum shrink factor. See PrintSettings::min_shrink for more information.
+ IPC_STRUCT_TRAITS_MEMBER(min_shrink)
+
+ // Maximum shrink factor. See PrintSettings::max_shrink for more information.
+ IPC_STRUCT_TRAITS_MEMBER(max_shrink)
+
+ // Desired apparent dpi on paper.
+ IPC_STRUCT_TRAITS_MEMBER(desired_dpi)
+
+ // Cookie for the document to ensure correctness.
+ IPC_STRUCT_TRAITS_MEMBER(document_cookie)
+
+ // Should only print currently selected text.
+ IPC_STRUCT_TRAITS_MEMBER(selection_only)
+
+ // Does the printer support alpha blending?
+ IPC_STRUCT_TRAITS_MEMBER(supports_alpha_blend)
+
+ // *** Parameters below are used only for print preview. ***
+
+ // The print preview ui associated with this request.
+ IPC_STRUCT_TRAITS_MEMBER(preview_ui_id)
+
+ // The id of the preview request.
+ IPC_STRUCT_TRAITS_MEMBER(preview_request_id)
+
+ // True if this is the first preview request.
+ IPC_STRUCT_TRAITS_MEMBER(is_first_request)
+
+ // Specifies the page scaling option for preview printing.
+ IPC_STRUCT_TRAITS_MEMBER(print_scaling_option)
+
+ // True if print to pdf is requested.
+ IPC_STRUCT_TRAITS_MEMBER(print_to_pdf)
+
+ // Specifies if the header and footer should be rendered.
+ IPC_STRUCT_TRAITS_MEMBER(display_header_footer)
+
+ // Title string to be printed as header if requested by the user.
+ IPC_STRUCT_TRAITS_MEMBER(title)
+
+ // URL string to be printed as footer if requested by the user.
+ IPC_STRUCT_TRAITS_MEMBER(url)
+
+ // True if print backgrounds is requested by the user.
+ IPC_STRUCT_TRAITS_MEMBER(should_print_backgrounds)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_BEGIN(PrintMsg_PrintPage_Params)
+ // Parameters to render the page as a printed page. It must always be the same
+ // value for all the document.
+ IPC_STRUCT_MEMBER(PrintMsg_Print_Params, params)
+
+ // The page number is the indicator of the square that should be rendered
+ // according to the layout specified in PrintMsg_Print_Params.
+ IPC_STRUCT_MEMBER(int, page_number)
+IPC_STRUCT_END()
+
+IPC_STRUCT_TRAITS_BEGIN(PrintHostMsg_RequestPrintPreview_Params)
+ IPC_STRUCT_TRAITS_MEMBER(is_modifiable)
+ IPC_STRUCT_TRAITS_MEMBER(webnode_only)
+ IPC_STRUCT_TRAITS_MEMBER(has_selection)
+ IPC_STRUCT_TRAITS_MEMBER(selection_only)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(printing::PageRange)
+ IPC_STRUCT_TRAITS_MEMBER(from)
+ IPC_STRUCT_TRAITS_MEMBER(to)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(PrintHostMsg_SetOptionsFromDocument_Params)
+ // Specifies whether print scaling is enabled or not.
+ IPC_STRUCT_TRAITS_MEMBER(is_scaling_disabled)
+
+ // Specifies number of copies to be printed.
+ IPC_STRUCT_TRAITS_MEMBER(copies)
+
+ // Specifies paper handling option.
+ IPC_STRUCT_TRAITS_MEMBER(duplex)
+
+ // Specifies page range to be printed.
+ IPC_STRUCT_TRAITS_MEMBER(page_ranges)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(printing::PageSizeMargins)
+ IPC_STRUCT_TRAITS_MEMBER(content_width)
+ IPC_STRUCT_TRAITS_MEMBER(content_height)
+ IPC_STRUCT_TRAITS_MEMBER(margin_left)
+ IPC_STRUCT_TRAITS_MEMBER(margin_right)
+ IPC_STRUCT_TRAITS_MEMBER(margin_top)
+ IPC_STRUCT_TRAITS_MEMBER(margin_bottom)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params)
+ // Parameters to render the page as a printed page. It must always be the same
+ // value for all the document.
+ IPC_STRUCT_TRAITS_MEMBER(params)
+
+ // If empty, this means a request to render all the printed pages.
+ IPC_STRUCT_TRAITS_MEMBER(pages)
+IPC_STRUCT_TRAITS_END()
+
+// Parameters to describe a rendered document.
+IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params)
+ // A shared memory handle to metafile data.
+ IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
+
+ // Size of metafile data.
+ IPC_STRUCT_MEMBER(uint32, data_size)
+
+ // Cookie for the document to ensure correctness.
+ IPC_STRUCT_MEMBER(int, document_cookie)
+
+ // Store the expected pages count.
+ IPC_STRUCT_MEMBER(int, expected_pages_count)
+
+ // Whether the preview can be modified.
+ IPC_STRUCT_MEMBER(bool, modifiable)
+
+ // The id of the preview request.
+ IPC_STRUCT_MEMBER(int, preview_request_id)
+IPC_STRUCT_END()
+
+// Parameters to describe a rendered preview page.
+IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewPage_Params)
+ // A shared memory handle to metafile data for a draft document of the page.
+ IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
+
+ // Size of metafile data.
+ IPC_STRUCT_MEMBER(uint32, data_size)
+
+ // |page_number| is zero-based and can be |printing::INVALID_PAGE_INDEX| if it
+ // is just a check.
+ IPC_STRUCT_MEMBER(int, page_number)
+
+ // The id of the preview request.
+ IPC_STRUCT_MEMBER(int, preview_request_id)
+IPC_STRUCT_END()
+
+// Parameters sent along with the page count.
+IPC_STRUCT_BEGIN(PrintHostMsg_DidGetPreviewPageCount_Params)
+ // Cookie for the document to ensure correctness.
+ IPC_STRUCT_MEMBER(int, document_cookie)
+
+ // Total page count.
+ IPC_STRUCT_MEMBER(int, page_count)
+
+ // Indicates whether the previewed document is modifiable.
+ IPC_STRUCT_MEMBER(bool, is_modifiable)
+
+ // The id of the preview request.
+ IPC_STRUCT_MEMBER(int, preview_request_id)
+
+ // Indicates whether the existing preview data needs to be cleared or not.
+ IPC_STRUCT_MEMBER(bool, clear_preview_data)
+IPC_STRUCT_END()
+
+// Parameters to describe a rendered page.
+IPC_STRUCT_BEGIN(PrintHostMsg_DidPrintPage_Params)
+ // A shared memory handle to the EMF data. This data can be quite large so a
+ // memory map needs to be used.
+ IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
+
+ // Size of the metafile data.
+ IPC_STRUCT_MEMBER(uint32, data_size)
+
+ // Cookie for the document to ensure correctness.
+ IPC_STRUCT_MEMBER(int, document_cookie)
+
+ // Page number.
+ IPC_STRUCT_MEMBER(int, page_number)
+
+ // The size of the page the page author specified.
+ IPC_STRUCT_MEMBER(gfx::Size, page_size)
+
+ // The printable area the page author specified.
+ IPC_STRUCT_MEMBER(gfx::Rect, content_area)
+IPC_STRUCT_END()
+
+// TODO(dgn) Rename *ScriptedPrint messages because they are not called only
+// from scripts.
+// Parameters for the IPC message ViewHostMsg_ScriptedPrint
+IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params)
+ IPC_STRUCT_MEMBER(int, cookie)
+ IPC_STRUCT_MEMBER(int, expected_pages_count)
+ IPC_STRUCT_MEMBER(bool, has_selection)
+ IPC_STRUCT_MEMBER(bool, is_scripted)
+ IPC_STRUCT_MEMBER(printing::MarginType, margin_type)
+IPC_STRUCT_END()
+
+
+// Messages sent from the browser to the renderer.
+
+// Tells the render view to initiate print preview for the entire document.
+IPC_MESSAGE_ROUTED1(PrintMsg_InitiatePrintPreview, bool /* selection_only */)
+
+// Tells the render frame to initiate printing or print preview for a particular
+// node, depending on which mode the render frame is in.
+IPC_MESSAGE_ROUTED0(PrintMsg_PrintNodeUnderContextMenu)
+
+// Tells the renderer to print the print preview tab's PDF plugin without
+// showing the print dialog. (This is the final step in the print preview
+// workflow.)
+IPC_MESSAGE_ROUTED1(PrintMsg_PrintForPrintPreview,
+ base::DictionaryValue /* settings */)
+
+#if defined(ENABLE_BASIC_PRINTING)
+// Tells the render view to switch the CSS to print media type, renders every
+// requested pages and switch back the CSS to display media type.
+IPC_MESSAGE_ROUTED0(PrintMsg_PrintPages)
+
+// Like PrintMsg_PrintPages, but using the print preview document's frame/node.
+IPC_MESSAGE_ROUTED0(PrintMsg_PrintForSystemDialog)
+#endif // ENABLE_BASIC_PRINTING
+
+// Tells the render view that printing is done so it can clean up.
+IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone,
+ bool /* success */)
+
+// Tells the render view whether scripted printing is blocked or not.
+IPC_MESSAGE_ROUTED1(PrintMsg_SetScriptedPrintingBlocked,
+ bool /* blocked */)
+
+// Tells the render view to switch the CSS to print media type, renders every
+// requested pages for print preview using the given |settings|. This gets
+// called multiple times as the user updates settings.
+IPC_MESSAGE_ROUTED1(PrintMsg_PrintPreview,
+ base::DictionaryValue /* settings */)
+
+// Messages sent from the renderer to the browser.
+
+#if defined(OS_WIN)
+// Duplicates a shared memory handle from the renderer to the browser. Then
+// the renderer can flush the handle.
+IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DuplicateSection,
+ base::SharedMemoryHandle /* renderer handle */,
+ base::SharedMemoryHandle /* browser handle */)
+#endif
+
+// Check if printing is enabled.
+IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_IsPrintingEnabled,
+ bool /* is_enabled */)
+
+// Tells the browser that the renderer is done calculating the number of
+// rendered pages according to the specified settings.
+IPC_MESSAGE_ROUTED2(PrintHostMsg_DidGetPrintedPagesCount,
+ int /* rendered document cookie */,
+ int /* number of rendered pages */)
+
+// Sends the document cookie of the current printer query to the browser.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetDocumentCookie,
+ int /* rendered document cookie */)
+
+// Tells the browser that the print dialog has been shown.
+IPC_MESSAGE_ROUTED0(PrintHostMsg_DidShowPrintDialog)
+
+// Sends back to the browser the rendered "printed page" that was requested by
+// a ViewMsg_PrintPage message or from scripted printing. The memory handle in
+// this message is already valid in the browser process.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPrintPage,
+ PrintHostMsg_DidPrintPage_Params /* page content */)
+
+// The renderer wants to know the default print settings.
+IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings,
+ PrintMsg_Print_Params /* default_settings */)
+
+// The renderer wants to update the current print settings with new
+// |job_settings|.
+IPC_SYNC_MESSAGE_ROUTED2_2(PrintHostMsg_UpdatePrintSettings,
+ int /* document_cookie */,
+ base::DictionaryValue /* job_settings */,
+ PrintMsg_PrintPages_Params /* current_settings */,
+ bool /* canceled */)
+
+// It's the renderer that controls the printing process when it is generated
+// by javascript. This step is about showing UI to the user to select the
+// final print settings. The output parameter is the same as
+// ViewMsg_PrintPages which is executed implicitly.
+IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_ScriptedPrint,
+ PrintHostMsg_ScriptedPrint_Params,
+ PrintMsg_PrintPages_Params
+ /* settings chosen by the user*/)
+
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+// Asks the browser to create a temporary file for the renderer to fill
+// in resulting PdfMetafileSkia in printing.
+IPC_SYNC_MESSAGE_CONTROL1_2(PrintHostMsg_AllocateTempFileForPrinting,
+ int /* render_view_id */,
+ base::FileDescriptor /* temp file fd */,
+ int /* fd in browser*/) // Used only by Chrome OS.
+IPC_MESSAGE_CONTROL2(PrintHostMsg_TempFileForPrintingWritten,
+ int /* render_view_id */,
+ int /* fd in browser */) // Used only by Chrome OS.
+#endif
+
+// Asks the browser to do print preview.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_RequestPrintPreview,
+ PrintHostMsg_RequestPrintPreview_Params /* params */)
+
+// Notify the browser the number of pages in the print preview document.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetPreviewPageCount,
+ PrintHostMsg_DidGetPreviewPageCount_Params /* params */)
+
+// Notify the browser of the default page layout according to the currently
+// selected printer and page size.
+// |printable_area_in_points| Specifies the printable area in points.
+// |has_custom_page_size_style| is true when the printing frame has a custom
+// page size css otherwise false.
+IPC_MESSAGE_ROUTED3(PrintHostMsg_DidGetDefaultPageLayout,
+ printing::PageSizeMargins /* page layout in points */,
+ gfx::Rect /* printable area in points */,
+ bool /* has custom page size style */)
+
+// Notify the browser a print preview page has been rendered.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPreviewPage,
+ PrintHostMsg_DidPreviewPage_Params /* params */)
+
+// Asks the browser whether the print preview has been cancelled.
+IPC_SYNC_MESSAGE_ROUTED2_1(PrintHostMsg_CheckForCancel,
+ int32 /* PrintPreviewUI ID */,
+ int /* request id */,
+ bool /* print preview cancelled */)
+
+// This is sent when there are invalid printer settings.
+IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError)
+
+// Sends back to the browser the complete rendered document (non-draft mode,
+// used for printing) 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_MetafileReadyForPrinting,
+ PrintHostMsg_DidPreviewDocument_Params /* params */)
+
+// Tell the browser printing failed.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed,
+ int /* document cookie */)
+
+// Tell the browser print preview failed.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintPreviewFailed,
+ int /* document cookie */)
+
+// Tell the browser print preview was cancelled.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintPreviewCancelled,
+ int /* document cookie */)
+
+// Tell the browser print preview found the selected printer has invalid
+// settings (which typically caused by disconnected network printer or printer
+// driver is bogus).
+IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintPreviewInvalidPrinterSettings,
+ int /* document cookie */)
+
+// Run a nested message loop in the renderer until print preview for
+// window.print() finishes.
+IPC_SYNC_MESSAGE_ROUTED0_0(PrintHostMsg_SetupScriptedPrintPreview)
+
+// Tell the browser to show the print preview, when the document is sufficiently
+// loaded such that the renderer can determine whether it is modifiable or not.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_ShowScriptedPrintPreview,
+ bool /* is_modifiable */)
+
+// Notify the browser to set print presets based on source PDF document.
+IPC_MESSAGE_ROUTED1(PrintHostMsg_SetOptionsFromDocument,
+ PrintHostMsg_SetOptionsFromDocument_Params /* params */)
diff --git a/components/printing/renderer/BUILD.gn b/components/printing/renderer/BUILD.gn
new file mode 100644
index 0000000..768c95b
--- /dev/null
+++ b/components/printing/renderer/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2015 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.
+
+static_library("printing_renderer") {
+ sources = [
+ "print_web_view_helper.cc",
+ "print_web_view_helper.h",
+ "print_web_view_helper_android.cc",
+ "print_web_view_helper_linux.cc",
+ "print_web_view_helper_mac.mm",
+ "print_web_view_helper_pdf_win.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//components/printing/common:printing_common",
+ "//components/resources",
+ "//content/public/common",
+ "//content/public/renderer",
+ "//net",
+ "//printing",
+ "//third_party/WebKit/public:blink",
+ "//ui/base",
+ ]
+
+ if (is_win) {
+ # TODO(dgn): crbug.com/167187 fix size_t to int truncations.
+ cflags = [ "/wd4267" ]
+ }
+}
diff --git a/components/printing/renderer/DEPS b/components/printing/renderer/DEPS
new file mode 100644
index 0000000..ada73c4
--- /dev/null
+++ b/components/printing/renderer/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+grit/components_resources.h",
+ "+net/base",
+ "+skia/ext",
+ "+ui/base",
+]
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
new file mode 100644
index 0000000..4c9368b
--- /dev/null
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -0,0 +1,2037 @@
+// 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.
+
+#include "components/printing/renderer/print_web_view_helper.h"
+
+#include <string>
+
+#include "base/auto_reset.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/printing/common/print_messages.h"
+#include "content/public/common/web_preferences.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/public/renderer/render_view.h"
+#include "grit/components_resources.h"
+#include "net/base/escape.h"
+#include "printing/pdf_metafile_skia.h"
+#include "printing/units.h"
+#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrameClient.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebPlugin.h"
+#include "third_party/WebKit/public/web/WebPluginDocument.h"
+#include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "third_party/WebKit/public/web/WebPrintPresetOptions.h"
+#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/WebKit/public/web/WebViewClient.h"
+#include "ui/base/resource/resource_bundle.h"
+
+using content::WebPreferences;
+
+namespace printing {
+
+namespace {
+
+enum PrintPreviewHelperEvents {
+ PREVIEW_EVENT_REQUESTED,
+ PREVIEW_EVENT_CACHE_HIT, // Unused
+ PREVIEW_EVENT_CREATE_DOCUMENT,
+ PREVIEW_EVENT_NEW_SETTINGS, // Unused
+ PREVIEW_EVENT_MAX,
+};
+
+const double kMinDpi = 1.0;
+
+#if !defined(ENABLE_PRINT_PREVIEW)
+bool g_is_preview_enabled_ = false;
+#else
+bool g_is_preview_enabled_ = true;
+
+const char kPageLoadScriptFormat[] =
+ "document.open(); document.write(%s); document.close();";
+
+const char kPageSetupScriptFormat[] = "setup(%s);";
+
+void ExecuteScript(blink::WebFrame* frame,
+ const char* script_format,
+ const base::Value& parameters) {
+ std::string json;
+ base::JSONWriter::Write(&parameters, &json);
+ std::string script = base::StringPrintf(script_format, json.c_str());
+ frame->executeScript(blink::WebString(base::UTF8ToUTF16(script)));
+}
+#endif // !defined(ENABLE_PRINT_PREVIEW)
+
+int GetDPI(const PrintMsg_Print_Params* print_params) {
+#if defined(OS_MACOSX)
+ // On the Mac, the printable area is in points, don't do any scaling based
+ // on dpi.
+ return kPointsPerInch;
+#else
+ return static_cast<int>(print_params->dpi);
+#endif // defined(OS_MACOSX)
+}
+
+bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) {
+ return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() &&
+ !params.printable_area.IsEmpty() && params.document_cookie &&
+ params.desired_dpi && params.max_shrink && params.min_shrink &&
+ params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0) &&
+ params.dpi > kMinDpi && params.document_cookie != 0;
+}
+
+PrintMsg_Print_Params GetCssPrintParams(
+ blink::WebFrame* frame,
+ int page_index,
+ const PrintMsg_Print_Params& page_params) {
+ PrintMsg_Print_Params page_css_params = page_params;
+ int dpi = GetDPI(&page_params);
+
+ blink::WebSize page_size_in_pixels(
+ ConvertUnit(page_params.page_size.width(), dpi, kPixelsPerInch),
+ ConvertUnit(page_params.page_size.height(), dpi, kPixelsPerInch));
+ int margin_top_in_pixels =
+ ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch);
+ int margin_right_in_pixels = ConvertUnit(
+ page_params.page_size.width() -
+ page_params.content_size.width() - page_params.margin_left,
+ dpi, kPixelsPerInch);
+ int margin_bottom_in_pixels = ConvertUnit(
+ page_params.page_size.height() -
+ page_params.content_size.height() - page_params.margin_top,
+ dpi, kPixelsPerInch);
+ int margin_left_in_pixels = ConvertUnit(
+ page_params.margin_left,
+ dpi, kPixelsPerInch);
+
+ blink::WebSize original_page_size_in_pixels = page_size_in_pixels;
+
+ if (frame) {
+ frame->pageSizeAndMarginsInPixels(page_index,
+ page_size_in_pixels,
+ margin_top_in_pixels,
+ margin_right_in_pixels,
+ margin_bottom_in_pixels,
+ margin_left_in_pixels);
+ }
+
+ int new_content_width = page_size_in_pixels.width -
+ margin_left_in_pixels - margin_right_in_pixels;
+ int new_content_height = page_size_in_pixels.height -
+ margin_top_in_pixels - margin_bottom_in_pixels;
+
+ // Invalid page size and/or margins. We just use the default setting.
+ if (new_content_width < 1 || new_content_height < 1) {
+ CHECK(frame != NULL);
+ page_css_params = GetCssPrintParams(NULL, page_index, page_params);
+ return page_css_params;
+ }
+
+ page_css_params.content_size = gfx::Size(
+ ConvertUnit(new_content_width, kPixelsPerInch, dpi),
+ ConvertUnit(new_content_height, kPixelsPerInch, dpi));
+
+ if (original_page_size_in_pixels != page_size_in_pixels) {
+ page_css_params.page_size = gfx::Size(
+ ConvertUnit(page_size_in_pixels.width, kPixelsPerInch, dpi),
+ ConvertUnit(page_size_in_pixels.height, kPixelsPerInch, dpi));
+ } else {
+ // Printing frame doesn't have any page size css. Pixels to dpi conversion
+ // causes rounding off errors. Therefore use the default page size values
+ // directly.
+ page_css_params.page_size = page_params.page_size;
+ }
+
+ page_css_params.margin_top =
+ ConvertUnit(margin_top_in_pixels, kPixelsPerInch, dpi);
+ page_css_params.margin_left =
+ ConvertUnit(margin_left_in_pixels, kPixelsPerInch, dpi);
+ return page_css_params;
+}
+
+double FitPrintParamsToPage(const PrintMsg_Print_Params& page_params,
+ PrintMsg_Print_Params* params_to_fit) {
+ double content_width =
+ static_cast<double>(params_to_fit->content_size.width());
+ double content_height =
+ static_cast<double>(params_to_fit->content_size.height());
+ int default_page_size_height = page_params.page_size.height();
+ int default_page_size_width = page_params.page_size.width();
+ int css_page_size_height = params_to_fit->page_size.height();
+ int css_page_size_width = params_to_fit->page_size.width();
+
+ double scale_factor = 1.0f;
+ if (page_params.page_size == params_to_fit->page_size)
+ return scale_factor;
+
+ if (default_page_size_width < css_page_size_width ||
+ default_page_size_height < css_page_size_height) {
+ double ratio_width =
+ static_cast<double>(default_page_size_width) / css_page_size_width;
+ double ratio_height =
+ static_cast<double>(default_page_size_height) / css_page_size_height;
+ scale_factor = ratio_width < ratio_height ? ratio_width : ratio_height;
+ content_width *= scale_factor;
+ content_height *= scale_factor;
+ }
+ params_to_fit->margin_top = static_cast<int>(
+ (default_page_size_height - css_page_size_height * scale_factor) / 2 +
+ (params_to_fit->margin_top * scale_factor));
+ params_to_fit->margin_left = static_cast<int>(
+ (default_page_size_width - css_page_size_width * scale_factor) / 2 +
+ (params_to_fit->margin_left * scale_factor));
+ params_to_fit->content_size = gfx::Size(
+ static_cast<int>(content_width), static_cast<int>(content_height));
+ params_to_fit->page_size = page_params.page_size;
+ return scale_factor;
+}
+
+void CalculatePageLayoutFromPrintParams(
+ const PrintMsg_Print_Params& params,
+ PageSizeMargins* page_layout_in_points) {
+ int dpi = GetDPI(&params);
+ int content_width = params.content_size.width();
+ int content_height = params.content_size.height();
+
+ int margin_bottom = params.page_size.height() -
+ content_height - params.margin_top;
+ int margin_right = params.page_size.width() -
+ content_width - params.margin_left;
+
+ page_layout_in_points->content_width =
+ ConvertUnit(content_width, dpi, kPointsPerInch);
+ page_layout_in_points->content_height =
+ ConvertUnit(content_height, dpi, kPointsPerInch);
+ page_layout_in_points->margin_top =
+ ConvertUnit(params.margin_top, dpi, kPointsPerInch);
+ page_layout_in_points->margin_right =
+ ConvertUnit(margin_right, dpi, kPointsPerInch);
+ page_layout_in_points->margin_bottom =
+ ConvertUnit(margin_bottom, dpi, kPointsPerInch);
+ page_layout_in_points->margin_left =
+ ConvertUnit(params.margin_left, dpi, kPointsPerInch);
+}
+
+void EnsureOrientationMatches(const PrintMsg_Print_Params& css_params,
+ PrintMsg_Print_Params* page_params) {
+ if ((page_params->page_size.width() > page_params->page_size.height()) ==
+ (css_params.page_size.width() > css_params.page_size.height())) {
+ return;
+ }
+
+ // Swap the |width| and |height| values.
+ page_params->page_size.SetSize(page_params->page_size.height(),
+ page_params->page_size.width());
+ page_params->content_size.SetSize(page_params->content_size.height(),
+ page_params->content_size.width());
+ page_params->printable_area.set_size(
+ gfx::Size(page_params->printable_area.height(),
+ page_params->printable_area.width()));
+}
+
+void ComputeWebKitPrintParamsInDesiredDpi(
+ const PrintMsg_Print_Params& print_params,
+ blink::WebPrintParams* webkit_print_params) {
+ int dpi = GetDPI(&print_params);
+ webkit_print_params->printerDPI = dpi;
+ webkit_print_params->printScalingOption = print_params.print_scaling_option;
+
+ webkit_print_params->printContentArea.width =
+ ConvertUnit(print_params.content_size.width(), dpi,
+ print_params.desired_dpi);
+ webkit_print_params->printContentArea.height =
+ ConvertUnit(print_params.content_size.height(), dpi,
+ print_params.desired_dpi);
+
+ webkit_print_params->printableArea.x =
+ ConvertUnit(print_params.printable_area.x(), dpi,
+ print_params.desired_dpi);
+ webkit_print_params->printableArea.y =
+ ConvertUnit(print_params.printable_area.y(), dpi,
+ print_params.desired_dpi);
+ webkit_print_params->printableArea.width =
+ ConvertUnit(print_params.printable_area.width(), dpi,
+ print_params.desired_dpi);
+ webkit_print_params->printableArea.height =
+ ConvertUnit(print_params.printable_area.height(),
+ dpi, print_params.desired_dpi);
+
+ webkit_print_params->paperSize.width =
+ ConvertUnit(print_params.page_size.width(), dpi,
+ print_params.desired_dpi);
+ webkit_print_params->paperSize.height =
+ ConvertUnit(print_params.page_size.height(), dpi,
+ print_params.desired_dpi);
+}
+
+blink::WebPlugin* GetPlugin(const blink::WebFrame* frame) {
+ return frame->document().isPluginDocument() ?
+ frame->document().to<blink::WebPluginDocument>().plugin() : NULL;
+}
+
+bool PrintingNodeOrPdfFrame(const blink::WebFrame* frame,
+ const blink::WebNode& node) {
+ if (!node.isNull())
+ return true;
+ blink::WebPlugin* plugin = GetPlugin(frame);
+ return plugin && plugin->supportsPaginatedPrint();
+}
+
+bool PrintingFrameHasPageSizeStyle(blink::WebFrame* frame,
+ int total_page_count) {
+ if (!frame)
+ return false;
+ bool frame_has_custom_page_size_style = false;
+ for (int i = 0; i < total_page_count; ++i) {
+ if (frame->hasCustomPageSizeStyle(i)) {
+ frame_has_custom_page_size_style = true;
+ break;
+ }
+ }
+ return frame_has_custom_page_size_style;
+}
+
+MarginType GetMarginsForPdf(blink::WebFrame* frame,
+ const blink::WebNode& node) {
+ if (frame->isPrintScalingDisabledForPlugin(node))
+ return NO_MARGINS;
+ else
+ return PRINTABLE_AREA_MARGINS;
+}
+
+bool FitToPageEnabled(const base::DictionaryValue& job_settings) {
+ bool fit_to_paper_size = false;
+ if (!job_settings.GetBoolean(kSettingFitToPageEnabled, &fit_to_paper_size)) {
+ NOTREACHED();
+ }
+ return fit_to_paper_size;
+}
+
+// Returns the print scaling option to retain/scale/crop the source page size
+// to fit the printable area of the paper.
+//
+// We retain the source page size when the current destination printer is
+// SAVE_AS_PDF.
+//
+// We crop the source page size to fit the printable area or we print only the
+// left top page contents when
+// (1) Source is PDF and the user has requested not to fit to printable area
+// via |job_settings|.
+// (2) Source is PDF. This is the first preview request and print scaling
+// option is disabled for initiator renderer plugin.
+//
+// In all other cases, we scale the source page to fit the printable area.
+blink::WebPrintScalingOption GetPrintScalingOption(
+ blink::WebFrame* frame,
+ const blink::WebNode& node,
+ bool source_is_html,
+ const base::DictionaryValue& job_settings,
+ const PrintMsg_Print_Params& params) {
+ if (params.print_to_pdf)
+ return blink::WebPrintScalingOptionSourceSize;
+
+ if (!source_is_html) {
+ if (!FitToPageEnabled(job_settings))
+ return blink::WebPrintScalingOptionNone;
+
+ bool no_plugin_scaling = frame->isPrintScalingDisabledForPlugin(node);
+
+ if (params.is_first_request && no_plugin_scaling)
+ return blink::WebPrintScalingOptionNone;
+ }
+ return blink::WebPrintScalingOptionFitToPrintableArea;
+}
+
+PrintMsg_Print_Params CalculatePrintParamsForCss(
+ blink::WebFrame* frame,
+ int page_index,
+ const PrintMsg_Print_Params& page_params,
+ bool ignore_css_margins,
+ bool fit_to_page,
+ double* scale_factor) {
+ PrintMsg_Print_Params css_params = GetCssPrintParams(frame, page_index,
+ page_params);
+
+ PrintMsg_Print_Params params = page_params;
+ EnsureOrientationMatches(css_params, &params);
+
+ if (ignore_css_margins && fit_to_page)
+ return params;
+
+ PrintMsg_Print_Params result_params = css_params;
+ if (ignore_css_margins) {
+ result_params.margin_top = params.margin_top;
+ result_params.margin_left = params.margin_left;
+
+ DCHECK(!fit_to_page);
+ // Since we are ignoring the margins, the css page size is no longer
+ // valid.
+ int default_margin_right = params.page_size.width() -
+ params.content_size.width() - params.margin_left;
+ int default_margin_bottom = params.page_size.height() -
+ params.content_size.height() - params.margin_top;
+ result_params.content_size = gfx::Size(
+ result_params.page_size.width() - result_params.margin_left -
+ default_margin_right,
+ result_params.page_size.height() - result_params.margin_top -
+ default_margin_bottom);
+ }
+
+ if (fit_to_page) {
+ double factor = FitPrintParamsToPage(params, &result_params);
+ if (scale_factor)
+ *scale_factor = factor;
+ }
+ return result_params;
+}
+
+} // namespace
+
+FrameReference::FrameReference(blink::WebLocalFrame* frame) {
+ Reset(frame);
+}
+
+FrameReference::FrameReference() {
+ Reset(NULL);
+}
+
+FrameReference::~FrameReference() {
+}
+
+void FrameReference::Reset(blink::WebLocalFrame* frame) {
+ if (frame) {
+ view_ = frame->view();
+ frame_ = frame;
+ } else {
+ view_ = NULL;
+ frame_ = NULL;
+ }
+}
+
+blink::WebLocalFrame* FrameReference::GetFrame() {
+ if (view_ == NULL || frame_ == NULL)
+ return NULL;
+ for (blink::WebFrame* frame = view_->mainFrame(); frame != NULL;
+ frame = frame->traverseNext(false)) {
+ if (frame == frame_)
+ return frame_;
+ }
+ return NULL;
+}
+
+blink::WebView* FrameReference::view() {
+ return view_;
+}
+
+#if defined(ENABLE_PRINT_PREVIEW)
+// static - Not anonymous so that platform implementations can use it.
+void PrintWebViewHelper::PrintHeaderAndFooter(
+ blink::WebCanvas* canvas,
+ int page_number,
+ int total_pages,
+ const blink::WebFrame& source_frame,
+ float webkit_scale_factor,
+ const PageSizeMargins& page_layout,
+ const PrintMsg_Print_Params& params) {
+ SkAutoCanvasRestore auto_restore(canvas, true);
+ canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor);
+
+ blink::WebSize page_size(page_layout.margin_left + page_layout.margin_right +
+ page_layout.content_width,
+ page_layout.margin_top + page_layout.margin_bottom +
+ page_layout.content_height);
+
+ blink::WebView* web_view = blink::WebView::create(NULL);
+ web_view->settings()->setJavaScriptEnabled(true);
+
+ blink::WebLocalFrame* frame = blink::WebLocalFrame::create(NULL);
+ web_view->setMainFrame(frame);
+
+ base::StringValue html(ResourceBundle::GetSharedInstance().GetLocalizedString(
+ IDR_PRINT_PREVIEW_PAGE));
+ // Load page with script to avoid async operations.
+ ExecuteScript(frame, kPageLoadScriptFormat, html);
+
+ scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue());
+ options.reset(new base::DictionaryValue());
+ options->SetDouble(kSettingHeaderFooterDate, base::Time::Now().ToJsTime());
+ options->SetDouble("width", page_size.width);
+ options->SetDouble("height", page_size.height);
+ options->SetDouble("topMargin", page_layout.margin_top);
+ options->SetDouble("bottomMargin", page_layout.margin_bottom);
+ options->SetString("pageNumber",
+ base::StringPrintf("%d/%d", page_number, total_pages));
+
+ // Fallback to initiator URL and title if it's empty for printed frame.
+ base::string16 url = source_frame.document().url().string();
+ options->SetString("url", url.empty() ? params.url : url);
+ base::string16 title = source_frame.document().title();
+ options->SetString("title", title.empty() ? params.title : title);
+
+ ExecuteScript(frame, kPageSetupScriptFormat, *options);
+
+ blink::WebPrintParams webkit_params(page_size);
+ webkit_params.printerDPI = GetDPI(&params);
+
+ frame->printBegin(webkit_params);
+ frame->printPage(0, canvas);
+ frame->printEnd();
+
+ web_view->close();
+ frame->close();
+}
+#endif // defined(ENABLE_PRINT_PREVIEW)
+
+// static - Not anonymous so that platform implementations can use it.
+float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame,
+ int page_number,
+ const gfx::Rect& canvas_area,
+ const gfx::Rect& content_area,
+ double scale_factor,
+ blink::WebCanvas* canvas) {
+ SkAutoCanvasRestore auto_restore(canvas, true);
+ if (content_area != canvas_area) {
+ canvas->translate((content_area.x() - canvas_area.x()) / scale_factor,
+ (content_area.y() - canvas_area.y()) / scale_factor);
+ SkRect clip_rect(
+ SkRect::MakeXYWH(content_area.origin().x() / scale_factor,
+ content_area.origin().y() / scale_factor,
+ content_area.size().width() / scale_factor,
+ content_area.size().height() / scale_factor));
+ SkIRect clip_int_rect;
+ clip_rect.roundOut(&clip_int_rect);
+ SkRegion clip_region(clip_int_rect);
+ canvas->setClipRegion(clip_region);
+ }
+ return frame->printPage(page_number, canvas);
+}
+
+// Class that calls the Begin and End print functions on the frame and changes
+// the size of the view temporarily to support full page printing..
+class PrepareFrameAndViewForPrint : public blink::WebViewClient,
+ public blink::WebFrameClient {
+ public:
+ PrepareFrameAndViewForPrint(const PrintMsg_Print_Params& params,
+ blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ bool ignore_css_margins);
+ virtual ~PrepareFrameAndViewForPrint();
+
+ // Optional. Replaces |frame_| with selection if needed. Will call |on_ready|
+ // when completed.
+ void CopySelectionIfNeeded(const WebPreferences& preferences,
+ const base::Closure& on_ready);
+
+ // Prepares frame for printing.
+ void StartPrinting();
+
+ blink::WebLocalFrame* frame() {
+ return frame_.GetFrame();
+ }
+
+ const blink::WebNode& node() const {
+ return node_to_print_;
+ }
+
+ int GetExpectedPageCount() const {
+ return expected_pages_count_;
+ }
+
+ void FinishPrinting();
+
+ bool IsLoadingSelection() {
+ // It's not selection if not |owns_web_view_|.
+ return owns_web_view_ && frame() && frame()->isLoading();
+ }
+
+ // TODO(ojan): Remove this override and have this class use a non-null
+ // layerTreeView.
+ // blink::WebViewClient override:
+ virtual bool allowsBrokenNullLayerTreeView() const;
+
+ protected:
+ // blink::WebViewClient override:
+ virtual void didStopLoading();
+
+ // blink::WebFrameClient override:
+ virtual blink::WebFrame* createChildFrame(blink::WebLocalFrame* parent,
+ const blink::WebString& name);
+ virtual void frameDetached(blink::WebFrame* frame);
+
+ private:
+ void CallOnReady();
+ void ResizeForPrinting();
+ void RestoreSize();
+ void CopySelection(const WebPreferences& preferences);
+
+ FrameReference frame_;
+ blink::WebNode node_to_print_;
+ bool owns_web_view_;
+ blink::WebPrintParams web_print_params_;
+ gfx::Size prev_view_size_;
+ gfx::Size prev_scroll_offset_;
+ int expected_pages_count_;
+ base::Closure on_ready_;
+ bool should_print_backgrounds_;
+ bool should_print_selection_only_;
+ bool is_printing_started_;
+
+ base::WeakPtrFactory<PrepareFrameAndViewForPrint> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint);
+};
+
+PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
+ const PrintMsg_Print_Params& params,
+ blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ bool ignore_css_margins)
+ : frame_(frame),
+ node_to_print_(node),
+ owns_web_view_(false),
+ expected_pages_count_(0),
+ should_print_backgrounds_(params.should_print_backgrounds),
+ should_print_selection_only_(params.selection_only),
+ is_printing_started_(false),
+ weak_ptr_factory_(this) {
+ PrintMsg_Print_Params print_params = params;
+ if (!should_print_selection_only_ ||
+ !PrintingNodeOrPdfFrame(frame, node_to_print_)) {
+ bool fit_to_page = ignore_css_margins &&
+ print_params.print_scaling_option ==
+ blink::WebPrintScalingOptionFitToPrintableArea;
+ ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_);
+ frame->printBegin(web_print_params_, node_to_print_);
+ print_params = CalculatePrintParamsForCss(frame, 0, print_params,
+ ignore_css_margins, fit_to_page,
+ NULL);
+ frame->printEnd();
+ }
+ ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_);
+}
+
+PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
+ FinishPrinting();
+}
+
+void PrepareFrameAndViewForPrint::ResizeForPrinting() {
+ // Layout page according to printer page size. Since WebKit shrinks the
+ // size of the page automatically (from 125% to 200%) we trick it to
+ // think the page is 125% larger so the size of the page is correct for
+ // minimum (default) scaling.
+ // This is important for sites that try to fill the page.
+ gfx::Size print_layout_size(web_print_params_.printContentArea.width,
+ web_print_params_.printContentArea.height);
+ print_layout_size.set_height(
+ static_cast<int>(static_cast<double>(print_layout_size.height()) * 1.25));
+
+ if (!frame())
+ return;
+ blink::WebView* web_view = frame_.view();
+ // Backup size and offset.
+ if (blink::WebFrame* web_frame = web_view->mainFrame())
+ prev_scroll_offset_ = web_frame->scrollOffset();
+ prev_view_size_ = web_view->size();
+
+ web_view->resize(print_layout_size);
+}
+
+
+void PrepareFrameAndViewForPrint::StartPrinting() {
+ ResizeForPrinting();
+ blink::WebView* web_view = frame_.view();
+ web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_);
+ expected_pages_count_ =
+ frame()->printBegin(web_print_params_, node_to_print_);
+ is_printing_started_ = true;
+}
+
+void PrepareFrameAndViewForPrint::CopySelectionIfNeeded(
+ const WebPreferences& preferences,
+ const base::Closure& on_ready) {
+ on_ready_ = on_ready;
+ if (should_print_selection_only_) {
+ CopySelection(preferences);
+ } else {
+ // Call immediately, async call crashes scripting printing.
+ CallOnReady();
+ }
+}
+
+void PrepareFrameAndViewForPrint::CopySelection(
+ const WebPreferences& preferences) {
+ ResizeForPrinting();
+ std::string url_str = "data:text/html;charset=utf-8,";
+ url_str.append(
+ net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false));
+ RestoreSize();
+ // Create a new WebView with the same settings as the current display one.
+ // Except that we disable javascript (don't want any active content running
+ // on the page).
+ WebPreferences prefs = preferences;
+ prefs.javascript_enabled = false;
+ prefs.java_enabled = false;
+
+ blink::WebView* web_view = blink::WebView::create(this);
+ owns_web_view_ = true;
+ content::RenderView::ApplyWebPreferences(prefs, web_view);
+ web_view->setMainFrame(blink::WebLocalFrame::create(this));
+ frame_.Reset(web_view->mainFrame()->toWebLocalFrame());
+ node_to_print_.reset();
+
+ // When loading is done this will call didStopLoading() and that will do the
+ // actual printing.
+ frame()->loadRequest(blink::WebURLRequest(GURL(url_str)));
+}
+
+bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
+ return true;
+}
+
+void PrepareFrameAndViewForPrint::didStopLoading() {
+ DCHECK(!on_ready_.is_null());
+ // Don't call callback here, because it can delete |this| and WebView that is
+ // called didStopLoading.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PrepareFrameAndViewForPrint::CallOnReady,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame(
+ blink::WebLocalFrame* parent,
+ const blink::WebString& name) {
+ blink::WebFrame* frame = blink::WebLocalFrame::create(this);
+ parent->appendChild(frame);
+ return frame;
+}
+
+void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame) {
+ if (frame->parent())
+ frame->parent()->removeChild(frame);
+ frame->close();
+}
+
+void PrepareFrameAndViewForPrint::CallOnReady() {
+ return on_ready_.Run(); // Can delete |this|.
+}
+
+void PrepareFrameAndViewForPrint::RestoreSize() {
+ if (frame()) {
+ blink::WebView* web_view = frame_.GetFrame()->view();
+ web_view->resize(prev_view_size_);
+ if (blink::WebFrame* web_frame = web_view->mainFrame())
+ web_frame->setScrollOffset(prev_scroll_offset_);
+ }
+}
+
+void PrepareFrameAndViewForPrint::FinishPrinting() {
+ blink::WebLocalFrame* frame = frame_.GetFrame();
+ if (frame) {
+ blink::WebView* web_view = frame->view();
+ if (is_printing_started_) {
+ is_printing_started_ = false;
+ frame->printEnd();
+ if (!owns_web_view_) {
+ web_view->settings()->setShouldPrintBackgrounds(false);
+ RestoreSize();
+ }
+ }
+ if (owns_web_view_) {
+ DCHECK(!frame->isLoading());
+ owns_web_view_ = false;
+ web_view->close();
+ }
+ }
+ frame_.Reset(NULL);
+ on_ready_.Reset();
+}
+
+PrintWebViewHelper::PrintWebViewHelper(
+ content::RenderView* render_view,
+ bool out_of_process_pdf_enabled,
+ bool print_preview_disabled,
+ scoped_ptr<Delegate> delegate)
+ : content::RenderViewObserver(render_view),
+ content::RenderViewObserverTracker<PrintWebViewHelper>(render_view),
+ reset_prep_frame_view_(false),
+ is_print_ready_metafile_sent_(false),
+ ignore_css_margins_(false),
+ is_scripted_printing_blocked_(false),
+ notify_browser_of_print_failure_(true),
+ print_for_preview_(false),
+ out_of_process_pdf_enabled_(out_of_process_pdf_enabled),
+ delegate_(delegate.Pass()),
+ print_node_in_progress_(false),
+ is_loading_(false),
+ is_scripted_preview_delayed_(false),
+ weak_ptr_factory_(this) {
+ if (print_preview_disabled)
+ DisablePreview();
+}
+
+PrintWebViewHelper::~PrintWebViewHelper() {}
+
+// static
+void PrintWebViewHelper::DisablePreview() {
+ g_is_preview_enabled_ = false;
+}
+
+bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
+ blink::WebFrame* frame, bool user_initiated) {
+ // If preview is enabled, then the print dialog is tab modal, and the user
+ // can always close the tab on a mis-behaving page (the system print dialog
+ // is app modal). If the print was initiated through user action, don't
+ // throttle. Or, if the command line flag to skip throttling has been set.
+ return !is_scripted_printing_blocked_ &&
+ (user_initiated || g_is_preview_enabled_ ||
+ scripting_throttler_.IsAllowed(frame));
+}
+
+void PrintWebViewHelper::DidStartLoading() {
+ is_loading_ = true;
+}
+
+void PrintWebViewHelper::DidStopLoading() {
+ is_loading_ = false;
+ if (!on_stop_loading_closure_.is_null()) {
+ on_stop_loading_closure_.Run();
+ on_stop_loading_closure_.Reset();
+ }
+}
+
+// Prints |frame| which called window.print().
+void PrintWebViewHelper::PrintPage(blink::WebLocalFrame* frame,
+ bool user_initiated) {
+ DCHECK(frame);
+
+ // Allow Prerendering to cancel this print request if necessary.
+ if (delegate_->CancelPrerender(render_view(), routing_id()))
+ return;
+
+ if (!IsScriptInitiatedPrintAllowed(frame, user_initiated))
+ return;
+
+ if (!g_is_preview_enabled_) {
+ Print(frame, blink::WebNode(), true);
+ } else {
+ print_preview_context_.InitWithFrame(frame);
+ RequestPrintPreview(PRINT_PREVIEW_SCRIPTED);
+ }
+}
+
+bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message)
+#if defined(ENABLE_BASIC_PRINTING)
+ IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages)
+ IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog)
+#endif // ENABLE_BASIC_PRINTING
+ IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview, OnInitiatePrintPreview)
+ IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview)
+ IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview, OnPrintForPrintPreview)
+ IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone)
+ IPC_MESSAGE_HANDLER(PrintMsg_SetScriptedPrintingBlocked,
+ SetScriptedPrintBlocked)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void PrintWebViewHelper::OnPrintForPrintPreview(
+ const base::DictionaryValue& job_settings) {
+ // If still not finished with earlier print request simply ignore.
+ if (prep_frame_view_)
+ return;
+
+ if (!render_view()->GetWebView())
+ return;
+ blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
+ if (!main_frame)
+ return;
+
+ blink::WebDocument document = main_frame->document();
+ // <object>/<iframe> with id="pdf-viewer" is created in
+ // chrome/browser/resources/print_preview/print_preview.js
+ blink::WebElement pdf_element = document.getElementById("pdf-viewer");
+ if (pdf_element.isNull()) {
+ NOTREACHED();
+ return;
+ }
+
+ // The out-of-process plugin element is nested within a frame. In tests, there
+ // may not be an iframe containing the out-of-process plugin, so continue with
+ // the element with ID "pdf-viewer" if it isn't an iframe.
+ blink::WebLocalFrame* plugin_frame = pdf_element.document().frame();
+ blink::WebElement plugin_element = pdf_element;
+ if (out_of_process_pdf_enabled_ && pdf_element.hasHTMLTagName("iframe")) {
+ plugin_frame = blink::WebLocalFrame::fromFrameOwnerElement(pdf_element);
+ plugin_element = delegate_->GetPdfElement(plugin_frame);
+ if (plugin_element.isNull()) {
+ NOTREACHED();
+ return;
+ }
+ }
+
+ // Set |print_for_preview_| flag and autoreset it to back to original
+ // on return.
+ base::AutoReset<bool> set_printing_flag(&print_for_preview_, true);
+
+ if (!UpdatePrintSettings(plugin_frame, plugin_element, job_settings)) {
+ LOG(ERROR) << "UpdatePrintSettings failed";
+ DidFinishPrinting(FAIL_PRINT);
+ return;
+ }
+
+ // Print page onto entire page not just printable area. Preview PDF already
+ // has content in correct position taking into account page size and printable
+ // area.
+ // TODO(vitalybuka) : Make this consistent on all platform. This change
+ // affects Windows only. On Linux and OSX RenderPagesForPrint does not use
+ // printable_area. Also we can't change printable_area deeper inside
+ // RenderPagesForPrint for Windows, because it's used also by native
+ // printing and it expects real printable_area value.
+ // See http://crbug.com/123408
+ PrintMsg_Print_Params& print_params = print_pages_params_->params;
+ print_params.printable_area = gfx::Rect(print_params.page_size);
+
+ // Render Pages for printing.
+ if (!RenderPagesForPrint(plugin_frame, plugin_element)) {
+ LOG(ERROR) << "RenderPagesForPrint failed";
+ DidFinishPrinting(FAIL_PRINT);
+ }
+}
+
+bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) {
+ DCHECK(frame);
+ blink::WebView* webView = render_view()->GetWebView();
+ DCHECK(webView);
+ if (!webView)
+ return false;
+
+ // If the user has selected text in the currently focused frame we print
+ // only that frame (this makes print selection work for multiple frames).
+ blink::WebLocalFrame* focusedFrame =
+ webView->focusedFrame()->toWebLocalFrame();
+ *frame = focusedFrame->hasSelection()
+ ? focusedFrame
+ : webView->mainFrame()->toWebLocalFrame();
+ return true;
+}
+
+#if defined(ENABLE_BASIC_PRINTING)
+void PrintWebViewHelper::OnPrintPages() {
+ blink::WebLocalFrame* frame;
+ if (!GetPrintFrame(&frame))
+ return;
+ // If we are printing a PDF extension frame, find the plugin node and print
+ // that instead.
+ auto plugin = delegate_->GetPdfElement(frame);
+ Print(frame, plugin, false);
+}
+
+void PrintWebViewHelper::OnPrintForSystemDialog() {
+ blink::WebLocalFrame* frame = print_preview_context_.source_frame();
+ if (!frame) {
+ NOTREACHED();
+ return;
+ }
+ Print(frame, print_preview_context_.source_node(), false);
+}
+#endif // ENABLE_BASIC_PRINTING
+
+void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
+ const PageSizeMargins& page_layout_in_points,
+ gfx::Size* page_size,
+ gfx::Rect* content_area) {
+ *page_size = gfx::Size(
+ page_layout_in_points.content_width +
+ page_layout_in_points.margin_right +
+ page_layout_in_points.margin_left,
+ page_layout_in_points.content_height +
+ page_layout_in_points.margin_top +
+ page_layout_in_points.margin_bottom);
+ *content_area = gfx::Rect(page_layout_in_points.margin_left,
+ page_layout_in_points.margin_top,
+ page_layout_in_points.content_width,
+ page_layout_in_points.content_height);
+}
+
+void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
+ const base::DictionaryValue& settings) {
+ int margins_type = 0;
+ if (!settings.GetInteger(kSettingMarginsType, &margins_type))
+ margins_type = DEFAULT_MARGINS;
+ ignore_css_margins_ = (margins_type != DEFAULT_MARGINS);
+}
+
+bool PrintWebViewHelper::IsPrintToPdfRequested(
+ const base::DictionaryValue& job_settings) {
+ bool print_to_pdf = false;
+ if (!job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf))
+ NOTREACHED();
+ return print_to_pdf;
+}
+
+void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) {
+ print_preview_context_.OnPrintPreview();
+
+ UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
+ PREVIEW_EVENT_REQUESTED, PREVIEW_EVENT_MAX);
+
+ if (!print_preview_context_.source_frame()) {
+ DidFinishPrinting(FAIL_PREVIEW);
+ return;
+ }
+
+ if (!UpdatePrintSettings(print_preview_context_.source_frame(),
+ print_preview_context_.source_node(), settings)) {
+ if (print_preview_context_.last_error() != PREVIEW_ERROR_BAD_SETTING) {
+ Send(new PrintHostMsg_PrintPreviewInvalidPrinterSettings(
+ routing_id(),
+ print_pages_params_ ?
+ print_pages_params_->params.document_cookie : 0));
+ notify_browser_of_print_failure_ = false; // Already sent.
+ }
+ DidFinishPrinting(FAIL_PREVIEW);
+ return;
+ }
+
+ // Set the options from document if we are previewing a pdf and send a
+ // message to browser.
+ if (print_pages_params_->params.is_first_request &&
+ !print_preview_context_.IsModifiable()) {
+ PrintHostMsg_SetOptionsFromDocument_Params params;
+ SetOptionsFromDocument(params);
+ Send(new PrintHostMsg_SetOptionsFromDocument(routing_id(), params));
+ }
+
+ is_print_ready_metafile_sent_ = false;
+
+ // PDF printer device supports alpha blending.
+ print_pages_params_->params.supports_alpha_blend = true;
+
+ bool generate_draft_pages = false;
+ if (!settings.GetBoolean(kSettingGenerateDraftData,
+ &generate_draft_pages)) {
+ NOTREACHED();
+ }
+ print_preview_context_.set_generate_draft_pages(generate_draft_pages);
+
+ PrepareFrameForPreviewDocument();
+}
+
+void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
+ reset_prep_frame_view_ = false;
+
+ if (!print_pages_params_ || CheckForCancel()) {
+ DidFinishPrinting(FAIL_PREVIEW);
+ return;
+ }
+
+ // Don't reset loading frame or WebKit will fail assert. Just retry when
+ // current selection is loaded.
+ if (prep_frame_view_ && prep_frame_view_->IsLoadingSelection()) {
+ reset_prep_frame_view_ = true;
+ return;
+ }
+
+ const PrintMsg_Print_Params& print_params = print_pages_params_->params;
+ prep_frame_view_.reset(
+ new PrepareFrameAndViewForPrint(print_params,
+ print_preview_context_.source_frame(),
+ print_preview_context_.source_node(),
+ ignore_css_margins_));
+ prep_frame_view_->CopySelectionIfNeeded(
+ render_view()->GetWebkitPreferences(),
+ base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument,
+ base::Unretained(this)));
+}
+
+void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
+ if (reset_prep_frame_view_) {
+ PrepareFrameForPreviewDocument();
+ return;
+ }
+ DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW);
+}
+
+bool PrintWebViewHelper::CreatePreviewDocument() {
+ if (!print_pages_params_ || CheckForCancel())
+ return false;
+
+ UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
+ PREVIEW_EVENT_CREATE_DOCUMENT, PREVIEW_EVENT_MAX);
+
+ const PrintMsg_Print_Params& print_params = print_pages_params_->params;
+ const std::vector<int>& pages = print_pages_params_->pages;
+
+ if (!print_preview_context_.CreatePreviewDocument(prep_frame_view_.release(),
+ pages)) {
+ return false;
+ }
+
+ PageSizeMargins default_page_layout;
+ ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(), 0,
+ print_params, ignore_css_margins_, NULL,
+ &default_page_layout);
+
+ bool has_page_size_style = PrintingFrameHasPageSizeStyle(
+ print_preview_context_.prepared_frame(),
+ print_preview_context_.total_page_count());
+ int dpi = GetDPI(&print_params);
+
+ gfx::Rect printable_area_in_points(
+ ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch),
+ ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch),
+ ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch),
+ ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch));
+
+ // Margins: Send default page layout to browser process.
+ Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
+ default_page_layout,
+ printable_area_in_points,
+ has_page_size_style));
+
+ PrintHostMsg_DidGetPreviewPageCount_Params params;
+ params.page_count = print_preview_context_.total_page_count();
+ params.is_modifiable = print_preview_context_.IsModifiable();
+ params.document_cookie = print_params.document_cookie;
+ params.preview_request_id = print_params.preview_request_id;
+ params.clear_preview_data = print_preview_context_.generate_draft_pages();
+ Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params));
+ if (CheckForCancel())
+ return false;
+
+ while (!print_preview_context_.IsFinalPageRendered()) {
+ int page_number = print_preview_context_.GetNextPageNumber();
+ DCHECK_GE(page_number, 0);
+ if (!RenderPreviewPage(page_number, print_params))
+ return false;
+
+ if (CheckForCancel())
+ return false;
+
+ // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of
+ // print_preview_context_.AllPagesRendered()) before calling
+ // FinalizePrintReadyDocument() when printing a PDF because the plugin
+ // code does not generate output until we call FinishPrinting(). We do not
+ // generate draft pages for PDFs, so IsFinalPageRendered() and
+ // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of
+ // the loop.
+ if (print_preview_context_.IsFinalPageRendered())
+ print_preview_context_.AllPagesRendered();
+
+ if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) {
+ DCHECK(print_preview_context_.IsModifiable() ||
+ print_preview_context_.IsFinalPageRendered());
+ if (!FinalizePrintReadyDocument())
+ return false;
+ }
+ }
+ print_preview_context_.Finished();
+ return true;
+}
+
+bool PrintWebViewHelper::FinalizePrintReadyDocument() {
+ DCHECK(!is_print_ready_metafile_sent_);
+ print_preview_context_.FinalizePrintReadyDocument();
+
+ // Get the size of the resulting metafile.
+ PdfMetafileSkia* metafile = print_preview_context_.metafile();
+ uint32 buf_size = metafile->GetDataSize();
+ DCHECK_GT(buf_size, 0u);
+
+ PrintHostMsg_DidPreviewDocument_Params preview_params;
+ preview_params.data_size = buf_size;
+ preview_params.document_cookie = print_pages_params_->params.document_cookie;
+ preview_params.expected_pages_count =
+ print_preview_context_.total_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))) {
+ LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
+ print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
+ return false;
+ }
+ is_print_ready_metafile_sent_ = true;
+
+ Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params));
+ return true;
+}
+
+void PrintWebViewHelper::OnPrintingDone(bool success) {
+ notify_browser_of_print_failure_ = false;
+ if (!success)
+ LOG(ERROR) << "Failure in OnPrintingDone";
+ DidFinishPrinting(success ? OK : FAIL_PRINT);
+}
+
+void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked) {
+ is_scripted_printing_blocked_ = blocked;
+}
+
+void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only) {
+ blink::WebLocalFrame* frame = NULL;
+ GetPrintFrame(&frame);
+ DCHECK(frame);
+ // If we are printing a PDF extension frame, find the plugin node and print
+ // that instead.
+ auto plugin = delegate_->GetPdfElement(frame);
+ if (!plugin.isNull()) {
+ PrintNode(plugin);
+ return;
+ }
+ print_preview_context_.InitWithFrame(frame);
+ RequestPrintPreview(selection_only ?
+ PRINT_PREVIEW_USER_INITIATED_SELECTION :
+ PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME);
+}
+
+bool PrintWebViewHelper::IsPrintingEnabled() {
+ bool result = false;
+ Send(new PrintHostMsg_IsPrintingEnabled(routing_id(), &result));
+ return result;
+}
+
+void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
+ if (node.isNull() || !node.document().frame()) {
+ // This can occur when the context menu refers to an invalid WebNode.
+ // See http://crbug.com/100890#c17 for a repro case.
+ return;
+ }
+
+ if (print_node_in_progress_) {
+ // This can happen as a result of processing sync messages when printing
+ // from ppapi plugins. It's a rare case, so its OK to just fail here.
+ // See http://crbug.com/159165.
+ return;
+ }
+
+ print_node_in_progress_ = true;
+
+ // Make a copy of the node, in case RenderView::OnContextMenuClosed resets
+ // its |context_menu_node_|.
+ if (!g_is_preview_enabled_) {
+ blink::WebNode duplicate_node(node);
+ Print(duplicate_node.document().frame(), duplicate_node, false);
+ } else {
+ print_preview_context_.InitWithNode(node);
+ RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE);
+ }
+
+ print_node_in_progress_ = false;
+}
+
+void PrintWebViewHelper::Print(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ bool is_scripted) {
+ // If still not finished with earlier print request simply ignore.
+ if (prep_frame_view_)
+ return;
+
+ FrameReference frame_ref(frame);
+
+ int expected_page_count = 0;
+ if (!CalculateNumberOfPages(frame, node, &expected_page_count)) {
+ DidFinishPrinting(FAIL_PRINT_INIT);
+ return; // Failed to init print page settings.
+ }
+
+ // Some full screen plugins can say they don't want to print.
+ if (!expected_page_count) {
+ DidFinishPrinting(FAIL_PRINT);
+ return;
+ }
+
+ // Ask the browser to show UI to retrieve the final print settings.
+ if (!GetPrintSettingsFromUser(frame_ref.GetFrame(), node,
+ expected_page_count,
+ is_scripted)) {
+ DidFinishPrinting(OK); // Release resources and fail silently.
+ return;
+ }
+
+ // Render Pages for printing.
+ if (!RenderPagesForPrint(frame_ref.GetFrame(), node)) {
+ LOG(ERROR) << "RenderPagesForPrint failed";
+ DidFinishPrinting(FAIL_PRINT);
+ }
+ scripting_throttler_.Reset();
+}
+
+void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
+ switch (result) {
+ case OK:
+ break;
+
+ case FAIL_PRINT_INIT:
+ DCHECK(!notify_browser_of_print_failure_);
+ break;
+
+ case FAIL_PRINT:
+ if (notify_browser_of_print_failure_ && print_pages_params_) {
+ int cookie = print_pages_params_->params.document_cookie;
+ Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
+ }
+ break;
+
+ case FAIL_PREVIEW:
+ int cookie = print_pages_params_ ?
+ print_pages_params_->params.document_cookie : 0;
+ if (notify_browser_of_print_failure_) {
+ LOG(ERROR) << "CreatePreviewDocument failed";
+ Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie));
+ } else {
+ Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie));
+ }
+ print_preview_context_.Failed(notify_browser_of_print_failure_);
+ break;
+ }
+ prep_frame_view_.reset();
+ print_pages_params_.reset();
+ notify_browser_of_print_failure_ = true;
+}
+
+void PrintWebViewHelper::OnFramePreparedForPrintPages() {
+ PrintPages();
+ FinishFramePrinting();
+}
+
+void PrintWebViewHelper::PrintPages() {
+ if (!prep_frame_view_) // Printing is already canceled or failed.
+ return;
+ prep_frame_view_->StartPrinting();
+
+ int page_count = prep_frame_view_->GetExpectedPageCount();
+ if (!page_count) {
+ LOG(ERROR) << "Can't print 0 pages.";
+ return DidFinishPrinting(FAIL_PRINT);
+ }
+
+ const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+ const PrintMsg_Print_Params& print_params = params.params;
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+ // TODO(vitalybuka): should be page_count or valid pages from params.pages.
+ // See http://crbug.com/161576
+ Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
+ print_params.document_cookie,
+ page_count));
+#endif // !defined(OS_CHROMEOS)
+
+ if (print_params.preview_ui_id < 0) {
+ // Printing for system dialog.
+ int printed_count = params.pages.empty() ? page_count : params.pages.size();
+#if !defined(OS_CHROMEOS)
+ UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count);
+#else
+ UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
+ printed_count);
+#endif // !defined(OS_CHROMEOS)
+ }
+
+
+ if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) {
+ LOG(ERROR) << "Printing failed.";
+ return DidFinishPrinting(FAIL_PRINT);
+ }
+}
+
+void PrintWebViewHelper::FinishFramePrinting() {
+ prep_frame_view_.reset();
+}
+
+#if defined(OS_MACOSX)
+bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+ int page_count) {
+ const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+ const PrintMsg_Print_Params& print_params = params.params;
+
+ PrintMsg_PrintPage_Params page_params;
+ page_params.params = print_params;
+ if (params.pages.empty()) {
+ for (int i = 0; i < page_count; ++i) {
+ page_params.page_number = i;
+ PrintPageInternal(page_params, 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];
+ PrintPageInternal(page_params, frame);
+ }
+ }
+ return true;
+}
+
+#endif // OS_MACOSX
+
+// static - Not anonymous so that platform implementations can use it.
+void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
+ blink::WebFrame* frame,
+ int page_index,
+ const PrintMsg_Print_Params& page_params,
+ bool ignore_css_margins,
+ double* scale_factor,
+ PageSizeMargins* page_layout_in_points) {
+ PrintMsg_Print_Params params = CalculatePrintParamsForCss(
+ frame, page_index, page_params, ignore_css_margins,
+ page_params.print_scaling_option ==
+ blink::WebPrintScalingOptionFitToPrintableArea,
+ scale_factor);
+ CalculatePageLayoutFromPrintParams(params, page_layout_in_points);
+}
+
+bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
+ PrintMsg_PrintPages_Params settings;
+ Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
+ &settings.params));
+ // Check if the printer returned any settings, if the settings is empty, we
+ // can safely assume there are no printer drivers configured. So we safely
+ // terminate.
+ bool result = true;
+ if (!PrintMsg_Print_Params_IsValid(settings.params))
+ result = false;
+
+ // Reset to default values.
+ ignore_css_margins_ = false;
+ settings.pages.clear();
+
+ settings.params.print_scaling_option =
+ blink::WebPrintScalingOptionSourceSize;
+ if (fit_to_paper_size) {
+ settings.params.print_scaling_option =
+ blink::WebPrintScalingOptionFitToPrintableArea;
+ }
+
+ SetPrintPagesParams(settings);
+ return result;
+}
+
+bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ int* number_of_pages) {
+ DCHECK(frame);
+ bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node));
+ if (!InitPrintSettings(fit_to_paper_size)) {
+ notify_browser_of_print_failure_ = false;
+ Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
+ return false;
+ }
+
+ const PrintMsg_Print_Params& params = print_pages_params_->params;
+ PrepareFrameAndViewForPrint prepare(params, frame, node, ignore_css_margins_);
+ prepare.StartPrinting();
+
+ *number_of_pages = prepare.GetExpectedPageCount();
+ return true;
+}
+
+void PrintWebViewHelper::SetOptionsFromDocument(
+ PrintHostMsg_SetOptionsFromDocument_Params& params) {
+ blink::WebLocalFrame* source_frame = print_preview_context_.source_frame();
+ const blink::WebNode& source_node = print_preview_context_.source_node();
+
+ blink::WebPrintPresetOptions preset_options;
+ if (!source_frame->getPrintPresetOptionsForPlugin(source_node,
+ &preset_options)) {
+ return;
+ }
+
+ params.is_scaling_disabled = preset_options.isScalingDisabled;
+ params.copies = preset_options.copies;
+}
+
+bool PrintWebViewHelper::UpdatePrintSettings(
+ blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ const base::DictionaryValue& passed_job_settings) {
+ const base::DictionaryValue* job_settings = &passed_job_settings;
+ base::DictionaryValue modified_job_settings;
+ if (job_settings->empty()) {
+ if (!print_for_preview_)
+ print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
+ return false;
+ }
+
+ bool source_is_html = true;
+ if (print_for_preview_) {
+ if (!job_settings->GetBoolean(kSettingPreviewModifiable, &source_is_html)) {
+ NOTREACHED();
+ }
+ } else {
+ source_is_html = !PrintingNodeOrPdfFrame(frame, node);
+ }
+
+ if (print_for_preview_ || !source_is_html) {
+ modified_job_settings.MergeDictionary(job_settings);
+ modified_job_settings.SetBoolean(kSettingHeaderFooterEnabled, false);
+ modified_job_settings.SetInteger(kSettingMarginsType, NO_MARGINS);
+ job_settings = &modified_job_settings;
+ }
+
+ // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when
+ // possible.
+ int cookie = print_pages_params_ ?
+ print_pages_params_->params.document_cookie : 0;
+ PrintMsg_PrintPages_Params settings;
+ bool canceled = false;
+ Send(new PrintHostMsg_UpdatePrintSettings(
+ routing_id(), cookie, *job_settings, &settings, &canceled));
+ if (canceled) {
+ notify_browser_of_print_failure_ = false;
+ return false;
+ }
+
+ if (!job_settings->GetInteger(kPreviewUIID, &settings.params.preview_ui_id)) {
+ NOTREACHED();
+ print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
+ return false;
+ }
+
+ if (!print_for_preview_) {
+ // Validate expected print preview settings.
+ if (!job_settings->GetInteger(kPreviewRequestID,
+ &settings.params.preview_request_id) ||
+ !job_settings->GetBoolean(kIsFirstRequest,
+ &settings.params.is_first_request)) {
+ NOTREACHED();
+ print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
+ return false;
+ }
+
+ settings.params.print_to_pdf = IsPrintToPdfRequested(*job_settings);
+ UpdateFrameMarginsCssInfo(*job_settings);
+ settings.params.print_scaling_option = GetPrintScalingOption(
+ frame, node, source_is_html, *job_settings, settings.params);
+ }
+
+ SetPrintPagesParams(settings);
+
+ if (!PrintMsg_Print_Params_IsValid(settings.params)) {
+ if (!print_for_preview_)
+ print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS);
+ else
+ Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
+
+ return false;
+ }
+
+ return true;
+}
+
+bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame,
+ const blink::WebNode& node,
+ int expected_pages_count,
+ bool is_scripted) {
+ PrintHostMsg_ScriptedPrint_Params params;
+ PrintMsg_PrintPages_Params print_settings;
+
+ params.cookie = print_pages_params_->params.document_cookie;
+ params.has_selection = frame->hasSelection();
+ params.expected_pages_count = expected_pages_count;
+ MarginType margin_type = DEFAULT_MARGINS;
+ if (PrintingNodeOrPdfFrame(frame, node))
+ margin_type = GetMarginsForPdf(frame, node);
+ params.margin_type = margin_type;
+ params.is_scripted = is_scripted;
+
+ Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));
+
+ // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the
+ // value before and restore it afterwards.
+ blink::WebPrintScalingOption scaling_option =
+ print_pages_params_->params.print_scaling_option;
+
+ print_pages_params_.reset();
+ IPC::SyncMessage* msg =
+ new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings);
+ msg->EnableMessagePumping();
+ Send(msg);
+ print_settings.params.print_scaling_option = scaling_option;
+ SetPrintPagesParams(print_settings);
+ return (print_settings.params.dpi && print_settings.params.document_cookie);
+}
+
+bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
+ const blink::WebNode& node) {
+ if (!frame || prep_frame_view_)
+ return false;
+ const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+ const PrintMsg_Print_Params& print_params = params.params;
+ prep_frame_view_.reset(new PrepareFrameAndViewForPrint(
+ print_params, frame, node, ignore_css_margins_));
+ DCHECK(!print_pages_params_->params.selection_only ||
+ print_pages_params_->pages.empty());
+ prep_frame_view_->CopySelectionIfNeeded(
+ render_view()->GetWebkitPreferences(),
+ base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages,
+ base::Unretained(this)));
+ return true;
+}
+
+#if defined(OS_POSIX)
+bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
+ PdfMetafileSkia* metafile,
+ base::SharedMemoryHandle* shared_mem_handle) {
+ uint32 buf_size = metafile->GetDataSize();
+ scoped_ptr<base::SharedMemory> shared_buf(
+ content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
+ buf_size).release());
+
+ if (shared_buf) {
+ if (shared_buf->Map(buf_size)) {
+ metafile->GetData(shared_buf->memory(), buf_size);
+ return shared_buf->GiveToProcess(base::GetCurrentProcessHandle(),
+ shared_mem_handle);
+ }
+ }
+ return false;
+}
+#endif // defined(OS_POSIX)
+
+void PrintWebViewHelper::ShowScriptedPrintPreview() {
+ if (is_scripted_preview_delayed_) {
+ is_scripted_preview_delayed_ = false;
+ Send(new PrintHostMsg_ShowScriptedPrintPreview(routing_id(),
+ print_preview_context_.IsModifiable()));
+ }
+}
+
+void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
+ const bool is_modifiable = print_preview_context_.IsModifiable();
+ const bool has_selection = print_preview_context_.HasSelection();
+ PrintHostMsg_RequestPrintPreview_Params params;
+ params.is_modifiable = is_modifiable;
+ params.has_selection = has_selection;
+ switch (type) {
+ case PRINT_PREVIEW_SCRIPTED: {
+ // Shows scripted print preview in two stages.
+ // 1. PrintHostMsg_SetupScriptedPrintPreview blocks this call and JS by
+ // pumping messages here.
+ // 2. PrintHostMsg_ShowScriptedPrintPreview shows preview once the
+ // document has been loaded.
+ is_scripted_preview_delayed_ = true;
+ if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
+ // Wait for DidStopLoading. Plugins may not know the correct
+ // |is_modifiable| value until they are fully loaded, which occurs when
+ // DidStopLoading() is called. Defer showing the preview until then.
+ on_stop_loading_closure_ =
+ base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
+ base::Unretained(this));
+ } else {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ IPC::SyncMessage* msg =
+ new PrintHostMsg_SetupScriptedPrintPreview(routing_id());
+ msg->EnableMessagePumping();
+ Send(msg);
+ is_scripted_preview_delayed_ = false;
+ return;
+ }
+ case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME: {
+ // Wait for DidStopLoading. Continuing with this function while
+ // |is_loading_| is true will cause print preview to hang when try to
+ // print a PDF document.
+ if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
+ on_stop_loading_closure_ =
+ base::Bind(&PrintWebViewHelper::RequestPrintPreview,
+ base::Unretained(this),
+ type);
+ return;
+ }
+
+ break;
+ }
+ case PRINT_PREVIEW_USER_INITIATED_SELECTION: {
+ DCHECK(has_selection);
+ DCHECK(!GetPlugin(print_preview_context_.source_frame()));
+ params.selection_only = has_selection;
+ break;
+ }
+ case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE: {
+ if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
+ on_stop_loading_closure_ =
+ base::Bind(&PrintWebViewHelper::RequestPrintPreview,
+ base::Unretained(this),
+ type);
+ return;
+ }
+
+ params.webnode_only = true;
+ break;
+ }
+ default: {
+ NOTREACHED();
+ return;
+ }
+ }
+ Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params));
+}
+
+bool PrintWebViewHelper::CheckForCancel() {
+ const PrintMsg_Print_Params& print_params = print_pages_params_->params;
+ bool cancel = false;
+ Send(new PrintHostMsg_CheckForCancel(routing_id(),
+ print_params.preview_ui_id,
+ print_params.preview_request_id,
+ &cancel));
+ if (cancel)
+ notify_browser_of_print_failure_ = false;
+ return cancel;
+}
+
+bool PrintWebViewHelper::PreviewPageRendered(int page_number,
+ PdfMetafileSkia* metafile) {
+ DCHECK_GE(page_number, FIRST_PAGE_INDEX);
+
+ // For non-modifiable files, |metafile| should be NULL, so do not bother
+ // sending a message. If we don't generate draft metafiles, |metafile| is
+ // NULL.
+ if (!print_preview_context_.IsModifiable() ||
+ !print_preview_context_.generate_draft_pages()) {
+ DCHECK(!metafile);
+ return true;
+ }
+
+ if (!metafile) {
+ NOTREACHED();
+ print_preview_context_.set_error(
+ PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE);
+ return false;
+ }
+
+ PrintHostMsg_DidPreviewPage_Params preview_page_params;
+ // Get the size of the resulting metafile.
+ uint32 buf_size = metafile->GetDataSize();
+ DCHECK_GT(buf_size, 0u);
+ if (!CopyMetafileDataToSharedMem(
+ metafile, &(preview_page_params.metafile_data_handle))) {
+ LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
+ print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
+ return false;
+ }
+ preview_page_params.data_size = buf_size;
+ preview_page_params.page_number = page_number;
+ preview_page_params.preview_request_id =
+ print_pages_params_->params.preview_request_id;
+
+ Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params));
+ return true;
+}
+
+PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
+ : total_page_count_(0),
+ current_page_index_(0),
+ generate_draft_pages_(true),
+ print_ready_metafile_page_count_(0),
+ error_(PREVIEW_ERROR_NONE),
+ state_(UNINITIALIZED) {
+}
+
+PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
+}
+
+void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
+ blink::WebLocalFrame* web_frame) {
+ DCHECK(web_frame);
+ DCHECK(!IsRendering());
+ state_ = INITIALIZED;
+ source_frame_.Reset(web_frame);
+ source_node_.reset();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
+ const blink::WebNode& web_node) {
+ DCHECK(!web_node.isNull());
+ DCHECK(web_node.document().frame());
+ DCHECK(!IsRendering());
+ state_ = INITIALIZED;
+ source_frame_.Reset(web_node.document().frame());
+ source_node_ = web_node;
+}
+
+void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
+ DCHECK_EQ(INITIALIZED, state_);
+ ClearContext();
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
+ PrepareFrameAndViewForPrint* prepared_frame,
+ const std::vector<int>& pages) {
+ DCHECK_EQ(INITIALIZED, state_);
+ state_ = RENDERING;
+
+ // Need to make sure old object gets destroyed first.
+ prep_frame_view_.reset(prepared_frame);
+ prep_frame_view_->StartPrinting();
+
+ total_page_count_ = prep_frame_view_->GetExpectedPageCount();
+ if (total_page_count_ == 0) {
+ LOG(ERROR) << "CreatePreviewDocument got 0 page count";
+ set_error(PREVIEW_ERROR_ZERO_PAGES);
+ return false;
+ }
+
+ metafile_.reset(new PdfMetafileSkia);
+ if (!metafile_->Init()) {
+ set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED);
+ LOG(ERROR) << "PdfMetafileSkia Init failed";
+ return false;
+ }
+
+ current_page_index_ = 0;
+ pages_to_render_ = pages;
+ // Sort and make unique.
+ std::sort(pages_to_render_.begin(), pages_to_render_.end());
+ pages_to_render_.resize(std::unique(pages_to_render_.begin(),
+ pages_to_render_.end()) -
+ pages_to_render_.begin());
+ // Remove invalid pages.
+ pages_to_render_.resize(std::lower_bound(pages_to_render_.begin(),
+ pages_to_render_.end(),
+ total_page_count_) -
+ pages_to_render_.begin());
+ print_ready_metafile_page_count_ = pages_to_render_.size();
+ if (pages_to_render_.empty()) {
+ print_ready_metafile_page_count_ = total_page_count_;
+ // Render all pages.
+ for (int i = 0; i < total_page_count_; ++i)
+ pages_to_render_.push_back(i);
+ } else if (generate_draft_pages_) {
+ int pages_index = 0;
+ for (int i = 0; i < total_page_count_; ++i) {
+ if (pages_index < print_ready_metafile_page_count_ &&
+ i == pages_to_render_[pages_index]) {
+ pages_index++;
+ continue;
+ }
+ pages_to_render_.push_back(i);
+ }
+ }
+
+ document_render_time_ = base::TimeDelta();
+ begin_time_ = base::TimeTicks::Now();
+
+ return true;
+}
+
+void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
+ const base::TimeDelta& page_time) {
+ DCHECK_EQ(RENDERING, state_);
+ document_render_time_ += page_time;
+ UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
+}
+
+void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
+ DCHECK_EQ(RENDERING, state_);
+ state_ = DONE;
+ prep_frame_view_->FinishPrinting();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
+ DCHECK(IsRendering());
+
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+ metafile_->FinishDocument();
+
+ if (print_ready_metafile_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_;
+ UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
+ total_time);
+ UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
+ total_time / pages_to_render_.size());
+}
+
+void PrintWebViewHelper::PrintPreviewContext::Finished() {
+ DCHECK_EQ(DONE, state_);
+ state_ = INITIALIZED;
+ ClearContext();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) {
+ DCHECK(state_ == INITIALIZED || state_ == RENDERING);
+ state_ = INITIALIZED;
+ if (report_error) {
+ DCHECK_NE(PREVIEW_ERROR_NONE, error_);
+ UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_,
+ PREVIEW_ERROR_LAST_ENUM);
+ }
+ ClearContext();
+}
+
+int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
+ DCHECK_EQ(RENDERING, state_);
+ if (IsFinalPageRendered())
+ return -1;
+ return pages_to_render_[current_page_index_++];
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
+ return state_ == RENDERING || state_ == DONE;
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
+ // The only kind of node we can print right now is a PDF node.
+ return !PrintingNodeOrPdfFrame(source_frame(), source_node_);
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
+ return IsModifiable() && source_frame()->hasSelection();
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
+ const {
+ DCHECK(IsRendering());
+ return current_page_index_ == print_ready_metafile_page_count_;
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
+ DCHECK(IsRendering());
+ return static_cast<size_t>(current_page_index_) == pages_to_render_.size();
+}
+
+void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
+ bool generate_draft_pages) {
+ DCHECK_EQ(INITIALIZED, state_);
+ generate_draft_pages_ = generate_draft_pages;
+}
+
+void PrintWebViewHelper::PrintPreviewContext::set_error(
+ enum PrintPreviewErrorBuckets error) {
+ error_ = error;
+}
+
+blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() {
+ DCHECK(state_ != UNINITIALIZED);
+ return source_frame_.GetFrame();
+}
+
+const blink::WebNode&
+ PrintWebViewHelper::PrintPreviewContext::source_node() const {
+ DCHECK(state_ != UNINITIALIZED);
+ return source_node_;
+}
+
+blink::WebLocalFrame*
+PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
+ DCHECK(state_ != UNINITIALIZED);
+ return prep_frame_view_->frame();
+}
+
+const blink::WebNode&
+ PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
+ DCHECK(state_ != UNINITIALIZED);
+ return prep_frame_view_->node();
+}
+
+int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
+ DCHECK(state_ != UNINITIALIZED);
+ return total_page_count_;
+}
+
+bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
+ return generate_draft_pages_;
+}
+
+PdfMetafileSkia* PrintWebViewHelper::PrintPreviewContext::metafile() {
+ DCHECK(IsRendering());
+ return metafile_.get();
+}
+
+int PrintWebViewHelper::PrintPreviewContext::last_error() const {
+ return error_;
+}
+
+void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
+ prep_frame_view_.reset();
+ metafile_.reset();
+ pages_to_render_.clear();
+ error_ = PREVIEW_ERROR_NONE;
+}
+
+void PrintWebViewHelper::SetPrintPagesParams(
+ const PrintMsg_PrintPages_Params& settings) {
+ print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
+ Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
+ settings.params.document_cookie));
+}
+
+PrintWebViewHelper::ScriptingThrottler::ScriptingThrottler() : count_(0) {
+}
+
+bool PrintWebViewHelper::ScriptingThrottler::IsAllowed(blink::WebFrame* frame) {
+ const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
+ const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 32;
+ bool too_frequent = false;
+
+ // 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
+ // gets excessive, we switch to exponential wait time. So for a page that
+ // calls print() in a loop the user will need to cancel the print dialog
+ // after: [2, 2, 2, 4, 8, 16, 32, 32, ...] seconds.
+ // This gives the user time to navigate from the page.
+ if (count_ > 0) {
+ base::TimeDelta diff = base::Time::Now() - last_print_;
+ int min_wait_seconds = kMinSecondsToIgnoreJavascriptInitiatedPrint;
+ if (count_ > 3) {
+ min_wait_seconds =
+ std::min(kMinSecondsToIgnoreJavascriptInitiatedPrint << (count_ - 3),
+ kMaxSecondsToIgnoreJavascriptInitiatedPrint);
+ }
+ if (diff.InSeconds() < min_wait_seconds) {
+ too_frequent = true;
+ }
+ }
+
+ if (!too_frequent) {
+ ++count_;
+ last_print_ = base::Time::Now();
+ return true;
+ }
+
+ blink::WebString message(
+ blink::WebString::fromUTF8("Ignoring too frequent calls to print()."));
+ frame->addMessageToConsole(blink::WebConsoleMessage(
+ blink::WebConsoleMessage::LevelWarning, message));
+ return false;
+}
+
+void PrintWebViewHelper::ScriptingThrottler::Reset() {
+ // Reset counter on successful print.
+ count_ = 0;
+}
+
+} // namespace printing
diff --git a/components/printing/renderer/print_web_view_helper.h b/components/printing/renderer/print_web_view_helper.h
new file mode 100644
index 0000000..3e8e573
--- /dev/null
+++ b/components/printing/renderer/print_web_view_helper.h
@@ -0,0 +1,499 @@
+// 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.
+
+#ifndef COMPONENTS_PRINTING_RENDERER_PRINT_WEB_VIEW_HELPER_H_
+#define COMPONENTS_PRINTING_RENDERER_PRINT_WEB_VIEW_HELPER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "content/public/renderer/render_view_observer_tracker.h"
+#include "printing/pdf_metafile_skia.h"
+#include "third_party/WebKit/public/platform/WebCanvas.h"
+#include "third_party/WebKit/public/web/WebNode.h"
+#include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "ui/gfx/geometry/size.h"
+
+struct PrintMsg_Print_Params;
+struct PrintMsg_PrintPage_Params;
+struct PrintMsg_PrintPages_Params;
+struct PrintHostMsg_SetOptionsFromDocument_Params;
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace blink {
+class WebFrame;
+class WebView;
+}
+
+namespace printing {
+
+struct PageSizeMargins;
+class PrepareFrameAndViewForPrint;
+
+// Stores reference to frame using WebVew and unique name.
+// Workaround to modal dialog issue on Linux. crbug.com/236147.
+// If WebFrame someday supports WeakPtr, we should use it here.
+class FrameReference {
+ public:
+ explicit FrameReference(blink::WebLocalFrame* frame);
+ FrameReference();
+ ~FrameReference();
+
+ void Reset(blink::WebLocalFrame* frame);
+
+ blink::WebLocalFrame* GetFrame();
+ blink::WebView* view();
+
+ private:
+ blink::WebView* view_;
+ blink::WebLocalFrame* frame_;
+};
+
+// PrintWebViewHelper handles most of the printing grunt work for RenderView.
+// We plan on making print asynchronous and that will require copying the DOM
+// of the document and creating a new WebView with the contents.
+class PrintWebViewHelper
+ : public content::RenderViewObserver,
+ public content::RenderViewObserverTracker<PrintWebViewHelper> {
+ public:
+
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Cancels prerender if it's currently in progress and returns |true| if
+ // the cancellation was done with success.
+ virtual bool CancelPrerender(content::RenderView* render_view,
+ int routing_id) = 0;
+
+ // Returns the element to be printed. Returns a null WebElement if
+ // a pdf plugin element can't be extracted from the frame.
+ virtual blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) = 0;
+ };
+
+ PrintWebViewHelper(content::RenderView* render_view,
+ bool out_of_process_pdf_enabled,
+ bool print_preview_disabled,
+ scoped_ptr<Delegate> delegate);
+ ~PrintWebViewHelper() override;
+
+ // Disable print preview and switch to system dialog printing even if full
+ // printing is build-in. This method is used by CEF.
+ static void DisablePreview();
+
+ bool IsPrintingEnabled();
+
+ void PrintNode(const blink::WebNode& node);
+
+ private:
+ friend class PrintWebViewHelperTestBase;
+ FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperPreviewTest,
+ BlockScriptInitiatedPrinting);
+ FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, OnPrintPages);
+ FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest,
+ BlockScriptInitiatedPrinting);
+ FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest,
+ BlockScriptInitiatedPrintingFromPopup);
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, PrintLayoutTest);
+ FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, PrintWithIframe);
+#endif // defined(OS_WIN) || defined(OS_MACOSX)
+
+ enum PrintingResult {
+ OK,
+ FAIL_PRINT_INIT,
+ FAIL_PRINT,
+ FAIL_PREVIEW,
+ };
+
+ enum PrintPreviewErrorBuckets {
+ PREVIEW_ERROR_NONE, // Always first.
+ PREVIEW_ERROR_BAD_SETTING,
+ PREVIEW_ERROR_METAFILE_COPY_FAILED,
+ PREVIEW_ERROR_METAFILE_INIT_FAILED,
+ PREVIEW_ERROR_ZERO_PAGES,
+ PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED,
+ PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE,
+ PREVIEW_ERROR_INVALID_PRINTER_SETTINGS,
+ PREVIEW_ERROR_LAST_ENUM // Always last.
+ };
+
+ enum PrintPreviewRequestType {
+ PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME,
+ PRINT_PREVIEW_USER_INITIATED_SELECTION,
+ PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE,
+ PRINT_PREVIEW_SCRIPTED // triggered by window.print().
+ };
+
+ // RenderViewObserver implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void PrintPage(blink::WebLocalFrame* frame, bool user_initiated) override;
+ void DidStartLoading() override;
+ void DidStopLoading() override;
+
+ // Message handlers ---------------------------------------------------------
+#if defined(ENABLE_BASIC_PRINTING)
+ void OnPrintPages();
+ void OnPrintForSystemDialog();
+#endif // ENABLE_BASIC_PRINTING
+ void OnInitiatePrintPreview(bool selection_only);
+ void OnPrintPreview(const base::DictionaryValue& settings);
+ void OnPrintForPrintPreview(const base::DictionaryValue& job_settings);
+ void OnPrintingDone(bool success);
+
+ // Get |page_size| and |content_area| information from
+ // |page_layout_in_points|.
+ void GetPageSizeAndContentAreaFromPageLayout(
+ const PageSizeMargins& page_layout_in_points,
+ gfx::Size* page_size,
+ gfx::Rect* content_area);
+
+ // Update |ignore_css_margins_| based on settings.
+ void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings);
+
+ // Returns true if the current destination printer is PRINT_TO_PDF.
+ bool IsPrintToPdfRequested(const base::DictionaryValue& settings);
+
+ // Prepare frame for creating preview document.
+ void PrepareFrameForPreviewDocument();
+
+ // Continue creating preview document.
+ void OnFramePreparedForPreviewDocument();
+
+ // Initialize the print preview document.
+ bool CreatePreviewDocument();
+
+ // Renders a print preview page. |page_number| is 0-based.
+ // Returns true if print preview should continue, false on failure.
+ bool RenderPreviewPage(int page_number,
+ const PrintMsg_Print_Params& print_params);
+
+ // Finalize the print ready preview document.
+ bool FinalizePrintReadyDocument();
+
+ // Enable/Disable window.print calls. If |blocked| is true window.print
+ // calls will silently fail. Call with |blocked| set to false to reenable.
+ void SetScriptedPrintBlocked(bool blocked);
+
+ // Main printing code -------------------------------------------------------
+
+ // |is_scripted| should be true when the call is coming from window.print()
+ void Print(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ bool is_scripted);
+
+ // Notification when printing is done - signal tear-down/free resources.
+ void DidFinishPrinting(PrintingResult result);
+
+ // Print Settings -----------------------------------------------------------
+
+ // Initialize print page settings with default settings.
+ // Used only for native printing workflow.
+ bool InitPrintSettings(bool fit_to_paper_size);
+
+ // Calculate number of pages in source document.
+ bool CalculateNumberOfPages(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ int* number_of_pages);
+
+ // Set options for print preset from source PDF document.
+ void SetOptionsFromDocument(
+ PrintHostMsg_SetOptionsFromDocument_Params& params);
+
+ // Update the current print settings with new |passed_job_settings|.
+ // |passed_job_settings| dictionary contains print job details such as printer
+ // name, number of copies, page range, etc.
+ bool UpdatePrintSettings(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ const base::DictionaryValue& passed_job_settings);
+
+ // Get final print settings from the user.
+ // Return false if the user cancels or on error.
+ bool GetPrintSettingsFromUser(blink::WebFrame* frame,
+ const blink::WebNode& node,
+ int expected_pages_count,
+ bool is_scripted);
+
+ // Page Printing / Rendering ------------------------------------------------
+
+ void OnFramePreparedForPrintPages();
+ void PrintPages();
+ bool PrintPagesNative(blink::WebFrame* frame, int page_count);
+ void FinishFramePrinting();
+
+ // Prints the page listed in |params|.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
+ blink::WebFrame* frame,
+ PdfMetafileSkia* metafile);
+#elif defined(OS_WIN)
+ void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
+ blink::WebFrame* frame,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size_in_dpi,
+ gfx::Rect* content_area_in_dpi);
+#else
+ void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
+ blink::WebFrame* frame);
+#endif
+
+ // Render the frame for printing.
+ bool RenderPagesForPrint(blink::WebLocalFrame* frame,
+ const blink::WebNode& node);
+
+ // Platform specific helper function for rendering page(s) to |metafile|.
+#if defined(OS_MACOSX)
+ void RenderPage(const PrintMsg_Print_Params& params,
+ int page_number,
+ blink::WebFrame* frame,
+ bool is_preview,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size,
+ gfx::Rect* content_rect);
+#endif // defined(OS_MACOSX)
+
+ // Renders page contents from |frame| to |content_area| of |canvas|.
+ // |page_number| is zero-based.
+ // When method is called, canvas should be setup to draw to |canvas_area|
+ // with |scale_factor|.
+ static float RenderPageContent(blink::WebFrame* frame,
+ int page_number,
+ const gfx::Rect& canvas_area,
+ const gfx::Rect& content_area,
+ double scale_factor,
+ blink::WebCanvas* canvas);
+
+ // Helper methods -----------------------------------------------------------
+
+ bool CopyMetafileDataToSharedMem(PdfMetafileSkia* metafile,
+ base::SharedMemoryHandle* shared_mem_handle);
+
+ // Helper method to get page layout in points and fit to page if needed.
+ static void ComputePageLayoutInPointsForCss(
+ blink::WebFrame* frame,
+ int page_index,
+ const PrintMsg_Print_Params& default_params,
+ bool ignore_css_margins,
+ double* scale_factor,
+ PageSizeMargins* page_layout_in_points);
+
+#if defined(ENABLE_PRINT_PREVIEW)
+ // Given the |device| and |canvas| to draw on, prints the appropriate headers
+ // and footers using strings from |header_footer_info| on to the canvas.
+ static void PrintHeaderAndFooter(blink::WebCanvas* canvas,
+ int page_number,
+ int total_pages,
+ const blink::WebFrame& source_frame,
+ float webkit_scale_factor,
+ const PageSizeMargins& page_layout_in_points,
+ const PrintMsg_Print_Params& params);
+#endif // defined(ENABLE_PRINT_PREVIEW)
+
+ bool GetPrintFrame(blink::WebLocalFrame** frame);
+
+ // Script Initiated Printing ------------------------------------------------
+
+ // Return true if script initiated printing is currently
+ // allowed. |user_initiated| should be true when a user event triggered the
+ // script, most likely by pressing a print button on the page.
+ bool IsScriptInitiatedPrintAllowed(blink::WebFrame* frame,
+ bool user_initiated);
+
+ // Shows scripted print preview when options from plugin are available.
+ void ShowScriptedPrintPreview();
+
+ void RequestPrintPreview(PrintPreviewRequestType type);
+
+ // Checks whether print preview should continue or not.
+ // Returns true if canceling, false if continuing.
+ bool CheckForCancel();
+
+ // Notifies the browser a print preview page has been rendered.
+ // |page_number| is 0-based.
+ // For a valid |page_number| with modifiable content,
+ // |metafile| is the rendered page. Otherwise |metafile| is NULL.
+ // Returns true if print preview should continue, false on failure.
+ bool PreviewPageRendered(int page_number, PdfMetafileSkia* metafile);
+
+ void SetPrintPagesParams(const PrintMsg_PrintPages_Params& settings);
+
+ // WebView used only to print the selection.
+ scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
+ bool reset_prep_frame_view_;
+
+ scoped_ptr<PrintMsg_PrintPages_Params> print_pages_params_;
+ bool is_print_ready_metafile_sent_;
+ bool ignore_css_margins_;
+
+ // Used for scripted initiated printing blocking.
+ bool is_scripted_printing_blocked_;
+
+ // Let the browser process know of a printing failure. Only set to false when
+ // the failure came from the browser in the first place.
+ bool notify_browser_of_print_failure_;
+
+ // True, when printing from print preview.
+ bool print_for_preview_;
+
+ // Whether the content to print could be nested in an iframe.
+ const bool out_of_process_pdf_enabled_;
+
+ // Used to check the prerendering status.
+ const scoped_ptr<Delegate> delegate_;
+
+ // Keeps track of the state of print preview between messages.
+ // TODO(vitalybuka): Create PrintPreviewContext when needed and delete after
+ // use. Now it's interaction with various messages is confusing.
+ class PrintPreviewContext {
+ public:
+ PrintPreviewContext();
+ ~PrintPreviewContext();
+
+ // Initializes the print preview context. Need to be called to set
+ // the |web_frame| / |web_node| to generate the print preview for.
+ void InitWithFrame(blink::WebLocalFrame* web_frame);
+ void InitWithNode(const blink::WebNode& web_node);
+
+ // Does bookkeeping at the beginning of print preview.
+ void OnPrintPreview();
+
+ // Create the print preview document. |pages| is empty to print all pages.
+ // Takes ownership of |prepared_frame|.
+ bool CreatePreviewDocument(PrepareFrameAndViewForPrint* prepared_frame,
+ const std::vector<int>& pages);
+
+ // Called after a page gets rendered. |page_time| is how long the
+ // rendering took.
+ void RenderedPreviewPage(const base::TimeDelta& page_time);
+
+ // 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();
+
+ // Cleanup after print preview fails.
+ void Failed(bool report_error);
+
+ // Helper functions
+ int GetNextPageNumber();
+ bool IsRendering() const;
+ bool IsModifiable();
+ bool HasSelection();
+ bool IsLastPageOfPrintReadyMetafile() const;
+ bool IsFinalPageRendered() const;
+
+ // Setters
+ void set_generate_draft_pages(bool generate_draft_pages);
+ void set_error(enum PrintPreviewErrorBuckets error);
+
+ // Getters
+ // Original frame for which preview was requested.
+ blink::WebLocalFrame* source_frame();
+ // Original node for which preview was requested.
+ const blink::WebNode& source_node() const;
+
+ // Frame to be use to render preview. May be the same as source_frame(), or
+ // generated from it, e.g. copy of selected block.
+ blink::WebLocalFrame* prepared_frame();
+ // Node to be use to render preview. May be the same as source_node(), or
+ // generated from it, e.g. copy of selected block.
+ const blink::WebNode& prepared_node() const;
+
+ int total_page_count() const;
+ bool generate_draft_pages() const;
+ PdfMetafileSkia* metafile();
+ int last_error() const;
+
+ private:
+ enum State {
+ UNINITIALIZED, // Not ready to render.
+ INITIALIZED, // Ready to render.
+ RENDERING, // Rendering.
+ DONE // Finished rendering.
+ };
+
+ // Reset some of the internal rendering context.
+ void ClearContext();
+
+ // Specifies what to render for print preview.
+ FrameReference source_frame_;
+ blink::WebNode source_node_;
+
+ scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
+ scoped_ptr<PdfMetafileSkia> metafile_;
+
+ // Total page count in the renderer.
+ int total_page_count_;
+
+ // The current page to render.
+ int current_page_index_;
+
+ // List of page indices that need to be rendered.
+ std::vector<int> pages_to_render_;
+
+ // True, when draft pages needs to be generated.
+ bool generate_draft_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_;
+
+ enum PrintPreviewErrorBuckets error_;
+
+ State state_;
+ };
+
+ class ScriptingThrottler {
+ public:
+ ScriptingThrottler();
+
+ // Returns false if script initiated printing occurs too often.
+ bool IsAllowed(blink::WebFrame* frame);
+
+ // Reset the counter for script initiated printing.
+ // Scripted printing will be allowed to continue.
+ void Reset();
+
+ private:
+ base::Time last_print_;
+ int count_ = 0;
+ DISALLOW_COPY_AND_ASSIGN(ScriptingThrottler);
+ };
+
+ ScriptingThrottler scripting_throttler_;
+
+ bool print_node_in_progress_;
+ PrintPreviewContext print_preview_context_;
+ bool is_loading_;
+ bool is_scripted_preview_delayed_;
+
+ // Used to fix a race condition where the source is a PDF and print preview
+ // hangs because RequestPrintPreview is called before DidStopLoading() is
+ // called. This is a store for the RequestPrintPreview() call and its
+ // parameters so that it can be invoked after DidStopLoading.
+ base::Closure on_stop_loading_closure_;
+
+ base::WeakPtrFactory<PrintWebViewHelper> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelper);
+};
+
+} // namespace printing
+
+#endif // COMPONENTS_PRINTING_RENDERER_PRINT_WEB_VIEW_HELPER_H_
diff --git a/components/printing/renderer/print_web_view_helper_android.cc b/components/printing/renderer/print_web_view_helper_android.cc
new file mode 100644
index 0000000..c5e4e4a
--- /dev/null
+++ b/components/printing/renderer/print_web_view_helper_android.cc
@@ -0,0 +1,7 @@
+// Copyright 2013 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.
+
+// All the necessary logic already lives in print_web_view_helper_linux.cc.
+// We need a separate file for Android due to build/filename_rules.gypi rules.
+#include "components/printing/renderer/print_web_view_helper_linux.cc"
diff --git a/components/printing/renderer/print_web_view_helper_linux.cc b/components/printing/renderer/print_web_view_helper_linux.cc
new file mode 100644
index 0000000..1ebc2ca
--- /dev/null
+++ b/components/printing/renderer/print_web_view_helper_linux.cc
@@ -0,0 +1,191 @@
+// 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.
+
+#include "components/printing/renderer/print_web_view_helper.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/printing/common/print_messages.h"
+#include "content/public/renderer/render_thread.h"
+#include "printing/metafile_skia_wrapper.h"
+#include "printing/page_size_margins.h"
+#include "printing/pdf_metafile_skia.h"
+#include "skia/ext/platform_device.h"
+#include "skia/ext/vector_canvas.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#include "base/process/process_handle.h"
+#else
+#include "base/file_descriptor_posix.h"
+#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+
+namespace printing {
+
+using blink::WebFrame;
+
+bool PrintWebViewHelper::RenderPreviewPage(
+ int page_number,
+ const PrintMsg_Print_Params& print_params) {
+ PrintMsg_PrintPage_Params page_params;
+ page_params.params = print_params;
+ page_params.page_number = page_number;
+ scoped_ptr<PdfMetafileSkia> draft_metafile;
+ PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
+ if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
+ draft_metafile.reset(new PdfMetafileSkia);
+ initial_render_metafile = draft_metafile.get();
+ }
+
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+ PrintPageInternal(page_params,
+ print_preview_context_.prepared_frame(),
+ initial_render_metafile);
+ print_preview_context_.RenderedPreviewPage(
+ base::TimeTicks::Now() - begin_time);
+ 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 =
+ print_preview_context_.metafile()->GetMetafileForCurrentPage();
+ }
+ return PreviewPageRendered(page_number, draft_metafile.get());
+}
+
+bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+ int page_count) {
+ PdfMetafileSkia metafile;
+ if (!metafile.Init())
+ return false;
+
+ const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+ std::vector<int> printed_pages;
+
+ if (params.pages.empty()) {
+ for (int i = 0; i < page_count; ++i) {
+ printed_pages.push_back(i);
+ }
+ } else {
+ // TODO(vitalybuka): redesign to make more code cross platform.
+ for (size_t i = 0; i < params.pages.size(); ++i) {
+ if (params.pages[i] >= 0 && params.pages[i] < page_count) {
+ printed_pages.push_back(params.pages[i]);
+ }
+ }
+ }
+
+ if (printed_pages.empty())
+ return false;
+
+ PrintMsg_PrintPage_Params page_params;
+ page_params.params = params.params;
+ for (size_t i = 0; i < printed_pages.size(); ++i) {
+ page_params.page_number = printed_pages[i];
+ PrintPageInternal(page_params, frame, &metafile);
+ }
+
+ // blink::printEnd() for PDF should be called before metafile is closed.
+ FinishFramePrinting();
+
+ metafile.FinishDocument();
+
+ // Get the size of the resulting metafile.
+ uint32 buf_size = metafile.GetDataSize();
+ DCHECK_GT(buf_size, 0u);
+
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+ int sequence_number = -1;
+ base::FileDescriptor fd;
+
+ // Ask the browser to open a file for us.
+ Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(),
+ &fd,
+ &sequence_number));
+ if (!metafile.SaveToFD(fd))
+ return false;
+
+ // Tell the browser we've finished writing the file.
+ Send(new PrintHostMsg_TempFileForPrintingWritten(routing_id(),
+ sequence_number));
+ return true;
+#else
+ PrintHostMsg_DidPrintPage_Params printed_page_params;
+ printed_page_params.data_size = 0;
+ printed_page_params.document_cookie = params.params.document_cookie;
+
+ {
+ scoped_ptr<base::SharedMemory> shared_mem(
+ content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
+ buf_size).release());
+ if (!shared_mem.get()) {
+ NOTREACHED() << "AllocateSharedMemoryBuffer failed";
+ return false;
+ }
+
+ if (!shared_mem->Map(buf_size)) {
+ NOTREACHED() << "Map failed";
+ return false;
+ }
+ metafile.GetData(shared_mem->memory(), buf_size);
+ printed_page_params.data_size = buf_size;
+ shared_mem->GiveToProcess(base::GetCurrentProcessHandle(),
+ &(printed_page_params.metafile_data_handle));
+ }
+
+ for (size_t i = 0; i < printed_pages.size(); ++i) {
+ printed_page_params.page_number = printed_pages[i];
+ Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
+ // Send the rest of the pages with an invalid metafile handle.
+ printed_page_params.metafile_data_handle.fd = -1;
+ }
+ return true;
+#endif // defined(OS_CHROMEOS)
+}
+
+void PrintWebViewHelper::PrintPageInternal(
+ const PrintMsg_PrintPage_Params& params,
+ WebFrame* frame,
+ PdfMetafileSkia* metafile) {
+ PageSizeMargins page_layout_in_points;
+ double scale_factor = 1.0f;
+ ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
+ ignore_css_margins_, &scale_factor,
+ &page_layout_in_points);
+ gfx::Size page_size;
+ gfx::Rect content_area;
+ GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
+ &content_area);
+ gfx::Rect canvas_area =
+ params.params.display_header_footer ? gfx::Rect(page_size) : content_area;
+
+ skia::VectorCanvas* canvas =
+ metafile->GetVectorCanvasForNewPage(page_size, canvas_area, scale_factor);
+ if (!canvas)
+ return;
+
+ MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
+ skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
+
+#if defined(ENABLE_PRINT_PREVIEW)
+ if (params.params.display_header_footer) {
+ // |page_number| is 0-based, so 1 is added.
+ // TODO(vitalybuka) : why does it work only with 1.25?
+ PrintHeaderAndFooter(canvas, params.page_number + 1,
+ print_preview_context_.total_page_count(), *frame,
+ scale_factor / 1.25, page_layout_in_points,
+ params.params);
+ }
+#endif // defined(ENABLE_PRINT_PREVIEW)
+
+ RenderPageContent(frame, params.page_number, canvas_area, content_area,
+ scale_factor, canvas);
+
+ // Done printing. Close the canvas to retrieve the compiled metafile.
+ if (!metafile->FinishPage())
+ NOTREACHED() << "metafile failed";
+}
+
+} // namespace printing
diff --git a/components/printing/renderer/print_web_view_helper_mac.mm b/components/printing/renderer/print_web_view_helper_mac.mm
new file mode 100644
index 0000000..ba1c946
--- /dev/null
+++ b/components/printing/renderer/print_web_view_helper_mac.mm
@@ -0,0 +1,145 @@
+// 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.
+
+#include "components/printing/renderer/print_web_view_helper.h"
+
+#import <AppKit/AppKit.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/metrics/histogram.h"
+#include "components/printing/common/print_messages.h"
+#include "printing/metafile_skia_wrapper.h"
+#include "printing/page_size_margins.h"
+#include "skia/ext/platform_device.h"
+#include "skia/ext/vector_canvas.h"
+#include "third_party/WebKit/public/platform/WebCanvas.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace printing {
+
+using blink::WebFrame;
+
+void PrintWebViewHelper::PrintPageInternal(
+ const PrintMsg_PrintPage_Params& params,
+ WebFrame* frame) {
+ PdfMetafileSkia metafile;
+ if (!metafile.Init())
+ return;
+
+ int page_number = params.page_number;
+ gfx::Size page_size_in_dpi;
+ gfx::Rect content_area_in_dpi;
+ RenderPage(print_pages_params_->params, page_number, frame, false, &metafile,
+ &page_size_in_dpi, &content_area_in_dpi);
+ metafile.FinishDocument();
+
+ PrintHostMsg_DidPrintPage_Params page_params;
+ page_params.data_size = metafile.GetDataSize();
+ page_params.page_number = page_number;
+ page_params.document_cookie = params.params.document_cookie;
+ page_params.page_size = page_size_in_dpi;
+ page_params.content_area = content_area_in_dpi;
+
+ // Ask the browser to create the shared memory for us.
+ if (!CopyMetafileDataToSharedMem(&metafile,
+ &(page_params.metafile_data_handle))) {
+ page_params.data_size = 0;
+ }
+
+ Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
+}
+
+bool PrintWebViewHelper::RenderPreviewPage(
+ int page_number,
+ const PrintMsg_Print_Params& print_params) {
+ PrintMsg_Print_Params printParams = print_params;
+ scoped_ptr<PdfMetafileSkia> draft_metafile;
+ PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
+
+ bool render_to_draft = print_preview_context_.IsModifiable() &&
+ is_print_ready_metafile_sent_;
+
+ if (render_to_draft) {
+ draft_metafile.reset(new PdfMetafileSkia());
+ if (!draft_metafile->Init()) {
+ print_preview_context_.set_error(
+ PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED);
+ LOG(ERROR) << "Draft PdfMetafileSkia Init failed";
+ return false;
+ }
+ initial_render_metafile = draft_metafile.get();
+ }
+
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+ gfx::Size page_size;
+ RenderPage(printParams, page_number, print_preview_context_.prepared_frame(),
+ true, initial_render_metafile, &page_size, NULL);
+ print_preview_context_.RenderedPreviewPage(
+ base::TimeTicks::Now() - begin_time);
+
+ 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 =
+ print_preview_context_.metafile()->GetMetafileForCurrentPage();
+ }
+ }
+ return PreviewPageRendered(page_number, draft_metafile.get());
+}
+
+void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params,
+ int page_number,
+ WebFrame* frame,
+ bool is_preview,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size,
+ gfx::Rect* content_rect) {
+ double scale_factor = 1.0f;
+ double webkit_shrink_factor = frame->getPrintPageShrink(page_number);
+ PageSizeMargins page_layout_in_points;
+ gfx::Rect content_area;
+
+ ComputePageLayoutInPointsForCss(frame, page_number, params,
+ ignore_css_margins_, &scale_factor,
+ &page_layout_in_points);
+ GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, page_size,
+ &content_area);
+ if (content_rect)
+ *content_rect = content_area;
+
+ scale_factor *= webkit_shrink_factor;
+
+ gfx::Rect canvas_area =
+ params.display_header_footer ? gfx::Rect(*page_size) : content_area;
+
+ {
+ skia::VectorCanvas* canvas = metafile->GetVectorCanvasForNewPage(
+ *page_size, canvas_area, scale_factor);
+ if (!canvas)
+ return;
+
+ MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
+ skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
+ skia::SetIsPreviewMetafile(*canvas, is_preview);
+#if defined(ENABLE_PRINT_PREVIEW)
+ if (params.display_header_footer) {
+ PrintHeaderAndFooter(static_cast<blink::WebCanvas*>(canvas),
+ page_number + 1,
+ print_preview_context_.total_page_count(), *frame,
+ scale_factor, page_layout_in_points, params);
+ }
+#endif // defined(ENABLE_PRINT_PREVIEW)
+ RenderPageContent(frame, page_number, canvas_area, content_area,
+ scale_factor, static_cast<blink::WebCanvas*>(canvas));
+ }
+
+ // Done printing. Close the device context to retrieve the compiled metafile.
+ metafile->FinishPage();
+}
+
+} // namespace printing
diff --git a/components/printing/renderer/print_web_view_helper_pdf_win.cc b/components/printing/renderer/print_web_view_helper_pdf_win.cc
new file mode 100644
index 0000000..5809639
--- /dev/null
+++ b/components/printing/renderer/print_web_view_helper_pdf_win.cc
@@ -0,0 +1,233 @@
+// Copyright 2014 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 "components/printing/renderer/print_web_view_helper.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process/process_handle.h"
+#include "components/printing/common/print_messages.h"
+#include "content/public/renderer/render_thread.h"
+#include "printing/metafile_skia_wrapper.h"
+#include "printing/page_size_margins.h"
+#include "printing/pdf_metafile_skia.h"
+#include "printing/units.h"
+#include "skia/ext/platform_device.h"
+#include "skia/ext/vector_canvas.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+
+namespace printing {
+
+using blink::WebFrame;
+
+bool PrintWebViewHelper::RenderPreviewPage(
+ int page_number,
+ const PrintMsg_Print_Params& print_params) {
+ PrintMsg_PrintPage_Params page_params;
+ page_params.params = print_params;
+ page_params.page_number = page_number;
+ scoped_ptr<PdfMetafileSkia> draft_metafile;
+ PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
+ if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
+ draft_metafile.reset(new PdfMetafileSkia);
+ initial_render_metafile = draft_metafile.get();
+ }
+
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+ PrintPageInternal(page_params,
+ print_preview_context_.prepared_frame(),
+ initial_render_metafile,
+ NULL,
+ NULL);
+ print_preview_context_.RenderedPreviewPage(
+ base::TimeTicks::Now() - begin_time);
+ 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 =
+ print_preview_context_.metafile()->GetMetafileForCurrentPage();
+ }
+ return PreviewPageRendered(page_number, draft_metafile.get());
+}
+
+bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+ int page_count) {
+ PdfMetafileSkia metafile;
+ if (!metafile.Init())
+ return false;
+
+ const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+ std::vector<int> printed_pages;
+ if (params.pages.empty()) {
+ for (int i = 0; i < page_count; ++i) {
+ printed_pages.push_back(i);
+ }
+ } else {
+ // TODO(vitalybuka): redesign to make more code cross platform.
+ for (size_t i = 0; i < params.pages.size(); ++i) {
+ if (params.pages[i] >= 0 && params.pages[i] < page_count) {
+ printed_pages.push_back(params.pages[i]);
+ }
+ }
+ }
+ if (printed_pages.empty())
+ return false;
+
+ std::vector<gfx::Size> page_size_in_dpi(printed_pages.size());
+ std::vector<gfx::Rect> content_area_in_dpi(printed_pages.size());
+
+ PrintMsg_PrintPage_Params page_params;
+ page_params.params = params.params;
+ for (size_t i = 0; i < printed_pages.size(); ++i) {
+ page_params.page_number = printed_pages[i];
+ PrintPageInternal(page_params,
+ frame,
+ &metafile,
+ &page_size_in_dpi[i],
+ &content_area_in_dpi[i]);
+ }
+
+ // blink::printEnd() for PDF should be called before metafile is closed.
+ FinishFramePrinting();
+
+ metafile.FinishDocument();
+
+ // Get the size of the resulting metafile.
+ uint32 buf_size = metafile.GetDataSize();
+ DCHECK_GT(buf_size, 0u);
+
+ PrintHostMsg_DidPrintPage_Params printed_page_params;
+ printed_page_params.data_size = 0;
+ printed_page_params.document_cookie = params.params.document_cookie;
+ printed_page_params.page_size = params.params.page_size;
+ printed_page_params.content_area = params.params.printable_area;
+
+ {
+ base::SharedMemory shared_buf;
+ // Allocate a shared memory buffer to hold the generated metafile data.
+ if (!shared_buf.CreateAndMapAnonymous(buf_size)) {
+ NOTREACHED() << "Buffer allocation failed";
+ return false;
+ }
+
+ // Copy the bits into shared memory.
+ if (!metafile.GetData(shared_buf.memory(), buf_size)) {
+ NOTREACHED() << "GetData() failed";
+ shared_buf.Unmap();
+ return false;
+ }
+ shared_buf.GiveToProcess(base::GetCurrentProcessHandle(),
+ &printed_page_params.metafile_data_handle);
+ shared_buf.Unmap();
+
+ printed_page_params.data_size = buf_size;
+ Send(new PrintHostMsg_DuplicateSection(
+ routing_id(),
+ printed_page_params.metafile_data_handle,
+ &printed_page_params.metafile_data_handle));
+ }
+
+ for (size_t i = 0; i < printed_pages.size(); ++i) {
+ printed_page_params.page_number = printed_pages[i];
+ printed_page_params.page_size = page_size_in_dpi[i];
+ printed_page_params.content_area = content_area_in_dpi[i];
+ Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
+ printed_page_params.metafile_data_handle = INVALID_HANDLE_VALUE;
+ }
+ return true;
+}
+
+void PrintWebViewHelper::PrintPageInternal(
+ const PrintMsg_PrintPage_Params& params,
+ WebFrame* frame,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size_in_dpi,
+ gfx::Rect* content_area_in_dpi) {
+ PageSizeMargins page_layout_in_points;
+ double css_scale_factor = 1.0f;
+ ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
+ ignore_css_margins_, &css_scale_factor,
+ &page_layout_in_points);
+ gfx::Size page_size;
+ gfx::Rect content_area;
+ GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
+ &content_area);
+ int dpi = static_cast<int>(params.params.dpi);
+ // Calculate the actual page size and content area in dpi.
+ if (page_size_in_dpi) {
+ *page_size_in_dpi =
+ gfx::Size(static_cast<int>(ConvertUnitDouble(
+ page_size.width(), kPointsPerInch, dpi)),
+ static_cast<int>(ConvertUnitDouble(
+ page_size.height(), kPointsPerInch, dpi)));
+ }
+
+ if (content_area_in_dpi) {
+ // Output PDF matches paper size and should be printer edge to edge.
+ *content_area_in_dpi =
+ gfx::Rect(0, 0, page_size_in_dpi->width(), page_size_in_dpi->height());
+ }
+
+ gfx::Rect canvas_area =
+ params.params.display_header_footer ? gfx::Rect(page_size) : content_area;
+
+ float webkit_page_shrink_factor =
+ frame->getPrintPageShrink(params.page_number);
+ float scale_factor = css_scale_factor * webkit_page_shrink_factor;
+
+ skia::VectorCanvas* canvas =
+ metafile->GetVectorCanvasForNewPage(page_size, canvas_area, scale_factor);
+ if (!canvas)
+ return;
+
+ MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
+ skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
+
+#if defined(ENABLE_PRINT_PREVIEW)
+ if (params.params.display_header_footer) {
+ // |page_number| is 0-based, so 1 is added.
+ PrintHeaderAndFooter(canvas, params.page_number + 1,
+ print_preview_context_.total_page_count(), *frame,
+ scale_factor, page_layout_in_points, params.params);
+ }
+#endif // defined(ENABLE_PRINT_PREVIEW)
+
+ float webkit_scale_factor =
+ RenderPageContent(frame, params.page_number, canvas_area, content_area,
+ scale_factor, canvas);
+ DCHECK_GT(webkit_scale_factor, 0.0f);
+ // Done printing. Close the canvas to retrieve the compiled metafile.
+ if (!metafile->FinishPage())
+ NOTREACHED() << "metafile failed";
+}
+
+bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
+ PdfMetafileSkia* metafile,
+ base::SharedMemoryHandle* shared_mem_handle) {
+ uint32 buf_size = metafile->GetDataSize();
+ base::SharedMemory shared_buf;
+ // Allocate a shared memory buffer to hold the generated metafile data.
+ if (!shared_buf.CreateAndMapAnonymous(buf_size)) {
+ NOTREACHED() << "Buffer allocation failed";
+ return false;
+ }
+
+ // Copy the bits into shared memory.
+ if (!metafile->GetData(shared_buf.memory(), buf_size)) {
+ NOTREACHED() << "GetData() failed";
+ shared_buf.Unmap();
+ return false;
+ }
+ shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle);
+ shared_buf.Unmap();
+
+ Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle,
+ shared_mem_handle));
+ return true;
+}
+
+} // namespace printing
diff --git a/components/printing/resources/print_preview_page.html b/components/printing/resources/print_preview_page.html
new file mode 100644
index 0000000..4ea37f5
--- /dev/null
+++ b/components/printing/resources/print_preview_page.html
@@ -0,0 +1,117 @@
+<!doctype html>
+<head>
+<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+<style>
+ body {
+ margin: 0px;
+ width: 0px;
+ }
+ .row {
+ display: table-row;
+ vertical-align: inherit;
+ }
+ #header, #footer {
+ display: table;
+ table-layout:fixed;
+ width: inherit;
+ }
+ #header {
+ vertical-align: top;
+ }
+ #footer {
+ vertical-align: bottom;
+ }
+ .text {
+ display: table-cell;
+ font-size: 8px;
+ vertical-align: inherit;
+ white-space: nowrap;
+ }
+ #page_number {
+ text-align: right;
+ }
+ #title {
+ text-align: center;
+ }
+ #date, #url {
+ padding-left: 0.7cm;
+ padding-right: 0.1cm;
+ }
+ #title, #page_number {
+ padding-left: 0.1cm;
+ padding-right: 0.7cm;
+ }
+ #title, #url {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ #title, #date {
+ padding-bottom: 0cm;
+ padding-top: 0.4cm;
+ }
+ #page_number, #url {
+ padding-bottom: 0.4cm;
+ padding-top: 0cm;
+ }
+</style>
+<script>
+
+function pixels(value) {
+ return value + 'px';
+}
+
+function setup(options) {
+ var body = document.querySelector('body');
+ var header = document.querySelector('#header');
+ var content = document.querySelector('#content');
+ var footer = document.querySelector('#footer');
+
+ body.style.width = pixels(options['width']);
+ body.style.height = pixels(options['height']);
+ header.style.height = pixels(options['topMargin']);
+ content.style.height = pixels(options['height'] - options['topMargin'] -
+ options['bottomMargin']);
+ footer.style.height = pixels(options['bottomMargin']);
+
+ document.querySelector('#date span').innerText =
+ new Date(options['date']).toLocaleDateString();
+ document.querySelector('#title span').innerText = options['title'];
+
+ document.querySelector('#url span').innerText = options['url'];
+ document.querySelector('#page_number span').innerText = options['pageNumber'];
+
+ // Reduce date and page number space to give more space to title and url.
+ document.querySelector('#date').style.width =
+ pixels(document.querySelector('#date span').offsetWidth);
+ document.querySelector('#page_number').style.width =
+ pixels(document.querySelector('#page_number span').offsetWidth);
+
+ // Hide text if it doesn't fit into expected margins.
+ if (header.offsetHeight > options['topMargin'] + 1) {
+ header.style.display = 'none';
+ content.style.height = pixels(options['height'] - options['bottomMargin']);
+ }
+ if (footer.offsetHeight > options['bottomMargin'] + 1) {
+ footer.style.display = 'none';
+ }
+}
+
+</script>
+</head>
+<body>
+ <div id="header">
+ <div class="row">
+ <div id="date" class="text"><span/></div>
+ <div id="title" class="text"><span/></div>
+ </div>
+ </div>
+ <div id="content">
+ </div>
+ <div id="footer">
+ <div class="row">
+ <div id="url" class="text"><span/></div>
+ <div id="page_number" class="text"><span/></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/components/resources/components_resources.grd b/components/resources/components_resources.grd
index c9b2312..2d0dfbe 100644
--- a/components/resources/components_resources.grd
+++ b/components/resources/components_resources.grd
@@ -9,6 +9,7 @@
<release seq="1">
<includes>
<part file="dom_distiller_resources.grdp" />
+ <part file="printing_resources.grdp" />
<part file="translate_resources.grdp" />
</includes>
</release>
diff --git a/components/resources/printing_resources.grdp b/components/resources/printing_resources.grdp
new file mode 100644
index 0000000..7213746
--- /dev/null
+++ b/components/resources/printing_resources.grdp
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <if expr="enable_print_preview">
+ <include name="IDR_PRINT_PREVIEW_PAGE" file="../printing/resources/print_preview_page.html" flattenhtml="true" allowexternalscript="false" type="BINDATA" />
+ </if>
+</grit-part>