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 |