| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "printing/emf_win.h" | 5 #include "printing/emf_win.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| 11 | 11 |
| 12 #include "base/files/file.h" | 12 #include "base/files/file.h" |
| 13 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
| 18 #include "base/win/scoped_gdi_object.h" | |
| 19 #include "base/win/scoped_hdc.h" | |
| 20 #include "base/win/scoped_select_object.h" | |
| 21 #include "skia/ext/skia_utils_win.h" | 18 #include "skia/ext/skia_utils_win.h" |
| 22 #include "third_party/skia/include/core/SkBitmap.h" | 19 #include "third_party/skia/include/core/SkBitmap.h" |
| 23 #include "ui/gfx/codec/jpeg_codec.h" | 20 #include "ui/gfx/codec/jpeg_codec.h" |
| 24 #include "ui/gfx/codec/png_codec.h" | 21 #include "ui/gfx/codec/png_codec.h" |
| 25 #include "ui/gfx/geometry/rect.h" | 22 #include "ui/gfx/geometry/rect.h" |
| 26 #include "ui/gfx/geometry/size.h" | 23 #include "ui/gfx/geometry/size.h" |
| 27 | 24 |
| 28 namespace printing { | 25 namespace printing { |
| 29 | 26 |
| 30 namespace { | 27 namespace { |
| 31 | 28 |
| 32 int CALLBACK IsAlphaBlendUsedEnumProc(HDC, | |
| 33 HANDLETABLE*, | |
| 34 const ENHMETARECORD *record, | |
| 35 int, | |
| 36 LPARAM data) { | |
| 37 bool* result = reinterpret_cast<bool*>(data); | |
| 38 if (!result) | |
| 39 return 0; | |
| 40 switch (record->iType) { | |
| 41 case EMR_ALPHABLEND: { | |
| 42 *result = true; | |
| 43 return 0; | |
| 44 break; | |
| 45 } | |
| 46 } | |
| 47 return 1; | |
| 48 } | |
| 49 | |
| 50 int CALLBACK RasterizeAlphaBlendProc(HDC metafile_dc, | |
| 51 HANDLETABLE* handle_table, | |
| 52 const ENHMETARECORD *record, | |
| 53 int num_objects, | |
| 54 LPARAM data) { | |
| 55 HDC bitmap_dc = *reinterpret_cast<HDC*>(data); | |
| 56 // Play this command to the bitmap DC. | |
| 57 ::PlayEnhMetaFileRecord(bitmap_dc, handle_table, record, num_objects); | |
| 58 switch (record->iType) { | |
| 59 case EMR_ALPHABLEND: { | |
| 60 const EMRALPHABLEND* alpha_blend = | |
| 61 reinterpret_cast<const EMRALPHABLEND*>(record); | |
| 62 // Don't modify transformation here. | |
| 63 // Old implementation did reset transformations for DC to identity matrix. | |
| 64 // That was not correct and cause some bugs, like unexpected cropping. | |
| 65 // EMRALPHABLEND is rendered into bitmap and metafile contexts with | |
| 66 // current transformation. If we don't touch them here BitBlt will copy | |
| 67 // same areas. | |
| 68 ::BitBlt(metafile_dc, | |
| 69 alpha_blend->xDest, | |
| 70 alpha_blend->yDest, | |
| 71 alpha_blend->cxDest, | |
| 72 alpha_blend->cyDest, | |
| 73 bitmap_dc, | |
| 74 alpha_blend->xDest, | |
| 75 alpha_blend->yDest, | |
| 76 SRCCOPY); | |
| 77 break; | |
| 78 } | |
| 79 case EMR_CREATEBRUSHINDIRECT: | |
| 80 case EMR_CREATECOLORSPACE: | |
| 81 case EMR_CREATECOLORSPACEW: | |
| 82 case EMR_CREATEDIBPATTERNBRUSHPT: | |
| 83 case EMR_CREATEMONOBRUSH: | |
| 84 case EMR_CREATEPALETTE: | |
| 85 case EMR_CREATEPEN: | |
| 86 case EMR_DELETECOLORSPACE: | |
| 87 case EMR_DELETEOBJECT: | |
| 88 case EMR_EXTCREATEFONTINDIRECTW: | |
| 89 // Play object creation command only once. | |
| 90 break; | |
| 91 | |
| 92 default: | |
| 93 // Play this command to the metafile DC. | |
| 94 ::PlayEnhMetaFileRecord(metafile_dc, handle_table, record, num_objects); | |
| 95 break; | |
| 96 } | |
| 97 return 1; // Continue enumeration | |
| 98 } | |
| 99 | |
| 100 // Bitmapt for rasterization. | |
| 101 class RasterBitmap { | |
| 102 public: | |
| 103 explicit RasterBitmap(const gfx::Size& raster_size) : saved_object_(nullptr) { | |
| 104 context_.Set(::CreateCompatibleDC(nullptr)); | |
| 105 if (!context_.IsValid()) { | |
| 106 NOTREACHED() << "Bitmap DC creation failed"; | |
| 107 return; | |
| 108 } | |
| 109 ::SetGraphicsMode(context_.Get(), GM_ADVANCED); | |
| 110 void* bits = nullptr; | |
| 111 gfx::Rect bitmap_rect(raster_size); | |
| 112 skia::CreateBitmapHeader(raster_size.width(), raster_size.height(), | |
| 113 &header_.bmiHeader); | |
| 114 bitmap_.reset(CreateDIBSection(context_.Get(), &header_, DIB_RGB_COLORS, | |
| 115 &bits, nullptr, 0)); | |
| 116 if (!bitmap_.is_valid()) | |
| 117 NOTREACHED() << "Raster bitmap creation for printing failed"; | |
| 118 | |
| 119 saved_object_ = ::SelectObject(context_.Get(), bitmap_.get()); | |
| 120 RECT rect = bitmap_rect.ToRECT(); | |
| 121 ::FillRect(context_.Get(), &rect, | |
| 122 static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH))); | |
| 123 } | |
| 124 | |
| 125 ~RasterBitmap() { | |
| 126 ::SelectObject(context_.Get(), saved_object_); | |
| 127 } | |
| 128 | |
| 129 HDC context() const { | |
| 130 return context_.Get(); | |
| 131 } | |
| 132 | |
| 133 base::win::ScopedCreateDC context_; | |
| 134 BITMAPINFO header_; | |
| 135 base::win::ScopedBitmap bitmap_; | |
| 136 HGDIOBJ saved_object_; | |
| 137 | |
| 138 private: | |
| 139 DISALLOW_COPY_AND_ASSIGN(RasterBitmap); | |
| 140 }; | |
| 141 | |
| 142 bool DIBFormatNativelySupported(HDC dc, uint32_t escape, const BYTE* bits, | 29 bool DIBFormatNativelySupported(HDC dc, uint32_t escape, const BYTE* bits, |
| 143 int size) { | 30 int size) { |
| 144 BOOL supported = FALSE; | 31 BOOL supported = FALSE; |
| 145 if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape), | 32 if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape), |
| 146 reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) { | 33 reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) { |
| 147 ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits), | 34 ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits), |
| 148 sizeof(supported), reinterpret_cast<LPSTR>(&supported)); | 35 sizeof(supported), reinterpret_cast<LPSTR>(&supported)); |
| 149 } | 36 } |
| 150 return !!supported; | 37 return !!supported; |
| 151 } | 38 } |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 emf.context_.hdc = hdc; | 394 emf.context_.hdc = hdc; |
| 508 } else { | 395 } else { |
| 509 DCHECK_EQ(emf.context_.handle_table, handle_table); | 396 DCHECK_EQ(emf.context_.handle_table, handle_table); |
| 510 DCHECK_EQ(emf.context_.objects_count, objects_count); | 397 DCHECK_EQ(emf.context_.objects_count, objects_count); |
| 511 DCHECK_EQ(emf.context_.hdc, hdc); | 398 DCHECK_EQ(emf.context_.hdc, hdc); |
| 512 } | 399 } |
| 513 emf.items_.push_back(Record(record)); | 400 emf.items_.push_back(Record(record)); |
| 514 return 1; | 401 return 1; |
| 515 } | 402 } |
| 516 | 403 |
| 517 bool Emf::IsAlphaBlendUsed() const { | |
| 518 bool result = false; | |
| 519 ::EnumEnhMetaFile(nullptr, emf(), &IsAlphaBlendUsedEnumProc, &result, | |
| 520 nullptr); | |
| 521 return result; | |
| 522 } | |
| 523 | |
| 524 std::unique_ptr<Emf> Emf::RasterizeMetafile(int raster_area_in_pixels) const { | |
| 525 gfx::Rect page_bounds = GetPageBounds(1); | |
| 526 gfx::Size page_size(page_bounds.size()); | |
| 527 if (page_size.GetArea() <= 0) { | |
| 528 NOTREACHED() << "Metafile is empty"; | |
| 529 page_bounds = gfx::Rect(1, 1); | |
| 530 } | |
| 531 | |
| 532 float scale = sqrt( | |
| 533 static_cast<float>(raster_area_in_pixels) / page_size.GetArea()); | |
| 534 page_size.set_width(std::max<int>(1, page_size.width() * scale)); | |
| 535 page_size.set_height(std::max<int>(1, page_size.height() * scale)); | |
| 536 | |
| 537 | |
| 538 RasterBitmap bitmap(page_size); | |
| 539 | |
| 540 gfx::Rect bitmap_rect(page_size); | |
| 541 RECT rect = bitmap_rect.ToRECT(); | |
| 542 Playback(bitmap.context(), &rect); | |
| 543 | |
| 544 std::unique_ptr<Emf> result = base::MakeUnique<Emf>(); | |
| 545 result->Init(); | |
| 546 HDC hdc = result->context(); | |
| 547 DCHECK(hdc); | |
| 548 skia::InitializeDC(hdc); | |
| 549 | |
| 550 // Params are ignored. | |
| 551 result->StartPage(page_bounds.size(), page_bounds, 1); | |
| 552 | |
| 553 ::ModifyWorldTransform(hdc, nullptr, MWT_IDENTITY); | |
| 554 XFORM xform = { | |
| 555 static_cast<float>(page_bounds.width()) / bitmap_rect.width(), | |
| 556 0, | |
| 557 0, | |
| 558 static_cast<float>(page_bounds.height()) / bitmap_rect.height(), | |
| 559 static_cast<float>(page_bounds.x()), | |
| 560 static_cast<float>(page_bounds.y()), | |
| 561 }; | |
| 562 ::SetWorldTransform(hdc, &xform); | |
| 563 ::BitBlt(hdc, 0, 0, bitmap_rect.width(), bitmap_rect.height(), | |
| 564 bitmap.context(), bitmap_rect.x(), bitmap_rect.y(), SRCCOPY); | |
| 565 | |
| 566 result->FinishPage(); | |
| 567 result->FinishDocument(); | |
| 568 return result; | |
| 569 } | |
| 570 | |
| 571 std::unique_ptr<Emf> Emf::RasterizeAlphaBlend() const { | |
| 572 gfx::Rect page_bounds = GetPageBounds(1); | |
| 573 if (page_bounds.size().GetArea() <= 0) { | |
| 574 NOTREACHED() << "Metafile is empty"; | |
| 575 page_bounds = gfx::Rect(1, 1); | |
| 576 } | |
| 577 | |
| 578 RasterBitmap bitmap(page_bounds.size()); | |
| 579 | |
| 580 // Map metafile page_bounds.x(), page_bounds.y() to bitmap 0, 0. | |
| 581 XFORM xform = {1, | |
| 582 0, | |
| 583 0, | |
| 584 1, | |
| 585 static_cast<float>(-page_bounds.x()), | |
| 586 static_cast<float>(-page_bounds.y())}; | |
| 587 ::SetWorldTransform(bitmap.context(), &xform); | |
| 588 | |
| 589 std::unique_ptr<Emf> result = base::MakeUnique<Emf>(); | |
| 590 result->Init(); | |
| 591 HDC hdc = result->context(); | |
| 592 DCHECK(hdc); | |
| 593 skia::InitializeDC(hdc); | |
| 594 | |
| 595 HDC bitmap_dc = bitmap.context(); | |
| 596 RECT rect = page_bounds.ToRECT(); | |
| 597 ::EnumEnhMetaFile(hdc, emf(), &RasterizeAlphaBlendProc, &bitmap_dc, &rect); | |
| 598 | |
| 599 result->FinishDocument(); | |
| 600 return result; | |
| 601 } | |
| 602 | |
| 603 } // namespace printing | 404 } // namespace printing |
| OLD | NEW |