Revert of Merge duplicate code in invalidation helper. (patchset #2 id:40001 of https...
[chromium-blink-merge.git] / ui / native_theme / native_theme_win.cc
blob0ecfd5fac40f350b0f878703a1ef3821feb56df7
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 "ui/native_theme/native_theme_win.h"
7 #include <windows.h>
8 #include <uxtheme.h>
9 #include <vsstyle.h>
10 #include <vssym32.h>
12 #include "base/basictypes.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/win/scoped_gdi_object.h"
16 #include "base/win/scoped_hdc.h"
17 #include "base/win/scoped_select_object.h"
18 #include "base/win/windows_version.h"
19 #include "skia/ext/bitmap_platform_device.h"
20 #include "skia/ext/platform_canvas.h"
21 #include "skia/ext/skia_utils_win.h"
22 #include "third_party/skia/include/core/SkCanvas.h"
23 #include "third_party/skia/include/core/SkColor.h"
24 #include "third_party/skia/include/core/SkColorPriv.h"
25 #include "third_party/skia/include/core/SkShader.h"
26 #include "ui/base/resource/material_design/material_design_controller.h"
27 #include "ui/gfx/color_utils.h"
28 #include "ui/gfx/gdi_util.h"
29 #include "ui/gfx/geometry/rect.h"
30 #include "ui/gfx/geometry/rect_conversions.h"
31 #include "ui/gfx/win/dpi.h"
32 #include "ui/native_theme/common_theme.h"
34 // This was removed from Winvers.h but is still used.
35 #if !defined(COLOR_MENUHIGHLIGHT)
36 #define COLOR_MENUHIGHLIGHT 29
37 #endif
39 namespace {
41 // Windows system color IDs cached and updated by the native theme.
42 const int kSystemColors[] = {
43 COLOR_3DFACE,
44 COLOR_BTNTEXT,
45 COLOR_GRAYTEXT,
46 COLOR_HIGHLIGHT,
47 COLOR_HIGHLIGHTTEXT,
48 COLOR_SCROLLBAR,
49 COLOR_WINDOW,
50 COLOR_WINDOWTEXT,
51 COLOR_BTNFACE,
52 COLOR_MENUHIGHLIGHT,
55 void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) {
56 // Create a 2x2 checkerboard pattern using the 3D face and highlight colors.
57 const SkColor face = color_utils::GetSysSkColor(COLOR_3DFACE);
58 const SkColor highlight = color_utils::GetSysSkColor(COLOR_3DHILIGHT);
59 SkColor buffer[] = { face, highlight, highlight, face };
60 // Confusing bit: we first create a temporary bitmap with our desired pattern,
61 // then copy it to another bitmap. The temporary bitmap doesn't take
62 // ownership of the pixel data, and so will point to garbage when this
63 // function returns. The copy will copy the pixel data into a place owned by
64 // the bitmap, which is in turn owned by the shader, etc., so it will live
65 // until we're done using it.
66 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2);
67 SkBitmap temp_bitmap;
68 temp_bitmap.installPixels(info, buffer, info.minRowBytes());
69 SkBitmap bitmap;
70 temp_bitmap.copyTo(&bitmap);
72 // Align the pattern with the upper corner of |align_rect|.
73 SkMatrix local_matrix;
74 local_matrix.setTranslate(SkIntToScalar(align_rect.left),
75 SkIntToScalar(align_rect.top));
76 skia::RefPtr<SkShader> shader =
77 skia::AdoptRef(SkShader::CreateBitmapShader(bitmap,
78 SkShader::kRepeat_TileMode,
79 SkShader::kRepeat_TileMode,
80 &local_matrix));
81 paint->setShader(shader.get());
84 // <-a->
85 // [ ***** ]
86 // ____ | |
87 // <-a-> <------b----->
88 // a: object_width
89 // b: frame_width
90 // *: animating object
92 // - the animation goes from "[" to "]" repeatedly.
93 // - the animation offset is at first "|"
95 int ComputeAnimationProgress(int frame_width,
96 int object_width,
97 int pixels_per_second,
98 double animated_seconds) {
99 int animation_width = frame_width + object_width;
100 double interval = static_cast<double>(animation_width) / pixels_per_second;
101 double ratio = fmod(animated_seconds, interval) / interval;
102 return static_cast<int>(animation_width * ratio) - object_width;
105 RECT InsetRect(const RECT* rect, int size) {
106 gfx::Rect result(*rect);
107 result.Inset(size, size);
108 return result.ToRECT();
111 } // namespace
113 namespace ui {
115 bool NativeThemeWin::IsThemingActive() const {
116 return is_theme_active_ && is_theme_active_();
119 bool NativeThemeWin::IsUsingHighContrastTheme() const {
120 if (is_using_high_contrast_valid_)
121 return is_using_high_contrast_;
122 HIGHCONTRAST result;
123 result.cbSize = sizeof(HIGHCONTRAST);
124 is_using_high_contrast_ =
125 SystemParametersInfo(SPI_GETHIGHCONTRAST, result.cbSize, &result, 0) &&
126 (result.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON;
127 is_using_high_contrast_valid_ = true;
128 return is_using_high_contrast_;
131 HRESULT NativeThemeWin::GetThemeColor(ThemeName theme,
132 int part_id,
133 int state_id,
134 int prop_id,
135 SkColor* color) const {
136 HANDLE handle = GetThemeHandle(theme);
137 if (!handle || !get_theme_color_)
138 return E_NOTIMPL;
139 COLORREF color_ref;
140 if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) != S_OK)
141 return E_NOTIMPL;
142 *color = skia::COLORREFToSkColor(color_ref);
143 return S_OK;
146 SkColor NativeThemeWin::GetThemeColorWithDefault(ThemeName theme,
147 int part_id,
148 int state_id,
149 int prop_id,
150 int default_sys_color) const {
151 SkColor color;
152 return (GetThemeColor(theme, part_id, state_id, prop_id, &color) == S_OK) ?
153 color : color_utils::GetSysSkColor(default_sys_color);
156 gfx::Size NativeThemeWin::GetThemeBorderSize(ThemeName theme) const {
157 // For simplicity use the wildcard state==0, part==0, since it works
158 // for the cases we currently depend on.
159 int border;
160 return (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK) ?
161 gfx::Size(border, border) :
162 gfx::Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
165 void NativeThemeWin::DisableTheming() const {
166 if (set_theme_properties_)
167 set_theme_properties_(0);
170 void NativeThemeWin::CloseHandles() const {
171 if (!close_theme_)
172 return;
174 for (int i = 0; i < LAST; ++i) {
175 if (theme_handles_[i]) {
176 close_theme_(theme_handles_[i]);
177 theme_handles_[i] = NULL;
182 bool NativeThemeWin::IsClassicTheme(ThemeName name) const {
183 return !theme_dll_ || !GetThemeHandle(name);
186 // static
187 NativeThemeWin* NativeThemeWin::instance() {
188 CR_DEFINE_STATIC_LOCAL(NativeThemeWin, s_native_theme, ());
189 return &s_native_theme;
192 gfx::Size NativeThemeWin::GetPartSize(Part part,
193 State state,
194 const ExtraParams& extra) const {
195 gfx::Size part_size = CommonThemeGetPartSize(part, state, extra);
196 if (!part_size.IsEmpty())
197 return part_size;
199 // The GetThemePartSize call below returns the default size without
200 // accounting for user customization (crbug/218291).
201 switch (part) {
202 case kScrollbarDownArrow:
203 case kScrollbarLeftArrow:
204 case kScrollbarRightArrow:
205 case kScrollbarUpArrow:
206 case kScrollbarHorizontalThumb:
207 case kScrollbarVerticalThumb:
208 case kScrollbarHorizontalTrack:
209 case kScrollbarVerticalTrack: {
210 int size = gfx::win::GetSystemMetricsInDIP(SM_CXVSCROLL);
211 if (size == 0)
212 size = 17;
213 return gfx::Size(size, size);
215 default:
216 break;
219 int part_id = GetWindowsPart(part, state, extra);
220 int state_id = GetWindowsState(part, state, extra);
222 base::win::ScopedGetDC screen_dc(NULL);
223 SIZE size;
224 if (SUCCEEDED(GetThemePartSize(GetThemeName(part), screen_dc, part_id,
225 state_id, NULL, TS_TRUE, &size)))
226 return gfx::Size(size.cx, size.cy);
228 // TODO(rogerta): For now, we need to support radio buttons and checkboxes
229 // when theming is not enabled. Support for other parts can be added
230 // if/when needed.
231 return (part == kCheckbox || part == kRadio) ?
232 gfx::Size(13, 13) : gfx::Size();
235 void NativeThemeWin::Paint(SkCanvas* canvas,
236 Part part,
237 State state,
238 const gfx::Rect& rect,
239 const ExtraParams& extra) const {
240 if (rect.IsEmpty())
241 return;
243 switch (part) {
244 case kComboboxArrow:
245 CommonThemePaintComboboxArrow(canvas, rect);
246 return;
247 case kMenuPopupGutter:
248 CommonThemePaintMenuGutter(canvas, rect);
249 return;
250 case kMenuPopupSeparator:
251 CommonThemePaintMenuSeparator(canvas, rect);
252 return;
253 case kMenuPopupBackground:
254 CommonThemePaintMenuBackground(canvas, rect);
255 return;
256 case kMenuItemBackground:
257 CommonThemePaintMenuItemBackground(canvas, state, rect);
258 return;
259 default:
260 break;
263 bool needs_paint_indirect = false;
264 if (!skia::SupportsPlatformPaint(canvas)) {
265 // This block will only get hit with --enable-accelerated-drawing flag.
266 needs_paint_indirect = true;
267 } else {
268 // Scrollbar components on Windows Classic theme (on all Windows versions)
269 // have particularly problematic alpha values, so always draw them
270 // indirectly. In addition, scrollbar thumbs and grippers for the Windows XP
271 // theme (available only on Windows XP) also need their alpha values
272 // fixed.
273 switch (part) {
274 case kScrollbarDownArrow:
275 case kScrollbarUpArrow:
276 case kScrollbarLeftArrow:
277 case kScrollbarRightArrow:
278 needs_paint_indirect = !GetThemeHandle(SCROLLBAR);
279 break;
280 case kScrollbarHorizontalThumb:
281 case kScrollbarVerticalThumb:
282 case kScrollbarHorizontalGripper:
283 case kScrollbarVerticalGripper:
284 needs_paint_indirect = !GetThemeHandle(SCROLLBAR) ||
285 base::win::GetVersion() == base::win::VERSION_XP;
286 break;
287 default:
288 break;
292 if (needs_paint_indirect)
293 PaintIndirect(canvas, part, state, rect, extra);
294 else
295 PaintDirect(canvas, part, state, rect, extra);
298 NativeThemeWin::NativeThemeWin()
299 : draw_theme_(NULL),
300 draw_theme_ex_(NULL),
301 get_theme_color_(NULL),
302 get_theme_content_rect_(NULL),
303 get_theme_part_size_(NULL),
304 open_theme_(NULL),
305 close_theme_(NULL),
306 set_theme_properties_(NULL),
307 is_theme_active_(NULL),
308 get_theme_int_(NULL),
309 theme_dll_(LoadLibrary(L"uxtheme.dll")),
310 color_change_listener_(this),
311 is_using_high_contrast_(false),
312 is_using_high_contrast_valid_(false) {
313 if (theme_dll_) {
314 draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
315 GetProcAddress(theme_dll_, "DrawThemeBackground"));
316 draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
317 GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
318 get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
319 GetProcAddress(theme_dll_, "GetThemeColor"));
320 get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
321 GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
322 get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
323 GetProcAddress(theme_dll_, "GetThemePartSize"));
324 open_theme_ = reinterpret_cast<OpenThemeDataPtr>(
325 GetProcAddress(theme_dll_, "OpenThemeData"));
326 close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
327 GetProcAddress(theme_dll_, "CloseThemeData"));
328 set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
329 GetProcAddress(theme_dll_, "SetThemeAppProperties"));
330 is_theme_active_ = reinterpret_cast<IsThemeActivePtr>(
331 GetProcAddress(theme_dll_, "IsThemeActive"));
332 get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
333 GetProcAddress(theme_dll_, "GetThemeInt"));
335 memset(theme_handles_, 0, sizeof(theme_handles_));
337 // Initialize the cached system colors.
338 UpdateSystemColors();
341 NativeThemeWin::~NativeThemeWin() {
342 if (theme_dll_) {
343 // todo (cpu): fix this soon. Making a call to CloseHandles() here breaks
344 // certain tests and the reliability bots.
345 // CloseHandles();
346 FreeLibrary(theme_dll_);
350 void NativeThemeWin::OnSysColorChange() {
351 UpdateSystemColors();
352 is_using_high_contrast_valid_ = false;
353 NotifyObservers();
356 void NativeThemeWin::UpdateSystemColors() {
357 for (int i = 0; i < arraysize(kSystemColors); ++i) {
358 system_colors_[kSystemColors[i]] =
359 color_utils::GetSysSkColor(kSystemColors[i]);
363 void NativeThemeWin::PaintDirect(SkCanvas* canvas,
364 Part part,
365 State state,
366 const gfx::Rect& rect,
367 const ExtraParams& extra) const {
368 skia::ScopedPlatformPaint scoped_platform_paint(canvas);
369 HDC hdc = scoped_platform_paint.GetPlatformSurface();
371 switch (part) {
372 case kCheckbox:
373 PaintCheckbox(hdc, part, state, rect, extra.button);
374 return;
375 case kInnerSpinButton:
376 PaintSpinButton(hdc, part, state, rect, extra.inner_spin);
377 return;
378 case kMenuList:
379 PaintMenuList(hdc, state, rect, extra.menu_list);
380 return;
381 case kMenuCheck:
382 PaintMenuCheck(hdc, state, rect, extra.menu_check);
383 return;
384 case kMenuCheckBackground:
385 PaintMenuCheckBackground(hdc, state, rect);
386 return;
387 case kMenuPopupArrow:
388 PaintMenuArrow(hdc, state, rect, extra.menu_arrow);
389 return;
390 case kMenuPopupBackground:
391 PaintMenuBackground(hdc, rect);
392 return;
393 case kMenuPopupGutter:
394 PaintMenuGutter(hdc, rect);
395 return;
396 case kMenuPopupSeparator:
397 PaintMenuSeparator(hdc, rect);
398 return;
399 case kMenuItemBackground:
400 PaintMenuItemBackground(hdc, state, rect, extra.menu_item);
401 return;
402 case kProgressBar:
403 PaintProgressBar(hdc, rect, extra.progress_bar);
404 return;
405 case kPushButton:
406 PaintPushButton(hdc, part, state, rect, extra.button);
407 return;
408 case kRadio:
409 PaintRadioButton(hdc, part, state, rect, extra.button);
410 return;
411 case kScrollbarDownArrow:
412 case kScrollbarUpArrow:
413 case kScrollbarLeftArrow:
414 case kScrollbarRightArrow:
415 PaintScrollbarArrow(hdc, part, state, rect, extra.scrollbar_arrow);
416 return;
417 case kScrollbarHorizontalThumb:
418 case kScrollbarVerticalThumb:
419 case kScrollbarHorizontalGripper:
420 case kScrollbarVerticalGripper:
421 PaintScrollbarThumb(hdc, part, state, rect, extra.scrollbar_thumb);
422 return;
423 case kScrollbarHorizontalTrack:
424 case kScrollbarVerticalTrack:
425 PaintScrollbarTrack(canvas, hdc, part, state, rect,
426 extra.scrollbar_track);
427 return;
428 case kScrollbarCorner:
429 canvas->drawColor(SK_ColorWHITE, SkXfermode::kSrc_Mode);
430 return;
431 case kTabPanelBackground:
432 PaintTabPanelBackground(hdc, rect);
433 return;
434 case kTextField:
435 PaintTextField(hdc, part, state, rect, extra.text_field);
436 return;
437 case kTrackbarThumb:
438 case kTrackbarTrack:
439 PaintTrackbar(canvas, hdc, part, state, rect, extra.trackbar);
440 return;
441 case kWindowResizeGripper:
442 PaintWindowResizeGripper(hdc, rect);
443 return;
444 case kComboboxArrow:
445 case kSliderTrack:
446 case kSliderThumb:
447 case kMaxPart:
448 NOTREACHED();
452 SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
453 SkColor color;
454 if (CommonThemeGetSystemColor(color_id, &color))
455 return color;
457 // TODO: Obtain the correct colors using GetSysColor.
458 const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
459 const SkColor kUrlTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
460 // Dialogs:
461 const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251);
462 // FocusableBorder:
463 const SkColor kFocusedBorderColor = SkColorSetRGB(0x4d, 0x90, 0xfe);
464 const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xd9, 0xd9, 0xd9);
465 // Button:
466 const SkColor kButtonBackgroundColor = SkColorSetRGB(0xde, 0xde, 0xde);
467 const SkColor kButtonHighlightColor = SkColorSetARGB(200, 255, 255, 255);
468 const SkColor kButtonHoverColor = SkColorSetRGB(6, 45, 117);
469 const SkColor kButtonHoverBackgroundColor = SkColorSetRGB(0xEA, 0xEA, 0xEA);
470 // MenuItem:
471 const SkColor kEnabledMenuItemForegroundColor = SkColorSetRGB(6, 45, 117);
472 const SkColor kDisabledMenuItemForegroundColor = SkColorSetRGB(161, 161, 146);
473 const SkColor kFocusedMenuItemBackgroundColor = SkColorSetRGB(246, 249, 253);
474 const SkColor kMenuSeparatorColor = SkColorSetARGB(50, 0, 0, 0);
475 // Table:
476 const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
477 const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29);
479 switch (color_id) {
480 // Windows
481 case kColorId_WindowBackground:
482 return system_colors_[COLOR_WINDOW];
484 // Dialogs
485 case kColorId_DialogBackground:
486 return color_utils::IsInvertedColorScheme() ?
487 color_utils::InvertColor(kDialogBackgroundColor) :
488 kDialogBackgroundColor;
490 // FocusableBorder
491 case kColorId_FocusedBorderColor:
492 return kFocusedBorderColor;
493 case kColorId_UnfocusedBorderColor:
494 return kUnfocusedBorderColor;
496 // Button
497 case kColorId_ButtonBackgroundColor:
498 return kButtonBackgroundColor;
499 case kColorId_ButtonEnabledColor:
500 return system_colors_[COLOR_BTNTEXT];
501 case kColorId_ButtonDisabledColor:
502 return system_colors_[COLOR_GRAYTEXT];
503 case kColorId_ButtonHighlightColor:
504 return kButtonHighlightColor;
505 case kColorId_ButtonHoverColor:
506 return kButtonHoverColor;
507 case kColorId_ButtonHoverBackgroundColor:
508 return kButtonHoverBackgroundColor;
509 case kColorId_BlueButtonEnabledColor:
510 case kColorId_BlueButtonDisabledColor:
511 case kColorId_BlueButtonPressedColor:
512 case kColorId_BlueButtonHoverColor:
513 NOTREACHED();
514 return kInvalidColorIdColor;
516 // MenuItem
517 case kColorId_EnabledMenuItemForegroundColor:
518 return kEnabledMenuItemForegroundColor;
519 case kColorId_DisabledMenuItemForegroundColor:
520 return kDisabledMenuItemForegroundColor;
521 case kColorId_DisabledEmphasizedMenuItemForegroundColor:
522 return SK_ColorBLACK;
523 case kColorId_FocusedMenuItemBackgroundColor:
524 return kFocusedMenuItemBackgroundColor;
525 case kColorId_MenuSeparatorColor:
526 return kMenuSeparatorColor;
527 case kColorId_SelectedMenuItemForegroundColor:
528 case kColorId_HoverMenuItemBackgroundColor:
529 case kColorId_MenuBackgroundColor:
530 case kColorId_MenuBorderColor:
531 NOTREACHED();
532 return kInvalidColorIdColor;
534 // MenuButton
535 case kColorId_EnabledMenuButtonBorderColor:
536 case kColorId_FocusedMenuButtonBorderColor:
537 case kColorId_HoverMenuButtonBorderColor:
538 NOTREACHED();
539 return kInvalidColorIdColor;
541 // Label
542 case kColorId_LabelEnabledColor:
543 return system_colors_[COLOR_BTNTEXT];
544 case kColorId_LabelDisabledColor:
545 return system_colors_[COLOR_GRAYTEXT];
546 case kColorId_LabelBackgroundColor:
547 return system_colors_[COLOR_WINDOW];
549 // Link
550 case kColorId_LinkDisabled:
551 return system_colors_[COLOR_WINDOWTEXT];
552 case kColorId_LinkEnabled:
553 return system_colors_[COLOR_HOTLIGHT];
554 case kColorId_LinkPressed:
555 return SkColorSetRGB(200, 0, 0);
557 // Textfield
558 case kColorId_TextfieldDefaultColor:
559 return system_colors_[COLOR_WINDOWTEXT];
560 case kColorId_TextfieldDefaultBackground:
561 return system_colors_[COLOR_WINDOW];
562 case kColorId_TextfieldReadOnlyColor:
563 return system_colors_[COLOR_GRAYTEXT];
564 case kColorId_TextfieldReadOnlyBackground:
565 return system_colors_[COLOR_3DFACE];
566 case kColorId_TextfieldSelectionColor:
567 return system_colors_[COLOR_HIGHLIGHTTEXT];
568 case kColorId_TextfieldSelectionBackgroundFocused:
569 return system_colors_[COLOR_HIGHLIGHT];
571 // Tooltip
572 case kColorId_TooltipBackground:
573 case kColorId_TooltipText:
574 NOTREACHED();
575 return kInvalidColorIdColor;
577 // Tree
578 // NOTE: these aren't right for all themes, but as close as I could get.
579 case kColorId_TreeBackground:
580 return system_colors_[COLOR_WINDOW];
581 case kColorId_TreeText:
582 return system_colors_[COLOR_WINDOWTEXT];
583 case kColorId_TreeSelectedText:
584 return system_colors_[COLOR_HIGHLIGHTTEXT];
585 case kColorId_TreeSelectedTextUnfocused:
586 return system_colors_[COLOR_BTNTEXT];
587 case kColorId_TreeSelectionBackgroundFocused:
588 return system_colors_[COLOR_HIGHLIGHT];
589 case kColorId_TreeSelectionBackgroundUnfocused:
590 return system_colors_[IsUsingHighContrastTheme() ?
591 COLOR_MENUHIGHLIGHT : COLOR_BTNFACE];
592 case kColorId_TreeArrow:
593 return system_colors_[COLOR_WINDOWTEXT];
595 // Table
596 case kColorId_TableBackground:
597 return system_colors_[COLOR_WINDOW];
598 case kColorId_TableText:
599 return system_colors_[COLOR_WINDOWTEXT];
600 case kColorId_TableSelectedText:
601 return system_colors_[COLOR_HIGHLIGHTTEXT];
602 case kColorId_TableSelectedTextUnfocused:
603 return system_colors_[COLOR_BTNTEXT];
604 case kColorId_TableSelectionBackgroundFocused:
605 return system_colors_[COLOR_HIGHLIGHT];
606 case kColorId_TableSelectionBackgroundUnfocused:
607 return system_colors_[IsUsingHighContrastTheme() ?
608 COLOR_MENUHIGHLIGHT : COLOR_BTNFACE];
609 case kColorId_TableGroupingIndicatorColor:
610 return system_colors_[COLOR_GRAYTEXT];
612 // Results Tables
613 case kColorId_ResultsTableNormalBackground:
614 return system_colors_[COLOR_WINDOW];
615 case kColorId_ResultsTableHoveredBackground:
616 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHT],
617 system_colors_[COLOR_WINDOW], 0x40);
618 case kColorId_ResultsTableSelectedBackground:
619 return system_colors_[COLOR_HIGHLIGHT];
620 case kColorId_ResultsTableNormalText:
621 return system_colors_[COLOR_WINDOWTEXT];
622 case kColorId_ResultsTableHoveredText:
623 return color_utils::GetReadableColor(
624 system_colors_[COLOR_WINDOWTEXT],
625 GetSystemColor(kColorId_ResultsTableHoveredBackground));
626 case kColorId_ResultsTableSelectedText:
627 return system_colors_[COLOR_HIGHLIGHTTEXT];
628 case kColorId_ResultsTableNormalDimmedText:
629 return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
630 system_colors_[COLOR_WINDOW], 0x80);
631 case kColorId_ResultsTableHoveredDimmedText:
632 return color_utils::AlphaBlend(
633 system_colors_[COLOR_WINDOWTEXT],
634 GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x80);
635 case kColorId_ResultsTableSelectedDimmedText:
636 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
637 system_colors_[COLOR_HIGHLIGHT], 0x80);
638 case kColorId_ResultsTableNormalUrl:
639 return color_utils::GetReadableColor(kUrlTextColor,
640 system_colors_[COLOR_WINDOW]);
641 case kColorId_ResultsTableHoveredUrl:
642 return color_utils::GetReadableColor(
643 kUrlTextColor,
644 GetSystemColor(kColorId_ResultsTableHoveredBackground));
645 case kColorId_ResultsTableSelectedUrl:
646 return color_utils::GetReadableColor(kUrlTextColor,
647 system_colors_[COLOR_HIGHLIGHT]);
648 case kColorId_ResultsTableNormalDivider:
649 return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
650 system_colors_[COLOR_WINDOW], 0x34);
651 case kColorId_ResultsTableHoveredDivider:
652 return color_utils::AlphaBlend(
653 system_colors_[COLOR_WINDOWTEXT],
654 GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x34);
655 case kColorId_ResultsTableSelectedDivider:
656 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
657 system_colors_[COLOR_HIGHLIGHT], 0x34);
658 case kColorId_ResultsTablePositiveText:
659 return color_utils::GetReadableColor(kPositiveTextColor,
660 system_colors_[COLOR_WINDOW]);
661 case kColorId_ResultsTablePositiveHoveredText:
662 return color_utils::GetReadableColor(
663 kPositiveTextColor,
664 GetSystemColor(kColorId_ResultsTableHoveredBackground));
665 case kColorId_ResultsTablePositiveSelectedText:
666 return color_utils::GetReadableColor(kPositiveTextColor,
667 system_colors_[COLOR_HIGHLIGHT]);
668 case kColorId_ResultsTableNegativeText:
669 return color_utils::GetReadableColor(kNegativeTextColor,
670 system_colors_[COLOR_WINDOW]);
671 case kColorId_ResultsTableNegativeHoveredText:
672 return color_utils::GetReadableColor(
673 kNegativeTextColor,
674 GetSystemColor(kColorId_ResultsTableHoveredBackground));
675 case kColorId_ResultsTableNegativeSelectedText:
676 return color_utils::GetReadableColor(kNegativeTextColor,
677 system_colors_[COLOR_HIGHLIGHT]);
678 default:
679 NOTREACHED();
680 return kInvalidColorIdColor;
684 void NativeThemeWin::PaintIndirect(SkCanvas* canvas,
685 Part part,
686 State state,
687 const gfx::Rect& rect,
688 const ExtraParams& extra) const {
689 // TODO(asvitkine): This path is pretty inefficient - for each paint operation
690 // it creates a new offscreen bitmap Skia canvas. This can
691 // be sped up by doing it only once per part/state and
692 // keeping a cache of the resulting bitmaps.
694 // Create an offscreen canvas that is backed by an HDC.
695 skia::RefPtr<skia::BitmapPlatformDevice> device = skia::AdoptRef(
696 skia::BitmapPlatformDevice::Create(
697 rect.width(), rect.height(), false, NULL));
698 DCHECK(device);
699 SkCanvas offscreen_canvas(device.get());
700 DCHECK(skia::SupportsPlatformPaint(&offscreen_canvas));
702 // Some of the Windows theme drawing operations do not write correct alpha
703 // values for fully-opaque pixels; instead the pixels get alpha 0. This is
704 // especially a problem on Windows XP or when using the Classic theme.
706 // To work-around this, mark all pixels with a placeholder value, to detect
707 // which pixels get touched by the paint operation. After paint, set any
708 // pixels that have alpha 0 to opaque and placeholders to fully-transparent.
709 const SkColor placeholder = SkColorSetARGB(1, 0, 0, 0);
710 offscreen_canvas.clear(placeholder);
712 // Offset destination rects to have origin (0,0).
713 gfx::Rect adjusted_rect(rect.size());
714 ExtraParams adjusted_extra(extra);
715 switch (part) {
716 case kProgressBar:
717 adjusted_extra.progress_bar.value_rect_x = 0;
718 adjusted_extra.progress_bar.value_rect_y = 0;
719 break;
720 case kScrollbarHorizontalTrack:
721 case kScrollbarVerticalTrack:
722 adjusted_extra.scrollbar_track.track_x = 0;
723 adjusted_extra.scrollbar_track.track_y = 0;
724 break;
725 default:
726 break;
728 // Draw the theme controls using existing HDC-drawing code.
729 PaintDirect(&offscreen_canvas, part, state, adjusted_rect, adjusted_extra);
731 // Copy the pixels to a bitmap that has ref-counted pixel storage, which is
732 // necessary to have when drawing to a SkPicture.
733 const SkBitmap& hdc_bitmap =
734 offscreen_canvas.getDevice()->accessBitmap(false);
735 SkBitmap bitmap;
736 hdc_bitmap.copyTo(&bitmap, kN32_SkColorType);
738 // Post-process the pixels to fix up the alpha values (see big comment above).
739 const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder);
740 const int pixel_count = rect.width() * rect.height();
741 SkPMColor* pixels = bitmap.getAddr32(0, 0);
742 for (int i = 0; i < pixel_count; i++) {
743 if (pixels[i] == placeholder_value) {
744 // Pixel wasn't touched - make it fully transparent.
745 pixels[i] = SkPackARGB32(0, 0, 0, 0);
746 } else if (SkGetPackedA32(pixels[i]) == 0) {
747 // Pixel was touched but has incorrect alpha of 0, make it fully opaque.
748 pixels[i] = SkPackARGB32(0xFF,
749 SkGetPackedR32(pixels[i]),
750 SkGetPackedG32(pixels[i]),
751 SkGetPackedB32(pixels[i]));
755 // Draw the offscreen bitmap to the destination canvas.
756 canvas->drawBitmap(bitmap, rect.x(), rect.y());
759 HRESULT NativeThemeWin::GetThemePartSize(ThemeName theme_name,
760 HDC hdc,
761 int part_id,
762 int state_id,
763 RECT* rect,
764 int ts,
765 SIZE* size) const {
766 HANDLE handle = GetThemeHandle(theme_name);
767 return (handle && get_theme_part_size_) ?
768 get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size) :
769 E_NOTIMPL;
772 HRESULT NativeThemeWin::PaintButton(HDC hdc,
773 State state,
774 const ButtonExtraParams& extra,
775 int part_id,
776 int state_id,
777 RECT* rect) const {
778 HANDLE handle = GetThemeHandle(BUTTON);
779 if (handle && draw_theme_)
780 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
782 // Adjust classic_state based on part, state, and extras.
783 int classic_state = extra.classic_state;
784 switch (part_id) {
785 case BP_CHECKBOX:
786 classic_state |= DFCS_BUTTONCHECK;
787 break;
788 case BP_RADIOBUTTON:
789 classic_state |= DFCS_BUTTONRADIO;
790 break;
791 case BP_PUSHBUTTON:
792 classic_state |= DFCS_BUTTONPUSH;
793 break;
794 default:
795 NOTREACHED();
796 break;
799 switch (state) {
800 case kDisabled:
801 classic_state |= DFCS_INACTIVE;
802 break;
803 case kHovered:
804 case kNormal:
805 break;
806 case kPressed:
807 classic_state |= DFCS_PUSHED;
808 break;
809 case kNumStates:
810 NOTREACHED();
811 break;
814 if (extra.checked)
815 classic_state |= DFCS_CHECKED;
817 // Draw it manually.
818 // All pressed states have both low bits set, and no other states do.
819 const bool focused = ((state_id & ETS_FOCUSED) == ETS_FOCUSED);
820 const bool pressed = ((state_id & PBS_PRESSED) == PBS_PRESSED);
821 if ((BP_PUSHBUTTON == part_id) && (pressed || focused)) {
822 // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
823 // button itself is shrunk by 1 pixel.
824 HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
825 if (brush) {
826 FrameRect(hdc, rect, brush);
827 InflateRect(rect, -1, -1);
830 DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
832 // Draw the focus rectangle (the dotted line box) only on buttons. For radio
833 // and checkboxes, we let webkit draw the focus rectangle (orange glow).
834 if ((BP_PUSHBUTTON == part_id) && focused) {
835 // The focus rect is inside the button. The exact number of pixels depends
836 // on whether we're in classic mode or using uxtheme.
837 if (handle && get_theme_content_rect_) {
838 get_theme_content_rect_(handle, hdc, part_id, state_id, rect, rect);
839 } else {
840 InflateRect(rect, -GetSystemMetrics(SM_CXEDGE),
841 -GetSystemMetrics(SM_CYEDGE));
843 DrawFocusRect(hdc, rect);
846 // Classic theme doesn't support indeterminate checkboxes. We draw
847 // a recangle inside a checkbox like IE10 does.
848 if (part_id == BP_CHECKBOX && extra.indeterminate) {
849 RECT inner_rect = *rect;
850 // "4 / 13" is same as IE10 in classic theme.
851 int padding = (inner_rect.right - inner_rect.left) * 4 / 13;
852 InflateRect(&inner_rect, -padding, -padding);
853 int color_index = state == kDisabled ? COLOR_GRAYTEXT : COLOR_WINDOWTEXT;
854 FillRect(hdc, &inner_rect, GetSysColorBrush(color_index));
857 return S_OK;
860 HRESULT NativeThemeWin::PaintMenuSeparator(
861 HDC hdc,
862 const gfx::Rect& rect) const {
863 RECT rect_win = rect.ToRECT();
865 HANDLE handle = GetThemeHandle(MENU);
866 if (handle && draw_theme_) {
867 // Delta is needed for non-classic to move separator up slightly.
868 --rect_win.top;
869 --rect_win.bottom;
870 return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win,
871 NULL);
874 DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP);
875 return S_OK;
878 HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc,
879 const gfx::Rect& rect) const {
880 RECT rect_win = rect.ToRECT();
881 HANDLE handle = GetThemeHandle(MENU);
882 return (handle && draw_theme_) ?
883 draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, NULL) :
884 E_NOTIMPL;
887 HRESULT NativeThemeWin::PaintMenuArrow(
888 HDC hdc,
889 State state,
890 const gfx::Rect& rect,
891 const MenuArrowExtraParams& extra) const {
892 int state_id = MSM_NORMAL;
893 if (state == kDisabled)
894 state_id = MSM_DISABLED;
896 HANDLE handle = GetThemeHandle(MENU);
897 RECT rect_win = rect.ToRECT();
898 if (handle && draw_theme_) {
899 if (extra.pointing_right) {
900 return draw_theme_(handle, hdc, MENU_POPUPSUBMENU, state_id, &rect_win,
901 NULL);
903 // There is no way to tell the uxtheme API to draw a left pointing arrow; it
904 // doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they are
905 // needed for RTL locales on Vista. So use a memory DC and mirror the
906 // region with GDI's StretchBlt.
907 gfx::Rect r(rect);
908 base::win::ScopedCreateDC mem_dc(CreateCompatibleDC(hdc));
909 base::win::ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
910 r.height()));
911 base::win::ScopedSelectObject select_bitmap(mem_dc.Get(), mem_bitmap);
912 // Copy and horizontally mirror the background from hdc into mem_dc. Use
913 // a negative-width source rect, starting at the rightmost pixel.
914 StretchBlt(mem_dc.Get(), 0, 0, r.width(), r.height(),
915 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
916 // Draw the arrow.
917 RECT theme_rect = {0, 0, r.width(), r.height()};
918 HRESULT result = draw_theme_(handle, mem_dc.Get(), MENU_POPUPSUBMENU,
919 state_id, &theme_rect, NULL);
920 // Copy and mirror the result back into mem_dc.
921 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
922 mem_dc.Get(), r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
923 return result;
926 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
927 // left pointing arrow. This makes the following statement counterintuitive.
928 UINT pfc_state = extra.pointing_right ? DFCS_MENUARROW : DFCS_MENUARROWRIGHT;
929 return PaintFrameControl(hdc, rect, DFC_MENU, pfc_state, extra.is_selected,
930 state);
933 HRESULT NativeThemeWin::PaintMenuBackground(HDC hdc,
934 const gfx::Rect& rect) const {
935 HANDLE handle = GetThemeHandle(MENU);
936 RECT rect_win = rect.ToRECT();
937 if (handle && draw_theme_) {
938 HRESULT result = draw_theme_(handle, hdc, MENU_POPUPBACKGROUND, 0,
939 &rect_win, NULL);
940 FrameRect(hdc, &rect_win, GetSysColorBrush(COLOR_3DSHADOW));
941 return result;
944 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_MENU));
945 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT);
946 return S_OK;
949 HRESULT NativeThemeWin::PaintMenuCheck(
950 HDC hdc,
951 State state,
952 const gfx::Rect& rect,
953 const MenuCheckExtraParams& extra) const {
954 HANDLE handle = GetThemeHandle(MENU);
955 if (handle && draw_theme_) {
956 const int state_id = extra.is_radio ?
957 ((state == kDisabled) ? MC_BULLETDISABLED : MC_BULLETNORMAL) :
958 ((state == kDisabled) ? MC_CHECKMARKDISABLED : MC_CHECKMARKNORMAL);
959 RECT rect_win = rect.ToRECT();
960 return draw_theme_(handle, hdc, MENU_POPUPCHECK, state_id, &rect_win, NULL);
963 return PaintFrameControl(hdc, rect, DFC_MENU,
964 extra.is_radio ? DFCS_MENUBULLET : DFCS_MENUCHECK,
965 extra.is_selected, state);
968 HRESULT NativeThemeWin::PaintMenuCheckBackground(HDC hdc,
969 State state,
970 const gfx::Rect& rect) const {
971 HANDLE handle = GetThemeHandle(MENU);
972 if (!handle || !draw_theme_)
973 return S_OK; // Nothing to do for background.
975 int state_id = state == kDisabled ? MCB_DISABLED : MCB_NORMAL;
976 RECT rect_win = rect.ToRECT();
977 return draw_theme_(handle, hdc, MENU_POPUPCHECKBACKGROUND, state_id,
978 &rect_win, NULL);
981 HRESULT NativeThemeWin::PaintMenuItemBackground(
982 HDC hdc,
983 State state,
984 const gfx::Rect& rect,
985 const MenuItemExtraParams& extra) const {
986 HANDLE handle = GetThemeHandle(MENU);
987 RECT rect_win = rect.ToRECT();
988 int state_id = MPI_NORMAL;
989 switch (state) {
990 case kDisabled:
991 state_id = extra.is_selected ? MPI_DISABLEDHOT : MPI_DISABLED;
992 break;
993 case kHovered:
994 state_id = MPI_HOT;
995 break;
996 case kNormal:
997 break;
998 case kPressed:
999 case kNumStates:
1000 NOTREACHED();
1001 break;
1004 if (handle && draw_theme_)
1005 return draw_theme_(handle, hdc, MENU_POPUPITEM, state_id, &rect_win, NULL);
1007 if (extra.is_selected)
1008 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_HIGHLIGHT));
1009 return S_OK;
1012 HRESULT NativeThemeWin::PaintPushButton(HDC hdc,
1013 Part part,
1014 State state,
1015 const gfx::Rect& rect,
1016 const ButtonExtraParams& extra) const {
1017 int state_id = extra.is_default ? PBS_DEFAULTED : PBS_NORMAL;
1018 switch (state) {
1019 case kDisabled:
1020 state_id = PBS_DISABLED;
1021 break;
1022 case kHovered:
1023 state_id = PBS_HOT;
1024 break;
1025 case kNormal:
1026 break;
1027 case kPressed:
1028 state_id = PBS_PRESSED;
1029 break;
1030 case kNumStates:
1031 NOTREACHED();
1032 break;
1035 RECT rect_win = rect.ToRECT();
1036 return PaintButton(hdc, state, extra, BP_PUSHBUTTON, state_id, &rect_win);
1039 HRESULT NativeThemeWin::PaintRadioButton(HDC hdc,
1040 Part part,
1041 State state,
1042 const gfx::Rect& rect,
1043 const ButtonExtraParams& extra) const {
1044 int state_id = extra.checked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
1045 switch (state) {
1046 case kDisabled:
1047 state_id = extra.checked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
1048 break;
1049 case kHovered:
1050 state_id = extra.checked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
1051 break;
1052 case kNormal:
1053 break;
1054 case kPressed:
1055 state_id = extra.checked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
1056 break;
1057 case kNumStates:
1058 NOTREACHED();
1059 break;
1062 RECT rect_win = rect.ToRECT();
1063 return PaintButton(hdc, state, extra, BP_RADIOBUTTON, state_id, &rect_win);
1066 HRESULT NativeThemeWin::PaintCheckbox(HDC hdc,
1067 Part part,
1068 State state,
1069 const gfx::Rect& rect,
1070 const ButtonExtraParams& extra) const {
1071 int state_id = extra.checked ?
1072 CBS_CHECKEDNORMAL :
1073 (extra.indeterminate ? CBS_MIXEDNORMAL : CBS_UNCHECKEDNORMAL);
1074 switch (state) {
1075 case kDisabled:
1076 state_id = extra.checked ?
1077 CBS_CHECKEDDISABLED :
1078 (extra.indeterminate ? CBS_MIXEDDISABLED : CBS_UNCHECKEDDISABLED);
1079 break;
1080 case kHovered:
1081 state_id = extra.checked ?
1082 CBS_CHECKEDHOT :
1083 (extra.indeterminate ? CBS_MIXEDHOT : CBS_UNCHECKEDHOT);
1084 break;
1085 case kNormal:
1086 break;
1087 case kPressed:
1088 state_id = extra.checked ?
1089 CBS_CHECKEDPRESSED :
1090 (extra.indeterminate ? CBS_MIXEDPRESSED : CBS_UNCHECKEDPRESSED);
1091 break;
1092 case kNumStates:
1093 NOTREACHED();
1094 break;
1097 RECT rect_win = rect.ToRECT();
1098 return PaintButton(hdc, state, extra, BP_CHECKBOX, state_id, &rect_win);
1101 HRESULT NativeThemeWin::PaintMenuList(HDC hdc,
1102 State state,
1103 const gfx::Rect& rect,
1104 const MenuListExtraParams& extra) const {
1105 HANDLE handle = GetThemeHandle(MENULIST);
1106 RECT rect_win = rect.ToRECT();
1107 int state_id = CBXS_NORMAL;
1108 switch (state) {
1109 case kDisabled:
1110 state_id = CBXS_DISABLED;
1111 break;
1112 case kHovered:
1113 state_id = CBXS_HOT;
1114 break;
1115 case kNormal:
1116 break;
1117 case kPressed:
1118 state_id = CBXS_PRESSED;
1119 break;
1120 case kNumStates:
1121 NOTREACHED();
1122 break;
1125 if (handle && draw_theme_)
1126 return draw_theme_(handle, hdc, CP_DROPDOWNBUTTON, state_id, &rect_win,
1127 NULL);
1129 // Draw it manually.
1130 DrawFrameControl(hdc, &rect_win, DFC_SCROLL,
1131 DFCS_SCROLLCOMBOBOX | extra.classic_state);
1132 return S_OK;
1135 HRESULT NativeThemeWin::PaintScrollbarArrow(
1136 HDC hdc,
1137 Part part,
1138 State state,
1139 const gfx::Rect& rect,
1140 const ScrollbarArrowExtraParams& extra) const {
1141 static const int state_id_matrix[4][kNumStates] = {
1142 {ABS_DOWNDISABLED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNPRESSED},
1143 {ABS_LEFTDISABLED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTPRESSED},
1144 {ABS_RIGHTDISABLED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTPRESSED},
1145 {ABS_UPDISABLED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPPRESSED},
1147 HANDLE handle = GetThemeHandle(SCROLLBAR);
1148 RECT rect_win = rect.ToRECT();
1149 if (handle && draw_theme_) {
1150 int index = part - kScrollbarDownArrow;
1151 DCHECK_GE(index, 0);
1152 DCHECK_LT(static_cast<size_t>(index), arraysize(state_id_matrix));
1153 int state_id = state_id_matrix[index][state];
1155 // Hovering means that the cursor is over the scroolbar, but not over the
1156 // specific arrow itself. We don't want to show it "hot" mode, but only
1157 // in "hover" mode.
1158 if (state == kHovered && extra.is_hovering) {
1159 switch (part) {
1160 case kScrollbarDownArrow:
1161 state_id = ABS_DOWNHOVER;
1162 break;
1163 case kScrollbarLeftArrow:
1164 state_id = ABS_LEFTHOVER;
1165 break;
1166 case kScrollbarRightArrow:
1167 state_id = ABS_RIGHTHOVER;
1168 break;
1169 case kScrollbarUpArrow:
1170 state_id = ABS_UPHOVER;
1171 break;
1172 default:
1173 NOTREACHED();
1174 break;
1177 return PaintScaledTheme(handle, hdc, SBP_ARROWBTN, state_id, rect);
1180 int classic_state = DFCS_SCROLLDOWN;
1181 switch (part) {
1182 case kScrollbarDownArrow:
1183 break;
1184 case kScrollbarLeftArrow:
1185 classic_state = DFCS_SCROLLLEFT;
1186 break;
1187 case kScrollbarRightArrow:
1188 classic_state = DFCS_SCROLLRIGHT;
1189 break;
1190 case kScrollbarUpArrow:
1191 classic_state = DFCS_SCROLLUP;
1192 break;
1193 default:
1194 NOTREACHED();
1195 break;
1197 switch (state) {
1198 case kDisabled:
1199 classic_state |= DFCS_INACTIVE;
1200 break;
1201 case kHovered:
1202 classic_state |= DFCS_HOT;
1203 break;
1204 case kNormal:
1205 break;
1206 case kPressed:
1207 classic_state |= DFCS_PUSHED;
1208 break;
1209 case kNumStates:
1210 NOTREACHED();
1211 break;
1213 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, classic_state);
1214 return S_OK;
1217 HRESULT NativeThemeWin::PaintScrollbarThumb(
1218 HDC hdc,
1219 Part part,
1220 State state,
1221 const gfx::Rect& rect,
1222 const ScrollbarThumbExtraParams& extra) const {
1223 HANDLE handle = GetThemeHandle(SCROLLBAR);
1224 RECT rect_win = rect.ToRECT();
1226 int part_id = SBP_THUMBBTNVERT;
1227 switch (part) {
1228 case kScrollbarHorizontalThumb:
1229 part_id = SBP_THUMBBTNHORZ;
1230 break;
1231 case kScrollbarVerticalThumb:
1232 break;
1233 case kScrollbarHorizontalGripper:
1234 part_id = SBP_GRIPPERHORZ;
1235 break;
1236 case kScrollbarVerticalGripper:
1237 part_id = SBP_GRIPPERVERT;
1238 break;
1239 default:
1240 NOTREACHED();
1241 break;
1244 int state_id = SCRBS_NORMAL;
1245 switch (state) {
1246 case kDisabled:
1247 state_id = SCRBS_DISABLED;
1248 break;
1249 case kHovered:
1250 state_id = extra.is_hovering ? SCRBS_HOVER : SCRBS_HOT;
1251 break;
1252 case kNormal:
1253 break;
1254 case kPressed:
1255 state_id = SCRBS_PRESSED;
1256 break;
1257 case kNumStates:
1258 NOTREACHED();
1259 break;
1262 if (handle && draw_theme_)
1263 return PaintScaledTheme(handle, hdc, part_id, state_id, rect);
1265 // Draw it manually.
1266 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
1267 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_MIDDLE);
1268 // Classic mode doesn't have a gripper.
1269 return S_OK;
1272 HRESULT NativeThemeWin::PaintScrollbarTrack(
1273 SkCanvas* canvas,
1274 HDC hdc,
1275 Part part,
1276 State state,
1277 const gfx::Rect& rect,
1278 const ScrollbarTrackExtraParams& extra) const {
1279 HANDLE handle = GetThemeHandle(SCROLLBAR);
1280 RECT rect_win = rect.ToRECT();
1282 const int part_id = extra.is_upper ?
1283 ((part == kScrollbarHorizontalTrack) ?
1284 SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT) :
1285 ((part == kScrollbarHorizontalTrack) ?
1286 SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT);
1288 int state_id = SCRBS_NORMAL;
1289 switch (state) {
1290 case kDisabled:
1291 state_id = SCRBS_DISABLED;
1292 break;
1293 case kHovered:
1294 state_id = SCRBS_HOVER;
1295 break;
1296 case kNormal:
1297 break;
1298 case kPressed:
1299 state_id = SCRBS_PRESSED;
1300 break;
1301 case kNumStates:
1302 NOTREACHED();
1303 break;
1306 if (handle && draw_theme_)
1307 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL);
1309 // Draw it manually.
1310 if ((system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_3DFACE]) &&
1311 (system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_WINDOW])) {
1312 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
1313 } else {
1314 SkPaint paint;
1315 RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width,
1316 extra.track_height).ToRECT();
1317 SetCheckerboardShader(&paint, align_rect);
1318 canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint);
1320 if (extra.classic_state & DFCS_PUSHED)
1321 InvertRect(hdc, &rect_win);
1322 return S_OK;
1325 HRESULT NativeThemeWin::PaintSpinButton(
1326 HDC hdc,
1327 Part part,
1328 State state,
1329 const gfx::Rect& rect,
1330 const InnerSpinButtonExtraParams& extra) const {
1331 HANDLE handle = GetThemeHandle(SPIN);
1332 RECT rect_win = rect.ToRECT();
1333 int part_id = extra.spin_up ? SPNP_UP : SPNP_DOWN;
1334 int state_id = extra.spin_up ? UPS_NORMAL : DNS_NORMAL;
1335 switch (state) {
1336 case kDisabled:
1337 state_id = extra.spin_up ? UPS_DISABLED : DNS_DISABLED;
1338 break;
1339 case kHovered:
1340 state_id = extra.spin_up ? UPS_HOT : DNS_HOT;
1341 break;
1342 case kNormal:
1343 break;
1344 case kPressed:
1345 state_id = extra.spin_up ? UPS_PRESSED : DNS_PRESSED;
1346 break;
1347 case kNumStates:
1348 NOTREACHED();
1349 break;
1352 if (handle && draw_theme_)
1353 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL);
1354 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, extra.classic_state);
1355 return S_OK;
1358 HRESULT NativeThemeWin::PaintTrackbar(
1359 SkCanvas* canvas,
1360 HDC hdc,
1361 Part part,
1362 State state,
1363 const gfx::Rect& rect,
1364 const TrackbarExtraParams& extra) const {
1365 const int part_id = extra.vertical ?
1366 ((part == kTrackbarTrack) ? TKP_TRACKVERT : TKP_THUMBVERT) :
1367 ((part == kTrackbarTrack) ? TKP_TRACK : TKP_THUMBBOTTOM);
1369 int state_id = TUS_NORMAL;
1370 switch (state) {
1371 case kDisabled:
1372 state_id = TUS_DISABLED;
1373 break;
1374 case kHovered:
1375 state_id = TUS_HOT;
1376 break;
1377 case kNormal:
1378 break;
1379 case kPressed:
1380 state_id = TUS_PRESSED;
1381 break;
1382 case kNumStates:
1383 NOTREACHED();
1384 break;
1387 // Make the channel be 4 px thick in the center of the supplied rect. (4 px
1388 // matches what XP does in various menus; GetThemePartSize() doesn't seem to
1389 // return good values here.)
1390 RECT rect_win = rect.ToRECT();
1391 RECT channel_rect = rect.ToRECT();
1392 const int channel_thickness = 4;
1393 if (part_id == TKP_TRACK) {
1394 channel_rect.top +=
1395 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2);
1396 channel_rect.bottom = channel_rect.top + channel_thickness;
1397 } else if (part_id == TKP_TRACKVERT) {
1398 channel_rect.left +=
1399 ((channel_rect.right - channel_rect.left - channel_thickness) / 2);
1400 channel_rect.right = channel_rect.left + channel_thickness;
1401 } // else this isn't actually a channel, so |channel_rect| == |rect|.
1403 HANDLE handle = GetThemeHandle(TRACKBAR);
1404 if (handle && draw_theme_)
1405 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL);
1407 // Classic mode, draw it manually.
1408 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) {
1409 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT);
1410 } else if (part_id == TKP_THUMBVERT) {
1411 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE);
1412 } else {
1413 // Split rect into top and bottom pieces.
1414 RECT top_section = rect.ToRECT();
1415 RECT bottom_section = rect.ToRECT();
1416 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2);
1417 bottom_section.top = top_section.bottom;
1418 DrawEdge(hdc, &top_section, EDGE_RAISED,
1419 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
1421 // Split triangular piece into two diagonals.
1422 RECT& left_half = bottom_section;
1423 RECT right_half = bottom_section;
1424 right_half.left += ((bottom_section.right - bottom_section.left) / 2);
1425 left_half.right = right_half.left;
1426 DrawEdge(hdc, &left_half, EDGE_RAISED,
1427 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
1428 DrawEdge(hdc, &right_half, EDGE_RAISED,
1429 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
1431 // If the button is pressed, draw hatching.
1432 if (extra.classic_state & DFCS_PUSHED) {
1433 SkPaint paint;
1434 SetCheckerboardShader(&paint, rect_win);
1436 // Fill all three pieces with the pattern.
1437 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint);
1439 SkScalar left_triangle_top = SkIntToScalar(left_half.top);
1440 SkScalar left_triangle_right = SkIntToScalar(left_half.right);
1441 SkPath left_triangle;
1442 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top);
1443 left_triangle.lineTo(left_triangle_right, left_triangle_top);
1444 left_triangle.lineTo(left_triangle_right,
1445 SkIntToScalar(left_half.bottom));
1446 left_triangle.close();
1447 canvas->drawPath(left_triangle, paint);
1449 SkScalar right_triangle_left = SkIntToScalar(right_half.left);
1450 SkScalar right_triangle_top = SkIntToScalar(right_half.top);
1451 SkPath right_triangle;
1452 right_triangle.moveTo(right_triangle_left, right_triangle_top);
1453 right_triangle.lineTo(SkIntToScalar(right_half.right),
1454 right_triangle_top);
1455 right_triangle.lineTo(right_triangle_left,
1456 SkIntToScalar(right_half.bottom));
1457 right_triangle.close();
1458 canvas->drawPath(right_triangle, paint);
1461 return S_OK;
1464 HRESULT NativeThemeWin::PaintProgressBar(
1465 HDC hdc,
1466 const gfx::Rect& rect,
1467 const ProgressBarExtraParams& extra) const {
1468 // There is no documentation about the animation speed, frame-rate, nor
1469 // size of moving overlay of the indeterminate progress bar.
1470 // So we just observed real-world programs and guessed following parameters.
1471 const int kDeterminateOverlayPixelsPerSecond = 300;
1472 const int kDeterminateOverlayWidth = 120;
1473 const int kIndeterminateOverlayPixelsPerSecond = 175;
1474 const int kVistaIndeterminateOverlayWidth = 120;
1475 const int kXPIndeterminateOverlayWidth = 55;
1476 // The thickness of the bar frame inside |value_rect|
1477 const int kXPBarPadding = 3;
1479 RECT bar_rect = rect.ToRECT();
1480 RECT value_rect = gfx::Rect(extra.value_rect_x,
1481 extra.value_rect_y,
1482 extra.value_rect_width,
1483 extra.value_rect_height).ToRECT();
1485 HANDLE handle = GetThemeHandle(PROGRESS);
1486 if (!handle || !draw_theme_ || !draw_theme_ex_) {
1487 FillRect(hdc, &bar_rect, GetSysColorBrush(COLOR_BTNFACE));
1488 FillRect(hdc, &value_rect, GetSysColorBrush(COLOR_BTNSHADOW));
1489 DrawEdge(hdc, &bar_rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1490 return S_OK;
1493 draw_theme_(handle, hdc, PP_BAR, 0, &bar_rect, NULL);
1495 bool pre_vista = base::win::GetVersion() < base::win::VERSION_VISTA;
1496 int bar_width = bar_rect.right - bar_rect.left;
1497 if (!extra.determinate) {
1498 // The glossy overlay for the indeterminate progress bar has a small pause
1499 // after each animation. We emulate this by adding an invisible margin the
1500 // animation has to traverse.
1501 int width_with_margin = bar_width + kIndeterminateOverlayPixelsPerSecond;
1502 int overlay_width = pre_vista ?
1503 kXPIndeterminateOverlayWidth : kVistaIndeterminateOverlayWidth;
1504 RECT overlay_rect = bar_rect;
1505 overlay_rect.left += ComputeAnimationProgress(
1506 width_with_margin, overlay_width, kIndeterminateOverlayPixelsPerSecond,
1507 extra.animated_seconds);
1508 overlay_rect.right = overlay_rect.left + overlay_width;
1509 if (pre_vista) {
1510 RECT shrunk_rect = InsetRect(&overlay_rect, kXPBarPadding);
1511 RECT shrunk_bar_rect = InsetRect(&bar_rect, kXPBarPadding);
1512 draw_theme_(handle, hdc, PP_CHUNK, 0, &shrunk_rect, &shrunk_bar_rect);
1513 } else {
1514 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &bar_rect);
1516 return S_OK;
1519 // We care about the direction here because PP_CHUNK painting is asymmetric.
1520 // TODO(morrita): This RTL guess can be wrong. We should pass in the
1521 // direction from WebKit.
1522 const DTBGOPTS value_draw_options = {
1523 sizeof(DTBGOPTS),
1524 (bar_rect.right == value_rect.right && bar_rect.left != value_rect.left) ?
1525 DTBG_MIRRORDC : 0u,
1526 bar_rect
1528 if (pre_vista) {
1529 // On XP, the progress bar is chunk-style and has no glossy effect. We need
1530 // to shrink the destination rect to fit the part inside the bar with an
1531 // appropriate margin.
1532 RECT shrunk_value_rect = InsetRect(&value_rect, kXPBarPadding);
1533 draw_theme_ex_(handle, hdc, PP_CHUNK, 0, &shrunk_value_rect,
1534 &value_draw_options);
1535 } else {
1536 // On Vista or later, the progress bar part has a single-block value part
1537 // and a glossy effect. The value part has exactly same height as the bar
1538 // part, so we don't need to shrink the rect.
1539 draw_theme_ex_(handle, hdc, PP_FILL, 0, &value_rect, &value_draw_options);
1541 RECT overlay_rect = value_rect;
1542 overlay_rect.left += ComputeAnimationProgress(
1543 bar_width, kDeterminateOverlayWidth, kDeterminateOverlayPixelsPerSecond,
1544 extra.animated_seconds);
1545 overlay_rect.right = overlay_rect.left + kDeterminateOverlayWidth;
1546 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &value_rect);
1548 return S_OK;
1551 HRESULT NativeThemeWin::PaintWindowResizeGripper(HDC hdc,
1552 const gfx::Rect& rect) const {
1553 HANDLE handle = GetThemeHandle(STATUS);
1554 RECT rect_win = rect.ToRECT();
1555 if (handle && draw_theme_) {
1556 // Paint the status bar gripper. There doesn't seem to be a standard
1557 // gripper in Windows for the space between scrollbars. This is pretty
1558 // close, but it's supposed to be painted over a status bar.
1559 return draw_theme_(handle, hdc, SP_GRIPPER, 0, &rect_win, NULL);
1562 // Draw a windows classic scrollbar gripper.
1563 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
1564 return S_OK;
1567 HRESULT NativeThemeWin::PaintTabPanelBackground(HDC hdc,
1568 const gfx::Rect& rect) const {
1569 HANDLE handle = GetThemeHandle(TAB);
1570 RECT rect_win = rect.ToRECT();
1571 if (handle && draw_theme_)
1572 return draw_theme_(handle, hdc, TABP_BODY, 0, &rect_win, NULL);
1574 // Classic just renders a flat color background.
1575 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
1576 return S_OK;
1579 HRESULT NativeThemeWin::PaintTextField(
1580 HDC hdc,
1581 Part part,
1582 State state,
1583 const gfx::Rect& rect,
1584 const TextFieldExtraParams& extra) const {
1585 int state_id = ETS_NORMAL;
1586 switch (state) {
1587 case kDisabled:
1588 state_id = ETS_DISABLED;
1589 break;
1590 case kHovered:
1591 state_id = ETS_HOT;
1592 break;
1593 case kNormal:
1594 if (extra.is_read_only)
1595 state_id = ETS_READONLY;
1596 else if (extra.is_focused)
1597 state_id = ETS_FOCUSED;
1598 break;
1599 case kPressed:
1600 state_id = ETS_SELECTED;
1601 break;
1602 case kNumStates:
1603 NOTREACHED();
1604 break;
1607 RECT rect_win = rect.ToRECT();
1608 return PaintTextField(hdc, EP_EDITTEXT, state_id, extra.classic_state,
1609 &rect_win,
1610 skia::SkColorToCOLORREF(extra.background_color),
1611 extra.fill_content_area, extra.draw_edges);
1614 HRESULT NativeThemeWin::PaintTextField(HDC hdc,
1615 int part_id,
1616 int state_id,
1617 int classic_state,
1618 RECT* rect,
1619 COLORREF color,
1620 bool fill_content_area,
1621 bool draw_edges) const {
1622 // TODO(ojan): http://b/1210017 Figure out how to give the ability to
1623 // exclude individual edges from being drawn.
1625 HANDLE handle = GetThemeHandle(TEXTFIELD);
1626 // TODO(mpcomplete): can we detect if the color is specified by the user,
1627 // and if not, just use the system color?
1628 // CreateSolidBrush() accepts a RGB value but alpha must be 0.
1629 base::win::ScopedGDIObject<HBRUSH> bg_brush(CreateSolidBrush(color));
1630 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
1631 // draw_theme_ex_ is NULL and draw_theme_ is non-null.
1632 if (!handle || (!draw_theme_ex_ && (!draw_theme_ || !draw_edges))) {
1633 // Draw it manually.
1634 if (draw_edges)
1635 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1637 if (fill_content_area) {
1638 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
1639 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
1641 return S_OK;
1644 static const DTBGOPTS omit_border_options = {
1645 sizeof(DTBGOPTS),
1646 DTBG_OMITBORDER,
1647 { 0, 0, 0, 0 }
1649 HRESULT hr = draw_theme_ex_ ?
1650 draw_theme_ex_(handle, hdc, part_id, state_id, rect,
1651 draw_edges ? NULL : &omit_border_options) :
1652 draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
1654 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
1655 if (fill_content_area && get_theme_content_rect_) {
1656 RECT content_rect;
1657 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
1658 &content_rect);
1659 FillRect(hdc, &content_rect, bg_brush);
1661 return hr;
1664 HRESULT NativeThemeWin::PaintScaledTheme(HANDLE theme,
1665 HDC hdc,
1666 int part_id,
1667 int state_id,
1668 const gfx::Rect& rect) const {
1669 // Correct the scaling and positioning of sub-components such as scrollbar
1670 // arrows and thumb grippers in the event that the world transform applies
1671 // scaling (e.g. in high-DPI mode).
1672 XFORM save_transform;
1673 if (GetWorldTransform(hdc, &save_transform)) {
1674 float scale = save_transform.eM11;
1675 if (scale != 1 && save_transform.eM12 == 0) {
1676 ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
1677 gfx::Rect scaled_rect = gfx::ScaleToEnclosedRect(rect, scale);
1678 scaled_rect.Offset(save_transform.eDx, save_transform.eDy);
1679 RECT bounds = scaled_rect.ToRECT();
1680 HRESULT result = draw_theme_(theme, hdc, part_id, state_id, &bounds,
1681 NULL);
1682 SetWorldTransform(hdc, &save_transform);
1683 return result;
1686 RECT bounds = rect.ToRECT();
1687 return draw_theme_(theme, hdc, part_id, state_id, &bounds, NULL);
1690 // static
1691 NativeThemeWin::ThemeName NativeThemeWin::GetThemeName(Part part) {
1692 switch (part) {
1693 case kCheckbox:
1694 case kPushButton:
1695 case kRadio:
1696 return BUTTON;
1697 case kInnerSpinButton:
1698 return SPIN;
1699 case kMenuList:
1700 case kMenuCheck:
1701 case kMenuPopupArrow:
1702 case kMenuPopupGutter:
1703 case kMenuPopupSeparator:
1704 return MENU;
1705 case kProgressBar:
1706 return PROGRESS;
1707 case kScrollbarDownArrow:
1708 case kScrollbarLeftArrow:
1709 case kScrollbarRightArrow:
1710 case kScrollbarUpArrow:
1711 case kScrollbarHorizontalThumb:
1712 case kScrollbarVerticalThumb:
1713 case kScrollbarHorizontalTrack:
1714 case kScrollbarVerticalTrack:
1715 return SCROLLBAR;
1716 case kSliderTrack:
1717 case kSliderThumb:
1718 return TRACKBAR;
1719 case kTextField:
1720 return TEXTFIELD;
1721 case kWindowResizeGripper:
1722 return STATUS;
1723 case kComboboxArrow:
1724 case kMenuCheckBackground:
1725 case kMenuPopupBackground:
1726 case kMenuItemBackground:
1727 case kScrollbarHorizontalGripper:
1728 case kScrollbarVerticalGripper:
1729 case kScrollbarCorner:
1730 case kTabPanelBackground:
1731 case kTrackbarThumb:
1732 case kTrackbarTrack:
1733 case kMaxPart:
1734 NOTREACHED();
1736 return LAST;
1739 // static
1740 int NativeThemeWin::GetWindowsPart(Part part,
1741 State state,
1742 const ExtraParams& extra) {
1743 switch (part) {
1744 case kCheckbox:
1745 return BP_CHECKBOX;
1746 case kMenuCheck:
1747 return MENU_POPUPCHECK;
1748 case kMenuPopupArrow:
1749 return MENU_POPUPSUBMENU;
1750 case kMenuPopupGutter:
1751 return MENU_POPUPGUTTER;
1752 case kMenuPopupSeparator:
1753 return MENU_POPUPSEPARATOR;
1754 case kPushButton:
1755 return BP_PUSHBUTTON;
1756 case kRadio:
1757 return BP_RADIOBUTTON;
1758 case kScrollbarDownArrow:
1759 case kScrollbarLeftArrow:
1760 case kScrollbarRightArrow:
1761 case kScrollbarUpArrow:
1762 return SBP_ARROWBTN;
1763 case kScrollbarHorizontalThumb:
1764 return SBP_THUMBBTNHORZ;
1765 case kScrollbarVerticalThumb:
1766 return SBP_THUMBBTNVERT;
1767 case kWindowResizeGripper:
1768 return SP_GRIPPER;
1769 case kComboboxArrow:
1770 case kInnerSpinButton:
1771 case kMenuList:
1772 case kMenuCheckBackground:
1773 case kMenuPopupBackground:
1774 case kMenuItemBackground:
1775 case kProgressBar:
1776 case kScrollbarHorizontalTrack:
1777 case kScrollbarVerticalTrack:
1778 case kScrollbarHorizontalGripper:
1779 case kScrollbarVerticalGripper:
1780 case kScrollbarCorner:
1781 case kSliderTrack:
1782 case kSliderThumb:
1783 case kTabPanelBackground:
1784 case kTextField:
1785 case kTrackbarThumb:
1786 case kTrackbarTrack:
1787 case kMaxPart:
1788 NOTREACHED();
1790 return 0;
1793 int NativeThemeWin::GetWindowsState(Part part,
1794 State state,
1795 const ExtraParams& extra) {
1796 switch (part) {
1797 case kCheckbox:
1798 switch (state) {
1799 case kDisabled:
1800 return CBS_UNCHECKEDDISABLED;
1801 case kHovered:
1802 return CBS_UNCHECKEDHOT;
1803 case kNormal:
1804 return CBS_UNCHECKEDNORMAL;
1805 case kPressed:
1806 return CBS_UNCHECKEDPRESSED;
1807 case kNumStates:
1808 NOTREACHED();
1809 return 0;
1811 case kMenuCheck:
1812 switch (state) {
1813 case kDisabled:
1814 return extra.menu_check.is_radio ?
1815 MC_BULLETDISABLED : MC_CHECKMARKDISABLED;
1816 case kHovered:
1817 case kNormal:
1818 case kPressed:
1819 return extra.menu_check.is_radio ?
1820 MC_BULLETNORMAL : MC_CHECKMARKNORMAL;
1821 case kNumStates:
1822 NOTREACHED();
1823 return 0;
1825 case kMenuPopupArrow:
1826 case kMenuPopupGutter:
1827 case kMenuPopupSeparator:
1828 switch (state) {
1829 case kDisabled:
1830 return MBI_DISABLED;
1831 case kHovered:
1832 return MBI_HOT;
1833 case kNormal:
1834 return MBI_NORMAL;
1835 case kPressed:
1836 return MBI_PUSHED;
1837 case kNumStates:
1838 NOTREACHED();
1839 return 0;
1841 case kPushButton:
1842 switch (state) {
1843 case kDisabled:
1844 return PBS_DISABLED;
1845 case kHovered:
1846 return PBS_HOT;
1847 case kNormal:
1848 return PBS_NORMAL;
1849 case kPressed:
1850 return PBS_PRESSED;
1851 case kNumStates:
1852 NOTREACHED();
1853 return 0;
1855 case kRadio:
1856 switch (state) {
1857 case kDisabled:
1858 return RBS_UNCHECKEDDISABLED;
1859 case kHovered:
1860 return RBS_UNCHECKEDHOT;
1861 case kNormal:
1862 return RBS_UNCHECKEDNORMAL;
1863 case kPressed:
1864 return RBS_UNCHECKEDPRESSED;
1865 case kNumStates:
1866 NOTREACHED();
1867 return 0;
1869 case kScrollbarDownArrow:
1870 switch (state) {
1871 case kDisabled:
1872 return ABS_DOWNDISABLED;
1873 case kHovered:
1874 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1875 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1876 ABS_DOWNHOT : ABS_DOWNHOVER;
1877 case kNormal:
1878 return ABS_DOWNNORMAL;
1879 case kPressed:
1880 return ABS_DOWNPRESSED;
1881 case kNumStates:
1882 NOTREACHED();
1883 return 0;
1885 case kScrollbarLeftArrow:
1886 switch (state) {
1887 case kDisabled:
1888 return ABS_LEFTDISABLED;
1889 case kHovered:
1890 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1891 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1892 ABS_LEFTHOT : ABS_LEFTHOVER;
1893 case kNormal:
1894 return ABS_LEFTNORMAL;
1895 case kPressed:
1896 return ABS_LEFTPRESSED;
1897 case kNumStates:
1898 NOTREACHED();
1899 return 0;
1901 case kScrollbarRightArrow:
1902 switch (state) {
1903 case kDisabled:
1904 return ABS_RIGHTDISABLED;
1905 case kHovered:
1906 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1907 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1908 ABS_RIGHTHOT : ABS_RIGHTHOVER;
1909 case kNormal:
1910 return ABS_RIGHTNORMAL;
1911 case kPressed:
1912 return ABS_RIGHTPRESSED;
1913 case kNumStates:
1914 NOTREACHED();
1915 return 0;
1917 break;
1918 case kScrollbarUpArrow:
1919 switch (state) {
1920 case kDisabled:
1921 return ABS_UPDISABLED;
1922 case kHovered:
1923 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1924 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1925 ABS_UPHOT : ABS_UPHOVER;
1926 case kNormal:
1927 return ABS_UPNORMAL;
1928 case kPressed:
1929 return ABS_UPPRESSED;
1930 case kNumStates:
1931 NOTREACHED();
1932 return 0;
1934 break;
1935 case kScrollbarHorizontalThumb:
1936 case kScrollbarVerticalThumb:
1937 switch (state) {
1938 case kDisabled:
1939 return SCRBS_DISABLED;
1940 case kHovered:
1941 // Mimic WebKit's behaviour in ScrollbarThemeChromiumWin.cpp.
1942 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1943 SCRBS_HOT : SCRBS_HOVER;
1944 case kNormal:
1945 return SCRBS_NORMAL;
1946 case kPressed:
1947 return SCRBS_PRESSED;
1948 case kNumStates:
1949 NOTREACHED();
1950 return 0;
1952 case kWindowResizeGripper:
1953 switch (state) {
1954 case kDisabled:
1955 case kHovered:
1956 case kNormal:
1957 case kPressed:
1958 return 1; // gripper has no windows state
1959 case kNumStates:
1960 NOTREACHED();
1961 return 0;
1963 case kComboboxArrow:
1964 case kInnerSpinButton:
1965 case kMenuList:
1966 case kMenuCheckBackground:
1967 case kMenuPopupBackground:
1968 case kMenuItemBackground:
1969 case kProgressBar:
1970 case kScrollbarHorizontalTrack:
1971 case kScrollbarVerticalTrack:
1972 case kScrollbarHorizontalGripper:
1973 case kScrollbarVerticalGripper:
1974 case kScrollbarCorner:
1975 case kSliderTrack:
1976 case kSliderThumb:
1977 case kTabPanelBackground:
1978 case kTextField:
1979 case kTrackbarThumb:
1980 case kTrackbarTrack:
1981 case kMaxPart:
1982 NOTREACHED();
1984 return 0;
1987 HRESULT NativeThemeWin::GetThemeInt(ThemeName theme,
1988 int part_id,
1989 int state_id,
1990 int prop_id,
1991 int *value) const {
1992 HANDLE handle = GetThemeHandle(theme);
1993 return (handle && get_theme_int_) ?
1994 get_theme_int_(handle, part_id, state_id, prop_id, value) : E_NOTIMPL;
1997 HRESULT NativeThemeWin::PaintFrameControl(HDC hdc,
1998 const gfx::Rect& rect,
1999 UINT type,
2000 UINT state,
2001 bool is_selected,
2002 State control_state) const {
2003 const int width = rect.width();
2004 const int height = rect.height();
2006 // DrawFrameControl for menu arrow/check wants a monochrome bitmap.
2007 base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
2009 if (mask_bitmap == NULL)
2010 return E_OUTOFMEMORY;
2012 base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(NULL));
2013 base::win::ScopedSelectObject select_bitmap(bitmap_dc.Get(), mask_bitmap);
2014 RECT local_rect = { 0, 0, width, height };
2015 DrawFrameControl(bitmap_dc.Get(), &local_rect, type, state);
2017 // We're going to use BitBlt with a b&w mask. This results in using the dest
2018 // dc's text color for the black bits in the mask, and the dest dc's
2019 // background color for the white bits in the mask. DrawFrameControl draws the
2020 // check in black, and the background in white.
2021 int bg_color_key = COLOR_MENU;
2022 int text_color_key = COLOR_MENUTEXT;
2023 switch (control_state) {
2024 case kDisabled:
2025 bg_color_key = is_selected ? COLOR_HIGHLIGHT : COLOR_MENU;
2026 text_color_key = COLOR_GRAYTEXT;
2027 break;
2028 case kHovered:
2029 bg_color_key = COLOR_HIGHLIGHT;
2030 text_color_key = COLOR_HIGHLIGHTTEXT;
2031 break;
2032 case kNormal:
2033 break;
2034 case kPressed:
2035 case kNumStates:
2036 NOTREACHED();
2037 break;
2039 COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key));
2040 COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key));
2041 BitBlt(hdc, rect.x(), rect.y(), width, height, bitmap_dc.Get(), 0, 0,
2042 SRCCOPY);
2043 SetBkColor(hdc, old_bg_color);
2044 SetTextColor(hdc, old_text_color);
2046 return S_OK;
2049 HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const {
2050 if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
2051 return 0;
2053 if (theme_handles_[theme_name])
2054 return theme_handles_[theme_name];
2056 // Not found, try to load it.
2057 HANDLE handle = 0;
2058 switch (theme_name) {
2059 case BUTTON:
2060 handle = open_theme_(NULL, L"Button");
2061 break;
2062 case LIST:
2063 handle = open_theme_(NULL, L"Listview");
2064 break;
2065 case MENU:
2066 handle = open_theme_(NULL, L"Menu");
2067 break;
2068 case MENULIST:
2069 handle = open_theme_(NULL, L"Combobox");
2070 break;
2071 case SCROLLBAR:
2072 handle = open_theme_(NULL, L"Scrollbar");
2073 break;
2074 case STATUS:
2075 handle = open_theme_(NULL, L"Status");
2076 break;
2077 case TAB:
2078 handle = open_theme_(NULL, L"Tab");
2079 break;
2080 case TEXTFIELD:
2081 handle = open_theme_(NULL, L"Edit");
2082 break;
2083 case TRACKBAR:
2084 handle = open_theme_(NULL, L"Trackbar");
2085 break;
2086 case WINDOW:
2087 handle = open_theme_(NULL, L"Window");
2088 break;
2089 case PROGRESS:
2090 handle = open_theme_(NULL, L"Progress");
2091 break;
2092 case SPIN:
2093 handle = open_theme_(NULL, L"Spin");
2094 break;
2095 case LAST:
2096 NOTREACHED();
2097 break;
2099 theme_handles_[theme_name] = handle;
2100 return handle;
2103 } // namespace ui