OLD | NEW |
| (Empty) |
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 <windows.h> | |
6 #include <psapi.h> | |
7 #include <stddef.h> | |
8 | |
9 #include "base/debug/gdi_debug_util_win.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/ptr_util.h" | |
12 #include "base/win/win_util.h" | |
13 #include "skia/ext/bitmap_platform_device_win.h" | |
14 #include "skia/ext/platform_canvas.h" | |
15 #include "skia/ext/skia_utils_win.h" | |
16 #include "third_party/skia/include/core/SkMatrix.h" | |
17 #include "third_party/skia/include/core/SkPath.h" | |
18 #include "third_party/skia/include/core/SkRefCnt.h" | |
19 #include "third_party/skia/include/core/SkRect.h" | |
20 | |
21 namespace { | |
22 | |
23 void LoadClippingRegionToDC(HDC context, | |
24 const SkIRect& clip_bounds, | |
25 const SkMatrix& transformation) { | |
26 HRGN hrgn = CreateRectRgnIndirect(&skia::SkIRectToRECT(clip_bounds)); | |
27 int result = SelectClipRgn(context, hrgn); | |
28 SkASSERT(result != ERROR); | |
29 result = DeleteObject(hrgn); | |
30 SkASSERT(result != 0); | |
31 } | |
32 | |
33 } // namespace | |
34 | |
35 namespace skia { | |
36 | |
37 HDC GetNativeDrawingContext(SkCanvas* canvas) { | |
38 PlatformDevice* platform_device = GetPlatformDevice(canvas->getTopDevice(true)
); | |
39 if (!platform_device) | |
40 return nullptr; | |
41 | |
42 // Compensate for drawing to a layer rather than the entire canvas | |
43 SkMatrix ctm; | |
44 SkIRect clip_bounds; | |
45 canvas->temporary_internal_describeTopLayer(&ctm, &clip_bounds); | |
46 | |
47 return platform_device->BeginPlatformPaint(ctm, clip_bounds); | |
48 } | |
49 | |
50 HDC BitmapPlatformDevice::GetBitmapDC(const SkMatrix& transform, | |
51 const SkIRect& clip_bounds) { | |
52 if (!hdc_) { | |
53 hdc_ = CreateCompatibleDC(NULL); | |
54 InitializeDC(hdc_); | |
55 old_hbitmap_ = static_cast<HBITMAP>(SelectObject(hdc_, hbitmap_)); | |
56 } | |
57 | |
58 LoadConfig(transform, clip_bounds); | |
59 return hdc_; | |
60 } | |
61 | |
62 void BitmapPlatformDevice::ReleaseBitmapDC() { | |
63 SkASSERT(hdc_); | |
64 SelectObject(hdc_, old_hbitmap_); | |
65 DeleteDC(hdc_); | |
66 hdc_ = NULL; | |
67 old_hbitmap_ = NULL; | |
68 } | |
69 | |
70 bool BitmapPlatformDevice::IsBitmapDCCreated() | |
71 const { | |
72 return hdc_ != NULL; | |
73 } | |
74 | |
75 void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, | |
76 const SkIRect& clip_bounds) { | |
77 if (!hdc_) | |
78 return; // Nothing to do. | |
79 | |
80 // Transform. | |
81 skia::LoadTransformToDC(hdc_, transform); | |
82 LoadClippingRegionToDC(hdc_, clip_bounds, transform); | |
83 } | |
84 | |
85 static void DeleteHBitmapCallback(void* addr, void* context) { | |
86 // If context is not NULL then it's a valid HBITMAP to delete. | |
87 // Otherwise we just unmap the pixel memory. | |
88 if (context) | |
89 DeleteObject(static_cast<HBITMAP>(context)); | |
90 else | |
91 UnmapViewOfFile(addr); | |
92 } | |
93 | |
94 static bool InstallHBitmapPixels(SkBitmap* bitmap, int width, int height, | |
95 bool is_opaque, void* data, HBITMAP hbitmap) { | |
96 const SkAlphaType at = is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; | |
97 const SkImageInfo info = SkImageInfo::MakeN32(width, height, at); | |
98 const size_t rowBytes = info.minRowBytes(); | |
99 SkColorTable* color_table = NULL; | |
100 return bitmap->installPixels(info, data, rowBytes, color_table, | |
101 DeleteHBitmapCallback, hbitmap); | |
102 } | |
103 | |
104 // We use this static factory function instead of the regular constructor so | |
105 // that we can create the pixel data before calling the constructor. This is | |
106 // required so that we can call the base class' constructor with the pixel | |
107 // data. | |
108 BitmapPlatformDevice* BitmapPlatformDevice::Create( | |
109 int width, | |
110 int height, | |
111 bool is_opaque, | |
112 HANDLE shared_section, | |
113 bool do_clear) { | |
114 | |
115 void* data; | |
116 HBITMAP hbitmap = NULL; | |
117 | |
118 // This function contains an implementation of a Skia platform bitmap for | |
119 // drawing and compositing graphics. The original implementation uses Windows | |
120 // GDI to create the backing bitmap memory, however it's possible for a | |
121 // process to not have access to GDI which will cause this code to fail. It's | |
122 // possible to detect when GDI is unavailable and instead directly map the | |
123 // shared memory as the bitmap. | |
124 if (base::win::IsUser32AndGdi32Available()) { | |
125 hbitmap = skia::CreateHBitmap(width, height, is_opaque, shared_section, | |
126 &data); | |
127 if (!hbitmap) { | |
128 LOG(ERROR) << "CreateHBitmap failed"; | |
129 return NULL; | |
130 } | |
131 } else { | |
132 DCHECK(shared_section != NULL); | |
133 data = MapViewOfFile(shared_section, FILE_MAP_WRITE, 0, 0, | |
134 PlatformCanvasStrideForWidth(width) * height); | |
135 if (!data) { | |
136 LOG(ERROR) << "MapViewOfFile failed"; | |
137 return NULL; | |
138 } | |
139 } | |
140 | |
141 SkBitmap bitmap; | |
142 if (!InstallHBitmapPixels(&bitmap, width, height, is_opaque, data, hbitmap)) { | |
143 LOG(ERROR) << "InstallHBitmapPixels failed"; | |
144 return NULL; | |
145 } | |
146 | |
147 if (do_clear) | |
148 bitmap.eraseColor(0); | |
149 | |
150 #ifndef NDEBUG | |
151 // If we were given data, then don't clobber it! | |
152 if (!shared_section && is_opaque) | |
153 // To aid in finding bugs, we set the background color to something | |
154 // obviously wrong so it will be noticable when it is not cleared | |
155 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green | |
156 #endif | |
157 | |
158 // The device object will take ownership of the HBITMAP. The initial refcount | |
159 // of the data object will be 1, which is what the constructor expects. | |
160 return new BitmapPlatformDevice(hbitmap, bitmap); | |
161 } | |
162 | |
163 // static | |
164 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, | |
165 bool is_opaque) { | |
166 const HANDLE shared_section = NULL; | |
167 const bool do_clear = false; | |
168 return Create(width, height, is_opaque, shared_section, do_clear); | |
169 } | |
170 | |
171 // The device will own the HBITMAP, which corresponds to also owning the pixel | |
172 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. | |
173 BitmapPlatformDevice::BitmapPlatformDevice( | |
174 HBITMAP hbitmap, | |
175 const SkBitmap& bitmap) | |
176 : SkBitmapDevice(bitmap), | |
177 hbitmap_(hbitmap), | |
178 old_hbitmap_(NULL), | |
179 hdc_(NULL) { | |
180 // The data object is already ref'ed for us by create(). | |
181 if (hbitmap) { | |
182 SetPlatformDevice(this, this); | |
183 BITMAP bitmap_data; | |
184 GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data); | |
185 } | |
186 } | |
187 | |
188 BitmapPlatformDevice::~BitmapPlatformDevice() { | |
189 if (hdc_) | |
190 ReleaseBitmapDC(); | |
191 } | |
192 | |
193 HDC BitmapPlatformDevice::BeginPlatformPaint(const SkMatrix& transform, | |
194 const SkIRect& clip_bounds) { | |
195 return GetBitmapDC(transform, clip_bounds); | |
196 } | |
197 | |
198 SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& cinfo, | |
199 const SkPaint*) { | |
200 const SkImageInfo& info = cinfo.fInfo; | |
201 const bool do_clear = !info.isOpaque(); | |
202 SkASSERT(info.colorType() == kN32_SkColorType); | |
203 return Create(info.width(), info.height(), info.isOpaque(), NULL, do_clear); | |
204 } | |
205 | |
206 // PlatformCanvas impl | |
207 | |
208 std::unique_ptr<SkCanvas> CreatePlatformCanvasWithSharedSection( | |
209 int width, | |
210 int height, | |
211 bool is_opaque, | |
212 HANDLE shared_section, | |
213 OnFailureType failureType) { | |
214 sk_sp<SkBaseDevice> device( | |
215 BitmapPlatformDevice::Create(width, height, is_opaque, shared_section)); | |
216 if (!device) { | |
217 if (CRASH_ON_FAILURE == failureType) | |
218 SK_CRASH(); | |
219 return nullptr; | |
220 } | |
221 | |
222 return base::MakeUnique<SkCanvas>(device.get()); | |
223 } | |
224 | |
225 } // namespace skia | |
OLD | NEW |