Getting rid of GetDefaultProfile(), clean up of ProfileManager (which was in a seriou...
[chromium-blink-merge.git] / skia / ext / bitmap_platform_device_win.cc
blob389e1d592271861671b892cab7d0e2a12033bcae
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.
5 #include <windows.h>
6 #include <psapi.h>
8 #include "base/logging.h"
9 #include "base/debug/alias.h"
10 #include "skia/ext/bitmap_platform_device_win.h"
11 #include "skia/ext/platform_canvas.h"
12 #include "third_party/skia/include/core/SkMatrix.h"
13 #include "third_party/skia/include/core/SkRefCnt.h"
14 #include "third_party/skia/include/core/SkRegion.h"
15 #include "third_party/skia/include/core/SkUtils.h"
17 namespace {
19 // PlatformBitmapPixelRef is an SkPixelRef that, on Windows, is backed by an
20 // HBITMAP.
21 class SK_API PlatformBitmapPixelRef : public SkPixelRef {
22 public:
23 PlatformBitmapPixelRef(const SkImageInfo& info, HBITMAP bitmap_handle,
24 void* pixels);
25 virtual ~PlatformBitmapPixelRef();
27 SK_DECLARE_UNFLATTENABLE_OBJECT();
29 protected:
30 virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE;
31 virtual void onUnlockPixels() SK_OVERRIDE;
33 private:
34 HBITMAP bitmap_handle_;
35 void* pixels_;
38 HBITMAP CreateHBitmap(int width, int height, bool is_opaque,
39 HANDLE shared_section, void** data) {
40 // CreateDIBSection appears to get unhappy if we create an empty bitmap, so
41 // just create a minimal bitmap
42 if ((width == 0) || (height == 0)) {
43 width = 1;
44 height = 1;
47 BITMAPINFOHEADER hdr = {0};
48 hdr.biSize = sizeof(BITMAPINFOHEADER);
49 hdr.biWidth = width;
50 hdr.biHeight = -height; // minus means top-down bitmap
51 hdr.biPlanes = 1;
52 hdr.biBitCount = 32;
53 hdr.biCompression = BI_RGB; // no compression
54 hdr.biSizeImage = 0;
55 hdr.biXPelsPerMeter = 1;
56 hdr.biYPelsPerMeter = 1;
57 hdr.biClrUsed = 0;
58 hdr.biClrImportant = 0;
60 HBITMAP hbitmap = CreateDIBSection(NULL, reinterpret_cast<BITMAPINFO*>(&hdr),
61 0, data, shared_section, 0);
63 // If this call fails, we're gonna crash hard. Try to get some useful
64 // information out before we crash for post-mortem analysis.
65 if (!hbitmap) {
66 // Make sure parameters are saved in the minidump.
67 base::debug::Alias(&width);
68 base::debug::Alias(&height);
70 int last_error = GetLastError();
71 base::debug::Alias(&last_error);
73 int num_gdi_handles = GetGuiResources(GetCurrentProcess(),
74 GR_GDIOBJECTS);
75 if (num_gdi_handles == 0) {
76 int get_gui_resources_error = GetLastError();
77 base::debug::Alias(&get_gui_resources_error);
78 CHECK(false);
81 base::debug::Alias(&num_gdi_handles);
82 const int kLotsOfHandles = 9990;
83 if (num_gdi_handles > kLotsOfHandles)
84 CHECK(false);
86 PROCESS_MEMORY_COUNTERS_EX pmc;
87 pmc.cb = sizeof(pmc);
88 if (!GetProcessMemoryInfo(GetCurrentProcess(),
89 reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc),
90 sizeof(pmc))) {
91 CHECK(false);
93 const size_t kLotsOfMemory = 1500 * 1024 * 1024; // 1.5GB
94 if (pmc.PagefileUsage > kLotsOfMemory)
95 CHECK(false);
96 if (pmc.PrivateUsage > kLotsOfMemory)
97 CHECK(false);
99 // Huh, that's weird. We don't have crazy handle count, we don't have
100 // ridiculous memory usage. Try to allocate a small bitmap and see if that
101 // fails too.
102 hdr.biWidth = 5;
103 hdr.biHeight = 5;
104 void* small_data;
105 HBITMAP small_bitmap = CreateDIBSection(
106 NULL, reinterpret_cast<BITMAPINFO*>(&hdr),
107 0, &small_data, shared_section, 0);
108 if (!small_bitmap)
109 CHECK(false);
110 BITMAP bitmap_data;
111 if (GetObject(small_bitmap, sizeof(BITMAP), &bitmap_data)) {
112 if (!DeleteObject(small_bitmap))
113 CHECK(false);
115 // No idea what's going on. Die!
116 CHECK(false);
118 return hbitmap;
121 PlatformBitmapPixelRef::PlatformBitmapPixelRef(const SkImageInfo& info,
122 HBITMAP bitmap_handle,
123 void* pixels)
124 : SkPixelRef(info),
125 bitmap_handle_(bitmap_handle),
126 pixels_(pixels) {
127 setPreLocked(pixels, info.minRowBytes(), NULL);
130 PlatformBitmapPixelRef::~PlatformBitmapPixelRef() {
131 if (bitmap_handle_)
132 DeleteObject(bitmap_handle_);
135 void* PlatformBitmapPixelRef::onLockPixels(SkColorTable** color_table) {
136 *color_table = NULL;
137 return pixels_;
140 void PlatformBitmapPixelRef::onUnlockPixels() {
141 // Nothing to do.
142 return;
145 } // namespace
147 namespace skia {
149 HDC BitmapPlatformDevice::GetBitmapDC() {
150 if (!hdc_) {
151 hdc_ = CreateCompatibleDC(NULL);
152 InitializeDC(hdc_);
153 old_hbitmap_ = static_cast<HBITMAP>(SelectObject(hdc_, hbitmap_));
156 LoadConfig();
157 return hdc_;
160 void BitmapPlatformDevice::ReleaseBitmapDC() {
161 SkASSERT(hdc_);
162 SelectObject(hdc_, old_hbitmap_);
163 DeleteDC(hdc_);
164 hdc_ = NULL;
165 old_hbitmap_ = NULL;
168 bool BitmapPlatformDevice::IsBitmapDCCreated()
169 const {
170 return hdc_ != NULL;
174 void BitmapPlatformDevice::SetMatrixClip(
175 const SkMatrix& transform,
176 const SkRegion& region) {
177 transform_ = transform;
178 clip_region_ = region;
179 config_dirty_ = true;
182 void BitmapPlatformDevice::LoadConfig() {
183 if (!config_dirty_ || !hdc_)
184 return; // Nothing to do.
185 config_dirty_ = false;
187 // Transform.
188 LoadTransformToDC(hdc_, transform_);
189 LoadClippingRegionToDC(hdc_, clip_region_, transform_);
192 // We use this static factory function instead of the regular constructor so
193 // that we can create the pixel data before calling the constructor. This is
194 // required so that we can call the base class' constructor with the pixel
195 // data.
196 BitmapPlatformDevice* BitmapPlatformDevice::Create(
197 int width,
198 int height,
199 bool is_opaque,
200 HANDLE shared_section) {
202 void* data;
203 HBITMAP hbitmap = CreateHBitmap(width, height, is_opaque, shared_section,
204 &data);
205 if (!hbitmap)
206 return NULL;
208 const SkImageInfo info = {
209 width,
210 height,
211 kPMColor_SkColorType,
212 is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType
214 SkBitmap bitmap;
215 bitmap.setConfig(info);
216 RefPtr<SkPixelRef> pixel_ref = AdoptRef(new PlatformBitmapPixelRef(info,
217 hbitmap,
218 data));
219 bitmap.setPixelRef(pixel_ref.get());
221 #ifndef NDEBUG
222 // If we were given data, then don't clobber it!
223 if (!shared_section && is_opaque)
224 // To aid in finding bugs, we set the background color to something
225 // obviously wrong so it will be noticable when it is not cleared
226 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green
227 #endif
229 // The device object will take ownership of the HBITMAP. The initial refcount
230 // of the data object will be 1, which is what the constructor expects.
231 return new BitmapPlatformDevice(hbitmap, bitmap);
234 // static
235 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
236 bool is_opaque) {
237 return Create(width, height, is_opaque, NULL);
240 // static
241 BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
242 int height,
243 bool is_opaque) {
244 BitmapPlatformDevice* device = BitmapPlatformDevice::Create(width, height,
245 is_opaque);
246 if (device && !is_opaque)
247 device->accessBitmap(true).eraseARGB(0, 0, 0, 0);
248 return device;
251 // The device will own the HBITMAP, which corresponds to also owning the pixel
252 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap.
253 BitmapPlatformDevice::BitmapPlatformDevice(
254 HBITMAP hbitmap,
255 const SkBitmap& bitmap)
256 : SkBitmapDevice(bitmap),
257 hbitmap_(hbitmap),
258 old_hbitmap_(NULL),
259 hdc_(NULL),
260 config_dirty_(true), // Want to load the config next time.
261 transform_(SkMatrix::I()) {
262 // The data object is already ref'ed for us by create().
263 SkDEBUGCODE(begin_paint_count_ = 0);
264 SetPlatformDevice(this, this);
265 // Initialize the clip region to the entire bitmap.
266 BITMAP bitmap_data;
267 if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) {
268 SkIRect rect;
269 rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight);
270 clip_region_ = SkRegion(rect);
274 BitmapPlatformDevice::~BitmapPlatformDevice() {
275 SkASSERT(begin_paint_count_ == 0);
276 if (hdc_)
277 ReleaseBitmapDC();
280 HDC BitmapPlatformDevice::BeginPlatformPaint() {
281 SkDEBUGCODE(begin_paint_count_++);
282 return GetBitmapDC();
285 void BitmapPlatformDevice::EndPlatformPaint() {
286 SkASSERT(begin_paint_count_--);
287 PlatformDevice::EndPlatformPaint();
290 void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
291 const SkRegion& region,
292 const SkClipStack&) {
293 SetMatrixClip(transform, region);
296 void BitmapPlatformDevice::DrawToNativeContext(HDC dc, int x, int y,
297 const RECT* src_rect) {
298 bool created_dc = !IsBitmapDCCreated();
299 HDC source_dc = BeginPlatformPaint();
301 RECT temp_rect;
302 if (!src_rect) {
303 temp_rect.left = 0;
304 temp_rect.right = width();
305 temp_rect.top = 0;
306 temp_rect.bottom = height();
307 src_rect = &temp_rect;
310 int copy_width = src_rect->right - src_rect->left;
311 int copy_height = src_rect->bottom - src_rect->top;
313 // We need to reset the translation for our bitmap or (0,0) won't be in the
314 // upper left anymore
315 SkMatrix identity;
316 identity.reset();
318 LoadTransformToDC(source_dc, identity);
319 if (isOpaque()) {
320 BitBlt(dc,
323 copy_width,
324 copy_height,
325 source_dc,
326 src_rect->left,
327 src_rect->top,
328 SRCCOPY);
329 } else {
330 SkASSERT(copy_width != 0 && copy_height != 0);
331 BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
332 GdiAlphaBlend(dc,
335 copy_width,
336 copy_height,
337 source_dc,
338 src_rect->left,
339 src_rect->top,
340 copy_width,
341 copy_height,
342 blend_function);
344 LoadTransformToDC(source_dc, transform_);
346 EndPlatformPaint();
347 if (created_dc)
348 ReleaseBitmapDC();
351 const SkBitmap& BitmapPlatformDevice::onAccessBitmap() {
352 // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI
353 // operation has occurred on our DC.
354 if (IsBitmapDCCreated())
355 GdiFlush();
356 return SkBitmapDevice::onAccessBitmap();
359 SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
360 SkBitmap::Config config, int width, int height, bool isOpaque, Usage) {
361 SkASSERT(config == SkBitmap::kARGB_8888_Config);
362 return BitmapPlatformDevice::CreateAndClear(width, height, isOpaque);
365 // PlatformCanvas impl
367 SkCanvas* CreatePlatformCanvas(int width,
368 int height,
369 bool is_opaque,
370 HANDLE shared_section,
371 OnFailureType failureType) {
372 skia::RefPtr<SkBaseDevice> dev = skia::AdoptRef(
373 BitmapPlatformDevice::Create(width, height, is_opaque, shared_section));
374 return CreateCanvas(dev, failureType);
377 // Port of PlatformBitmap to win
379 PlatformBitmap::~PlatformBitmap() {
380 if (surface_) {
381 if (platform_extra_)
382 SelectObject(surface_, reinterpret_cast<HGDIOBJ>(platform_extra_));
383 DeleteDC(surface_);
387 bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) {
388 void* data;
389 HBITMAP hbitmap = CreateHBitmap(width, height, is_opaque, 0, &data);
390 if (!hbitmap)
391 return false;
393 surface_ = CreateCompatibleDC(NULL);
394 InitializeDC(surface_);
395 // When the memory DC is created, its display surface is exactly one
396 // monochrome pixel wide and one monochrome pixel high. Save this object
397 // off, we'll restore it just before deleting the memory DC.
398 HGDIOBJ stock_bitmap = SelectObject(surface_, hbitmap);
399 platform_extra_ = reinterpret_cast<intptr_t>(stock_bitmap);
401 const SkImageInfo info = {
402 width,
403 height,
404 kPMColor_SkColorType,
405 is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType
407 bitmap_.setConfig(info);
408 // PlatformBitmapPixelRef takes ownership of |hbitmap|.
409 RefPtr<SkPixelRef> pixel_ref = AdoptRef(new PlatformBitmapPixelRef(info,
410 hbitmap,
411 data));
412 bitmap_.setPixelRef(pixel_ref.get());
413 bitmap_.lockPixels();
415 return true;
418 } // namespace skia