1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/printing/print_web_view_helper.h"
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram.h"
15 #include "base/process/process_handle.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/print_messages.h"
21 #include "chrome/common/render_messages.h"
22 #include "chrome/renderer/prerender/prerender_helper.h"
23 #include "content/public/renderer/render_frame.h"
24 #include "content/public/renderer/render_thread.h"
25 #include "content/public/renderer/render_view.h"
26 #include "content/public/renderer/web_preferences.h"
27 #include "grit/browser_resources.h"
28 #include "net/base/escape.h"
29 #include "printing/metafile.h"
30 #include "printing/metafile_impl.h"
31 #include "printing/units.h"
32 #include "skia/ext/vector_platform_device_skia.h"
33 #include "third_party/WebKit/public/platform/WebSize.h"
34 #include "third_party/WebKit/public/platform/WebURLRequest.h"
35 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
36 #include "third_party/WebKit/public/web/WebDocument.h"
37 #include "third_party/WebKit/public/web/WebElement.h"
38 #include "third_party/WebKit/public/web/WebFrameClient.h"
39 #include "third_party/WebKit/public/web/WebLocalFrame.h"
40 #include "third_party/WebKit/public/web/WebPlugin.h"
41 #include "third_party/WebKit/public/web/WebPluginDocument.h"
42 #include "third_party/WebKit/public/web/WebPrintParams.h"
43 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
44 #include "third_party/WebKit/public/web/WebScriptSource.h"
45 #include "third_party/WebKit/public/web/WebSettings.h"
46 #include "third_party/WebKit/public/web/WebView.h"
47 #include "third_party/WebKit/public/web/WebViewClient.h"
48 #include "ui/base/resource/resource_bundle.h"
49 #include "webkit/common/webpreferences.h"
55 enum PrintPreviewHelperEvents
{
56 PREVIEW_EVENT_REQUESTED
,
57 PREVIEW_EVENT_CACHE_HIT
, // Unused
58 PREVIEW_EVENT_CREATE_DOCUMENT
,
59 PREVIEW_EVENT_NEW_SETTINGS
, // Unused
63 const double kMinDpi
= 1.0;
65 const char kPageLoadScriptFormat
[] =
66 "document.open(); document.write(%s); document.close();";
68 const char kPageSetupScriptFormat
[] = "setup(%s);";
70 void ExecuteScript(blink::WebFrame
* frame
,
71 const char* script_format
,
72 const base::Value
& parameters
) {
74 base::JSONWriter::Write(¶meters
, &json
);
75 std::string script
= base::StringPrintf(script_format
, json
.c_str());
76 frame
->executeScript(blink::WebString(base::UTF8ToUTF16(script
)));
79 int GetDPI(const PrintMsg_Print_Params
* print_params
) {
80 #if defined(OS_MACOSX)
81 // On the Mac, the printable area is in points, don't do any scaling based
83 return kPointsPerInch
;
85 return static_cast<int>(print_params
->dpi
);
86 #endif // defined(OS_MACOSX)
89 bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params
& params
) {
90 return !params
.content_size
.IsEmpty() && !params
.page_size
.IsEmpty() &&
91 !params
.printable_area
.IsEmpty() && params
.document_cookie
&&
92 params
.desired_dpi
&& params
.max_shrink
&& params
.min_shrink
&&
93 params
.dpi
&& (params
.margin_top
>= 0) && (params
.margin_left
>= 0);
96 PrintMsg_Print_Params
GetCssPrintParams(
97 blink::WebFrame
* frame
,
99 const PrintMsg_Print_Params
& page_params
) {
100 PrintMsg_Print_Params page_css_params
= page_params
;
101 int dpi
= GetDPI(&page_params
);
103 blink::WebSize
page_size_in_pixels(
104 ConvertUnit(page_params
.page_size
.width(), dpi
, kPixelsPerInch
),
105 ConvertUnit(page_params
.page_size
.height(), dpi
, kPixelsPerInch
));
106 int margin_top_in_pixels
=
107 ConvertUnit(page_params
.margin_top
, dpi
, kPixelsPerInch
);
108 int margin_right_in_pixels
= ConvertUnit(
109 page_params
.page_size
.width() -
110 page_params
.content_size
.width() - page_params
.margin_left
,
111 dpi
, kPixelsPerInch
);
112 int margin_bottom_in_pixels
= ConvertUnit(
113 page_params
.page_size
.height() -
114 page_params
.content_size
.height() - page_params
.margin_top
,
115 dpi
, kPixelsPerInch
);
116 int margin_left_in_pixels
= ConvertUnit(
117 page_params
.margin_left
,
118 dpi
, kPixelsPerInch
);
120 blink::WebSize original_page_size_in_pixels
= page_size_in_pixels
;
123 frame
->pageSizeAndMarginsInPixels(page_index
,
125 margin_top_in_pixels
,
126 margin_right_in_pixels
,
127 margin_bottom_in_pixels
,
128 margin_left_in_pixels
);
131 int new_content_width
= page_size_in_pixels
.width
-
132 margin_left_in_pixels
- margin_right_in_pixels
;
133 int new_content_height
= page_size_in_pixels
.height
-
134 margin_top_in_pixels
- margin_bottom_in_pixels
;
136 // Invalid page size and/or margins. We just use the default setting.
137 if (new_content_width
< 1 || new_content_height
< 1) {
138 CHECK(frame
!= NULL
);
139 page_css_params
= GetCssPrintParams(NULL
, page_index
, page_params
);
140 return page_css_params
;
143 page_css_params
.content_size
= gfx::Size(
144 ConvertUnit(new_content_width
, kPixelsPerInch
, dpi
),
145 ConvertUnit(new_content_height
, kPixelsPerInch
, dpi
));
147 if (original_page_size_in_pixels
!= page_size_in_pixels
) {
148 page_css_params
.page_size
= gfx::Size(
149 ConvertUnit(page_size_in_pixels
.width
, kPixelsPerInch
, dpi
),
150 ConvertUnit(page_size_in_pixels
.height
, kPixelsPerInch
, dpi
));
152 // Printing frame doesn't have any page size css. Pixels to dpi conversion
153 // causes rounding off errors. Therefore use the default page size values
155 page_css_params
.page_size
= page_params
.page_size
;
158 page_css_params
.margin_top
=
159 ConvertUnit(margin_top_in_pixels
, kPixelsPerInch
, dpi
);
160 page_css_params
.margin_left
=
161 ConvertUnit(margin_left_in_pixels
, kPixelsPerInch
, dpi
);
162 return page_css_params
;
165 double FitPrintParamsToPage(const PrintMsg_Print_Params
& page_params
,
166 PrintMsg_Print_Params
* params_to_fit
) {
167 double content_width
=
168 static_cast<double>(params_to_fit
->content_size
.width());
169 double content_height
=
170 static_cast<double>(params_to_fit
->content_size
.height());
171 int default_page_size_height
= page_params
.page_size
.height();
172 int default_page_size_width
= page_params
.page_size
.width();
173 int css_page_size_height
= params_to_fit
->page_size
.height();
174 int css_page_size_width
= params_to_fit
->page_size
.width();
176 double scale_factor
= 1.0f
;
177 if (page_params
.page_size
== params_to_fit
->page_size
)
180 if (default_page_size_width
< css_page_size_width
||
181 default_page_size_height
< css_page_size_height
) {
183 static_cast<double>(default_page_size_width
) / css_page_size_width
;
184 double ratio_height
=
185 static_cast<double>(default_page_size_height
) / css_page_size_height
;
186 scale_factor
= ratio_width
< ratio_height
? ratio_width
: ratio_height
;
187 content_width
*= scale_factor
;
188 content_height
*= scale_factor
;
190 params_to_fit
->margin_top
= static_cast<int>(
191 (default_page_size_height
- css_page_size_height
* scale_factor
) / 2 +
192 (params_to_fit
->margin_top
* scale_factor
));
193 params_to_fit
->margin_left
= static_cast<int>(
194 (default_page_size_width
- css_page_size_width
* scale_factor
) / 2 +
195 (params_to_fit
->margin_left
* scale_factor
));
196 params_to_fit
->content_size
= gfx::Size(
197 static_cast<int>(content_width
), static_cast<int>(content_height
));
198 params_to_fit
->page_size
= page_params
.page_size
;
202 void CalculatePageLayoutFromPrintParams(
203 const PrintMsg_Print_Params
& params
,
204 PageSizeMargins
* page_layout_in_points
) {
205 int dpi
= GetDPI(¶ms
);
206 int content_width
= params
.content_size
.width();
207 int content_height
= params
.content_size
.height();
209 int margin_bottom
= params
.page_size
.height() -
210 content_height
- params
.margin_top
;
211 int margin_right
= params
.page_size
.width() -
212 content_width
- params
.margin_left
;
214 page_layout_in_points
->content_width
=
215 ConvertUnit(content_width
, dpi
, kPointsPerInch
);
216 page_layout_in_points
->content_height
=
217 ConvertUnit(content_height
, dpi
, kPointsPerInch
);
218 page_layout_in_points
->margin_top
=
219 ConvertUnit(params
.margin_top
, dpi
, kPointsPerInch
);
220 page_layout_in_points
->margin_right
=
221 ConvertUnit(margin_right
, dpi
, kPointsPerInch
);
222 page_layout_in_points
->margin_bottom
=
223 ConvertUnit(margin_bottom
, dpi
, kPointsPerInch
);
224 page_layout_in_points
->margin_left
=
225 ConvertUnit(params
.margin_left
, dpi
, kPointsPerInch
);
228 void EnsureOrientationMatches(const PrintMsg_Print_Params
& css_params
,
229 PrintMsg_Print_Params
* page_params
) {
230 if ((page_params
->page_size
.width() > page_params
->page_size
.height()) ==
231 (css_params
.page_size
.width() > css_params
.page_size
.height())) {
235 // Swap the |width| and |height| values.
236 page_params
->page_size
.SetSize(page_params
->page_size
.height(),
237 page_params
->page_size
.width());
238 page_params
->content_size
.SetSize(page_params
->content_size
.height(),
239 page_params
->content_size
.width());
240 page_params
->printable_area
.set_size(
241 gfx::Size(page_params
->printable_area
.height(),
242 page_params
->printable_area
.width()));
245 void ComputeWebKitPrintParamsInDesiredDpi(
246 const PrintMsg_Print_Params
& print_params
,
247 blink::WebPrintParams
* webkit_print_params
) {
248 int dpi
= GetDPI(&print_params
);
249 webkit_print_params
->printerDPI
= dpi
;
250 webkit_print_params
->printScalingOption
= print_params
.print_scaling_option
;
252 webkit_print_params
->printContentArea
.width
=
253 ConvertUnit(print_params
.content_size
.width(), dpi
,
254 print_params
.desired_dpi
);
255 webkit_print_params
->printContentArea
.height
=
256 ConvertUnit(print_params
.content_size
.height(), dpi
,
257 print_params
.desired_dpi
);
259 webkit_print_params
->printableArea
.x
=
260 ConvertUnit(print_params
.printable_area
.x(), dpi
,
261 print_params
.desired_dpi
);
262 webkit_print_params
->printableArea
.y
=
263 ConvertUnit(print_params
.printable_area
.y(), dpi
,
264 print_params
.desired_dpi
);
265 webkit_print_params
->printableArea
.width
=
266 ConvertUnit(print_params
.printable_area
.width(), dpi
,
267 print_params
.desired_dpi
);
268 webkit_print_params
->printableArea
.height
=
269 ConvertUnit(print_params
.printable_area
.height(),
270 dpi
, print_params
.desired_dpi
);
272 webkit_print_params
->paperSize
.width
=
273 ConvertUnit(print_params
.page_size
.width(), dpi
,
274 print_params
.desired_dpi
);
275 webkit_print_params
->paperSize
.height
=
276 ConvertUnit(print_params
.page_size
.height(), dpi
,
277 print_params
.desired_dpi
);
280 blink::WebPlugin
* GetPlugin(const blink::WebFrame
* frame
) {
281 return frame
->document().isPluginDocument() ?
282 frame
->document().to
<blink::WebPluginDocument
>().plugin() : NULL
;
285 bool PrintingNodeOrPdfFrame(const blink::WebFrame
* frame
,
286 const blink::WebNode
& node
) {
289 blink::WebPlugin
* plugin
= GetPlugin(frame
);
290 return plugin
&& plugin
->supportsPaginatedPrint();
293 bool PrintingFrameHasPageSizeStyle(blink::WebFrame
* frame
,
294 int total_page_count
) {
297 bool frame_has_custom_page_size_style
= false;
298 for (int i
= 0; i
< total_page_count
; ++i
) {
299 if (frame
->hasCustomPageSizeStyle(i
)) {
300 frame_has_custom_page_size_style
= true;
304 return frame_has_custom_page_size_style
;
307 MarginType
GetMarginsForPdf(blink::WebFrame
* frame
,
308 const blink::WebNode
& node
) {
309 if (frame
->isPrintScalingDisabledForPlugin(node
))
312 return PRINTABLE_AREA_MARGINS
;
315 bool FitToPageEnabled(const base::DictionaryValue
& job_settings
) {
316 bool fit_to_paper_size
= false;
317 if (!job_settings
.GetBoolean(kSettingFitToPageEnabled
, &fit_to_paper_size
)) {
320 return fit_to_paper_size
;
323 // Returns the print scaling option to retain/scale/crop the source page size
324 // to fit the printable area of the paper.
326 // We retain the source page size when the current destination printer is
329 // We crop the source page size to fit the printable area or we print only the
330 // left top page contents when
331 // (1) Source is PDF and the user has requested not to fit to printable area
332 // via |job_settings|.
333 // (2) Source is PDF. This is the first preview request and print scaling
334 // option is disabled for initiator renderer plugin.
336 // In all other cases, we scale the source page to fit the printable area.
337 blink::WebPrintScalingOption
GetPrintScalingOption(
338 blink::WebFrame
* frame
,
339 const blink::WebNode
& node
,
341 const base::DictionaryValue
& job_settings
,
342 const PrintMsg_Print_Params
& params
) {
343 if (params
.print_to_pdf
)
344 return blink::WebPrintScalingOptionSourceSize
;
346 if (!source_is_html
) {
347 if (!FitToPageEnabled(job_settings
))
348 return blink::WebPrintScalingOptionNone
;
350 bool no_plugin_scaling
= frame
->isPrintScalingDisabledForPlugin(node
);
352 if (params
.is_first_request
&& no_plugin_scaling
)
353 return blink::WebPrintScalingOptionNone
;
355 return blink::WebPrintScalingOptionFitToPrintableArea
;
358 PrintMsg_Print_Params
CalculatePrintParamsForCss(
359 blink::WebFrame
* frame
,
361 const PrintMsg_Print_Params
& page_params
,
362 bool ignore_css_margins
,
364 double* scale_factor
) {
365 PrintMsg_Print_Params css_params
= GetCssPrintParams(frame
, page_index
,
368 PrintMsg_Print_Params params
= page_params
;
369 EnsureOrientationMatches(css_params
, ¶ms
);
371 if (ignore_css_margins
&& fit_to_page
)
374 PrintMsg_Print_Params result_params
= css_params
;
375 if (ignore_css_margins
) {
376 result_params
.margin_top
= params
.margin_top
;
377 result_params
.margin_left
= params
.margin_left
;
379 DCHECK(!fit_to_page
);
380 // Since we are ignoring the margins, the css page size is no longer
382 int default_margin_right
= params
.page_size
.width() -
383 params
.content_size
.width() - params
.margin_left
;
384 int default_margin_bottom
= params
.page_size
.height() -
385 params
.content_size
.height() - params
.margin_top
;
386 result_params
.content_size
= gfx::Size(
387 result_params
.page_size
.width() - result_params
.margin_left
-
388 default_margin_right
,
389 result_params
.page_size
.height() - result_params
.margin_top
-
390 default_margin_bottom
);
394 double factor
= FitPrintParamsToPage(params
, &result_params
);
396 *scale_factor
= factor
;
398 return result_params
;
401 bool IsPrintPreviewEnabled() {
402 return CommandLine::ForCurrentProcess()->HasSwitch(
403 switches::kRendererPrintPreview
);
406 bool IsPrintThrottlingDisabled() {
407 return CommandLine::ForCurrentProcess()->HasSwitch(
408 switches::kDisableScriptedPrintThrottling
);
413 FrameReference::FrameReference(blink::WebLocalFrame
* frame
) {
417 FrameReference::FrameReference() {
421 FrameReference::~FrameReference() {
424 void FrameReference::Reset(blink::WebLocalFrame
* frame
) {
426 view_
= frame
->view();
434 blink::WebLocalFrame
* FrameReference::GetFrame() {
435 if (view_
== NULL
|| frame_
== NULL
)
437 for (blink::WebFrame
* frame
= view_
->mainFrame(); frame
!= NULL
;
438 frame
= frame
->traverseNext(false)) {
445 blink::WebView
* FrameReference::view() {
449 // static - Not anonymous so that platform implementations can use it.
450 void PrintWebViewHelper::PrintHeaderAndFooter(
451 blink::WebCanvas
* canvas
,
454 float webkit_scale_factor
,
455 const PageSizeMargins
& page_layout
,
456 const base::DictionaryValue
& header_footer_info
,
457 const PrintMsg_Print_Params
& params
) {
458 skia::VectorPlatformDeviceSkia
* device
=
459 static_cast<skia::VectorPlatformDeviceSkia
*>(canvas
->getTopDevice());
460 device
->setDrawingArea(SkPDFDevice::kMargin_DrawingArea
);
462 SkAutoCanvasRestore
auto_restore(canvas
, true);
463 canvas
->scale(1 / webkit_scale_factor
, 1 / webkit_scale_factor
);
465 blink::WebSize
page_size(page_layout
.margin_left
+ page_layout
.margin_right
+
466 page_layout
.content_width
,
467 page_layout
.margin_top
+ page_layout
.margin_bottom
+
468 page_layout
.content_height
);
470 blink::WebView
* web_view
= blink::WebView::create(NULL
);
471 web_view
->settings()->setJavaScriptEnabled(true);
473 blink::WebLocalFrame
* frame
= blink::WebLocalFrame::create(NULL
);
474 web_view
->setMainFrame(frame
);
476 base::StringValue
html(
477 ResourceBundle::GetSharedInstance().GetLocalizedString(
478 IDR_PRINT_PREVIEW_PAGE
));
479 // Load page with script to avoid async operations.
480 ExecuteScript(frame
, kPageLoadScriptFormat
, html
);
482 scoped_ptr
<base::DictionaryValue
> options(header_footer_info
.DeepCopy());
483 options
->SetDouble("width", page_size
.width
);
484 options
->SetDouble("height", page_size
.height
);
485 options
->SetDouble("topMargin", page_layout
.margin_top
);
486 options
->SetDouble("bottomMargin", page_layout
.margin_bottom
);
487 options
->SetString("pageNumber",
488 base::StringPrintf("%d/%d", page_number
, total_pages
));
490 ExecuteScript(frame
, kPageSetupScriptFormat
, *options
);
492 blink::WebPrintParams
webkit_params(page_size
);
493 webkit_params
.printerDPI
= GetDPI(¶ms
);
495 frame
->printBegin(webkit_params
);
496 frame
->printPage(0, canvas
);
502 device
->setDrawingArea(SkPDFDevice::kContent_DrawingArea
);
505 // static - Not anonymous so that platform implementations can use it.
506 float PrintWebViewHelper::RenderPageContent(blink::WebFrame
* frame
,
508 const gfx::Rect
& canvas_area
,
509 const gfx::Rect
& content_area
,
511 blink::WebCanvas
* canvas
) {
512 SkAutoCanvasRestore
auto_restore(canvas
, true);
513 if (content_area
!= canvas_area
) {
514 canvas
->translate((content_area
.x() - canvas_area
.x()) / scale_factor
,
515 (content_area
.y() - canvas_area
.y()) / scale_factor
);
517 SkRect::MakeXYWH(content_area
.origin().x() / scale_factor
,
518 content_area
.origin().y() / scale_factor
,
519 content_area
.size().width() / scale_factor
,
520 content_area
.size().height() / scale_factor
));
521 SkIRect clip_int_rect
;
522 clip_rect
.roundOut(&clip_int_rect
);
523 SkRegion
clip_region(clip_int_rect
);
524 canvas
->setClipRegion(clip_region
);
526 return frame
->printPage(page_number
, canvas
);
529 // Class that calls the Begin and End print functions on the frame and changes
530 // the size of the view temporarily to support full page printing..
531 class PrepareFrameAndViewForPrint
: public blink::WebViewClient
,
532 public blink::WebFrameClient
{
534 PrepareFrameAndViewForPrint(const PrintMsg_Print_Params
& params
,
535 blink::WebLocalFrame
* frame
,
536 const blink::WebNode
& node
,
537 bool ignore_css_margins
);
538 virtual ~PrepareFrameAndViewForPrint();
540 // Optional. Replaces |frame_| with selection if needed. Will call |on_ready|
542 void CopySelectionIfNeeded(const WebPreferences
& preferences
,
543 const base::Closure
& on_ready
);
545 // Prepares frame for printing.
546 void StartPrinting();
548 blink::WebLocalFrame
* frame() {
549 return frame_
.GetFrame();
552 const blink::WebNode
& node() const {
553 return node_to_print_
;
556 int GetExpectedPageCount() const {
557 return expected_pages_count_
;
560 gfx::Size
GetPrintCanvasSize() const;
562 void FinishPrinting();
564 bool IsLoadingSelection() {
565 // It's not selection if not |owns_web_view_|.
566 return owns_web_view_
&& frame() && frame()->isLoading();
569 // TODO(ojan): Remove this override and have this class use a non-null
571 // blink::WebViewClient override:
572 virtual bool allowsBrokenNullLayerTreeView() const;
575 // blink::WebViewClient override:
576 virtual void didStopLoading();
578 // blink::WebFrameClient override:
579 virtual blink::WebFrame
* createChildFrame(blink::WebLocalFrame
* parent
,
580 const blink::WebString
& name
);
581 virtual void frameDetached(blink::WebFrame
* frame
);
585 void ResizeForPrinting();
587 void CopySelection(const WebPreferences
& preferences
);
589 base::WeakPtrFactory
<PrepareFrameAndViewForPrint
> weak_ptr_factory_
;
591 FrameReference frame_
;
592 blink::WebNode node_to_print_
;
594 blink::WebPrintParams web_print_params_
;
595 gfx::Size prev_view_size_
;
596 gfx::Size prev_scroll_offset_
;
597 int expected_pages_count_
;
598 base::Closure on_ready_
;
599 bool should_print_backgrounds_
;
600 bool should_print_selection_only_
;
601 bool is_printing_started_
;
603 DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint
);
606 PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
607 const PrintMsg_Print_Params
& params
,
608 blink::WebLocalFrame
* frame
,
609 const blink::WebNode
& node
,
610 bool ignore_css_margins
)
611 : weak_ptr_factory_(this),
613 node_to_print_(node
),
614 owns_web_view_(false),
615 expected_pages_count_(0),
616 should_print_backgrounds_(params
.should_print_backgrounds
),
617 should_print_selection_only_(params
.selection_only
),
618 is_printing_started_(false) {
619 PrintMsg_Print_Params print_params
= params
;
620 if (!should_print_selection_only_
||
621 !PrintingNodeOrPdfFrame(frame
, node_to_print_
)) {
622 bool fit_to_page
= ignore_css_margins
&&
623 print_params
.print_scaling_option
==
624 blink::WebPrintScalingOptionFitToPrintableArea
;
625 ComputeWebKitPrintParamsInDesiredDpi(params
, &web_print_params_
);
626 frame
->printBegin(web_print_params_
, node_to_print_
);
627 print_params
= CalculatePrintParamsForCss(frame
, 0, print_params
,
628 ignore_css_margins
, fit_to_page
,
632 ComputeWebKitPrintParamsInDesiredDpi(print_params
, &web_print_params_
);
635 PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
639 void PrepareFrameAndViewForPrint::ResizeForPrinting() {
640 // Layout page according to printer page size. Since WebKit shrinks the
641 // size of the page automatically (from 125% to 200%) we trick it to
642 // think the page is 125% larger so the size of the page is correct for
643 // minimum (default) scaling.
644 // This is important for sites that try to fill the page.
645 gfx::Size
print_layout_size(web_print_params_
.printContentArea
.width
,
646 web_print_params_
.printContentArea
.height
);
647 print_layout_size
.set_height(
648 static_cast<int>(static_cast<double>(print_layout_size
.height()) * 1.25));
652 blink::WebView
* web_view
= frame_
.view();
653 // Backup size and offset.
654 if (blink::WebFrame
* web_frame
= web_view
->mainFrame())
655 prev_scroll_offset_
= web_frame
->scrollOffset();
656 prev_view_size_
= web_view
->size();
658 web_view
->resize(print_layout_size
);
662 void PrepareFrameAndViewForPrint::StartPrinting() {
664 blink::WebView
* web_view
= frame_
.view();
665 web_view
->settings()->setShouldPrintBackgrounds(should_print_backgrounds_
);
666 expected_pages_count_
=
667 frame()->printBegin(web_print_params_
, node_to_print_
);
668 is_printing_started_
= true;
671 void PrepareFrameAndViewForPrint::CopySelectionIfNeeded(
672 const WebPreferences
& preferences
,
673 const base::Closure
& on_ready
) {
674 on_ready_
= on_ready
;
675 if (should_print_selection_only_
) {
676 CopySelection(preferences
);
678 // Call immediately, async call crashes scripting printing.
683 void PrepareFrameAndViewForPrint::CopySelection(
684 const WebPreferences
& preferences
) {
686 std::string url_str
= "data:text/html;charset=utf-8,";
688 net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false));
690 // Create a new WebView with the same settings as the current display one.
691 // Except that we disable javascript (don't want any active content running
693 WebPreferences prefs
= preferences
;
694 prefs
.javascript_enabled
= false;
695 prefs
.java_enabled
= false;
697 blink::WebView
* web_view
= blink::WebView::create(this);
698 owns_web_view_
= true;
699 content::ApplyWebPreferences(prefs
, web_view
);
700 web_view
->setMainFrame(blink::WebLocalFrame::create(this));
701 frame_
.Reset(web_view
->mainFrame()->toWebLocalFrame());
702 node_to_print_
.reset();
704 // When loading is done this will call didStopLoading() and that will do the
706 frame()->loadRequest(blink::WebURLRequest(GURL(url_str
)));
709 bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
713 void PrepareFrameAndViewForPrint::didStopLoading() {
714 DCHECK(!on_ready_
.is_null());
715 // Don't call callback here, because it can delete |this| and WebView that is
716 // called didStopLoading.
717 base::MessageLoop::current()->PostTask(
719 base::Bind(&PrepareFrameAndViewForPrint::CallOnReady
,
720 weak_ptr_factory_
.GetWeakPtr()));
723 blink::WebFrame
* PrepareFrameAndViewForPrint::createChildFrame(
724 blink::WebLocalFrame
* parent
,
725 const blink::WebString
& name
) {
726 blink::WebFrame
* frame
= blink::WebLocalFrame::create(this);
727 parent
->appendChild(frame
);
731 void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame
* frame
) {
733 frame
->parent()->removeChild(frame
);
737 void PrepareFrameAndViewForPrint::CallOnReady() {
738 return on_ready_
.Run(); // Can delete |this|.
741 gfx::Size
PrepareFrameAndViewForPrint::GetPrintCanvasSize() const {
742 DCHECK(is_printing_started_
);
743 return gfx::Size(web_print_params_
.printContentArea
.width
,
744 web_print_params_
.printContentArea
.height
);
747 void PrepareFrameAndViewForPrint::RestoreSize() {
749 blink::WebView
* web_view
= frame_
.GetFrame()->view();
750 web_view
->resize(prev_view_size_
);
751 if (blink::WebFrame
* web_frame
= web_view
->mainFrame())
752 web_frame
->setScrollOffset(prev_scroll_offset_
);
756 void PrepareFrameAndViewForPrint::FinishPrinting() {
757 blink::WebFrame
* frame
= frame_
.GetFrame();
759 blink::WebView
* web_view
= frame
->view();
760 if (is_printing_started_
) {
761 is_printing_started_
= false;
763 if (!owns_web_view_
) {
764 web_view
->settings()->setShouldPrintBackgrounds(false);
768 if (owns_web_view_
) {
769 DCHECK(!frame
->isLoading());
770 owns_web_view_
= false;
778 PrintWebViewHelper::PrintWebViewHelper(content::RenderView
* render_view
)
779 : content::RenderViewObserver(render_view
),
780 content::RenderViewObserverTracker
<PrintWebViewHelper
>(render_view
),
781 reset_prep_frame_view_(false),
782 is_preview_enabled_(IsPrintPreviewEnabled()),
783 is_scripted_print_throttling_disabled_(IsPrintThrottlingDisabled()),
784 is_print_ready_metafile_sent_(false),
785 ignore_css_margins_(false),
786 user_cancelled_scripted_print_count_(0),
787 is_scripted_printing_blocked_(false),
788 notify_browser_of_print_failure_(true),
789 print_for_preview_(false),
790 print_node_in_progress_(false),
792 is_scripted_preview_delayed_(false),
793 weak_ptr_factory_(this) {
796 PrintWebViewHelper::~PrintWebViewHelper() {}
798 bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
799 blink::WebFrame
* frame
, bool user_initiated
) {
800 #if defined(OS_ANDROID)
802 #endif // defined(OS_ANDROID)
803 if (is_scripted_printing_blocked_
)
805 // If preview is enabled, then the print dialog is tab modal, and the user
806 // can always close the tab on a mis-behaving page (the system print dialog
807 // is app modal). If the print was initiated through user action, don't
808 // throttle. Or, if the command line flag to skip throttling has been set.
809 if (!is_scripted_print_throttling_disabled_
&&
810 !is_preview_enabled_
&&
812 return !IsScriptInitiatedPrintTooFrequent(frame
);
816 void PrintWebViewHelper::DidStartLoading() {
820 void PrintWebViewHelper::DidStopLoading() {
822 ShowScriptedPrintPreview();
825 // Prints |frame| which called window.print().
826 void PrintWebViewHelper::PrintPage(blink::WebLocalFrame
* frame
,
827 bool user_initiated
) {
830 // Allow Prerendering to cancel this print request if necessary.
831 if (prerender::PrerenderHelper::IsPrerendering(
832 render_view()->GetMainRenderFrame())) {
833 Send(new ChromeViewHostMsg_CancelPrerenderForPrinting(routing_id()));
837 if (!IsScriptInitiatedPrintAllowed(frame
, user_initiated
))
839 IncrementScriptedPrintCount();
841 if (is_preview_enabled_
) {
842 print_preview_context_
.InitWithFrame(frame
);
843 RequestPrintPreview(PRINT_PREVIEW_SCRIPTED
);
845 Print(frame
, blink::WebNode());
849 bool PrintWebViewHelper::OnMessageReceived(const IPC::Message
& message
) {
851 IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper
, message
)
852 IPC_MESSAGE_HANDLER(PrintMsg_PrintPages
, OnPrintPages
)
853 IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog
, OnPrintForSystemDialog
)
854 IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview
, OnInitiatePrintPreview
)
855 IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview
, OnPrintPreview
)
856 IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview
, OnPrintForPrintPreview
)
857 IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone
, OnPrintingDone
)
858 IPC_MESSAGE_HANDLER(PrintMsg_ResetScriptedPrintCount
,
859 ResetScriptedPrintCount
)
860 IPC_MESSAGE_HANDLER(PrintMsg_SetScriptedPrintingBlocked
,
861 SetScriptedPrintBlocked
)
862 IPC_MESSAGE_UNHANDLED(handled
= false)
863 IPC_END_MESSAGE_MAP()
867 void PrintWebViewHelper::OnPrintForPrintPreview(
868 const base::DictionaryValue
& job_settings
) {
869 DCHECK(is_preview_enabled_
);
870 // If still not finished with earlier print request simply ignore.
871 if (prep_frame_view_
)
874 if (!render_view()->GetWebView())
876 blink::WebFrame
* main_frame
= render_view()->GetWebView()->mainFrame();
880 blink::WebDocument document
= main_frame
->document();
881 // <object> with id="pdf-viewer" is created in
882 // chrome/browser/resources/print_preview/print_preview.js
883 blink::WebElement pdf_element
= document
.getElementById("pdf-viewer");
884 if (pdf_element
.isNull()) {
889 // Set |print_for_preview_| flag and autoreset it to back to original
891 base::AutoReset
<bool> set_printing_flag(&print_for_preview_
, true);
893 blink::WebLocalFrame
* pdf_frame
= pdf_element
.document().frame();
894 if (!UpdatePrintSettings(pdf_frame
, pdf_element
, job_settings
)) {
895 LOG(ERROR
) << "UpdatePrintSettings failed";
896 DidFinishPrinting(FAIL_PRINT
);
900 // Print page onto entire page not just printable area. Preview PDF already
901 // has content in correct position taking into account page size and printable
903 // TODO(vitalybuka) : Make this consistent on all platform. This change
904 // affects Windows only. On Linux and OSX RenderPagesForPrint does not use
905 // printable_area. Also we can't change printable_area deeper inside
906 // RenderPagesForPrint for Windows, because it's used also by native
907 // printing and it expects real printable_area value.
908 // See http://crbug.com/123408
909 PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
910 print_params
.printable_area
= gfx::Rect(print_params
.page_size
);
912 // Render Pages for printing.
913 if (!RenderPagesForPrint(pdf_frame
, pdf_element
)) {
914 LOG(ERROR
) << "RenderPagesForPrint failed";
915 DidFinishPrinting(FAIL_PRINT
);
919 bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame
** frame
) {
921 blink::WebView
* webView
= render_view()->GetWebView();
926 // If the user has selected text in the currently focused frame we print
927 // only that frame (this makes print selection work for multiple frames).
928 blink::WebLocalFrame
* focusedFrame
=
929 webView
->focusedFrame()->toWebLocalFrame();
930 *frame
= focusedFrame
->hasSelection()
932 : webView
->mainFrame()->toWebLocalFrame();
936 void PrintWebViewHelper::OnPrintPages() {
937 blink::WebLocalFrame
* frame
;
938 if (GetPrintFrame(&frame
))
939 Print(frame
, blink::WebNode());
942 void PrintWebViewHelper::OnPrintForSystemDialog() {
943 blink::WebLocalFrame
* frame
= print_preview_context_
.source_frame();
949 Print(frame
, print_preview_context_
.source_node());
952 void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
953 const PageSizeMargins
& page_layout_in_points
,
954 gfx::Size
* page_size
,
955 gfx::Rect
* content_area
) {
956 *page_size
= gfx::Size(
957 page_layout_in_points
.content_width
+
958 page_layout_in_points
.margin_right
+
959 page_layout_in_points
.margin_left
,
960 page_layout_in_points
.content_height
+
961 page_layout_in_points
.margin_top
+
962 page_layout_in_points
.margin_bottom
);
963 *content_area
= gfx::Rect(page_layout_in_points
.margin_left
,
964 page_layout_in_points
.margin_top
,
965 page_layout_in_points
.content_width
,
966 page_layout_in_points
.content_height
);
969 void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
970 const base::DictionaryValue
& settings
) {
971 int margins_type
= 0;
972 if (!settings
.GetInteger(kSettingMarginsType
, &margins_type
))
973 margins_type
= DEFAULT_MARGINS
;
974 ignore_css_margins_
= (margins_type
!= DEFAULT_MARGINS
);
977 bool PrintWebViewHelper::IsPrintToPdfRequested(
978 const base::DictionaryValue
& job_settings
) {
979 bool print_to_pdf
= false;
980 if (!job_settings
.GetBoolean(kSettingPrintToPDF
, &print_to_pdf
))
985 void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue
& settings
) {
986 DCHECK(is_preview_enabled_
);
987 print_preview_context_
.OnPrintPreview();
989 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
990 PREVIEW_EVENT_REQUESTED
, PREVIEW_EVENT_MAX
);
992 if (!print_preview_context_
.source_frame()) {
993 DidFinishPrinting(FAIL_PREVIEW
);
997 if (!UpdatePrintSettings(print_preview_context_
.source_frame(),
998 print_preview_context_
.source_node(), settings
)) {
999 if (print_preview_context_
.last_error() != PREVIEW_ERROR_BAD_SETTING
) {
1000 Send(new PrintHostMsg_PrintPreviewInvalidPrinterSettings(
1002 print_pages_params_
.get()
1003 ? print_pages_params_
->params
.document_cookie
1005 notify_browser_of_print_failure_
= false; // Already sent.
1007 DidFinishPrinting(FAIL_PREVIEW
);
1011 // If we are previewing a pdf and the print scaling is disabled, send a
1012 // message to browser.
1013 if (print_pages_params_
->params
.is_first_request
&&
1014 !print_preview_context_
.IsModifiable() &&
1015 print_preview_context_
.source_frame()->isPrintScalingDisabledForPlugin(
1016 print_preview_context_
.source_node())) {
1017 Send(new PrintHostMsg_PrintPreviewScalingDisabled(routing_id()));
1020 is_print_ready_metafile_sent_
= false;
1022 // PDF printer device supports alpha blending.
1023 print_pages_params_
->params
.supports_alpha_blend
= true;
1025 bool generate_draft_pages
= false;
1026 if (!settings
.GetBoolean(kSettingGenerateDraftData
,
1027 &generate_draft_pages
)) {
1030 print_preview_context_
.set_generate_draft_pages(generate_draft_pages
);
1032 PrepareFrameForPreviewDocument();
1035 void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
1036 reset_prep_frame_view_
= false;
1038 if (!print_pages_params_
|| CheckForCancel()) {
1039 DidFinishPrinting(FAIL_PREVIEW
);
1043 // Don't reset loading frame or WebKit will fail assert. Just retry when
1044 // current selection is loaded.
1045 if (prep_frame_view_
&& prep_frame_view_
->IsLoadingSelection()) {
1046 reset_prep_frame_view_
= true;
1050 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1051 prep_frame_view_
.reset(
1052 new PrepareFrameAndViewForPrint(print_params
,
1053 print_preview_context_
.source_frame(),
1054 print_preview_context_
.source_node(),
1055 ignore_css_margins_
));
1056 prep_frame_view_
->CopySelectionIfNeeded(
1057 render_view()->GetWebkitPreferences(),
1058 base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument
,
1059 base::Unretained(this)));
1062 void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
1063 if (reset_prep_frame_view_
) {
1064 PrepareFrameForPreviewDocument();
1067 DidFinishPrinting(CreatePreviewDocument() ? OK
: FAIL_PREVIEW
);
1070 bool PrintWebViewHelper::CreatePreviewDocument() {
1071 if (!print_pages_params_
|| CheckForCancel())
1074 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
1075 PREVIEW_EVENT_CREATE_DOCUMENT
, PREVIEW_EVENT_MAX
);
1077 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1078 const std::vector
<int>& pages
= print_pages_params_
->pages
;
1080 if (!print_preview_context_
.CreatePreviewDocument(prep_frame_view_
.release(),
1085 PageSizeMargins default_page_layout
;
1086 ComputePageLayoutInPointsForCss(print_preview_context_
.prepared_frame(), 0,
1087 print_params
, ignore_css_margins_
, NULL
,
1088 &default_page_layout
);
1090 bool has_page_size_style
= PrintingFrameHasPageSizeStyle(
1091 print_preview_context_
.prepared_frame(),
1092 print_preview_context_
.total_page_count());
1093 int dpi
= GetDPI(&print_params
);
1095 gfx::Rect
printable_area_in_points(
1096 ConvertUnit(print_params
.printable_area
.x(), dpi
, kPointsPerInch
),
1097 ConvertUnit(print_params
.printable_area
.y(), dpi
, kPointsPerInch
),
1098 ConvertUnit(print_params
.printable_area
.width(), dpi
, kPointsPerInch
),
1099 ConvertUnit(print_params
.printable_area
.height(), dpi
, kPointsPerInch
));
1101 // Margins: Send default page layout to browser process.
1102 Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
1103 default_page_layout
,
1104 printable_area_in_points
,
1105 has_page_size_style
));
1107 PrintHostMsg_DidGetPreviewPageCount_Params params
;
1108 params
.page_count
= print_preview_context_
.total_page_count();
1109 params
.is_modifiable
= print_preview_context_
.IsModifiable();
1110 params
.document_cookie
= print_params
.document_cookie
;
1111 params
.preview_request_id
= print_params
.preview_request_id
;
1112 params
.clear_preview_data
= print_preview_context_
.generate_draft_pages();
1113 Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params
));
1114 if (CheckForCancel())
1117 while (!print_preview_context_
.IsFinalPageRendered()) {
1118 int page_number
= print_preview_context_
.GetNextPageNumber();
1119 DCHECK_GE(page_number
, 0);
1120 if (!RenderPreviewPage(page_number
, print_params
))
1123 if (CheckForCancel())
1126 // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of
1127 // print_preview_context_.AllPagesRendered()) before calling
1128 // FinalizePrintReadyDocument() when printing a PDF because the plugin
1129 // code does not generate output until we call FinishPrinting(). We do not
1130 // generate draft pages for PDFs, so IsFinalPageRendered() and
1131 // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of
1133 if (print_preview_context_
.IsFinalPageRendered())
1134 print_preview_context_
.AllPagesRendered();
1136 if (print_preview_context_
.IsLastPageOfPrintReadyMetafile()) {
1137 DCHECK(print_preview_context_
.IsModifiable() ||
1138 print_preview_context_
.IsFinalPageRendered());
1139 if (!FinalizePrintReadyDocument())
1143 print_preview_context_
.Finished();
1147 bool PrintWebViewHelper::FinalizePrintReadyDocument() {
1148 DCHECK(!is_print_ready_metafile_sent_
);
1149 print_preview_context_
.FinalizePrintReadyDocument();
1151 // Get the size of the resulting metafile.
1152 PreviewMetafile
* metafile
= print_preview_context_
.metafile();
1153 uint32 buf_size
= metafile
->GetDataSize();
1154 DCHECK_GT(buf_size
, 0u);
1156 PrintHostMsg_DidPreviewDocument_Params preview_params
;
1157 preview_params
.data_size
= buf_size
;
1158 preview_params
.document_cookie
= print_pages_params_
->params
.document_cookie
;
1159 preview_params
.expected_pages_count
=
1160 print_preview_context_
.total_page_count();
1161 preview_params
.modifiable
= print_preview_context_
.IsModifiable();
1162 preview_params
.preview_request_id
=
1163 print_pages_params_
->params
.preview_request_id
;
1165 // Ask the browser to create the shared memory for us.
1166 if (!CopyMetafileDataToSharedMem(metafile
,
1167 &(preview_params
.metafile_data_handle
))) {
1168 LOG(ERROR
) << "CopyMetafileDataToSharedMem failed";
1169 print_preview_context_
.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED
);
1172 is_print_ready_metafile_sent_
= true;
1174 Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params
));
1178 void PrintWebViewHelper::OnPrintingDone(bool success
) {
1179 notify_browser_of_print_failure_
= false;
1181 LOG(ERROR
) << "Failure in OnPrintingDone";
1182 DidFinishPrinting(success
? OK
: FAIL_PRINT
);
1185 void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked
) {
1186 is_scripted_printing_blocked_
= blocked
;
1189 void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only
) {
1190 DCHECK(is_preview_enabled_
);
1191 blink::WebLocalFrame
* frame
= NULL
;
1192 GetPrintFrame(&frame
);
1194 print_preview_context_
.InitWithFrame(frame
);
1195 RequestPrintPreview(selection_only
?
1196 PRINT_PREVIEW_USER_INITIATED_SELECTION
:
1197 PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME
);
1200 bool PrintWebViewHelper::IsPrintingEnabled() {
1201 bool result
= false;
1202 Send(new PrintHostMsg_IsPrintingEnabled(routing_id(), &result
));
1206 void PrintWebViewHelper::PrintNode(const blink::WebNode
& node
) {
1207 if (node
.isNull() || !node
.document().frame()) {
1208 // This can occur when the context menu refers to an invalid WebNode.
1209 // See http://crbug.com/100890#c17 for a repro case.
1213 if (print_node_in_progress_
) {
1214 // This can happen as a result of processing sync messages when printing
1215 // from ppapi plugins. It's a rare case, so its OK to just fail here.
1216 // See http://crbug.com/159165.
1220 print_node_in_progress_
= true;
1222 // Make a copy of the node, in case RenderView::OnContextMenuClosed resets
1223 // its |context_menu_node_|.
1224 if (is_preview_enabled_
) {
1225 print_preview_context_
.InitWithNode(node
);
1226 RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE
);
1228 blink::WebNode
duplicate_node(node
);
1229 Print(duplicate_node
.document().frame(), duplicate_node
);
1232 print_node_in_progress_
= false;
1235 void PrintWebViewHelper::Print(blink::WebLocalFrame
* frame
,
1236 const blink::WebNode
& node
) {
1237 // If still not finished with earlier print request simply ignore.
1238 if (prep_frame_view_
)
1241 FrameReference
frame_ref(frame
);
1243 int expected_page_count
= 0;
1244 if (!CalculateNumberOfPages(frame
, node
, &expected_page_count
)) {
1245 DidFinishPrinting(FAIL_PRINT_INIT
);
1246 return; // Failed to init print page settings.
1249 // Some full screen plugins can say they don't want to print.
1250 if (!expected_page_count
) {
1251 DidFinishPrinting(FAIL_PRINT
);
1255 // Ask the browser to show UI to retrieve the final print settings.
1256 if (!GetPrintSettingsFromUser(frame_ref
.GetFrame(), node
,
1257 expected_page_count
)) {
1258 DidFinishPrinting(OK
); // Release resources and fail silently.
1262 // Render Pages for printing.
1263 if (!RenderPagesForPrint(frame_ref
.GetFrame(), node
)) {
1264 LOG(ERROR
) << "RenderPagesForPrint failed";
1265 DidFinishPrinting(FAIL_PRINT
);
1267 ResetScriptedPrintCount();
1270 void PrintWebViewHelper::DidFinishPrinting(PrintingResult result
) {
1275 case FAIL_PRINT_INIT
:
1276 DCHECK(!notify_browser_of_print_failure_
);
1280 if (notify_browser_of_print_failure_
&& print_pages_params_
.get()) {
1281 int cookie
= print_pages_params_
->params
.document_cookie
;
1282 Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie
));
1287 DCHECK(is_preview_enabled_
);
1288 int cookie
= print_pages_params_
.get() ?
1289 print_pages_params_
->params
.document_cookie
: 0;
1290 if (notify_browser_of_print_failure_
) {
1291 LOG(ERROR
) << "CreatePreviewDocument failed";
1292 Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie
));
1294 Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie
));
1296 print_preview_context_
.Failed(notify_browser_of_print_failure_
);
1299 prep_frame_view_
.reset();
1300 print_pages_params_
.reset();
1301 notify_browser_of_print_failure_
= true;
1304 void PrintWebViewHelper::OnFramePreparedForPrintPages() {
1306 FinishFramePrinting();
1309 void PrintWebViewHelper::PrintPages() {
1310 if (!prep_frame_view_
) // Printing is already canceled or failed.
1312 prep_frame_view_
->StartPrinting();
1314 int page_count
= prep_frame_view_
->GetExpectedPageCount();
1316 LOG(ERROR
) << "Can't print 0 pages.";
1317 return DidFinishPrinting(FAIL_PRINT
);
1320 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1321 const PrintMsg_Print_Params
& print_params
= params
.params
;
1323 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
1324 // TODO(vitalybuka): should be page_count or valid pages from params.pages.
1325 // See http://crbug.com/161576
1326 Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
1327 print_params
.document_cookie
,
1329 #endif // !defined(OS_CHROMEOS)
1331 if (print_params
.preview_ui_id
< 0) {
1332 // Printing for system dialog.
1333 int printed_count
= params
.pages
.empty() ? page_count
: params
.pages
.size();
1334 #if !defined(OS_CHROMEOS)
1335 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count
);
1337 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1339 #endif // !defined(OS_CHROMEOS)
1343 if (!PrintPagesNative(prep_frame_view_
->frame(), page_count
,
1344 prep_frame_view_
->GetPrintCanvasSize())) {
1345 LOG(ERROR
) << "Printing failed.";
1346 return DidFinishPrinting(FAIL_PRINT
);
1350 void PrintWebViewHelper::FinishFramePrinting() {
1351 prep_frame_view_
.reset();
1354 #if defined(OS_MACOSX) || defined(OS_WIN)
1355 bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame
* frame
,
1357 const gfx::Size
& canvas_size
) {
1358 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1359 const PrintMsg_Print_Params
& print_params
= params
.params
;
1361 PrintMsg_PrintPage_Params page_params
;
1362 page_params
.params
= print_params
;
1363 if (params
.pages
.empty()) {
1364 for (int i
= 0; i
< page_count
; ++i
) {
1365 page_params
.page_number
= i
;
1366 PrintPageInternal(page_params
, canvas_size
, frame
);
1369 for (size_t i
= 0; i
< params
.pages
.size(); ++i
) {
1370 if (params
.pages
[i
] >= page_count
)
1372 page_params
.page_number
= params
.pages
[i
];
1373 PrintPageInternal(page_params
, canvas_size
, frame
);
1379 #endif // OS_MACOSX || OS_WIN
1381 // static - Not anonymous so that platform implementations can use it.
1382 void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
1383 blink::WebFrame
* frame
,
1385 const PrintMsg_Print_Params
& page_params
,
1386 bool ignore_css_margins
,
1387 double* scale_factor
,
1388 PageSizeMargins
* page_layout_in_points
) {
1389 PrintMsg_Print_Params params
= CalculatePrintParamsForCss(
1390 frame
, page_index
, page_params
, ignore_css_margins
,
1391 page_params
.print_scaling_option
==
1392 blink::WebPrintScalingOptionFitToPrintableArea
,
1394 CalculatePageLayoutFromPrintParams(params
, page_layout_in_points
);
1397 bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size
) {
1398 PrintMsg_PrintPages_Params settings
;
1399 Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
1401 // Check if the printer returned any settings, if the settings is empty, we
1402 // can safely assume there are no printer drivers configured. So we safely
1405 if (!PrintMsg_Print_Params_IsValid(settings
.params
))
1409 (settings
.params
.dpi
< kMinDpi
|| settings
.params
.document_cookie
== 0)) {
1410 // Invalid print page settings.
1415 // Reset to default values.
1416 ignore_css_margins_
= false;
1417 settings
.pages
.clear();
1419 settings
.params
.print_scaling_option
=
1420 blink::WebPrintScalingOptionSourceSize
;
1421 if (fit_to_paper_size
) {
1422 settings
.params
.print_scaling_option
=
1423 blink::WebPrintScalingOptionFitToPrintableArea
;
1426 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1430 bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame
* frame
,
1431 const blink::WebNode
& node
,
1432 int* number_of_pages
) {
1434 bool fit_to_paper_size
= !(PrintingNodeOrPdfFrame(frame
, node
));
1435 if (!InitPrintSettings(fit_to_paper_size
)) {
1436 notify_browser_of_print_failure_
= false;
1437 Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
1441 const PrintMsg_Print_Params
& params
= print_pages_params_
->params
;
1442 PrepareFrameAndViewForPrint
prepare(params
, frame
, node
, ignore_css_margins_
);
1443 prepare
.StartPrinting();
1445 Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
1446 params
.document_cookie
));
1447 *number_of_pages
= prepare
.GetExpectedPageCount();
1451 bool PrintWebViewHelper::UpdatePrintSettings(
1452 blink::WebLocalFrame
* frame
,
1453 const blink::WebNode
& node
,
1454 const base::DictionaryValue
& passed_job_settings
) {
1455 DCHECK(is_preview_enabled_
);
1456 const base::DictionaryValue
* job_settings
= &passed_job_settings
;
1457 base::DictionaryValue modified_job_settings
;
1458 if (job_settings
->empty()) {
1459 if (!print_for_preview_
)
1460 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1464 bool source_is_html
= true;
1465 if (print_for_preview_
) {
1466 if (!job_settings
->GetBoolean(kSettingPreviewModifiable
, &source_is_html
)) {
1470 source_is_html
= !PrintingNodeOrPdfFrame(frame
, node
);
1473 if (print_for_preview_
|| !source_is_html
) {
1474 modified_job_settings
.MergeDictionary(job_settings
);
1475 modified_job_settings
.SetBoolean(kSettingHeaderFooterEnabled
, false);
1476 modified_job_settings
.SetInteger(kSettingMarginsType
, NO_MARGINS
);
1477 job_settings
= &modified_job_settings
;
1480 // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when
1482 int cookie
= print_pages_params_
.get() ?
1483 print_pages_params_
->params
.document_cookie
: 0;
1484 PrintMsg_PrintPages_Params settings
;
1485 Send(new PrintHostMsg_UpdatePrintSettings(routing_id(), cookie
, *job_settings
,
1487 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1489 if (!PrintMsg_Print_Params_IsValid(settings
.params
)) {
1490 if (!print_for_preview_
)
1491 print_preview_context_
.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS
);
1493 Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
1498 if (settings
.params
.dpi
< kMinDpi
|| !settings
.params
.document_cookie
) {
1499 print_preview_context_
.set_error(PREVIEW_ERROR_UPDATING_PRINT_SETTINGS
);
1503 if (!job_settings
->GetInteger(kPreviewUIID
, &settings
.params
.preview_ui_id
)) {
1505 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1509 if (!print_for_preview_
) {
1510 // Validate expected print preview settings.
1511 if (!job_settings
->GetInteger(kPreviewRequestID
,
1512 &settings
.params
.preview_request_id
) ||
1513 !job_settings
->GetBoolean(kIsFirstRequest
,
1514 &settings
.params
.is_first_request
)) {
1516 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1520 settings
.params
.print_to_pdf
= IsPrintToPdfRequested(*job_settings
);
1521 UpdateFrameMarginsCssInfo(*job_settings
);
1522 settings
.params
.print_scaling_option
= GetPrintScalingOption(
1523 frame
, node
, source_is_html
, *job_settings
, settings
.params
);
1525 // Header/Footer: Set |header_footer_info_|.
1526 if (settings
.params
.display_header_footer
) {
1527 header_footer_info_
.reset(new base::DictionaryValue());
1528 header_footer_info_
->SetDouble(kSettingHeaderFooterDate
,
1529 base::Time::Now().ToJsTime());
1530 header_footer_info_
->SetString(kSettingHeaderFooterURL
,
1531 settings
.params
.url
);
1532 header_footer_info_
->SetString(kSettingHeaderFooterTitle
,
1533 settings
.params
.title
);
1537 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1538 Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
1539 settings
.params
.document_cookie
));
1544 bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame
* frame
,
1545 const blink::WebNode
& node
,
1546 int expected_pages_count
) {
1547 PrintHostMsg_ScriptedPrint_Params params
;
1548 PrintMsg_PrintPages_Params print_settings
;
1550 params
.cookie
= print_pages_params_
->params
.document_cookie
;
1551 params
.has_selection
= frame
->hasSelection();
1552 params
.expected_pages_count
= expected_pages_count
;
1553 MarginType margin_type
= DEFAULT_MARGINS
;
1554 if (PrintingNodeOrPdfFrame(frame
, node
))
1555 margin_type
= GetMarginsForPdf(frame
, node
);
1556 params
.margin_type
= margin_type
;
1558 Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));
1560 // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the
1561 // value before and restore it afterwards.
1562 blink::WebPrintScalingOption scaling_option
=
1563 print_pages_params_
->params
.print_scaling_option
;
1565 print_pages_params_
.reset();
1566 IPC::SyncMessage
* msg
=
1567 new PrintHostMsg_ScriptedPrint(routing_id(), params
, &print_settings
);
1568 msg
->EnableMessagePumping();
1570 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(print_settings
));
1572 print_pages_params_
->params
.print_scaling_option
= scaling_option
;
1573 return (print_settings
.params
.dpi
&& print_settings
.params
.document_cookie
);
1576 bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame
* frame
,
1577 const blink::WebNode
& node
) {
1578 if (!frame
|| prep_frame_view_
)
1580 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1581 const PrintMsg_Print_Params
& print_params
= params
.params
;
1582 prep_frame_view_
.reset(
1583 new PrepareFrameAndViewForPrint(print_params
, frame
, node
,
1584 ignore_css_margins_
));
1585 DCHECK(!print_pages_params_
->params
.selection_only
||
1586 print_pages_params_
->pages
.empty());
1587 prep_frame_view_
->CopySelectionIfNeeded(
1588 render_view()->GetWebkitPreferences(),
1589 base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages
,
1590 base::Unretained(this)));
1594 #if defined(OS_POSIX)
1595 bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
1597 base::SharedMemoryHandle
* shared_mem_handle
) {
1598 uint32 buf_size
= metafile
->GetDataSize();
1599 scoped_ptr
<base::SharedMemory
> shared_buf(
1600 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
1601 buf_size
).release());
1603 if (shared_buf
.get()) {
1604 if (shared_buf
->Map(buf_size
)) {
1605 metafile
->GetData(shared_buf
->memory(), buf_size
);
1606 shared_buf
->GiveToProcess(base::GetCurrentProcessHandle(),
1614 #endif // defined(OS_POSIX)
1616 bool PrintWebViewHelper::IsScriptInitiatedPrintTooFrequent(
1617 blink::WebFrame
* frame
) {
1618 const int kMinSecondsToIgnoreJavascriptInitiatedPrint
= 2;
1619 const int kMaxSecondsToIgnoreJavascriptInitiatedPrint
= 32;
1620 bool too_frequent
= false;
1622 // Check if there is script repeatedly trying to print and ignore it if too
1623 // frequent. The first 3 times, we use a constant wait time, but if this
1624 // gets excessive, we switch to exponential wait time. So for a page that
1625 // calls print() in a loop the user will need to cancel the print dialog
1626 // after: [2, 2, 2, 4, 8, 16, 32, 32, ...] seconds.
1627 // This gives the user time to navigate from the page.
1628 if (user_cancelled_scripted_print_count_
> 0) {
1629 base::TimeDelta diff
= base::Time::Now() - last_cancelled_script_print_
;
1630 int min_wait_seconds
= kMinSecondsToIgnoreJavascriptInitiatedPrint
;
1631 if (user_cancelled_scripted_print_count_
> 3) {
1632 min_wait_seconds
= std::min(
1633 kMinSecondsToIgnoreJavascriptInitiatedPrint
<<
1634 (user_cancelled_scripted_print_count_
- 3),
1635 kMaxSecondsToIgnoreJavascriptInitiatedPrint
);
1637 if (diff
.InSeconds() < min_wait_seconds
) {
1638 too_frequent
= true;
1645 blink::WebString
message(
1646 blink::WebString::fromUTF8("Ignoring too frequent calls to print()."));
1647 frame
->addMessageToConsole(
1648 blink::WebConsoleMessage(
1649 blink::WebConsoleMessage::LevelWarning
, message
));
1653 void PrintWebViewHelper::ResetScriptedPrintCount() {
1654 // Reset cancel counter on successful print.
1655 user_cancelled_scripted_print_count_
= 0;
1658 void PrintWebViewHelper::IncrementScriptedPrintCount() {
1659 ++user_cancelled_scripted_print_count_
;
1660 last_cancelled_script_print_
= base::Time::Now();
1664 void PrintWebViewHelper::ShowScriptedPrintPreview() {
1665 if (is_scripted_preview_delayed_
) {
1666 is_scripted_preview_delayed_
= false;
1667 Send(new PrintHostMsg_ShowScriptedPrintPreview(routing_id(),
1668 print_preview_context_
.IsModifiable()));
1672 void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type
) {
1673 const bool is_modifiable
= print_preview_context_
.IsModifiable();
1674 const bool has_selection
= print_preview_context_
.HasSelection();
1675 PrintHostMsg_RequestPrintPreview_Params params
;
1676 params
.is_modifiable
= is_modifiable
;
1677 params
.has_selection
= has_selection
;
1679 case PRINT_PREVIEW_SCRIPTED
: {
1680 // Shows scripted print preview in two stages.
1681 // 1. PrintHostMsg_SetupScriptedPrintPreview blocks this call and JS by
1682 // pumping messages here.
1683 // 2. PrintHostMsg_ShowScriptedPrintPreview shows preview once the
1684 // document has been loaded.
1685 is_scripted_preview_delayed_
= true;
1686 if (is_loading_
&& GetPlugin(print_preview_context_
.source_frame())) {
1687 // Wait for DidStopLoading. Plugins may not know the correct
1688 // |is_modifiable| value until they are fully loaded, which occurs when
1689 // DidStopLoading() is called. Defer showing the preview until then.
1691 base::MessageLoop::current()->PostTask(
1693 base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview
,
1694 weak_ptr_factory_
.GetWeakPtr()));
1696 IPC::SyncMessage
* msg
=
1697 new PrintHostMsg_SetupScriptedPrintPreview(routing_id());
1698 msg
->EnableMessagePumping();
1700 is_scripted_preview_delayed_
= false;
1703 case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME
: {
1706 case PRINT_PREVIEW_USER_INITIATED_SELECTION
: {
1707 DCHECK(has_selection
);
1708 params
.selection_only
= has_selection
;
1711 case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE
: {
1712 params
.webnode_only
= true;
1720 Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params
));
1723 bool PrintWebViewHelper::CheckForCancel() {
1724 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1725 bool cancel
= false;
1726 Send(new PrintHostMsg_CheckForCancel(routing_id(),
1727 print_params
.preview_ui_id
,
1728 print_params
.preview_request_id
,
1731 notify_browser_of_print_failure_
= false;
1735 bool PrintWebViewHelper::PreviewPageRendered(int page_number
,
1736 Metafile
* metafile
) {
1737 DCHECK_GE(page_number
, FIRST_PAGE_INDEX
);
1739 // For non-modifiable files, |metafile| should be NULL, so do not bother
1740 // sending a message. If we don't generate draft metafiles, |metafile| is
1742 if (!print_preview_context_
.IsModifiable() ||
1743 !print_preview_context_
.generate_draft_pages()) {
1750 print_preview_context_
.set_error(
1751 PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE
);
1755 PrintHostMsg_DidPreviewPage_Params preview_page_params
;
1756 // Get the size of the resulting metafile.
1757 uint32 buf_size
= metafile
->GetDataSize();
1758 DCHECK_GT(buf_size
, 0u);
1759 if (!CopyMetafileDataToSharedMem(
1760 metafile
, &(preview_page_params
.metafile_data_handle
))) {
1761 LOG(ERROR
) << "CopyMetafileDataToSharedMem failed";
1762 print_preview_context_
.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED
);
1765 preview_page_params
.data_size
= buf_size
;
1766 preview_page_params
.page_number
= page_number
;
1767 preview_page_params
.preview_request_id
=
1768 print_pages_params_
->params
.preview_request_id
;
1770 Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params
));
1774 PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
1775 : total_page_count_(0),
1776 current_page_index_(0),
1777 generate_draft_pages_(true),
1778 print_ready_metafile_page_count_(0),
1779 error_(PREVIEW_ERROR_NONE
),
1780 state_(UNINITIALIZED
) {
1783 PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
1786 void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
1787 blink::WebLocalFrame
* web_frame
) {
1789 DCHECK(!IsRendering());
1790 state_
= INITIALIZED
;
1791 source_frame_
.Reset(web_frame
);
1792 source_node_
.reset();
1795 void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
1796 const blink::WebNode
& web_node
) {
1797 DCHECK(!web_node
.isNull());
1798 DCHECK(web_node
.document().frame());
1799 DCHECK(!IsRendering());
1800 state_
= INITIALIZED
;
1801 source_frame_
.Reset(web_node
.document().frame());
1802 source_node_
= web_node
;
1805 void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
1806 DCHECK_EQ(INITIALIZED
, state_
);
1810 bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
1811 PrepareFrameAndViewForPrint
* prepared_frame
,
1812 const std::vector
<int>& pages
) {
1813 DCHECK_EQ(INITIALIZED
, state_
);
1816 // Need to make sure old object gets destroyed first.
1817 prep_frame_view_
.reset(prepared_frame
);
1818 prep_frame_view_
->StartPrinting();
1820 total_page_count_
= prep_frame_view_
->GetExpectedPageCount();
1821 if (total_page_count_
== 0) {
1822 LOG(ERROR
) << "CreatePreviewDocument got 0 page count";
1823 set_error(PREVIEW_ERROR_ZERO_PAGES
);
1827 metafile_
.reset(new PreviewMetafile
);
1828 if (!metafile_
->Init()) {
1829 set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED
);
1830 LOG(ERROR
) << "PreviewMetafile Init failed";
1834 current_page_index_
= 0;
1835 pages_to_render_
= pages
;
1836 // Sort and make unique.
1837 std::sort(pages_to_render_
.begin(), pages_to_render_
.end());
1838 pages_to_render_
.resize(std::unique(pages_to_render_
.begin(),
1839 pages_to_render_
.end()) -
1840 pages_to_render_
.begin());
1841 // Remove invalid pages.
1842 pages_to_render_
.resize(std::lower_bound(pages_to_render_
.begin(),
1843 pages_to_render_
.end(),
1844 total_page_count_
) -
1845 pages_to_render_
.begin());
1846 print_ready_metafile_page_count_
= pages_to_render_
.size();
1847 if (pages_to_render_
.empty()) {
1848 print_ready_metafile_page_count_
= total_page_count_
;
1849 // Render all pages.
1850 for (int i
= 0; i
< total_page_count_
; ++i
)
1851 pages_to_render_
.push_back(i
);
1852 } else if (generate_draft_pages_
) {
1853 int pages_index
= 0;
1854 for (int i
= 0; i
< total_page_count_
; ++i
) {
1855 if (pages_index
< print_ready_metafile_page_count_
&&
1856 i
== pages_to_render_
[pages_index
]) {
1860 pages_to_render_
.push_back(i
);
1864 document_render_time_
= base::TimeDelta();
1865 begin_time_
= base::TimeTicks::Now();
1870 void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
1871 const base::TimeDelta
& page_time
) {
1872 DCHECK_EQ(RENDERING
, state_
);
1873 document_render_time_
+= page_time
;
1874 UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time
);
1877 void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
1878 DCHECK_EQ(RENDERING
, state_
);
1880 prep_frame_view_
->FinishPrinting();
1883 void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
1884 DCHECK(IsRendering());
1886 base::TimeTicks begin_time
= base::TimeTicks::Now();
1887 metafile_
->FinishDocument();
1889 if (print_ready_metafile_page_count_
<= 0) {
1894 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
1895 document_render_time_
);
1896 base::TimeDelta total_time
= (base::TimeTicks::Now() - begin_time
) +
1897 document_render_time_
;
1898 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
1900 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
1901 total_time
/ pages_to_render_
.size());
1904 void PrintWebViewHelper::PrintPreviewContext::Finished() {
1905 DCHECK_EQ(DONE
, state_
);
1906 state_
= INITIALIZED
;
1910 void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error
) {
1911 DCHECK(state_
== INITIALIZED
|| state_
== RENDERING
);
1912 state_
= INITIALIZED
;
1914 DCHECK_NE(PREVIEW_ERROR_NONE
, error_
);
1915 UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_
,
1916 PREVIEW_ERROR_LAST_ENUM
);
1921 int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
1922 DCHECK_EQ(RENDERING
, state_
);
1923 if (IsFinalPageRendered())
1925 return pages_to_render_
[current_page_index_
++];
1928 bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
1929 return state_
== RENDERING
|| state_
== DONE
;
1932 bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
1933 // The only kind of node we can print right now is a PDF node.
1934 return !PrintingNodeOrPdfFrame(source_frame(), source_node_
);
1937 bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
1938 return IsModifiable() && source_frame()->hasSelection();
1941 bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
1943 DCHECK(IsRendering());
1944 return current_page_index_
== print_ready_metafile_page_count_
;
1947 bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
1948 DCHECK(IsRendering());
1949 return static_cast<size_t>(current_page_index_
) == pages_to_render_
.size();
1952 void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
1953 bool generate_draft_pages
) {
1954 DCHECK_EQ(INITIALIZED
, state_
);
1955 generate_draft_pages_
= generate_draft_pages
;
1958 void PrintWebViewHelper::PrintPreviewContext::set_error(
1959 enum PrintPreviewErrorBuckets error
) {
1963 blink::WebLocalFrame
* PrintWebViewHelper::PrintPreviewContext::source_frame() {
1964 DCHECK(state_
!= UNINITIALIZED
);
1965 return source_frame_
.GetFrame();
1968 const blink::WebNode
&
1969 PrintWebViewHelper::PrintPreviewContext::source_node() const {
1970 DCHECK(state_
!= UNINITIALIZED
);
1971 return source_node_
;
1974 blink::WebLocalFrame
*
1975 PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
1976 DCHECK(state_
!= UNINITIALIZED
);
1977 return prep_frame_view_
->frame();
1980 const blink::WebNode
&
1981 PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
1982 DCHECK(state_
!= UNINITIALIZED
);
1983 return prep_frame_view_
->node();
1986 int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
1987 DCHECK(state_
!= UNINITIALIZED
);
1988 return total_page_count_
;
1991 bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
1992 return generate_draft_pages_
;
1995 PreviewMetafile
* PrintWebViewHelper::PrintPreviewContext::metafile() {
1996 DCHECK(IsRendering());
1997 return metafile_
.get();
2000 int PrintWebViewHelper::PrintPreviewContext::last_error() const {
2004 gfx::Size
PrintWebViewHelper::PrintPreviewContext::GetPrintCanvasSize() const {
2005 DCHECK(IsRendering());
2006 return prep_frame_view_
->GetPrintCanvasSize();
2009 void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
2010 prep_frame_view_
.reset();
2012 pages_to_render_
.clear();
2013 error_
= PREVIEW_ERROR_NONE
;
2016 } // namespace printing