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 "components/printing/renderer/print_web_view_helper.h"
9 #include "base/auto_reset.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "base/process/process_handle.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "components/printing/common/print_messages.h"
19 #include "content/public/common/web_preferences.h"
20 #include "content/public/renderer/render_frame.h"
21 #include "content/public/renderer/render_thread.h"
22 #include "content/public/renderer/render_view.h"
23 #include "grit/components_resources.h"
24 #include "net/base/escape.h"
25 #include "printing/pdf_metafile_skia.h"
26 #include "printing/units.h"
27 #include "third_party/WebKit/public/platform/WebSize.h"
28 #include "third_party/WebKit/public/platform/WebURLRequest.h"
29 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
30 #include "third_party/WebKit/public/web/WebDocument.h"
31 #include "third_party/WebKit/public/web/WebElement.h"
32 #include "third_party/WebKit/public/web/WebFrameClient.h"
33 #include "third_party/WebKit/public/web/WebLocalFrame.h"
34 #include "third_party/WebKit/public/web/WebPlugin.h"
35 #include "third_party/WebKit/public/web/WebPluginDocument.h"
36 #include "third_party/WebKit/public/web/WebPrintParams.h"
37 #include "third_party/WebKit/public/web/WebPrintPresetOptions.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/resource/resource_bundle.h"
46 using content::WebPreferences
;
52 enum PrintPreviewHelperEvents
{
53 PREVIEW_EVENT_REQUESTED
,
54 PREVIEW_EVENT_CACHE_HIT
, // Unused
55 PREVIEW_EVENT_CREATE_DOCUMENT
,
56 PREVIEW_EVENT_NEW_SETTINGS
, // Unused
60 const double kMinDpi
= 1.0;
62 #if !defined(ENABLE_PRINT_PREVIEW)
63 bool g_is_preview_enabled_
= false;
65 bool g_is_preview_enabled_
= true;
67 const char kPageLoadScriptFormat
[] =
68 "document.open(); document.write(%s); document.close();";
70 const char kPageSetupScriptFormat
[] = "setup(%s);";
72 void ExecuteScript(blink::WebFrame
* frame
,
73 const char* script_format
,
74 const base::Value
& parameters
) {
76 base::JSONWriter::Write(¶meters
, &json
);
77 std::string script
= base::StringPrintf(script_format
, json
.c_str());
78 frame
->executeScript(blink::WebString(base::UTF8ToUTF16(script
)));
80 #endif // !defined(ENABLE_PRINT_PREVIEW)
82 int GetDPI(const PrintMsg_Print_Params
* print_params
) {
83 #if defined(OS_MACOSX)
84 // On the Mac, the printable area is in points, don't do any scaling based
86 return kPointsPerInch
;
88 return static_cast<int>(print_params
->dpi
);
89 #endif // defined(OS_MACOSX)
92 bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params
& params
) {
93 return !params
.content_size
.IsEmpty() && !params
.page_size
.IsEmpty() &&
94 !params
.printable_area
.IsEmpty() && params
.document_cookie
&&
95 params
.desired_dpi
&& params
.max_shrink
&& params
.min_shrink
&&
96 params
.dpi
&& (params
.margin_top
>= 0) && (params
.margin_left
>= 0) &&
97 params
.dpi
> kMinDpi
&& params
.document_cookie
!= 0;
100 PrintMsg_Print_Params
GetCssPrintParams(
101 blink::WebFrame
* frame
,
103 const PrintMsg_Print_Params
& page_params
) {
104 PrintMsg_Print_Params page_css_params
= page_params
;
105 int dpi
= GetDPI(&page_params
);
107 blink::WebSize
page_size_in_pixels(
108 ConvertUnit(page_params
.page_size
.width(), dpi
, kPixelsPerInch
),
109 ConvertUnit(page_params
.page_size
.height(), dpi
, kPixelsPerInch
));
110 int margin_top_in_pixels
=
111 ConvertUnit(page_params
.margin_top
, dpi
, kPixelsPerInch
);
112 int margin_right_in_pixels
= ConvertUnit(
113 page_params
.page_size
.width() -
114 page_params
.content_size
.width() - page_params
.margin_left
,
115 dpi
, kPixelsPerInch
);
116 int margin_bottom_in_pixels
= ConvertUnit(
117 page_params
.page_size
.height() -
118 page_params
.content_size
.height() - page_params
.margin_top
,
119 dpi
, kPixelsPerInch
);
120 int margin_left_in_pixels
= ConvertUnit(
121 page_params
.margin_left
,
122 dpi
, kPixelsPerInch
);
124 blink::WebSize original_page_size_in_pixels
= page_size_in_pixels
;
127 frame
->pageSizeAndMarginsInPixels(page_index
,
129 margin_top_in_pixels
,
130 margin_right_in_pixels
,
131 margin_bottom_in_pixels
,
132 margin_left_in_pixels
);
135 int new_content_width
= page_size_in_pixels
.width
-
136 margin_left_in_pixels
- margin_right_in_pixels
;
137 int new_content_height
= page_size_in_pixels
.height
-
138 margin_top_in_pixels
- margin_bottom_in_pixels
;
140 // Invalid page size and/or margins. We just use the default setting.
141 if (new_content_width
< 1 || new_content_height
< 1) {
142 CHECK(frame
!= NULL
);
143 page_css_params
= GetCssPrintParams(NULL
, page_index
, page_params
);
144 return page_css_params
;
147 page_css_params
.content_size
= gfx::Size(
148 ConvertUnit(new_content_width
, kPixelsPerInch
, dpi
),
149 ConvertUnit(new_content_height
, kPixelsPerInch
, dpi
));
151 if (original_page_size_in_pixels
!= page_size_in_pixels
) {
152 page_css_params
.page_size
= gfx::Size(
153 ConvertUnit(page_size_in_pixels
.width
, kPixelsPerInch
, dpi
),
154 ConvertUnit(page_size_in_pixels
.height
, kPixelsPerInch
, dpi
));
156 // Printing frame doesn't have any page size css. Pixels to dpi conversion
157 // causes rounding off errors. Therefore use the default page size values
159 page_css_params
.page_size
= page_params
.page_size
;
162 page_css_params
.margin_top
=
163 ConvertUnit(margin_top_in_pixels
, kPixelsPerInch
, dpi
);
164 page_css_params
.margin_left
=
165 ConvertUnit(margin_left_in_pixels
, kPixelsPerInch
, dpi
);
166 return page_css_params
;
169 double FitPrintParamsToPage(const PrintMsg_Print_Params
& page_params
,
170 PrintMsg_Print_Params
* params_to_fit
) {
171 double content_width
=
172 static_cast<double>(params_to_fit
->content_size
.width());
173 double content_height
=
174 static_cast<double>(params_to_fit
->content_size
.height());
175 int default_page_size_height
= page_params
.page_size
.height();
176 int default_page_size_width
= page_params
.page_size
.width();
177 int css_page_size_height
= params_to_fit
->page_size
.height();
178 int css_page_size_width
= params_to_fit
->page_size
.width();
180 double scale_factor
= 1.0f
;
181 if (page_params
.page_size
== params_to_fit
->page_size
)
184 if (default_page_size_width
< css_page_size_width
||
185 default_page_size_height
< css_page_size_height
) {
187 static_cast<double>(default_page_size_width
) / css_page_size_width
;
188 double ratio_height
=
189 static_cast<double>(default_page_size_height
) / css_page_size_height
;
190 scale_factor
= ratio_width
< ratio_height
? ratio_width
: ratio_height
;
191 content_width
*= scale_factor
;
192 content_height
*= scale_factor
;
194 params_to_fit
->margin_top
= static_cast<int>(
195 (default_page_size_height
- css_page_size_height
* scale_factor
) / 2 +
196 (params_to_fit
->margin_top
* scale_factor
));
197 params_to_fit
->margin_left
= static_cast<int>(
198 (default_page_size_width
- css_page_size_width
* scale_factor
) / 2 +
199 (params_to_fit
->margin_left
* scale_factor
));
200 params_to_fit
->content_size
= gfx::Size(
201 static_cast<int>(content_width
), static_cast<int>(content_height
));
202 params_to_fit
->page_size
= page_params
.page_size
;
206 void CalculatePageLayoutFromPrintParams(
207 const PrintMsg_Print_Params
& params
,
208 PageSizeMargins
* page_layout_in_points
) {
209 int dpi
= GetDPI(¶ms
);
210 int content_width
= params
.content_size
.width();
211 int content_height
= params
.content_size
.height();
213 int margin_bottom
= params
.page_size
.height() -
214 content_height
- params
.margin_top
;
215 int margin_right
= params
.page_size
.width() -
216 content_width
- params
.margin_left
;
218 page_layout_in_points
->content_width
=
219 ConvertUnit(content_width
, dpi
, kPointsPerInch
);
220 page_layout_in_points
->content_height
=
221 ConvertUnit(content_height
, dpi
, kPointsPerInch
);
222 page_layout_in_points
->margin_top
=
223 ConvertUnit(params
.margin_top
, dpi
, kPointsPerInch
);
224 page_layout_in_points
->margin_right
=
225 ConvertUnit(margin_right
, dpi
, kPointsPerInch
);
226 page_layout_in_points
->margin_bottom
=
227 ConvertUnit(margin_bottom
, dpi
, kPointsPerInch
);
228 page_layout_in_points
->margin_left
=
229 ConvertUnit(params
.margin_left
, dpi
, kPointsPerInch
);
232 void EnsureOrientationMatches(const PrintMsg_Print_Params
& css_params
,
233 PrintMsg_Print_Params
* page_params
) {
234 if ((page_params
->page_size
.width() > page_params
->page_size
.height()) ==
235 (css_params
.page_size
.width() > css_params
.page_size
.height())) {
239 // Swap the |width| and |height| values.
240 page_params
->page_size
.SetSize(page_params
->page_size
.height(),
241 page_params
->page_size
.width());
242 page_params
->content_size
.SetSize(page_params
->content_size
.height(),
243 page_params
->content_size
.width());
244 page_params
->printable_area
.set_size(
245 gfx::Size(page_params
->printable_area
.height(),
246 page_params
->printable_area
.width()));
249 void ComputeWebKitPrintParamsInDesiredDpi(
250 const PrintMsg_Print_Params
& print_params
,
251 blink::WebPrintParams
* webkit_print_params
) {
252 int dpi
= GetDPI(&print_params
);
253 webkit_print_params
->printerDPI
= dpi
;
254 webkit_print_params
->printScalingOption
= print_params
.print_scaling_option
;
256 webkit_print_params
->printContentArea
.width
=
257 ConvertUnit(print_params
.content_size
.width(), dpi
,
258 print_params
.desired_dpi
);
259 webkit_print_params
->printContentArea
.height
=
260 ConvertUnit(print_params
.content_size
.height(), dpi
,
261 print_params
.desired_dpi
);
263 webkit_print_params
->printableArea
.x
=
264 ConvertUnit(print_params
.printable_area
.x(), dpi
,
265 print_params
.desired_dpi
);
266 webkit_print_params
->printableArea
.y
=
267 ConvertUnit(print_params
.printable_area
.y(), dpi
,
268 print_params
.desired_dpi
);
269 webkit_print_params
->printableArea
.width
=
270 ConvertUnit(print_params
.printable_area
.width(), dpi
,
271 print_params
.desired_dpi
);
272 webkit_print_params
->printableArea
.height
=
273 ConvertUnit(print_params
.printable_area
.height(),
274 dpi
, print_params
.desired_dpi
);
276 webkit_print_params
->paperSize
.width
=
277 ConvertUnit(print_params
.page_size
.width(), dpi
,
278 print_params
.desired_dpi
);
279 webkit_print_params
->paperSize
.height
=
280 ConvertUnit(print_params
.page_size
.height(), dpi
,
281 print_params
.desired_dpi
);
284 blink::WebPlugin
* GetPlugin(const blink::WebFrame
* frame
) {
285 return frame
->document().isPluginDocument() ?
286 frame
->document().to
<blink::WebPluginDocument
>().plugin() : NULL
;
289 bool PrintingNodeOrPdfFrame(const blink::WebFrame
* frame
,
290 const blink::WebNode
& node
) {
293 blink::WebPlugin
* plugin
= GetPlugin(frame
);
294 return plugin
&& plugin
->supportsPaginatedPrint();
297 bool PrintingFrameHasPageSizeStyle(blink::WebFrame
* frame
,
298 int total_page_count
) {
301 bool frame_has_custom_page_size_style
= false;
302 for (int i
= 0; i
< total_page_count
; ++i
) {
303 if (frame
->hasCustomPageSizeStyle(i
)) {
304 frame_has_custom_page_size_style
= true;
308 return frame_has_custom_page_size_style
;
311 MarginType
GetMarginsForPdf(blink::WebFrame
* frame
,
312 const blink::WebNode
& node
) {
313 if (frame
->isPrintScalingDisabledForPlugin(node
))
316 return PRINTABLE_AREA_MARGINS
;
319 bool FitToPageEnabled(const base::DictionaryValue
& job_settings
) {
320 bool fit_to_paper_size
= false;
321 if (!job_settings
.GetBoolean(kSettingFitToPageEnabled
, &fit_to_paper_size
)) {
324 return fit_to_paper_size
;
327 // Returns the print scaling option to retain/scale/crop the source page size
328 // to fit the printable area of the paper.
330 // We retain the source page size when the current destination printer is
333 // We crop the source page size to fit the printable area or we print only the
334 // left top page contents when
335 // (1) Source is PDF and the user has requested not to fit to printable area
336 // via |job_settings|.
337 // (2) Source is PDF. This is the first preview request and print scaling
338 // option is disabled for initiator renderer plugin.
340 // In all other cases, we scale the source page to fit the printable area.
341 blink::WebPrintScalingOption
GetPrintScalingOption(
342 blink::WebFrame
* frame
,
343 const blink::WebNode
& node
,
345 const base::DictionaryValue
& job_settings
,
346 const PrintMsg_Print_Params
& params
) {
347 if (params
.print_to_pdf
)
348 return blink::WebPrintScalingOptionSourceSize
;
350 if (!source_is_html
) {
351 if (!FitToPageEnabled(job_settings
))
352 return blink::WebPrintScalingOptionNone
;
354 bool no_plugin_scaling
= frame
->isPrintScalingDisabledForPlugin(node
);
356 if (params
.is_first_request
&& no_plugin_scaling
)
357 return blink::WebPrintScalingOptionNone
;
359 return blink::WebPrintScalingOptionFitToPrintableArea
;
362 PrintMsg_Print_Params
CalculatePrintParamsForCss(
363 blink::WebFrame
* frame
,
365 const PrintMsg_Print_Params
& page_params
,
366 bool ignore_css_margins
,
368 double* scale_factor
) {
369 PrintMsg_Print_Params css_params
= GetCssPrintParams(frame
, page_index
,
372 PrintMsg_Print_Params params
= page_params
;
373 EnsureOrientationMatches(css_params
, ¶ms
);
375 if (ignore_css_margins
&& fit_to_page
)
378 PrintMsg_Print_Params result_params
= css_params
;
379 if (ignore_css_margins
) {
380 result_params
.margin_top
= params
.margin_top
;
381 result_params
.margin_left
= params
.margin_left
;
383 DCHECK(!fit_to_page
);
384 // Since we are ignoring the margins, the css page size is no longer
386 int default_margin_right
= params
.page_size
.width() -
387 params
.content_size
.width() - params
.margin_left
;
388 int default_margin_bottom
= params
.page_size
.height() -
389 params
.content_size
.height() - params
.margin_top
;
390 result_params
.content_size
= gfx::Size(
391 result_params
.page_size
.width() - result_params
.margin_left
-
392 default_margin_right
,
393 result_params
.page_size
.height() - result_params
.margin_top
-
394 default_margin_bottom
);
398 double factor
= FitPrintParamsToPage(params
, &result_params
);
400 *scale_factor
= factor
;
402 return result_params
;
407 FrameReference::FrameReference(blink::WebLocalFrame
* frame
) {
411 FrameReference::FrameReference() {
415 FrameReference::~FrameReference() {
418 void FrameReference::Reset(blink::WebLocalFrame
* frame
) {
420 view_
= frame
->view();
428 blink::WebLocalFrame
* FrameReference::GetFrame() {
429 if (view_
== NULL
|| frame_
== NULL
)
431 for (blink::WebFrame
* frame
= view_
->mainFrame(); frame
!= NULL
;
432 frame
= frame
->traverseNext(false)) {
439 blink::WebView
* FrameReference::view() {
443 #if defined(ENABLE_PRINT_PREVIEW)
444 // static - Not anonymous so that platform implementations can use it.
445 void PrintWebViewHelper::PrintHeaderAndFooter(
446 blink::WebCanvas
* canvas
,
449 const blink::WebFrame
& source_frame
,
450 float webkit_scale_factor
,
451 const PageSizeMargins
& page_layout
,
452 const PrintMsg_Print_Params
& params
) {
453 SkAutoCanvasRestore
auto_restore(canvas
, true);
454 canvas
->scale(1 / webkit_scale_factor
, 1 / webkit_scale_factor
);
456 blink::WebSize
page_size(page_layout
.margin_left
+ page_layout
.margin_right
+
457 page_layout
.content_width
,
458 page_layout
.margin_top
+ page_layout
.margin_bottom
+
459 page_layout
.content_height
);
461 blink::WebView
* web_view
= blink::WebView::create(NULL
);
462 web_view
->settings()->setJavaScriptEnabled(true);
464 blink::WebLocalFrame
* frame
= blink::WebLocalFrame::create(NULL
);
465 web_view
->setMainFrame(frame
);
467 base::StringValue
html(ResourceBundle::GetSharedInstance().GetLocalizedString(
468 IDR_PRINT_PREVIEW_PAGE
));
469 // Load page with script to avoid async operations.
470 ExecuteScript(frame
, kPageLoadScriptFormat
, html
);
472 scoped_ptr
<base::DictionaryValue
> options(new base::DictionaryValue());
473 options
.reset(new base::DictionaryValue());
474 options
->SetDouble(kSettingHeaderFooterDate
, base::Time::Now().ToJsTime());
475 options
->SetDouble("width", page_size
.width
);
476 options
->SetDouble("height", page_size
.height
);
477 options
->SetDouble("topMargin", page_layout
.margin_top
);
478 options
->SetDouble("bottomMargin", page_layout
.margin_bottom
);
479 options
->SetString("pageNumber",
480 base::StringPrintf("%d/%d", page_number
, total_pages
));
482 // Fallback to initiator URL and title if it's empty for printed frame.
483 base::string16 url
= source_frame
.document().url().string();
484 options
->SetString("url", url
.empty() ? params
.url
: url
);
485 base::string16 title
= source_frame
.document().title();
486 options
->SetString("title", title
.empty() ? params
.title
: title
);
488 ExecuteScript(frame
, kPageSetupScriptFormat
, *options
);
490 blink::WebPrintParams
webkit_params(page_size
);
491 webkit_params
.printerDPI
= GetDPI(¶ms
);
493 frame
->printBegin(webkit_params
);
494 frame
->printPage(0, canvas
);
500 #endif // defined(ENABLE_PRINT_PREVIEW)
502 // static - Not anonymous so that platform implementations can use it.
503 float PrintWebViewHelper::RenderPageContent(blink::WebFrame
* frame
,
505 const gfx::Rect
& canvas_area
,
506 const gfx::Rect
& content_area
,
508 blink::WebCanvas
* canvas
) {
509 SkAutoCanvasRestore
auto_restore(canvas
, true);
510 canvas
->translate((content_area
.x() - canvas_area
.x()) / scale_factor
,
511 (content_area
.y() - canvas_area
.y()) / scale_factor
);
512 return frame
->printPage(page_number
, canvas
);
515 // Class that calls the Begin and End print functions on the frame and changes
516 // the size of the view temporarily to support full page printing..
517 class PrepareFrameAndViewForPrint
: public blink::WebViewClient
,
518 public blink::WebFrameClient
{
520 PrepareFrameAndViewForPrint(const PrintMsg_Print_Params
& params
,
521 blink::WebLocalFrame
* frame
,
522 const blink::WebNode
& node
,
523 bool ignore_css_margins
);
524 virtual ~PrepareFrameAndViewForPrint();
526 // Optional. Replaces |frame_| with selection if needed. Will call |on_ready|
528 void CopySelectionIfNeeded(const WebPreferences
& preferences
,
529 const base::Closure
& on_ready
);
531 // Prepares frame for printing.
532 void StartPrinting();
534 blink::WebLocalFrame
* frame() {
535 return frame_
.GetFrame();
538 const blink::WebNode
& node() const {
539 return node_to_print_
;
542 int GetExpectedPageCount() const {
543 return expected_pages_count_
;
546 void FinishPrinting();
548 bool IsLoadingSelection() {
549 // It's not selection if not |owns_web_view_|.
550 return owns_web_view_
&& frame() && frame()->isLoading();
553 // TODO(ojan): Remove this override and have this class use a non-null
555 // blink::WebViewClient override:
556 virtual bool allowsBrokenNullLayerTreeView() const;
559 // blink::WebViewClient override:
560 virtual void didStopLoading();
562 // blink::WebFrameClient override:
563 virtual blink::WebFrame
* createChildFrame(
564 blink::WebLocalFrame
* parent
,
565 const blink::WebString
& name
,
566 blink::WebSandboxFlags sandboxFlags
);
567 virtual void frameDetached(blink::WebFrame
* frame
);
571 void ResizeForPrinting();
573 void CopySelection(const WebPreferences
& preferences
);
575 FrameReference frame_
;
576 blink::WebNode node_to_print_
;
578 blink::WebPrintParams web_print_params_
;
579 gfx::Size prev_view_size_
;
580 gfx::Size prev_scroll_offset_
;
581 int expected_pages_count_
;
582 base::Closure on_ready_
;
583 bool should_print_backgrounds_
;
584 bool should_print_selection_only_
;
585 bool is_printing_started_
;
587 base::WeakPtrFactory
<PrepareFrameAndViewForPrint
> weak_ptr_factory_
;
589 DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint
);
592 PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
593 const PrintMsg_Print_Params
& params
,
594 blink::WebLocalFrame
* frame
,
595 const blink::WebNode
& node
,
596 bool ignore_css_margins
)
598 node_to_print_(node
),
599 owns_web_view_(false),
600 expected_pages_count_(0),
601 should_print_backgrounds_(params
.should_print_backgrounds
),
602 should_print_selection_only_(params
.selection_only
),
603 is_printing_started_(false),
604 weak_ptr_factory_(this) {
605 PrintMsg_Print_Params print_params
= params
;
606 if (!should_print_selection_only_
||
607 !PrintingNodeOrPdfFrame(frame
, node_to_print_
)) {
608 bool fit_to_page
= ignore_css_margins
&&
609 print_params
.print_scaling_option
==
610 blink::WebPrintScalingOptionFitToPrintableArea
;
611 ComputeWebKitPrintParamsInDesiredDpi(params
, &web_print_params_
);
612 frame
->printBegin(web_print_params_
, node_to_print_
);
613 print_params
= CalculatePrintParamsForCss(frame
, 0, print_params
,
614 ignore_css_margins
, fit_to_page
,
618 ComputeWebKitPrintParamsInDesiredDpi(print_params
, &web_print_params_
);
621 PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
625 void PrepareFrameAndViewForPrint::ResizeForPrinting() {
626 // Layout page according to printer page size. Since WebKit shrinks the
627 // size of the page automatically (from 125% to 200%) we trick it to
628 // think the page is 125% larger so the size of the page is correct for
629 // minimum (default) scaling.
630 // This is important for sites that try to fill the page.
631 gfx::Size
print_layout_size(web_print_params_
.printContentArea
.width
,
632 web_print_params_
.printContentArea
.height
);
633 print_layout_size
.set_height(
634 static_cast<int>(static_cast<double>(print_layout_size
.height()) * 1.25));
638 blink::WebView
* web_view
= frame_
.view();
639 // Backup size and offset.
640 if (blink::WebFrame
* web_frame
= web_view
->mainFrame())
641 prev_scroll_offset_
= web_frame
->scrollOffset();
642 prev_view_size_
= web_view
->size();
644 web_view
->resize(print_layout_size
);
648 void PrepareFrameAndViewForPrint::StartPrinting() {
650 blink::WebView
* web_view
= frame_
.view();
651 web_view
->settings()->setShouldPrintBackgrounds(should_print_backgrounds_
);
652 expected_pages_count_
=
653 frame()->printBegin(web_print_params_
, node_to_print_
);
654 is_printing_started_
= true;
657 void PrepareFrameAndViewForPrint::CopySelectionIfNeeded(
658 const WebPreferences
& preferences
,
659 const base::Closure
& on_ready
) {
660 on_ready_
= on_ready
;
661 if (should_print_selection_only_
) {
662 CopySelection(preferences
);
664 // Call immediately, async call crashes scripting printing.
669 void PrepareFrameAndViewForPrint::CopySelection(
670 const WebPreferences
& preferences
) {
672 std::string url_str
= "data:text/html;charset=utf-8,";
674 net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false));
676 // Create a new WebView with the same settings as the current display one.
677 // Except that we disable javascript (don't want any active content running
679 WebPreferences prefs
= preferences
;
680 prefs
.javascript_enabled
= false;
681 prefs
.java_enabled
= false;
683 blink::WebView
* web_view
= blink::WebView::create(this);
684 owns_web_view_
= true;
685 content::RenderView::ApplyWebPreferences(prefs
, web_view
);
686 web_view
->setMainFrame(blink::WebLocalFrame::create(this));
687 frame_
.Reset(web_view
->mainFrame()->toWebLocalFrame());
688 node_to_print_
.reset();
690 // When loading is done this will call didStopLoading() and that will do the
692 frame()->loadRequest(blink::WebURLRequest(GURL(url_str
)));
695 bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
699 void PrepareFrameAndViewForPrint::didStopLoading() {
700 DCHECK(!on_ready_
.is_null());
701 // Don't call callback here, because it can delete |this| and WebView that is
702 // called didStopLoading.
703 base::MessageLoop::current()->PostTask(
705 base::Bind(&PrepareFrameAndViewForPrint::CallOnReady
,
706 weak_ptr_factory_
.GetWeakPtr()));
709 blink::WebFrame
* PrepareFrameAndViewForPrint::createChildFrame(
710 blink::WebLocalFrame
* parent
,
711 const blink::WebString
& name
,
712 blink::WebSandboxFlags sandboxFlags
) {
713 blink::WebFrame
* frame
= blink::WebLocalFrame::create(this);
714 parent
->appendChild(frame
);
718 void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame
* frame
) {
720 frame
->parent()->removeChild(frame
);
724 void PrepareFrameAndViewForPrint::CallOnReady() {
725 return on_ready_
.Run(); // Can delete |this|.
728 void PrepareFrameAndViewForPrint::RestoreSize() {
730 blink::WebView
* web_view
= frame_
.GetFrame()->view();
731 web_view
->resize(prev_view_size_
);
732 if (blink::WebFrame
* web_frame
= web_view
->mainFrame())
733 web_frame
->setScrollOffset(prev_scroll_offset_
);
737 void PrepareFrameAndViewForPrint::FinishPrinting() {
738 blink::WebLocalFrame
* frame
= frame_
.GetFrame();
740 blink::WebView
* web_view
= frame
->view();
741 if (is_printing_started_
) {
742 is_printing_started_
= false;
744 if (!owns_web_view_
) {
745 web_view
->settings()->setShouldPrintBackgrounds(false);
749 if (owns_web_view_
) {
750 DCHECK(!frame
->isLoading());
751 owns_web_view_
= false;
759 PrintWebViewHelper::PrintWebViewHelper(
760 content::RenderView
* render_view
,
761 scoped_ptr
<Delegate
> delegate
)
762 : content::RenderViewObserver(render_view
),
763 content::RenderViewObserverTracker
<PrintWebViewHelper
>(render_view
),
764 reset_prep_frame_view_(false),
765 is_print_ready_metafile_sent_(false),
766 ignore_css_margins_(false),
767 is_scripted_printing_blocked_(false),
768 notify_browser_of_print_failure_(true),
769 print_for_preview_(false),
770 delegate_(delegate
.Pass()),
771 print_node_in_progress_(false),
773 is_scripted_preview_delayed_(false),
774 weak_ptr_factory_(this) {
775 if (!delegate_
->IsPrintPreviewEnabled())
779 PrintWebViewHelper::~PrintWebViewHelper() {}
782 void PrintWebViewHelper::DisablePreview() {
783 g_is_preview_enabled_
= false;
786 bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
787 blink::WebFrame
* frame
, bool user_initiated
) {
788 // If preview is enabled, then the print dialog is tab modal, and the user
789 // can always close the tab on a mis-behaving page (the system print dialog
790 // is app modal). If the print was initiated through user action, don't
791 // throttle. Or, if the command line flag to skip throttling has been set.
792 return !is_scripted_printing_blocked_
&&
793 (user_initiated
|| g_is_preview_enabled_
||
794 scripting_throttler_
.IsAllowed(frame
));
797 void PrintWebViewHelper::DidStartLoading() {
801 void PrintWebViewHelper::DidStopLoading() {
803 if (!on_stop_loading_closure_
.is_null()) {
804 on_stop_loading_closure_
.Run();
805 on_stop_loading_closure_
.Reset();
809 // Prints |frame| which called window.print().
810 void PrintWebViewHelper::PrintPage(blink::WebLocalFrame
* frame
,
811 bool user_initiated
) {
814 // Allow Prerendering to cancel this print request if necessary.
815 if (delegate_
->CancelPrerender(render_view(), routing_id()))
818 if (!IsScriptInitiatedPrintAllowed(frame
, user_initiated
))
821 if (delegate_
->OverridePrint(frame
))
824 if (!g_is_preview_enabled_
) {
825 Print(frame
, blink::WebNode(), true);
827 print_preview_context_
.InitWithFrame(frame
);
828 RequestPrintPreview(PRINT_PREVIEW_SCRIPTED
);
832 bool PrintWebViewHelper::OnMessageReceived(const IPC::Message
& message
) {
834 IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper
, message
)
835 #if defined(ENABLE_BASIC_PRINTING)
836 IPC_MESSAGE_HANDLER(PrintMsg_PrintPages
, OnPrintPages
)
837 IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog
, OnPrintForSystemDialog
)
838 #endif // ENABLE_BASIC_PRINTING
839 IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview
, OnInitiatePrintPreview
)
840 IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview
, OnPrintPreview
)
841 IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview
, OnPrintForPrintPreview
)
842 IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone
, OnPrintingDone
)
843 IPC_MESSAGE_HANDLER(PrintMsg_SetScriptedPrintingBlocked
,
844 SetScriptedPrintBlocked
)
845 IPC_MESSAGE_UNHANDLED(handled
= false)
846 IPC_END_MESSAGE_MAP()
850 void PrintWebViewHelper::OnPrintForPrintPreview(
851 const base::DictionaryValue
& job_settings
) {
852 // If still not finished with earlier print request simply ignore.
853 if (prep_frame_view_
)
856 if (!render_view()->GetWebView())
858 blink::WebFrame
* main_frame
= render_view()->GetWebView()->mainFrame();
862 blink::WebDocument document
= main_frame
->document();
863 // <object>/<iframe> with id="pdf-viewer" is created in
864 // chrome/browser/resources/print_preview/print_preview.js
865 blink::WebElement pdf_element
= document
.getElementById("pdf-viewer");
866 if (pdf_element
.isNull()) {
871 // The out-of-process plugin element is nested within a frame. In tests, there
872 // may not be an iframe containing the out-of-process plugin, so continue with
873 // the element with ID "pdf-viewer" if it isn't an iframe.
874 blink::WebLocalFrame
* plugin_frame
= pdf_element
.document().frame();
875 blink::WebElement plugin_element
= pdf_element
;
876 if (delegate_
->IsOutOfProcessPdfEnabled() &&
877 pdf_element
.hasHTMLTagName("iframe")) {
878 plugin_frame
= blink::WebLocalFrame::fromFrameOwnerElement(pdf_element
);
879 plugin_element
= delegate_
->GetPdfElement(plugin_frame
);
880 if (plugin_element
.isNull()) {
886 // Set |print_for_preview_| flag and autoreset it to back to original
888 base::AutoReset
<bool> set_printing_flag(&print_for_preview_
, true);
890 if (!UpdatePrintSettings(plugin_frame
, plugin_element
, job_settings
)) {
891 LOG(ERROR
) << "UpdatePrintSettings failed";
892 DidFinishPrinting(FAIL_PRINT
);
896 // Print page onto entire page not just printable area. Preview PDF already
897 // has content in correct position taking into account page size and printable
899 // TODO(vitalybuka) : Make this consistent on all platform. This change
900 // affects Windows only. On Linux and OSX RenderPagesForPrint does not use
901 // printable_area. Also we can't change printable_area deeper inside
902 // RenderPagesForPrint for Windows, because it's used also by native
903 // printing and it expects real printable_area value.
904 // See http://crbug.com/123408
905 PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
906 print_params
.printable_area
= gfx::Rect(print_params
.page_size
);
908 // Render Pages for printing.
909 if (!RenderPagesForPrint(plugin_frame
, plugin_element
)) {
910 LOG(ERROR
) << "RenderPagesForPrint failed";
911 DidFinishPrinting(FAIL_PRINT
);
915 bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame
** frame
) {
917 blink::WebView
* webView
= render_view()->GetWebView();
922 // If the user has selected text in the currently focused frame we print
923 // only that frame (this makes print selection work for multiple frames).
924 blink::WebLocalFrame
* focusedFrame
=
925 webView
->focusedFrame()->toWebLocalFrame();
926 *frame
= focusedFrame
->hasSelection()
928 : webView
->mainFrame()->toWebLocalFrame();
932 #if defined(ENABLE_BASIC_PRINTING)
933 void PrintWebViewHelper::OnPrintPages() {
934 blink::WebLocalFrame
* frame
;
935 if (!GetPrintFrame(&frame
))
937 // If we are printing a PDF extension frame, find the plugin node and print
939 auto plugin
= delegate_
->GetPdfElement(frame
);
940 Print(frame
, plugin
, false);
943 void PrintWebViewHelper::OnPrintForSystemDialog() {
944 blink::WebLocalFrame
* frame
= print_preview_context_
.source_frame();
949 Print(frame
, print_preview_context_
.source_node(), false);
951 #endif // ENABLE_BASIC_PRINTING
953 void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
954 const PageSizeMargins
& page_layout_in_points
,
955 gfx::Size
* page_size
,
956 gfx::Rect
* content_area
) {
957 *page_size
= gfx::Size(
958 page_layout_in_points
.content_width
+
959 page_layout_in_points
.margin_right
+
960 page_layout_in_points
.margin_left
,
961 page_layout_in_points
.content_height
+
962 page_layout_in_points
.margin_top
+
963 page_layout_in_points
.margin_bottom
);
964 *content_area
= gfx::Rect(page_layout_in_points
.margin_left
,
965 page_layout_in_points
.margin_top
,
966 page_layout_in_points
.content_width
,
967 page_layout_in_points
.content_height
);
970 void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
971 const base::DictionaryValue
& settings
) {
972 int margins_type
= 0;
973 if (!settings
.GetInteger(kSettingMarginsType
, &margins_type
))
974 margins_type
= DEFAULT_MARGINS
;
975 ignore_css_margins_
= (margins_type
!= DEFAULT_MARGINS
);
978 bool PrintWebViewHelper::IsPrintToPdfRequested(
979 const base::DictionaryValue
& job_settings
) {
980 bool print_to_pdf
= false;
981 if (!job_settings
.GetBoolean(kSettingPrintToPDF
, &print_to_pdf
))
986 void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue
& settings
) {
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_
?
1003 print_pages_params_
->params
.document_cookie
: 0));
1004 notify_browser_of_print_failure_
= false; // Already sent.
1006 DidFinishPrinting(FAIL_PREVIEW
);
1010 // Set the options from document if we are previewing a pdf and send a
1011 // message to browser.
1012 if (print_pages_params_
->params
.is_first_request
&&
1013 !print_preview_context_
.IsModifiable()) {
1014 PrintHostMsg_SetOptionsFromDocument_Params params
;
1015 SetOptionsFromDocument(params
);
1016 Send(new PrintHostMsg_SetOptionsFromDocument(routing_id(), params
));
1019 is_print_ready_metafile_sent_
= false;
1021 // PDF printer device supports alpha blending.
1022 print_pages_params_
->params
.supports_alpha_blend
= true;
1024 bool generate_draft_pages
= false;
1025 if (!settings
.GetBoolean(kSettingGenerateDraftData
,
1026 &generate_draft_pages
)) {
1029 print_preview_context_
.set_generate_draft_pages(generate_draft_pages
);
1031 PrepareFrameForPreviewDocument();
1034 void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
1035 reset_prep_frame_view_
= false;
1037 if (!print_pages_params_
|| CheckForCancel()) {
1038 DidFinishPrinting(FAIL_PREVIEW
);
1042 // Don't reset loading frame or WebKit will fail assert. Just retry when
1043 // current selection is loaded.
1044 if (prep_frame_view_
&& prep_frame_view_
->IsLoadingSelection()) {
1045 reset_prep_frame_view_
= true;
1049 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1050 prep_frame_view_
.reset(
1051 new PrepareFrameAndViewForPrint(print_params
,
1052 print_preview_context_
.source_frame(),
1053 print_preview_context_
.source_node(),
1054 ignore_css_margins_
));
1055 prep_frame_view_
->CopySelectionIfNeeded(
1056 render_view()->GetWebkitPreferences(),
1057 base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument
,
1058 base::Unretained(this)));
1061 void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
1062 if (reset_prep_frame_view_
) {
1063 PrepareFrameForPreviewDocument();
1066 DidFinishPrinting(CreatePreviewDocument() ? OK
: FAIL_PREVIEW
);
1069 bool PrintWebViewHelper::CreatePreviewDocument() {
1070 if (!print_pages_params_
|| CheckForCancel())
1073 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
1074 PREVIEW_EVENT_CREATE_DOCUMENT
, PREVIEW_EVENT_MAX
);
1076 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1077 const std::vector
<int>& pages
= print_pages_params_
->pages
;
1079 if (!print_preview_context_
.CreatePreviewDocument(prep_frame_view_
.release(),
1084 PageSizeMargins default_page_layout
;
1085 ComputePageLayoutInPointsForCss(print_preview_context_
.prepared_frame(), 0,
1086 print_params
, ignore_css_margins_
, NULL
,
1087 &default_page_layout
);
1089 bool has_page_size_style
= PrintingFrameHasPageSizeStyle(
1090 print_preview_context_
.prepared_frame(),
1091 print_preview_context_
.total_page_count());
1092 int dpi
= GetDPI(&print_params
);
1094 gfx::Rect
printable_area_in_points(
1095 ConvertUnit(print_params
.printable_area
.x(), dpi
, kPointsPerInch
),
1096 ConvertUnit(print_params
.printable_area
.y(), dpi
, kPointsPerInch
),
1097 ConvertUnit(print_params
.printable_area
.width(), dpi
, kPointsPerInch
),
1098 ConvertUnit(print_params
.printable_area
.height(), dpi
, kPointsPerInch
));
1100 // Margins: Send default page layout to browser process.
1101 Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
1102 default_page_layout
,
1103 printable_area_in_points
,
1104 has_page_size_style
));
1106 PrintHostMsg_DidGetPreviewPageCount_Params params
;
1107 params
.page_count
= print_preview_context_
.total_page_count();
1108 params
.is_modifiable
= print_preview_context_
.IsModifiable();
1109 params
.document_cookie
= print_params
.document_cookie
;
1110 params
.preview_request_id
= print_params
.preview_request_id
;
1111 params
.clear_preview_data
= print_preview_context_
.generate_draft_pages();
1112 Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params
));
1113 if (CheckForCancel())
1116 while (!print_preview_context_
.IsFinalPageRendered()) {
1117 int page_number
= print_preview_context_
.GetNextPageNumber();
1118 DCHECK_GE(page_number
, 0);
1119 if (!RenderPreviewPage(page_number
, print_params
))
1122 if (CheckForCancel())
1125 // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of
1126 // print_preview_context_.AllPagesRendered()) before calling
1127 // FinalizePrintReadyDocument() when printing a PDF because the plugin
1128 // code does not generate output until we call FinishPrinting(). We do not
1129 // generate draft pages for PDFs, so IsFinalPageRendered() and
1130 // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of
1132 if (print_preview_context_
.IsFinalPageRendered())
1133 print_preview_context_
.AllPagesRendered();
1135 if (print_preview_context_
.IsLastPageOfPrintReadyMetafile()) {
1136 DCHECK(print_preview_context_
.IsModifiable() ||
1137 print_preview_context_
.IsFinalPageRendered());
1138 if (!FinalizePrintReadyDocument())
1142 print_preview_context_
.Finished();
1146 bool PrintWebViewHelper::FinalizePrintReadyDocument() {
1147 DCHECK(!is_print_ready_metafile_sent_
);
1148 print_preview_context_
.FinalizePrintReadyDocument();
1150 // Get the size of the resulting metafile.
1151 PdfMetafileSkia
* metafile
= print_preview_context_
.metafile();
1152 uint32 buf_size
= metafile
->GetDataSize();
1153 DCHECK_GT(buf_size
, 0u);
1155 PrintHostMsg_DidPreviewDocument_Params preview_params
;
1156 preview_params
.data_size
= buf_size
;
1157 preview_params
.document_cookie
= print_pages_params_
->params
.document_cookie
;
1158 preview_params
.expected_pages_count
=
1159 print_preview_context_
.total_page_count();
1160 preview_params
.modifiable
= print_preview_context_
.IsModifiable();
1161 preview_params
.preview_request_id
=
1162 print_pages_params_
->params
.preview_request_id
;
1164 // Ask the browser to create the shared memory for us.
1165 if (!CopyMetafileDataToSharedMem(metafile
,
1166 &(preview_params
.metafile_data_handle
))) {
1167 LOG(ERROR
) << "CopyMetafileDataToSharedMem failed";
1168 print_preview_context_
.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED
);
1171 is_print_ready_metafile_sent_
= true;
1173 Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params
));
1177 void PrintWebViewHelper::OnPrintingDone(bool success
) {
1178 notify_browser_of_print_failure_
= false;
1180 LOG(ERROR
) << "Failure in OnPrintingDone";
1181 DidFinishPrinting(success
? OK
: FAIL_PRINT
);
1184 void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked
) {
1185 is_scripted_printing_blocked_
= blocked
;
1188 void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only
) {
1189 blink::WebLocalFrame
* frame
= NULL
;
1190 GetPrintFrame(&frame
);
1192 // If we are printing a PDF extension frame, find the plugin node and print
1194 auto plugin
= delegate_
->GetPdfElement(frame
);
1195 if (!plugin
.isNull()) {
1199 print_preview_context_
.InitWithFrame(frame
);
1200 RequestPrintPreview(selection_only
?
1201 PRINT_PREVIEW_USER_INITIATED_SELECTION
:
1202 PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME
);
1205 bool PrintWebViewHelper::IsPrintingEnabled() {
1206 bool result
= false;
1207 Send(new PrintHostMsg_IsPrintingEnabled(routing_id(), &result
));
1211 void PrintWebViewHelper::PrintNode(const blink::WebNode
& node
) {
1212 if (node
.isNull() || !node
.document().frame()) {
1213 // This can occur when the context menu refers to an invalid WebNode.
1214 // See http://crbug.com/100890#c17 for a repro case.
1218 if (print_node_in_progress_
) {
1219 // This can happen as a result of processing sync messages when printing
1220 // from ppapi plugins. It's a rare case, so its OK to just fail here.
1221 // See http://crbug.com/159165.
1225 print_node_in_progress_
= true;
1227 // Make a copy of the node, in case RenderView::OnContextMenuClosed resets
1228 // its |context_menu_node_|.
1229 if (!g_is_preview_enabled_
) {
1230 blink::WebNode
duplicate_node(node
);
1231 Print(duplicate_node
.document().frame(), duplicate_node
, false);
1233 print_preview_context_
.InitWithNode(node
);
1234 RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE
);
1237 print_node_in_progress_
= false;
1240 void PrintWebViewHelper::Print(blink::WebLocalFrame
* frame
,
1241 const blink::WebNode
& node
,
1243 // If still not finished with earlier print request simply ignore.
1244 if (prep_frame_view_
)
1247 FrameReference
frame_ref(frame
);
1249 int expected_page_count
= 0;
1250 if (!CalculateNumberOfPages(frame
, node
, &expected_page_count
)) {
1251 DidFinishPrinting(FAIL_PRINT_INIT
);
1252 return; // Failed to init print page settings.
1255 // Some full screen plugins can say they don't want to print.
1256 if (!expected_page_count
) {
1257 DidFinishPrinting(FAIL_PRINT
);
1261 // Ask the browser to show UI to retrieve the final print settings.
1262 if (!GetPrintSettingsFromUser(frame_ref
.GetFrame(), node
,
1263 expected_page_count
,
1265 DidFinishPrinting(OK
); // Release resources and fail silently.
1269 // Render Pages for printing.
1270 if (!RenderPagesForPrint(frame_ref
.GetFrame(), node
)) {
1271 LOG(ERROR
) << "RenderPagesForPrint failed";
1272 DidFinishPrinting(FAIL_PRINT
);
1274 scripting_throttler_
.Reset();
1277 void PrintWebViewHelper::DidFinishPrinting(PrintingResult result
) {
1282 case FAIL_PRINT_INIT
:
1283 DCHECK(!notify_browser_of_print_failure_
);
1287 if (notify_browser_of_print_failure_
&& print_pages_params_
) {
1288 int cookie
= print_pages_params_
->params
.document_cookie
;
1289 Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie
));
1294 int cookie
= print_pages_params_
?
1295 print_pages_params_
->params
.document_cookie
: 0;
1296 if (notify_browser_of_print_failure_
) {
1297 LOG(ERROR
) << "CreatePreviewDocument failed";
1298 Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie
));
1300 Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie
));
1302 print_preview_context_
.Failed(notify_browser_of_print_failure_
);
1305 prep_frame_view_
.reset();
1306 print_pages_params_
.reset();
1307 notify_browser_of_print_failure_
= true;
1310 void PrintWebViewHelper::OnFramePreparedForPrintPages() {
1312 FinishFramePrinting();
1315 void PrintWebViewHelper::PrintPages() {
1316 if (!prep_frame_view_
) // Printing is already canceled or failed.
1318 prep_frame_view_
->StartPrinting();
1320 int page_count
= prep_frame_view_
->GetExpectedPageCount();
1322 LOG(ERROR
) << "Can't print 0 pages.";
1323 return DidFinishPrinting(FAIL_PRINT
);
1326 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1327 const PrintMsg_Print_Params
& print_params
= params
.params
;
1329 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
1330 // TODO(vitalybuka): should be page_count or valid pages from params.pages.
1331 // See http://crbug.com/161576
1332 Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
1333 print_params
.document_cookie
,
1335 #endif // !defined(OS_CHROMEOS)
1337 if (print_params
.preview_ui_id
< 0) {
1338 // Printing for system dialog.
1339 int printed_count
= params
.pages
.empty() ? page_count
: params
.pages
.size();
1340 #if !defined(OS_CHROMEOS)
1341 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count
);
1343 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1345 #endif // !defined(OS_CHROMEOS)
1349 if (!PrintPagesNative(prep_frame_view_
->frame(), page_count
)) {
1350 LOG(ERROR
) << "Printing failed.";
1351 return DidFinishPrinting(FAIL_PRINT
);
1355 void PrintWebViewHelper::FinishFramePrinting() {
1356 prep_frame_view_
.reset();
1359 #if defined(OS_MACOSX)
1360 bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame
* frame
,
1362 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1363 const PrintMsg_Print_Params
& print_params
= params
.params
;
1365 PrintMsg_PrintPage_Params page_params
;
1366 page_params
.params
= print_params
;
1367 if (params
.pages
.empty()) {
1368 for (int i
= 0; i
< page_count
; ++i
) {
1369 page_params
.page_number
= i
;
1370 PrintPageInternal(page_params
, frame
);
1373 for (size_t i
= 0; i
< params
.pages
.size(); ++i
) {
1374 if (params
.pages
[i
] >= page_count
)
1376 page_params
.page_number
= params
.pages
[i
];
1377 PrintPageInternal(page_params
, frame
);
1385 // static - Not anonymous so that platform implementations can use it.
1386 void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
1387 blink::WebFrame
* frame
,
1389 const PrintMsg_Print_Params
& page_params
,
1390 bool ignore_css_margins
,
1391 double* scale_factor
,
1392 PageSizeMargins
* page_layout_in_points
) {
1393 PrintMsg_Print_Params params
= CalculatePrintParamsForCss(
1394 frame
, page_index
, page_params
, ignore_css_margins
,
1395 page_params
.print_scaling_option
==
1396 blink::WebPrintScalingOptionFitToPrintableArea
,
1398 CalculatePageLayoutFromPrintParams(params
, page_layout_in_points
);
1401 bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size
) {
1402 PrintMsg_PrintPages_Params settings
;
1403 Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
1405 // Check if the printer returned any settings, if the settings is empty, we
1406 // can safely assume there are no printer drivers configured. So we safely
1409 if (!PrintMsg_Print_Params_IsValid(settings
.params
))
1412 // Reset to default values.
1413 ignore_css_margins_
= false;
1414 settings
.pages
.clear();
1416 settings
.params
.print_scaling_option
=
1417 blink::WebPrintScalingOptionSourceSize
;
1418 if (fit_to_paper_size
) {
1419 settings
.params
.print_scaling_option
=
1420 blink::WebPrintScalingOptionFitToPrintableArea
;
1423 SetPrintPagesParams(settings
);
1427 bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame
* frame
,
1428 const blink::WebNode
& node
,
1429 int* number_of_pages
) {
1431 bool fit_to_paper_size
= !(PrintingNodeOrPdfFrame(frame
, node
));
1432 if (!InitPrintSettings(fit_to_paper_size
)) {
1433 notify_browser_of_print_failure_
= false;
1434 Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
1438 const PrintMsg_Print_Params
& params
= print_pages_params_
->params
;
1439 PrepareFrameAndViewForPrint
prepare(params
, frame
, node
, ignore_css_margins_
);
1440 prepare
.StartPrinting();
1442 *number_of_pages
= prepare
.GetExpectedPageCount();
1446 void PrintWebViewHelper::SetOptionsFromDocument(
1447 PrintHostMsg_SetOptionsFromDocument_Params
& params
) {
1448 blink::WebLocalFrame
* source_frame
= print_preview_context_
.source_frame();
1449 const blink::WebNode
& source_node
= print_preview_context_
.source_node();
1451 blink::WebPrintPresetOptions preset_options
;
1452 if (!source_frame
->getPrintPresetOptionsForPlugin(source_node
,
1457 params
.is_scaling_disabled
= preset_options
.isScalingDisabled
;
1458 params
.copies
= preset_options
.copies
;
1461 bool PrintWebViewHelper::UpdatePrintSettings(
1462 blink::WebLocalFrame
* frame
,
1463 const blink::WebNode
& node
,
1464 const base::DictionaryValue
& passed_job_settings
) {
1465 const base::DictionaryValue
* job_settings
= &passed_job_settings
;
1466 base::DictionaryValue modified_job_settings
;
1467 if (job_settings
->empty()) {
1468 if (!print_for_preview_
)
1469 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1473 bool source_is_html
= true;
1474 if (print_for_preview_
) {
1475 if (!job_settings
->GetBoolean(kSettingPreviewModifiable
, &source_is_html
)) {
1479 source_is_html
= !PrintingNodeOrPdfFrame(frame
, node
);
1482 if (print_for_preview_
|| !source_is_html
) {
1483 modified_job_settings
.MergeDictionary(job_settings
);
1484 modified_job_settings
.SetBoolean(kSettingHeaderFooterEnabled
, false);
1485 modified_job_settings
.SetInteger(kSettingMarginsType
, NO_MARGINS
);
1486 job_settings
= &modified_job_settings
;
1489 // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when
1491 int cookie
= print_pages_params_
?
1492 print_pages_params_
->params
.document_cookie
: 0;
1493 PrintMsg_PrintPages_Params settings
;
1494 bool canceled
= false;
1495 Send(new PrintHostMsg_UpdatePrintSettings(
1496 routing_id(), cookie
, *job_settings
, &settings
, &canceled
));
1498 notify_browser_of_print_failure_
= false;
1502 if (!job_settings
->GetInteger(kPreviewUIID
, &settings
.params
.preview_ui_id
)) {
1504 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1508 if (!print_for_preview_
) {
1509 // Validate expected print preview settings.
1510 if (!job_settings
->GetInteger(kPreviewRequestID
,
1511 &settings
.params
.preview_request_id
) ||
1512 !job_settings
->GetBoolean(kIsFirstRequest
,
1513 &settings
.params
.is_first_request
)) {
1515 print_preview_context_
.set_error(PREVIEW_ERROR_BAD_SETTING
);
1519 settings
.params
.print_to_pdf
= IsPrintToPdfRequested(*job_settings
);
1520 UpdateFrameMarginsCssInfo(*job_settings
);
1521 settings
.params
.print_scaling_option
= GetPrintScalingOption(
1522 frame
, node
, source_is_html
, *job_settings
, settings
.params
);
1525 SetPrintPagesParams(settings
);
1527 if (!PrintMsg_Print_Params_IsValid(settings
.params
)) {
1528 if (!print_for_preview_
)
1529 print_preview_context_
.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS
);
1531 Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
1539 bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame
* frame
,
1540 const blink::WebNode
& node
,
1541 int expected_pages_count
,
1543 PrintHostMsg_ScriptedPrint_Params params
;
1544 PrintMsg_PrintPages_Params print_settings
;
1546 params
.cookie
= print_pages_params_
->params
.document_cookie
;
1547 params
.has_selection
= frame
->hasSelection();
1548 params
.expected_pages_count
= expected_pages_count
;
1549 MarginType margin_type
= DEFAULT_MARGINS
;
1550 if (PrintingNodeOrPdfFrame(frame
, node
))
1551 margin_type
= GetMarginsForPdf(frame
, node
);
1552 params
.margin_type
= margin_type
;
1553 params
.is_scripted
= is_scripted
;
1555 Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));
1557 // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the
1558 // value before and restore it afterwards.
1559 blink::WebPrintScalingOption scaling_option
=
1560 print_pages_params_
->params
.print_scaling_option
;
1562 print_pages_params_
.reset();
1563 IPC::SyncMessage
* msg
=
1564 new PrintHostMsg_ScriptedPrint(routing_id(), params
, &print_settings
);
1565 msg
->EnableMessagePumping();
1567 print_settings
.params
.print_scaling_option
= scaling_option
;
1568 SetPrintPagesParams(print_settings
);
1569 return (print_settings
.params
.dpi
&& print_settings
.params
.document_cookie
);
1572 bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame
* frame
,
1573 const blink::WebNode
& node
) {
1574 if (!frame
|| prep_frame_view_
)
1576 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
1577 const PrintMsg_Print_Params
& print_params
= params
.params
;
1578 prep_frame_view_
.reset(new PrepareFrameAndViewForPrint(
1579 print_params
, frame
, node
, ignore_css_margins_
));
1580 DCHECK(!print_pages_params_
->params
.selection_only
||
1581 print_pages_params_
->pages
.empty());
1582 prep_frame_view_
->CopySelectionIfNeeded(
1583 render_view()->GetWebkitPreferences(),
1584 base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages
,
1585 base::Unretained(this)));
1589 #if defined(OS_POSIX)
1590 bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
1591 PdfMetafileSkia
* metafile
,
1592 base::SharedMemoryHandle
* shared_mem_handle
) {
1593 uint32 buf_size
= metafile
->GetDataSize();
1594 scoped_ptr
<base::SharedMemory
> shared_buf(
1595 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
1596 buf_size
).release());
1599 if (shared_buf
->Map(buf_size
)) {
1600 metafile
->GetData(shared_buf
->memory(), buf_size
);
1601 return shared_buf
->GiveToProcess(base::GetCurrentProcessHandle(),
1607 #endif // defined(OS_POSIX)
1609 void PrintWebViewHelper::ShowScriptedPrintPreview() {
1610 if (is_scripted_preview_delayed_
) {
1611 is_scripted_preview_delayed_
= false;
1612 Send(new PrintHostMsg_ShowScriptedPrintPreview(routing_id(),
1613 print_preview_context_
.IsModifiable()));
1617 void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type
) {
1618 const bool is_modifiable
= print_preview_context_
.IsModifiable();
1619 const bool has_selection
= print_preview_context_
.HasSelection();
1620 PrintHostMsg_RequestPrintPreview_Params params
;
1621 params
.is_modifiable
= is_modifiable
;
1622 params
.has_selection
= has_selection
;
1624 case PRINT_PREVIEW_SCRIPTED
: {
1625 // Shows scripted print preview in two stages.
1626 // 1. PrintHostMsg_SetupScriptedPrintPreview blocks this call and JS by
1627 // pumping messages here.
1628 // 2. PrintHostMsg_ShowScriptedPrintPreview shows preview once the
1629 // document has been loaded.
1630 is_scripted_preview_delayed_
= true;
1631 if (is_loading_
&& GetPlugin(print_preview_context_
.source_frame())) {
1632 // Wait for DidStopLoading. Plugins may not know the correct
1633 // |is_modifiable| value until they are fully loaded, which occurs when
1634 // DidStopLoading() is called. Defer showing the preview until then.
1635 on_stop_loading_closure_
=
1636 base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview
,
1637 base::Unretained(this));
1639 base::MessageLoop::current()->PostTask(
1641 base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview
,
1642 weak_ptr_factory_
.GetWeakPtr()));
1644 IPC::SyncMessage
* msg
=
1645 new PrintHostMsg_SetupScriptedPrintPreview(routing_id());
1646 msg
->EnableMessagePumping();
1648 is_scripted_preview_delayed_
= false;
1651 case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME
: {
1652 // Wait for DidStopLoading. Continuing with this function while
1653 // |is_loading_| is true will cause print preview to hang when try to
1654 // print a PDF document.
1655 if (is_loading_
&& GetPlugin(print_preview_context_
.source_frame())) {
1656 on_stop_loading_closure_
=
1657 base::Bind(&PrintWebViewHelper::RequestPrintPreview
,
1658 base::Unretained(this),
1665 case PRINT_PREVIEW_USER_INITIATED_SELECTION
: {
1666 DCHECK(has_selection
);
1667 DCHECK(!GetPlugin(print_preview_context_
.source_frame()));
1668 params
.selection_only
= has_selection
;
1671 case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE
: {
1672 if (is_loading_
&& GetPlugin(print_preview_context_
.source_frame())) {
1673 on_stop_loading_closure_
=
1674 base::Bind(&PrintWebViewHelper::RequestPrintPreview
,
1675 base::Unretained(this),
1680 params
.webnode_only
= true;
1688 Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params
));
1691 bool PrintWebViewHelper::CheckForCancel() {
1692 const PrintMsg_Print_Params
& print_params
= print_pages_params_
->params
;
1693 bool cancel
= false;
1694 Send(new PrintHostMsg_CheckForCancel(routing_id(),
1695 print_params
.preview_ui_id
,
1696 print_params
.preview_request_id
,
1699 notify_browser_of_print_failure_
= false;
1703 bool PrintWebViewHelper::PreviewPageRendered(int page_number
,
1704 PdfMetafileSkia
* metafile
) {
1705 DCHECK_GE(page_number
, FIRST_PAGE_INDEX
);
1707 // For non-modifiable files, |metafile| should be NULL, so do not bother
1708 // sending a message. If we don't generate draft metafiles, |metafile| is
1710 if (!print_preview_context_
.IsModifiable() ||
1711 !print_preview_context_
.generate_draft_pages()) {
1718 print_preview_context_
.set_error(
1719 PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE
);
1723 PrintHostMsg_DidPreviewPage_Params preview_page_params
;
1724 // Get the size of the resulting metafile.
1725 uint32 buf_size
= metafile
->GetDataSize();
1726 DCHECK_GT(buf_size
, 0u);
1727 if (!CopyMetafileDataToSharedMem(
1728 metafile
, &(preview_page_params
.metafile_data_handle
))) {
1729 LOG(ERROR
) << "CopyMetafileDataToSharedMem failed";
1730 print_preview_context_
.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED
);
1733 preview_page_params
.data_size
= buf_size
;
1734 preview_page_params
.page_number
= page_number
;
1735 preview_page_params
.preview_request_id
=
1736 print_pages_params_
->params
.preview_request_id
;
1738 Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params
));
1742 PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
1743 : total_page_count_(0),
1744 current_page_index_(0),
1745 generate_draft_pages_(true),
1746 print_ready_metafile_page_count_(0),
1747 error_(PREVIEW_ERROR_NONE
),
1748 state_(UNINITIALIZED
) {
1751 PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
1754 void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
1755 blink::WebLocalFrame
* web_frame
) {
1757 DCHECK(!IsRendering());
1758 state_
= INITIALIZED
;
1759 source_frame_
.Reset(web_frame
);
1760 source_node_
.reset();
1763 void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
1764 const blink::WebNode
& web_node
) {
1765 DCHECK(!web_node
.isNull());
1766 DCHECK(web_node
.document().frame());
1767 DCHECK(!IsRendering());
1768 state_
= INITIALIZED
;
1769 source_frame_
.Reset(web_node
.document().frame());
1770 source_node_
= web_node
;
1773 void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
1774 DCHECK_EQ(INITIALIZED
, state_
);
1778 bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
1779 PrepareFrameAndViewForPrint
* prepared_frame
,
1780 const std::vector
<int>& pages
) {
1781 DCHECK_EQ(INITIALIZED
, state_
);
1784 // Need to make sure old object gets destroyed first.
1785 prep_frame_view_
.reset(prepared_frame
);
1786 prep_frame_view_
->StartPrinting();
1788 total_page_count_
= prep_frame_view_
->GetExpectedPageCount();
1789 if (total_page_count_
== 0) {
1790 LOG(ERROR
) << "CreatePreviewDocument got 0 page count";
1791 set_error(PREVIEW_ERROR_ZERO_PAGES
);
1795 metafile_
.reset(new PdfMetafileSkia
);
1796 if (!metafile_
->Init()) {
1797 set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED
);
1798 LOG(ERROR
) << "PdfMetafileSkia Init failed";
1802 current_page_index_
= 0;
1803 pages_to_render_
= pages
;
1804 // Sort and make unique.
1805 std::sort(pages_to_render_
.begin(), pages_to_render_
.end());
1806 pages_to_render_
.resize(std::unique(pages_to_render_
.begin(),
1807 pages_to_render_
.end()) -
1808 pages_to_render_
.begin());
1809 // Remove invalid pages.
1810 pages_to_render_
.resize(std::lower_bound(pages_to_render_
.begin(),
1811 pages_to_render_
.end(),
1812 total_page_count_
) -
1813 pages_to_render_
.begin());
1814 print_ready_metafile_page_count_
= pages_to_render_
.size();
1815 if (pages_to_render_
.empty()) {
1816 print_ready_metafile_page_count_
= total_page_count_
;
1817 // Render all pages.
1818 for (int i
= 0; i
< total_page_count_
; ++i
)
1819 pages_to_render_
.push_back(i
);
1820 } else if (generate_draft_pages_
) {
1821 int pages_index
= 0;
1822 for (int i
= 0; i
< total_page_count_
; ++i
) {
1823 if (pages_index
< print_ready_metafile_page_count_
&&
1824 i
== pages_to_render_
[pages_index
]) {
1828 pages_to_render_
.push_back(i
);
1832 document_render_time_
= base::TimeDelta();
1833 begin_time_
= base::TimeTicks::Now();
1838 void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
1839 const base::TimeDelta
& page_time
) {
1840 DCHECK_EQ(RENDERING
, state_
);
1841 document_render_time_
+= page_time
;
1842 UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time
);
1845 void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
1846 DCHECK_EQ(RENDERING
, state_
);
1848 prep_frame_view_
->FinishPrinting();
1851 void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
1852 DCHECK(IsRendering());
1854 base::TimeTicks begin_time
= base::TimeTicks::Now();
1855 metafile_
->FinishDocument();
1857 if (print_ready_metafile_page_count_
<= 0) {
1862 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
1863 document_render_time_
);
1864 base::TimeDelta total_time
= (base::TimeTicks::Now() - begin_time
) +
1865 document_render_time_
;
1866 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
1868 UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
1869 total_time
/ pages_to_render_
.size());
1872 void PrintWebViewHelper::PrintPreviewContext::Finished() {
1873 DCHECK_EQ(DONE
, state_
);
1874 state_
= INITIALIZED
;
1878 void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error
) {
1879 DCHECK(state_
== INITIALIZED
|| state_
== RENDERING
);
1880 state_
= INITIALIZED
;
1882 DCHECK_NE(PREVIEW_ERROR_NONE
, error_
);
1883 UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_
,
1884 PREVIEW_ERROR_LAST_ENUM
);
1889 int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
1890 DCHECK_EQ(RENDERING
, state_
);
1891 if (IsFinalPageRendered())
1893 return pages_to_render_
[current_page_index_
++];
1896 bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
1897 return state_
== RENDERING
|| state_
== DONE
;
1900 bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
1901 // The only kind of node we can print right now is a PDF node.
1902 return !PrintingNodeOrPdfFrame(source_frame(), source_node_
);
1905 bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
1906 return IsModifiable() && source_frame()->hasSelection();
1909 bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
1911 DCHECK(IsRendering());
1912 return current_page_index_
== print_ready_metafile_page_count_
;
1915 bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
1916 DCHECK(IsRendering());
1917 return static_cast<size_t>(current_page_index_
) == pages_to_render_
.size();
1920 void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
1921 bool generate_draft_pages
) {
1922 DCHECK_EQ(INITIALIZED
, state_
);
1923 generate_draft_pages_
= generate_draft_pages
;
1926 void PrintWebViewHelper::PrintPreviewContext::set_error(
1927 enum PrintPreviewErrorBuckets error
) {
1931 blink::WebLocalFrame
* PrintWebViewHelper::PrintPreviewContext::source_frame() {
1932 DCHECK(state_
!= UNINITIALIZED
);
1933 return source_frame_
.GetFrame();
1936 const blink::WebNode
&
1937 PrintWebViewHelper::PrintPreviewContext::source_node() const {
1938 DCHECK(state_
!= UNINITIALIZED
);
1939 return source_node_
;
1942 blink::WebLocalFrame
*
1943 PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
1944 DCHECK(state_
!= UNINITIALIZED
);
1945 return prep_frame_view_
->frame();
1948 const blink::WebNode
&
1949 PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
1950 DCHECK(state_
!= UNINITIALIZED
);
1951 return prep_frame_view_
->node();
1954 int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
1955 DCHECK(state_
!= UNINITIALIZED
);
1956 return total_page_count_
;
1959 bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
1960 return generate_draft_pages_
;
1963 PdfMetafileSkia
* PrintWebViewHelper::PrintPreviewContext::metafile() {
1964 DCHECK(IsRendering());
1965 return metafile_
.get();
1968 int PrintWebViewHelper::PrintPreviewContext::last_error() const {
1972 void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
1973 prep_frame_view_
.reset();
1975 pages_to_render_
.clear();
1976 error_
= PREVIEW_ERROR_NONE
;
1979 void PrintWebViewHelper::SetPrintPagesParams(
1980 const PrintMsg_PrintPages_Params
& settings
) {
1981 print_pages_params_
.reset(new PrintMsg_PrintPages_Params(settings
));
1982 Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
1983 settings
.params
.document_cookie
));
1986 PrintWebViewHelper::ScriptingThrottler::ScriptingThrottler() : count_(0) {
1989 bool PrintWebViewHelper::ScriptingThrottler::IsAllowed(blink::WebFrame
* frame
) {
1990 const int kMinSecondsToIgnoreJavascriptInitiatedPrint
= 2;
1991 const int kMaxSecondsToIgnoreJavascriptInitiatedPrint
= 32;
1992 bool too_frequent
= false;
1994 // Check if there is script repeatedly trying to print and ignore it if too
1995 // frequent. The first 3 times, we use a constant wait time, but if this
1996 // gets excessive, we switch to exponential wait time. So for a page that
1997 // calls print() in a loop the user will need to cancel the print dialog
1998 // after: [2, 2, 2, 4, 8, 16, 32, 32, ...] seconds.
1999 // This gives the user time to navigate from the page.
2001 base::TimeDelta diff
= base::Time::Now() - last_print_
;
2002 int min_wait_seconds
= kMinSecondsToIgnoreJavascriptInitiatedPrint
;
2005 std::min(kMinSecondsToIgnoreJavascriptInitiatedPrint
<< (count_
- 3),
2006 kMaxSecondsToIgnoreJavascriptInitiatedPrint
);
2008 if (diff
.InSeconds() < min_wait_seconds
) {
2009 too_frequent
= true;
2013 if (!too_frequent
) {
2015 last_print_
= base::Time::Now();
2019 blink::WebString
message(
2020 blink::WebString::fromUTF8("Ignoring too frequent calls to print()."));
2021 frame
->addMessageToConsole(blink::WebConsoleMessage(
2022 blink::WebConsoleMessage::LevelWarning
, message
));
2026 void PrintWebViewHelper::ScriptingThrottler::Reset() {
2027 // Reset counter on successful print.
2031 } // namespace printing