Chromium Code Reviews| Index: base/win/scoped_hdc.h |
| =================================================================== |
| --- base/win/scoped_hdc.h (revision 118400) |
| +++ base/win/scoped_hdc.h (working copy) |
| @@ -1,4 +1,4 @@ |
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| @@ -14,65 +14,163 @@ |
| namespace base { |
| namespace win { |
| -// Like ScopedHandle but for HDC. Only use this on HDCs returned from |
| -// GetDC. |
| -class ScopedGetDC { |
| - public: |
| - explicit ScopedGetDC(HWND hwnd) |
| - : hwnd_(hwnd), |
| - hdc_(GetDC(hwnd)) { |
| - DCHECK(!hwnd_ || IsWindow(hwnd_)); |
| - DCHECK(hdc_); |
| +// The ScopedGetDC and ScopedCreateDC classes manage the default GDI objects |
| +// that are initially selected into a DC. They help you avoid the following |
| +// common mistake: |
| +// |
| +// HDC hdc = GetDC(NULL); |
| +// SelectObject(hdc, new_obj); |
| +// .. drawing code here .. |
| +// ReleaseDC(hdc); <--- error: the DC has a custom object still selected! |
| +// |
| +// This code should be: |
| +// |
| +// HDC hdc = GetDC(NULL); |
| +// HGDIOBJ old_obj = SelectObject(hdc, new_obj); |
| +// .. drawing code here .. |
| +// SelectObject(hdc, old_obj); |
| +// ReleaseDC(hdc); <--- ok to release now. |
| +// |
| +// But why work so hard? use our handy classes: |
|
Derek Bruening
2012/01/21 02:30:49
nit: "Use"
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Done.
|
| +// |
| +// ScopedGetDC dc(NULL); |
| +// dc.SelectObject(hdc, new_obj); |
|
Derek Bruening
2012/01/21 02:30:49
a little misleading: there is no "SelectObject".
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Done.
|
| +// .. drawing here |
|
Derek Bruening
2012/01/21 02:30:49
is there a nice way we can prevent someone from ac
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Let me look into that, I believe the cast to HDC i
Derek Bruening
2012/01/24 18:49:43
OK, waiting on that
|
| +// .. when dc goes out of scope it will select the original object before |
| +// .. being released. |
| +// |
| +template <typename Derived> |
| +class ScopedDC { |
| +public: |
|
Derek Bruening
2012/01/21 02:30:49
indentation
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Done.
|
| + ~ScopedDC() { |
| + Close(); |
| } |
| - ~ScopedGetDC() { |
| - if (hdc_) |
| - ReleaseDC(hwnd_, hdc_); |
| + HDC Get() { |
| + return hdc_; |
| } |
| - operator HDC() { return hdc_; } |
| + operator HDC() { |
| + return hdc_; |
| + } |
| + void SelectBitmap(HBITMAP bitmap) { |
|
Derek Bruening
2012/01/21 02:30:49
do callers never need to know return value of Sele
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Ideally the objects that are not the initial, will
|
| + Select(bitmap, &bitmap_); |
| + } |
| + |
| + void SelectFont(HFONT font) { |
| + Select(font, &font_); |
| + } |
| + |
| + void SelectBrush(HBRUSH brush) { |
| + Select(brush, &brush_); |
| + } |
| + |
| + void SelectPen(HPEN pen) { |
| + Select(pen, &pen_); |
| + } |
| + |
| + void SelectRegion(HRGN region) { |
| + Select(region, ®ion); |
| + } |
| + |
| + protected: |
| + ScopedDC(HDC hdc) |
| + : hdc_(hdc), bitmap_(0), font_(0), brush_(0), pen_(0), region_(0) { |
| + } |
| + |
| + void Close() { |
| + if (!hdc_) |
| + return; |
| + ResetObjects(); |
| + static_cast<Derived*>(this)->DisposeDC(hdc_); |
| + } |
| + |
| + void Reset(HDC hdc) { |
| + Close(); |
| + hdc_ = hdc; |
| + } |
| + |
| private: |
| - HWND hwnd_; |
| + void ResetObjects() { |
| + if (bitmap_) { |
| + SelectObject(hdc_, bitmap_); |
| + bitmap_ = 0; |
| + } |
| + if (font_) { |
| + SelectObject(hdc_, font_); |
| + font_ = 0; |
| + } |
| + if (brush_) { |
| + SelectObject(hdc_, brush_); |
| + brush_ = 0; |
| + } |
| + if (pen_) { |
| + SelectObject(hdc_, pen_); |
| + pen_ = 0; |
| + } |
| + if (region_) { |
| + SelectObject(hdc_, region_); |
| + region_ = 0; |
| + } |
| + } |
| + |
| + void Select(HGDIOBJ object, HGDIOBJ* holder) { |
| + HGDIOBJ old = SelectObject(hdc_, object); |
| + DCHECK(old); |
|
Derek Bruening
2012/01/21 02:30:49
DCHECK(holder)
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
I rather not, a null pointer is guaranteed crash i
|
| + if (!*holder) |
|
Derek Bruening
2012/01/21 02:30:49
ok you're not returning the HGDIOBJ and are instea
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Done.
|
| + *holder = old; |
| + } |
| + |
| HDC hdc_; |
| + HGDIOBJ bitmap_; |
| + HGDIOBJ font_; |
| + HGDIOBJ brush_; |
| + HGDIOBJ pen_; |
| + HGDIOBJ region_; |
|
Derek Bruening
2012/01/21 02:30:49
prior_bitmap_ or old_bitmap_ or orig_bitmap_ are m
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
ugly. do you really really want me to change them?
|
| +}; |
| +// Creates and manages a HDC obtained by GetDC. |
| +class ScopedGetDC : public ScopedDC<ScopedGetDC> { |
|
Derek Bruening
2012/01/21 02:30:49
yeah IMHO simpler code via virtual is the way to g
cpu_(ooo_6.6-7.5)
2012/01/24 04:48:04
Ok, by popular demand changed the code to use vtab
|
| + public: |
| + explicit ScopedGetDC(HWND hwnd) |
| + : ScopedDC(GetDC(hwnd)), hwnd_(hwnd) { |
| + } |
| + |
| + private: |
| + friend class ScopedDC<ScopedGetDC>; |
| + |
| + void DisposeDC(HDC hdc) { |
| + ReleaseDC(hwnd_, hdc); |
| + } |
| + |
| + HWND hwnd_; |
| DISALLOW_COPY_AND_ASSIGN(ScopedGetDC); |
| }; |
| // Like ScopedHandle but for HDC. Only use this on HDCs returned from |
| // CreateCompatibleDC, CreateDC and CreateIC. |
| -class ScopedCreateDC { |
| +class ScopedCreateDC : public ScopedDC<ScopedCreateDC> { |
| public: |
| - ScopedCreateDC() : hdc_(NULL) { } |
| - explicit ScopedCreateDC(HDC h) : hdc_(h) { } |
| - |
| - ~ScopedCreateDC() { |
| - Close(); |
| + ScopedCreateDC() |
| + : ScopedDC(0) { |
| } |
| - HDC Get() { |
| - return hdc_; |
| + explicit ScopedCreateDC(HDC hdc) |
| + : ScopedDC(hdc) { |
| } |
| - void Set(HDC h) { |
| - Close(); |
| - hdc_ = h; |
| + void Set(HDC hdc) { |
| + Reset(hdc); |
| } |
| - operator HDC() { return hdc_; } |
| + private: |
| + friend class ScopedDC<ScopedCreateDC>; |
| - private: |
| - void Close() { |
| -#ifdef NOGDI |
| - assert(false); |
| -#else |
| - if (hdc_) |
| - DeleteDC(hdc_); |
| -#endif // NOGDI |
| + void DisposeDC(HDC hdc) { |
| + DeleteDC(hdc); |
| } |
| - HDC hdc_; |
| - |
| DISALLOW_COPY_AND_ASSIGN(ScopedCreateDC); |
| }; |