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