Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / printing / emf_win.cc
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
3 // found in the LICENSE file.
4
5 #include "printing/emf_win.h"
6
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/win/scoped_gdi_object.h"
11 #include "base/win/scoped_hdc.h"
12 #include "base/win/scoped_select_object.h"
13 #include "skia/ext/vector_platform_device_emf_win.h"
14 #include "third_party/skia/include/core/SkBitmap.h"
15 #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"
19 #include "ui/gfx/size.h"
20
21 namespace {
22
23 const int kCustomGdiCommentSignature = 0xdeadbabe;
24 struct 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 };
38
39 int 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;
55 }
56
57 int 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.
108 class 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     RECT rect = bitmap_rect.ToRECT();
129     ::FillRect(context_, &rect,
130                static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH)));
131
132   }
133
134   ~RasterBitmap() {
135     ::SelectObject(context_, saved_object_);
136   }
137
138   HDC context() const {
139     return context_;
140   }
141
142   base::win::ScopedCreateDC context_;
143   BITMAPINFO header_;
144   base::win::ScopedBitmap bitmap_;
145   HGDIOBJ saved_object_;
146
147  private:
148   DISALLOW_COPY_AND_ASSIGN(RasterBitmap);
149 };
150
151
152
153 }  // namespace
154
155 namespace printing {
156
157 bool DIBFormatNativelySupported(HDC dc, uint32 escape, const BYTE* bits,
158                                 int size) {
159   BOOL supported = FALSE;
160   if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape),
161                 reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) {
162     ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits),
163               sizeof(supported), reinterpret_cast<LPSTR>(&supported));
164   }
165   return !!supported;
166 }
167
168 Emf::Emf() : emf_(NULL), hdc_(NULL), page_count_(0) {
169 }
170
171 Emf::~Emf() {
172   Close();
173 }
174
175 void Emf::Close() {
176   DCHECK(!hdc_);
177   if (emf_)
178     DeleteEnhMetaFile(emf_);
179   emf_ = NULL;
180 }
181
182 bool Emf::InitToFile(const base::FilePath& metafile_path) {
183   DCHECK(!emf_ && !hdc_);
184   hdc_ = CreateEnhMetaFile(NULL, metafile_path.value().c_str(), NULL, NULL);
185   DCHECK(hdc_);
186   return hdc_ != NULL;
187 }
188
189 bool Emf::InitFromFile(const base::FilePath& metafile_path) {
190   DCHECK(!emf_ && !hdc_);
191   emf_ = GetEnhMetaFile(metafile_path.value().c_str());
192   DCHECK(emf_);
193   return emf_ != NULL;
194 }
195
196 bool Emf::Init() {
197   DCHECK(!emf_ && !hdc_);
198   hdc_ = CreateEnhMetaFile(NULL, NULL, NULL, NULL);
199   DCHECK(hdc_);
200   return hdc_ != NULL;
201 }
202
203 bool Emf::InitFromData(const void* src_buffer, uint32 src_buffer_size) {
204   DCHECK(!emf_ && !hdc_);
205   emf_ = SetEnhMetaFileBits(src_buffer_size,
206                             reinterpret_cast<const BYTE*>(src_buffer));
207   return emf_ != NULL;
208 }
209
210 bool Emf::FinishDocument() {
211   DCHECK(!emf_ && hdc_);
212   emf_ = CloseEnhMetaFile(hdc_);
213   DCHECK(emf_);
214   hdc_ = NULL;
215   return emf_ != NULL;
216 }
217
218 bool Emf::Playback(HDC hdc, const RECT* rect) const {
219   DCHECK(emf_ && !hdc_);
220   RECT bounds;
221   if (!rect) {
222     // Get the natural bounds of the EMF buffer.
223     bounds = GetPageBounds(1).ToRECT();
224     rect = &bounds;
225   }
226   return PlayEnhMetaFile(hdc, emf_, rect) != 0;
227 }
228
229 bool Emf::SafePlayback(HDC context) const {
230   DCHECK(emf_ && !hdc_);
231   XFORM base_matrix;
232   if (!GetWorldTransform(context, &base_matrix)) {
233     NOTREACHED();
234     return false;
235   }
236   Emf::EnumerationContext playback_context;
237   playback_context.base_matrix = &base_matrix;
238   RECT rect = GetPageBounds(1).ToRECT();
239   return EnumEnhMetaFile(context,
240                          emf_,
241                          &Emf::SafePlaybackProc,
242                          reinterpret_cast<void*>(&playback_context),
243                          &rect) != 0;
244 }
245
246 gfx::Rect Emf::GetPageBounds(unsigned int page_number) const {
247   DCHECK(emf_ && !hdc_);
248   DCHECK_EQ(1U, page_number);
249   ENHMETAHEADER header;
250   if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) {
251     NOTREACHED();
252     return gfx::Rect();
253   }
254   // Add 1 to right and bottom because it's inclusive rectangle.
255   // See ENHMETAHEADER.
256   return gfx::Rect(header.rclBounds.left,
257                    header.rclBounds.top,
258                    header.rclBounds.right - header.rclBounds.left + 1,
259                    header.rclBounds.bottom - header.rclBounds.top + 1);
260 }
261
262 uint32 Emf::GetDataSize() const {
263   DCHECK(emf_ && !hdc_);
264   return GetEnhMetaFileBits(emf_, 0, NULL);
265 }
266
267 bool Emf::GetData(void* buffer, uint32 size) const {
268   DCHECK(emf_ && !hdc_);
269   DCHECK(buffer && size);
270   uint32 size2 =
271       GetEnhMetaFileBits(emf_, size, reinterpret_cast<BYTE*>(buffer));
272   DCHECK(size2 == size);
273   return size2 == size && size2 != 0;
274 }
275
276 bool Emf::GetDataAsVector(std::vector<uint8>* buffer) const {
277   uint32 size = GetDataSize();
278   if (!size)
279     return false;
280
281   buffer->resize(size);
282   if (!GetData(&buffer->front(), size))
283     return false;
284   return true;
285 }
286
287 bool Emf::SaveTo(const base::FilePath& file_path) const {
288   HANDLE file = CreateFile(file_path.value().c_str(), GENERIC_WRITE,
289                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
290                            CREATE_ALWAYS, 0, NULL);
291   if (file == INVALID_HANDLE_VALUE)
292     return false;
293
294   bool success = false;
295   std::vector<uint8> buffer;
296   if (GetDataAsVector(&buffer)) {
297     DWORD written = 0;
298     if (WriteFile(file, &*buffer.begin(), static_cast<DWORD>(buffer.size()),
299                   &written, NULL) &&
300         written == buffer.size()) {
301       success = true;
302     }
303   }
304   CloseHandle(file);
305   return success;
306 }
307
308 int CALLBACK Emf::SafePlaybackProc(HDC hdc,
309                                    HANDLETABLE* handle_table,
310                                    const ENHMETARECORD* record,
311                                    int objects_count,
312                                    LPARAM param) {
313   Emf::EnumerationContext* context =
314       reinterpret_cast<Emf::EnumerationContext*>(param);
315   context->handle_table = handle_table;
316   context->objects_count = objects_count;
317   context->hdc = hdc;
318   Record record_instance(record);
319   bool success = record_instance.SafePlayback(context);
320   DCHECK(success);
321   return 1;
322 }
323
324 Emf::EnumerationContext::EnumerationContext() {
325   memset(this, 0, sizeof(*this));
326 }
327
328 Emf::Record::Record(const ENHMETARECORD* record)
329     : record_(record) {
330   DCHECK(record_);
331 }
332
333 bool Emf::Record::Play(Emf::EnumerationContext* context) const {
334   return 0 != PlayEnhMetaFileRecord(context->hdc,
335                                     context->handle_table,
336                                     record_,
337                                     context->objects_count);
338 }
339
340 bool Emf::Record::SafePlayback(Emf::EnumerationContext* context) const {
341   // For EMF field description, see [MS-EMF] Enhanced Metafile Format
342   // Specification.
343   //
344   // This is the second major EMF breakage I get; the first one being
345   // SetDCBrushColor/SetDCPenColor/DC_PEN/DC_BRUSH being silently ignored.
346   //
347   // This function is the guts of the fix for bug 1186598. Some printer drivers
348   // somehow choke on certain EMF records, but calling the corresponding
349   // function directly on the printer HDC is fine. Still, playing the EMF record
350   // fails. Go figure.
351   //
352   // The main issue is that SetLayout is totally unsupported on these printers
353   // (HP 4500/4700). I used to call SetLayout and I stopped. I found out this is
354   // not sufficient because GDI32!PlayEnhMetaFile internally calls SetLayout(!)
355   // Damn.
356   //
357   // So I resorted to manually parse the EMF records and play them one by one.
358   // The issue with this method compared to using PlayEnhMetaFile to play back
359   // an EMF buffer is that the later silently fixes the matrix to take in
360   // account the matrix currently loaded at the time of the call.
361   // The matrix magic is done transparently when using PlayEnhMetaFile but since
362   // I'm processing one field at a time, I need to do the fixup myself. Note
363   // that PlayEnhMetaFileRecord doesn't fix the matrix correctly even when
364   // called inside an EnumEnhMetaFile loop. Go figure (bis).
365   //
366   // So when I see a EMR_SETWORLDTRANSFORM and EMR_MODIFYWORLDTRANSFORM, I need
367   // to fix the matrix according to the matrix previously loaded before playing
368   // back the buffer. Otherwise, the previously loaded matrix would be ignored
369   // and the EMF buffer would always be played back at its native resolution.
370   // Duh.
371   //
372   // I also use this opportunity to skip over eventual EMR_SETLAYOUT record that
373   // could remain.
374   //
375   // Another tweak we make is for JPEGs/PNGs in calls to StretchDIBits.
376   // (Our Pepper plugin code uses a JPEG). If the printer does not support
377   // JPEGs/PNGs natively we decompress the JPEG/PNG and then set it to the
378   // device.
379   // TODO(sanjeevr): We should also add JPEG/PNG support for SetSIBitsToDevice
380   //
381   // We also process any custom EMR_GDICOMMENT records which are our
382   // placeholders for StartPage and EndPage.
383   // Note: I should probably care about view ports and clipping, eventually.
384   bool res = false;
385   const XFORM* base_matrix = context->base_matrix;
386   switch (record()->iType) {
387     case EMR_STRETCHDIBITS: {
388       const EMRSTRETCHDIBITS * sdib_record =
389           reinterpret_cast<const EMRSTRETCHDIBITS*>(record());
390       const BYTE* record_start = reinterpret_cast<const BYTE *>(record());
391       const BITMAPINFOHEADER *bmih =
392           reinterpret_cast<const BITMAPINFOHEADER *>(record_start +
393                                                      sdib_record->offBmiSrc);
394       const BYTE* bits = record_start + sdib_record->offBitsSrc;
395       bool play_normally = true;
396       res = false;
397       HDC hdc = context->hdc;
398       scoped_ptr<SkBitmap> bitmap;
399       if (bmih->biCompression == BI_JPEG) {
400         if (!DIBFormatNativelySupported(hdc, CHECKJPEGFORMAT, bits,
401                                         bmih->biSizeImage)) {
402           play_normally = false;
403           bitmap.reset(gfx::JPEGCodec::Decode(bits, bmih->biSizeImage));
404         }
405       } else if (bmih->biCompression == BI_PNG) {
406         if (!DIBFormatNativelySupported(hdc, CHECKPNGFORMAT, bits,
407                                         bmih->biSizeImage)) {
408           play_normally = false;
409           bitmap.reset(new SkBitmap());
410           gfx::PNGCodec::Decode(bits, bmih->biSizeImage, bitmap.get());
411         }
412       }
413       if (!play_normally) {
414         DCHECK(bitmap.get());
415         if (bitmap.get()) {
416           SkAutoLockPixels lock(*bitmap.get());
417           DCHECK_EQ(bitmap->colorType(), kN32_SkColorType);
418           const uint32_t* pixels =
419               static_cast<const uint32_t*>(bitmap->getPixels());
420           if (pixels == NULL) {
421             NOTREACHED();
422             return false;
423           }
424           BITMAPINFOHEADER bmi = {0};
425           gfx::CreateBitmapHeader(bitmap->width(), bitmap->height(), &bmi);
426           res = (0 != StretchDIBits(hdc, sdib_record->xDest, sdib_record->yDest,
427                                     sdib_record->cxDest,
428                                     sdib_record->cyDest, sdib_record->xSrc,
429                                     sdib_record->ySrc,
430                                     sdib_record->cxSrc, sdib_record->cySrc,
431                                     pixels,
432                                     reinterpret_cast<const BITMAPINFO *>(&bmi),
433                                     sdib_record->iUsageSrc,
434                                     sdib_record->dwRop));
435         }
436       } else {
437         res = Play(context);
438       }
439       break;
440     }
441     case EMR_SETWORLDTRANSFORM: {
442       DCHECK_EQ(record()->nSize, sizeof(DWORD) * 2 + sizeof(XFORM));
443       const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
444       HDC hdc = context->hdc;
445       if (base_matrix) {
446         res = 0 != SetWorldTransform(hdc, base_matrix) &&
447                    ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
448       } else {
449         res = 0 != SetWorldTransform(hdc, xform);
450       }
451       break;
452     }
453     case EMR_MODIFYWORLDTRANSFORM: {
454       DCHECK_EQ(record()->nSize,
455                 sizeof(DWORD) * 2 + sizeof(XFORM) + sizeof(DWORD));
456       const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
457       const DWORD* option = reinterpret_cast<const DWORD*>(xform + 1);
458       HDC hdc = context->hdc;
459       switch (*option) {
460         case MWT_IDENTITY:
461           if (base_matrix) {
462             res = 0 != SetWorldTransform(hdc, base_matrix);
463           } else {
464             res = 0 != ModifyWorldTransform(hdc, xform, MWT_IDENTITY);
465           }
466           break;
467         case MWT_LEFTMULTIPLY:
468         case MWT_RIGHTMULTIPLY:
469           res = 0 != ModifyWorldTransform(hdc, xform, *option);
470           break;
471         case 4:  // MWT_SET
472           if (base_matrix) {
473             res = 0 != SetWorldTransform(hdc, base_matrix) &&
474                        ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
475           } else {
476             res = 0 != SetWorldTransform(hdc, xform);
477           }
478           break;
479         default:
480           res = false;
481           break;
482       }
483       break;
484     }
485     case EMR_SETLAYOUT:
486       // Ignore it.
487       res = true;
488       break;
489     case EMR_GDICOMMENT: {
490       const EMRGDICOMMENT* comment_record =
491           reinterpret_cast<const EMRGDICOMMENT*>(record());
492       if (comment_record->cbData == sizeof(PageBreakRecord)) {
493         const PageBreakRecord* page_break_record =
494             reinterpret_cast<const PageBreakRecord*>(comment_record->Data);
495         if (page_break_record && page_break_record->IsValid()) {
496           if (page_break_record->type == PageBreakRecord::START_PAGE) {
497             res = !!::StartPage(context->hdc);
498             DCHECK_EQ(0, context->dc_on_page_start);
499             context->dc_on_page_start = ::SaveDC(context->hdc);
500           } else if (page_break_record->type == PageBreakRecord::END_PAGE) {
501             DCHECK_NE(0, context->dc_on_page_start);
502             ::RestoreDC(context->hdc, context->dc_on_page_start);
503             context->dc_on_page_start = 0;
504             res = !!::EndPage(context->hdc);
505           } else {
506             res = false;
507             NOTREACHED();
508           }
509         } else {
510           res = Play(context);
511         }
512       } else {
513         res = true;
514       }
515       break;
516     }
517     default: {
518       res = Play(context);
519       break;
520     }
521   }
522   return res;
523 }
524
525 SkBaseDevice* Emf::StartPageForVectorCanvas(
526     const gfx::Size& page_size, const gfx::Rect& content_area,
527     const float& scale_factor) {
528   if (!StartPage(page_size, content_area, scale_factor))
529     return NULL;
530
531   return skia::VectorPlatformDeviceEmf::CreateDevice(page_size.width(),
532                                                      page_size.height(),
533                                                      true, hdc_);
534 }
535
536 bool Emf::StartPage(const gfx::Size& /*page_size*/,
537                     const gfx::Rect& /*content_area*/,
538                     const float& /*scale_factor*/) {
539   DCHECK(hdc_);
540   if (!hdc_)
541     return false;
542   page_count_++;
543   PageBreakRecord record(PageBreakRecord::START_PAGE);
544   return !!GdiComment(hdc_, sizeof(record),
545                       reinterpret_cast<const BYTE *>(&record));
546 }
547
548 bool Emf::FinishPage() {
549   DCHECK(hdc_);
550   if (!hdc_)
551     return false;
552   PageBreakRecord record(PageBreakRecord::END_PAGE);
553   return !!GdiComment(hdc_, sizeof(record),
554                       reinterpret_cast<const BYTE *>(&record));
555 }
556
557 Emf::Enumerator::Enumerator(const Emf& emf, HDC context, const RECT* rect) {
558   items_.clear();
559   if (!EnumEnhMetaFile(context,
560                        emf.emf(),
561                        &Emf::Enumerator::EnhMetaFileProc,
562                        reinterpret_cast<void*>(this),
563                        rect)) {
564     NOTREACHED();
565     items_.clear();
566   }
567   DCHECK_EQ(context_.hdc, context);
568 }
569
570 Emf::Enumerator::const_iterator Emf::Enumerator::begin() const {
571   return items_.begin();
572 }
573
574 Emf::Enumerator::const_iterator Emf::Enumerator::end() const {
575   return items_.end();
576 }
577
578 int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc,
579                                               HANDLETABLE* handle_table,
580                                               const ENHMETARECORD* record,
581                                               int objects_count,
582                                               LPARAM param) {
583   Enumerator& emf = *reinterpret_cast<Enumerator*>(param);
584   if (!emf.context_.handle_table) {
585     DCHECK(!emf.context_.handle_table);
586     DCHECK(!emf.context_.objects_count);
587     emf.context_.handle_table = handle_table;
588     emf.context_.objects_count = objects_count;
589     emf.context_.hdc = hdc;
590   } else {
591     DCHECK_EQ(emf.context_.handle_table, handle_table);
592     DCHECK_EQ(emf.context_.objects_count, objects_count);
593     DCHECK_EQ(emf.context_.hdc, hdc);
594   }
595   emf.items_.push_back(Record(record));
596   return 1;
597 }
598
599 bool Emf::IsAlphaBlendUsed() const {
600   bool result = false;
601   ::EnumEnhMetaFile(NULL,
602                     emf(),
603                     &IsAlphaBlendUsedEnumProc,
604                     &result,
605                     NULL);
606   return result;
607 }
608
609 Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const {
610   gfx::Rect page_bounds = GetPageBounds(1);
611   gfx::Size page_size(page_bounds.size());
612   if (page_size.GetArea() <= 0) {
613     NOTREACHED() << "Metafile is empty";
614     page_bounds = gfx::Rect(1, 1);
615   }
616
617   float scale = sqrt(float(raster_area_in_pixels) / page_size.GetArea());
618   page_size.set_width(std::max<int>(1, page_size.width() * scale));
619   page_size.set_height(std::max<int>(1, page_size.height() * scale));
620
621
622   RasterBitmap bitmap(page_size);
623
624   gfx::Rect bitmap_rect(page_size);
625   RECT rect = bitmap_rect.ToRECT();
626   Playback(bitmap.context(), &rect);
627
628   scoped_ptr<Emf> result(new Emf);
629   result->Init();
630   HDC hdc = result->context();
631   DCHECK(hdc);
632   skia::InitializeDC(hdc);
633
634   // Params are ignored.
635   result->StartPage(page_bounds.size(), page_bounds, 1);
636
637   ::ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
638   XFORM xform = {
639     float(page_bounds.width()) / bitmap_rect.width(), 0,
640     0, float(page_bounds.height()) / bitmap_rect.height(),
641     page_bounds.x(),
642     page_bounds.y(),
643   };
644   ::SetWorldTransform(hdc, &xform);
645   ::BitBlt(hdc, 0, 0, bitmap_rect.width(), bitmap_rect.height(),
646            bitmap.context(), bitmap_rect.x(), bitmap_rect.y(), SRCCOPY);
647
648   result->FinishPage();
649   result->FinishDocument();
650
651   return result.release();
652 }
653
654 Emf* Emf::RasterizeAlphaBlend() const {
655   gfx::Rect page_bounds = GetPageBounds(1);
656   if (page_bounds.size().GetArea() <= 0) {
657     NOTREACHED() << "Metafile is empty";
658     page_bounds = gfx::Rect(1, 1);
659   }
660
661   RasterBitmap bitmap(page_bounds.size());
662
663   // Map metafile page_bounds.x(), page_bounds.y() to bitmap 0, 0.
664   XFORM xform = { 1, 0, 0, 1, -page_bounds.x(), -page_bounds.y()};
665   ::SetWorldTransform(bitmap.context(), &xform);
666
667   scoped_ptr<Emf> result(new Emf);
668   result->Init();
669   HDC hdc = result->context();
670   DCHECK(hdc);
671   skia::InitializeDC(hdc);
672
673   HDC bitmap_dc = bitmap.context();
674   RECT rect = page_bounds.ToRECT();
675   ::EnumEnhMetaFile(hdc, emf(), &RasterizeAlphaBlendProc, &bitmap_dc, &rect);
676
677   result->FinishDocument();
678
679   return result.release();
680 }
681
682
683 }  // namespace printing