summaryrefslogtreecommitdiffstats
path: root/base/gfx/native_theme.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
commitd7cae12696b96500c05dd2d430f6238922c20c96 (patch)
treeecff27b367735535b2a66477f8cd89d3c462a6c0 /base/gfx/native_theme.cc
parentee2815e28d408216cf94e874825b6bcf76c69083 (diff)
downloadchromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.zip
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.gz
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.bz2
Add base to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/gfx/native_theme.cc')
-rw-r--r--base/gfx/native_theme.cc626
1 files changed, 626 insertions, 0 deletions
diff --git a/base/gfx/native_theme.cc b/base/gfx/native_theme.cc
new file mode 100644
index 0000000..8ab4ca3
--- /dev/null
+++ b/base/gfx/native_theme.cc
@@ -0,0 +1,626 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/gfx/native_theme.h"
+
+#include <windows.h>
+#include <uxtheme.h>
+#include <vsstyle.h>
+#include <vssym32.h>
+
+#include "base/gfx/bitmap_header.h"
+#include "base/gfx/platform_canvas.h"
+#include "base/gfx/skia_utils.h"
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "base/scoped_handle.h"
+#include "skia/include/SkShader.h"
+
+namespace gfx {
+
+/* static */
+const NativeTheme* NativeTheme::instance() {
+ // The global NativeTheme instance.
+ static const NativeTheme s_native_theme;
+ return &s_native_theme;
+}
+
+NativeTheme::NativeTheme()
+ : theme_dll_(LoadLibrary(L"uxtheme.dll")),
+ draw_theme_(NULL),
+ draw_theme_ex_(NULL),
+ get_theme_color_(NULL),
+ get_theme_content_rect_(NULL),
+ get_theme_part_size_(NULL),
+ open_theme_(NULL),
+ close_theme_(NULL),
+ set_theme_properties_(NULL),
+ is_theme_active_(NULL),
+ get_theme_int_(NULL) {
+ if (theme_dll_) {
+ draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
+ GetProcAddress(theme_dll_, "DrawThemeBackground"));
+ draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
+ GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
+ get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
+ GetProcAddress(theme_dll_, "GetThemeColor"));
+ get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
+ GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
+ get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
+ GetProcAddress(theme_dll_, "GetThemePartSize"));
+ open_theme_ = reinterpret_cast<OpenThemeDataPtr>(
+ GetProcAddress(theme_dll_, "OpenThemeData"));
+ close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
+ GetProcAddress(theme_dll_, "CloseThemeData"));
+ set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
+ GetProcAddress(theme_dll_, "SetThemeAppProperties"));
+ is_theme_active_ = reinterpret_cast<IsThemeActivePtr>(
+ GetProcAddress(theme_dll_, "IsThemeActive"));
+ get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
+ GetProcAddress(theme_dll_, "GetThemeInt"));
+ }
+ memset(theme_handles_, 0, sizeof(theme_handles_));
+}
+
+NativeTheme::~NativeTheme() {
+ if (theme_dll_) {
+ CloseHandles();
+ FreeLibrary(theme_dll_);
+ }
+}
+
+HRESULT NativeTheme::PaintButton(HDC hdc,
+ int part_id,
+ int state_id,
+ int classic_state,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(BUTTON);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+
+ // Draw it manually.
+ // All pressed states have both low bits set, and no other states do.
+ const bool focused = ((state_id & PBS_PRESSED) == PBS_PRESSED);
+ if ((part_id == BP_PUSHBUTTON) && focused) {
+ // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
+ // button itself is shrunk by 1 pixel.
+ HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
+ if (brush) {
+ FrameRect(hdc, rect, brush);
+ InflateRect(rect, -1, -1);
+ }
+ }
+
+ DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
+
+ // BP_RADIOBUTTON, BP_CHECKBOX, BP_GROUPBOX and BP_USERBUTTON have their
+ // focus drawn over the control.
+ if ((part_id != BP_PUSHBUTTON) && focused)
+ DrawFocusRect(hdc, rect);
+
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintTextField(HDC hdc,
+ int part_id,
+ int state_id,
+ int classic_state,
+ RECT* rect,
+ COLORREF color,
+ bool fill_content_area,
+ bool draw_edges) const {
+ // TODO(ojan): http://b/1210017 Figure out how to give the ability to
+ // exclude individual edges from being drawn.
+
+ HANDLE handle = GetThemeHandle(TEXTFIELD);
+ // TODO(mpcomplete): can we detect if the color is specified by the user,
+ // and if not, just use the system color?
+ // CreateSolidBrush() accepts a RGB value but alpha must be 0.
+ HBRUSH bg_brush = CreateSolidBrush(color);
+ HRESULT hr;
+ // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
+ // draw_theme_ex_ is NULL and draw_theme_ is non-null.
+ if (handle && (draw_theme_ex_ || (draw_theme_ && draw_edges))) {
+ if (draw_theme_ex_) {
+ static DTBGOPTS omit_border_options = {
+ sizeof(DTBGOPTS),
+ DTBG_OMITBORDER,
+ {0,0,0,0}
+ };
+ DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options;
+ hr = draw_theme_ex_(handle, hdc, part_id, state_id, rect, draw_opts);
+ } else {
+ hr = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ }
+
+ // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
+ if (fill_content_area && get_theme_content_rect_) {
+ RECT content_rect;
+ hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
+ &content_rect);
+ FillRect(hdc, &content_rect, bg_brush);
+ }
+ } else {
+ // Draw it manually.
+ if (draw_edges)
+ DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+
+ if (fill_content_area) {
+ FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
+ reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
+ }
+ hr = S_OK;
+ }
+ DeleteObject(bg_brush);
+ return hr;
+}
+
+HRESULT NativeTheme::PaintMenuList(HDC hdc,
+ int part_id,
+ int state_id,
+ int classic_state,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(MENULIST);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+
+ // Draw it manually.
+ DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | classic_state);
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintScrollbarArrow(HDC hdc,
+ int state_id,
+ int classic_state,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(SCROLLBAR);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, rect, NULL);
+
+ // Draw it manually.
+ DrawFrameControl(hdc, rect, DFC_SCROLL, classic_state);
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintScrollbarTrack(HDC hdc,
+ int part_id,
+ int state_id,
+ int classic_state,
+ RECT* target_rect,
+ RECT* align_rect,
+ PlatformCanvas* canvas) const {
+ HANDLE handle = GetThemeHandle(SCROLLBAR);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL);
+
+ // Draw it manually.
+ const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR);
+ const DWORD color3DFace = GetSysColor(COLOR_3DFACE);
+ if ((colorScrollbar != color3DFace) &&
+ (colorScrollbar != GetSysColor(COLOR_WINDOW))) {
+ FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
+ } else {
+ // Create a 2x2 checkerboard pattern using the 3D face and highlight
+ // colors.
+ SkColor face = COLORREFToSkColor(color3DFace);
+ SkColor highlight = COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT));
+ SkColor buffer[] = { face, highlight, highlight, face };
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bitmap.setPixels(buffer);
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ // Draw that pattern into the target rect, setting the origin to the top
+ // left corner of the scrollbar track (so the checked rect below the thumb
+ // aligns properly with the portion above the thumb).
+ SkMatrix matrix;
+ matrix.setTranslate(SkIntToScalar(align_rect->left),
+ SkIntToScalar(align_rect->top));
+ shader->setLocalMatrix(matrix);
+ SkPaint paint;
+ paint.setShader(shader)->unref();
+ canvas->drawIRect(RECTToSkIRect(*target_rect), paint);
+ }
+ if (classic_state & DFCS_PUSHED)
+ InvertRect(hdc, target_rect);
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc,
+ int part_id,
+ int state_id,
+ int classic_state,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(SCROLLBAR);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+
+ // Draw it manually.
+ if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
+ DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+ // Classic mode doesn't have a gripper.
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintStatusGripper(HDC hdc,
+ int part_id,
+ int state_id,
+ int classic_state,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(STATUS);
+ if (handle && draw_theme_) {
+ // Paint the status bar gripper. There doesn't seem to be a
+ // standard gripper in Windows for the space between
+ // scrollbars. This is pretty close, but it's supposed to be
+ // painted over a status bar.
+ return draw_theme_(handle, hdc, SP_GRIPPER, 0, rect, 0);
+ }
+
+ // Draw a windows classic scrollbar gripper.
+ DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintDialogBackground(HDC hdc, bool active,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(WINDOW);
+ if (handle && draw_theme_) {
+ return draw_theme_(handle, hdc, WP_DIALOG,
+ active ? FS_ACTIVE : FS_INACTIVE, rect, NULL);
+ }
+
+ // Classic just renders a flat color background.
+ FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const {
+ HANDLE handle = GetThemeHandle(TAB);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL);
+
+ // Classic just renders a flat color background.
+ FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintListBackground(HDC hdc,
+ bool enabled,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(LIST);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, 1, TS_NORMAL, rect, NULL);
+
+ // Draw it manually.
+ HBRUSH bg_brush = GetSysColorBrush(COLOR_WINDOW);
+ FillRect(hdc, rect, bg_brush);
+ DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ return S_OK;
+}
+
+bool NativeTheme::IsThemingActive() const {
+ if (is_theme_active_)
+ return !!is_theme_active_();
+ return false;
+}
+
+HRESULT NativeTheme::PaintMenuArrow(ThemeName theme,
+ HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect,
+ MenuArrowDirection arrow_direction,
+ bool is_highlighted) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_) {
+ if (arrow_direction == RIGHT_POINTING_ARROW) {
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ } else {
+ // There is no way to tell the uxtheme API to draw a left pointing arrow;
+ // it doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they
+ // are needed for RTL locales on Vista. So use a memory DC and mirror
+ // the region with GDI's StretchBlt.
+ Rect r(*rect);
+ ScopedHDC mem_dc(CreateCompatibleDC(hdc));
+ ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
+ r.height()));
+ HGDIOBJ old_bitmap = SelectObject(mem_dc, mem_bitmap);
+ // Copy and horizontally mirror the background from hdc into mem_dc. Use
+ // a negative-width source rect, starting at the rightmost pixel.
+ StretchBlt(mem_dc, 0, 0, r.width(), r.height(),
+ hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
+ // Draw the arrow.
+ RECT theme_rect = {0, 0, r.width(), r.height()};
+ HRESULT result = draw_theme_(handle, mem_dc, part_id,
+ state_id, &theme_rect, NULL);
+ // Copy and mirror the result back into mem_dc.
+ StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
+ mem_dc, r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
+ SelectObject(mem_dc, old_bitmap);
+ return result;
+ }
+ }
+
+ // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
+ // left pointing arrow. This makes the following 'if' statement slightly
+ // counterintuitive.
+ UINT state;
+ if (arrow_direction == RIGHT_POINTING_ARROW)
+ state = DFCS_MENUARROW;
+ else
+ state = DFCS_MENUARROWRIGHT;
+ return PaintFrameControl(hdc, rect, DFC_MENU, state, is_highlighted);
+}
+
+HRESULT NativeTheme::PaintMenuBackground(ThemeName theme,
+ HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_) {
+ HRESULT result = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ FrameRect(hdc, rect, GetSysColorBrush(COLOR_3DSHADOW));
+ return result;
+ }
+
+ FillRect(hdc, rect, GetSysColorBrush(COLOR_MENU));
+ DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT);
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintMenuCheckBackground(ThemeName theme,
+ HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ // Nothing to do for background.
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintMenuCheck(ThemeName theme,
+ HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect,
+ bool is_highlighted) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_) {
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ }
+ return PaintFrameControl(hdc, rect, DFC_MENU, DFCS_MENUCHECK, is_highlighted);
+}
+
+HRESULT NativeTheme::PaintMenuGutter(HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ return E_NOTIMPL;
+}
+
+HRESULT NativeTheme::PaintMenuSeparator(HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ DrawEdge(hdc, rect, EDGE_ETCHED, BF_TOP);
+ return S_OK;
+}
+
+HRESULT NativeTheme::PaintMenuItemBackground(ThemeName theme,
+ HDC hdc,
+ int part_id,
+ int state_id,
+ bool selected,
+ RECT* rect) const {
+ HANDLE handle = GetThemeHandle(MENU);
+ if (handle && draw_theme_)
+ return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
+ if (selected)
+ FillRect(hdc, rect, GetSysColorBrush(COLOR_HIGHLIGHT));
+ return S_OK;
+}
+
+HRESULT NativeTheme::GetThemePartSize(ThemeName theme_name,
+ HDC hdc,
+ int part_id,
+ int state_id,
+ RECT* rect,
+ int ts,
+ SIZE* size) const {
+ HANDLE handle = GetThemeHandle(theme_name);
+ if (handle && get_theme_part_size_)
+ return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size);
+
+ return E_NOTIMPL;
+}
+
+HRESULT NativeTheme::GetThemeColor(ThemeName theme,
+ int part_id,
+ int state_id,
+ int prop_id,
+ SkColor* color) const {
+ HANDLE handle = GetThemeHandle(theme);
+ if (handle && get_theme_color_) {
+ COLORREF color_ref;
+ if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) ==
+ S_OK) {
+ *color = gfx::COLORREFToSkColor(color_ref);
+ return S_OK;
+ }
+ }
+ return E_NOTIMPL;
+}
+
+SkColor NativeTheme::GetThemeColorWithDefault(ThemeName theme,
+ int part_id,
+ int state_id,
+ int prop_id,
+ int default_sys_color) const {
+ SkColor color;
+ if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK)
+ color = gfx::COLORREFToSkColor(GetSysColor(default_sys_color));
+ return color;
+}
+
+HRESULT NativeTheme::GetThemeInt(ThemeName theme,
+ int part_id,
+ int state_id,
+ int prop_id,
+ int *value) const {
+ HANDLE handle = GetThemeHandle(theme);
+ if (handle && get_theme_int_)
+ return get_theme_int_(handle, part_id, state_id, prop_id, value);
+ return E_NOTIMPL;
+}
+
+Size NativeTheme::GetThemeBorderSize(ThemeName theme) const {
+ // For simplicity use the wildcard state==0, part==0, since it works
+ // for the cases we currently depend on.
+ int border;
+ if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK)
+ return Size(border, border);
+ else
+ return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
+}
+
+
+void NativeTheme::DisableTheming() const {
+ if (!set_theme_properties_)
+ return;
+ set_theme_properties_(0);
+}
+
+HRESULT NativeTheme::PaintFrameControl(HDC hdc,
+ RECT* rect,
+ UINT type,
+ UINT state,
+ bool is_highlighted) const {
+ const int width = rect->right - rect->left;
+ const int height = rect->bottom - rect->top;
+
+ // DrawFrameControl for menu arrow/check wants a monochrome bitmap.
+ ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
+
+ if (mask_bitmap == NULL)
+ return E_OUTOFMEMORY;
+
+ ScopedHDC bitmap_dc(CreateCompatibleDC(NULL));
+ HGDIOBJ org_bitmap = SelectObject(bitmap_dc, mask_bitmap);
+ RECT local_rect = { 0, 0, width, height };
+ DrawFrameControl(bitmap_dc, &local_rect, type, state);
+
+ // We're going to use BitBlt with a b&w mask. This results in using the dest
+ // dc's text color for the black bits in the mask, and the dest dc's
+ // background color for the white bits in the mask. DrawFrameControl draws the
+ // check in black, and the background in white.
+ COLORREF old_bg_color =
+ SetBkColor(hdc,
+ GetSysColor(is_highlighted ? COLOR_HIGHLIGHT : COLOR_MENU));
+ COLORREF old_text_color =
+ SetTextColor(hdc,
+ GetSysColor(is_highlighted ? COLOR_HIGHLIGHTTEXT :
+ COLOR_MENUTEXT));
+ BitBlt(hdc, rect->left, rect->top, width, height, bitmap_dc, 0, 0, SRCCOPY);
+ SetBkColor(hdc, old_bg_color);
+ SetTextColor(hdc, old_text_color);
+
+ SelectObject(bitmap_dc, org_bitmap);
+
+ return S_OK;
+}
+
+void NativeTheme::CloseHandles() const
+{
+ if (!close_theme_)
+ return;
+
+ for (int i = 0; i < LAST; ++i) {
+ if (theme_handles_[i])
+ close_theme_(theme_handles_[i]);
+ theme_handles_[i] = NULL;
+ }
+}
+
+HANDLE NativeTheme::GetThemeHandle(ThemeName theme_name) const
+{
+ if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
+ return 0;
+
+ if (theme_handles_[theme_name])
+ return theme_handles_[theme_name];
+
+ // Not found, try to load it.
+ HANDLE handle = 0;
+ switch (theme_name) {
+ case NativeTheme::BUTTON:
+ handle = open_theme_(NULL, L"Button");
+ break;
+ case NativeTheme::TEXTFIELD:
+ handle = open_theme_(NULL, L"Edit");
+ break;
+ case NativeTheme::MENULIST:
+ handle = open_theme_(NULL, L"Combobox");
+ break;
+ case NativeTheme::SCROLLBAR:
+ handle = open_theme_(NULL, L"Scrollbar");
+ break;
+ case NativeTheme::STATUS:
+ handle = open_theme_(NULL, L"Status");
+ break;
+ case NativeTheme::MENU:
+ handle = open_theme_(NULL, L"Menu");
+ break;
+ case NativeTheme::WINDOW:
+ handle = open_theme_(NULL, L"Window");
+ break;
+ case NativeTheme::TAB:
+ handle = open_theme_(NULL, L"Tab");
+ break;
+ case NativeTheme::LIST:
+ handle = open_theme_(NULL, L"Listview");
+ break;
+ default:
+ NOTREACHED();
+ }
+ theme_handles_[theme_name] = handle;
+ return handle;
+}
+
+} // namespace gfx