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