Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/process_util.h" | |
| 8 #include "chrome/common/render_messages.h" | 9 #include "chrome/common/render_messages.h" |
| 9 #include "chrome/common/render_messages_params.h" | 10 #include "chrome/common/render_messages_params.h" |
| 10 #include "chrome/renderer/render_view.h" | 11 #include "chrome/renderer/render_view.h" |
| 11 #include "gfx/gdi_util.h" | 12 #include "gfx/gdi_util.h" |
| 12 #include "gfx/size.h" | 13 #include "gfx/size.h" |
| 13 #include "grit/generated_resources.h" | 14 #include "grit/generated_resources.h" |
| 14 #include "printing/native_metafile.h" | 15 #include "printing/native_metafile.h" |
| 15 #include "printing/units.h" | 16 #include "printing/units.h" |
| 16 #include "skia/ext/vector_canvas.h" | 17 #include "skia/ext/vector_canvas.h" |
| 17 #include "skia/ext/vector_platform_device.h" | 18 #include "skia/ext/vector_platform_device.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 // Play this command to the metafile DC. | 60 // Play this command to the metafile DC. |
| 60 PlayEnhMetaFileRecord(dc, handle_table, record, num_objects); | 61 PlayEnhMetaFileRecord(dc, handle_table, record, num_objects); |
| 61 } | 62 } |
| 62 return 1; // Continue enumeration | 63 return 1; // Continue enumeration |
| 63 } | 64 } |
| 64 | 65 |
| 65 void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, | 66 void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, |
| 66 const gfx::Size& canvas_size, | 67 const gfx::Size& canvas_size, |
| 67 WebFrame* frame) { | 68 WebFrame* frame) { |
| 68 // Generate a memory-based metafile. It will use the current screen's DPI. | 69 // Generate a memory-based metafile. It will use the current screen's DPI. |
| 69 printing::NativeMetafile metafile; | 70 // Each metafile contains a single page. |
| 70 | 71 scoped_ptr<printing::NativeMetafile> metafile(new printing::NativeMetafile()); |
| 71 metafile.CreateDc(NULL, NULL); | 72 metafile->CreateDc(NULL, NULL); |
| 72 HDC hdc = metafile.hdc(); | 73 DCHECK(metafile->hdc()); |
| 73 DCHECK(hdc); | 74 skia::PlatformDevice::InitializeDC(metafile->hdc()); |
| 74 skia::PlatformDevice::InitializeDC(hdc); | |
| 75 | 75 |
| 76 int page_number = params.page_number; | 76 int page_number = params.page_number; |
| 77 | 77 |
| 78 double content_width_in_points; | 78 double content_width_in_points; |
| 79 double content_height_in_points; | 79 double content_height_in_points; |
| 80 GetPageSizeAndMarginsInPoints(frame, page_number, params.params, | 80 GetPageSizeAndMarginsInPoints(frame, page_number, params.params, |
| 81 &content_width_in_points, &content_height_in_points, NULL, NULL, NULL, | 81 &content_width_in_points, &content_height_in_points, NULL, NULL, NULL, |
| 82 NULL); | 82 NULL); |
| 83 | 83 |
| 84 // Calculate the dpi adjustment. | 84 // Calculate the dpi adjustment. |
| 85 float scale_factor = static_cast<float>(params.params.desired_dpi / | 85 float scale_factor = static_cast<float>(params.params.desired_dpi / |
| 86 params.params.dpi); | 86 params.params.dpi); |
| 87 | 87 |
| 88 // Since WebKit extends the page width depending on the magical |scale_factor| | 88 // Since WebKit extends the page width depending on the magical |scale_factor| |
| 89 // we make sure the canvas covers the worst case scenario (x2.0 currently). | 89 // we make sure the canvas covers the worst case scenario (x2.0 currently). |
| 90 // PrintContext will then set the correct clipping region. | 90 // PrintContext will then set the correct clipping region. |
| 91 int width = static_cast<int>(content_width_in_points * | 91 gfx::Size page_size( |
| 92 params.params.max_shrink); | 92 static_cast<int>(content_width_in_points * params.params.max_shrink), |
| 93 int height = static_cast<int>(content_height_in_points * | 93 static_cast<int>(content_height_in_points * params.params.max_shrink)); |
| 94 params.params.max_shrink); | 94 |
| 95 // Render page for printing. | |
| 96 RenderPage(page_size, &scale_factor, page_number, frame, &metafile, | |
| 97 params.params.supports_alpha_blend); | |
| 98 | |
| 99 // Close the device context to retrieve the compiled metafile. | |
| 100 if (!metafile->CloseDc()) | |
| 101 NOTREACHED(); | |
| 102 | |
| 103 ViewHostMsg_DidPrintPage_Params page_params; | |
| 104 page_params.data_size = metafile->GetDataSize(); | |
| 105 page_params.metafile_data_handle = base::SharedMemory::NULLHandle(); | |
|
kmadhusu
2011/01/24 16:23:22
Removed this code because metafile_data_handle is
| |
| 106 page_params.page_number = page_number; | |
| 107 page_params.document_cookie = params.params.document_cookie; | |
| 108 page_params.actual_shrink = scale_factor; | |
| 109 page_params.page_size = params.params.page_size; | |
| 110 page_params.content_area = gfx::Rect(params.params.margin_left, | |
| 111 params.params.margin_top, params.params.printable_size.width(), | |
| 112 params.params.printable_size.height()); | |
| 113 page_params.has_visible_overlays = frame->isPageBoxVisible(page_number); | |
| 114 | |
| 115 if (CopyMetafileDataToSharedMem(metafile, | |
| 116 &(page_params.metafile_data_handle))) { | |
| 117 Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 void PrintWebViewHelper::RenderPage( | |
| 122 const gfx::Size& page_size, float* scale_factor, int page_number, | |
| 123 WebFrame* frame, scoped_ptr<printing::NativeMetafile>* metafile, | |
| 124 bool supports_alpha_blend) { | |
| 125 HDC hdc = (*metafile)->hdc(); | |
| 126 DCHECK(hdc); | |
| 127 | |
| 128 int width = page_size.width(); | |
| 129 int height = page_size.height(); | |
| 95 #if 0 | 130 #if 0 |
| 96 // TODO(maruel): This code is kept for testing until the 100% GDI drawing | 131 // TODO(maruel): This code is kept for testing until the 100% GDI drawing |
| 97 // code is stable. maruels use this code's output as a reference when the | 132 // code is stable. maruels use this code's output as a reference when the |
| 98 // GDI drawing code fails. | 133 // GDI drawing code fails. |
| 99 | 134 |
| 100 // Mix of Skia and GDI based. | 135 // Mix of Skia and GDI based. |
| 101 skia::PlatformCanvas canvas(width, height, true); | 136 skia::PlatformCanvas canvas(width, height, true); |
| 102 canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | 137 canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); |
| 103 float webkit_scale_factor = frame->printPage(page_number, &canvas); | 138 float webkit_scale_factor = frame->printPage(page_number, &canvas); |
| 104 if (scale_factor <= 0 || webkit_scale_factor <= 0) { | 139 if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |
| 105 NOTREACHED() << "Printing page " << page_number << " failed."; | 140 NOTREACHED() << "Printing page " << page_number << "failed."; |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
nit: "failed" -> " failed."
kmadhusu
2011/01/24 16:23:22
Done.
| |
| 106 } else { | 141 } else { |
| 107 // Update the dpi adjustment with the "page |scale_factor|" calculated | 142 // Update the dpi adjustment with the "page |scale_factor|" calculated in |
| 108 // in webkit. | 143 // webkit. |
| 109 scale_factor /= webkit_scale_factor; | 144 *scale_factor /= webkit_scale_factor; |
| 110 } | 145 } |
| 111 | 146 |
| 112 // Create a BMP v4 header that we can serialize. | 147 // Create a BMP v4 header that we can serialize. |
| 113 BITMAPV4HEADER bitmap_header; | 148 BITMAPV4HEADER bitmap_header; |
| 114 gfx::CreateBitmapV4Header(width, height, &bitmap_header); | 149 gfx::CreateBitmapV4Header(width, height, &bitmap_header); |
| 115 const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); | 150 const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); |
| 116 SkAutoLockPixels src_lock(src_bmp); | 151 SkAutoLockPixels src_lock(src_bmp); |
| 117 int retval = StretchDIBits(hdc, | 152 int retval = StretchDIBits(hdc, |
| 118 0, | 153 0, |
| 119 0, | 154 0, |
| 120 width, height, | 155 width, height, |
| 121 0, 0, | 156 0, 0, |
| 122 width, height, | 157 width, height, |
| 123 src_bmp.getPixels(), | 158 src_bmp.getPixels(), |
| 124 reinterpret_cast<BITMAPINFO*>(&bitmap_header), | 159 reinterpret_cast<BITMAPINFO*>(&bitmap_header), |
| 125 DIB_RGB_COLORS, | 160 DIB_RGB_COLORS, |
| 126 SRCCOPY); | 161 SRCCOPY); |
| 127 DCHECK(retval != GDI_ERROR); | 162 DCHECK(retval != GDI_ERROR); |
| 128 #else | 163 #else |
| 129 // 100% GDI based. | 164 // 100% GDI based. |
| 130 skia::VectorCanvas canvas(hdc, width, height); | 165 skia::VectorCanvas canvas(hdc, width, height); |
| 131 float webkit_scale_factor = frame->printPage(page_number, &canvas); | 166 float webkit_scale_factor = frame->printPage(page_number, &canvas); |
| 132 if (scale_factor <= 0 || webkit_scale_factor <= 0) { | 167 if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |
| 133 NOTREACHED() << "Printing page " << page_number << " failed."; | 168 NOTREACHED() << "Printing page " << page_number << "failed"; |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
And here
kmadhusu
2011/01/24 16:23:22
Done.
| |
| 134 } else { | 169 } else { |
| 135 // Update the dpi adjustment with the "page scale_factor" calculated | 170 // Update the dpi adjustment with the "page |scale_factor|" calculated in |
| 136 // in webkit. | 171 // webkit. |
| 137 scale_factor /= webkit_scale_factor; | 172 *scale_factor /= webkit_scale_factor; |
| 138 } | 173 } |
| 139 #endif | 174 #endif |
| 140 | 175 |
| 141 // Done printing. Close the device context to retrieve the compiled metafile. | 176 skia::VectorPlatformDevice* platform_device = |
| 142 if (!metafile.CloseDc()) { | 177 static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); |
| 143 NOTREACHED() << "metafile failed"; | 178 if (platform_device->alpha_blend_used() && !supports_alpha_blend) { |
| 144 } | 179 // Close the device context to retrieve the compiled metafile. |
| 145 printing::NativeMetafile* mf = &metafile; | 180 if (!(*metafile)->CloseDc()) |
| 146 printing::NativeMetafile metafile2; | 181 NOTREACHED(); |
| 147 | 182 |
| 148 skia::VectorPlatformDevice* platform_device = | 183 printing::NativeMetafile* metafile2(new printing::NativeMetafile()); |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
scoped_ptr<>
kmadhusu
2011/01/24 16:23:22
Done.
| |
| 149 static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); | |
| 150 if (platform_device->alpha_blend_used() && | |
| 151 !params.params.supports_alpha_blend) { | |
| 152 // Page used alpha blend, but printer doesn't support it. Rewrite the | 184 // Page used alpha blend, but printer doesn't support it. Rewrite the |
| 153 // metafile and flatten out the transparency. | 185 // metafile and flatten out the transparency. |
| 154 HDC bitmap_dc = CreateCompatibleDC(GetDC(NULL)); | 186 HDC bitmap_dc = CreateCompatibleDC(GetDC(NULL)); |
| 155 if (!bitmap_dc) { | 187 if (!bitmap_dc) { |
| 156 NOTREACHED() << "Bitmap DC creation failed"; | 188 NOTREACHED() << "Bitmap DC creation failed"; |
| 157 } | 189 } |
| 158 SetGraphicsMode(bitmap_dc, GM_ADVANCED); | 190 SetGraphicsMode(bitmap_dc, GM_ADVANCED); |
| 159 void* bits = NULL; | 191 void* bits = NULL; |
| 160 BITMAPINFO hdr; | 192 BITMAPINFO hdr; |
| 161 gfx::CreateBitmapHeader(width, height, &hdr.bmiHeader); | 193 gfx::CreateBitmapHeader(width, height, &hdr.bmiHeader); |
| 162 HBITMAP hbitmap = CreateDIBSection( | 194 HBITMAP hbitmap = CreateDIBSection( |
| 163 bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0); | 195 bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0); |
| 164 if (!hbitmap) { | 196 if (!hbitmap) { |
| 165 NOTREACHED() << "Raster bitmap creation for printing failed"; | 197 NOTREACHED() << "Raster bitmap creation for printing failed"; |
| 166 } | 198 } |
| 167 | 199 |
| 168 HGDIOBJ old_bitmap = SelectObject(bitmap_dc, hbitmap); | 200 HGDIOBJ old_bitmap = SelectObject(bitmap_dc, hbitmap); |
| 169 RECT rect = {0, 0, width, height }; | 201 RECT rect = {0, 0, width, height }; |
| 170 HBRUSH whiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); | 202 HBRUSH whiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); |
| 171 FillRect(bitmap_dc, &rect, whiteBrush); | 203 FillRect(bitmap_dc, &rect, whiteBrush); |
| 172 | 204 |
| 173 metafile2.CreateDc(NULL, NULL); | 205 metafile2->CreateDc(NULL, NULL); |
| 174 HDC hdc = metafile2.hdc(); | 206 HDC hdc = metafile2->hdc(); |
| 175 DCHECK(hdc); | 207 DCHECK(hdc); |
| 176 skia::PlatformDevice::InitializeDC(hdc); | 208 skia::PlatformDevice::InitializeDC(hdc); |
| 177 | 209 |
| 178 RECT metafile_bounds = metafile.GetBounds().ToRECT(); | 210 RECT metafile_bounds = (*metafile)->GetBounds().ToRECT(); |
| 179 // Process the old metafile, placing all non-AlphaBlend calls into the | 211 // Process the old metafile, placing all non-AlphaBlend calls into the |
| 180 // new metafile, and copying the results of all the AlphaBlend calls | 212 // new metafile, and copying the results of all the AlphaBlend calls |
| 181 // from the bitmap DC. | 213 // from the bitmap DC. |
| 182 EnumEnhMetaFile(hdc, | 214 EnumEnhMetaFile(hdc, |
| 183 metafile.emf(), | 215 (*metafile)->emf(), |
| 184 EnhMetaFileProc, | 216 EnhMetaFileProc, |
| 185 &bitmap_dc, | 217 &bitmap_dc, |
| 186 &metafile_bounds); | 218 &metafile_bounds); |
| 187 | 219 |
| 188 SelectObject(bitmap_dc, old_bitmap); | 220 SelectObject(bitmap_dc, old_bitmap); |
| 221 (*metafile)->CloseEmf(); | |
| 222 metafile->reset(metafile2); | |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
to go with the scoped_ptr<>:
metafile->reset(metaf
kmadhusu
2011/01/24 16:23:22
Done.
| |
| 223 } | |
| 224 } | |
| 189 | 225 |
| 190 if (!metafile2.CloseDc()) { | 226 bool PrintWebViewHelper::CopyMetafileDataToSharedMem( |
| 191 NOTREACHED() << "metafile failed"; | 227 scoped_ptr<printing::NativeMetafile>& metafile, |
| 192 } | 228 base::SharedMemoryHandle* shared_mem_handle) { |
| 193 mf = &metafile2; | 229 uint32 buf_size = metafile->GetDataSize(); |
| 194 } | |
| 195 | |
| 196 // Get the size of the compiled metafile. | |
| 197 uint32 buf_size = mf->GetDataSize(); | |
| 198 DCHECK_GT(buf_size, 128u); | |
| 199 ViewHostMsg_DidPrintPage_Params page_params; | |
| 200 page_params.data_size = 0; | |
| 201 page_params.metafile_data_handle = NULL; | |
| 202 page_params.page_number = page_number; | |
| 203 page_params.document_cookie = params.params.document_cookie; | |
| 204 page_params.actual_shrink = scale_factor; | |
| 205 page_params.page_size = params.params.page_size; | |
| 206 page_params.content_area = gfx::Rect(params.params.margin_left, | |
| 207 params.params.margin_top, params.params.printable_size.width(), | |
| 208 params.params.printable_size.height()); | |
| 209 page_params.has_visible_overlays = frame->isPageBoxVisible(page_number); | |
| 210 base::SharedMemory shared_buf; | |
| 211 | |
| 212 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx | 230 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx |
| 213 // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 | 231 // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 |
| 214 // MB, it can fail to print and not send an error message. | 232 // MB, it can fail to print and not send an error message. |
| 215 if (buf_size < 350*1024*1024) { | 233 if (buf_size > 350*1024*1024) { |
| 216 // Allocate a shared memory buffer to hold the generated metafile data. | 234 NOTREACHED() << "Buffer too large: " << buf_size; |
| 217 if (shared_buf.CreateAndMapAnonymous(buf_size)) { | 235 metafile->CloseEmf(); |
| 218 // Copy the bits into shared memory. | 236 return false; |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
The old code Sends the DuplicateSection call even
kmadhusu
2011/01/24 16:23:22
metafile_data_handle is initialized to "INVALID_HA
| |
| 219 if (mf->GetData(shared_buf.memory(), buf_size)) { | 237 } |
| 220 page_params.metafile_data_handle = shared_buf.handle(); | 238 |
| 221 page_params.data_size = buf_size; | 239 base::SharedMemory shared_buf; |
| 222 } else { | 240 // Allocate a shared memory buffer to hold the generated metafile data. |
| 223 NOTREACHED() << "GetData() failed"; | 241 if (!shared_buf.CreateAndMapAnonymous(buf_size)) { |
| 224 } | 242 NOTREACHED() << "Buffer allocation failed"; |
| 225 shared_buf.Unmap(); | 243 return false; |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
You're missing the CloseEmf() here. This comment
kmadhusu
2011/01/24 16:23:22
Reverted to the old control flow.
| |
| 226 } else { | 244 } |
| 227 NOTREACHED() << "Buffer allocation failed"; | 245 |
| 228 } | 246 // Copy the bits into shared memory. |
| 247 if (metafile->GetData(shared_buf.memory(), buf_size)) { | |
| 248 shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), | |
|
vandebo (ex-Chrome)
2011/01/21 21:53:28
Will this cause the shared mem handle to leak? Yo
kmadhusu
2011/01/24 16:23:22
No. I confirmed this with brettw@chromium.org.
| |
| 249 shared_mem_handle); | |
| 229 } else { | 250 } else { |
| 230 NOTREACHED() << "Buffer too large: " << buf_size; | 251 NOTREACHED() << "GetData() failed"; |
| 231 } | 252 } |
| 232 mf->CloseEmf(); | 253 shared_buf.Unmap(); |
| 233 if (Send(new ViewHostMsg_DuplicateSection( | 254 metafile->CloseEmf(); |
| 234 routing_id(), | 255 |
| 235 page_params.metafile_data_handle, | 256 return (Send(new ViewHostMsg_DuplicateSection(routing_id(), |
| 236 &page_params.metafile_data_handle))) { | 257 *shared_mem_handle, shared_mem_handle))); |
| 237 if (!is_preview_) { | |
| 238 Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); | |
| 239 } | |
| 240 } | |
| 241 } | 258 } |
| OLD | NEW |