1 // Copyright 2013 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 // TODO(sgurun) copied from chrome/renderer. Remove after crbug.com/322276
7 #include "android_webview/renderer/print_web_view_helper.h"
11 #include "android_webview/common/print_messages.h"
12 #include "base/auto_reset.h"
13 #include "base/command_line.h"
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h"
18 #include "base/process/process_handle.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "content/public/common/web_preferences.h"
23 #include "content/public/renderer/render_thread.h"
24 #include "content/public/renderer/render_view.h"
25 #include "net/base/escape.h"
26 #include "printing/pdf_metafile_skia.h"
27 #include "printing/units.h"
28 #include "third_party/WebKit/public/platform/WebSize.h"
29 #include "third_party/WebKit/public/platform/WebURLRequest.h"
30 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
31 #include "third_party/WebKit/public/web/WebDocument.h"
32 #include "third_party/WebKit/public/web/WebElement.h"
33 #include "third_party/WebKit/public/web/WebFrameClient.h"
34 #include "third_party/WebKit/public/web/WebLocalFrame.h"
35 #include "third_party/WebKit/public/web/WebPlugin.h"
36 #include "third_party/WebKit/public/web/WebPluginDocument.h"
37 #include "third_party/WebKit/public/web/WebPrintParams.h"
38 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
39 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
40 #include "third_party/WebKit/public/web/WebScriptSource.h"
41 #include "third_party/WebKit/public/web/WebSettings.h"
42 #include "third_party/WebKit/public/web/WebView.h"
43 #include "third_party/WebKit/public/web/WebViewClient.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
47 // This code is copied from chrome/renderer/printing. Code is slightly
48 // modified to run it with webview, and the modifications are marked
50 // TODO(sgurun): remove the code as part of componentization of printing.
52 using content::WebPreferences
;
58 enum PrintPreviewHelperEvents
{
59 PREVIEW_EVENT_REQUESTED
,
60 PREVIEW_EVENT_CACHE_HIT
, // Unused
61 PREVIEW_EVENT_CREATE_DOCUMENT
,
62 PREVIEW_EVENT_NEW_SETTINGS
, // Unused
66 const double kMinDpi
= 1.0;
69 // TODO(sgurun) android_webview hack
70 const char kPageLoadScriptFormat
[] =
71 "document.open(); document.write(%s); document.close();";
73 const char kPageSetupScriptFormat
[] = "setup(%s);";
75 void ExecuteScript(blink::WebFrame
* frame
,
76 const char* script_format
,
77 const base::Value
& parameters
) {
79 base::JSONWriter::Write(¶meters
, &json
);
80 std::string script
= base::StringPrintf(script_format
, json
.c_str());
81 frame
->executeScript(blink::WebString(base::UTF8ToUTF16(script
)));
85 int GetDPI(const PrintMsg_Print_Params
* print_params
) {
86 #if defined(OS_MACOSX)
87 // On the Mac, the printable area is in points, don't do any scaling based
89 return kPointsPerInch
;
91 return static_cast<int>(print_params
->dpi
);
92 #endif // defined(OS_MACOSX)
95 bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params
& params
) {
96 return !params
.content_size
.IsEmpty() && !params
.page_size
.IsEmpty() &&
97 !params
.printable_area
.IsEmpty() && params
.document_cookie
&&
98 params
.desired_dpi
&& params
.max_shrink
&& params
.min_shrink
&&
99 params
.dpi
&& (params
.margin_top
>= 0) && (params
.margin_left
>= 0);
102 PrintMsg_Print_Params
GetCssPrintParams(
103 blink::WebFrame
* frame
,
105 const PrintMsg_Print_Params
& page_params
) {
106 PrintMsg_Print_Params page_css_params
= page_params
;
107 int dpi
= GetDPI(&page_params
);
109 blink::WebSize
page_size_in_pixels(
110 ConvertUnit(page_params
.page_size
.width(), dpi
, kPixelsPerInch
),
111 ConvertUnit(page_params
.page_size
.height(), dpi
, kPixelsPerInch
));
112 int margin_top_in_pixels
=
113 ConvertUnit(page_params
.margin_top
, dpi
, kPixelsPerInch
);
114 int margin_right_in_pixels
= ConvertUnit(
115 page_params
.page_size
.width() -
116 page_params
.content_size
.width() - page_params
.margin_left
,
117 dpi
, kPixelsPerInch
);
118 int margin_bottom_in_pixels
= ConvertUnit(
119 page_params
.page_size
.height() -
120 page_params
.content_size
.height() - page_params
.margin_top
,
121 dpi
, kPixelsPerInch
);
122 int margin_left_in_pixels
= ConvertUnit(
123 page_params
.margin_left
,
124 dpi
, kPixelsPerInch
);
126 blink::WebSize original_page_size_in_pixels
= page_size_in_pixels
;
129 frame
->pageSizeAndMarginsInPixels(page_index
,
131 margin_top_in_pixels
,
132 margin_right_in_pixels
,
133 margin_bottom_in_pixels
,
134 margin_left_in_pixels
);
137 int new_content_width
= page_size_in_pixels
.width
-
138 margin_left_in_pixels
- margin_right_in_pixels
;
139 int new_content_height
= page_size_in_pixels
.height
-
140 margin_top_in_pixels
- margin_bottom_in_pixels
;
142 // Invalid page size and/or margins. We just use the default setting.
143 if (new_content_width
< 1 || new_content_height
< 1) {
145 page_css_params
= GetCssPrintParams(NULL
, page_index
, page_params
);
146 return page_css_params
;
149 page_css_params
.content_size
= gfx::Size(
150 ConvertUnit(new_content_width
, kPixelsPerInch
, dpi
),
151 ConvertUnit(new_content_height
, kPixelsPerInch
, dpi
));
153 if (original_page_size_in_pixels
!= page_size_in_pixels
) {
154 page_css_params
.page_size
= gfx::Size(
155 ConvertUnit(page_size_in_pixels
.width
, kPixelsPerInch
, dpi
),
156 ConvertUnit(page_size_in_pixels
.height
, kPixelsPerInch
, dpi
));
158 // Printing frame doesn't have any page size css. Pixels to dpi conversion
159 // causes rounding off errors. Therefore use the default page size values
161 page_css_params
.page_size
= page_params
.page_size
;
164 page_css_params
.margin_top
=
165 ConvertUnit(margin_top_in_pixels
, kPixelsPerInch
, dpi
);
166 page_css_params
.margin_left
=
167 ConvertUnit(margin_left_in_pixels
, kPixelsPerInch
, dpi
);
168 return page_css_params
;
171 double FitPrintParamsToPage(const PrintMsg_Print_Params
& page_params
,
172 PrintMsg_Print_Params
* params_to_fit
) {
173 double content_width
=
174 static_cast<double>(params_to_fit
->content_size
.width());
175 double content_height
=
176 static_cast<double>(params_to_fit
->content_size
.height());
177 int default_page_size_height
= page_params
.page_size
.height();
178 int default_page_size_width
= page_params
.page_size
.width();
179 int css_page_size_height
= params_to_fit
->page_size
.height();
180 int css_page_size_width
= params_to_fit
->page_size
.width();
182 double scale_factor
= 1.0f
;
183 if (page_params
.page_size
== params_to_fit
->page_size
)
186 if (default_page_size_width
< css_page_size_width
||
187 default_page_size_height
< css_page_size_height
) {
189 static_cast<double>(default_page_size_width
) / css_page_size_width
;
190 double ratio_height
=
191 static_cast<double>(default_page_size_height
) / css_page_size_height
;
192 scale_factor
= ratio_width
< ratio_height
? ratio_width
: ratio_height
;
193 content_width
*= scale_factor
;
194 content_height
*= scale_factor
;
196 params_to_fit
->margin_top
= static_cast<int>(
197 (default_page_size_height
- css_page_size_height
* scale_factor
) / 2 +
198 (params_to_fit
->margin_top
* scale_factor
));
199 params_to_fit
->margin_left
= static_cast<int>(
200 (default_page_size_width
- css_page_size_width
* scale_factor
) / 2 +
201 (params_to_fit
->margin_left
* scale_factor
));
202 params_to_fit
->content_size
= gfx::Size(
203 static_cast<int>(content_width
), static_cast<int>(content_height
));
204 params_to_fit
->page_size
= page_params
.page_size
;
208 void CalculatePageLayoutFromPrintParams(
209 const PrintMsg_Print_Params
& params
,
210 PageSizeMargins
* page_layout_in_points
) {
211 int dpi
= GetDPI(¶ms
);
212 int content_width
= params
.content_size
.width();
213 int content_height
= params
.content_size
.height();
215 int margin_bottom
= params
.page_size
.height() -
216 content_height
- params
.margin_top
;
217 int margin_right
= params
.page_size
.width() -
218 content_width
- params
.margin_left
;
220 page_layout_in_points
->content_width
=
221 ConvertUnit(content_width
, dpi
, kPointsPerInch
);
222 page_layout_in_points
->content_height
=
223 ConvertUnit(content_height
, dpi
, kPointsPerInch
);
224 page_layout_in_points
->margin_top
=
225 ConvertUnit(params
.margin_top
, dpi
, kPointsPerInch
);
226 page_layout_in_points
->margin_right
=
227 ConvertUnit(margin_right
, dpi
, kPointsPerInch
);
228 page_layout_in_points
->margin_bottom
=
229 ConvertUnit(margin_bottom
, dpi
, kPointsPerInch
);
230 page_layout_in_points
->margin_left
=
231 ConvertUnit(params
.margin_left
, dpi
, kPointsPerInch
);
234 void EnsureOrientationMatches(const PrintMsg_Print_Params
& css_params
,
235 PrintMsg_Print_Params
* page_params
) {
236 if ((page_params
->page_size
.width() > page_params
->page_size
.height()) ==
237 (css_params
.page_size
.width() > css_params
.page_size
.height())) {
241 // Swap the |width| and |height| values.
242 page_params
->page_size
.SetSize(page_params
->page_size
.height(),
243 page_params
->page_size
.width());
244 page_params
->content_size
.SetSize(page_params
->content_size
.height(),
245 page_params
->content_size
.width());
246 page_params
->printable_area
.set_size(
247 gfx::Size(page_params
->printable_area
.height(),
248 page_params
->printable_area
.width()));
251 void ComputeWebKitPrintParamsInDesiredDpi(
252 const PrintMsg_Print_Params
& print_params
,
253 blink::WebPrintParams
* webkit_print_params
) {
254 int dpi
= GetDPI(&print_params
);
255 webkit_print_params
->printerDPI
= dpi
;
256 webkit_print_params
->printScalingOption
= print_params
.print_scaling_option
;
258 webkit_print_params
->printContentArea
.width
=
259 ConvertUnit(print_params
.content_size
.width(), dpi
,
260 print_params
.desired_dpi
);
261 webkit_print_params
->printContentArea
.height
=
262 ConvertUnit(print_params
.content_size
.height(), dpi
,
263 print_params
.desired_dpi
);
265 webkit_print_params
->printableArea
.x
=
266 ConvertUnit(print_params
.printable_area
.x(), dpi
,
267 print_params
.desired_dpi
);
268 webkit_print_params
->printableArea
.y
=
269 ConvertUnit(print_params
.printable_area
.y(), dpi
,
270 print_params
.desired_dpi
);
271 webkit_print_params
->printableArea
.width
=
272 ConvertUnit(print_params
.printable_area
.width(), dpi
,
273 print_params
.desired_dpi
);
274 webkit_print_params
->printableArea
.height
=
275 ConvertUnit(print_params
.printable_area
.height(),
276 dpi
, print_params
.desired_dpi
);
278 webkit_print_params
->paperSize
.width
=
279 ConvertUnit(print_params
.page_size
.width(), dpi
,
280 print_params
.desired_dpi
);
281 webkit_print_params
->paperSize
.height
=
282 ConvertUnit(print_params
.page_size
.height(), dpi
,
283 print_params
.desired_dpi
);
286 blink::WebPlugin
* GetPlugin(const blink::WebFrame
* frame
) {
287 return frame
->document().isPluginDocument() ?
288 frame
->document().to
<blink::WebPluginDocument
>().plugin() : NULL
;
291 bool PrintingNodeOrPdfFrame(const blink::WebFrame
* frame
,
292 const blink::WebNode
& node
) {
295 blink::WebPlugin
* plugin
= GetPlugin(frame
);
296 return plugin
&& plugin
->supportsPaginatedPrint();
299 bool PrintingFrameHasPageSizeStyle(blink::WebFrame
* frame
,
300 int total_page_count
) {
303 bool frame_has_custom_page_size_style
= false;
304 for (int i
= 0; i
< total_page_count
; ++i
) {
305 if (frame
->hasCustomPageSizeStyle(i
)) {
306 frame_has_custom_page_size_style
= true;
310 return frame_has_custom_page_size_style
;
313 MarginType
GetMarginsForPdf(blink::WebFrame
* frame
,
314 const blink::WebNode
& node
) {
315 if (frame
->isPrintScalingDisabledForPlugin(node
))
318 return PRINTABLE_AREA_MARGINS
;
321 bool FitToPageEnabled(const base::DictionaryValue
& job_settings
) {
322 bool fit_to_paper_size
= false;
323 if (!job_settings
.GetBoolean(kSettingFitToPageEnabled
, &fit_to_paper_size
)) {
326 return fit_to_paper_size
;
329 PrintMsg_Print_Params
CalculatePrintParamsForCss(
330 blink::WebFrame
* frame
,
332 const PrintMsg_Print_Params
& page_params
,
333 bool ignore_css_margins
,
335 double* scale_factor
) {
336 PrintMsg_Print_Params css_params
= GetCssPrintParams(frame
, page_index
,
339 PrintMsg_Print_Params params
= page_params
;
340 EnsureOrientationMatches(css_params
, ¶ms
);
342 if (ignore_css_margins
&& fit_to_page
)
345 PrintMsg_Print_Params result_params
= css_params
;
346 if (ignore_css_margins
) {
347 result_params
.margin_top
= params
.margin_top
;
348 result_params
.margin_left
= params
.margin_left
;
350 DCHECK(!fit_to_page
);
351 // Since we are ignoring the margins, the css page size is no longer
353 int default_margin_right
= params
.page_size
.width() -
354 params
.content_size
.width() - params
.margin_left
;
355 int default_margin_bottom
= params
.page_size
.height() -
356 params
.content_size
.height() - params
.margin_top
;
357 result_params
.content_size
= gfx::Size(
358 result_params
.page_size
.width() - result_params
.margin_left
-
359 default_margin_right
,
360 result_params
.page_size
.height() - result_params
.margin_top
-
361 default_margin_bottom
);
365 double factor
= FitPrintParamsToPage(params
, &result_params
);
367 *scale_factor
= factor
;
369 return result_params
;
372 bool IsPrintPreviewEnabled() {
376 bool IsPrintThrottlingDisabled() {
382 FrameReference::FrameReference(blink::WebLocalFrame
* frame
) {
386 FrameReference::FrameReference() {
390 FrameReference::~FrameReference() {
393 void FrameReference::Reset(blink::WebLocalFrame
* frame
) {
395 view_
= frame
->view();
403 blink::WebLocalFrame
* FrameReference::GetFrame() {
404 if (view_
== NULL
|| frame_
== NULL
)
406 for (blink::WebFrame
* frame
= view_
->mainFrame(); frame
!= NULL
;
407 frame
= frame
->traverseNext(false)) {
414 blink::WebView
* FrameReference::view() {
418 // static - Not anonymous so that platform implementations can use it.
419 void PrintWebViewHelper::PrintHeaderAndFooter(
420 blink::WebCanvas
* canvas
,
423 float webkit_scale_factor
,
424 const PageSizeMargins
& page_layout
,
425 const base::DictionaryValue
& header_footer_info
,
426 const PrintMsg_Print_Params
& params
) {
428 // TODO(sgurun) android_webview hack
429 SkAutoCanvasRestore
auto_restore(canvas
, true);
430 canvas
->scale(1 / webkit_scale_factor
, 1 / webkit_scale_factor
);
432 blink::WebSize
page_size(page_layout
.margin_left
+ page_layout
.margin_right
+
433 page_layout
.content_width
,
434 page_layout
.margin_top
+ page_layout
.margin_bottom
+
435 page_layout
.content_height
);
437 blink::WebView
* web_view
= blink::WebView::create(NULL
);
438 web_view
->settings()->setJavaScriptEnabled(true);
439 blink::WebFrame
* frame
= blink::WebLocalFrame::create(NULL
)
440 web_view
->setMainFrame(web_frame
);
442 base::StringValue
html(
443 ResourceBundle::GetSharedInstance().GetLocalizedString(
444 IDR_PRINT_PREVIEW_PAGE
));
445 // Load page with script to avoid async operations.
446 ExecuteScript(frame
, kPageLoadScriptFormat
, html
);
448 scoped_ptr
<base::DictionaryValue
> options(header_footer_info
.DeepCopy());
449 options
->SetDouble("width", page_size
.width
);
450 options
->SetDouble("height", page_size
.height
);
451 options
->SetDouble("topMargin", page_layout
.margin_top
);
452 options
->SetDouble("bottomMargin", page_layout
.margin_bottom
);
453 options
->SetString("pageNumber",
454 base::StringPrintf("%d/%d", page_number
, total_pages
));
456 ExecuteScript(frame
, kPageSetupScriptFormat
, *options
);
458 blink::WebPrintParams
webkit_params(page_size
);
459 webkit_params
.printerDPI
= GetDPI(¶ms
);
461 frame
->printBegin(webkit_params
, WebKit::WebNode(), NULL
);
462 frame
->printPage(0, canvas
);
470 // static - Not anonymous so that platform implementations can use it.
471 float PrintWebViewHelper::RenderPageContent(blink::WebFrame
* frame
,
473 const gfx::Rect
& canvas_area
,
474 const gfx::Rect
& content_area
,
476 blink::WebCanvas
* canvas
) {
477 SkAutoCanvasRestore
auto_restore(canvas
, true);
478 if (content_area
!= canvas_area
) {
479 canvas
->translate((content_area
.x() - canvas_area
.x()) / scale_factor
,
480 (content_area
.y() - canvas_area
.y()) / scale_factor
);
482 SkRect::MakeXYWH(content_area
.origin().x() / scale_factor
,
483 content_area
.origin().y() / scale_factor
,
484 content_area
.size().width() / scale_factor
,
485 content_area
.size().height() / scale_factor
));
486 SkIRect clip_int_rect
;
487 clip_rect
.roundOut(&clip_int_rect
);
488 SkRegion
clip_region(clip_int_rect
);
489 canvas
->setClipRegion(clip_region
);
491 return frame
->printPage(page_number
, canvas
);
494 // Class that calls the Begin and End print functions on the frame and changes
495 // the size of the view temporarily to support full page printing..
496 class PrepareFrameAndViewForPrint
: public blink::WebViewClient
,
497 public blink::WebFrameClient
{
499 PrepareFrameAndViewForPrint(const PrintMsg_Print_Params
& params
,
500 blink::WebLocalFrame
* frame
,
501 const blink::WebNode
& node
,
502 bool ignore_css_margins
);
503 virtual ~PrepareFrameAndViewForPrint();
505 // Optional. Replaces |frame_| with selection if needed. Will call |on_ready|
507 void CopySelectionIfNeeded(const WebPreferences
& preferences
,
508 const base::Closure
& on_ready
);
510 // Prepares frame for printing.
511 void StartPrinting();
513 blink::WebLocalFrame
* frame() {
514 return frame_
.GetFrame();
517 const blink::WebNode
& node() const {
518 return node_to_print_
;
521 int GetExpectedPageCount() const {
522 return expected_pages_count_
;
525 gfx::Size
GetPrintCanvasSize() const;
527 void FinishPrinting();
529 bool IsLoadingSelection() {
530 // It's not selection if not |owns_web_view_|.
531 return owns_web_view_
&& frame() && frame()->isLoading();
534 // TODO(ojan): Remove this override and have this class use a non-null
536 // blink::WebViewClient override:
537 virtual bool allowsBrokenNullLayerTreeView() const;
540 // blink::WebViewClient override:
541 virtual void didStopLoading();
543 // blink::WebFrameClient override:
544 // TODO(alexmos): Remove once Blink is updated to use sandbox flags.
545 virtual blink::WebFrame
* createChildFrame(blink::WebLocalFrame
* parent
,
546 const blink::WebString
& name
);
547 virtual blink::WebFrame
* createChildFrame(
548 blink::WebLocalFrame
* parent
,
549 const blink::WebString
& name
,
550 blink::WebSandboxFlags sandboxFlags
);
551 virtual void frameDetached(blink::WebFrame
* frame
);
555 void ResizeForPrinting();
557 void CopySelection(const WebPreferences
& preferences
);
559 FrameReference frame_
;
560 blink::WebNode node_to_print_
;
562 blink::WebPrintParams web_print_params_
;
563 gfx::Size prev_view_size_
;
564 gfx::Size prev_scroll_offset_
;
565 int expected_pages_count_
;
566 base::Closure on_ready_
;
567 bool should_print_backgrounds_
;
568 bool should_print_selection_only_
;
569 bool is_printing_started_
;
571 base::WeakPtrFactory
<PrepareFrameAndViewForPrint
> weak_ptr_factory_
;
573 DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint
);
576 PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
577 const PrintMsg_Print_Params
& params
,
578 blink::WebLocalFrame
* frame
,
579 const blink::WebNode
& node
,
580 bool ignore_css_margins
)
582 node_to_print_(node
),
583 owns_web_view_(false),
584 expected_pages_count_(0),
585 should_print_backgrounds_(params
.should_print_backgrounds
),
586 should_print_selection_only_(params
.selection_only
),
587 is_printing_started_(false),
588 weak_ptr_factory_(this) {
589 PrintMsg_Print_Params print_params
= params
;
590 if (!should_print_selection_only_
||
591 !PrintingNodeOrPdfFrame(frame
, node_to_print_
)) {
592 bool fit_to_page
= ignore_css_margins
&&
593 print_params
.print_scaling_option
==
594 blink::WebPrintScalingOptionFitToPrintableArea
;
595 ComputeWebKitPrintParamsInDesiredDpi(params
, &web_print_params_
);
596 frame
->printBegin(web_print_params_
, node_to_print_
);
597 print_params
= CalculatePrintParamsForCss(frame
, 0, print_params
,
598 ignore_css_margins
, fit_to_page
,
602 ComputeWebKitPrintParamsInDesiredDpi(print_params
, &web_print_params_
);
605 PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
609 void PrepareFrameAndViewForPrint::ResizeForPrinting() {
610 // Layout page according to printer page size. Since WebKit shrinks the
611 // size of the page automatically (from 125% to 200%) we trick it to
612 // think the page is 125% larger so the size of the page is correct for
613 // minimum (default) scaling.
614 // This is important for sites that try to fill the page.
615 gfx::Size
print_layout_size(web_print_params_
.printContentArea
.width
,
616 web_print_params_
.printContentArea
.height
);
617 print_layout_size
.set_height(
618 static_cast<int>(static_cast<double>(print_layout_size
.height()) * 1.25));
622 blink::WebView
* web_view
= frame_
.view();
623 // Backup size and offset.
624 if (blink::WebFrame
* web_frame
= web_view
->mainFrame())
625 prev_scroll_offset_
= web_frame
->scrollOffset();
626 prev_view_size_
= web_view
->size();
628 web_view
->resize(print_layout_size
);
632 void PrepareFrameAndViewForPrint::StartPrinting() {
634 blink::WebView
* web_view
= frame_
.view();
635 web_view
->settings()->setShouldPrintBackgrounds(should_print_backgrounds_
);
636 expected_pages_count_
=
637 frame()->printBegin(web_print_params_
, node_to_print_
);
638 is_printing_started_
= true;
641 void PrepareFrameAndViewForPrint::CopySelectionIfNeeded(
642 const WebPreferences
& preferences
,
643 const base::Closure
& on_ready
) {
644 on_ready_
= on_ready
;
645 if (should_print_selection_only_
)
646 CopySelection(preferences
);
651 void PrepareFrameAndViewForPrint::CopySelection(
652 const WebPreferences
& preferences
) {
654 std::string url_str
= "data:text/html;charset=utf-8,";
656 net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false));
658 // Create a new WebView with the same settings as the current display one.
659 // Except that we disable javascript (don't want any active content running
661 WebPreferences prefs
= preferences
;
662 prefs
.javascript_enabled
= false;
663 prefs
.java_enabled
= false;
665 blink::WebView
* web_view
= blink::WebView::create(this);
666 owns_web_view_
= true;
667 content::RenderView::ApplyWebPreferences(prefs
, web_view
);
668 web_view
->setMainFrame(blink::WebLocalFrame::create(this));
669 frame_
.Reset(web_view
->mainFrame()->toWebLocalFrame());
670 node_to_print_
.reset();
672 // When loading is done this will call didStopLoading() and that will do the
674 frame()->loadRequest(blink::WebURLRequest(GURL(url_str
)));
677 bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
681 void PrepareFrameAndViewForPrint::didStopLoading() {
682 DCHECK(!on_ready_
.is_null());
683 // Don't call callback here, because it can delete |this| and WebView that is
684 // called didStopLoading.
685 base::MessageLoop::current()->PostTask(
687 base::Bind(&PrepareFrameAndViewForPrint::CallOnReady
,
688 weak_ptr_factory_
.GetWeakPtr()));
691 // TODO(alexmos): Remove once Blink is updated to use sandbox flags.
692 blink::WebFrame
* PrepareFrameAndViewForPrint::createChildFrame(
693 blink::WebLocalFrame
* parent
,
694 const blink::WebString
& name
) {
695 return createChildFrame(parent
, name
, blink::WebSandboxFlags::None
);
698 blink::WebFrame
* PrepareFrameAndViewForPrint::createChildFrame(
699 blink::WebLocalFrame
* parent
,
700 const blink::WebString
& name
,
701 blink::WebSandboxFlags sandboxFlags
) {
702 blink::WebFrame
* frame
= blink::WebLocalFrame::create(this);
703 parent
->appendChild(frame
);
707 void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame
* frame
) {
709 frame
->parent()->removeChild(frame
);
713 void PrepareFrameAndViewForPrint::CallOnReady() {
714 return on_ready_
.Run(); // Can delete |this|.
717 gfx::Size
PrepareFrameAndViewForPrint::GetPrintCanvasSize() const {
718 DCHECK(is_printing_started_
);
719 return gfx::Size(web_print_params_
.printContentArea
.width
,
720 web_print_params_
.printContentArea
.height
);
723 void PrepareFrameAndViewForPrint::RestoreSize() {
725 blink::WebView
* web_view
= frame_
.GetFrame()->view();
726 web_view
->resize(prev_view_size_
);
727 if (blink::WebFrame
* web_frame
= web_view
->mainFrame())
728 web_frame
->setScrollOffset(prev_scroll_offset_
);
732 void PrepareFrameAndViewForPrint::FinishPrinting() {
733 blink::WebLocalFrame
* frame
= frame_
.GetFrame();
735 blink::WebView
* web_view
= frame
->view();
736 if (is_printing_started_
) {
737 is_printing_started_
= false;
739 if (!owns_web_view_
) {
740 web_view
->settings()->setShouldPrintBackgrounds(false);
744 if (owns_web_view_
) {
745 DCHECK(!frame
->isLoading());
746 owns_web_view_
= false;
754 PrintWebViewHelper::PrintWebViewHelper(content::RenderView
* render_view
)
755 : content::RenderViewObserver(render_view
),
756 content::RenderViewObserverTracker
<PrintWebViewHelper
>(render_view
),
757 reset_prep_frame_view_(false),
758 is_preview_enabled_(IsPrintPreviewEnabled()),
759 is_scripted_print_throttling_disabled_(IsPrintThrottlingDisabled()),
760 is_print_ready_metafile_sent_(false),
761 ignore_css_margins_(false),
762 user_cancelled_scripted_print_count_(0),
763 is_scripted_printing_blocked_(false),
764 notify_browser_of_print_failure_(true),
765 print_for_preview_(false),
766 print_node_in_progress_(false),
768 is_scripted_preview_delayed_(false),
769 weak_ptr_factory_(this) {
770 // TODO(sgurun) enable window.print() for webview crbug.com/322303
771 SetScriptedPrintBlocked(true);
774 PrintWebViewHelper::~PrintWebViewHelper() {}
776 bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
777 blink::WebFrame
* frame
, bool user_initiated
) {
778 #if defined(OS_ANDROID)
780 #endif // defined(OS_ANDROID)
781 if (is_scripted_printing_blocked_
)
783 // If preview is enabled, then the print dialog is tab modal, and the user
784 // can always close the tab on a mis-behaving page (the system print dialog
785 // is app modal). If the print was initiated through user action, don't
786 // throttle. Or, if the command line flag to skip throttling has been set.
787 if (!is_scripted_print_throttling_disabled_
&&
788 !is_preview_enabled_
&&
790 return !IsScriptInitiatedPrintTooFrequent(frame
);
794 void PrintWebViewHelper::DidStartLoading() {
798 void PrintWebViewHelper::DidStopLoading() {
800 ShowScriptedPrintPreview();
803 // Prints |frame| which called window.print().
804 void PrintWebViewHelper::PrintPage(blink::WebLocalFrame
* frame
,
805 bool user_initiated
) {
808 #if !defined(OS_ANDROID)
809 // TODO(sgurun) android_webview hack
810 // Allow Prerendering to cancel this print request if necessary.
811 if (prerender::PrerenderHelper::IsPrerendering(render_view())) {
812 Send(new ChromeViewHostMsg_CancelPrerenderForPrinting(routing_id()));
815 #endif // !defined(OS_ANDROID)
817 if (!IsScriptInitiatedPrintAllowed(frame
, user_initiated
))
819 IncrementScriptedPrintCount();
821 if (is_preview_enabled_
) {
822 print_preview_context_
.InitWithFrame(frame
);
823 RequestPrintPreview(PRINT_PREVIEW_SCRIPTED
);
825 Print(frame
, blink::WebNode());
829 bool PrintWebViewHelper::OnMessageReceived(const IPC::Message
& message
) {
831 IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper
, message
)
832 IPC_MESSAGE_HANDLER(PrintMsg_PrintPages
, OnPrintPages
)
833 IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog
, OnPrintForSystemDialog
)
834 IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview
, OnInitiatePrintPreview
)
835 IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview
, OnPrintPreview
)
836 IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview
, OnPrintForPrintPreview
)
837 IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone
, OnPrintingDone
)
838 IPC_MESSAGE_HANDLER(PrintMsg_ResetScriptedPrintCount
,
839 ResetScriptedPrintCount
)
840 IPC_MESSAGE_HANDLER(PrintMsg_SetScriptedPrintingBlocked
,
841 SetScriptedPrintBlocked
)
842 IPC_MESSAGE_UNHANDLED(handled
= false)
843 IPC_END_MESSAGE_MAP()
847 void PrintWebViewHelper::OnPrintForPrintPreview(
848 const base::DictionaryValue
& job_settings
) {
849 DCHECK(is_preview_enabled_
);
850 // If still not finished with earlier print request simply ignore.
851 if (prep_frame_view_
)
854 if (!render_view()->GetWebView())
856 blink::WebFrame
* main_frame
= render_view()->GetWebView()->mainFrame();
860 blink::WebDocument document
= main_frame
->document();
861 // <object> with id="pdf-viewer" is created in
862 // chrome/browser/resources/print_preview/print_preview.js
863 blink::WebElement pdf_element
= document
.getElementById("pdf-viewer");
864 if (pdf_element
.isNull()) {
869 // Set |print_for_preview_| flag and autoreset it to back to original
871 base::AutoReset
<bool> set_printing_flag(&print_for_preview_
, true);
873 blink::WebLocalFrame
* pdf_frame
= pdf_element
.document().frame();
874 if (!UpdatePrintSettings(pdf_frame
, pdf_element
, job_settings
)) {
875 LOG(ERROR
) << "UpdatePrintSettings failed";
876 DidFinishPrinting(FAIL_PRINT
);
880 // Print page onto entire page not just printable area. Preview PDF already
881 // has content in correct position taking into account page size and printable
883 // TODO(vitalybuka) : Make this consistent on all platform. This change
884 // affects Windows only. On Linux and OSX RenderPagesForPrint does not use
885 // printable_area. Also we can't change printable_area deeper inside
886 // RenderPagesForPrint for Windows, because it's used also by native
887 // printing and it expects real printable_area value.
888 // See http://crbug.com/123408
889 PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
890 print_params
.printable_area
= gfx::Rect(print_params
.page_size
);
892 // Render Pages for printing.
893 if (!RenderPagesForPrint(pdf_frame
, pdf_element
)) {
894 LOG(ERROR
) << "RenderPagesForPrint failed";
895 DidFinishPrinting(FAIL_PRINT
);
899 bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame
** frame
) {
901 blink::WebView
* webView
= render_view()->GetWebView();
906 // If the user has selected text in the currently focused frame we print
907 // only that frame (this makes print selection work for multiple frames).
908 blink::WebLocalFrame
* focusedFrame
=
909 webView
->focusedFrame()->toWebLocalFrame();
910 *frame
= focusedFrame
->hasSelection()
912 : webView
->mainFrame()->toWebLocalFrame();
916 void PrintWebViewHelper::OnPrintPages() {
917 blink::WebLocalFrame
* frame
;
918 if (GetPrintFrame(&frame
))
919 Print(frame
, blink::WebNode());
922 void PrintWebViewHelper::OnPrintForSystemDialog() {
923 blink::WebLocalFrame
* frame
= print_preview_context_
.source_frame();
929 Print(frame
, print_preview_context_
.source_node());
932 void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
933 const PageSizeMargins
& page_layout_in_points
,
934 gfx::Size
* page_size
,
935 gfx::Rect
* content_area
) {
936 *page_size
= gfx::Size(
937 page_layout_in_points
.content_width
+
938 page_layout_in_points
.margin_right
+
939 page_layout_in_points
.margin_left
,
940 page_layout_in_points
.content_height
+
941 page_layout_in_points
.margin_top
+
942 page_layout_in_points
.margin_bottom
);
943 *content_area
= gfx::Rect(page_layout_in_points
.margin_left
,
944 page_layout_in_points
.margin_top
,
945 page_layout_in_points
.content_width
,
946 page_layout_in_points
.content_height
);
949 void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
950 const base::DictionaryValue
& settings
) {
951 int margins_type
= 0;
952 if (!settings
.GetInteger(kSettingMarginsType
, &margins_type
))
953 margins_type
= DEFAULT_MARGINS
;
954 ignore_css_margins_
= (margins_type
!= DEFAULT_MARGINS
);
957 bool PrintWebViewHelper::IsPrintToPdfRequested(
958 const base::DictionaryValue
& job_settings
) {
959 bool print_to_pdf
= false;
960 if (!job_settings
.GetBoolean(kSettingPrintToPDF
, &print_to_pdf
))
965 blink::WebPrintScalingOption
PrintWebViewHelper::GetPrintScalingOption(
966 bool source_is_html
, const base::DictionaryValue
& job_settings
,
967 const PrintMsg_Print_Params
& params
) {
968 DCHECK(!print_for_preview_
);
970 if (params
.print_to_pdf
)
971 return blink::WebPrintScalingOptionSourceSize
;
973 if (!source_is_html
) {
974 if (!FitToPageEnabled(job_settings
))
975 return blink::WebPrintScalingOptionNone
;
977 bool no_plugin_scaling
=
978 print_preview_context_
.source_frame()->isPrintScalingDisabledForPlugin(
979 print_preview_context_
.source_node());
981 if (params
.is_first_request
&& no_plugin_scaling
)
982 return blink::WebPrintScalingOptionNone
;
984 return blink::WebPrintScalingOptionFitToPrintableArea
;
987 void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue
& settings
) {
988 DCHECK(is_preview_enabled_
);
989 print_preview_context_
.OnPrintPreview();
991 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
992 PREVIEW_EVENT_REQUESTED
, PREVIEW_EVENT_MAX
);
994 if (!UpdatePrintSettings(print_preview_context_
.source_frame(),
995 print_preview_context_
.source_node(), settings
)) {
996 if (print_preview_context_
.last_error() != PREVIEW_ERROR_BAD_SETTING
) {
997 Send(new PrintHostMsg_PrintPreviewInvalidPrinterSettings(
998 routing_id(), print_pages_params_
->params
.document_cookie
));
999 notify_browser_of_print_failure_
= false; // Already sent.
1001 DidFinishPrinting(FAIL_PREVIEW
);
1005 // If we are previewing a pdf and the print scaling is disabled, send a
1006 // message to browser.
1007 if (print_pages_params_
->params
.is_first_request
&&
1008 !print_preview_context_
.IsModifiable() &&
1009 print_preview_context_
.source_frame()->isPrintScalingDisabledForPlugin(
1010 print_preview_context_
.source_node())) {
1011 Send(new PrintHostMsg_PrintPreviewScalingDisabled(routing_id()));
1014 is_print_ready_metafile_sent_
= false;
1016 // PDF printer device supports alpha blending.
1017 print_pages_params_
->params
.supports_alpha_blend
= true;
1019 bool generate_draft_pages
= false;
1020 if (!settings
.GetBoolean(kSettingGenerateDraftData
,
1021 &generate_draft_pages
)) {
1024 print_preview_context_
.set_generate_draft_pages(generate_draft_pages
);
1026 PrepareFrameForPreviewDocument();
1029 void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
1030 reset_prep_frame_view_
= false;
1032 if (!print_pages_params_
|| CheckForCancel()) {
1033 DidFinishPrinting(FAIL_PREVIEW
);
1037 // Don't reset loading frame or WebKit will fail assert. Just retry when
1038 // current selection is loaded.
1039 if (prep_frame_view_
&& prep_frame_view_
->IsLoadingSelection()) {
1040 reset_prep_frame_view_
= true;
1044 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1045 prep_frame_view_
.reset(
1046 new PrepareFrameAndViewForPrint(print_params
,
1047 print_preview_context_
.source_frame(),
1048 print_preview_context_
.source_node(),
1049 ignore_css_margins_
));
1050 prep_frame_view_
->CopySelectionIfNeeded(
1051 render_view()->GetWebkitPreferences(),
1052 base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument
,
1053 base::Unretained(this)));
1056 void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
1057 if (reset_prep_frame_view_
) {
1058 PrepareFrameForPreviewDocument();
1061 DidFinishPrinting(CreatePreviewDocument() ? OK
: FAIL_PREVIEW
);
1064 bool PrintWebViewHelper::CreatePreviewDocument() {
1065 if (!print_pages_params_
|| CheckForCancel())
1068 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
1069 PREVIEW_EVENT_CREATE_DOCUMENT
, PREVIEW_EVENT_MAX
);
1071 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1072 const std::vector
<int>& pages
= print_pages_params_
->pages
;
1074 if (!print_preview_context_
.CreatePreviewDocument(prep_frame_view_
.release(),
1079 PageSizeMargins default_page_layout
;
1080 ComputePageLayoutInPointsForCss(print_preview_context_
.prepared_frame(), 0,
1081 print_params
, ignore_css_margins_
, NULL
,
1082 &default_page_layout
);
1084 bool has_page_size_style
= PrintingFrameHasPageSizeStyle(
1085 print_preview_context_
.prepared_frame(),
1086 print_preview_context_
.total_page_count());
1087 int dpi
= GetDPI(&print_params
);
1089 gfx::Rect
printable_area_in_points(
1090 ConvertUnit(print_params
.printable_area
.x(), dpi
, kPointsPerInch
),
1091 ConvertUnit(print_params
.printable_area
.y(), dpi
, kPointsPerInch
),
1092 ConvertUnit(print_params
.printable_area
.width(), dpi
, kPointsPerInch
),
1093 ConvertUnit(print_params
.printable_area
.height(), dpi
, kPointsPerInch
));
1095 // Margins: Send default page layout to browser process.
1096 Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
1097 default_page_layout
,
1098 printable_area_in_points
,
1099 has_page_size_style
));
1101 PrintHostMsg_DidGetPreviewPageCount_Params params
;
1102 params
.page_count
= print_preview_context_
.total_page_count();
1103 params
.is_modifiable
= print_preview_context_
.IsModifiable();
1104 params
.document_cookie
= print_params
.document_cookie
;
1105 params
.preview_request_id
= print_params
.preview_request_id
;
1106 params
.clear_preview_data
= print_preview_context_
.generate_draft_pages();
1107 Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params
));
1108 if (CheckForCancel())
1111 while (!print_preview_context_
.IsFinalPageRendered()) {
1112 int page_number
= print_preview_context_
.GetNextPageNumber();
1113 DCHECK_GE(page_number
, 0);
1114 if (!RenderPreviewPage(page_number
, print_params
))
1117 if (CheckForCancel())
1120 // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of
1121 // print_preview_context_.AllPagesRendered()) before calling
1122 // FinalizePrintReadyDocument() when printing a PDF because the plugin
1123 // code does not generate output until we call FinishPrinting(). We do not
1124 // generate draft pages for PDFs, so IsFinalPageRendered() and
1125 // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of
1127 if (print_preview_context_
.IsFinalPageRendered())
1128 print_preview_context_
.AllPagesRendered();
1130 if (print_preview_context_
.IsLastPageOfPrintReadyMetafile()) {
1131 DCHECK(print_preview_context_
.IsModifiable() ||
1132 print_preview_context_
.IsFinalPageRendered());
1133 if (!FinalizePrintReadyDocument())
1137 print_preview_context_
.Finished();
1141 bool PrintWebViewHelper::FinalizePrintReadyDocument() {
1142 DCHECK(!is_print_ready_metafile_sent_
);
1143 print_preview_context_
.FinalizePrintReadyDocument();
1145 // Get the size of the resulting metafile.
1146 PdfMetafileSkia
* metafile
= print_preview_context_
.metafile();
1147 uint32 buf_size
= metafile
->GetDataSize();
1148 DCHECK_GT(buf_size
, 0u);
1150 PrintHostMsg_DidPreviewDocument_Params preview_params
;
1151 preview_params
.reuse_existing_data
= false;
1152 preview_params
.data_size
= buf_size
;
1153 preview_params
.document_cookie
= print_pages_params_
->params
.document_cookie
;
1154 preview_params
.expected_pages_count
=
1155 print_preview_context_
.total_page_count();
1156 preview_params
.modifiable
= print_preview_context_
.IsModifiable();
1157 preview_params
.preview_request_id
=
1158 print_pages_params_
->params
.preview_request_id
;
1160 // Ask the browser to create the shared memory for us.
1161 if (!CopyMetafileDataToSharedMem(metafile
,
1162 &(preview_params
.metafile_data_handle
))) {
1163 LOG(ERROR
) << "CopyMetafileDataToSharedMem failed";
1164 print_preview_context_
.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED
);
1167 is_print_ready_metafile_sent_
= true;
1169 Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params
));
1173 void PrintWebViewHelper::OnPrintingDone(bool success
) {
1174 notify_browser_of_print_failure_
= false;
1176 LOG(ERROR
) << "Failure in OnPrintingDone";
1177 DidFinishPrinting(success
? OK
: FAIL_PRINT
);
1180 void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked
) {
1181 is_scripted_printing_blocked_
= blocked
;
1184 void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only
) {
1185 DCHECK(is_preview_enabled_
);
1186 blink::WebLocalFrame
* frame
= NULL
;
1187 GetPrintFrame(&frame
);
1189 print_preview_context_
.InitWithFrame(frame
);
1190 RequestPrintPreview(selection_only
?
1191 PRINT_PREVIEW_USER_INITIATED_SELECTION
:
1192 PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME
);
1195 bool PrintWebViewHelper::IsPrintingEnabled() {
1196 bool result
= false;
1197 Send(new PrintHostMsg_IsPrintingEnabled(routing_id(), &result
));
1201 void PrintWebViewHelper::PrintNode(const blink::WebNode
& node
) {
1202 if (node
.isNull() || !node
.document().frame()) {
1203 // This can occur when the context menu refers to an invalid WebNode.
1204 // See http://crbug.com/100890#c17 for a repro case.
1208 if (print_node_in_progress_
) {
1209 // This can happen as a result of processing sync messages when printing
1210 // from ppapi plugins. It's a rare case, so its OK to just fail here.
1211 // See http://crbug.com/159165.
1215 print_node_in_progress_
= true;
1217 // Make a copy of the node, in case RenderView::OnContextMenuClosed resets
1218 // its |context_menu_node_|.
1219 if (is_preview_enabled_
) {
1220 print_preview_context_
.InitWithNode(node
);
1221 RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE
);
1223 blink::WebNode
duplicate_node(node
);
1224 Print(duplicate_node
.document().frame(), duplicate_node
);
1227 print_node_in_progress_
= false;
1230 void PrintWebViewHelper::Print(blink::WebLocalFrame
* frame
,
1231 const blink::WebNode
& node
) {
1232 // If still not finished with earlier print request simply ignore.
1233 if (prep_frame_view_
)
1236 FrameReference
frame_ref(frame
);
1238 int expected_page_count
= 0;
1239 if (!CalculateNumberOfPages(frame
, node
, &expected_page_count
)) {
1240 DidFinishPrinting(FAIL_PRINT_INIT
);
1241 return; // Failed to init print page settings.
1244 // Some full screen plugins can say they don't want to print.
1245 if (!expected_page_count
) {
1246 DidFinishPrinting(FAIL_PRINT
);
1250 #if !defined(OS_ANDROID)
1251 // TODO(sgurun) android_webview hack
1252 // Ask the browser to show UI to retrieve the final print settings.
1253 if (!GetPrintSettingsFromUser(frame_ref
.GetFrame(), node
,
1254 expected_page_count
)) {
1255 DidFinishPrinting(OK
); // Release resources and fail silently.
1258 #endif // !defined(OS_ANDROID)
1260 // Render Pages for printing.
1261 if (!RenderPagesForPrint(frame_ref
.GetFrame(), node
)) {
1262 LOG(ERROR
) << "RenderPagesForPrint failed";
1263 DidFinishPrinting(FAIL_PRINT
);
1265 ResetScriptedPrintCount();
1268 void PrintWebViewHelper::DidFinishPrinting(PrintingResult result
) {
1273 case FAIL_PRINT_INIT
:
1274 DCHECK(!notify_browser_of_print_failure_
);
1278 if (notify_browser_of_print_failure_
&& print_pages_params_
.get()) {
1279 int cookie
= print_pages_params_
->params
.document_cookie
;
1280 Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie
));
1285 DCHECK(is_preview_enabled_
);
1286 int cookie
= print_pages_params_
.get() ?
1287 print_pages_params_
->params
.document_cookie
: 0;
1288 if (notify_browser_of_print_failure_
) {
1289 LOG(ERROR
) << "CreatePreviewDocument failed";
1290 Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie
));
1292 Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie
));
1294 print_preview_context_
.Failed(notify_browser_of_print_failure_
);
1298 prep_frame_view_
.reset();
1299 print_pages_params_
.reset();
1300 notify_browser_of_print_failure_
= true;
1303 void PrintWebViewHelper::OnFramePreparedForPrintPages() {
1305 FinishFramePrinting();
1308 void PrintWebViewHelper::PrintPages() {
1309 if (!prep_frame_view_
) // Printing is already canceled or failed.
1311 prep_frame_view_
->StartPrinting();
1313 int page_count
= prep_frame_view_
->GetExpectedPageCount();
1315 LOG(ERROR
) << "Can't print 0 pages.";
1316 return DidFinishPrinting(FAIL_PRINT
);
1319 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1320 const PrintMsg_Print_Params
& print_params
= params
.params
;
1322 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
1323 // TODO(vitalybuka): should be page_count or valid pages from params.pages.
1324 // See http://crbug.com/161576
1325 Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
1326 print_params
.document_cookie
,
1328 #endif // !defined(OS_CHROMEOS)
1330 if (print_params
.preview_ui_id
< 0) {
1331 // Printing for system dialog.
1332 int printed_count
= params
.pages
.empty() ? page_count
: params
.pages
.size();
1333 #if !defined(OS_CHROMEOS)
1334 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count
);
1336 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1338 #endif // !defined(OS_CHROMEOS)
1342 if (!PrintPagesNative(prep_frame_view_
->frame(), page_count
,
1343 prep_frame_view_
->GetPrintCanvasSize())) {
1344 LOG(ERROR
) << "Printing failed.";
1345 return DidFinishPrinting(FAIL_PRINT
);
1349 void PrintWebViewHelper::FinishFramePrinting() {
1350 prep_frame_view_
.reset();
1353 #if defined(OS_MACOSX) || defined(OS_WIN)
1354 bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame
* frame
,
1356 const gfx::Size
& canvas_size
) {
1357 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1358 const PrintMsg_Print_Params
& print_params
= params
.params
;
1360 PrintMsg_PrintPage_Params page_params
;
1361 page_params
.params
= print_params
;
1362 if (params
.pages
.empty()) {
1363 for (int i
= 0; i
< page_count
; ++i
) {
1364 page_params
.page_number
= i
;
1365 PrintPageInternal(page_params
, canvas_size
, frame
);
1368 for (size_t i
= 0; i
< params
.pages
.size(); ++i
) {
1369 if (params
.pages
[i
] >= page_count
)
1371 page_params
.page_number
= params
.pages
[i
];
1372 PrintPageInternal(page_params
, canvas_size
, frame
);
1378 #endif // OS_MACOSX || OS_WIN
1380 // static - Not anonymous so that platform implementations can use it.
1381 void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
1382 blink::WebFrame
* frame
,
1384 const PrintMsg_Print_Params
& page_params
,
1385 bool ignore_css_margins
,
1386 double* scale_factor
,
1387 PageSizeMargins
* page_layout_in_points
) {
1388 PrintMsg_Print_Params params
= CalculatePrintParamsForCss(
1389 frame
, page_index
, page_params
, ignore_css_margins
,
1390 page_params
.print_scaling_option
==
1391 blink::WebPrintScalingOptionFitToPrintableArea
,
1393 CalculatePageLayoutFromPrintParams(params
, page_layout_in_points
);
1396 bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size
) {
1397 PrintMsg_PrintPages_Params settings
;
1398 Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
1400 // Check if the printer returned any settings, if the settings is empty, we
1401 // can safely assume there are no printer drivers configured. So we safely
1404 if (!PrintMsg_Print_Params_IsValid(settings
.params
))
1408 (settings
.params
.dpi
< kMinDpi
|| settings
.params
.document_cookie
== 0)) {
1409 // Invalid print page settings.
1414 // Reset to default values.
1415 ignore_css_margins_
= false;
1416 settings
.pages
.clear();
1418 settings
.params
.print_scaling_option
=
1419 blink::WebPrintScalingOptionSourceSize
;
1420 if (fit_to_paper_size
) {
1421 settings
.params
.print_scaling_option
=
1422 blink::WebPrintScalingOptionFitToPrintableArea
;
1425 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1429 bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame
* frame
,
1430 const blink::WebNode
& node
,
1431 int* number_of_pages
) {
1433 bool fit_to_paper_size
= !(PrintingNodeOrPdfFrame(frame
, node
));
1434 if (!InitPrintSettings(fit_to_paper_size
)) {
1435 notify_browser_of_print_failure_
= false;
1436 #if !defined(OS_ANDROID)
1437 // TODO(sgurun) android_webview hack
1438 render_view()->RunModalAlertDialog(
1440 l10n_util::GetStringUTF16(IDS_PRINT_INVALID_PRINTER_SETTINGS
));
1441 #endif // !defined(OS_ANDROID)
1445 const PrintMsg_Print_Params
& params
= print_pages_params_
->params
;
1446 PrepareFrameAndViewForPrint
prepare(params
, frame
, node
, ignore_css_margins_
);
1447 prepare
.StartPrinting();
1449 Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
1450 params
.document_cookie
));
1451 *number_of_pages
= prepare
.GetExpectedPageCount();
1455 bool PrintWebViewHelper::UpdatePrintSettings(
1456 blink::WebLocalFrame
* frame
,
1457 const blink::WebNode
& node
,
1458 const base::DictionaryValue
& passed_job_settings
) {
1459 DCHECK(is_preview_enabled_
);
1460 const base::DictionaryValue
* job_settings
= &passed_job_settings
;
1461 base::DictionaryValue modified_job_settings
;
1462 if (job_settings
->empty()) {
1463 if (!print_for_preview_
)
1464 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1468 bool source_is_html
= true;
1469 if (print_for_preview_
) {
1470 if (!job_settings
->GetBoolean(kSettingPreviewModifiable
, &source_is_html
)) {
1474 source_is_html
= !PrintingNodeOrPdfFrame(frame
, node
);
1477 if (print_for_preview_
|| !source_is_html
) {
1478 modified_job_settings
.MergeDictionary(job_settings
);
1479 modified_job_settings
.SetBoolean(kSettingHeaderFooterEnabled
, false);
1480 modified_job_settings
.SetInteger(kSettingMarginsType
, NO_MARGINS
);
1481 job_settings
= &modified_job_settings
;
1484 // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when
1486 int cookie
= print_pages_params_
.get() ?
1487 print_pages_params_
->params
.document_cookie
: 0;
1488 PrintMsg_PrintPages_Params settings
;
1489 Send(new PrintHostMsg_UpdatePrintSettings(routing_id(), cookie
, *job_settings
,
1491 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1493 if (!PrintMsg_Print_Params_IsValid(settings
.params
)) {
1494 if (!print_for_preview_
) {
1495 print_preview_context_
.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS
);
1497 #if !defined(OS_ANDROID)
1498 // TODO(sgurun) android_webview hack
1499 // PrintForPrintPreview
1500 blink::WebFrame
* print_frame
= NULL
;
1501 // This may not be the right frame, but the alert will be modal,
1502 // therefore it works well enough.
1503 GetPrintFrame(&print_frame
);
1505 render_view()->RunModalAlertDialog(
1507 l10n_util::GetStringUTF16(
1508 IDS_PRINT_INVALID_PRINTER_SETTINGS
));
1510 #endif // !defined(OS_ANDROID)
1515 if (settings
.params
.dpi
< kMinDpi
|| !settings
.params
.document_cookie
) {
1516 print_preview_context_
.set_error(PREVIEW_ERROR_UPDATING_PRINT_SETTINGS
);
1520 if (!job_settings
->GetInteger(kPreviewUIID
, &settings
.params
.preview_ui_id
)) {
1522 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1526 if (!print_for_preview_
) {
1527 // Validate expected print preview settings.
1528 if (!job_settings
->GetInteger(kPreviewRequestID
,
1529 &settings
.params
.preview_request_id
) ||
1530 !job_settings
->GetBoolean(kIsFirstRequest
,
1531 &settings
.params
.is_first_request
)) {
1533 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1537 settings
.params
.print_to_pdf
= IsPrintToPdfRequested(*job_settings
);
1538 UpdateFrameMarginsCssInfo(*job_settings
);
1539 settings
.params
.print_scaling_option
= GetPrintScalingOption(
1540 source_is_html
, *job_settings
, settings
.params
);
1542 // Header/Footer: Set |header_footer_info_|.
1543 if (settings
.params
.display_header_footer
) {
1544 header_footer_info_
.reset(new base::DictionaryValue());
1545 header_footer_info_
->SetDouble(kSettingHeaderFooterDate
,
1546 base::Time::Now().ToJsTime());
1547 header_footer_info_
->SetString(kSettingHeaderFooterURL
,
1548 settings
.params
.url
);
1549 header_footer_info_
->SetString(kSettingHeaderFooterTitle
,
1550 settings
.params
.title
);
1554 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1555 Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
1556 settings
.params
.document_cookie
));
1561 bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame
* frame
,
1562 const blink::WebNode
& node
,
1563 int expected_pages_count
) {
1564 PrintHostMsg_ScriptedPrint_Params params
;
1565 PrintMsg_PrintPages_Params print_settings
;
1567 params
.cookie
= print_pages_params_
->params
.document_cookie
;
1568 params
.has_selection
= frame
->hasSelection();
1569 params
.expected_pages_count
= expected_pages_count
;
1570 MarginType margin_type
= DEFAULT_MARGINS
;
1571 if (PrintingNodeOrPdfFrame(frame
, node
))
1572 margin_type
= GetMarginsForPdf(frame
, node
);
1573 params
.margin_type
= margin_type
;
1575 Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));
1577 // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the
1578 // value before and restore it afterwards.
1579 blink::WebPrintScalingOption scaling_option
=
1580 print_pages_params_
->params
.print_scaling_option
;
1582 print_pages_params_
.reset();
1583 IPC::SyncMessage
* msg
=
1584 new PrintHostMsg_ScriptedPrint(routing_id(), params
, &print_settings
);
1585 msg
->EnableMessagePumping();
1587 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(print_settings
));
1589 print_pages_params_
->params
.print_scaling_option
= scaling_option
;
1590 return (print_settings
.params
.dpi
&& print_settings
.params
.document_cookie
);
1593 bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame
* frame
,
1594 const blink::WebNode
& node
) {
1595 if (!frame
|| prep_frame_view_
)
1597 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1598 const PrintMsg_Print_Params
& print_params
= params
.params
;
1599 prep_frame_view_
.reset(new PrepareFrameAndViewForPrint(
1600 print_params
, frame
, node
, ignore_css_margins_
));
1601 DCHECK(!print_pages_params_
->params
.selection_only
||
1602 print_pages_params_
->pages
.empty());
1603 prep_frame_view_
->CopySelectionIfNeeded(
1604 render_view()->GetWebkitPreferences(),
1605 base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages
,
1606 base::Unretained(this)));
1610 #if defined(OS_POSIX)
1611 bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
1612 PdfMetafileSkia
* metafile
,
1613 base::SharedMemoryHandle
* shared_mem_handle
) {
1614 uint32 buf_size
= metafile
->GetDataSize();
1615 scoped_ptr
<base::SharedMemory
> shared_buf(
1616 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
1617 buf_size
).release());
1619 if (shared_buf
.get()) {
1620 if (shared_buf
->Map(buf_size
)) {
1621 metafile
->GetData(shared_buf
->memory(), buf_size
);
1622 shared_buf
->GiveToProcess(base::GetCurrentProcessHandle(),
1630 #endif // defined(OS_POSIX)
1632 bool PrintWebViewHelper::IsScriptInitiatedPrintTooFrequent(
1633 blink::WebFrame
* frame
) {
1634 const int kMinSecondsToIgnoreJavascriptInitiatedPrint
= 2;
1635 const int kMaxSecondsToIgnoreJavascriptInitiatedPrint
= 32;
1636 bool too_frequent
= false;
1638 // Check if there is script repeatedly trying to print and ignore it if too
1639 // frequent. The first 3 times, we use a constant wait time, but if this
1640 // gets excessive, we switch to exponential wait time. So for a page that
1641 // calls print() in a loop the user will need to cancel the print dialog
1642 // after: [2, 2, 2, 4, 8, 16, 32, 32, ...] seconds.
1643 // This gives the user time to navigate from the page.
1644 if (user_cancelled_scripted_print_count_
> 0) {
1645 base::TimeDelta diff
= base::Time::Now() - last_cancelled_script_print_
;
1646 int min_wait_seconds
= kMinSecondsToIgnoreJavascriptInitiatedPrint
;
1647 if (user_cancelled_scripted_print_count_
> 3) {
1648 min_wait_seconds
= std::min(
1649 kMinSecondsToIgnoreJavascriptInitiatedPrint
<<
1650 (user_cancelled_scripted_print_count_
- 3),
1651 kMaxSecondsToIgnoreJavascriptInitiatedPrint
);
1653 if (diff
.InSeconds() < min_wait_seconds
) {
1654 too_frequent
= true;
1661 blink::WebString
message(
1662 blink::WebString::fromUTF8("Ignoring too frequent calls to print()."));
1663 frame
->addMessageToConsole(
1664 blink::WebConsoleMessage(
1665 blink::WebConsoleMessage::LevelWarning
, message
));
1669 void PrintWebViewHelper::ResetScriptedPrintCount() {
1670 // Reset cancel counter on successful print.
1671 user_cancelled_scripted_print_count_
= 0;
1674 void PrintWebViewHelper::IncrementScriptedPrintCount() {
1675 ++user_cancelled_scripted_print_count_
;
1676 last_cancelled_script_print_
= base::Time::Now();
1679 void PrintWebViewHelper::ShowScriptedPrintPreview() {
1680 if (is_scripted_preview_delayed_
) {
1681 is_scripted_preview_delayed_
= false;
1682 Send(new PrintHostMsg_ShowScriptedPrintPreview(routing_id(),
1683 print_preview_context_
.IsModifiable()));
1687 void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type
) {
1688 const bool is_modifiable
= print_preview_context_
.IsModifiable();
1689 const bool has_selection
= print_preview_context_
.HasSelection();
1690 PrintHostMsg_RequestPrintPreview_Params params
;
1691 params
.is_modifiable
= is_modifiable
;
1692 params
.has_selection
= has_selection
;
1694 case PRINT_PREVIEW_SCRIPTED
: {
1695 // Shows scripted print preview in two stages.
1696 // 1. PrintHostMsg_SetupScriptedPrintPreview blocks this call and JS by
1697 // pumping messages here.
1698 // 2. PrintHostMsg_ShowScriptedPrintPreview shows preview once the
1699 // document has been loaded.
1700 is_scripted_preview_delayed_
= true;
1701 if (is_loading_
&& GetPlugin(print_preview_context_
.source_frame())) {
1702 // Wait for DidStopLoading. Plugins may not know the correct
1703 // |is_modifiable| value until they are fully loaded, which occurs when
1704 // DidStopLoading() is called. Defer showing the preview until then.
1706 base::MessageLoop::current()->PostTask(
1708 base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview
,
1709 weak_ptr_factory_
.GetWeakPtr()));
1711 IPC::SyncMessage
* msg
=
1712 new PrintHostMsg_SetupScriptedPrintPreview(routing_id());
1713 msg
->EnableMessagePumping();
1715 is_scripted_preview_delayed_
= false;
1718 case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME
: {
1721 case PRINT_PREVIEW_USER_INITIATED_SELECTION
: {
1722 DCHECK(has_selection
);
1723 params
.selection_only
= has_selection
;
1726 case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE
: {
1727 params
.webnode_only
= true;
1735 Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params
));
1738 bool PrintWebViewHelper::CheckForCancel() {
1739 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1740 bool cancel
= false;
1741 Send(new PrintHostMsg_CheckForCancel(routing_id(),
1742 print_params
.preview_ui_id
,
1743 print_params
.preview_request_id
,
1746 notify_browser_of_print_failure_
= false;
1750 bool PrintWebViewHelper::PreviewPageRendered(int page_number
,
1751 PdfMetafileSkia
* metafile
) {
1752 DCHECK_GE(page_number
, FIRST_PAGE_INDEX
);
1754 // For non-modifiable files, |metafile| should be NULL, so do not bother
1755 // sending a message. If we don't generate draft metafiles, |metafile| is
1757 if (!print_preview_context_
.IsModifiable() ||
1758 !print_preview_context_
.generate_draft_pages()) {
1765 print_preview_context_
.set_error(
1766 PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE
);
1770 PrintHostMsg_DidPreviewPage_Params preview_page_params
;
1771 // Get the size of the resulting metafile.
1772 uint32 buf_size
= metafile
->GetDataSize();
1773 DCHECK_GT(buf_size
, 0u);
1774 if (!CopyMetafileDataToSharedMem(
1775 metafile
, &(preview_page_params
.metafile_data_handle
))) {
1776 LOG(ERROR
) << "CopyMetafileDataToSharedMem failed";
1777 print_preview_context_
.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED
);
1780 preview_page_params
.data_size
= buf_size
;
1781 preview_page_params
.page_number
= page_number
;
1782 preview_page_params
.preview_request_id
=
1783 print_pages_params_
->params
.preview_request_id
;
1785 Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params
));
1789 PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
1790 : total_page_count_(0),
1791 current_page_index_(0),
1792 generate_draft_pages_(true),
1793 print_ready_metafile_page_count_(0),
1794 error_(PREVIEW_ERROR_NONE
),
1795 state_(UNINITIALIZED
) {
1798 PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
1801 void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
1802 blink::WebLocalFrame
* web_frame
) {
1804 DCHECK(!IsRendering());
1805 state_
= INITIALIZED
;
1806 source_frame_
.Reset(web_frame
);
1807 source_node_
.reset();
1810 void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
1811 const blink::WebNode
& web_node
) {
1812 DCHECK(!web_node
.isNull());
1813 DCHECK(web_node
.document().frame());
1814 DCHECK(!IsRendering());
1815 state_
= INITIALIZED
;
1816 source_frame_
.Reset(web_node
.document().frame());
1817 source_node_
= web_node
;
1820 void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
1821 DCHECK_EQ(INITIALIZED
, state_
);
1825 bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
1826 PrepareFrameAndViewForPrint
* prepared_frame
,
1827 const std::vector
<int>& pages
) {
1828 DCHECK_EQ(INITIALIZED
, state_
);
1831 // Need to make sure old object gets destroyed first.
1832 prep_frame_view_
.reset(prepared_frame
);
1833 prep_frame_view_
->StartPrinting();
1835 total_page_count_
= prep_frame_view_
->GetExpectedPageCount();
1836 if (total_page_count_
== 0) {
1837 LOG(ERROR
) << "CreatePreviewDocument got 0 page count";
1838 set_error(PREVIEW_ERROR_ZERO_PAGES
);
1842 metafile_
.reset(new PdfMetafileSkia
);
1843 if (!metafile_
->Init()) {
1844 set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED
);
1845 LOG(ERROR
) << "PdfMetafileSkia Init failed";
1849 current_page_index_
= 0;
1850 pages_to_render_
= pages
;
1851 // Sort and make unique.
1852 std::sort(pages_to_render_
.begin(), pages_to_render_
.end());
1853 pages_to_render_
.resize(std::unique(pages_to_render_
.begin(),
1854 pages_to_render_
.end()) -
1855 pages_to_render_
.begin());
1856 // Remove invalid pages.
1857 pages_to_render_
.resize(std::lower_bound(pages_to_render_
.begin(),
1858 pages_to_render_
.end(),
1859 total_page_count_
) -
1860 pages_to_render_
.begin());
1861 print_ready_metafile_page_count_
= pages_to_render_
.size();
1862 if (pages_to_render_
.empty()) {
1863 print_ready_metafile_page_count_
= total_page_count_
;
1864 // Render all pages.
1865 for (int i
= 0; i
< total_page_count_
; ++i
)
1866 pages_to_render_
.push_back(i
);
1867 } else if (generate_draft_pages_
) {
1868 int pages_index
= 0;
1869 for (int i
= 0; i
< total_page_count_
; ++i
) {
1870 if (pages_index
< print_ready_metafile_page_count_
&&
1871 i
== pages_to_render_
[pages_index
]) {
1875 pages_to_render_
.push_back(i
);
1879 document_render_time_
= base::TimeDelta();
1880 begin_time_
= base::TimeTicks::Now();
1885 void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
1886 const base::TimeDelta
& page_time
) {
1887 DCHECK_EQ(RENDERING
, state_
);
1888 document_render_time_
+= page_time
;
1889 UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time
);
1892 void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
1893 DCHECK_EQ(RENDERING
, state_
);
1895 prep_frame_view_
->FinishPrinting();
1898 void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
1899 DCHECK(IsRendering());
1901 base::TimeTicks begin_time
= base::TimeTicks::Now();
1902 metafile_
->FinishDocument();
1904 if (print_ready_metafile_page_count_
<= 0) {
1909 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
1910 document_render_time_
);
1911 base::TimeDelta total_time
= (base::TimeTicks::Now() - begin_time
) +
1912 document_render_time_
;
1913 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
1915 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
1916 total_time
/ pages_to_render_
.size());
1919 void PrintWebViewHelper::PrintPreviewContext::Finished() {
1920 DCHECK_EQ(DONE
, state_
);
1921 state_
= INITIALIZED
;
1925 void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error
) {
1926 DCHECK(state_
== INITIALIZED
|| state_
== RENDERING
);
1927 state_
= INITIALIZED
;
1929 DCHECK_NE(PREVIEW_ERROR_NONE
, error_
);
1930 UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_
,
1931 PREVIEW_ERROR_LAST_ENUM
);
1936 int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
1937 DCHECK_EQ(RENDERING
, state_
);
1938 if (IsFinalPageRendered())
1940 return pages_to_render_
[current_page_index_
++];
1943 bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
1944 return state_
== RENDERING
|| state_
== DONE
;
1947 bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
1948 // The only kind of node we can print right now is a PDF node.
1949 return !PrintingNodeOrPdfFrame(source_frame(), source_node_
);
1952 bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
1953 return IsModifiable() && source_frame()->hasSelection();
1956 bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
1958 DCHECK(IsRendering());
1959 return current_page_index_
== print_ready_metafile_page_count_
;
1962 bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
1963 DCHECK(IsRendering());
1964 return static_cast<size_t>(current_page_index_
) == pages_to_render_
.size();
1967 void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
1968 bool generate_draft_pages
) {
1969 DCHECK_EQ(INITIALIZED
, state_
);
1970 generate_draft_pages_
= generate_draft_pages
;
1973 void PrintWebViewHelper::PrintPreviewContext::set_error(
1974 enum PrintPreviewErrorBuckets error
) {
1978 blink::WebLocalFrame
* PrintWebViewHelper::PrintPreviewContext::source_frame() {
1979 DCHECK_NE(UNINITIALIZED
, state_
);
1980 return source_frame_
.GetFrame();
1983 const blink::WebNode
&
1984 PrintWebViewHelper::PrintPreviewContext::source_node() const {
1985 DCHECK_NE(UNINITIALIZED
, state_
);
1986 return source_node_
;
1989 blink::WebLocalFrame
*
1990 PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
1991 DCHECK_NE(UNINITIALIZED
, state_
);
1992 return prep_frame_view_
->frame();
1995 const blink::WebNode
&
1996 PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
1997 DCHECK_NE(UNINITIALIZED
, state_
);
1998 return prep_frame_view_
->node();
2001 int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
2002 DCHECK_NE(UNINITIALIZED
, state_
);
2003 return total_page_count_
;
2006 bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
2007 return generate_draft_pages_
;
2010 PdfMetafileSkia
* PrintWebViewHelper::PrintPreviewContext::metafile() {
2011 DCHECK(IsRendering());
2012 return metafile_
.get();
2015 int PrintWebViewHelper::PrintPreviewContext::last_error() const {
2019 gfx::Size
PrintWebViewHelper::PrintPreviewContext::GetPrintCanvasSize() const {
2020 DCHECK(IsRendering());
2021 return prep_frame_view_
->GetPrintCanvasSize();
2024 void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
2025 prep_frame_view_
.reset();
2027 pages_to_render_
.clear();
2028 error_
= PREVIEW_ERROR_NONE
;
2031 } // namespace printing