| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/print_web_view_helper.h" | 5 #include "chrome/renderer/print_web_view_helper.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/process_util.h" | 10 #include "base/process_util.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "ui/gfx/point.h" | 25 #include "ui/gfx/point.h" |
| 26 #include "ui/gfx/rect.h" | 26 #include "ui/gfx/rect.h" |
| 27 #include "ui/gfx/size.h" | 27 #include "ui/gfx/size.h" |
| 28 | 28 |
| 29 using printing::ConvertUnit; | 29 using printing::ConvertUnit; |
| 30 using printing::ConvertUnitDouble; | 30 using printing::ConvertUnitDouble; |
| 31 using printing::kPointsPerInch; | 31 using printing::kPointsPerInch; |
| 32 using printing::Metafile; | 32 using printing::Metafile; |
| 33 using WebKit::WebFrame; | 33 using WebKit::WebFrame; |
| 34 | 34 |
| 35 namespace { | |
| 36 | |
| 37 int CALLBACK EnhMetaFileProc(HDC dc, | |
| 38 HANDLETABLE* handle_table, | |
| 39 const ENHMETARECORD *record, | |
| 40 int num_objects, | |
| 41 LPARAM data) { | |
| 42 HDC* bitmap_dc = reinterpret_cast<HDC*>(data); | |
| 43 // Play this command to the bitmap DC. | |
| 44 PlayEnhMetaFileRecord(*bitmap_dc, handle_table, record, num_objects); | |
| 45 switch (record->iType) { | |
| 46 case EMR_ALPHABLEND: { | |
| 47 const EMRALPHABLEND* emr_alpha_blend = | |
| 48 reinterpret_cast<const EMRALPHABLEND*>(record); | |
| 49 XFORM bitmap_dc_transform, metafile_dc_transform; | |
| 50 XFORM identity = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; | |
| 51 // Temporarily set the world transforms of both DC's to identity. | |
| 52 GetWorldTransform(dc, &metafile_dc_transform); | |
| 53 SetWorldTransform(dc, &identity); | |
| 54 GetWorldTransform(*bitmap_dc, &bitmap_dc_transform); | |
| 55 SetWorldTransform(*bitmap_dc, &identity); | |
| 56 const RECTL& rect = emr_alpha_blend->rclBounds; | |
| 57 // Since the printer does not support alpha blend, copy the alpha | |
| 58 // blended region from our (software-rendered) bitmap DC to the | |
| 59 // metafile DC. | |
| 60 BitBlt(dc, | |
| 61 rect.left, | |
| 62 rect.top, | |
| 63 rect.right - rect.left + 1, | |
| 64 rect.bottom - rect.top + 1, | |
| 65 *bitmap_dc, | |
| 66 rect.left, | |
| 67 rect.top, | |
| 68 SRCCOPY); | |
| 69 // Restore the world transforms of both DC's. | |
| 70 SetWorldTransform(dc, &metafile_dc_transform); | |
| 71 SetWorldTransform(*bitmap_dc, &bitmap_dc_transform); | |
| 72 break; | |
| 73 } | |
| 74 | |
| 75 case EMR_CREATEBRUSHINDIRECT: | |
| 76 case EMR_CREATECOLORSPACE: | |
| 77 case EMR_CREATECOLORSPACEW: | |
| 78 case EMR_CREATEDIBPATTERNBRUSHPT: | |
| 79 case EMR_CREATEMONOBRUSH: | |
| 80 case EMR_CREATEPALETTE: | |
| 81 case EMR_CREATEPEN: | |
| 82 case EMR_DELETECOLORSPACE: | |
| 83 case EMR_DELETEOBJECT: | |
| 84 case EMR_EXTCREATEFONTINDIRECTW: | |
| 85 // Play object creation command only once. | |
| 86 break; | |
| 87 | |
| 88 default: | |
| 89 // Play this command to the metafile DC. | |
| 90 PlayEnhMetaFileRecord(dc, handle_table, record, num_objects); | |
| 91 break; | |
| 92 } | |
| 93 return 1; // Continue enumeration | |
| 94 } | |
| 95 | |
| 96 Metafile* FlattenTransparency(Metafile* metafile, const gfx::Size& page_size) { | |
| 97 // Currently, we handle alpha blend transparency for a single page. | |
| 98 // Therefore, expecting a metafile with page count 1. | |
| 99 DCHECK_EQ(1U, metafile->GetPageCount()); | |
| 100 | |
| 101 // Close the device context to retrieve the compiled metafile. | |
| 102 if (!metafile->FinishDocument()) | |
| 103 NOTREACHED(); | |
| 104 | |
| 105 // Page used alpha blend, but printer doesn't support it. Rewrite the | |
| 106 // metafile and flatten out the transparency. | |
| 107 base::win::ScopedGetDC screen_dc(NULL); | |
| 108 base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(screen_dc)); | |
| 109 if (!bitmap_dc) | |
| 110 NOTREACHED() << "Bitmap DC creation failed"; | |
| 111 SetGraphicsMode(bitmap_dc, GM_ADVANCED); | |
| 112 void* bits = NULL; | |
| 113 BITMAPINFO hdr; | |
| 114 gfx::CreateBitmapHeader(page_size.width(), page_size.height(), | |
| 115 &hdr.bmiHeader); | |
| 116 base::win::ScopedBitmap hbitmap(CreateDIBSection( | |
| 117 bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0)); | |
| 118 if (!hbitmap) | |
| 119 NOTREACHED() << "Raster bitmap creation for printing failed"; | |
| 120 | |
| 121 base::win::ScopedSelectObject selectBitmap(bitmap_dc, hbitmap); | |
| 122 RECT rect = { 0, 0, page_size.width(), page_size.height() }; | |
| 123 HBRUSH whiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); | |
| 124 FillRect(bitmap_dc, &rect, whiteBrush); | |
| 125 | |
| 126 Metafile* metafile2(new printing::NativeMetafile); | |
| 127 metafile2->Init(); | |
| 128 HDC hdc = metafile2->context(); | |
| 129 DCHECK(hdc); | |
| 130 skia::InitializeDC(hdc); | |
| 131 | |
| 132 RECT metafile_bounds = metafile->GetPageBounds(1).ToRECT(); | |
| 133 // Process the old metafile, placing all non-AlphaBlend calls into the | |
| 134 // new metafile, and copying the results of all the AlphaBlend calls | |
| 135 // from the bitmap DC. | |
| 136 EnumEnhMetaFile(hdc, | |
| 137 metafile->emf(), | |
| 138 EnhMetaFileProc, | |
| 139 &bitmap_dc, | |
| 140 &metafile_bounds); | |
| 141 return metafile2; | |
| 142 } | |
| 143 | |
| 144 } // namespace | |
| 145 | |
| 146 void PrintWebViewHelper::PrintPageInternal( | 35 void PrintWebViewHelper::PrintPageInternal( |
| 147 const PrintMsg_PrintPage_Params& params, | 36 const PrintMsg_PrintPage_Params& params, |
| 148 const gfx::Size& canvas_size, | 37 const gfx::Size& canvas_size, |
| 149 WebFrame* frame) { | 38 WebFrame* frame) { |
| 150 // Generate a memory-based metafile. It will use the current screen's DPI. | 39 // Generate a memory-based metafile. It will use the current screen's DPI. |
| 151 // Each metafile contains a single page. | 40 // Each metafile contains a single page. |
| 152 scoped_ptr<Metafile> metafile(new printing::NativeMetafile); | 41 scoped_ptr<Metafile> metafile(new printing::NativeMetafile); |
| 153 metafile->Init(); | 42 metafile->Init(); |
| 154 DCHECK(metafile->context()); | 43 DCHECK(metafile->context()); |
| 155 skia::InitializeDC(metafile->context()); | 44 skia::InitializeDC(metafile->context()); |
| 156 | 45 |
| 157 int page_number = params.page_number; | 46 int page_number = params.page_number; |
| 158 | 47 |
| 159 // Calculate the dpi adjustment. | 48 // Calculate the dpi adjustment. |
| 160 // Browser will render context using desired_dpi, so we need to calculate | 49 // Browser will render context using desired_dpi, so we need to calculate |
| 161 // adjustment factor to play content on the printer DC later during the | 50 // adjustment factor to play content on the printer DC later during the |
| 162 // actual printing. | 51 // actual printing. |
| 163 double actual_shrink = static_cast<float>(params.params.desired_dpi / | 52 double actual_shrink = static_cast<float>(params.params.desired_dpi / |
| 164 params.params.dpi); | 53 params.params.dpi); |
| 165 gfx::Size page_size_in_dpi; | 54 gfx::Size page_size_in_dpi; |
| 166 gfx::Rect content_area_in_dpi; | 55 gfx::Rect content_area_in_dpi; |
| 167 | 56 |
| 168 // Render page for printing. | 57 // Render page for printing. |
| 169 metafile.reset(RenderPage(params.params, page_number, frame, false, | 58 RenderPage(params.params, page_number, frame, false, metafile.get(), |
| 170 metafile.get(), &actual_shrink, &page_size_in_dpi, | 59 &actual_shrink, &page_size_in_dpi, &content_area_in_dpi); |
| 171 &content_area_in_dpi)); | |
| 172 | 60 |
| 173 // Close the device context to retrieve the compiled metafile. | 61 // Close the device context to retrieve the compiled metafile. |
| 174 if (!metafile->FinishDocument()) | 62 if (!metafile->FinishDocument()) |
| 175 NOTREACHED(); | 63 NOTREACHED(); |
| 176 | 64 |
| 177 // Get the size of the compiled metafile. | 65 // Get the size of the compiled metafile. |
| 178 uint32 buf_size = metafile->GetDataSize(); | 66 uint32 buf_size = metafile->GetDataSize(); |
| 179 DCHECK_GT(buf_size, 128u); | 67 DCHECK_GT(buf_size, 128u); |
| 180 | 68 |
| 181 PrintHostMsg_DidPrintPage_Params page_params; | 69 PrintHostMsg_DidPrintPage_Params page_params; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 203 scoped_ptr<Metafile> draft_metafile; | 91 scoped_ptr<Metafile> draft_metafile; |
| 204 printing::Metafile* initial_render_metafile = | 92 printing::Metafile* initial_render_metafile = |
| 205 print_preview_context_.metafile(); | 93 print_preview_context_.metafile(); |
| 206 | 94 |
| 207 if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { | 95 if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { |
| 208 draft_metafile.reset(new printing::PreviewMetafile); | 96 draft_metafile.reset(new printing::PreviewMetafile); |
| 209 initial_render_metafile = draft_metafile.get(); | 97 initial_render_metafile = draft_metafile.get(); |
| 210 } | 98 } |
| 211 | 99 |
| 212 base::TimeTicks begin_time = base::TimeTicks::Now(); | 100 base::TimeTicks begin_time = base::TimeTicks::Now(); |
| 213 printing::Metafile* render_page_result = | 101 RenderPage(print_params, page_number, print_preview_context_.frame(), true, |
| 214 RenderPage(print_params, page_number, print_preview_context_.frame(), | 102 initial_render_metafile, &actual_shrink, NULL, NULL); |
| 215 true, initial_render_metafile, &actual_shrink, NULL, NULL); | |
| 216 // In the preview flow, RenderPage will never return a new metafile. | |
| 217 DCHECK_EQ(render_page_result, initial_render_metafile); | |
| 218 print_preview_context_.RenderedPreviewPage( | 103 print_preview_context_.RenderedPreviewPage( |
| 219 base::TimeTicks::Now() - begin_time); | 104 base::TimeTicks::Now() - begin_time); |
| 220 | 105 |
| 221 if (draft_metafile.get()) { | 106 if (draft_metafile.get()) { |
| 222 draft_metafile->FinishDocument(); | 107 draft_metafile->FinishDocument(); |
| 223 } else if (print_preview_context_.IsModifiable() && | 108 } else if (print_preview_context_.IsModifiable() && |
| 224 print_preview_context_.generate_draft_pages()) { | 109 print_preview_context_.generate_draft_pages()) { |
| 225 DCHECK(!draft_metafile.get()); | 110 DCHECK(!draft_metafile.get()); |
| 226 draft_metafile.reset( | 111 draft_metafile.reset( |
| 227 print_preview_context_.metafile()->GetMetafileForCurrentPage()); | 112 print_preview_context_.metafile()->GetMetafileForCurrentPage()); |
| 228 } | 113 } |
| 229 return PreviewPageRendered(page_number, draft_metafile.get()); | 114 return PreviewPageRendered(page_number, draft_metafile.get()); |
| 230 } | 115 } |
| 231 | 116 |
| 232 Metafile* PrintWebViewHelper::RenderPage( | 117 void PrintWebViewHelper::RenderPage( |
| 233 const PrintMsg_Print_Params& params, int page_number, WebFrame* frame, | 118 const PrintMsg_Print_Params& params, int page_number, WebFrame* frame, |
| 234 bool is_preview, Metafile* metafile, double* actual_shrink, | 119 bool is_preview, Metafile* metafile, double* actual_shrink, |
| 235 gfx::Size* page_size_in_dpi, gfx::Rect* content_area_in_dpi) { | 120 gfx::Size* page_size_in_dpi, gfx::Rect* content_area_in_dpi) { |
| 236 printing::PageSizeMargins page_layout_in_points; | 121 printing::PageSizeMargins page_layout_in_points; |
| 237 double css_scale_factor = 1.0f; | 122 double css_scale_factor = 1.0f; |
| 238 ComputePageLayoutInPointsForCss(frame, page_number, params, | 123 ComputePageLayoutInPointsForCss(frame, page_number, params, |
| 239 ignore_css_margins_, &css_scale_factor, | 124 ignore_css_margins_, &css_scale_factor, |
| 240 &page_layout_in_points); | 125 &page_layout_in_points); |
| 241 gfx::Size page_size; | 126 gfx::Size page_size; |
| 242 gfx::Rect content_area; | 127 gfx::Rect content_area; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 if (!printing::MetafileSkiaWrapper::GetCustomScaleOnCanvas( | 197 if (!printing::MetafileSkiaWrapper::GetCustomScaleOnCanvas( |
| 313 *canvas, actual_shrink)) { | 198 *canvas, actual_shrink)) { |
| 314 // Update the dpi adjustment with the "page |actual_shrink|" calculated in | 199 // Update the dpi adjustment with the "page |actual_shrink|" calculated in |
| 315 // webkit. | 200 // webkit. |
| 316 *actual_shrink /= (webkit_scale_factor * css_scale_factor); | 201 *actual_shrink /= (webkit_scale_factor * css_scale_factor); |
| 317 } | 202 } |
| 318 } | 203 } |
| 319 | 204 |
| 320 bool result = metafile->FinishPage(); | 205 bool result = metafile->FinishPage(); |
| 321 DCHECK(result); | 206 DCHECK(result); |
| 322 | |
| 323 if (!params.supports_alpha_blend) { | |
| 324 // PreviewMetafile (PDF) supports alpha blend, so we only hit this case | |
| 325 // for NativeMetafile. | |
| 326 DCHECK(!is_preview); | |
| 327 skia::PlatformDevice* platform_device = skia::GetPlatformDevice(device); | |
| 328 if (platform_device && platform_device->AlphaBlendUsed()) { | |
| 329 return FlattenTransparency(metafile, page_size); | |
| 330 } | |
| 331 } | |
| 332 return metafile; | |
| 333 } | 207 } |
| 334 | 208 |
| 335 bool PrintWebViewHelper::CopyMetafileDataToSharedMem( | 209 bool PrintWebViewHelper::CopyMetafileDataToSharedMem( |
| 336 Metafile* metafile, base::SharedMemoryHandle* shared_mem_handle) { | 210 Metafile* metafile, base::SharedMemoryHandle* shared_mem_handle) { |
| 337 uint32 buf_size = metafile->GetDataSize(); | 211 uint32 buf_size = metafile->GetDataSize(); |
| 338 base::SharedMemory shared_buf; | 212 base::SharedMemory shared_buf; |
| 339 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx | 213 if (buf_size >= printing::kMetafileMaxSize) { |
| 340 // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 | |
| 341 // MB, it can fail to print and not send an error message. | |
| 342 if (buf_size >= 350*1024*1024) { | |
| 343 NOTREACHED() << "Buffer too large: " << buf_size; | 214 NOTREACHED() << "Buffer too large: " << buf_size; |
| 344 return false; | 215 return false; |
| 345 } | 216 } |
| 346 | 217 |
| 347 // Allocate a shared memory buffer to hold the generated metafile data. | 218 // Allocate a shared memory buffer to hold the generated metafile data. |
| 348 if (!shared_buf.CreateAndMapAnonymous(buf_size)) { | 219 if (!shared_buf.CreateAndMapAnonymous(buf_size)) { |
| 349 NOTREACHED() << "Buffer allocation failed"; | 220 NOTREACHED() << "Buffer allocation failed"; |
| 350 return false; | 221 return false; |
| 351 } | 222 } |
| 352 | 223 |
| 353 // Copy the bits into shared memory. | 224 // Copy the bits into shared memory. |
| 354 if (!metafile->GetData(shared_buf.memory(), buf_size)) { | 225 if (!metafile->GetData(shared_buf.memory(), buf_size)) { |
| 355 NOTREACHED() << "GetData() failed"; | 226 NOTREACHED() << "GetData() failed"; |
| 356 shared_buf.Unmap(); | 227 shared_buf.Unmap(); |
| 357 return false; | 228 return false; |
| 358 } | 229 } |
| 359 shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle); | 230 shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle); |
| 360 shared_buf.Unmap(); | 231 shared_buf.Unmap(); |
| 361 | 232 |
| 362 Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle, | 233 Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle, |
| 363 shared_mem_handle)); | 234 shared_mem_handle)); |
| 364 return true; | 235 return true; |
| 365 } | 236 } |
| OLD | NEW |