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.page_number = page_number; | |
106 page_params.document_cookie = params.params.document_cookie; | |
107 page_params.actual_shrink = scale_factor; | |
108 page_params.page_size = params.params.page_size; | |
109 page_params.content_area = gfx::Rect(params.params.margin_left, | |
110 params.params.margin_top, params.params.printable_size.width(), | |
111 params.params.printable_size.height()); | |
112 page_params.has_visible_overlays = frame->isPageBoxVisible(page_number); | |
113 | |
114 if (CopyMetafileDataToSharedMem(metafile, | |
115 &(page_params.metafile_data_handle))) { | |
116 Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); | |
117 } | |
118 } | |
119 | |
120 void PrintWebViewHelper::RenderPage( | |
121 const gfx::Size& page_size, float* scale_factor, int page_number, | |
122 WebFrame* frame, scoped_ptr<printing::NativeMetafile>* metafile, | |
123 bool supports_alpha_blend) { | |
124 HDC hdc = (*metafile)->hdc(); | |
125 DCHECK(hdc); | |
126 | |
127 int width = page_size.width(); | |
128 int height = page_size.height(); | |
95 #if 0 | 129 #if 0 |
96 // TODO(maruel): This code is kept for testing until the 100% GDI drawing | 130 // 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 | 131 // code is stable. maruels use this code's output as a reference when the |
98 // GDI drawing code fails. | 132 // GDI drawing code fails. |
99 | 133 |
100 // Mix of Skia and GDI based. | 134 // Mix of Skia and GDI based. |
101 skia::PlatformCanvas canvas(width, height, true); | 135 skia::PlatformCanvas canvas(width, height, true); |
102 canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | 136 canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); |
103 float webkit_scale_factor = frame->printPage(page_number, &canvas); | 137 float webkit_scale_factor = frame->printPage(page_number, &canvas); |
104 if (scale_factor <= 0 || webkit_scale_factor <= 0) { | 138 if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |
105 NOTREACHED() << "Printing page " << page_number << " failed."; | 139 NOTREACHED() << "Printing page " << page_number << " failed."; |
106 } else { | 140 } else { |
107 // Update the dpi adjustment with the "page |scale_factor|" calculated | 141 // Update the dpi adjustment with the "page |scale_factor|" calculated in |
108 // in webkit. | 142 // webkit. |
109 scale_factor /= webkit_scale_factor; | 143 *scale_factor /= webkit_scale_factor; |
110 } | 144 } |
111 | 145 |
112 // Create a BMP v4 header that we can serialize. | 146 // Create a BMP v4 header that we can serialize. |
113 BITMAPV4HEADER bitmap_header; | 147 BITMAPV4HEADER bitmap_header; |
114 gfx::CreateBitmapV4Header(width, height, &bitmap_header); | 148 gfx::CreateBitmapV4Header(width, height, &bitmap_header); |
115 const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); | 149 const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); |
116 SkAutoLockPixels src_lock(src_bmp); | 150 SkAutoLockPixels src_lock(src_bmp); |
117 int retval = StretchDIBits(hdc, | 151 int retval = StretchDIBits(hdc, |
118 0, | 152 0, |
119 0, | 153 0, |
120 width, height, | 154 width, height, |
121 0, 0, | 155 0, 0, |
122 width, height, | 156 width, height, |
123 src_bmp.getPixels(), | 157 src_bmp.getPixels(), |
124 reinterpret_cast<BITMAPINFO*>(&bitmap_header), | 158 reinterpret_cast<BITMAPINFO*>(&bitmap_header), |
125 DIB_RGB_COLORS, | 159 DIB_RGB_COLORS, |
126 SRCCOPY); | 160 SRCCOPY); |
127 DCHECK(retval != GDI_ERROR); | 161 DCHECK(retval != GDI_ERROR); |
128 #else | 162 #else |
129 // 100% GDI based. | 163 // 100% GDI based. |
130 skia::VectorCanvas canvas(hdc, width, height); | 164 skia::VectorCanvas canvas(hdc, width, height); |
131 float webkit_scale_factor = frame->printPage(page_number, &canvas); | 165 float webkit_scale_factor = frame->printPage(page_number, &canvas); |
132 if (scale_factor <= 0 || webkit_scale_factor <= 0) { | 166 if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |
133 NOTREACHED() << "Printing page " << page_number << " failed."; | 167 NOTREACHED() << "Printing page " << page_number << " failed."; |
134 } else { | 168 } else { |
135 // Update the dpi adjustment with the "page scale_factor" calculated | 169 // Update the dpi adjustment with the "page |scale_factor|" calculated in |
136 // in webkit. | 170 // webkit. |
137 scale_factor /= webkit_scale_factor; | 171 *scale_factor /= webkit_scale_factor; |
138 } | 172 } |
139 #endif | 173 #endif |
140 | 174 |
141 // Done printing. Close the device context to retrieve the compiled metafile. | 175 skia::VectorPlatformDevice* platform_device = |
142 if (!metafile.CloseDc()) { | 176 static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); |
143 NOTREACHED() << "metafile failed"; | 177 if (platform_device->alpha_blend_used() && !supports_alpha_blend) { |
144 } | 178 // Close the device context to retrieve the compiled metafile. |
145 printing::NativeMetafile* mf = &metafile; | 179 if (!(*metafile)->CloseDc()) |
146 printing::NativeMetafile metafile2; | 180 NOTREACHED(); |
147 | 181 |
148 skia::VectorPlatformDevice* platform_device = | 182 scoped_ptr<printing::NativeMetafile> metafile2( |
149 static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); | 183 new printing::NativeMetafile()); |
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(); | |
vandebo (ex-Chrome)
2011/01/24 17:39:18
nit: Not neded. metafile->reset will destruct *me
kmadhusu
2011/01/24 22:26:04
Fixed.
| |
222 metafile->reset(metafile2.release()); | |
223 } | |
224 } | |
189 | 225 |
190 if (!metafile2.CloseDc()) { | 226 bool PrintWebViewHelper::CopyMetafileDataToSharedMem( |
191 NOTREACHED() << "metafile failed"; | 227 scoped_ptr<printing::NativeMetafile>& metafile, |
vandebo (ex-Chrome)
2011/01/24 17:39:18
Pass the raw pointer, not a scoped_ptr<>&.
kmadhusu
2011/01/24 22:26:04
Done.
| |
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); | |
vandebo (ex-Chrome)
2011/01/24 17:39:18
nit: You've lost this DCHECK
kmadhusu
2011/01/24 22:26:04
Fixed.
| |
199 ViewHostMsg_DidPrintPage_Params page_params; | |
200 page_params.data_size = 0; | |
201 page_params.metafile_data_handle = NULL; | |
vandebo (ex-Chrome)
2011/01/24 17:39:18
This will lead to a different control flow than yo
kmadhusu
2011/01/24 22:26:04
Added "page_params.metafile_data_handle = NULL" st
| |
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; | 230 base::SharedMemory shared_buf; |
211 | |
212 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx | 231 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx |
213 // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 | 232 // 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. | 233 // MB, it can fail to print and not send an error message. |
215 if (buf_size < 350*1024*1024) { | 234 if (buf_size < 350*1024*1024) { |
216 // Allocate a shared memory buffer to hold the generated metafile data. | 235 // Allocate a shared memory buffer to hold the generated metafile data. |
217 if (shared_buf.CreateAndMapAnonymous(buf_size)) { | 236 if (shared_buf.CreateAndMapAnonymous(buf_size)) { |
218 // Copy the bits into shared memory. | 237 // Copy the bits into shared memory. |
219 if (mf->GetData(shared_buf.memory(), buf_size)) { | 238 if (metafile->GetData(shared_buf.memory(), buf_size)) { |
220 page_params.metafile_data_handle = shared_buf.handle(); | 239 shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), |
221 page_params.data_size = buf_size; | 240 shared_mem_handle); |
222 } else { | 241 } else { |
223 NOTREACHED() << "GetData() failed"; | 242 NOTREACHED() << "GetData() failed"; |
224 } | 243 } |
225 shared_buf.Unmap(); | 244 shared_buf.Unmap(); |
226 } else { | 245 } else { |
227 NOTREACHED() << "Buffer allocation failed"; | 246 NOTREACHED() << "Buffer allocation failed"; |
228 } | 247 } |
229 } else { | 248 } else { |
230 NOTREACHED() << "Buffer too large: " << buf_size; | 249 NOTREACHED() << "Buffer too large: " << buf_size; |
231 } | 250 } |
232 mf->CloseEmf(); | 251 metafile->CloseEmf(); |
233 if (Send(new ViewHostMsg_DuplicateSection( | 252 return (Send(new ViewHostMsg_DuplicateSection(routing_id(), |
234 routing_id(), | 253 *shared_mem_handle, shared_mem_handle))); |
235 page_params.metafile_data_handle, | |
236 &page_params.metafile_data_handle))) { | |
237 if (!is_preview_) { | |
238 Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); | |
239 } | |
240 } | |
241 } | 254 } |
OLD | NEW |