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