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