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 // Get the size of the compiled metafile. | |
104 uint32 buf_size = metafile->GetDataSize(); | |
105 DCHECK_GT(buf_size, 128u); | |
106 | |
107 ViewHostMsg_DidPrintPage_Params page_params; | |
108 page_params.data_size = 0; | |
109 page_params.metafile_data_handle = NULL; | |
110 page_params.page_number = page_number; | |
111 page_params.document_cookie = params.params.document_cookie; | |
112 page_params.actual_shrink = scale_factor; | |
113 page_params.page_size = params.params.page_size; | |
114 page_params.content_area = gfx::Rect(params.params.margin_left, | |
115 params.params.margin_top, params.params.printable_size.width(), | |
116 params.params.printable_size.height()); | |
117 page_params.has_visible_overlays = frame->isPageBoxVisible(page_number); | |
118 | |
119 if (CopyMetafileDataToSharedMem(metafile.get(), | |
120 &(page_params.metafile_data_handle))) { | |
121 page_params.data_size = buf_size; | |
122 } | |
123 (*metafile).CloseEmf(); | |
Lei Zhang
2011/01/25 03:02:54
Isn't this the same as metafile->CloseEmf()?
kmadhusu
2011/01/25 17:39:18
Fixed.
| |
124 if (Send(new ViewHostMsg_DuplicateSection( | |
125 routing_id(), | |
126 page_params.metafile_data_handle, | |
127 &page_params.metafile_data_handle))) { | |
128 Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); | |
129 } | |
130 } | |
131 | |
132 void PrintWebViewHelper::RenderPage( | |
133 const gfx::Size& page_size, float* scale_factor, int page_number, | |
134 WebFrame* frame, scoped_ptr<printing::NativeMetafile>* metafile, | |
135 bool supports_alpha_blend) { | |
136 HDC hdc = (*metafile)->hdc(); | |
137 DCHECK(hdc); | |
138 | |
139 int width = page_size.width(); | |
140 int height = page_size.height(); | |
95 #if 0 | 141 #if 0 |
96 // TODO(maruel): This code is kept for testing until the 100% GDI drawing | 142 // 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 | 143 // code is stable. maruels use this code's output as a reference when the |
98 // GDI drawing code fails. | 144 // GDI drawing code fails. |
99 | 145 |
100 // Mix of Skia and GDI based. | 146 // Mix of Skia and GDI based. |
101 skia::PlatformCanvas canvas(width, height, true); | 147 skia::PlatformCanvas canvas(width, height, true); |
102 canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | 148 canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); |
103 float webkit_scale_factor = frame->printPage(page_number, &canvas); | 149 float webkit_scale_factor = frame->printPage(page_number, &canvas); |
104 if (scale_factor <= 0 || webkit_scale_factor <= 0) { | 150 if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |
105 NOTREACHED() << "Printing page " << page_number << " failed."; | 151 NOTREACHED() << "Printing page " << page_number << " failed."; |
106 } else { | 152 } else { |
107 // Update the dpi adjustment with the "page |scale_factor|" calculated | 153 // Update the dpi adjustment with the "page |scale_factor|" calculated in |
108 // in webkit. | 154 // webkit. |
109 scale_factor /= webkit_scale_factor; | 155 *scale_factor /= webkit_scale_factor; |
110 } | 156 } |
111 | 157 |
112 // Create a BMP v4 header that we can serialize. | 158 // Create a BMP v4 header that we can serialize. |
113 BITMAPV4HEADER bitmap_header; | 159 BITMAPV4HEADER bitmap_header; |
114 gfx::CreateBitmapV4Header(width, height, &bitmap_header); | 160 gfx::CreateBitmapV4Header(width, height, &bitmap_header); |
115 const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); | 161 const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); |
116 SkAutoLockPixels src_lock(src_bmp); | 162 SkAutoLockPixels src_lock(src_bmp); |
117 int retval = StretchDIBits(hdc, | 163 int retval = StretchDIBits(hdc, |
118 0, | 164 0, |
119 0, | 165 0, |
120 width, height, | 166 width, height, |
121 0, 0, | 167 0, 0, |
122 width, height, | 168 width, height, |
123 src_bmp.getPixels(), | 169 src_bmp.getPixels(), |
124 reinterpret_cast<BITMAPINFO*>(&bitmap_header), | 170 reinterpret_cast<BITMAPINFO*>(&bitmap_header), |
125 DIB_RGB_COLORS, | 171 DIB_RGB_COLORS, |
126 SRCCOPY); | 172 SRCCOPY); |
127 DCHECK(retval != GDI_ERROR); | 173 DCHECK(retval != GDI_ERROR); |
128 #else | 174 #else |
129 // 100% GDI based. | 175 // 100% GDI based. |
130 skia::VectorCanvas canvas(hdc, width, height); | 176 skia::VectorCanvas canvas(hdc, width, height); |
131 float webkit_scale_factor = frame->printPage(page_number, &canvas); | 177 float webkit_scale_factor = frame->printPage(page_number, &canvas); |
132 if (scale_factor <= 0 || webkit_scale_factor <= 0) { | 178 if (*scale_factor <= 0 || webkit_scale_factor <= 0) { |
133 NOTREACHED() << "Printing page " << page_number << " failed."; | 179 NOTREACHED() << "Printing page " << page_number << " failed."; |
134 } else { | 180 } else { |
135 // Update the dpi adjustment with the "page scale_factor" calculated | 181 // Update the dpi adjustment with the "page |scale_factor|" calculated in |
136 // in webkit. | 182 // webkit. |
137 scale_factor /= webkit_scale_factor; | 183 *scale_factor /= webkit_scale_factor; |
138 } | 184 } |
139 #endif | 185 #endif |
140 | 186 |
141 // Done printing. Close the device context to retrieve the compiled metafile. | 187 skia::VectorPlatformDevice* platform_device = |
142 if (!metafile.CloseDc()) { | 188 static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); |
143 NOTREACHED() << "metafile failed"; | 189 if (platform_device->alpha_blend_used() && !supports_alpha_blend) { |
144 } | 190 // Close the device context to retrieve the compiled metafile. |
145 printing::NativeMetafile* mf = &metafile; | 191 if (!(*metafile)->CloseDc()) |
146 printing::NativeMetafile metafile2; | 192 NOTREACHED(); |
147 | 193 |
148 skia::VectorPlatformDevice* platform_device = | 194 scoped_ptr<printing::NativeMetafile> metafile2( |
149 static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); | 195 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 | 196 // Page used alpha blend, but printer doesn't support it. Rewrite the |
153 // metafile and flatten out the transparency. | 197 // metafile and flatten out the transparency. |
154 HDC bitmap_dc = CreateCompatibleDC(GetDC(NULL)); | 198 HDC bitmap_dc = CreateCompatibleDC(GetDC(NULL)); |
155 if (!bitmap_dc) { | 199 if (!bitmap_dc) { |
156 NOTREACHED() << "Bitmap DC creation failed"; | 200 NOTREACHED() << "Bitmap DC creation failed"; |
157 } | 201 } |
158 SetGraphicsMode(bitmap_dc, GM_ADVANCED); | 202 SetGraphicsMode(bitmap_dc, GM_ADVANCED); |
159 void* bits = NULL; | 203 void* bits = NULL; |
160 BITMAPINFO hdr; | 204 BITMAPINFO hdr; |
161 gfx::CreateBitmapHeader(width, height, &hdr.bmiHeader); | 205 gfx::CreateBitmapHeader(width, height, &hdr.bmiHeader); |
162 HBITMAP hbitmap = CreateDIBSection( | 206 HBITMAP hbitmap = CreateDIBSection( |
163 bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0); | 207 bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0); |
164 if (!hbitmap) { | 208 if (!hbitmap) { |
165 NOTREACHED() << "Raster bitmap creation for printing failed"; | 209 NOTREACHED() << "Raster bitmap creation for printing failed"; |
166 } | 210 } |
167 | 211 |
168 HGDIOBJ old_bitmap = SelectObject(bitmap_dc, hbitmap); | 212 HGDIOBJ old_bitmap = SelectObject(bitmap_dc, hbitmap); |
169 RECT rect = {0, 0, width, height }; | 213 RECT rect = {0, 0, width, height }; |
170 HBRUSH whiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); | 214 HBRUSH whiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); |
171 FillRect(bitmap_dc, &rect, whiteBrush); | 215 FillRect(bitmap_dc, &rect, whiteBrush); |
172 | 216 |
173 metafile2.CreateDc(NULL, NULL); | 217 metafile2->CreateDc(NULL, NULL); |
174 HDC hdc = metafile2.hdc(); | 218 HDC hdc = metafile2->hdc(); |
175 DCHECK(hdc); | 219 DCHECK(hdc); |
176 skia::PlatformDevice::InitializeDC(hdc); | 220 skia::PlatformDevice::InitializeDC(hdc); |
177 | 221 |
178 RECT metafile_bounds = metafile.GetBounds().ToRECT(); | 222 RECT metafile_bounds = (*metafile)->GetBounds().ToRECT(); |
179 // Process the old metafile, placing all non-AlphaBlend calls into the | 223 // Process the old metafile, placing all non-AlphaBlend calls into the |
180 // new metafile, and copying the results of all the AlphaBlend calls | 224 // new metafile, and copying the results of all the AlphaBlend calls |
181 // from the bitmap DC. | 225 // from the bitmap DC. |
182 EnumEnhMetaFile(hdc, | 226 EnumEnhMetaFile(hdc, |
183 metafile.emf(), | 227 (*metafile)->emf(), |
184 EnhMetaFileProc, | 228 EnhMetaFileProc, |
185 &bitmap_dc, | 229 &bitmap_dc, |
186 &metafile_bounds); | 230 &metafile_bounds); |
187 | 231 |
188 SelectObject(bitmap_dc, old_bitmap); | 232 SelectObject(bitmap_dc, old_bitmap); |
233 metafile->reset(metafile2.release()); | |
234 } | |
235 } | |
189 | 236 |
190 if (!metafile2.CloseDc()) { | 237 bool PrintWebViewHelper::CopyMetafileDataToSharedMem( |
191 NOTREACHED() << "metafile failed"; | 238 printing::NativeMetafile* metafile, |
192 } | 239 base::SharedMemoryHandle* shared_mem_handle) { |
193 mf = &metafile2; | 240 bool ret_val = false; |
194 } | 241 uint32 buf_size = metafile->GetDataSize(); |
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; | 242 base::SharedMemory shared_buf; |
211 | 243 |
212 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx | 244 // http://msdn2.microsoft.com/en-us/library/ms535522.aspx |
213 // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 | 245 // 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. | 246 // MB, it can fail to print and not send an error message. |
215 if (buf_size < 350*1024*1024) { | 247 if (buf_size > 350*1024*1024) { |
Lei Zhang
2011/01/25 03:02:54
Change > to >= to preserve the original code.
kmadhusu
2011/01/25 17:39:18
Done.
| |
216 // Allocate a shared memory buffer to hold the generated metafile data. | 248 NOTREACHED() << "Buffer too large: " << buf_size; |
217 if (shared_buf.CreateAndMapAnonymous(buf_size)) { | 249 return ret_val; |
218 // Copy the bits into shared memory. | 250 } |
219 if (mf->GetData(shared_buf.memory(), buf_size)) { | 251 |
220 page_params.metafile_data_handle = shared_buf.handle(); | 252 // Allocate a shared memory buffer to hold the generated metafile data. |
221 page_params.data_size = buf_size; | 253 if (!shared_buf.CreateAndMapAnonymous(buf_size)) { |
222 } else { | 254 NOTREACHED() << "Buffer allocation failed"; |
223 NOTREACHED() << "GetData() failed"; | 255 return ret_val; |
224 } | 256 } |
225 shared_buf.Unmap(); | 257 |
226 } else { | 258 // Copy the bits into shared memory. |
227 NOTREACHED() << "Buffer allocation failed"; | 259 if (metafile->GetData(shared_buf.memory(), buf_size)) { |
Lei Zhang
2011/01/25 03:02:54
If you change this to:
if (!metafile->GetData())
kmadhusu
2011/01/25 17:39:18
Done.
| |
228 } | 260 shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), |
261 shared_mem_handle); | |
262 ret_val = true; | |
229 } else { | 263 } else { |
230 NOTREACHED() << "Buffer too large: " << buf_size; | 264 NOTREACHED() << "GetData() failed"; |
231 } | 265 } |
232 mf->CloseEmf(); | 266 shared_buf.Unmap(); |
233 if (Send(new ViewHostMsg_DuplicateSection( | 267 return ret_val; |
234 routing_id(), | |
235 page_params.metafile_data_handle, | |
236 &page_params.metafile_data_handle))) { | |
237 if (!is_preview_) { | |
Lei Zhang
2011/01/25 03:02:54
Do you need to add a placeholder here to say what
kmadhusu
2011/01/25 17:39:18
No. For preview workflow, we are not going to call
Lei Zhang
2011/01/25 20:01:05
If you're never going to call this function for pr
| |
238 Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); | |
239 } | |
240 } | |
241 } | 268 } |
OLD | NEW |