Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / printing / print_web_view_helper.cc
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.
4
5 #include "chrome/renderer/printing/print_web_view_helper.h"
6
7 #include <string>
8
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram.h"
15 #include "base/process/process_handle.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/print_messages.h"
21 #include "chrome/common/render_messages.h"
22 #include "chrome/grit/browser_resources.h"
23 #include "chrome/renderer/prerender/prerender_helper.h"
24 #include "content/public/common/web_preferences.h"
25 #include "content/public/renderer/render_frame.h"
26 #include "content/public/renderer/render_thread.h"
27 #include "content/public/renderer/render_view.h"
28 #include "net/base/escape.h"
29 #include "printing/pdf_metafile_skia.h"
30 #include "printing/units.h"
31 #include "skia/ext/vector_platform_device_skia.h"
32 #include "third_party/WebKit/public/platform/WebSize.h"
33 #include "third_party/WebKit/public/platform/WebURLRequest.h"
34 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
35 #include "third_party/WebKit/public/web/WebDocument.h"
36 #include "third_party/WebKit/public/web/WebElement.h"
37 #include "third_party/WebKit/public/web/WebFrameClient.h"
38 #include "third_party/WebKit/public/web/WebLocalFrame.h"
39 #include "third_party/WebKit/public/web/WebPlugin.h"
40 #include "third_party/WebKit/public/web/WebPluginDocument.h"
41 #include "third_party/WebKit/public/web/WebPrintParams.h"
42 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
43 #include "third_party/WebKit/public/web/WebScriptSource.h"
44 #include "third_party/WebKit/public/web/WebSettings.h"
45 #include "third_party/WebKit/public/web/WebView.h"
46 #include "third_party/WebKit/public/web/WebViewClient.h"
47 #include "ui/base/resource/resource_bundle.h"
48
49 using content::WebPreferences;
50
51 namespace printing {
52
53 namespace {
54
55 enum PrintPreviewHelperEvents {
56   PREVIEW_EVENT_REQUESTED,
57   PREVIEW_EVENT_CACHE_HIT,  // Unused
58   PREVIEW_EVENT_CREATE_DOCUMENT,
59   PREVIEW_EVENT_NEW_SETTINGS,  // Unused
60   PREVIEW_EVENT_MAX,
61 };
62
63 const double kMinDpi = 1.0;
64
65 const char kPageLoadScriptFormat[] =
66     "document.open(); document.write(%s); document.close();";
67
68 const char kPageSetupScriptFormat[] = "setup(%s);";
69
70 #if defined(ENABLE_FULL_PRINTING)
71 bool g_is_preview_enabled_ = true;
72 #else
73 bool g_is_preview_enabled_ = false;
74 #endif
75
76 void ExecuteScript(blink::WebFrame* frame,
77                    const char* script_format,
78                    const base::Value& parameters) {
79   std::string json;
80   base::JSONWriter::Write(&parameters, &json);
81   std::string script = base::StringPrintf(script_format, json.c_str());
82   frame->executeScript(blink::WebString(base::UTF8ToUTF16(script)));
83 }
84
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
88   // on dpi.
89   return kPointsPerInch;
90 #else
91   return static_cast<int>(print_params->dpi);
92 #endif  // defined(OS_MACOSX)
93 }
94
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) &&
100          params.dpi > kMinDpi && params.document_cookie != 0;
101 }
102
103 PrintMsg_Print_Params GetCssPrintParams(
104     blink::WebFrame* frame,
105     int page_index,
106     const PrintMsg_Print_Params& page_params) {
107   PrintMsg_Print_Params page_css_params = page_params;
108   int dpi = GetDPI(&page_params);
109
110   blink::WebSize page_size_in_pixels(
111       ConvertUnit(page_params.page_size.width(), dpi, kPixelsPerInch),
112       ConvertUnit(page_params.page_size.height(), dpi, kPixelsPerInch));
113   int margin_top_in_pixels =
114       ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch);
115   int margin_right_in_pixels = ConvertUnit(
116       page_params.page_size.width() -
117       page_params.content_size.width() - page_params.margin_left,
118       dpi, kPixelsPerInch);
119   int margin_bottom_in_pixels = ConvertUnit(
120       page_params.page_size.height() -
121       page_params.content_size.height() - page_params.margin_top,
122       dpi, kPixelsPerInch);
123   int margin_left_in_pixels = ConvertUnit(
124       page_params.margin_left,
125       dpi, kPixelsPerInch);
126
127   blink::WebSize original_page_size_in_pixels = page_size_in_pixels;
128
129   if (frame) {
130     frame->pageSizeAndMarginsInPixels(page_index,
131                                       page_size_in_pixels,
132                                       margin_top_in_pixels,
133                                       margin_right_in_pixels,
134                                       margin_bottom_in_pixels,
135                                       margin_left_in_pixels);
136   }
137
138   int new_content_width = page_size_in_pixels.width -
139                           margin_left_in_pixels - margin_right_in_pixels;
140   int new_content_height = page_size_in_pixels.height -
141                            margin_top_in_pixels - margin_bottom_in_pixels;
142
143   // Invalid page size and/or margins. We just use the default setting.
144   if (new_content_width < 1 || new_content_height < 1) {
145     CHECK(frame != NULL);
146     page_css_params = GetCssPrintParams(NULL, page_index, page_params);
147     return page_css_params;
148   }
149
150   page_css_params.content_size = gfx::Size(
151       ConvertUnit(new_content_width, kPixelsPerInch, dpi),
152       ConvertUnit(new_content_height, kPixelsPerInch, dpi));
153
154   if (original_page_size_in_pixels != page_size_in_pixels) {
155     page_css_params.page_size = gfx::Size(
156         ConvertUnit(page_size_in_pixels.width, kPixelsPerInch, dpi),
157         ConvertUnit(page_size_in_pixels.height, kPixelsPerInch, dpi));
158   } else {
159     // Printing frame doesn't have any page size css. Pixels to dpi conversion
160     // causes rounding off errors. Therefore use the default page size values
161     // directly.
162     page_css_params.page_size = page_params.page_size;
163   }
164
165   page_css_params.margin_top =
166       ConvertUnit(margin_top_in_pixels, kPixelsPerInch, dpi);
167   page_css_params.margin_left =
168       ConvertUnit(margin_left_in_pixels, kPixelsPerInch, dpi);
169   return page_css_params;
170 }
171
172 double FitPrintParamsToPage(const PrintMsg_Print_Params& page_params,
173                             PrintMsg_Print_Params* params_to_fit) {
174   double content_width =
175       static_cast<double>(params_to_fit->content_size.width());
176   double content_height =
177       static_cast<double>(params_to_fit->content_size.height());
178   int default_page_size_height = page_params.page_size.height();
179   int default_page_size_width = page_params.page_size.width();
180   int css_page_size_height = params_to_fit->page_size.height();
181   int css_page_size_width = params_to_fit->page_size.width();
182
183   double scale_factor = 1.0f;
184   if (page_params.page_size == params_to_fit->page_size)
185     return scale_factor;
186
187   if (default_page_size_width < css_page_size_width ||
188       default_page_size_height < css_page_size_height) {
189     double ratio_width =
190         static_cast<double>(default_page_size_width) / css_page_size_width;
191     double ratio_height =
192         static_cast<double>(default_page_size_height) / css_page_size_height;
193     scale_factor = ratio_width < ratio_height ? ratio_width : ratio_height;
194     content_width *= scale_factor;
195     content_height *= scale_factor;
196   }
197   params_to_fit->margin_top = static_cast<int>(
198       (default_page_size_height - css_page_size_height * scale_factor) / 2 +
199       (params_to_fit->margin_top * scale_factor));
200   params_to_fit->margin_left = static_cast<int>(
201       (default_page_size_width - css_page_size_width * scale_factor) / 2 +
202       (params_to_fit->margin_left * scale_factor));
203   params_to_fit->content_size = gfx::Size(
204       static_cast<int>(content_width), static_cast<int>(content_height));
205   params_to_fit->page_size = page_params.page_size;
206   return scale_factor;
207 }
208
209 void CalculatePageLayoutFromPrintParams(
210     const PrintMsg_Print_Params& params,
211     PageSizeMargins* page_layout_in_points) {
212   int dpi = GetDPI(&params);
213   int content_width = params.content_size.width();
214   int content_height = params.content_size.height();
215
216   int margin_bottom = params.page_size.height() -
217                       content_height - params.margin_top;
218   int margin_right = params.page_size.width() -
219                       content_width - params.margin_left;
220
221   page_layout_in_points->content_width =
222       ConvertUnit(content_width, dpi, kPointsPerInch);
223   page_layout_in_points->content_height =
224       ConvertUnit(content_height, dpi, kPointsPerInch);
225   page_layout_in_points->margin_top =
226       ConvertUnit(params.margin_top, dpi, kPointsPerInch);
227   page_layout_in_points->margin_right =
228       ConvertUnit(margin_right, dpi, kPointsPerInch);
229   page_layout_in_points->margin_bottom =
230       ConvertUnit(margin_bottom, dpi, kPointsPerInch);
231   page_layout_in_points->margin_left =
232       ConvertUnit(params.margin_left, dpi, kPointsPerInch);
233 }
234
235 void EnsureOrientationMatches(const PrintMsg_Print_Params& css_params,
236                               PrintMsg_Print_Params* page_params) {
237   if ((page_params->page_size.width() > page_params->page_size.height()) ==
238       (css_params.page_size.width() > css_params.page_size.height())) {
239     return;
240   }
241
242   // Swap the |width| and |height| values.
243   page_params->page_size.SetSize(page_params->page_size.height(),
244                                  page_params->page_size.width());
245   page_params->content_size.SetSize(page_params->content_size.height(),
246                                     page_params->content_size.width());
247   page_params->printable_area.set_size(
248       gfx::Size(page_params->printable_area.height(),
249                 page_params->printable_area.width()));
250 }
251
252 void ComputeWebKitPrintParamsInDesiredDpi(
253     const PrintMsg_Print_Params& print_params,
254     blink::WebPrintParams* webkit_print_params) {
255   int dpi = GetDPI(&print_params);
256   webkit_print_params->printerDPI = dpi;
257   webkit_print_params->printScalingOption = print_params.print_scaling_option;
258
259   webkit_print_params->printContentArea.width =
260       ConvertUnit(print_params.content_size.width(), dpi,
261                   print_params.desired_dpi);
262   webkit_print_params->printContentArea.height =
263       ConvertUnit(print_params.content_size.height(), dpi,
264                   print_params.desired_dpi);
265
266   webkit_print_params->printableArea.x =
267       ConvertUnit(print_params.printable_area.x(), dpi,
268                   print_params.desired_dpi);
269   webkit_print_params->printableArea.y =
270       ConvertUnit(print_params.printable_area.y(), dpi,
271                   print_params.desired_dpi);
272   webkit_print_params->printableArea.width =
273       ConvertUnit(print_params.printable_area.width(), dpi,
274                   print_params.desired_dpi);
275   webkit_print_params->printableArea.height =
276       ConvertUnit(print_params.printable_area.height(),
277                   dpi, print_params.desired_dpi);
278
279   webkit_print_params->paperSize.width =
280       ConvertUnit(print_params.page_size.width(), dpi,
281                   print_params.desired_dpi);
282   webkit_print_params->paperSize.height =
283       ConvertUnit(print_params.page_size.height(), dpi,
284                   print_params.desired_dpi);
285 }
286
287 blink::WebPlugin* GetPlugin(const blink::WebFrame* frame) {
288   return frame->document().isPluginDocument() ?
289          frame->document().to<blink::WebPluginDocument>().plugin() : NULL;
290 }
291
292 bool PrintingNodeOrPdfFrame(const blink::WebFrame* frame,
293                             const blink::WebNode& node) {
294   if (!node.isNull())
295     return true;
296   blink::WebPlugin* plugin = GetPlugin(frame);
297   return plugin && plugin->supportsPaginatedPrint();
298 }
299
300 bool PrintingFrameHasPageSizeStyle(blink::WebFrame* frame,
301                                    int total_page_count) {
302   if (!frame)
303     return false;
304   bool frame_has_custom_page_size_style = false;
305   for (int i = 0; i < total_page_count; ++i) {
306     if (frame->hasCustomPageSizeStyle(i)) {
307       frame_has_custom_page_size_style = true;
308       break;
309     }
310   }
311   return frame_has_custom_page_size_style;
312 }
313
314 MarginType GetMarginsForPdf(blink::WebFrame* frame,
315                             const blink::WebNode& node) {
316   if (frame->isPrintScalingDisabledForPlugin(node))
317     return NO_MARGINS;
318   else
319     return PRINTABLE_AREA_MARGINS;
320 }
321
322 bool FitToPageEnabled(const base::DictionaryValue& job_settings) {
323   bool fit_to_paper_size = false;
324   if (!job_settings.GetBoolean(kSettingFitToPageEnabled, &fit_to_paper_size)) {
325     NOTREACHED();
326   }
327   return fit_to_paper_size;
328 }
329
330 // Returns the print scaling option to retain/scale/crop the source page size
331 // to fit the printable area of the paper.
332 //
333 // We retain the source page size when the current destination printer is
334 // SAVE_AS_PDF.
335 //
336 // We crop the source page size to fit the printable area or we print only the
337 // left top page contents when
338 // (1) Source is PDF and the user has requested not to fit to printable area
339 // via |job_settings|.
340 // (2) Source is PDF. This is the first preview request and print scaling
341 // option is disabled for initiator renderer plugin.
342 //
343 // In all other cases, we scale the source page to fit the printable area.
344 blink::WebPrintScalingOption GetPrintScalingOption(
345     blink::WebFrame* frame,
346     const blink::WebNode& node,
347     bool source_is_html,
348     const base::DictionaryValue& job_settings,
349     const PrintMsg_Print_Params& params) {
350   if (params.print_to_pdf)
351     return blink::WebPrintScalingOptionSourceSize;
352
353   if (!source_is_html) {
354     if (!FitToPageEnabled(job_settings))
355       return blink::WebPrintScalingOptionNone;
356
357     bool no_plugin_scaling = frame->isPrintScalingDisabledForPlugin(node);
358
359     if (params.is_first_request && no_plugin_scaling)
360       return blink::WebPrintScalingOptionNone;
361   }
362   return blink::WebPrintScalingOptionFitToPrintableArea;
363 }
364
365 PrintMsg_Print_Params CalculatePrintParamsForCss(
366     blink::WebFrame* frame,
367     int page_index,
368     const PrintMsg_Print_Params& page_params,
369     bool ignore_css_margins,
370     bool fit_to_page,
371     double* scale_factor) {
372   PrintMsg_Print_Params css_params = GetCssPrintParams(frame, page_index,
373                                                        page_params);
374
375   PrintMsg_Print_Params params = page_params;
376   EnsureOrientationMatches(css_params, &params);
377
378   if (ignore_css_margins && fit_to_page)
379     return params;
380
381   PrintMsg_Print_Params result_params = css_params;
382   if (ignore_css_margins) {
383     result_params.margin_top = params.margin_top;
384     result_params.margin_left = params.margin_left;
385
386     DCHECK(!fit_to_page);
387     // Since we are ignoring the margins, the css page size is no longer
388     // valid.
389     int default_margin_right = params.page_size.width() -
390         params.content_size.width() - params.margin_left;
391     int default_margin_bottom = params.page_size.height() -
392         params.content_size.height() - params.margin_top;
393     result_params.content_size = gfx::Size(
394         result_params.page_size.width() - result_params.margin_left -
395             default_margin_right,
396         result_params.page_size.height() - result_params.margin_top -
397             default_margin_bottom);
398   }
399
400   if (fit_to_page) {
401     double factor = FitPrintParamsToPage(params, &result_params);
402     if (scale_factor)
403       *scale_factor = factor;
404   }
405   return result_params;
406 }
407
408 }  // namespace
409
410 FrameReference::FrameReference(blink::WebLocalFrame* frame) {
411   Reset(frame);
412 }
413
414 FrameReference::FrameReference() {
415   Reset(NULL);
416 }
417
418 FrameReference::~FrameReference() {
419 }
420
421 void FrameReference::Reset(blink::WebLocalFrame* frame) {
422   if (frame) {
423     view_ = frame->view();
424     frame_ = frame;
425   } else {
426     view_ = NULL;
427     frame_ = NULL;
428   }
429 }
430
431 blink::WebLocalFrame* FrameReference::GetFrame() {
432   if (view_ == NULL || frame_ == NULL)
433     return NULL;
434   for (blink::WebFrame* frame = view_->mainFrame(); frame != NULL;
435            frame = frame->traverseNext(false)) {
436     if (frame == frame_)
437       return frame_;
438   }
439   return NULL;
440 }
441
442 blink::WebView* FrameReference::view() {
443   return view_;
444 }
445
446 // static - Not anonymous so that platform implementations can use it.
447 void PrintWebViewHelper::PrintHeaderAndFooter(
448     blink::WebCanvas* canvas,
449     int page_number,
450     int total_pages,
451     const blink::WebFrame& source_frame,
452     float webkit_scale_factor,
453     const PageSizeMargins& page_layout,
454     const PrintMsg_Print_Params& params) {
455   skia::VectorPlatformDeviceSkia* device =
456       static_cast<skia::VectorPlatformDeviceSkia*>(canvas->getTopDevice());
457   device->setDrawingArea(SkPDFDevice::kMargin_DrawingArea);
458
459   SkAutoCanvasRestore auto_restore(canvas, true);
460   canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor);
461
462   blink::WebSize page_size(page_layout.margin_left + page_layout.margin_right +
463                                page_layout.content_width,
464                            page_layout.margin_top + page_layout.margin_bottom +
465                                page_layout.content_height);
466
467   blink::WebView* web_view = blink::WebView::create(NULL);
468   web_view->settings()->setJavaScriptEnabled(true);
469
470   blink::WebLocalFrame* frame = blink::WebLocalFrame::create(NULL);
471   web_view->setMainFrame(frame);
472
473   base::StringValue html(ResourceBundle::GetSharedInstance().GetLocalizedString(
474       IDR_PRINT_PREVIEW_PAGE));
475   // Load page with script to avoid async operations.
476   ExecuteScript(frame, kPageLoadScriptFormat, html);
477
478   scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue());
479   options.reset(new base::DictionaryValue());
480   options->SetDouble(kSettingHeaderFooterDate, base::Time::Now().ToJsTime());
481   options->SetDouble("width", page_size.width);
482   options->SetDouble("height", page_size.height);
483   options->SetDouble("topMargin", page_layout.margin_top);
484   options->SetDouble("bottomMargin", page_layout.margin_bottom);
485   options->SetString("pageNumber",
486                      base::StringPrintf("%d/%d", page_number, total_pages));
487
488   // Fallback to initiator URL and title if it's empty for printed frame.
489   base::string16 url = source_frame.document().url().string();
490   options->SetString("url", url.empty() ? params.url : url);
491   base::string16 title = source_frame.document().title();
492   options->SetString("title", title.empty() ? params.title : title);
493
494   ExecuteScript(frame, kPageSetupScriptFormat, *options);
495
496   blink::WebPrintParams webkit_params(page_size);
497   webkit_params.printerDPI = GetDPI(&params);
498
499   frame->printBegin(webkit_params);
500   frame->printPage(0, canvas);
501   frame->printEnd();
502
503   web_view->close();
504   frame->close();
505
506   device->setDrawingArea(SkPDFDevice::kContent_DrawingArea);
507 }
508
509 // static - Not anonymous so that platform implementations can use it.
510 float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame,
511                                             int page_number,
512                                             const gfx::Rect& canvas_area,
513                                             const gfx::Rect& content_area,
514                                             double scale_factor,
515                                             blink::WebCanvas* canvas) {
516   SkAutoCanvasRestore auto_restore(canvas, true);
517   if (content_area != canvas_area) {
518     canvas->translate((content_area.x() - canvas_area.x()) / scale_factor,
519                       (content_area.y() - canvas_area.y()) / scale_factor);
520     SkRect clip_rect(
521         SkRect::MakeXYWH(content_area.origin().x() / scale_factor,
522                          content_area.origin().y() / scale_factor,
523                          content_area.size().width() / scale_factor,
524                          content_area.size().height() / scale_factor));
525     SkIRect clip_int_rect;
526     clip_rect.roundOut(&clip_int_rect);
527     SkRegion clip_region(clip_int_rect);
528     canvas->setClipRegion(clip_region);
529   }
530   return frame->printPage(page_number, canvas);
531 }
532
533 // Class that calls the Begin and End print functions on the frame and changes
534 // the size of the view temporarily to support full page printing..
535 class PrepareFrameAndViewForPrint : public blink::WebViewClient,
536                                     public blink::WebFrameClient {
537  public:
538   PrepareFrameAndViewForPrint(const PrintMsg_Print_Params& params,
539                               blink::WebLocalFrame* frame,
540                               const blink::WebNode& node,
541                               bool ignore_css_margins);
542   virtual ~PrepareFrameAndViewForPrint();
543
544   // Optional. Replaces |frame_| with selection if needed. Will call |on_ready|
545   // when completed.
546   void CopySelectionIfNeeded(const WebPreferences& preferences,
547                              const base::Closure& on_ready);
548
549   // Prepares frame for printing.
550   void StartPrinting();
551
552   blink::WebLocalFrame* frame() {
553     return frame_.GetFrame();
554   }
555
556   const blink::WebNode& node() const {
557     return node_to_print_;
558   }
559
560   int GetExpectedPageCount() const {
561     return expected_pages_count_;
562   }
563
564   void FinishPrinting();
565
566   bool IsLoadingSelection() {
567     // It's not selection if not |owns_web_view_|.
568     return owns_web_view_ && frame() && frame()->isLoading();
569   }
570
571   // TODO(ojan): Remove this override and have this class use a non-null
572   // layerTreeView.
573   // blink::WebViewClient override:
574   virtual bool allowsBrokenNullLayerTreeView() const;
575
576  protected:
577   // blink::WebViewClient override:
578   virtual void didStopLoading();
579
580   // blink::WebFrameClient override:
581   virtual blink::WebFrame* createChildFrame(blink::WebLocalFrame* parent,
582                                             const blink::WebString& name);
583   virtual void frameDetached(blink::WebFrame* frame);
584
585  private:
586   void CallOnReady();
587   void ResizeForPrinting();
588   void RestoreSize();
589   void CopySelection(const WebPreferences& preferences);
590
591   base::WeakPtrFactory<PrepareFrameAndViewForPrint> weak_ptr_factory_;
592
593   FrameReference frame_;
594   blink::WebNode node_to_print_;
595   bool owns_web_view_;
596   blink::WebPrintParams web_print_params_;
597   gfx::Size prev_view_size_;
598   gfx::Size prev_scroll_offset_;
599   int expected_pages_count_;
600   base::Closure on_ready_;
601   bool should_print_backgrounds_;
602   bool should_print_selection_only_;
603   bool is_printing_started_;
604
605   DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint);
606 };
607
608 PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
609     const PrintMsg_Print_Params& params,
610     blink::WebLocalFrame* frame,
611     const blink::WebNode& node,
612     bool ignore_css_margins)
613     : weak_ptr_factory_(this),
614       frame_(frame),
615       node_to_print_(node),
616       owns_web_view_(false),
617       expected_pages_count_(0),
618       should_print_backgrounds_(params.should_print_backgrounds),
619       should_print_selection_only_(params.selection_only),
620       is_printing_started_(false) {
621   PrintMsg_Print_Params print_params = params;
622   if (!should_print_selection_only_ ||
623       !PrintingNodeOrPdfFrame(frame, node_to_print_)) {
624     bool fit_to_page = ignore_css_margins &&
625                        print_params.print_scaling_option ==
626                             blink::WebPrintScalingOptionFitToPrintableArea;
627     ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_);
628     frame->printBegin(web_print_params_, node_to_print_);
629     print_params = CalculatePrintParamsForCss(frame, 0, print_params,
630                                               ignore_css_margins, fit_to_page,
631                                               NULL);
632     frame->printEnd();
633   }
634   ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_);
635 }
636
637 PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
638   FinishPrinting();
639 }
640
641 void PrepareFrameAndViewForPrint::ResizeForPrinting() {
642   // Layout page according to printer page size. Since WebKit shrinks the
643   // size of the page automatically (from 125% to 200%) we trick it to
644   // think the page is 125% larger so the size of the page is correct for
645   // minimum (default) scaling.
646   // This is important for sites that try to fill the page.
647   gfx::Size print_layout_size(web_print_params_.printContentArea.width,
648                               web_print_params_.printContentArea.height);
649   print_layout_size.set_height(
650       static_cast<int>(static_cast<double>(print_layout_size.height()) * 1.25));
651
652   if (!frame())
653     return;
654   blink::WebView* web_view = frame_.view();
655   // Backup size and offset.
656   if (blink::WebFrame* web_frame = web_view->mainFrame())
657     prev_scroll_offset_ = web_frame->scrollOffset();
658   prev_view_size_ = web_view->size();
659
660   web_view->resize(print_layout_size);
661 }
662
663
664 void PrepareFrameAndViewForPrint::StartPrinting() {
665   ResizeForPrinting();
666   blink::WebView* web_view = frame_.view();
667   web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_);
668   expected_pages_count_ =
669       frame()->printBegin(web_print_params_, node_to_print_);
670   is_printing_started_ = true;
671 }
672
673 void PrepareFrameAndViewForPrint::CopySelectionIfNeeded(
674     const WebPreferences& preferences,
675     const base::Closure& on_ready) {
676   on_ready_ = on_ready;
677   if (should_print_selection_only_) {
678     CopySelection(preferences);
679   } else {
680     // Call immediately, async call crashes scripting printing.
681     CallOnReady();
682   }
683 }
684
685 void PrepareFrameAndViewForPrint::CopySelection(
686     const WebPreferences& preferences) {
687   ResizeForPrinting();
688   std::string url_str = "data:text/html;charset=utf-8,";
689   url_str.append(
690       net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false));
691   RestoreSize();
692   // Create a new WebView with the same settings as the current display one.
693   // Except that we disable javascript (don't want any active content running
694   // on the page).
695   WebPreferences prefs = preferences;
696   prefs.javascript_enabled = false;
697   prefs.java_enabled = false;
698
699   blink::WebView* web_view = blink::WebView::create(this);
700   owns_web_view_ = true;
701   content::RenderView::ApplyWebPreferences(prefs, web_view);
702   web_view->setMainFrame(blink::WebLocalFrame::create(this));
703   frame_.Reset(web_view->mainFrame()->toWebLocalFrame());
704   node_to_print_.reset();
705
706   // When loading is done this will call didStopLoading() and that will do the
707   // actual printing.
708   frame()->loadRequest(blink::WebURLRequest(GURL(url_str)));
709 }
710
711 bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
712   return true;
713 }
714
715 void PrepareFrameAndViewForPrint::didStopLoading() {
716   DCHECK(!on_ready_.is_null());
717   // Don't call callback here, because it can delete |this| and WebView that is
718   // called didStopLoading.
719   base::MessageLoop::current()->PostTask(
720       FROM_HERE,
721       base::Bind(&PrepareFrameAndViewForPrint::CallOnReady,
722                  weak_ptr_factory_.GetWeakPtr()));
723 }
724
725 blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame(
726     blink::WebLocalFrame* parent,
727     const blink::WebString& name) {
728   blink::WebFrame* frame = blink::WebLocalFrame::create(this);
729   parent->appendChild(frame);
730   return frame;
731 }
732
733 void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame) {
734   if (frame->parent())
735     frame->parent()->removeChild(frame);
736   frame->close();
737 }
738
739 void PrepareFrameAndViewForPrint::CallOnReady() {
740   return on_ready_.Run();  // Can delete |this|.
741 }
742
743 void PrepareFrameAndViewForPrint::RestoreSize() {
744   if (frame()) {
745     blink::WebView* web_view = frame_.GetFrame()->view();
746     web_view->resize(prev_view_size_);
747     if (blink::WebFrame* web_frame = web_view->mainFrame())
748       web_frame->setScrollOffset(prev_scroll_offset_);
749   }
750 }
751
752 void PrepareFrameAndViewForPrint::FinishPrinting() {
753   blink::WebLocalFrame* frame = frame_.GetFrame();
754   if (frame) {
755     blink::WebView* web_view = frame->view();
756     if (is_printing_started_) {
757       is_printing_started_ = false;
758       frame->printEnd();
759       if (!owns_web_view_) {
760         web_view->settings()->setShouldPrintBackgrounds(false);
761         RestoreSize();
762       }
763     }
764     if (owns_web_view_) {
765       DCHECK(!frame->isLoading());
766       owns_web_view_ = false;
767       web_view->close();
768     }
769   }
770   frame_.Reset(NULL);
771   on_ready_.Reset();
772 }
773
774 PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view)
775     : content::RenderViewObserver(render_view),
776       content::RenderViewObserverTracker<PrintWebViewHelper>(render_view),
777       reset_prep_frame_view_(false),
778       is_print_ready_metafile_sent_(false),
779       ignore_css_margins_(false),
780       is_scripted_printing_blocked_(false),
781       notify_browser_of_print_failure_(true),
782       print_for_preview_(false),
783       print_node_in_progress_(false),
784       is_loading_(false),
785       is_scripted_preview_delayed_(false),
786       weak_ptr_factory_(this) {
787   if (CommandLine::ForCurrentProcess()->HasSwitch(
788           switches::kDisablePrintPreview)) {
789     DisablePreview();
790   }
791 }
792
793 PrintWebViewHelper::~PrintWebViewHelper() {}
794
795 // static
796 void PrintWebViewHelper::DisablePreview() {
797   g_is_preview_enabled_ = false;
798 }
799
800 bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
801     blink::WebFrame* frame, bool user_initiated) {
802 #if defined(OS_ANDROID)
803   return false;
804 #endif  // defined(OS_ANDROID)
805   // If preview is enabled, then the print dialog is tab modal, and the user
806   // can always close the tab on a mis-behaving page (the system print dialog
807   // is app modal). If the print was initiated through user action, don't
808   // throttle. Or, if the command line flag to skip throttling has been set.
809   return !is_scripted_printing_blocked_ &&
810          (user_initiated || g_is_preview_enabled_ ||
811           scripting_throttler_.IsAllowed(frame));
812 }
813
814 void PrintWebViewHelper::DidStartLoading() {
815   is_loading_ = true;
816 }
817
818 void PrintWebViewHelper::DidStopLoading() {
819   is_loading_ = false;
820   if (!on_stop_loading_closure_.is_null()) {
821     on_stop_loading_closure_.Run();
822     on_stop_loading_closure_.Reset();
823   }
824 }
825
826 // Prints |frame| which called window.print().
827 void PrintWebViewHelper::PrintPage(blink::WebLocalFrame* frame,
828                                    bool user_initiated) {
829   DCHECK(frame);
830
831   // Allow Prerendering to cancel this print request if necessary.
832   if (prerender::PrerenderHelper::IsPrerendering(
833           render_view()->GetMainRenderFrame())) {
834     Send(new ChromeViewHostMsg_CancelPrerenderForPrinting(routing_id()));
835     return;
836   }
837
838   if (!IsScriptInitiatedPrintAllowed(frame, user_initiated))
839     return;
840
841   if (!g_is_preview_enabled_) {
842     Print(frame, blink::WebNode());
843   } else {
844     print_preview_context_.InitWithFrame(frame);
845     RequestPrintPreview(PRINT_PREVIEW_SCRIPTED);
846   }
847 }
848
849 bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
850   bool handled = true;
851   IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message)
852 #if !defined(DISABLE_BASIC_PRINTING)
853     IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages)
854     IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog)
855 #endif  // !DISABLE_BASIC_PRINTING
856     IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview, OnInitiatePrintPreview)
857     IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview)
858     IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview, OnPrintForPrintPreview)
859     IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone)
860     IPC_MESSAGE_HANDLER(PrintMsg_SetScriptedPrintingBlocked,
861                         SetScriptedPrintBlocked)
862     IPC_MESSAGE_UNHANDLED(handled = false)
863     IPC_END_MESSAGE_MAP()
864   return handled;
865 }
866
867 void PrintWebViewHelper::OnPrintForPrintPreview(
868     const base::DictionaryValue& job_settings) {
869   // If still not finished with earlier print request simply ignore.
870   if (prep_frame_view_)
871     return;
872
873   if (!render_view()->GetWebView())
874     return;
875   blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
876   if (!main_frame)
877     return;
878
879   blink::WebDocument document = main_frame->document();
880   // <object>/<iframe> with id="pdf-viewer" is created in
881   // chrome/browser/resources/print_preview/print_preview.js
882   blink::WebElement pdf_element = document.getElementById("pdf-viewer");
883   if (pdf_element.isNull()) {
884     NOTREACHED();
885     return;
886   }
887
888   // The out-of-process plugin element is nested within a frame.
889   blink::WebLocalFrame* plugin_frame = pdf_element.document().frame();
890   blink::WebElement plugin_element = pdf_element;
891   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kOutOfProcessPdf)) {
892     if (!pdf_element.hasHTMLTagName("iframe")) {
893       NOTREACHED();
894       return;
895     }
896     plugin_frame = blink::WebLocalFrame::fromFrameOwnerElement(pdf_element);
897     // <object> with id="plugin" is created in
898     // chrome/browser/resources/pdf/pdf.js.
899     plugin_element = plugin_frame->document().getElementById("plugin");
900     if (plugin_element.isNull()) {
901       NOTREACHED();
902       return;
903     }
904   }
905
906   // Set |print_for_preview_| flag and autoreset it to back to original
907   // on return.
908   base::AutoReset<bool> set_printing_flag(&print_for_preview_, true);
909
910   if (!UpdatePrintSettings(plugin_frame, plugin_element, job_settings)) {
911     LOG(ERROR) << "UpdatePrintSettings failed";
912     DidFinishPrinting(FAIL_PRINT);
913     return;
914   }
915
916   // Print page onto entire page not just printable area. Preview PDF already
917   // has content in correct position taking into account page size and printable
918   // area.
919   // TODO(vitalybuka) : Make this consistent on all platform. This change
920   // affects Windows only. On Linux and OSX RenderPagesForPrint does not use
921   // printable_area. Also we can't change printable_area deeper inside
922   // RenderPagesForPrint for Windows, because it's used also by native
923   // printing and it expects real printable_area value.
924   // See http://crbug.com/123408
925   PrintMsg_Print_Params& print_params = print_pages_params_->params;
926   print_params.printable_area = gfx::Rect(print_params.page_size);
927
928   // Render Pages for printing.
929   if (!RenderPagesForPrint(plugin_frame, plugin_element)) {
930     LOG(ERROR) << "RenderPagesForPrint failed";
931     DidFinishPrinting(FAIL_PRINT);
932   }
933 }
934
935 bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) {
936   DCHECK(frame);
937   blink::WebView* webView = render_view()->GetWebView();
938   DCHECK(webView);
939   if (!webView)
940     return false;
941
942   // If the user has selected text in the currently focused frame we print
943   // only that frame (this makes print selection work for multiple frames).
944   blink::WebLocalFrame* focusedFrame =
945       webView->focusedFrame()->toWebLocalFrame();
946   *frame = focusedFrame->hasSelection()
947                ? focusedFrame
948                : webView->mainFrame()->toWebLocalFrame();
949   return true;
950 }
951
952 #if !defined(DISABLE_BASIC_PRINTING)
953 void PrintWebViewHelper::OnPrintPages() {
954   blink::WebLocalFrame* frame;
955   if (GetPrintFrame(&frame))
956     Print(frame, blink::WebNode());
957 }
958
959 void PrintWebViewHelper::OnPrintForSystemDialog() {
960   blink::WebLocalFrame* frame = print_preview_context_.source_frame();
961   if (!frame) {
962     NOTREACHED();
963     return;
964   }
965   Print(frame, print_preview_context_.source_node());
966 }
967 #endif  // !DISABLE_BASIC_PRINTING
968
969 void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
970     const PageSizeMargins& page_layout_in_points,
971     gfx::Size* page_size,
972     gfx::Rect* content_area) {
973   *page_size = gfx::Size(
974       page_layout_in_points.content_width +
975           page_layout_in_points.margin_right +
976           page_layout_in_points.margin_left,
977       page_layout_in_points.content_height +
978           page_layout_in_points.margin_top +
979           page_layout_in_points.margin_bottom);
980   *content_area = gfx::Rect(page_layout_in_points.margin_left,
981                             page_layout_in_points.margin_top,
982                             page_layout_in_points.content_width,
983                             page_layout_in_points.content_height);
984 }
985
986 void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
987     const base::DictionaryValue& settings) {
988   int margins_type = 0;
989   if (!settings.GetInteger(kSettingMarginsType, &margins_type))
990     margins_type = DEFAULT_MARGINS;
991   ignore_css_margins_ = (margins_type != DEFAULT_MARGINS);
992 }
993
994 bool PrintWebViewHelper::IsPrintToPdfRequested(
995     const base::DictionaryValue& job_settings) {
996   bool print_to_pdf = false;
997   if (!job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf))
998     NOTREACHED();
999   return print_to_pdf;
1000 }
1001
1002 void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) {
1003   print_preview_context_.OnPrintPreview();
1004
1005   UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
1006                             PREVIEW_EVENT_REQUESTED, PREVIEW_EVENT_MAX);
1007
1008   if (!print_preview_context_.source_frame()) {
1009     DidFinishPrinting(FAIL_PREVIEW);
1010     return;
1011   }
1012
1013   if (!UpdatePrintSettings(print_preview_context_.source_frame(),
1014                            print_preview_context_.source_node(), settings)) {
1015     if (print_preview_context_.last_error() != PREVIEW_ERROR_BAD_SETTING) {
1016       Send(new PrintHostMsg_PrintPreviewInvalidPrinterSettings(
1017           routing_id(),
1018           print_pages_params_ ?
1019               print_pages_params_->params.document_cookie : 0));
1020       notify_browser_of_print_failure_ = false;  // Already sent.
1021     }
1022     DidFinishPrinting(FAIL_PREVIEW);
1023     return;
1024   }
1025
1026   // Set the options from document if we are previewing a pdf and send a
1027   // message to browser.
1028   if (print_pages_params_->params.is_first_request &&
1029       !print_preview_context_.IsModifiable()) {
1030     PrintHostMsg_SetOptionsFromDocument_Params params;
1031     SetOptionsFromDocument(params);
1032     Send(new PrintHostMsg_SetOptionsFromDocument(routing_id(), params));
1033   }
1034
1035   is_print_ready_metafile_sent_ = false;
1036
1037   // PDF printer device supports alpha blending.
1038   print_pages_params_->params.supports_alpha_blend = true;
1039
1040   bool generate_draft_pages = false;
1041   if (!settings.GetBoolean(kSettingGenerateDraftData,
1042                            &generate_draft_pages)) {
1043     NOTREACHED();
1044   }
1045   print_preview_context_.set_generate_draft_pages(generate_draft_pages);
1046
1047   PrepareFrameForPreviewDocument();
1048 }
1049
1050 void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
1051   reset_prep_frame_view_ = false;
1052
1053   if (!print_pages_params_ || CheckForCancel()) {
1054     DidFinishPrinting(FAIL_PREVIEW);
1055     return;
1056   }
1057
1058   // Don't reset loading frame or WebKit will fail assert. Just retry when
1059   // current selection is loaded.
1060   if (prep_frame_view_ && prep_frame_view_->IsLoadingSelection()) {
1061     reset_prep_frame_view_ = true;
1062     return;
1063   }
1064
1065   const PrintMsg_Print_Params& print_params = print_pages_params_->params;
1066   prep_frame_view_.reset(
1067       new PrepareFrameAndViewForPrint(print_params,
1068                                       print_preview_context_.source_frame(),
1069                                       print_preview_context_.source_node(),
1070                                       ignore_css_margins_));
1071   prep_frame_view_->CopySelectionIfNeeded(
1072       render_view()->GetWebkitPreferences(),
1073       base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument,
1074                  base::Unretained(this)));
1075 }
1076
1077 void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
1078   if (reset_prep_frame_view_) {
1079     PrepareFrameForPreviewDocument();
1080     return;
1081   }
1082   DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW);
1083 }
1084
1085 bool PrintWebViewHelper::CreatePreviewDocument() {
1086   if (!print_pages_params_ || CheckForCancel())
1087     return false;
1088
1089   UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
1090                             PREVIEW_EVENT_CREATE_DOCUMENT, PREVIEW_EVENT_MAX);
1091
1092   const PrintMsg_Print_Params& print_params = print_pages_params_->params;
1093   const std::vector<int>& pages = print_pages_params_->pages;
1094
1095   if (!print_preview_context_.CreatePreviewDocument(prep_frame_view_.release(),
1096                                                     pages)) {
1097     return false;
1098   }
1099
1100   PageSizeMargins default_page_layout;
1101   ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(), 0,
1102                                   print_params, ignore_css_margins_, NULL,
1103                                   &default_page_layout);
1104
1105   bool has_page_size_style = PrintingFrameHasPageSizeStyle(
1106       print_preview_context_.prepared_frame(),
1107       print_preview_context_.total_page_count());
1108   int dpi = GetDPI(&print_params);
1109
1110   gfx::Rect printable_area_in_points(
1111       ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch),
1112       ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch),
1113       ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch),
1114       ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch));
1115
1116   // Margins: Send default page layout to browser process.
1117   Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
1118                                                 default_page_layout,
1119                                                 printable_area_in_points,
1120                                                 has_page_size_style));
1121
1122   PrintHostMsg_DidGetPreviewPageCount_Params params;
1123   params.page_count = print_preview_context_.total_page_count();
1124   params.is_modifiable = print_preview_context_.IsModifiable();
1125   params.document_cookie = print_params.document_cookie;
1126   params.preview_request_id = print_params.preview_request_id;
1127   params.clear_preview_data = print_preview_context_.generate_draft_pages();
1128   Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params));
1129   if (CheckForCancel())
1130     return false;
1131
1132   while (!print_preview_context_.IsFinalPageRendered()) {
1133     int page_number = print_preview_context_.GetNextPageNumber();
1134     DCHECK_GE(page_number, 0);
1135     if (!RenderPreviewPage(page_number, print_params))
1136       return false;
1137
1138     if (CheckForCancel())
1139       return false;
1140
1141     // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of
1142     // print_preview_context_.AllPagesRendered()) before calling
1143     // FinalizePrintReadyDocument() when printing a PDF because the plugin
1144     // code does not generate output until we call FinishPrinting().  We do not
1145     // generate draft pages for PDFs, so IsFinalPageRendered() and
1146     // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of
1147     // the loop.
1148     if (print_preview_context_.IsFinalPageRendered())
1149       print_preview_context_.AllPagesRendered();
1150
1151     if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) {
1152       DCHECK(print_preview_context_.IsModifiable() ||
1153              print_preview_context_.IsFinalPageRendered());
1154       if (!FinalizePrintReadyDocument())
1155         return false;
1156     }
1157   }
1158   print_preview_context_.Finished();
1159   return true;
1160 }
1161
1162 bool PrintWebViewHelper::FinalizePrintReadyDocument() {
1163   DCHECK(!is_print_ready_metafile_sent_);
1164   print_preview_context_.FinalizePrintReadyDocument();
1165
1166   // Get the size of the resulting metafile.
1167   PdfMetafileSkia* metafile = print_preview_context_.metafile();
1168   uint32 buf_size = metafile->GetDataSize();
1169   DCHECK_GT(buf_size, 0u);
1170
1171   PrintHostMsg_DidPreviewDocument_Params preview_params;
1172   preview_params.data_size = buf_size;
1173   preview_params.document_cookie = print_pages_params_->params.document_cookie;
1174   preview_params.expected_pages_count =
1175       print_preview_context_.total_page_count();
1176   preview_params.modifiable = print_preview_context_.IsModifiable();
1177   preview_params.preview_request_id =
1178       print_pages_params_->params.preview_request_id;
1179
1180   // Ask the browser to create the shared memory for us.
1181   if (!CopyMetafileDataToSharedMem(metafile,
1182                                    &(preview_params.metafile_data_handle))) {
1183     LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
1184     print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
1185     return false;
1186   }
1187   is_print_ready_metafile_sent_ = true;
1188
1189   Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params));
1190   return true;
1191 }
1192
1193 void PrintWebViewHelper::OnPrintingDone(bool success) {
1194   notify_browser_of_print_failure_ = false;
1195   if (!success)
1196     LOG(ERROR) << "Failure in OnPrintingDone";
1197   DidFinishPrinting(success ? OK : FAIL_PRINT);
1198 }
1199
1200 void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked) {
1201   is_scripted_printing_blocked_ = blocked;
1202 }
1203
1204 void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only) {
1205   blink::WebLocalFrame* frame = NULL;
1206   GetPrintFrame(&frame);
1207   DCHECK(frame);
1208   print_preview_context_.InitWithFrame(frame);
1209   RequestPrintPreview(selection_only ?
1210                       PRINT_PREVIEW_USER_INITIATED_SELECTION :
1211                       PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME);
1212 }
1213
1214 bool PrintWebViewHelper::IsPrintingEnabled() {
1215   bool result = false;
1216   Send(new PrintHostMsg_IsPrintingEnabled(routing_id(), &result));
1217   return result;
1218 }
1219
1220 void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
1221   if (node.isNull() || !node.document().frame()) {
1222     // This can occur when the context menu refers to an invalid WebNode.
1223     // See http://crbug.com/100890#c17 for a repro case.
1224     return;
1225   }
1226
1227   if (print_node_in_progress_) {
1228     // This can happen as a result of processing sync messages when printing
1229     // from ppapi plugins. It's a rare case, so its OK to just fail here.
1230     // See http://crbug.com/159165.
1231     return;
1232   }
1233
1234   print_node_in_progress_ = true;
1235
1236   // Make a copy of the node, in case RenderView::OnContextMenuClosed resets
1237   // its |context_menu_node_|.
1238   if (!g_is_preview_enabled_) {
1239     blink::WebNode duplicate_node(node);
1240     Print(duplicate_node.document().frame(), duplicate_node);
1241   } else {
1242     print_preview_context_.InitWithNode(node);
1243     RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE);
1244   }
1245
1246   print_node_in_progress_ = false;
1247 }
1248
1249 void PrintWebViewHelper::Print(blink::WebLocalFrame* frame,
1250                                const blink::WebNode& node) {
1251   // If still not finished with earlier print request simply ignore.
1252   if (prep_frame_view_)
1253     return;
1254
1255   FrameReference frame_ref(frame);
1256
1257   int expected_page_count = 0;
1258   if (!CalculateNumberOfPages(frame, node, &expected_page_count)) {
1259     DidFinishPrinting(FAIL_PRINT_INIT);
1260     return;  // Failed to init print page settings.
1261   }
1262
1263   // Some full screen plugins can say they don't want to print.
1264   if (!expected_page_count) {
1265     DidFinishPrinting(FAIL_PRINT);
1266     return;
1267   }
1268
1269   // Ask the browser to show UI to retrieve the final print settings.
1270   if (!GetPrintSettingsFromUser(frame_ref.GetFrame(), node,
1271                                 expected_page_count)) {
1272     DidFinishPrinting(OK);  // Release resources and fail silently.
1273     return;
1274   }
1275
1276   // Render Pages for printing.
1277   if (!RenderPagesForPrint(frame_ref.GetFrame(), node)) {
1278     LOG(ERROR) << "RenderPagesForPrint failed";
1279     DidFinishPrinting(FAIL_PRINT);
1280   }
1281   scripting_throttler_.Reset();
1282 }
1283
1284 void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
1285   switch (result) {
1286     case OK:
1287       break;
1288
1289     case FAIL_PRINT_INIT:
1290       DCHECK(!notify_browser_of_print_failure_);
1291       break;
1292
1293     case FAIL_PRINT:
1294       if (notify_browser_of_print_failure_ && print_pages_params_) {
1295         int cookie = print_pages_params_->params.document_cookie;
1296         Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
1297       }
1298       break;
1299
1300     case FAIL_PREVIEW:
1301       int cookie = print_pages_params_ ?
1302           print_pages_params_->params.document_cookie : 0;
1303       if (notify_browser_of_print_failure_) {
1304         LOG(ERROR) << "CreatePreviewDocument failed";
1305         Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie));
1306       } else {
1307         Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie));
1308       }
1309       print_preview_context_.Failed(notify_browser_of_print_failure_);
1310       break;
1311   }
1312   prep_frame_view_.reset();
1313   print_pages_params_.reset();
1314   notify_browser_of_print_failure_ = true;
1315 }
1316
1317 void PrintWebViewHelper::OnFramePreparedForPrintPages() {
1318   PrintPages();
1319   FinishFramePrinting();
1320 }
1321
1322 void PrintWebViewHelper::PrintPages() {
1323   if (!prep_frame_view_)  // Printing is already canceled or failed.
1324     return;
1325   prep_frame_view_->StartPrinting();
1326
1327   int page_count = prep_frame_view_->GetExpectedPageCount();
1328   if (!page_count) {
1329     LOG(ERROR) << "Can't print 0 pages.";
1330     return DidFinishPrinting(FAIL_PRINT);
1331   }
1332
1333   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
1334   const PrintMsg_Print_Params& print_params = params.params;
1335
1336 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
1337   // TODO(vitalybuka): should be page_count or valid pages from params.pages.
1338   // See http://crbug.com/161576
1339   Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
1340                                                 print_params.document_cookie,
1341                                                 page_count));
1342 #endif  // !defined(OS_CHROMEOS)
1343
1344   if (print_params.preview_ui_id < 0) {
1345     // Printing for system dialog.
1346     int printed_count = params.pages.empty() ? page_count : params.pages.size();
1347 #if !defined(OS_CHROMEOS)
1348     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count);
1349 #else
1350     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1351                          printed_count);
1352 #endif  // !defined(OS_CHROMEOS)
1353   }
1354
1355
1356   if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) {
1357     LOG(ERROR) << "Printing failed.";
1358     return DidFinishPrinting(FAIL_PRINT);
1359   }
1360 }
1361
1362 void PrintWebViewHelper::FinishFramePrinting() {
1363   prep_frame_view_.reset();
1364 }
1365
1366 #if defined(OS_MACOSX)
1367 bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
1368                                           int page_count) {
1369   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
1370   const PrintMsg_Print_Params& print_params = params.params;
1371
1372   PrintMsg_PrintPage_Params page_params;
1373   page_params.params = print_params;
1374   if (params.pages.empty()) {
1375     for (int i = 0; i < page_count; ++i) {
1376       page_params.page_number = i;
1377       PrintPageInternal(page_params, frame);
1378     }
1379   } else {
1380     for (size_t i = 0; i < params.pages.size(); ++i) {
1381       if (params.pages[i] >= page_count)
1382         break;
1383       page_params.page_number = params.pages[i];
1384       PrintPageInternal(page_params, frame);
1385     }
1386   }
1387   return true;
1388 }
1389
1390 #endif  // OS_MACOSX
1391
1392 // static - Not anonymous so that platform implementations can use it.
1393 void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
1394     blink::WebFrame* frame,
1395     int page_index,
1396     const PrintMsg_Print_Params& page_params,
1397     bool ignore_css_margins,
1398     double* scale_factor,
1399     PageSizeMargins* page_layout_in_points) {
1400   PrintMsg_Print_Params params = CalculatePrintParamsForCss(
1401       frame, page_index, page_params, ignore_css_margins,
1402       page_params.print_scaling_option ==
1403           blink::WebPrintScalingOptionFitToPrintableArea,
1404       scale_factor);
1405   CalculatePageLayoutFromPrintParams(params, page_layout_in_points);
1406 }
1407
1408 bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
1409   PrintMsg_PrintPages_Params settings;
1410   Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
1411                                                 &settings.params));
1412   // Check if the printer returned any settings, if the settings is empty, we
1413   // can safely assume there are no printer drivers configured. So we safely
1414   // terminate.
1415   bool result = true;
1416   if (!PrintMsg_Print_Params_IsValid(settings.params))
1417     result = false;
1418
1419   // Reset to default values.
1420   ignore_css_margins_ = false;
1421   settings.pages.clear();
1422
1423   settings.params.print_scaling_option =
1424       blink::WebPrintScalingOptionSourceSize;
1425   if (fit_to_paper_size) {
1426     settings.params.print_scaling_option =
1427         blink::WebPrintScalingOptionFitToPrintableArea;
1428   }
1429
1430   SetPrintPagesParams(settings);
1431   return result;
1432 }
1433
1434 bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
1435                                                 const blink::WebNode& node,
1436                                                 int* number_of_pages) {
1437   DCHECK(frame);
1438   bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node));
1439   if (!InitPrintSettings(fit_to_paper_size)) {
1440     notify_browser_of_print_failure_ = false;
1441     Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
1442     return false;
1443   }
1444
1445   const PrintMsg_Print_Params& params = print_pages_params_->params;
1446   PrepareFrameAndViewForPrint prepare(params, frame, node, ignore_css_margins_);
1447   prepare.StartPrinting();
1448
1449   *number_of_pages = prepare.GetExpectedPageCount();
1450   return true;
1451 }
1452
1453 void PrintWebViewHelper::SetOptionsFromDocument(
1454     PrintHostMsg_SetOptionsFromDocument_Params& params) {
1455   blink::WebLocalFrame* source_frame = print_preview_context_.source_frame();
1456   const blink::WebNode& source_node = print_preview_context_.source_node();
1457
1458   params.is_scaling_disabled =
1459       source_frame->isPrintScalingDisabledForPlugin(source_node);
1460 }
1461
1462 bool PrintWebViewHelper::UpdatePrintSettings(
1463     blink::WebLocalFrame* frame,
1464     const blink::WebNode& node,
1465     const base::DictionaryValue& passed_job_settings) {
1466   const base::DictionaryValue* job_settings = &passed_job_settings;
1467   base::DictionaryValue modified_job_settings;
1468   if (job_settings->empty()) {
1469     if (!print_for_preview_)
1470       print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
1471     return false;
1472   }
1473
1474   bool source_is_html = true;
1475   if (print_for_preview_) {
1476     if (!job_settings->GetBoolean(kSettingPreviewModifiable, &source_is_html)) {
1477       NOTREACHED();
1478     }
1479   } else {
1480     source_is_html = !PrintingNodeOrPdfFrame(frame, node);
1481   }
1482
1483   if (print_for_preview_ || !source_is_html) {
1484     modified_job_settings.MergeDictionary(job_settings);
1485     modified_job_settings.SetBoolean(kSettingHeaderFooterEnabled, false);
1486     modified_job_settings.SetInteger(kSettingMarginsType, NO_MARGINS);
1487     job_settings = &modified_job_settings;
1488   }
1489
1490   // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when
1491   // possible.
1492   int cookie = print_pages_params_ ?
1493       print_pages_params_->params.document_cookie : 0;
1494   PrintMsg_PrintPages_Params settings;
1495   bool canceled = false;
1496   Send(new PrintHostMsg_UpdatePrintSettings(
1497       routing_id(), cookie, *job_settings, &settings, &canceled));
1498   if (canceled) {
1499     notify_browser_of_print_failure_ = false;
1500     return false;
1501   }
1502
1503   if (!job_settings->GetInteger(kPreviewUIID, &settings.params.preview_ui_id)) {
1504     NOTREACHED();
1505     print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
1506     return false;
1507   }
1508
1509   if (!print_for_preview_) {
1510     // Validate expected print preview settings.
1511     if (!job_settings->GetInteger(kPreviewRequestID,
1512                                   &settings.params.preview_request_id) ||
1513         !job_settings->GetBoolean(kIsFirstRequest,
1514                                   &settings.params.is_first_request)) {
1515       NOTREACHED();
1516       print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
1517       return false;
1518     }
1519
1520     settings.params.print_to_pdf = IsPrintToPdfRequested(*job_settings);
1521     UpdateFrameMarginsCssInfo(*job_settings);
1522     settings.params.print_scaling_option = GetPrintScalingOption(
1523         frame, node, source_is_html, *job_settings, settings.params);
1524   }
1525
1526   SetPrintPagesParams(settings);
1527
1528   if (!PrintMsg_Print_Params_IsValid(settings.params)) {
1529     if (!print_for_preview_)
1530       print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS);
1531     else
1532       Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
1533
1534     return false;
1535   }
1536
1537   return true;
1538 }
1539
1540 bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame,
1541                                                   const blink::WebNode& node,
1542                                                   int expected_pages_count) {
1543   PrintHostMsg_ScriptedPrint_Params params;
1544   PrintMsg_PrintPages_Params print_settings;
1545
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
1554   Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));
1555
1556   // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the
1557   // value before and restore it afterwards.
1558   blink::WebPrintScalingOption scaling_option =
1559       print_pages_params_->params.print_scaling_option;
1560
1561   print_pages_params_.reset();
1562   IPC::SyncMessage* msg =
1563       new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings);
1564   msg->EnableMessagePumping();
1565   Send(msg);
1566   print_settings.params.print_scaling_option = scaling_option;
1567   SetPrintPagesParams(print_settings);
1568   return (print_settings.params.dpi && print_settings.params.document_cookie);
1569 }
1570
1571 bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
1572                                              const blink::WebNode& node) {
1573   if (!frame || prep_frame_view_)
1574     return false;
1575   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
1576   const PrintMsg_Print_Params& print_params = params.params;
1577   prep_frame_view_.reset(new PrepareFrameAndViewForPrint(
1578       print_params, frame, node, ignore_css_margins_));
1579   DCHECK(!print_pages_params_->params.selection_only ||
1580          print_pages_params_->pages.empty());
1581   prep_frame_view_->CopySelectionIfNeeded(
1582       render_view()->GetWebkitPreferences(),
1583       base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages,
1584                  base::Unretained(this)));
1585   return true;
1586 }
1587
1588 #if defined(OS_POSIX)
1589 bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
1590     PdfMetafileSkia* metafile,
1591     base::SharedMemoryHandle* shared_mem_handle) {
1592   uint32 buf_size = metafile->GetDataSize();
1593   scoped_ptr<base::SharedMemory> shared_buf(
1594       content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
1595           buf_size).release());
1596
1597   if (shared_buf) {
1598     if (shared_buf->Map(buf_size)) {
1599       metafile->GetData(shared_buf->memory(), buf_size);
1600       return shared_buf->GiveToProcess(base::GetCurrentProcessHandle(),
1601                                        shared_mem_handle);
1602     }
1603   }
1604   return false;
1605 }
1606 #endif  // defined(OS_POSIX)
1607
1608 void PrintWebViewHelper::ShowScriptedPrintPreview() {
1609   if (is_scripted_preview_delayed_) {
1610     is_scripted_preview_delayed_ = false;
1611     Send(new PrintHostMsg_ShowScriptedPrintPreview(routing_id(),
1612             print_preview_context_.IsModifiable()));
1613   }
1614 }
1615
1616 void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
1617   const bool is_modifiable = print_preview_context_.IsModifiable();
1618   const bool has_selection = print_preview_context_.HasSelection();
1619   PrintHostMsg_RequestPrintPreview_Params params;
1620   params.is_modifiable = is_modifiable;
1621   params.has_selection = has_selection;
1622   switch (type) {
1623     case PRINT_PREVIEW_SCRIPTED: {
1624       // Shows scripted print preview in two stages.
1625       // 1. PrintHostMsg_SetupScriptedPrintPreview blocks this call and JS by
1626       //    pumping messages here.
1627       // 2. PrintHostMsg_ShowScriptedPrintPreview shows preview once the
1628       //    document has been loaded.
1629       is_scripted_preview_delayed_ = true;
1630       if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
1631         // Wait for DidStopLoading. Plugins may not know the correct
1632         // |is_modifiable| value until they are fully loaded, which occurs when
1633         // DidStopLoading() is called. Defer showing the preview until then.
1634         on_stop_loading_closure_ =
1635             base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
1636                        base::Unretained(this));
1637       } else {
1638         base::MessageLoop::current()->PostTask(
1639             FROM_HERE,
1640             base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
1641                        weak_ptr_factory_.GetWeakPtr()));
1642       }
1643       IPC::SyncMessage* msg =
1644           new PrintHostMsg_SetupScriptedPrintPreview(routing_id());
1645       msg->EnableMessagePumping();
1646       Send(msg);
1647       is_scripted_preview_delayed_ = false;
1648       return;
1649     }
1650     case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME: {
1651       // Wait for DidStopLoading. Continuing with this function while
1652       // |is_loading_| is true will cause print preview to hang when try to
1653       // print a PDF document.
1654       if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
1655         on_stop_loading_closure_ =
1656             base::Bind(&PrintWebViewHelper::RequestPrintPreview,
1657                        base::Unretained(this),
1658                        type);
1659         return;
1660       }
1661
1662       break;
1663     }
1664     case PRINT_PREVIEW_USER_INITIATED_SELECTION: {
1665       DCHECK(has_selection);
1666       DCHECK(!GetPlugin(print_preview_context_.source_frame()));
1667       params.selection_only = has_selection;
1668       break;
1669     }
1670     case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE: {
1671       if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
1672         on_stop_loading_closure_ =
1673             base::Bind(&PrintWebViewHelper::RequestPrintPreview,
1674                        base::Unretained(this),
1675                        type);
1676         return;
1677       }
1678
1679       params.webnode_only = true;
1680       break;
1681     }
1682     default: {
1683       NOTREACHED();
1684       return;
1685     }
1686   }
1687   Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params));
1688 }
1689
1690 bool PrintWebViewHelper::CheckForCancel() {
1691   const PrintMsg_Print_Params& print_params = print_pages_params_->params;
1692   bool cancel = false;
1693   Send(new PrintHostMsg_CheckForCancel(routing_id(),
1694                                        print_params.preview_ui_id,
1695                                        print_params.preview_request_id,
1696                                        &cancel));
1697   if (cancel)
1698     notify_browser_of_print_failure_ = false;
1699   return cancel;
1700 }
1701
1702 bool PrintWebViewHelper::PreviewPageRendered(int page_number,
1703                                              PdfMetafileSkia* metafile) {
1704   DCHECK_GE(page_number, FIRST_PAGE_INDEX);
1705
1706   // For non-modifiable files, |metafile| should be NULL, so do not bother
1707   // sending a message. If we don't generate draft metafiles, |metafile| is
1708   // NULL.
1709   if (!print_preview_context_.IsModifiable() ||
1710       !print_preview_context_.generate_draft_pages()) {
1711     DCHECK(!metafile);
1712     return true;
1713   }
1714
1715   if (!metafile) {
1716     NOTREACHED();
1717     print_preview_context_.set_error(
1718         PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE);
1719     return false;
1720   }
1721
1722   PrintHostMsg_DidPreviewPage_Params preview_page_params;
1723   // Get the size of the resulting metafile.
1724   uint32 buf_size = metafile->GetDataSize();
1725   DCHECK_GT(buf_size, 0u);
1726   if (!CopyMetafileDataToSharedMem(
1727       metafile, &(preview_page_params.metafile_data_handle))) {
1728     LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
1729     print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
1730     return false;
1731   }
1732   preview_page_params.data_size = buf_size;
1733   preview_page_params.page_number = page_number;
1734   preview_page_params.preview_request_id =
1735       print_pages_params_->params.preview_request_id;
1736
1737   Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params));
1738   return true;
1739 }
1740
1741 PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
1742     : total_page_count_(0),
1743       current_page_index_(0),
1744       generate_draft_pages_(true),
1745       print_ready_metafile_page_count_(0),
1746       error_(PREVIEW_ERROR_NONE),
1747       state_(UNINITIALIZED) {
1748 }
1749
1750 PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
1751 }
1752
1753 void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
1754     blink::WebLocalFrame* web_frame) {
1755   DCHECK(web_frame);
1756   DCHECK(!IsRendering());
1757   state_ = INITIALIZED;
1758   source_frame_.Reset(web_frame);
1759   source_node_.reset();
1760 }
1761
1762 void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
1763     const blink::WebNode& web_node) {
1764   DCHECK(!web_node.isNull());
1765   DCHECK(web_node.document().frame());
1766   DCHECK(!IsRendering());
1767   state_ = INITIALIZED;
1768   source_frame_.Reset(web_node.document().frame());
1769   source_node_ = web_node;
1770 }
1771
1772 void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
1773   DCHECK_EQ(INITIALIZED, state_);
1774   ClearContext();
1775 }
1776
1777 bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
1778     PrepareFrameAndViewForPrint* prepared_frame,
1779     const std::vector<int>& pages) {
1780   DCHECK_EQ(INITIALIZED, state_);
1781   state_ = RENDERING;
1782
1783   // Need to make sure old object gets destroyed first.
1784   prep_frame_view_.reset(prepared_frame);
1785   prep_frame_view_->StartPrinting();
1786
1787   total_page_count_ = prep_frame_view_->GetExpectedPageCount();
1788   if (total_page_count_ == 0) {
1789     LOG(ERROR) << "CreatePreviewDocument got 0 page count";
1790     set_error(PREVIEW_ERROR_ZERO_PAGES);
1791     return false;
1792   }
1793
1794   metafile_.reset(new PdfMetafileSkia);
1795   if (!metafile_->Init()) {
1796     set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED);
1797     LOG(ERROR) << "PdfMetafileSkia Init failed";
1798     return false;
1799   }
1800
1801   current_page_index_ = 0;
1802   pages_to_render_ = pages;
1803   // Sort and make unique.
1804   std::sort(pages_to_render_.begin(), pages_to_render_.end());
1805   pages_to_render_.resize(std::unique(pages_to_render_.begin(),
1806                                       pages_to_render_.end()) -
1807                           pages_to_render_.begin());
1808   // Remove invalid pages.
1809   pages_to_render_.resize(std::lower_bound(pages_to_render_.begin(),
1810                                            pages_to_render_.end(),
1811                                            total_page_count_) -
1812                           pages_to_render_.begin());
1813   print_ready_metafile_page_count_ = pages_to_render_.size();
1814   if (pages_to_render_.empty()) {
1815     print_ready_metafile_page_count_ = total_page_count_;
1816     // Render all pages.
1817     for (int i = 0; i < total_page_count_; ++i)
1818       pages_to_render_.push_back(i);
1819   } else if (generate_draft_pages_) {
1820     int pages_index = 0;
1821     for (int i = 0; i < total_page_count_; ++i) {
1822       if (pages_index < print_ready_metafile_page_count_ &&
1823           i == pages_to_render_[pages_index]) {
1824         pages_index++;
1825         continue;
1826       }
1827       pages_to_render_.push_back(i);
1828     }
1829   }
1830
1831   document_render_time_ = base::TimeDelta();
1832   begin_time_ = base::TimeTicks::Now();
1833
1834   return true;
1835 }
1836
1837 void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
1838     const base::TimeDelta& page_time) {
1839   DCHECK_EQ(RENDERING, state_);
1840   document_render_time_ += page_time;
1841   UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
1842 }
1843
1844 void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
1845   DCHECK_EQ(RENDERING, state_);
1846   state_ = DONE;
1847   prep_frame_view_->FinishPrinting();
1848 }
1849
1850 void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
1851   DCHECK(IsRendering());
1852
1853   base::TimeTicks begin_time = base::TimeTicks::Now();
1854   metafile_->FinishDocument();
1855
1856   if (print_ready_metafile_page_count_ <= 0) {
1857     NOTREACHED();
1858     return;
1859   }
1860
1861   UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
1862                              document_render_time_);
1863   base::TimeDelta total_time = (base::TimeTicks::Now() - begin_time) +
1864                                document_render_time_;
1865   UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
1866                              total_time);
1867   UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
1868                              total_time / pages_to_render_.size());
1869 }
1870
1871 void PrintWebViewHelper::PrintPreviewContext::Finished() {
1872   DCHECK_EQ(DONE, state_);
1873   state_ = INITIALIZED;
1874   ClearContext();
1875 }
1876
1877 void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) {
1878   DCHECK(state_ == INITIALIZED || state_ == RENDERING);
1879   state_ = INITIALIZED;
1880   if (report_error) {
1881     DCHECK_NE(PREVIEW_ERROR_NONE, error_);
1882     UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_,
1883                               PREVIEW_ERROR_LAST_ENUM);
1884   }
1885   ClearContext();
1886 }
1887
1888 int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
1889   DCHECK_EQ(RENDERING, state_);
1890   if (IsFinalPageRendered())
1891     return -1;
1892   return pages_to_render_[current_page_index_++];
1893 }
1894
1895 bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
1896   return state_ == RENDERING || state_ == DONE;
1897 }
1898
1899 bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
1900   // The only kind of node we can print right now is a PDF node.
1901   return !PrintingNodeOrPdfFrame(source_frame(), source_node_);
1902 }
1903
1904 bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
1905   return IsModifiable() && source_frame()->hasSelection();
1906 }
1907
1908 bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
1909     const {
1910   DCHECK(IsRendering());
1911   return current_page_index_ == print_ready_metafile_page_count_;
1912 }
1913
1914 bool  PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
1915   DCHECK(IsRendering());
1916   return static_cast<size_t>(current_page_index_) == pages_to_render_.size();
1917 }
1918
1919 void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
1920     bool generate_draft_pages) {
1921   DCHECK_EQ(INITIALIZED, state_);
1922   generate_draft_pages_ = generate_draft_pages;
1923 }
1924
1925 void PrintWebViewHelper::PrintPreviewContext::set_error(
1926     enum PrintPreviewErrorBuckets error) {
1927   error_ = error;
1928 }
1929
1930 blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() {
1931   DCHECK(state_ != UNINITIALIZED);
1932   return source_frame_.GetFrame();
1933 }
1934
1935 const blink::WebNode&
1936     PrintWebViewHelper::PrintPreviewContext::source_node() const {
1937   DCHECK(state_ != UNINITIALIZED);
1938   return source_node_;
1939 }
1940
1941 blink::WebLocalFrame*
1942 PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
1943   DCHECK(state_ != UNINITIALIZED);
1944   return prep_frame_view_->frame();
1945 }
1946
1947 const blink::WebNode&
1948     PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
1949   DCHECK(state_ != UNINITIALIZED);
1950   return prep_frame_view_->node();
1951 }
1952
1953 int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
1954   DCHECK(state_ != UNINITIALIZED);
1955   return total_page_count_;
1956 }
1957
1958 bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
1959   return generate_draft_pages_;
1960 }
1961
1962 PdfMetafileSkia* PrintWebViewHelper::PrintPreviewContext::metafile() {
1963   DCHECK(IsRendering());
1964   return metafile_.get();
1965 }
1966
1967 int PrintWebViewHelper::PrintPreviewContext::last_error() const {
1968   return error_;
1969 }
1970
1971 void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
1972   prep_frame_view_.reset();
1973   metafile_.reset();
1974   pages_to_render_.clear();
1975   error_ = PREVIEW_ERROR_NONE;
1976 }
1977
1978 void PrintWebViewHelper::SetPrintPagesParams(
1979     const PrintMsg_PrintPages_Params& settings) {
1980   print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
1981   Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
1982                                              settings.params.document_cookie));
1983 }
1984
1985 PrintWebViewHelper::ScriptingThrottler::ScriptingThrottler() : count_(0) {
1986 }
1987
1988 bool PrintWebViewHelper::ScriptingThrottler::IsAllowed(blink::WebFrame* frame) {
1989   const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
1990   const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 32;
1991   bool too_frequent = false;
1992
1993   // Check if there is script repeatedly trying to print and ignore it if too
1994   // frequent.  The first 3 times, we use a constant wait time, but if this
1995   // gets excessive, we switch to exponential wait time. So for a page that
1996   // calls print() in a loop the user will need to cancel the print dialog
1997   // after: [2, 2, 2, 4, 8, 16, 32, 32, ...] seconds.
1998   // This gives the user time to navigate from the page.
1999   if (count_ > 0) {
2000     base::TimeDelta diff = base::Time::Now() - last_print_;
2001     int min_wait_seconds = kMinSecondsToIgnoreJavascriptInitiatedPrint;
2002     if (count_ > 3) {
2003       min_wait_seconds =
2004           std::min(kMinSecondsToIgnoreJavascriptInitiatedPrint << (count_ - 3),
2005                    kMaxSecondsToIgnoreJavascriptInitiatedPrint);
2006     }
2007     if (diff.InSeconds() < min_wait_seconds) {
2008       too_frequent = true;
2009     }
2010   }
2011
2012   if (!too_frequent) {
2013     ++count_;
2014     last_print_ = base::Time::Now();
2015     return true;
2016   }
2017
2018   blink::WebString message(
2019       blink::WebString::fromUTF8("Ignoring too frequent calls to print()."));
2020   frame->addMessageToConsole(blink::WebConsoleMessage(
2021       blink::WebConsoleMessage::LevelWarning, message));
2022   return false;
2023 }
2024
2025 void PrintWebViewHelper::ScriptingThrottler::Reset() {
2026   // Reset counter on successful print.
2027   count_ = 0;
2028 }
2029
2030 }  // namespace printing