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