| 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 "base/file_path.h" | 7 #include "base/file_path.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/scoped_ptr.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" |
| 10 #include "skia/ext/vector_platform_device_emf_win.h" | 13 #include "skia/ext/vector_platform_device_emf_win.h" |
| 11 #include "third_party/skia/include/core/SkBitmap.h" | 14 #include "third_party/skia/include/core/SkBitmap.h" |
| 12 #include "ui/gfx/codec/jpeg_codec.h" | 15 #include "ui/gfx/codec/jpeg_codec.h" |
| 13 #include "ui/gfx/codec/png_codec.h" | 16 #include "ui/gfx/codec/png_codec.h" |
| 14 #include "ui/gfx/gdi_util.h" | 17 #include "ui/gfx/gdi_util.h" |
| 15 #include "ui/gfx/rect.h" | 18 #include "ui/gfx/rect.h" |
| 16 #include "ui/gfx/size.h" | 19 #include "ui/gfx/size.h" |
| 17 | 20 |
| 18 namespace { | 21 namespace { |
| 22 |
| 19 const int kCustomGdiCommentSignature = 0xdeadbabe; | 23 const int kCustomGdiCommentSignature = 0xdeadbabe; |
| 20 struct PageBreakRecord { | 24 struct PageBreakRecord { |
| 21 int signature; | 25 int signature; |
| 22 enum PageBreakType { | 26 enum PageBreakType { |
| 23 START_PAGE, | 27 START_PAGE, |
| 24 END_PAGE, | 28 END_PAGE, |
| 25 } type; | 29 } type; |
| 26 explicit PageBreakRecord(PageBreakType type_in) | 30 explicit PageBreakRecord(PageBreakType type_in) |
| 27 : signature(kCustomGdiCommentSignature), type(type_in) { | 31 : signature(kCustomGdiCommentSignature), type(type_in) { |
| 28 } | 32 } |
| 29 bool IsValid() const { | 33 bool IsValid() const { |
| 30 return (signature == kCustomGdiCommentSignature) && | 34 return (signature == kCustomGdiCommentSignature) && |
| 31 (type >= START_PAGE) && (type <= END_PAGE); | 35 (type >= START_PAGE) && (type <= END_PAGE); |
| 32 } | 36 } |
| 33 }; | 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; |
| 34 } | 55 } |
| 35 | 56 |
| 57 } // namespace |
| 58 |
| 36 namespace printing { | 59 namespace printing { |
| 37 | 60 |
| 38 bool DIBFormatNativelySupported(HDC dc, uint32 escape, const BYTE* bits, | 61 bool DIBFormatNativelySupported(HDC dc, uint32 escape, const BYTE* bits, |
| 39 int size) { | 62 int size) { |
| 40 BOOL supported = FALSE; | 63 BOOL supported = FALSE; |
| 41 if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape), | 64 if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape), |
| 42 reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) { | 65 reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) { |
| 43 ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits), | 66 ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits), |
| 44 sizeof(supported), reinterpret_cast<LPSTR>(&supported)); | 67 sizeof(supported), reinterpret_cast<LPSTR>(&supported)); |
| 45 } | 68 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 } | 142 } |
| 120 | 143 |
| 121 gfx::Rect Emf::GetPageBounds(unsigned int page_number) const { | 144 gfx::Rect Emf::GetPageBounds(unsigned int page_number) const { |
| 122 DCHECK(emf_ && !hdc_); | 145 DCHECK(emf_ && !hdc_); |
| 123 DCHECK_EQ(1U, page_number); | 146 DCHECK_EQ(1U, page_number); |
| 124 ENHMETAHEADER header; | 147 ENHMETAHEADER header; |
| 125 if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) { | 148 if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) { |
| 126 NOTREACHED(); | 149 NOTREACHED(); |
| 127 return gfx::Rect(); | 150 return gfx::Rect(); |
| 128 } | 151 } |
| 129 if (header.rclBounds.left == 0 && | 152 // Add 1 to right and bottom because it's inclusive rectangle. |
| 130 header.rclBounds.top == 0 && | 153 // See ENHMETAHEADER. |
| 131 header.rclBounds.right == -1 && | |
| 132 header.rclBounds.bottom == -1) { | |
| 133 // A freshly created EMF buffer that has no drawing operation has invalid | |
| 134 // bounds. Instead of having an (0,0) size, it has a (-1,-1) size. Detect | |
| 135 // this special case and returns an empty Rect instead of an invalid one. | |
| 136 return gfx::Rect(); | |
| 137 } | |
| 138 return gfx::Rect(header.rclBounds.left, | 154 return gfx::Rect(header.rclBounds.left, |
| 139 header.rclBounds.top, | 155 header.rclBounds.top, |
| 140 header.rclBounds.right - header.rclBounds.left, | 156 header.rclBounds.right - header.rclBounds.left + 1, |
| 141 header.rclBounds.bottom - header.rclBounds.top); | 157 header.rclBounds.bottom - header.rclBounds.top + 1); |
| 142 } | 158 } |
| 143 | 159 |
| 144 uint32 Emf::GetDataSize() const { | 160 uint32 Emf::GetDataSize() const { |
| 145 DCHECK(emf_ && !hdc_); | 161 DCHECK(emf_ && !hdc_); |
| 146 return GetEnhMetaFileBits(emf_, 0, NULL); | 162 return GetEnhMetaFileBits(emf_, 0, NULL); |
| 147 } | 163 } |
| 148 | 164 |
| 149 bool Emf::GetData(void* buffer, uint32 size) const { | 165 bool Emf::GetData(void* buffer, uint32 size) const { |
| 150 DCHECK(emf_ && !hdc_); | 166 DCHECK(emf_ && !hdc_); |
| 151 DCHECK(buffer && size); | 167 DCHECK(buffer && size); |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 emf.context_.hdc = hdc; | 487 emf.context_.hdc = hdc; |
| 472 } else { | 488 } else { |
| 473 DCHECK_EQ(emf.context_.handle_table, handle_table); | 489 DCHECK_EQ(emf.context_.handle_table, handle_table); |
| 474 DCHECK_EQ(emf.context_.objects_count, objects_count); | 490 DCHECK_EQ(emf.context_.objects_count, objects_count); |
| 475 DCHECK_EQ(emf.context_.hdc, hdc); | 491 DCHECK_EQ(emf.context_.hdc, hdc); |
| 476 } | 492 } |
| 477 emf.items_.push_back(Record(record)); | 493 emf.items_.push_back(Record(record)); |
| 478 return 1; | 494 return 1; |
| 479 } | 495 } |
| 480 | 496 |
| 497 bool Emf::IsAlphaBlendUsed() const { |
| 498 bool result = false; |
| 499 ::EnumEnhMetaFile(NULL, |
| 500 emf(), |
| 501 &IsAlphaBlendUsedEnumProc, |
| 502 &result, |
| 503 NULL); |
| 504 return result; |
| 505 } |
| 506 |
| 507 Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const { |
| 508 gfx::Rect page_bounds = GetPageBounds(1); |
| 509 gfx::Size page_size(page_bounds.size()); |
| 510 if (page_size.GetArea() <= 0) { |
| 511 NOTREACHED() << "Metafile is empty"; |
| 512 page_bounds = gfx::Rect(1, 1); |
| 513 } |
| 514 |
| 515 float scale = sqrt(float(raster_area_in_pixels) / page_size.GetArea()); |
| 516 page_size.set_width(std::max<int>(1, page_size.width() * scale)); |
| 517 page_size.set_height(std::max<int>(1, page_size.height() * scale)); |
| 518 |
| 519 base::win::ScopedCreateDC bitmap_dc(::CreateCompatibleDC(NULL)); |
| 520 if (!bitmap_dc) { |
| 521 NOTREACHED() << "Bitmap DC creation failed"; |
| 522 return NULL; |
| 523 } |
| 524 ::SetGraphicsMode(bitmap_dc, GM_ADVANCED); |
| 525 void* bits = NULL; |
| 526 BITMAPINFO hdr; |
| 527 gfx::CreateBitmapHeader(page_size.width(), page_size.height(), |
| 528 &hdr.bmiHeader); |
| 529 base::win::ScopedBitmap hbitmap(CreateDIBSection( |
| 530 bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0)); |
| 531 if (!hbitmap) |
| 532 NOTREACHED() << "Raster bitmap creation for printing failed"; |
| 533 |
| 534 base::win::ScopedSelectObject selectBitmap(bitmap_dc, hbitmap); |
| 535 RECT rect = { 0, 0, page_size.width(), page_size.height() }; |
| 536 HBRUSH white_brush = static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH)); |
| 537 FillRect(bitmap_dc, &rect, white_brush); |
| 538 |
| 539 gfx::Rect bitmap_rect(page_size); |
| 540 Playback(bitmap_dc, &bitmap_rect.ToRECT()); |
| 541 |
| 542 scoped_ptr<Emf> result(new Emf); |
| 543 result->Init(); |
| 544 HDC hdc = result->context(); |
| 545 DCHECK(hdc); |
| 546 skia::InitializeDC(hdc); |
| 547 |
| 548 // Params are ignored. |
| 549 result->StartPage(page_bounds.size(), page_bounds, 1); |
| 550 |
| 551 ::ModifyWorldTransform(hdc, NULL, MWT_IDENTITY); |
| 552 XFORM xform = { |
| 553 float(page_bounds.width()) / bitmap_rect.width(), 0, |
| 554 0, float(page_bounds.height()) / bitmap_rect.height(), |
| 555 page_bounds.x(), |
| 556 page_bounds.y(), |
| 557 }; |
| 558 ::SetWorldTransform(hdc, &xform); |
| 559 ::BitBlt(hdc, 0, 0, bitmap_rect.width(), bitmap_rect.height(), |
| 560 bitmap_dc, bitmap_rect.x(), bitmap_rect.y(), SRCCOPY); |
| 561 |
| 562 result->FinishPage(); |
| 563 result->FinishDocument(); |
| 564 |
| 565 return result.release(); |
| 566 } |
| 567 |
| 481 } // namespace printing | 568 } // namespace printing |
| OLD | NEW |