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