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