Chromium Code Reviews| Index: printing/emf_win.cc |
| diff --git a/printing/emf_win.cc b/printing/emf_win.cc |
| index a5d4c024070042c7e8ebd02f0cd88467ca345a6a..a6005dc7f8ae0687de9ae3228990834e06fbbb73 100644 |
| --- a/printing/emf_win.cc |
| +++ b/printing/emf_win.cc |
| @@ -54,6 +54,101 @@ int CALLBACK IsAlphaBlendUsedEnumProc(HDC, |
| return 1; |
| } |
| +int CALLBACK RasterizeAlphaBlendProc(HDC metafile_dc, |
| + HANDLETABLE* handle_table, |
| + const ENHMETARECORD *record, |
| + int num_objects, |
| + LPARAM data) { |
| + HDC bitmap_dc = *reinterpret_cast<HDC*>(data); |
| + // Play this command to the bitmap DC. |
| + ::PlayEnhMetaFileRecord(bitmap_dc, handle_table, record, num_objects); |
| + switch (record->iType) { |
| + case EMR_ALPHABLEND: { |
| + const EMRALPHABLEND* alpha_blend = |
| + reinterpret_cast<const EMRALPHABLEND*>(record); |
| + // Don't modify transformation here. |
| + // Old implementation did reset transformations for DC to identity matrix. |
| + // That was not correct and cause some bugs, like unexpected cropping. |
| + // EMRALPHABLEND is rendered into bitmap and metafile contexts with |
| + // current transformation. If we don't touch them here BitBlt will copy |
| + // same areas. |
| + ::BitBlt(metafile_dc, |
| + alpha_blend->xDest, |
| + alpha_blend->yDest, |
| + alpha_blend->cxDest, |
| + alpha_blend->cyDest, |
| + bitmap_dc, |
| + alpha_blend->xDest, |
| + alpha_blend->yDest, |
| + SRCCOPY); |
| + break; |
| + } |
| + case EMR_CREATEBRUSHINDIRECT: |
| + case EMR_CREATECOLORSPACE: |
| + case EMR_CREATECOLORSPACEW: |
| + case EMR_CREATEDIBPATTERNBRUSHPT: |
| + case EMR_CREATEMONOBRUSH: |
| + case EMR_CREATEPALETTE: |
| + case EMR_CREATEPEN: |
| + case EMR_DELETECOLORSPACE: |
| + case EMR_DELETEOBJECT: |
| + case EMR_EXTCREATEFONTINDIRECTW: |
| + // Play object creation command only once. |
| + break; |
| + |
| + default: |
| + // Play this command to the metafile DC. |
| + ::PlayEnhMetaFileRecord(metafile_dc, handle_table, record, num_objects); |
| + break; |
| + } |
| + return 1; // Continue enumeration |
| +} |
| + |
| +// Bitmapt for rasterization. |
| +class RasterBitmap { |
| + public: |
| + explicit RasterBitmap(const gfx::Size& raster_size) |
| + : saved_object_(NULL) { |
| + context_.Set(::CreateCompatibleDC(NULL)); |
| + if (!context_) { |
| + NOTREACHED() << "Bitmap DC creation failed"; |
| + return; |
| + } |
| + ::SetGraphicsMode(context_, GM_ADVANCED); |
| + void* bits = NULL; |
| + gfx::Rect bitmap_rect(raster_size); |
| + gfx::CreateBitmapHeader(raster_size.width(), raster_size.height(), |
| + &header_.bmiHeader); |
| + bitmap_.Set(::CreateDIBSection(context_, &header_, DIB_RGB_COLORS, &bits, |
| + NULL, 0)); |
| + if (!bitmap_) |
| + NOTREACHED() << "Raster bitmap creation for printing failed"; |
| + |
| + saved_object_ = ::SelectObject(context_, bitmap_); |
| + ::FillRect(context_, &bitmap_rect.ToRECT(), |
|
Timur Iskhodzhanov
2013/03/28 03:49:39
FYI taking an address of a temporary object is not
|
| + static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH))); |
| + |
| + } |
| + |
| + ~RasterBitmap() { |
| + ::SelectObject(context_, saved_object_); |
| + } |
| + |
| + HDC context() const { |
| + return context_; |
| + } |
| + |
| + base::win::ScopedCreateDC context_; |
| + BITMAPINFO header_; |
| + base::win::ScopedBitmap bitmap_; |
| + HGDIOBJ saved_object_; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(RasterBitmap); |
| +}; |
| + |
| + |
| + |
| } // namespace |
| namespace printing { |
| @@ -516,28 +611,11 @@ Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const { |
| page_size.set_width(std::max<int>(1, page_size.width() * scale)); |
| page_size.set_height(std::max<int>(1, page_size.height() * scale)); |
| - base::win::ScopedCreateDC bitmap_dc(::CreateCompatibleDC(NULL)); |
| - if (!bitmap_dc) { |
| - NOTREACHED() << "Bitmap DC creation failed"; |
| - return NULL; |
| - } |
| - ::SetGraphicsMode(bitmap_dc, GM_ADVANCED); |
| - void* bits = NULL; |
| - BITMAPINFO hdr; |
| - gfx::CreateBitmapHeader(page_size.width(), page_size.height(), |
| - &hdr.bmiHeader); |
| - base::win::ScopedBitmap hbitmap(CreateDIBSection( |
| - bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0)); |
| - if (!hbitmap) |
| - NOTREACHED() << "Raster bitmap creation for printing failed"; |
| - |
| - base::win::ScopedSelectObject selectBitmap(bitmap_dc, hbitmap); |
| - RECT rect = { 0, 0, page_size.width(), page_size.height() }; |
| - HBRUSH white_brush = static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH)); |
| - FillRect(bitmap_dc, &rect, white_brush); |
| + |
| + RasterBitmap bitmap(page_size); |
| gfx::Rect bitmap_rect(page_size); |
| - Playback(bitmap_dc, &bitmap_rect.ToRECT()); |
| + Playback(bitmap.context(), &bitmap_rect.ToRECT()); |
| scoped_ptr<Emf> result(new Emf); |
| result->Init(); |
| @@ -557,7 +635,7 @@ Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const { |
| }; |
| ::SetWorldTransform(hdc, &xform); |
| ::BitBlt(hdc, 0, 0, bitmap_rect.width(), bitmap_rect.height(), |
| - bitmap_dc, bitmap_rect.x(), bitmap_rect.y(), SRCCOPY); |
| + bitmap.context(), bitmap_rect.x(), bitmap_rect.y(), SRCCOPY); |
| result->FinishPage(); |
| result->FinishDocument(); |
| @@ -565,4 +643,33 @@ Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const { |
| return result.release(); |
| } |
| +Emf* Emf::RasterizeAlphaBlend() const { |
| + gfx::Rect page_bounds = GetPageBounds(1); |
| + if (page_bounds.size().GetArea() <= 0) { |
| + NOTREACHED() << "Metafile is empty"; |
| + page_bounds = gfx::Rect(1, 1); |
| + } |
| + |
| + RasterBitmap bitmap(page_bounds.size()); |
| + |
| + // Map metafile page_bounds.x(), page_bounds.y() to bitmap 0, 0. |
| + XFORM xform = { 1, 0, 0, 1, -page_bounds.x(), -page_bounds.y()}; |
| + ::SetWorldTransform(bitmap.context(), &xform); |
| + |
| + scoped_ptr<Emf> result(new Emf); |
| + result->Init(); |
| + HDC hdc = result->context(); |
| + DCHECK(hdc); |
| + skia::InitializeDC(hdc); |
| + |
| + HDC bitmap_dc = bitmap.context(); |
| + ::EnumEnhMetaFile(hdc, emf(), &RasterizeAlphaBlendProc, &bitmap_dc, |
| + &page_bounds.ToRECT()); |
| + |
| + result->FinishDocument(); |
| + |
| + return result.release(); |
| +} |
| + |
| + |
| } // namespace printing |