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