blob: ea55502a28e3db16a2409dd70dbce8c96228aae9 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#include "base/gfx/native_theme.h"
6
7#include <windows.h>
8#include <uxtheme.h>
9#include <vsstyle.h>
10#include <vssym32.h>
11
12#include "base/gfx/bitmap_header.h"
awalker@google.combce88e12008-08-15 02:47:00 +090013#include "base/gfx/platform_canvas_win.h"
initial.commit3f4a7322008-07-27 06:49:38 +090014#include "base/gfx/skia_utils.h"
15#include "base/gfx/rect.h"
16#include "base/logging.h"
17#include "base/scoped_handle.h"
18#include "skia/include/SkShader.h"
19
20namespace gfx {
21
22/* static */
23const NativeTheme* NativeTheme::instance() {
24 // The global NativeTheme instance.
25 static const NativeTheme s_native_theme;
26 return &s_native_theme;
27}
28
29NativeTheme::NativeTheme()
30 : theme_dll_(LoadLibrary(L"uxtheme.dll")),
31 draw_theme_(NULL),
32 draw_theme_ex_(NULL),
33 get_theme_color_(NULL),
34 get_theme_content_rect_(NULL),
35 get_theme_part_size_(NULL),
36 open_theme_(NULL),
37 close_theme_(NULL),
38 set_theme_properties_(NULL),
39 is_theme_active_(NULL),
40 get_theme_int_(NULL) {
41 if (theme_dll_) {
42 draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
43 GetProcAddress(theme_dll_, "DrawThemeBackground"));
44 draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
45 GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
46 get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
47 GetProcAddress(theme_dll_, "GetThemeColor"));
48 get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
49 GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
50 get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
51 GetProcAddress(theme_dll_, "GetThemePartSize"));
52 open_theme_ = reinterpret_cast<OpenThemeDataPtr>(
53 GetProcAddress(theme_dll_, "OpenThemeData"));
54 close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
55 GetProcAddress(theme_dll_, "CloseThemeData"));
56 set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
57 GetProcAddress(theme_dll_, "SetThemeAppProperties"));
58 is_theme_active_ = reinterpret_cast<IsThemeActivePtr>(
59 GetProcAddress(theme_dll_, "IsThemeActive"));
60 get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
61 GetProcAddress(theme_dll_, "GetThemeInt"));
62 }
63 memset(theme_handles_, 0, sizeof(theme_handles_));
64}
65
66NativeTheme::~NativeTheme() {
67 if (theme_dll_) {
cpu@google.comc9f04cc2008-08-02 09:20:46 +090068 // todo (cpu): fix this soon.
69 // CloseHandles();
initial.commit3f4a7322008-07-27 06:49:38 +090070 FreeLibrary(theme_dll_);
71 }
72}
73
74HRESULT NativeTheme::PaintButton(HDC hdc,
75 int part_id,
76 int state_id,
77 int classic_state,
78 RECT* rect) const {
79 HANDLE handle = GetThemeHandle(BUTTON);
80 if (handle && draw_theme_)
81 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
82
83 // Draw it manually.
84 // All pressed states have both low bits set, and no other states do.
85 const bool focused = ((state_id & PBS_PRESSED) == PBS_PRESSED);
86 if ((part_id == BP_PUSHBUTTON) && focused) {
87 // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
88 // button itself is shrunk by 1 pixel.
89 HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
90 if (brush) {
91 FrameRect(hdc, rect, brush);
92 InflateRect(rect, -1, -1);
93 }
94 }
95
96 DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
97
98 // BP_RADIOBUTTON, BP_CHECKBOX, BP_GROUPBOX and BP_USERBUTTON have their
99 // focus drawn over the control.
100 if ((part_id != BP_PUSHBUTTON) && focused)
101 DrawFocusRect(hdc, rect);
102
103 return S_OK;
104}
105
106HRESULT NativeTheme::PaintTextField(HDC hdc,
107 int part_id,
108 int state_id,
109 int classic_state,
110 RECT* rect,
111 COLORREF color,
112 bool fill_content_area,
113 bool draw_edges) const {
114 // TODO(ojan): http://b/1210017 Figure out how to give the ability to
115 // exclude individual edges from being drawn.
116
117 HANDLE handle = GetThemeHandle(TEXTFIELD);
118 // TODO(mpcomplete): can we detect if the color is specified by the user,
119 // and if not, just use the system color?
120 // CreateSolidBrush() accepts a RGB value but alpha must be 0.
121 HBRUSH bg_brush = CreateSolidBrush(color);
122 HRESULT hr;
123 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
124 // draw_theme_ex_ is NULL and draw_theme_ is non-null.
125 if (handle && (draw_theme_ex_ || (draw_theme_ && draw_edges))) {
126 if (draw_theme_ex_) {
127 static DTBGOPTS omit_border_options = {
128 sizeof(DTBGOPTS),
129 DTBG_OMITBORDER,
130 {0,0,0,0}
131 };
132 DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options;
133 hr = draw_theme_ex_(handle, hdc, part_id, state_id, rect, draw_opts);
134 } else {
135 hr = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
136 }
137
138 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
139 if (fill_content_area && get_theme_content_rect_) {
140 RECT content_rect;
141 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
142 &content_rect);
143 FillRect(hdc, &content_rect, bg_brush);
144 }
145 } else {
146 // Draw it manually.
147 if (draw_edges)
148 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
149
150 if (fill_content_area) {
151 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
152 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
153 }
154 hr = S_OK;
155 }
156 DeleteObject(bg_brush);
157 return hr;
158}
159
160HRESULT NativeTheme::PaintMenuList(HDC hdc,
161 int part_id,
162 int state_id,
163 int classic_state,
164 RECT* rect) const {
165 HANDLE handle = GetThemeHandle(MENULIST);
166 if (handle && draw_theme_)
167 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
168
169 // Draw it manually.
170 DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | classic_state);
171 return S_OK;
172}
173
174HRESULT NativeTheme::PaintScrollbarArrow(HDC hdc,
175 int state_id,
176 int classic_state,
177 RECT* rect) const {
178 HANDLE handle = GetThemeHandle(SCROLLBAR);
179 if (handle && draw_theme_)
180 return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, rect, NULL);
181
182 // Draw it manually.
183 DrawFrameControl(hdc, rect, DFC_SCROLL, classic_state);
184 return S_OK;
185}
186
187HRESULT NativeTheme::PaintScrollbarTrack(HDC hdc,
188 int part_id,
189 int state_id,
190 int classic_state,
191 RECT* target_rect,
192 RECT* align_rect,
awalker@google.combce88e12008-08-15 02:47:00 +0900193 PlatformCanvasWin* canvas) const {
initial.commit3f4a7322008-07-27 06:49:38 +0900194 HANDLE handle = GetThemeHandle(SCROLLBAR);
195 if (handle && draw_theme_)
196 return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL);
197
198 // Draw it manually.
199 const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR);
200 const DWORD color3DFace = GetSysColor(COLOR_3DFACE);
201 if ((colorScrollbar != color3DFace) &&
202 (colorScrollbar != GetSysColor(COLOR_WINDOW))) {
203 FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
204 } else {
205 // Create a 2x2 checkerboard pattern using the 3D face and highlight
206 // colors.
207 SkColor face = COLORREFToSkColor(color3DFace);
208 SkColor highlight = COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT));
209 SkColor buffer[] = { face, highlight, highlight, face };
210 SkBitmap bitmap;
211 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
212 bitmap.setPixels(buffer);
213 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
214 SkShader::kRepeat_TileMode,
215 SkShader::kRepeat_TileMode);
216
217 // Draw that pattern into the target rect, setting the origin to the top
218 // left corner of the scrollbar track (so the checked rect below the thumb
219 // aligns properly with the portion above the thumb).
220 SkMatrix matrix;
221 matrix.setTranslate(SkIntToScalar(align_rect->left),
222 SkIntToScalar(align_rect->top));
223 shader->setLocalMatrix(matrix);
224 SkPaint paint;
225 paint.setShader(shader)->unref();
226 canvas->drawIRect(RECTToSkIRect(*target_rect), paint);
227 }
228 if (classic_state & DFCS_PUSHED)
229 InvertRect(hdc, target_rect);
230 return S_OK;
231}
232
233HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc,
234 int part_id,
235 int state_id,
236 int classic_state,
237 RECT* rect) const {
238 HANDLE handle = GetThemeHandle(SCROLLBAR);
239 if (handle && draw_theme_)
240 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
241
242 // Draw it manually.
243 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
244 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
245 // Classic mode doesn't have a gripper.
246 return S_OK;
247}
248
249HRESULT NativeTheme::PaintStatusGripper(HDC hdc,
250 int part_id,
251 int state_id,
252 int classic_state,
253 RECT* rect) const {
254 HANDLE handle = GetThemeHandle(STATUS);
255 if (handle && draw_theme_) {
256 // Paint the status bar gripper. There doesn't seem to be a
257 // standard gripper in Windows for the space between
258 // scrollbars. This is pretty close, but it's supposed to be
259 // painted over a status bar.
260 return draw_theme_(handle, hdc, SP_GRIPPER, 0, rect, 0);
261 }
262
263 // Draw a windows classic scrollbar gripper.
264 DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
265 return S_OK;
266}
267
268HRESULT NativeTheme::PaintDialogBackground(HDC hdc, bool active,
269 RECT* rect) const {
270 HANDLE handle = GetThemeHandle(WINDOW);
271 if (handle && draw_theme_) {
272 return draw_theme_(handle, hdc, WP_DIALOG,
273 active ? FS_ACTIVE : FS_INACTIVE, rect, NULL);
274 }
275
276 // Classic just renders a flat color background.
277 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
278 return S_OK;
279}
280
281HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const {
282 HANDLE handle = GetThemeHandle(TAB);
283 if (handle && draw_theme_)
284 return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL);
285
286 // Classic just renders a flat color background.
287 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
288 return S_OK;
289}
290
291HRESULT NativeTheme::PaintListBackground(HDC hdc,
292 bool enabled,
293 RECT* rect) const {
294 HANDLE handle = GetThemeHandle(LIST);
295 if (handle && draw_theme_)
296 return draw_theme_(handle, hdc, 1, TS_NORMAL, rect, NULL);
297
298 // Draw it manually.
299 HBRUSH bg_brush = GetSysColorBrush(COLOR_WINDOW);
300 FillRect(hdc, rect, bg_brush);
301 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
302 return S_OK;
303}
304
305bool NativeTheme::IsThemingActive() const {
306 if (is_theme_active_)
307 return !!is_theme_active_();
308 return false;
309}
310
311HRESULT NativeTheme::PaintMenuArrow(ThemeName theme,
312 HDC hdc,
313 int part_id,
314 int state_id,
315 RECT* rect,
316 MenuArrowDirection arrow_direction,
317 bool is_highlighted) const {
318 HANDLE handle = GetThemeHandle(MENU);
319 if (handle && draw_theme_) {
320 if (arrow_direction == RIGHT_POINTING_ARROW) {
321 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
322 } else {
323 // There is no way to tell the uxtheme API to draw a left pointing arrow;
324 // it doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they
325 // are needed for RTL locales on Vista. So use a memory DC and mirror
326 // the region with GDI's StretchBlt.
327 Rect r(*rect);
328 ScopedHDC mem_dc(CreateCompatibleDC(hdc));
329 ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
330 r.height()));
331 HGDIOBJ old_bitmap = SelectObject(mem_dc, mem_bitmap);
332 // Copy and horizontally mirror the background from hdc into mem_dc. Use
333 // a negative-width source rect, starting at the rightmost pixel.
334 StretchBlt(mem_dc, 0, 0, r.width(), r.height(),
335 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
336 // Draw the arrow.
337 RECT theme_rect = {0, 0, r.width(), r.height()};
338 HRESULT result = draw_theme_(handle, mem_dc, part_id,
339 state_id, &theme_rect, NULL);
340 // Copy and mirror the result back into mem_dc.
341 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
342 mem_dc, r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
343 SelectObject(mem_dc, old_bitmap);
344 return result;
345 }
346 }
347
348 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
349 // left pointing arrow. This makes the following 'if' statement slightly
350 // counterintuitive.
351 UINT state;
352 if (arrow_direction == RIGHT_POINTING_ARROW)
353 state = DFCS_MENUARROW;
354 else
355 state = DFCS_MENUARROWRIGHT;
356 return PaintFrameControl(hdc, rect, DFC_MENU, state, is_highlighted);
357}
358
359HRESULT NativeTheme::PaintMenuBackground(ThemeName theme,
360 HDC hdc,
361 int part_id,
362 int state_id,
363 RECT* rect) const {
364 HANDLE handle = GetThemeHandle(MENU);
365 if (handle && draw_theme_) {
366 HRESULT result = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
367 FrameRect(hdc, rect, GetSysColorBrush(COLOR_3DSHADOW));
368 return result;
369 }
370
371 FillRect(hdc, rect, GetSysColorBrush(COLOR_MENU));
372 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT);
373 return S_OK;
374}
375
376HRESULT NativeTheme::PaintMenuCheckBackground(ThemeName theme,
377 HDC hdc,
378 int part_id,
379 int state_id,
380 RECT* rect) const {
381 HANDLE handle = GetThemeHandle(MENU);
382 if (handle && draw_theme_)
383 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
384 // Nothing to do for background.
385 return S_OK;
386}
387
388HRESULT NativeTheme::PaintMenuCheck(ThemeName theme,
389 HDC hdc,
390 int part_id,
391 int state_id,
392 RECT* rect,
393 bool is_highlighted) const {
394 HANDLE handle = GetThemeHandle(MENU);
395 if (handle && draw_theme_) {
396 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
397 }
398 return PaintFrameControl(hdc, rect, DFC_MENU, DFCS_MENUCHECK, is_highlighted);
399}
400
401HRESULT NativeTheme::PaintMenuGutter(HDC hdc,
402 int part_id,
403 int state_id,
404 RECT* rect) const {
405 HANDLE handle = GetThemeHandle(MENU);
406 if (handle && draw_theme_)
407 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
408 return E_NOTIMPL;
409}
410
411HRESULT NativeTheme::PaintMenuSeparator(HDC hdc,
412 int part_id,
413 int state_id,
414 RECT* rect) const {
415 HANDLE handle = GetThemeHandle(MENU);
416 if (handle && draw_theme_)
417 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
418 DrawEdge(hdc, rect, EDGE_ETCHED, BF_TOP);
419 return S_OK;
420}
421
422HRESULT NativeTheme::PaintMenuItemBackground(ThemeName theme,
423 HDC hdc,
424 int part_id,
425 int state_id,
426 bool selected,
427 RECT* rect) const {
428 HANDLE handle = GetThemeHandle(MENU);
429 if (handle && draw_theme_)
430 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
431 if (selected)
432 FillRect(hdc, rect, GetSysColorBrush(COLOR_HIGHLIGHT));
433 return S_OK;
434}
435
436HRESULT NativeTheme::GetThemePartSize(ThemeName theme_name,
437 HDC hdc,
438 int part_id,
439 int state_id,
440 RECT* rect,
441 int ts,
442 SIZE* size) const {
443 HANDLE handle = GetThemeHandle(theme_name);
444 if (handle && get_theme_part_size_)
445 return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size);
446
447 return E_NOTIMPL;
448}
449
450HRESULT NativeTheme::GetThemeColor(ThemeName theme,
451 int part_id,
452 int state_id,
453 int prop_id,
454 SkColor* color) const {
455 HANDLE handle = GetThemeHandle(theme);
456 if (handle && get_theme_color_) {
457 COLORREF color_ref;
458 if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) ==
459 S_OK) {
460 *color = gfx::COLORREFToSkColor(color_ref);
461 return S_OK;
462 }
463 }
464 return E_NOTIMPL;
465}
466
467SkColor NativeTheme::GetThemeColorWithDefault(ThemeName theme,
468 int part_id,
469 int state_id,
470 int prop_id,
471 int default_sys_color) const {
472 SkColor color;
473 if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK)
474 color = gfx::COLORREFToSkColor(GetSysColor(default_sys_color));
475 return color;
476}
477
478HRESULT NativeTheme::GetThemeInt(ThemeName theme,
479 int part_id,
480 int state_id,
481 int prop_id,
482 int *value) const {
483 HANDLE handle = GetThemeHandle(theme);
484 if (handle && get_theme_int_)
485 return get_theme_int_(handle, part_id, state_id, prop_id, value);
486 return E_NOTIMPL;
487}
488
489Size NativeTheme::GetThemeBorderSize(ThemeName theme) const {
490 // For simplicity use the wildcard state==0, part==0, since it works
491 // for the cases we currently depend on.
492 int border;
493 if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK)
494 return Size(border, border);
495 else
496 return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
497}
498
499
500void NativeTheme::DisableTheming() const {
501 if (!set_theme_properties_)
502 return;
503 set_theme_properties_(0);
504}
505
506HRESULT NativeTheme::PaintFrameControl(HDC hdc,
507 RECT* rect,
508 UINT type,
509 UINT state,
510 bool is_highlighted) const {
511 const int width = rect->right - rect->left;
512 const int height = rect->bottom - rect->top;
513
514 // DrawFrameControl for menu arrow/check wants a monochrome bitmap.
515 ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
516
517 if (mask_bitmap == NULL)
518 return E_OUTOFMEMORY;
519
520 ScopedHDC bitmap_dc(CreateCompatibleDC(NULL));
521 HGDIOBJ org_bitmap = SelectObject(bitmap_dc, mask_bitmap);
522 RECT local_rect = { 0, 0, width, height };
523 DrawFrameControl(bitmap_dc, &local_rect, type, state);
524
525 // We're going to use BitBlt with a b&w mask. This results in using the dest
526 // dc's text color for the black bits in the mask, and the dest dc's
527 // background color for the white bits in the mask. DrawFrameControl draws the
528 // check in black, and the background in white.
529 COLORREF old_bg_color =
530 SetBkColor(hdc,
531 GetSysColor(is_highlighted ? COLOR_HIGHLIGHT : COLOR_MENU));
532 COLORREF old_text_color =
533 SetTextColor(hdc,
534 GetSysColor(is_highlighted ? COLOR_HIGHLIGHTTEXT :
535 COLOR_MENUTEXT));
536 BitBlt(hdc, rect->left, rect->top, width, height, bitmap_dc, 0, 0, SRCCOPY);
537 SetBkColor(hdc, old_bg_color);
538 SetTextColor(hdc, old_text_color);
539
540 SelectObject(bitmap_dc, org_bitmap);
541
542 return S_OK;
543}
544
545void NativeTheme::CloseHandles() const
546{
547 if (!close_theme_)
548 return;
549
550 for (int i = 0; i < LAST; ++i) {
551 if (theme_handles_[i])
552 close_theme_(theme_handles_[i]);
553 theme_handles_[i] = NULL;
554 }
555}
556
557HANDLE NativeTheme::GetThemeHandle(ThemeName theme_name) const
558{
559 if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
560 return 0;
561
562 if (theme_handles_[theme_name])
563 return theme_handles_[theme_name];
564
565 // Not found, try to load it.
566 HANDLE handle = 0;
567 switch (theme_name) {
568 case NativeTheme::BUTTON:
569 handle = open_theme_(NULL, L"Button");
570 break;
571 case NativeTheme::TEXTFIELD:
572 handle = open_theme_(NULL, L"Edit");
573 break;
574 case NativeTheme::MENULIST:
575 handle = open_theme_(NULL, L"Combobox");
576 break;
577 case NativeTheme::SCROLLBAR:
578 handle = open_theme_(NULL, L"Scrollbar");
579 break;
580 case NativeTheme::STATUS:
581 handle = open_theme_(NULL, L"Status");
582 break;
583 case NativeTheme::MENU:
584 handle = open_theme_(NULL, L"Menu");
585 break;
586 case NativeTheme::WINDOW:
587 handle = open_theme_(NULL, L"Window");
588 break;
589 case NativeTheme::TAB:
590 handle = open_theme_(NULL, L"Tab");
591 break;
592 case NativeTheme::LIST:
593 handle = open_theme_(NULL, L"Listview");
594 break;
595 default:
596 NOTREACHED();
597 }
598 theme_handles_[theme_name] = handle;
599 return handle;
600}
601
602} // namespace gfx
license.botf003cfe2008-08-24 09:55:55 +0900603