Home | History | Annotate | Download | only in printing
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/renderer/printing/print_web_view_helper.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/process/process_handle.h"
     10 #include "chrome/common/print_messages.h"
     11 #include "content/public/renderer/render_thread.h"
     12 #include "printing/metafile_skia_wrapper.h"
     13 #include "printing/page_size_margins.h"
     14 #include "printing/pdf_metafile_skia.h"
     15 #include "printing/units.h"
     16 #include "skia/ext/platform_device.h"
     17 #include "skia/ext/vector_canvas.h"
     18 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     19 
     20 
     21 namespace printing {
     22 
     23 using blink::WebFrame;
     24 
     25 bool PrintWebViewHelper::RenderPreviewPage(
     26     int page_number,
     27     const PrintMsg_Print_Params& print_params) {
     28   PrintMsg_PrintPage_Params page_params;
     29   page_params.params = print_params;
     30   page_params.page_number = page_number;
     31   scoped_ptr<PdfMetafileSkia> draft_metafile;
     32   PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
     33   if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
     34     draft_metafile.reset(new PdfMetafileSkia);
     35     initial_render_metafile = draft_metafile.get();
     36   }
     37 
     38   base::TimeTicks begin_time = base::TimeTicks::Now();
     39   PrintPageInternal(page_params,
     40                     print_preview_context_.prepared_frame(),
     41                     initial_render_metafile,
     42                     NULL,
     43                     NULL);
     44   print_preview_context_.RenderedPreviewPage(
     45       base::TimeTicks::Now() - begin_time);
     46   if (draft_metafile.get()) {
     47     draft_metafile->FinishDocument();
     48   } else if (print_preview_context_.IsModifiable() &&
     49              print_preview_context_.generate_draft_pages()) {
     50     DCHECK(!draft_metafile.get());
     51     draft_metafile =
     52         print_preview_context_.metafile()->GetMetafileForCurrentPage();
     53   }
     54   return PreviewPageRendered(page_number, draft_metafile.get());
     55 }
     56 
     57 bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
     58                                           int page_count) {
     59   PdfMetafileSkia metafile;
     60   if (!metafile.Init())
     61     return false;
     62 
     63   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
     64   std::vector<int> printed_pages;
     65   if (params.pages.empty()) {
     66     for (int i = 0; i < page_count; ++i) {
     67       printed_pages.push_back(i);
     68     }
     69   } else {
     70     // TODO(vitalybuka): redesign to make more code cross platform.
     71     for (size_t i = 0; i < params.pages.size(); ++i) {
     72       if (params.pages[i] >= 0 && params.pages[i] < page_count) {
     73         printed_pages.push_back(params.pages[i]);
     74       }
     75     }
     76   }
     77   if (printed_pages.empty())
     78     return false;
     79 
     80   std::vector<gfx::Size> page_size_in_dpi(printed_pages.size());
     81   std::vector<gfx::Rect> content_area_in_dpi(printed_pages.size());
     82 
     83   PrintMsg_PrintPage_Params page_params;
     84   page_params.params = params.params;
     85   for (size_t i = 0; i < printed_pages.size(); ++i) {
     86     page_params.page_number = printed_pages[i];
     87     PrintPageInternal(page_params,
     88                       frame,
     89                       &metafile,
     90                       &page_size_in_dpi[i],
     91                       &content_area_in_dpi[i]);
     92   }
     93 
     94   // blink::printEnd() for PDF should be called before metafile is closed.
     95   FinishFramePrinting();
     96 
     97   metafile.FinishDocument();
     98 
     99   // Get the size of the resulting metafile.
    100   uint32 buf_size = metafile.GetDataSize();
    101   DCHECK_GT(buf_size, 0u);
    102 
    103   PrintHostMsg_DidPrintPage_Params printed_page_params;
    104   printed_page_params.data_size = 0;
    105   printed_page_params.document_cookie = params.params.document_cookie;
    106   printed_page_params.page_size = params.params.page_size;
    107   printed_page_params.content_area = params.params.printable_area;
    108 
    109   {
    110     base::SharedMemory shared_buf;
    111     // Allocate a shared memory buffer to hold the generated metafile data.
    112     if (!shared_buf.CreateAndMapAnonymous(buf_size)) {
    113       NOTREACHED() << "Buffer allocation failed";
    114       return false;
    115     }
    116 
    117     // Copy the bits into shared memory.
    118     if (!metafile.GetData(shared_buf.memory(), buf_size)) {
    119       NOTREACHED() << "GetData() failed";
    120       shared_buf.Unmap();
    121       return false;
    122     }
    123     shared_buf.GiveToProcess(base::GetCurrentProcessHandle(),
    124                              &printed_page_params.metafile_data_handle);
    125     shared_buf.Unmap();
    126 
    127     printed_page_params.data_size = buf_size;
    128     Send(new PrintHostMsg_DuplicateSection(
    129         routing_id(),
    130         printed_page_params.metafile_data_handle,
    131         &printed_page_params.metafile_data_handle));
    132   }
    133 
    134   for (size_t i = 0; i < printed_pages.size(); ++i) {
    135     printed_page_params.page_number = printed_pages[i];
    136     printed_page_params.page_size = page_size_in_dpi[i];
    137     printed_page_params.content_area = content_area_in_dpi[i];
    138     Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
    139     printed_page_params.metafile_data_handle = INVALID_HANDLE_VALUE;
    140   }
    141   return true;
    142 }
    143 
    144 void PrintWebViewHelper::PrintPageInternal(
    145     const PrintMsg_PrintPage_Params& params,
    146     WebFrame* frame,
    147     PdfMetafileSkia* metafile,
    148     gfx::Size* page_size_in_dpi,
    149     gfx::Rect* content_area_in_dpi) {
    150   PageSizeMargins page_layout_in_points;
    151   double css_scale_factor = 1.0f;
    152   ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
    153                                   ignore_css_margins_, &css_scale_factor,
    154                                   &page_layout_in_points);
    155   gfx::Size page_size;
    156   gfx::Rect content_area;
    157   GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
    158                                           &content_area);
    159   int dpi = static_cast<int>(params.params.dpi);
    160   // Calculate the actual page size and content area in dpi.
    161   if (page_size_in_dpi) {
    162     *page_size_in_dpi =
    163         gfx::Size(static_cast<int>(ConvertUnitDouble(
    164                       page_size.width(), kPointsPerInch, dpi)),
    165                   static_cast<int>(ConvertUnitDouble(
    166                       page_size.height(), kPointsPerInch, dpi)));
    167   }
    168 
    169   if (content_area_in_dpi) {
    170     // Output PDF matches paper size and should be printer edge to edge.
    171     *content_area_in_dpi =
    172         gfx::Rect(0, 0, page_size_in_dpi->width(), page_size_in_dpi->height());
    173   }
    174 
    175   gfx::Rect canvas_area =
    176       params.params.display_header_footer ? gfx::Rect(page_size) : content_area;
    177 
    178   float webkit_page_shrink_factor =
    179       frame->getPrintPageShrink(params.page_number);
    180   float scale_factor = css_scale_factor * webkit_page_shrink_factor;
    181 
    182   SkBaseDevice* device = metafile->StartPageForVectorCanvas(page_size,
    183                                                             canvas_area,
    184                                                             scale_factor);
    185   if (!device)
    186     return;
    187 
    188   // The printPage method take a reference to the canvas we pass down, so it
    189   // can't be a stack object.
    190   skia::RefPtr<skia::VectorCanvas> canvas =
    191       skia::AdoptRef(new skia::VectorCanvas(device));
    192   MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
    193   skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
    194 
    195   if (params.params.display_header_footer) {
    196     // |page_number| is 0-based, so 1 is added.
    197     PrintHeaderAndFooter(canvas.get(),
    198                          params.page_number + 1,
    199                          print_preview_context_.total_page_count(),
    200                          *frame,
    201                          scale_factor,
    202                          page_layout_in_points,
    203                          params.params);
    204   }
    205 
    206   float webkit_scale_factor = RenderPageContent(frame,
    207                                                 params.page_number,
    208                                                 canvas_area,
    209                                                 content_area,
    210                                                 scale_factor,
    211                                                 canvas.get());
    212   DCHECK_GT(webkit_scale_factor, 0.0f);
    213   // Done printing. Close the device context to retrieve the compiled metafile.
    214   if (!metafile->FinishPage())
    215     NOTREACHED() << "metafile failed";
    216 }
    217 
    218 bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
    219     PdfMetafileSkia* metafile,
    220     base::SharedMemoryHandle* shared_mem_handle) {
    221   uint32 buf_size = metafile->GetDataSize();
    222   base::SharedMemory shared_buf;
    223   // Allocate a shared memory buffer to hold the generated metafile data.
    224   if (!shared_buf.CreateAndMapAnonymous(buf_size)) {
    225     NOTREACHED() << "Buffer allocation failed";
    226     return false;
    227   }
    228 
    229   // Copy the bits into shared memory.
    230   if (!metafile->GetData(shared_buf.memory(), buf_size)) {
    231     NOTREACHED() << "GetData() failed";
    232     shared_buf.Unmap();
    233     return false;
    234   }
    235   shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle);
    236   shared_buf.Unmap();
    237 
    238   Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle,
    239                                          shared_mem_handle));
    240   return true;
    241 }
    242 
    243 }  // namespace printing
    244