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