blob: a6005dc7f8ae0687de9ae3228990834e06fbbb73 [file] [log] [blame]
[email protected]f53351f2012-02-23 03:28:301// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]0e0fca32009-07-06 15:25:505#include "printing/emf_win.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]e6cddc572010-09-29 21:39:457#include "base/file_path.h"
initial.commit09911bf2008-07-26 23:55:298#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:159#include "base/memory/scoped_ptr.h"
[email protected]60d77bd2012-08-22 00:10:0710#include "base/win/scoped_gdi_object.h"
11#include "base/win/scoped_hdc.h"
12#include "base/win/scoped_select_object.h"
[email protected]9b617532011-04-04 23:15:0613#include "skia/ext/vector_platform_device_emf_win.h"
[email protected]38bba4f2010-03-12 05:29:0714#include "third_party/skia/include/core/SkBitmap.h"
[email protected]08397d52011-02-05 01:53:3815#include "ui/gfx/codec/jpeg_codec.h"
16#include "ui/gfx/codec/png_codec.h"
17#include "ui/gfx/gdi_util.h"
18#include "ui/gfx/rect.h"
[email protected]edc531f92011-03-18 17:52:2319#include "ui/gfx/size.h"
initial.commit09911bf2008-07-26 23:55:2920
[email protected]2aa8e182010-07-12 16:25:0421namespace {
[email protected]60d77bd2012-08-22 00:10:0722
[email protected]2aa8e182010-07-12 16:25:0423const int kCustomGdiCommentSignature = 0xdeadbabe;
24struct PageBreakRecord {
25 int signature;
26 enum PageBreakType {
27 START_PAGE,
28 END_PAGE,
29 } type;
30 explicit PageBreakRecord(PageBreakType type_in)
31 : signature(kCustomGdiCommentSignature), type(type_in) {
32 }
33 bool IsValid() const {
34 return (signature == kCustomGdiCommentSignature) &&
35 (type >= START_PAGE) && (type <= END_PAGE);
36 }
37};
[email protected]60d77bd2012-08-22 00:10:0738
39int CALLBACK IsAlphaBlendUsedEnumProc(HDC,
40 HANDLETABLE*,
41 const ENHMETARECORD *record,
42 int,
43 LPARAM data) {
44 bool* result = reinterpret_cast<bool*>(data);
45 if (!result)
46 return 0;
47 switch (record->iType) {
48 case EMR_ALPHABLEND: {
49 *result = true;
50 return 0;
51 break;
52 }
53 }
54 return 1;
[email protected]2aa8e182010-07-12 16:25:0455}
56
[email protected]64f5f922012-10-13 04:50:0657int CALLBACK RasterizeAlphaBlendProc(HDC metafile_dc,
58 HANDLETABLE* handle_table,
59 const ENHMETARECORD *record,
60 int num_objects,
61 LPARAM data) {
62 HDC bitmap_dc = *reinterpret_cast<HDC*>(data);
63 // Play this command to the bitmap DC.
64 ::PlayEnhMetaFileRecord(bitmap_dc, handle_table, record, num_objects);
65 switch (record->iType) {
66 case EMR_ALPHABLEND: {
67 const EMRALPHABLEND* alpha_blend =
68 reinterpret_cast<const EMRALPHABLEND*>(record);
69 // Don't modify transformation here.
70 // Old implementation did reset transformations for DC to identity matrix.
71 // That was not correct and cause some bugs, like unexpected cropping.
72 // EMRALPHABLEND is rendered into bitmap and metafile contexts with
73 // current transformation. If we don't touch them here BitBlt will copy
74 // same areas.
75 ::BitBlt(metafile_dc,
76 alpha_blend->xDest,
77 alpha_blend->yDest,
78 alpha_blend->cxDest,
79 alpha_blend->cyDest,
80 bitmap_dc,
81 alpha_blend->xDest,
82 alpha_blend->yDest,
83 SRCCOPY);
84 break;
85 }
86 case EMR_CREATEBRUSHINDIRECT:
87 case EMR_CREATECOLORSPACE:
88 case EMR_CREATECOLORSPACEW:
89 case EMR_CREATEDIBPATTERNBRUSHPT:
90 case EMR_CREATEMONOBRUSH:
91 case EMR_CREATEPALETTE:
92 case EMR_CREATEPEN:
93 case EMR_DELETECOLORSPACE:
94 case EMR_DELETEOBJECT:
95 case EMR_EXTCREATEFONTINDIRECTW:
96 // Play object creation command only once.
97 break;
98
99 default:
100 // Play this command to the metafile DC.
101 ::PlayEnhMetaFileRecord(metafile_dc, handle_table, record, num_objects);
102 break;
103 }
104 return 1; // Continue enumeration
105}
106
107// Bitmapt for rasterization.
108class RasterBitmap {
109 public:
110 explicit RasterBitmap(const gfx::Size& raster_size)
111 : saved_object_(NULL) {
112 context_.Set(::CreateCompatibleDC(NULL));
113 if (!context_) {
114 NOTREACHED() << "Bitmap DC creation failed";
115 return;
116 }
117 ::SetGraphicsMode(context_, GM_ADVANCED);
118 void* bits = NULL;
119 gfx::Rect bitmap_rect(raster_size);
120 gfx::CreateBitmapHeader(raster_size.width(), raster_size.height(),
121 &header_.bmiHeader);
122 bitmap_.Set(::CreateDIBSection(context_, &header_, DIB_RGB_COLORS, &bits,
123 NULL, 0));
124 if (!bitmap_)
125 NOTREACHED() << "Raster bitmap creation for printing failed";
126
127 saved_object_ = ::SelectObject(context_, bitmap_);
128 ::FillRect(context_, &bitmap_rect.ToRECT(),
129 static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH)));
130
131 }
132
133 ~RasterBitmap() {
134 ::SelectObject(context_, saved_object_);
135 }
136
137 HDC context() const {
138 return context_;
139 }
140
141 base::win::ScopedCreateDC context_;
142 BITMAPINFO header_;
143 base::win::ScopedBitmap bitmap_;
144 HGDIOBJ saved_object_;
145
146 private:
147 DISALLOW_COPY_AND_ASSIGN(RasterBitmap);
148};
149
150
151
[email protected]60d77bd2012-08-22 00:10:07152} // namespace
153
[email protected]0e0fca32009-07-06 15:25:50154namespace printing {
initial.commit09911bf2008-07-26 23:55:29155
[email protected]38bba4f2010-03-12 05:29:07156bool DIBFormatNativelySupported(HDC dc, uint32 escape, const BYTE* bits,
157 int size) {
158 BOOL supported = FALSE;
159 if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape),
160 reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) {
161 ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits),
162 sizeof(supported), reinterpret_cast<LPSTR>(&supported));
163 }
164 return !!supported;
165}
166
[email protected]830cf742011-04-01 16:06:25167Emf::Emf() : emf_(NULL), hdc_(NULL), page_count_(0) {
initial.commit09911bf2008-07-26 23:55:29168}
169
170Emf::~Emf() {
[email protected]481edc52011-03-22 06:36:58171 DCHECK(!hdc_);
172 if (emf_)
173 DeleteEnhMetaFile(emf_);
174}
175
176bool Emf::InitToFile(const FilePath& metafile_path) {
initial.commit09911bf2008-07-26 23:55:29177 DCHECK(!emf_ && !hdc_);
[email protected]481edc52011-03-22 06:36:58178 hdc_ = CreateEnhMetaFile(NULL, metafile_path.value().c_str(), NULL, NULL);
179 DCHECK(hdc_);
180 return hdc_ != NULL;
181}
182
183bool Emf::InitFromFile(const FilePath& metafile_path) {
184 DCHECK(!emf_ && !hdc_);
185 emf_ = GetEnhMetaFile(metafile_path.value().c_str());
186 DCHECK(emf_);
187 return emf_ != NULL;
188}
189
190bool Emf::Init() {
191 DCHECK(!emf_ && !hdc_);
192 hdc_ = CreateEnhMetaFile(NULL, NULL, NULL, NULL);
193 DCHECK(hdc_);
194 return hdc_ != NULL;
initial.commit09911bf2008-07-26 23:55:29195}
196
[email protected]89eff96a2011-03-17 23:22:06197bool Emf::InitFromData(const void* src_buffer, uint32 src_buffer_size) {
[email protected]e8980a52010-10-07 20:11:24198 DCHECK(!emf_ && !hdc_);
199 emf_ = SetEnhMetaFileBits(src_buffer_size,
200 reinterpret_cast<const BYTE*>(src_buffer));
[email protected]e8980a52010-10-07 20:11:24201 return emf_ != NULL;
202}
203
[email protected]cdd19f52011-03-19 01:04:57204bool Emf::FinishDocument() {
initial.commit09911bf2008-07-26 23:55:29205 DCHECK(!emf_ && hdc_);
206 emf_ = CloseEnhMetaFile(hdc_);
207 DCHECK(emf_);
208 hdc_ = NULL;
209 return emf_ != NULL;
210}
211
initial.commit09911bf2008-07-26 23:55:29212bool Emf::Playback(HDC hdc, const RECT* rect) const {
213 DCHECK(emf_ && !hdc_);
214 RECT bounds;
215 if (!rect) {
216 // Get the natural bounds of the EMF buffer.
[email protected]8f17cd3e2011-03-16 01:39:42217 bounds = GetPageBounds(1).ToRECT();
initial.commit09911bf2008-07-26 23:55:29218 rect = &bounds;
219 }
220 return PlayEnhMetaFile(hdc, emf_, rect) != 0;
221}
222
223bool Emf::SafePlayback(HDC context) const {
224 DCHECK(emf_ && !hdc_);
225 XFORM base_matrix;
226 if (!GetWorldTransform(context, &base_matrix)) {
227 NOTREACHED();
228 return false;
229 }
[email protected]0064b392012-06-20 01:57:38230 Emf::EnumerationContext playback_context;
231 playback_context.base_matrix = &base_matrix;
initial.commit09911bf2008-07-26 23:55:29232 return EnumEnhMetaFile(context,
233 emf_,
234 &Emf::SafePlaybackProc,
[email protected]0064b392012-06-20 01:57:38235 reinterpret_cast<void*>(&playback_context),
[email protected]8f17cd3e2011-03-16 01:39:42236 &GetPageBounds(1).ToRECT()) != 0;
initial.commit09911bf2008-07-26 23:55:29237}
238
[email protected]8f17cd3e2011-03-16 01:39:42239gfx::Rect Emf::GetPageBounds(unsigned int page_number) const {
initial.commit09911bf2008-07-26 23:55:29240 DCHECK(emf_ && !hdc_);
[email protected]8f17cd3e2011-03-16 01:39:42241 DCHECK_EQ(1U, page_number);
initial.commit09911bf2008-07-26 23:55:29242 ENHMETAHEADER header;
243 if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) {
244 NOTREACHED();
245 return gfx::Rect();
246 }
[email protected]60d77bd2012-08-22 00:10:07247 // Add 1 to right and bottom because it's inclusive rectangle.
248 // See ENHMETAHEADER.
initial.commit09911bf2008-07-26 23:55:29249 return gfx::Rect(header.rclBounds.left,
250 header.rclBounds.top,
[email protected]60d77bd2012-08-22 00:10:07251 header.rclBounds.right - header.rclBounds.left + 1,
252 header.rclBounds.bottom - header.rclBounds.top + 1);
initial.commit09911bf2008-07-26 23:55:29253}
254
[email protected]b5ab3982010-02-16 23:58:27255uint32 Emf::GetDataSize() const {
initial.commit09911bf2008-07-26 23:55:29256 DCHECK(emf_ && !hdc_);
257 return GetEnhMetaFileBits(emf_, 0, NULL);
258}
259
[email protected]b5ab3982010-02-16 23:58:27260bool Emf::GetData(void* buffer, uint32 size) const {
initial.commit09911bf2008-07-26 23:55:29261 DCHECK(emf_ && !hdc_);
262 DCHECK(buffer && size);
[email protected]b5ab3982010-02-16 23:58:27263 uint32 size2 =
264 GetEnhMetaFileBits(emf_, size, reinterpret_cast<BYTE*>(buffer));
initial.commit09911bf2008-07-26 23:55:29265 DCHECK(size2 == size);
266 return size2 == size && size2 != 0;
267}
268
[email protected]96fddd82011-03-24 23:37:45269bool Emf::GetDataAsVector(std::vector<uint8>* buffer) const {
[email protected]b5ab3982010-02-16 23:58:27270 uint32 size = GetDataSize();
initial.commit09911bf2008-07-26 23:55:29271 if (!size)
272 return false;
273
274 buffer->resize(size);
275 if (!GetData(&buffer->front(), size))
276 return false;
277 return true;
278}
279
[email protected]8f17cd3e2011-03-16 01:39:42280bool Emf::SaveTo(const FilePath& file_path) const {
281 HANDLE file = CreateFile(file_path.value().c_str(), GENERIC_WRITE,
initial.commit09911bf2008-07-26 23:55:29282 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
283 CREATE_ALWAYS, 0, NULL);
284 if (file == INVALID_HANDLE_VALUE)
285 return false;
286
287 bool success = false;
288 std::vector<uint8> buffer;
[email protected]96fddd82011-03-24 23:37:45289 if (GetDataAsVector(&buffer)) {
initial.commit09911bf2008-07-26 23:55:29290 DWORD written = 0;
291 if (WriteFile(file, &*buffer.begin(), static_cast<DWORD>(buffer.size()),
292 &written, NULL) &&
293 written == buffer.size()) {
294 success = true;
295 }
296 }
297 CloseHandle(file);
298 return success;
299}
300
301int CALLBACK Emf::SafePlaybackProc(HDC hdc,
302 HANDLETABLE* handle_table,
303 const ENHMETARECORD* record,
304 int objects_count,
305 LPARAM param) {
[email protected]0064b392012-06-20 01:57:38306 Emf::EnumerationContext* context =
307 reinterpret_cast<Emf::EnumerationContext*>(param);
308 context->handle_table = handle_table;
309 context->objects_count = objects_count;
310 context->hdc = hdc;
311 Record record_instance(record);
312 bool success = record_instance.SafePlayback(context);
initial.commit09911bf2008-07-26 23:55:29313 DCHECK(success);
314 return 1;
315}
316
[email protected]0064b392012-06-20 01:57:38317Emf::EnumerationContext::EnumerationContext() {
318 memset(this, 0, sizeof(*this));
319}
320
321Emf::Record::Record(const ENHMETARECORD* record)
322 : record_(record) {
initial.commit09911bf2008-07-26 23:55:29323 DCHECK(record_);
324}
325
[email protected]0064b392012-06-20 01:57:38326bool Emf::Record::Play(Emf::EnumerationContext* context) const {
327 return 0 != PlayEnhMetaFileRecord(context->hdc,
328 context->handle_table,
initial.commit09911bf2008-07-26 23:55:29329 record_,
[email protected]0064b392012-06-20 01:57:38330 context->objects_count);
initial.commit09911bf2008-07-26 23:55:29331}
332
[email protected]0064b392012-06-20 01:57:38333bool Emf::Record::SafePlayback(Emf::EnumerationContext* context) const {
initial.commit09911bf2008-07-26 23:55:29334 // For EMF field description, see [MS-EMF] Enhanced Metafile Format
335 // Specification.
336 //
337 // This is the second major EMF breakage I get; the first one being
338 // SetDCBrushColor/SetDCPenColor/DC_PEN/DC_BRUSH being silently ignored.
339 //
340 // This function is the guts of the fix for bug 1186598. Some printer drivers
341 // somehow choke on certain EMF records, but calling the corresponding
342 // function directly on the printer HDC is fine. Still, playing the EMF record
343 // fails. Go figure.
344 //
345 // The main issue is that SetLayout is totally unsupported on these printers
346 // (HP 4500/4700). I used to call SetLayout and I stopped. I found out this is
347 // not sufficient because GDI32!PlayEnhMetaFile internally calls SetLayout(!)
348 // Damn.
349 //
350 // So I resorted to manually parse the EMF records and play them one by one.
351 // The issue with this method compared to using PlayEnhMetaFile to play back
352 // an EMF buffer is that the later silently fixes the matrix to take in
353 // account the matrix currently loaded at the time of the call.
354 // The matrix magic is done transparently when using PlayEnhMetaFile but since
355 // I'm processing one field at a time, I need to do the fixup myself. Note
356 // that PlayEnhMetaFileRecord doesn't fix the matrix correctly even when
357 // called inside an EnumEnhMetaFile loop. Go figure (bis).
358 //
359 // So when I see a EMR_SETWORLDTRANSFORM and EMR_MODIFYWORLDTRANSFORM, I need
360 // to fix the matrix according to the matrix previously loaded before playing
361 // back the buffer. Otherwise, the previously loaded matrix would be ignored
362 // and the EMF buffer would always be played back at its native resolution.
363 // Duh.
364 //
365 // I also use this opportunity to skip over eventual EMR_SETLAYOUT record that
366 // could remain.
367 //
[email protected]38bba4f2010-03-12 05:29:07368 // Another tweak we make is for JPEGs/PNGs in calls to StretchDIBits.
369 // (Our Pepper plugin code uses a JPEG). If the printer does not support
370 // JPEGs/PNGs natively we decompress the JPEG/PNG and then set it to the
371 // device.
372 // TODO(sanjeevr): We should also add JPEG/PNG support for SetSIBitsToDevice
373 //
[email protected]2aa8e182010-07-12 16:25:04374 // We also process any custom EMR_GDICOMMENT records which are our
375 // placeholders for StartPage and EndPage.
initial.commit09911bf2008-07-26 23:55:29376 // Note: I should probably care about view ports and clipping, eventually.
[email protected]0064b392012-06-20 01:57:38377 bool res = false;
378 const XFORM* base_matrix = context->base_matrix;
initial.commit09911bf2008-07-26 23:55:29379 switch (record()->iType) {
[email protected]38bba4f2010-03-12 05:29:07380 case EMR_STRETCHDIBITS: {
381 const EMRSTRETCHDIBITS * sdib_record =
382 reinterpret_cast<const EMRSTRETCHDIBITS*>(record());
383 const BYTE* record_start = reinterpret_cast<const BYTE *>(record());
384 const BITMAPINFOHEADER *bmih =
385 reinterpret_cast<const BITMAPINFOHEADER *>(record_start +
386 sdib_record->offBmiSrc);
387 const BYTE* bits = record_start + sdib_record->offBitsSrc;
388 bool play_normally = true;
389 res = false;
[email protected]0064b392012-06-20 01:57:38390 HDC hdc = context->hdc;
[email protected]38bba4f2010-03-12 05:29:07391 scoped_ptr<SkBitmap> bitmap;
392 if (bmih->biCompression == BI_JPEG) {
393 if (!DIBFormatNativelySupported(hdc, CHECKJPEGFORMAT, bits,
394 bmih->biSizeImage)) {
395 play_normally = false;
[email protected]38bba4f2010-03-12 05:29:07396 bitmap.reset(gfx::JPEGCodec::Decode(bits, bmih->biSizeImage));
[email protected]38bba4f2010-03-12 05:29:07397 }
398 } else if (bmih->biCompression == BI_PNG) {
399 if (!DIBFormatNativelySupported(hdc, CHECKPNGFORMAT, bits,
400 bmih->biSizeImage)) {
401 play_normally = false;
402 bitmap.reset(new SkBitmap());
[email protected]38bba4f2010-03-12 05:29:07403 gfx::PNGCodec::Decode(bits, bmih->biSizeImage, bitmap.get());
[email protected]38bba4f2010-03-12 05:29:07404 }
405 }
406 if (!play_normally) {
407 DCHECK(bitmap.get());
408 if (bitmap.get()) {
409 SkAutoLockPixels lock(*bitmap.get());
[email protected]125b62002012-03-19 14:30:40410 DCHECK_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
[email protected]38bba4f2010-03-12 05:29:07411 const uint32_t* pixels =
412 static_cast<const uint32_t*>(bitmap->getPixels());
413 if (pixels == NULL) {
414 NOTREACHED();
415 return false;
416 }
417 BITMAPINFOHEADER bmi = {0};
418 gfx::CreateBitmapHeader(bitmap->width(), bitmap->height(), &bmi);
419 res = (0 != StretchDIBits(hdc, sdib_record->xDest, sdib_record->yDest,
420 sdib_record->cxDest,
421 sdib_record->cyDest, sdib_record->xSrc,
422 sdib_record->ySrc,
423 sdib_record->cxSrc, sdib_record->cySrc,
424 pixels,
425 reinterpret_cast<const BITMAPINFO *>(&bmi),
426 sdib_record->iUsageSrc,
427 sdib_record->dwRop));
428 }
429 } else {
[email protected]0064b392012-06-20 01:57:38430 res = Play(context);
[email protected]38bba4f2010-03-12 05:29:07431 }
432 break;
433 }
initial.commit09911bf2008-07-26 23:55:29434 case EMR_SETWORLDTRANSFORM: {
435 DCHECK_EQ(record()->nSize, sizeof(DWORD) * 2 + sizeof(XFORM));
436 const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
[email protected]0064b392012-06-20 01:57:38437 HDC hdc = context->hdc;
initial.commit09911bf2008-07-26 23:55:29438 if (base_matrix) {
439 res = 0 != SetWorldTransform(hdc, base_matrix) &&
440 ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
441 } else {
442 res = 0 != SetWorldTransform(hdc, xform);
443 }
444 break;
445 }
446 case EMR_MODIFYWORLDTRANSFORM: {
447 DCHECK_EQ(record()->nSize,
448 sizeof(DWORD) * 2 + sizeof(XFORM) + sizeof(DWORD));
449 const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
450 const DWORD* option = reinterpret_cast<const DWORD*>(xform + 1);
[email protected]0064b392012-06-20 01:57:38451 HDC hdc = context->hdc;
initial.commit09911bf2008-07-26 23:55:29452 switch (*option) {
453 case MWT_IDENTITY:
454 if (base_matrix) {
455 res = 0 != SetWorldTransform(hdc, base_matrix);
456 } else {
457 res = 0 != ModifyWorldTransform(hdc, xform, MWT_IDENTITY);
458 }
459 break;
460 case MWT_LEFTMULTIPLY:
461 case MWT_RIGHTMULTIPLY:
462 res = 0 != ModifyWorldTransform(hdc, xform, *option);
463 break;
464 case 4: // MWT_SET
465 if (base_matrix) {
466 res = 0 != SetWorldTransform(hdc, base_matrix) &&
467 ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
468 } else {
469 res = 0 != SetWorldTransform(hdc, xform);
470 }
471 break;
472 default:
473 res = false;
474 break;
475 }
476 break;
477 }
478 case EMR_SETLAYOUT:
479 // Ignore it.
480 res = true;
481 break;
[email protected]2aa8e182010-07-12 16:25:04482 case EMR_GDICOMMENT: {
483 const EMRGDICOMMENT* comment_record =
484 reinterpret_cast<const EMRGDICOMMENT*>(record());
485 if (comment_record->cbData == sizeof(PageBreakRecord)) {
486 const PageBreakRecord* page_break_record =
487 reinterpret_cast<const PageBreakRecord*>(comment_record->Data);
488 if (page_break_record && page_break_record->IsValid()) {
489 if (page_break_record->type == PageBreakRecord::START_PAGE) {
[email protected]0064b392012-06-20 01:57:38490 res = !!::StartPage(context->hdc);
491 DCHECK_EQ(0, context->dc_on_page_start);
492 context->dc_on_page_start = ::SaveDC(context->hdc);
[email protected]2aa8e182010-07-12 16:25:04493 } else if (page_break_record->type == PageBreakRecord::END_PAGE) {
[email protected]0064b392012-06-20 01:57:38494 DCHECK_NE(0, context->dc_on_page_start);
495 ::RestoreDC(context->hdc, context->dc_on_page_start);
496 context->dc_on_page_start = 0;
497 res = !!::EndPage(context->hdc);
[email protected]2aa8e182010-07-12 16:25:04498 } else {
499 res = false;
500 NOTREACHED();
501 }
502 } else {
[email protected]0064b392012-06-20 01:57:38503 res = Play(context);
[email protected]2aa8e182010-07-12 16:25:04504 }
[email protected]b2b0fce2011-01-12 16:34:40505 } else {
506 res = true;
[email protected]2aa8e182010-07-12 16:25:04507 }
508 break;
509 }
initial.commit09911bf2008-07-26 23:55:29510 default: {
[email protected]0064b392012-06-20 01:57:38511 res = Play(context);
initial.commit09911bf2008-07-26 23:55:29512 break;
513 }
514 }
515 return res;
516}
517
[email protected]62f2e802011-05-26 14:28:35518SkDevice* Emf::StartPageForVectorCanvas(
[email protected]534c4fb2011-08-02 16:44:20519 const gfx::Size& page_size, const gfx::Rect& content_area,
[email protected]d2fdcf02011-03-21 22:16:43520 const float& scale_factor) {
[email protected]39892b92011-04-30 02:24:44521 if (!StartPage(page_size, content_area, scale_factor))
[email protected]d2fdcf02011-03-21 22:16:43522 return NULL;
523
[email protected]1e564162011-07-05 14:17:31524 return skia::VectorPlatformDeviceEmf::CreateDevice(page_size.width(),
525 page_size.height(),
526 true, hdc_);
[email protected]d2fdcf02011-03-21 22:16:43527}
528
[email protected]edc531f92011-03-18 17:52:23529bool Emf::StartPage(const gfx::Size& /*page_size*/,
[email protected]39892b92011-04-30 02:24:44530 const gfx::Rect& /*content_area*/,
[email protected]1c7d72d2011-04-20 06:59:23531 const float& /*scale_factor*/) {
[email protected]2aa8e182010-07-12 16:25:04532 DCHECK(hdc_);
533 if (!hdc_)
534 return false;
[email protected]830cf742011-04-01 16:06:25535 page_count_++;
[email protected]2aa8e182010-07-12 16:25:04536 PageBreakRecord record(PageBreakRecord::START_PAGE);
537 return !!GdiComment(hdc_, sizeof(record),
538 reinterpret_cast<const BYTE *>(&record));
539}
540
[email protected]8f17cd3e2011-03-16 01:39:42541bool Emf::FinishPage() {
[email protected]2aa8e182010-07-12 16:25:04542 DCHECK(hdc_);
543 if (!hdc_)
544 return false;
545 PageBreakRecord record(PageBreakRecord::END_PAGE);
546 return !!GdiComment(hdc_, sizeof(record),
547 reinterpret_cast<const BYTE *>(&record));
548}
549
initial.commit09911bf2008-07-26 23:55:29550Emf::Enumerator::Enumerator(const Emf& emf, HDC context, const RECT* rect) {
initial.commit09911bf2008-07-26 23:55:29551 items_.clear();
552 if (!EnumEnhMetaFile(context,
553 emf.emf(),
554 &Emf::Enumerator::EnhMetaFileProc,
555 reinterpret_cast<void*>(this),
556 rect)) {
557 NOTREACHED();
558 items_.clear();
559 }
560 DCHECK_EQ(context_.hdc, context);
561}
562
563Emf::Enumerator::const_iterator Emf::Enumerator::begin() const {
564 return items_.begin();
565}
566
567Emf::Enumerator::const_iterator Emf::Enumerator::end() const {
568 return items_.end();
569}
570
571int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc,
572 HANDLETABLE* handle_table,
573 const ENHMETARECORD* record,
574 int objects_count,
575 LPARAM param) {
576 Enumerator& emf = *reinterpret_cast<Enumerator*>(param);
577 if (!emf.context_.handle_table) {
578 DCHECK(!emf.context_.handle_table);
579 DCHECK(!emf.context_.objects_count);
580 emf.context_.handle_table = handle_table;
581 emf.context_.objects_count = objects_count;
582 emf.context_.hdc = hdc;
583 } else {
584 DCHECK_EQ(emf.context_.handle_table, handle_table);
585 DCHECK_EQ(emf.context_.objects_count, objects_count);
586 DCHECK_EQ(emf.context_.hdc, hdc);
587 }
[email protected]0064b392012-06-20 01:57:38588 emf.items_.push_back(Record(record));
initial.commit09911bf2008-07-26 23:55:29589 return 1;
590}
591
[email protected]60d77bd2012-08-22 00:10:07592bool Emf::IsAlphaBlendUsed() const {
593 bool result = false;
594 ::EnumEnhMetaFile(NULL,
595 emf(),
596 &IsAlphaBlendUsedEnumProc,
597 &result,
598 NULL);
599 return result;
600}
601
602Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const {
603 gfx::Rect page_bounds = GetPageBounds(1);
604 gfx::Size page_size(page_bounds.size());
605 if (page_size.GetArea() <= 0) {
606 NOTREACHED() << "Metafile is empty";
607 page_bounds = gfx::Rect(1, 1);
608 }
609
610 float scale = sqrt(float(raster_area_in_pixels) / page_size.GetArea());
611 page_size.set_width(std::max<int>(1, page_size.width() * scale));
612 page_size.set_height(std::max<int>(1, page_size.height() * scale));
613
[email protected]60d77bd2012-08-22 00:10:07614
[email protected]64f5f922012-10-13 04:50:06615 RasterBitmap bitmap(page_size);
[email protected]60d77bd2012-08-22 00:10:07616
617 gfx::Rect bitmap_rect(page_size);
[email protected]64f5f922012-10-13 04:50:06618 Playback(bitmap.context(), &bitmap_rect.ToRECT());
[email protected]60d77bd2012-08-22 00:10:07619
620 scoped_ptr<Emf> result(new Emf);
621 result->Init();
622 HDC hdc = result->context();
623 DCHECK(hdc);
624 skia::InitializeDC(hdc);
625
626 // Params are ignored.
627 result->StartPage(page_bounds.size(), page_bounds, 1);
628
629 ::ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
630 XFORM xform = {
631 float(page_bounds.width()) / bitmap_rect.width(), 0,
632 0, float(page_bounds.height()) / bitmap_rect.height(),
633 page_bounds.x(),
634 page_bounds.y(),
635 };
636 ::SetWorldTransform(hdc, &xform);
637 ::BitBlt(hdc, 0, 0, bitmap_rect.width(), bitmap_rect.height(),
[email protected]64f5f922012-10-13 04:50:06638 bitmap.context(), bitmap_rect.x(), bitmap_rect.y(), SRCCOPY);
[email protected]60d77bd2012-08-22 00:10:07639
640 result->FinishPage();
641 result->FinishDocument();
642
643 return result.release();
644}
645
[email protected]64f5f922012-10-13 04:50:06646Emf* Emf::RasterizeAlphaBlend() const {
647 gfx::Rect page_bounds = GetPageBounds(1);
648 if (page_bounds.size().GetArea() <= 0) {
649 NOTREACHED() << "Metafile is empty";
650 page_bounds = gfx::Rect(1, 1);
651 }
652
653 RasterBitmap bitmap(page_bounds.size());
654
655 // Map metafile page_bounds.x(), page_bounds.y() to bitmap 0, 0.
656 XFORM xform = { 1, 0, 0, 1, -page_bounds.x(), -page_bounds.y()};
657 ::SetWorldTransform(bitmap.context(), &xform);
658
659 scoped_ptr<Emf> result(new Emf);
660 result->Init();
661 HDC hdc = result->context();
662 DCHECK(hdc);
663 skia::InitializeDC(hdc);
664
665 HDC bitmap_dc = bitmap.context();
666 ::EnumEnhMetaFile(hdc, emf(), &RasterizeAlphaBlendProc, &bitmap_dc,
667 &page_bounds.ToRECT());
668
669 result->FinishDocument();
670
671 return result.release();
672}
673
674
[email protected]0e0fca32009-07-06 15:25:50675} // namespace printing