Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / ui / native_theme / native_theme_win.cc
bloba5c0a6ad983d1e482022d8cec26a822c354a6ace
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/gfx/color_utils.h"
27 #include "ui/gfx/gdi_util.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/geometry/rect_conversions.h"
30 #include "ui/gfx/win/dpi.h"
31 #include "ui/native_theme/common_theme.h"
33 // This was removed from Winvers.h but is still used.
34 #if !defined(COLOR_MENUHIGHLIGHT)
35 #define COLOR_MENUHIGHLIGHT 29
36 #endif
38 namespace {
40 // Windows system color IDs cached and updated by the native theme.
41 const int kSystemColors[] = {
42 COLOR_3DFACE,
43 COLOR_BTNFACE,
44 COLOR_BTNTEXT,
45 COLOR_GRAYTEXT,
46 COLOR_HIGHLIGHT,
47 COLOR_HIGHLIGHTTEXT,
48 COLOR_HOTLIGHT,
49 COLOR_MENUHIGHLIGHT,
50 COLOR_SCROLLBAR,
51 COLOR_WINDOW,
52 COLOR_WINDOWTEXT,
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 // Link:
476 const SkColor kLinkPressedColor = SkColorSetRGB(200, 0, 0);
477 // Table:
478 const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
479 const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29);
481 switch (color_id) {
482 // Windows
483 case kColorId_WindowBackground:
484 return system_colors_[COLOR_WINDOW];
486 // Dialogs
487 case kColorId_DialogBackground:
488 return color_utils::IsInvertedColorScheme() ?
489 color_utils::InvertColor(kDialogBackgroundColor) :
490 kDialogBackgroundColor;
492 // FocusableBorder
493 case kColorId_FocusedBorderColor:
494 return kFocusedBorderColor;
495 case kColorId_UnfocusedBorderColor:
496 return kUnfocusedBorderColor;
498 // Button
499 case kColorId_ButtonBackgroundColor:
500 return kButtonBackgroundColor;
501 case kColorId_ButtonEnabledColor:
502 return system_colors_[COLOR_BTNTEXT];
503 case kColorId_ButtonDisabledColor:
504 return system_colors_[COLOR_GRAYTEXT];
505 case kColorId_ButtonHighlightColor:
506 return kButtonHighlightColor;
507 case kColorId_ButtonHoverColor:
508 return kButtonHoverColor;
509 case kColorId_ButtonHoverBackgroundColor:
510 return kButtonHoverBackgroundColor;
511 case kColorId_BlueButtonEnabledColor:
512 case kColorId_BlueButtonDisabledColor:
513 case kColorId_BlueButtonPressedColor:
514 case kColorId_BlueButtonHoverColor:
515 NOTREACHED();
516 return kInvalidColorIdColor;
518 // MenuItem
519 case kColorId_EnabledMenuItemForegroundColor:
520 return kEnabledMenuItemForegroundColor;
521 case kColorId_DisabledMenuItemForegroundColor:
522 return kDisabledMenuItemForegroundColor;
523 case kColorId_DisabledEmphasizedMenuItemForegroundColor:
524 return SK_ColorBLACK;
525 case kColorId_FocusedMenuItemBackgroundColor:
526 return kFocusedMenuItemBackgroundColor;
527 case kColorId_MenuSeparatorColor:
528 return kMenuSeparatorColor;
529 case kColorId_SelectedMenuItemForegroundColor:
530 case kColorId_HoverMenuItemBackgroundColor:
531 case kColorId_MenuBackgroundColor:
532 case kColorId_MenuBorderColor:
533 NOTREACHED();
534 return kInvalidColorIdColor;
536 // MenuButton
537 case kColorId_EnabledMenuButtonBorderColor:
538 case kColorId_FocusedMenuButtonBorderColor:
539 case kColorId_HoverMenuButtonBorderColor:
540 NOTREACHED();
541 return kInvalidColorIdColor;
543 // Label
544 case kColorId_LabelEnabledColor:
545 return system_colors_[COLOR_BTNTEXT];
546 case kColorId_LabelDisabledColor:
547 return system_colors_[COLOR_GRAYTEXT];
548 case kColorId_LabelBackgroundColor:
549 return system_colors_[COLOR_WINDOW];
551 // Link
552 case kColorId_LinkDisabled:
553 return system_colors_[COLOR_WINDOWTEXT];
554 case kColorId_LinkEnabled:
555 return system_colors_[COLOR_HOTLIGHT];
556 case kColorId_LinkPressed:
557 return kLinkPressedColor;
559 // Textfield
560 case kColorId_TextfieldDefaultColor:
561 return system_colors_[COLOR_WINDOWTEXT];
562 case kColorId_TextfieldDefaultBackground:
563 return system_colors_[COLOR_WINDOW];
564 case kColorId_TextfieldReadOnlyColor:
565 return system_colors_[COLOR_GRAYTEXT];
566 case kColorId_TextfieldReadOnlyBackground:
567 return system_colors_[COLOR_3DFACE];
568 case kColorId_TextfieldSelectionColor:
569 return system_colors_[COLOR_HIGHLIGHTTEXT];
570 case kColorId_TextfieldSelectionBackgroundFocused:
571 return system_colors_[COLOR_HIGHLIGHT];
573 // Tooltip
574 case kColorId_TooltipBackground:
575 case kColorId_TooltipText:
576 NOTREACHED();
577 return kInvalidColorIdColor;
579 // Tree
580 // NOTE: these aren't right for all themes, but as close as I could get.
581 case kColorId_TreeBackground:
582 return system_colors_[COLOR_WINDOW];
583 case kColorId_TreeText:
584 return system_colors_[COLOR_WINDOWTEXT];
585 case kColorId_TreeSelectedText:
586 return system_colors_[COLOR_HIGHLIGHTTEXT];
587 case kColorId_TreeSelectedTextUnfocused:
588 return system_colors_[COLOR_BTNTEXT];
589 case kColorId_TreeSelectionBackgroundFocused:
590 return system_colors_[COLOR_HIGHLIGHT];
591 case kColorId_TreeSelectionBackgroundUnfocused:
592 return system_colors_[IsUsingHighContrastTheme() ?
593 COLOR_MENUHIGHLIGHT : COLOR_BTNFACE];
594 case kColorId_TreeArrow:
595 return system_colors_[COLOR_WINDOWTEXT];
597 // Table
598 case kColorId_TableBackground:
599 return system_colors_[COLOR_WINDOW];
600 case kColorId_TableText:
601 return system_colors_[COLOR_WINDOWTEXT];
602 case kColorId_TableSelectedText:
603 return system_colors_[COLOR_HIGHLIGHTTEXT];
604 case kColorId_TableSelectedTextUnfocused:
605 return system_colors_[COLOR_BTNTEXT];
606 case kColorId_TableSelectionBackgroundFocused:
607 return system_colors_[COLOR_HIGHLIGHT];
608 case kColorId_TableSelectionBackgroundUnfocused:
609 return system_colors_[IsUsingHighContrastTheme() ?
610 COLOR_MENUHIGHLIGHT : COLOR_BTNFACE];
611 case kColorId_TableGroupingIndicatorColor:
612 return system_colors_[COLOR_GRAYTEXT];
614 // Results Tables
615 case kColorId_ResultsTableNormalBackground:
616 return system_colors_[COLOR_WINDOW];
617 case kColorId_ResultsTableHoveredBackground:
618 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHT],
619 system_colors_[COLOR_WINDOW], 0x40);
620 case kColorId_ResultsTableSelectedBackground:
621 return system_colors_[COLOR_HIGHLIGHT];
622 case kColorId_ResultsTableNormalText:
623 return system_colors_[COLOR_WINDOWTEXT];
624 case kColorId_ResultsTableHoveredText:
625 return color_utils::GetReadableColor(
626 system_colors_[COLOR_WINDOWTEXT],
627 GetSystemColor(kColorId_ResultsTableHoveredBackground));
628 case kColorId_ResultsTableSelectedText:
629 return system_colors_[COLOR_HIGHLIGHTTEXT];
630 case kColorId_ResultsTableNormalDimmedText:
631 return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
632 system_colors_[COLOR_WINDOW], 0x80);
633 case kColorId_ResultsTableHoveredDimmedText:
634 return color_utils::AlphaBlend(
635 system_colors_[COLOR_WINDOWTEXT],
636 GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x80);
637 case kColorId_ResultsTableSelectedDimmedText:
638 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
639 system_colors_[COLOR_HIGHLIGHT], 0x80);
640 case kColorId_ResultsTableNormalUrl:
641 return color_utils::GetReadableColor(kUrlTextColor,
642 system_colors_[COLOR_WINDOW]);
643 case kColorId_ResultsTableHoveredUrl:
644 return color_utils::GetReadableColor(
645 kUrlTextColor,
646 GetSystemColor(kColorId_ResultsTableHoveredBackground));
647 case kColorId_ResultsTableSelectedUrl:
648 return color_utils::GetReadableColor(kUrlTextColor,
649 system_colors_[COLOR_HIGHLIGHT]);
650 case kColorId_ResultsTableNormalDivider:
651 return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
652 system_colors_[COLOR_WINDOW], 0x34);
653 case kColorId_ResultsTableHoveredDivider:
654 return color_utils::AlphaBlend(
655 system_colors_[COLOR_WINDOWTEXT],
656 GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x34);
657 case kColorId_ResultsTableSelectedDivider:
658 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
659 system_colors_[COLOR_HIGHLIGHT], 0x34);
660 case kColorId_ResultsTablePositiveText:
661 return color_utils::GetReadableColor(kPositiveTextColor,
662 system_colors_[COLOR_WINDOW]);
663 case kColorId_ResultsTablePositiveHoveredText:
664 return color_utils::GetReadableColor(
665 kPositiveTextColor,
666 GetSystemColor(kColorId_ResultsTableHoveredBackground));
667 case kColorId_ResultsTablePositiveSelectedText:
668 return color_utils::GetReadableColor(kPositiveTextColor,
669 system_colors_[COLOR_HIGHLIGHT]);
670 case kColorId_ResultsTableNegativeText:
671 return color_utils::GetReadableColor(kNegativeTextColor,
672 system_colors_[COLOR_WINDOW]);
673 case kColorId_ResultsTableNegativeHoveredText:
674 return color_utils::GetReadableColor(
675 kNegativeTextColor,
676 GetSystemColor(kColorId_ResultsTableHoveredBackground));
677 case kColorId_ResultsTableNegativeSelectedText:
678 return color_utils::GetReadableColor(kNegativeTextColor,
679 system_colors_[COLOR_HIGHLIGHT]);
680 default:
681 NOTREACHED();
682 return kInvalidColorIdColor;
686 void NativeThemeWin::PaintIndirect(SkCanvas* canvas,
687 Part part,
688 State state,
689 const gfx::Rect& rect,
690 const ExtraParams& extra) const {
691 // TODO(asvitkine): This path is pretty inefficient - for each paint operation
692 // it creates a new offscreen bitmap Skia canvas. This can
693 // be sped up by doing it only once per part/state and
694 // keeping a cache of the resulting bitmaps.
696 // Create an offscreen canvas that is backed by an HDC.
697 skia::RefPtr<skia::BitmapPlatformDevice> device = skia::AdoptRef(
698 skia::BitmapPlatformDevice::Create(
699 rect.width(), rect.height(), false, NULL));
700 DCHECK(device);
701 SkCanvas offscreen_canvas(device.get());
702 DCHECK(skia::SupportsPlatformPaint(&offscreen_canvas));
704 // Some of the Windows theme drawing operations do not write correct alpha
705 // values for fully-opaque pixels; instead the pixels get alpha 0. This is
706 // especially a problem on Windows XP or when using the Classic theme.
708 // To work-around this, mark all pixels with a placeholder value, to detect
709 // which pixels get touched by the paint operation. After paint, set any
710 // pixels that have alpha 0 to opaque and placeholders to fully-transparent.
711 const SkColor placeholder = SkColorSetARGB(1, 0, 0, 0);
712 offscreen_canvas.clear(placeholder);
714 // Offset destination rects to have origin (0,0).
715 gfx::Rect adjusted_rect(rect.size());
716 ExtraParams adjusted_extra(extra);
717 switch (part) {
718 case kProgressBar:
719 adjusted_extra.progress_bar.value_rect_x = 0;
720 adjusted_extra.progress_bar.value_rect_y = 0;
721 break;
722 case kScrollbarHorizontalTrack:
723 case kScrollbarVerticalTrack:
724 adjusted_extra.scrollbar_track.track_x = 0;
725 adjusted_extra.scrollbar_track.track_y = 0;
726 break;
727 default:
728 break;
730 // Draw the theme controls using existing HDC-drawing code.
731 PaintDirect(&offscreen_canvas, part, state, adjusted_rect, adjusted_extra);
733 // Copy the pixels to a bitmap that has ref-counted pixel storage, which is
734 // necessary to have when drawing to a SkPicture.
735 const SkBitmap& hdc_bitmap =
736 offscreen_canvas.getDevice()->accessBitmap(false);
737 SkBitmap bitmap;
738 hdc_bitmap.copyTo(&bitmap, kN32_SkColorType);
740 // Post-process the pixels to fix up the alpha values (see big comment above).
741 const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder);
742 const int pixel_count = rect.width() * rect.height();
743 SkPMColor* pixels = bitmap.getAddr32(0, 0);
744 for (int i = 0; i < pixel_count; i++) {
745 if (pixels[i] == placeholder_value) {
746 // Pixel wasn't touched - make it fully transparent.
747 pixels[i] = SkPackARGB32(0, 0, 0, 0);
748 } else if (SkGetPackedA32(pixels[i]) == 0) {
749 // Pixel was touched but has incorrect alpha of 0, make it fully opaque.
750 pixels[i] = SkPackARGB32(0xFF,
751 SkGetPackedR32(pixels[i]),
752 SkGetPackedG32(pixels[i]),
753 SkGetPackedB32(pixels[i]));
757 // Draw the offscreen bitmap to the destination canvas.
758 canvas->drawBitmap(bitmap, rect.x(), rect.y());
761 HRESULT NativeThemeWin::GetThemePartSize(ThemeName theme_name,
762 HDC hdc,
763 int part_id,
764 int state_id,
765 RECT* rect,
766 int ts,
767 SIZE* size) const {
768 HANDLE handle = GetThemeHandle(theme_name);
769 return (handle && get_theme_part_size_) ?
770 get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size) :
771 E_NOTIMPL;
774 HRESULT NativeThemeWin::PaintButton(HDC hdc,
775 State state,
776 const ButtonExtraParams& extra,
777 int part_id,
778 int state_id,
779 RECT* rect) const {
780 HANDLE handle = GetThemeHandle(BUTTON);
781 if (handle && draw_theme_)
782 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
784 // Adjust classic_state based on part, state, and extras.
785 int classic_state = extra.classic_state;
786 switch (part_id) {
787 case BP_CHECKBOX:
788 classic_state |= DFCS_BUTTONCHECK;
789 break;
790 case BP_RADIOBUTTON:
791 classic_state |= DFCS_BUTTONRADIO;
792 break;
793 case BP_PUSHBUTTON:
794 classic_state |= DFCS_BUTTONPUSH;
795 break;
796 default:
797 NOTREACHED();
798 break;
801 switch (state) {
802 case kDisabled:
803 classic_state |= DFCS_INACTIVE;
804 break;
805 case kHovered:
806 case kNormal:
807 break;
808 case kPressed:
809 classic_state |= DFCS_PUSHED;
810 break;
811 case kNumStates:
812 NOTREACHED();
813 break;
816 if (extra.checked)
817 classic_state |= DFCS_CHECKED;
819 // Draw it manually.
820 // All pressed states have both low bits set, and no other states do.
821 const bool focused = ((state_id & ETS_FOCUSED) == ETS_FOCUSED);
822 const bool pressed = ((state_id & PBS_PRESSED) == PBS_PRESSED);
823 if ((BP_PUSHBUTTON == part_id) && (pressed || focused)) {
824 // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
825 // button itself is shrunk by 1 pixel.
826 HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
827 if (brush) {
828 FrameRect(hdc, rect, brush);
829 InflateRect(rect, -1, -1);
832 DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
834 // Draw the focus rectangle (the dotted line box) only on buttons. For radio
835 // and checkboxes, we let webkit draw the focus rectangle (orange glow).
836 if ((BP_PUSHBUTTON == part_id) && focused) {
837 // The focus rect is inside the button. The exact number of pixels depends
838 // on whether we're in classic mode or using uxtheme.
839 if (handle && get_theme_content_rect_) {
840 get_theme_content_rect_(handle, hdc, part_id, state_id, rect, rect);
841 } else {
842 InflateRect(rect, -GetSystemMetrics(SM_CXEDGE),
843 -GetSystemMetrics(SM_CYEDGE));
845 DrawFocusRect(hdc, rect);
848 // Classic theme doesn't support indeterminate checkboxes. We draw
849 // a recangle inside a checkbox like IE10 does.
850 if (part_id == BP_CHECKBOX && extra.indeterminate) {
851 RECT inner_rect = *rect;
852 // "4 / 13" is same as IE10 in classic theme.
853 int padding = (inner_rect.right - inner_rect.left) * 4 / 13;
854 InflateRect(&inner_rect, -padding, -padding);
855 int color_index = state == kDisabled ? COLOR_GRAYTEXT : COLOR_WINDOWTEXT;
856 FillRect(hdc, &inner_rect, GetSysColorBrush(color_index));
859 return S_OK;
862 HRESULT NativeThemeWin::PaintMenuSeparator(
863 HDC hdc,
864 const gfx::Rect& rect) const {
865 RECT rect_win = rect.ToRECT();
867 HANDLE handle = GetThemeHandle(MENU);
868 if (handle && draw_theme_) {
869 // Delta is needed for non-classic to move separator up slightly.
870 --rect_win.top;
871 --rect_win.bottom;
872 return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win,
873 NULL);
876 DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP);
877 return S_OK;
880 HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc,
881 const gfx::Rect& rect) const {
882 RECT rect_win = rect.ToRECT();
883 HANDLE handle = GetThemeHandle(MENU);
884 return (handle && draw_theme_) ?
885 draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, NULL) :
886 E_NOTIMPL;
889 HRESULT NativeThemeWin::PaintMenuArrow(
890 HDC hdc,
891 State state,
892 const gfx::Rect& rect,
893 const MenuArrowExtraParams& extra) const {
894 int state_id = MSM_NORMAL;
895 if (state == kDisabled)
896 state_id = MSM_DISABLED;
898 HANDLE handle = GetThemeHandle(MENU);
899 RECT rect_win = rect.ToRECT();
900 if (handle && draw_theme_) {
901 if (extra.pointing_right) {
902 return draw_theme_(handle, hdc, MENU_POPUPSUBMENU, state_id, &rect_win,
903 NULL);
905 // There is no way to tell the uxtheme API to draw a left pointing arrow; it
906 // doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they are
907 // needed for RTL locales on Vista. So use a memory DC and mirror the
908 // region with GDI's StretchBlt.
909 gfx::Rect r(rect);
910 base::win::ScopedCreateDC mem_dc(CreateCompatibleDC(hdc));
911 base::win::ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
912 r.height()));
913 base::win::ScopedSelectObject select_bitmap(mem_dc.Get(), mem_bitmap);
914 // Copy and horizontally mirror the background from hdc into mem_dc. Use
915 // a negative-width source rect, starting at the rightmost pixel.
916 StretchBlt(mem_dc.Get(), 0, 0, r.width(), r.height(),
917 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
918 // Draw the arrow.
919 RECT theme_rect = {0, 0, r.width(), r.height()};
920 HRESULT result = draw_theme_(handle, mem_dc.Get(), MENU_POPUPSUBMENU,
921 state_id, &theme_rect, NULL);
922 // Copy and mirror the result back into mem_dc.
923 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
924 mem_dc.Get(), r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
925 return result;
928 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
929 // left pointing arrow. This makes the following statement counterintuitive.
930 UINT pfc_state = extra.pointing_right ? DFCS_MENUARROW : DFCS_MENUARROWRIGHT;
931 return PaintFrameControl(hdc, rect, DFC_MENU, pfc_state, extra.is_selected,
932 state);
935 HRESULT NativeThemeWin::PaintMenuBackground(HDC hdc,
936 const gfx::Rect& rect) const {
937 HANDLE handle = GetThemeHandle(MENU);
938 RECT rect_win = rect.ToRECT();
939 if (handle && draw_theme_) {
940 HRESULT result = draw_theme_(handle, hdc, MENU_POPUPBACKGROUND, 0,
941 &rect_win, NULL);
942 FrameRect(hdc, &rect_win, GetSysColorBrush(COLOR_3DSHADOW));
943 return result;
946 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_MENU));
947 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT);
948 return S_OK;
951 HRESULT NativeThemeWin::PaintMenuCheck(
952 HDC hdc,
953 State state,
954 const gfx::Rect& rect,
955 const MenuCheckExtraParams& extra) const {
956 HANDLE handle = GetThemeHandle(MENU);
957 if (handle && draw_theme_) {
958 const int state_id = extra.is_radio ?
959 ((state == kDisabled) ? MC_BULLETDISABLED : MC_BULLETNORMAL) :
960 ((state == kDisabled) ? MC_CHECKMARKDISABLED : MC_CHECKMARKNORMAL);
961 RECT rect_win = rect.ToRECT();
962 return draw_theme_(handle, hdc, MENU_POPUPCHECK, state_id, &rect_win, NULL);
965 return PaintFrameControl(hdc, rect, DFC_MENU,
966 extra.is_radio ? DFCS_MENUBULLET : DFCS_MENUCHECK,
967 extra.is_selected, state);
970 HRESULT NativeThemeWin::PaintMenuCheckBackground(HDC hdc,
971 State state,
972 const gfx::Rect& rect) const {
973 HANDLE handle = GetThemeHandle(MENU);
974 if (!handle || !draw_theme_)
975 return S_OK; // Nothing to do for background.
977 int state_id = state == kDisabled ? MCB_DISABLED : MCB_NORMAL;
978 RECT rect_win = rect.ToRECT();
979 return draw_theme_(handle, hdc, MENU_POPUPCHECKBACKGROUND, state_id,
980 &rect_win, NULL);
983 HRESULT NativeThemeWin::PaintMenuItemBackground(
984 HDC hdc,
985 State state,
986 const gfx::Rect& rect,
987 const MenuItemExtraParams& extra) const {
988 HANDLE handle = GetThemeHandle(MENU);
989 RECT rect_win = rect.ToRECT();
990 int state_id = MPI_NORMAL;
991 switch (state) {
992 case kDisabled:
993 state_id = extra.is_selected ? MPI_DISABLEDHOT : MPI_DISABLED;
994 break;
995 case kHovered:
996 state_id = MPI_HOT;
997 break;
998 case kNormal:
999 break;
1000 case kPressed:
1001 case kNumStates:
1002 NOTREACHED();
1003 break;
1006 if (handle && draw_theme_)
1007 return draw_theme_(handle, hdc, MENU_POPUPITEM, state_id, &rect_win, NULL);
1009 if (extra.is_selected)
1010 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_HIGHLIGHT));
1011 return S_OK;
1014 HRESULT NativeThemeWin::PaintPushButton(HDC hdc,
1015 Part part,
1016 State state,
1017 const gfx::Rect& rect,
1018 const ButtonExtraParams& extra) const {
1019 int state_id = extra.is_default ? PBS_DEFAULTED : PBS_NORMAL;
1020 switch (state) {
1021 case kDisabled:
1022 state_id = PBS_DISABLED;
1023 break;
1024 case kHovered:
1025 state_id = PBS_HOT;
1026 break;
1027 case kNormal:
1028 break;
1029 case kPressed:
1030 state_id = PBS_PRESSED;
1031 break;
1032 case kNumStates:
1033 NOTREACHED();
1034 break;
1037 RECT rect_win = rect.ToRECT();
1038 return PaintButton(hdc, state, extra, BP_PUSHBUTTON, state_id, &rect_win);
1041 HRESULT NativeThemeWin::PaintRadioButton(HDC hdc,
1042 Part part,
1043 State state,
1044 const gfx::Rect& rect,
1045 const ButtonExtraParams& extra) const {
1046 int state_id = extra.checked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
1047 switch (state) {
1048 case kDisabled:
1049 state_id = extra.checked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
1050 break;
1051 case kHovered:
1052 state_id = extra.checked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
1053 break;
1054 case kNormal:
1055 break;
1056 case kPressed:
1057 state_id = extra.checked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
1058 break;
1059 case kNumStates:
1060 NOTREACHED();
1061 break;
1064 RECT rect_win = rect.ToRECT();
1065 return PaintButton(hdc, state, extra, BP_RADIOBUTTON, state_id, &rect_win);
1068 HRESULT NativeThemeWin::PaintCheckbox(HDC hdc,
1069 Part part,
1070 State state,
1071 const gfx::Rect& rect,
1072 const ButtonExtraParams& extra) const {
1073 int state_id = extra.checked ?
1074 CBS_CHECKEDNORMAL :
1075 (extra.indeterminate ? CBS_MIXEDNORMAL : CBS_UNCHECKEDNORMAL);
1076 switch (state) {
1077 case kDisabled:
1078 state_id = extra.checked ?
1079 CBS_CHECKEDDISABLED :
1080 (extra.indeterminate ? CBS_MIXEDDISABLED : CBS_UNCHECKEDDISABLED);
1081 break;
1082 case kHovered:
1083 state_id = extra.checked ?
1084 CBS_CHECKEDHOT :
1085 (extra.indeterminate ? CBS_MIXEDHOT : CBS_UNCHECKEDHOT);
1086 break;
1087 case kNormal:
1088 break;
1089 case kPressed:
1090 state_id = extra.checked ?
1091 CBS_CHECKEDPRESSED :
1092 (extra.indeterminate ? CBS_MIXEDPRESSED : CBS_UNCHECKEDPRESSED);
1093 break;
1094 case kNumStates:
1095 NOTREACHED();
1096 break;
1099 RECT rect_win = rect.ToRECT();
1100 return PaintButton(hdc, state, extra, BP_CHECKBOX, state_id, &rect_win);
1103 HRESULT NativeThemeWin::PaintMenuList(HDC hdc,
1104 State state,
1105 const gfx::Rect& rect,
1106 const MenuListExtraParams& extra) const {
1107 HANDLE handle = GetThemeHandle(MENULIST);
1108 RECT rect_win = rect.ToRECT();
1109 int state_id = CBXS_NORMAL;
1110 switch (state) {
1111 case kDisabled:
1112 state_id = CBXS_DISABLED;
1113 break;
1114 case kHovered:
1115 state_id = CBXS_HOT;
1116 break;
1117 case kNormal:
1118 break;
1119 case kPressed:
1120 state_id = CBXS_PRESSED;
1121 break;
1122 case kNumStates:
1123 NOTREACHED();
1124 break;
1127 if (handle && draw_theme_)
1128 return draw_theme_(handle, hdc, CP_DROPDOWNBUTTON, state_id, &rect_win,
1129 NULL);
1131 // Draw it manually.
1132 DrawFrameControl(hdc, &rect_win, DFC_SCROLL,
1133 DFCS_SCROLLCOMBOBOX | extra.classic_state);
1134 return S_OK;
1137 HRESULT NativeThemeWin::PaintScrollbarArrow(
1138 HDC hdc,
1139 Part part,
1140 State state,
1141 const gfx::Rect& rect,
1142 const ScrollbarArrowExtraParams& extra) const {
1143 static const int state_id_matrix[4][kNumStates] = {
1144 {ABS_DOWNDISABLED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNPRESSED},
1145 {ABS_LEFTDISABLED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTPRESSED},
1146 {ABS_RIGHTDISABLED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTPRESSED},
1147 {ABS_UPDISABLED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPPRESSED},
1149 HANDLE handle = GetThemeHandle(SCROLLBAR);
1150 RECT rect_win = rect.ToRECT();
1151 if (handle && draw_theme_) {
1152 int index = part - kScrollbarDownArrow;
1153 DCHECK_GE(index, 0);
1154 DCHECK_LT(static_cast<size_t>(index), arraysize(state_id_matrix));
1155 int state_id = state_id_matrix[index][state];
1157 // Hovering means that the cursor is over the scroolbar, but not over the
1158 // specific arrow itself. We don't want to show it "hot" mode, but only
1159 // in "hover" mode.
1160 if (state == kHovered && extra.is_hovering) {
1161 switch (part) {
1162 case kScrollbarDownArrow:
1163 state_id = ABS_DOWNHOVER;
1164 break;
1165 case kScrollbarLeftArrow:
1166 state_id = ABS_LEFTHOVER;
1167 break;
1168 case kScrollbarRightArrow:
1169 state_id = ABS_RIGHTHOVER;
1170 break;
1171 case kScrollbarUpArrow:
1172 state_id = ABS_UPHOVER;
1173 break;
1174 default:
1175 NOTREACHED();
1176 break;
1179 return PaintScaledTheme(handle, hdc, SBP_ARROWBTN, state_id, rect);
1182 int classic_state = DFCS_SCROLLDOWN;
1183 switch (part) {
1184 case kScrollbarDownArrow:
1185 break;
1186 case kScrollbarLeftArrow:
1187 classic_state = DFCS_SCROLLLEFT;
1188 break;
1189 case kScrollbarRightArrow:
1190 classic_state = DFCS_SCROLLRIGHT;
1191 break;
1192 case kScrollbarUpArrow:
1193 classic_state = DFCS_SCROLLUP;
1194 break;
1195 default:
1196 NOTREACHED();
1197 break;
1199 switch (state) {
1200 case kDisabled:
1201 classic_state |= DFCS_INACTIVE;
1202 break;
1203 case kHovered:
1204 classic_state |= DFCS_HOT;
1205 break;
1206 case kNormal:
1207 break;
1208 case kPressed:
1209 classic_state |= DFCS_PUSHED;
1210 break;
1211 case kNumStates:
1212 NOTREACHED();
1213 break;
1215 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, classic_state);
1216 return S_OK;
1219 HRESULT NativeThemeWin::PaintScrollbarThumb(
1220 HDC hdc,
1221 Part part,
1222 State state,
1223 const gfx::Rect& rect,
1224 const ScrollbarThumbExtraParams& extra) const {
1225 HANDLE handle = GetThemeHandle(SCROLLBAR);
1226 RECT rect_win = rect.ToRECT();
1228 int part_id = SBP_THUMBBTNVERT;
1229 switch (part) {
1230 case kScrollbarHorizontalThumb:
1231 part_id = SBP_THUMBBTNHORZ;
1232 break;
1233 case kScrollbarVerticalThumb:
1234 break;
1235 case kScrollbarHorizontalGripper:
1236 part_id = SBP_GRIPPERHORZ;
1237 break;
1238 case kScrollbarVerticalGripper:
1239 part_id = SBP_GRIPPERVERT;
1240 break;
1241 default:
1242 NOTREACHED();
1243 break;
1246 int state_id = SCRBS_NORMAL;
1247 switch (state) {
1248 case kDisabled:
1249 state_id = SCRBS_DISABLED;
1250 break;
1251 case kHovered:
1252 state_id = extra.is_hovering ? SCRBS_HOVER : SCRBS_HOT;
1253 break;
1254 case kNormal:
1255 break;
1256 case kPressed:
1257 state_id = SCRBS_PRESSED;
1258 break;
1259 case kNumStates:
1260 NOTREACHED();
1261 break;
1264 if (handle && draw_theme_)
1265 return PaintScaledTheme(handle, hdc, part_id, state_id, rect);
1267 // Draw it manually.
1268 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
1269 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_MIDDLE);
1270 // Classic mode doesn't have a gripper.
1271 return S_OK;
1274 HRESULT NativeThemeWin::PaintScrollbarTrack(
1275 SkCanvas* canvas,
1276 HDC hdc,
1277 Part part,
1278 State state,
1279 const gfx::Rect& rect,
1280 const ScrollbarTrackExtraParams& extra) const {
1281 HANDLE handle = GetThemeHandle(SCROLLBAR);
1282 RECT rect_win = rect.ToRECT();
1284 const int part_id = extra.is_upper ?
1285 ((part == kScrollbarHorizontalTrack) ?
1286 SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT) :
1287 ((part == kScrollbarHorizontalTrack) ?
1288 SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT);
1290 int state_id = SCRBS_NORMAL;
1291 switch (state) {
1292 case kDisabled:
1293 state_id = SCRBS_DISABLED;
1294 break;
1295 case kHovered:
1296 state_id = SCRBS_HOVER;
1297 break;
1298 case kNormal:
1299 break;
1300 case kPressed:
1301 state_id = SCRBS_PRESSED;
1302 break;
1303 case kNumStates:
1304 NOTREACHED();
1305 break;
1308 if (handle && draw_theme_)
1309 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL);
1311 // Draw it manually.
1312 if ((system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_3DFACE]) &&
1313 (system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_WINDOW])) {
1314 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
1315 } else {
1316 SkPaint paint;
1317 RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width,
1318 extra.track_height).ToRECT();
1319 SetCheckerboardShader(&paint, align_rect);
1320 canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint);
1322 if (extra.classic_state & DFCS_PUSHED)
1323 InvertRect(hdc, &rect_win);
1324 return S_OK;
1327 HRESULT NativeThemeWin::PaintSpinButton(
1328 HDC hdc,
1329 Part part,
1330 State state,
1331 const gfx::Rect& rect,
1332 const InnerSpinButtonExtraParams& extra) const {
1333 HANDLE handle = GetThemeHandle(SPIN);
1334 RECT rect_win = rect.ToRECT();
1335 int part_id = extra.spin_up ? SPNP_UP : SPNP_DOWN;
1336 int state_id = extra.spin_up ? UPS_NORMAL : DNS_NORMAL;
1337 switch (state) {
1338 case kDisabled:
1339 state_id = extra.spin_up ? UPS_DISABLED : DNS_DISABLED;
1340 break;
1341 case kHovered:
1342 state_id = extra.spin_up ? UPS_HOT : DNS_HOT;
1343 break;
1344 case kNormal:
1345 break;
1346 case kPressed:
1347 state_id = extra.spin_up ? UPS_PRESSED : DNS_PRESSED;
1348 break;
1349 case kNumStates:
1350 NOTREACHED();
1351 break;
1354 if (handle && draw_theme_)
1355 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL);
1356 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, extra.classic_state);
1357 return S_OK;
1360 HRESULT NativeThemeWin::PaintTrackbar(
1361 SkCanvas* canvas,
1362 HDC hdc,
1363 Part part,
1364 State state,
1365 const gfx::Rect& rect,
1366 const TrackbarExtraParams& extra) const {
1367 const int part_id = extra.vertical ?
1368 ((part == kTrackbarTrack) ? TKP_TRACKVERT : TKP_THUMBVERT) :
1369 ((part == kTrackbarTrack) ? TKP_TRACK : TKP_THUMBBOTTOM);
1371 int state_id = TUS_NORMAL;
1372 switch (state) {
1373 case kDisabled:
1374 state_id = TUS_DISABLED;
1375 break;
1376 case kHovered:
1377 state_id = TUS_HOT;
1378 break;
1379 case kNormal:
1380 break;
1381 case kPressed:
1382 state_id = TUS_PRESSED;
1383 break;
1384 case kNumStates:
1385 NOTREACHED();
1386 break;
1389 // Make the channel be 4 px thick in the center of the supplied rect. (4 px
1390 // matches what XP does in various menus; GetThemePartSize() doesn't seem to
1391 // return good values here.)
1392 RECT rect_win = rect.ToRECT();
1393 RECT channel_rect = rect.ToRECT();
1394 const int channel_thickness = 4;
1395 if (part_id == TKP_TRACK) {
1396 channel_rect.top +=
1397 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2);
1398 channel_rect.bottom = channel_rect.top + channel_thickness;
1399 } else if (part_id == TKP_TRACKVERT) {
1400 channel_rect.left +=
1401 ((channel_rect.right - channel_rect.left - channel_thickness) / 2);
1402 channel_rect.right = channel_rect.left + channel_thickness;
1403 } // else this isn't actually a channel, so |channel_rect| == |rect|.
1405 HANDLE handle = GetThemeHandle(TRACKBAR);
1406 if (handle && draw_theme_)
1407 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL);
1409 // Classic mode, draw it manually.
1410 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) {
1411 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT);
1412 } else if (part_id == TKP_THUMBVERT) {
1413 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE);
1414 } else {
1415 // Split rect into top and bottom pieces.
1416 RECT top_section = rect.ToRECT();
1417 RECT bottom_section = rect.ToRECT();
1418 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2);
1419 bottom_section.top = top_section.bottom;
1420 DrawEdge(hdc, &top_section, EDGE_RAISED,
1421 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
1423 // Split triangular piece into two diagonals.
1424 RECT& left_half = bottom_section;
1425 RECT right_half = bottom_section;
1426 right_half.left += ((bottom_section.right - bottom_section.left) / 2);
1427 left_half.right = right_half.left;
1428 DrawEdge(hdc, &left_half, EDGE_RAISED,
1429 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
1430 DrawEdge(hdc, &right_half, EDGE_RAISED,
1431 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
1433 // If the button is pressed, draw hatching.
1434 if (extra.classic_state & DFCS_PUSHED) {
1435 SkPaint paint;
1436 SetCheckerboardShader(&paint, rect_win);
1438 // Fill all three pieces with the pattern.
1439 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint);
1441 SkScalar left_triangle_top = SkIntToScalar(left_half.top);
1442 SkScalar left_triangle_right = SkIntToScalar(left_half.right);
1443 SkPath left_triangle;
1444 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top);
1445 left_triangle.lineTo(left_triangle_right, left_triangle_top);
1446 left_triangle.lineTo(left_triangle_right,
1447 SkIntToScalar(left_half.bottom));
1448 left_triangle.close();
1449 canvas->drawPath(left_triangle, paint);
1451 SkScalar right_triangle_left = SkIntToScalar(right_half.left);
1452 SkScalar right_triangle_top = SkIntToScalar(right_half.top);
1453 SkPath right_triangle;
1454 right_triangle.moveTo(right_triangle_left, right_triangle_top);
1455 right_triangle.lineTo(SkIntToScalar(right_half.right),
1456 right_triangle_top);
1457 right_triangle.lineTo(right_triangle_left,
1458 SkIntToScalar(right_half.bottom));
1459 right_triangle.close();
1460 canvas->drawPath(right_triangle, paint);
1463 return S_OK;
1466 HRESULT NativeThemeWin::PaintProgressBar(
1467 HDC hdc,
1468 const gfx::Rect& rect,
1469 const ProgressBarExtraParams& extra) const {
1470 // There is no documentation about the animation speed, frame-rate, nor
1471 // size of moving overlay of the indeterminate progress bar.
1472 // So we just observed real-world programs and guessed following parameters.
1473 const int kDeterminateOverlayPixelsPerSecond = 300;
1474 const int kDeterminateOverlayWidth = 120;
1475 const int kIndeterminateOverlayPixelsPerSecond = 175;
1476 const int kVistaIndeterminateOverlayWidth = 120;
1477 const int kXPIndeterminateOverlayWidth = 55;
1478 // The thickness of the bar frame inside |value_rect|
1479 const int kXPBarPadding = 3;
1481 RECT bar_rect = rect.ToRECT();
1482 RECT value_rect = gfx::Rect(extra.value_rect_x,
1483 extra.value_rect_y,
1484 extra.value_rect_width,
1485 extra.value_rect_height).ToRECT();
1487 HANDLE handle = GetThemeHandle(PROGRESS);
1488 if (!handle || !draw_theme_ || !draw_theme_ex_) {
1489 FillRect(hdc, &bar_rect, GetSysColorBrush(COLOR_BTNFACE));
1490 FillRect(hdc, &value_rect, GetSysColorBrush(COLOR_BTNSHADOW));
1491 DrawEdge(hdc, &bar_rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1492 return S_OK;
1495 draw_theme_(handle, hdc, PP_BAR, 0, &bar_rect, NULL);
1497 bool pre_vista = base::win::GetVersion() < base::win::VERSION_VISTA;
1498 int bar_width = bar_rect.right - bar_rect.left;
1499 if (!extra.determinate) {
1500 // The glossy overlay for the indeterminate progress bar has a small pause
1501 // after each animation. We emulate this by adding an invisible margin the
1502 // animation has to traverse.
1503 int width_with_margin = bar_width + kIndeterminateOverlayPixelsPerSecond;
1504 int overlay_width = pre_vista ?
1505 kXPIndeterminateOverlayWidth : kVistaIndeterminateOverlayWidth;
1506 RECT overlay_rect = bar_rect;
1507 overlay_rect.left += ComputeAnimationProgress(
1508 width_with_margin, overlay_width, kIndeterminateOverlayPixelsPerSecond,
1509 extra.animated_seconds);
1510 overlay_rect.right = overlay_rect.left + overlay_width;
1511 if (pre_vista) {
1512 RECT shrunk_rect = InsetRect(&overlay_rect, kXPBarPadding);
1513 RECT shrunk_bar_rect = InsetRect(&bar_rect, kXPBarPadding);
1514 draw_theme_(handle, hdc, PP_CHUNK, 0, &shrunk_rect, &shrunk_bar_rect);
1515 } else {
1516 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &bar_rect);
1518 return S_OK;
1521 // We care about the direction here because PP_CHUNK painting is asymmetric.
1522 // TODO(morrita): This RTL guess can be wrong. We should pass in the
1523 // direction from WebKit.
1524 const DTBGOPTS value_draw_options = {
1525 sizeof(DTBGOPTS),
1526 (bar_rect.right == value_rect.right && bar_rect.left != value_rect.left) ?
1527 DTBG_MIRRORDC : 0u,
1528 bar_rect
1530 if (pre_vista) {
1531 // On XP, the progress bar is chunk-style and has no glossy effect. We need
1532 // to shrink the destination rect to fit the part inside the bar with an
1533 // appropriate margin.
1534 RECT shrunk_value_rect = InsetRect(&value_rect, kXPBarPadding);
1535 draw_theme_ex_(handle, hdc, PP_CHUNK, 0, &shrunk_value_rect,
1536 &value_draw_options);
1537 } else {
1538 // On Vista or later, the progress bar part has a single-block value part
1539 // and a glossy effect. The value part has exactly same height as the bar
1540 // part, so we don't need to shrink the rect.
1541 draw_theme_ex_(handle, hdc, PP_FILL, 0, &value_rect, &value_draw_options);
1543 RECT overlay_rect = value_rect;
1544 overlay_rect.left += ComputeAnimationProgress(
1545 bar_width, kDeterminateOverlayWidth, kDeterminateOverlayPixelsPerSecond,
1546 extra.animated_seconds);
1547 overlay_rect.right = overlay_rect.left + kDeterminateOverlayWidth;
1548 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &value_rect);
1550 return S_OK;
1553 HRESULT NativeThemeWin::PaintWindowResizeGripper(HDC hdc,
1554 const gfx::Rect& rect) const {
1555 HANDLE handle = GetThemeHandle(STATUS);
1556 RECT rect_win = rect.ToRECT();
1557 if (handle && draw_theme_) {
1558 // Paint the status bar gripper. There doesn't seem to be a standard
1559 // gripper in Windows for the space between scrollbars. This is pretty
1560 // close, but it's supposed to be painted over a status bar.
1561 return draw_theme_(handle, hdc, SP_GRIPPER, 0, &rect_win, NULL);
1564 // Draw a windows classic scrollbar gripper.
1565 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
1566 return S_OK;
1569 HRESULT NativeThemeWin::PaintTabPanelBackground(HDC hdc,
1570 const gfx::Rect& rect) const {
1571 HANDLE handle = GetThemeHandle(TAB);
1572 RECT rect_win = rect.ToRECT();
1573 if (handle && draw_theme_)
1574 return draw_theme_(handle, hdc, TABP_BODY, 0, &rect_win, NULL);
1576 // Classic just renders a flat color background.
1577 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
1578 return S_OK;
1581 HRESULT NativeThemeWin::PaintTextField(
1582 HDC hdc,
1583 Part part,
1584 State state,
1585 const gfx::Rect& rect,
1586 const TextFieldExtraParams& extra) const {
1587 int state_id = ETS_NORMAL;
1588 switch (state) {
1589 case kDisabled:
1590 state_id = ETS_DISABLED;
1591 break;
1592 case kHovered:
1593 state_id = ETS_HOT;
1594 break;
1595 case kNormal:
1596 if (extra.is_read_only)
1597 state_id = ETS_READONLY;
1598 else if (extra.is_focused)
1599 state_id = ETS_FOCUSED;
1600 break;
1601 case kPressed:
1602 state_id = ETS_SELECTED;
1603 break;
1604 case kNumStates:
1605 NOTREACHED();
1606 break;
1609 RECT rect_win = rect.ToRECT();
1610 return PaintTextField(hdc, EP_EDITTEXT, state_id, extra.classic_state,
1611 &rect_win,
1612 skia::SkColorToCOLORREF(extra.background_color),
1613 extra.fill_content_area, extra.draw_edges);
1616 HRESULT NativeThemeWin::PaintTextField(HDC hdc,
1617 int part_id,
1618 int state_id,
1619 int classic_state,
1620 RECT* rect,
1621 COLORREF color,
1622 bool fill_content_area,
1623 bool draw_edges) const {
1624 // TODO(ojan): http://b/1210017 Figure out how to give the ability to
1625 // exclude individual edges from being drawn.
1627 HANDLE handle = GetThemeHandle(TEXTFIELD);
1628 // TODO(mpcomplete): can we detect if the color is specified by the user,
1629 // and if not, just use the system color?
1630 // CreateSolidBrush() accepts a RGB value but alpha must be 0.
1631 base::win::ScopedGDIObject<HBRUSH> bg_brush(CreateSolidBrush(color));
1632 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
1633 // draw_theme_ex_ is NULL and draw_theme_ is non-null.
1634 if (!handle || (!draw_theme_ex_ && (!draw_theme_ || !draw_edges))) {
1635 // Draw it manually.
1636 if (draw_edges)
1637 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1639 if (fill_content_area) {
1640 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
1641 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
1643 return S_OK;
1646 static const DTBGOPTS omit_border_options = {
1647 sizeof(DTBGOPTS),
1648 DTBG_OMITBORDER,
1649 { 0, 0, 0, 0 }
1651 HRESULT hr = draw_theme_ex_ ?
1652 draw_theme_ex_(handle, hdc, part_id, state_id, rect,
1653 draw_edges ? NULL : &omit_border_options) :
1654 draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
1656 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
1657 if (fill_content_area && get_theme_content_rect_) {
1658 RECT content_rect;
1659 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
1660 &content_rect);
1661 FillRect(hdc, &content_rect, bg_brush);
1663 return hr;
1666 HRESULT NativeThemeWin::PaintScaledTheme(HANDLE theme,
1667 HDC hdc,
1668 int part_id,
1669 int state_id,
1670 const gfx::Rect& rect) const {
1671 // Correct the scaling and positioning of sub-components such as scrollbar
1672 // arrows and thumb grippers in the event that the world transform applies
1673 // scaling (e.g. in high-DPI mode).
1674 XFORM save_transform;
1675 if (GetWorldTransform(hdc, &save_transform)) {
1676 float scale = save_transform.eM11;
1677 if (scale != 1 && save_transform.eM12 == 0) {
1678 ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
1679 gfx::Rect scaled_rect = gfx::ScaleToEnclosedRect(rect, scale);
1680 scaled_rect.Offset(save_transform.eDx, save_transform.eDy);
1681 RECT bounds = scaled_rect.ToRECT();
1682 HRESULT result = draw_theme_(theme, hdc, part_id, state_id, &bounds,
1683 NULL);
1684 SetWorldTransform(hdc, &save_transform);
1685 return result;
1688 RECT bounds = rect.ToRECT();
1689 return draw_theme_(theme, hdc, part_id, state_id, &bounds, NULL);
1692 // static
1693 NativeThemeWin::ThemeName NativeThemeWin::GetThemeName(Part part) {
1694 switch (part) {
1695 case kCheckbox:
1696 case kPushButton:
1697 case kRadio:
1698 return BUTTON;
1699 case kInnerSpinButton:
1700 return SPIN;
1701 case kMenuList:
1702 case kMenuCheck:
1703 case kMenuPopupArrow:
1704 case kMenuPopupGutter:
1705 case kMenuPopupSeparator:
1706 return MENU;
1707 case kProgressBar:
1708 return PROGRESS;
1709 case kScrollbarDownArrow:
1710 case kScrollbarLeftArrow:
1711 case kScrollbarRightArrow:
1712 case kScrollbarUpArrow:
1713 case kScrollbarHorizontalThumb:
1714 case kScrollbarVerticalThumb:
1715 case kScrollbarHorizontalTrack:
1716 case kScrollbarVerticalTrack:
1717 return SCROLLBAR;
1718 case kSliderTrack:
1719 case kSliderThumb:
1720 return TRACKBAR;
1721 case kTextField:
1722 return TEXTFIELD;
1723 case kWindowResizeGripper:
1724 return STATUS;
1725 case kComboboxArrow:
1726 case kMenuCheckBackground:
1727 case kMenuPopupBackground:
1728 case kMenuItemBackground:
1729 case kScrollbarHorizontalGripper:
1730 case kScrollbarVerticalGripper:
1731 case kScrollbarCorner:
1732 case kTabPanelBackground:
1733 case kTrackbarThumb:
1734 case kTrackbarTrack:
1735 case kMaxPart:
1736 NOTREACHED();
1738 return LAST;
1741 // static
1742 int NativeThemeWin::GetWindowsPart(Part part,
1743 State state,
1744 const ExtraParams& extra) {
1745 switch (part) {
1746 case kCheckbox:
1747 return BP_CHECKBOX;
1748 case kMenuCheck:
1749 return MENU_POPUPCHECK;
1750 case kMenuPopupArrow:
1751 return MENU_POPUPSUBMENU;
1752 case kMenuPopupGutter:
1753 return MENU_POPUPGUTTER;
1754 case kMenuPopupSeparator:
1755 return MENU_POPUPSEPARATOR;
1756 case kPushButton:
1757 return BP_PUSHBUTTON;
1758 case kRadio:
1759 return BP_RADIOBUTTON;
1760 case kScrollbarDownArrow:
1761 case kScrollbarLeftArrow:
1762 case kScrollbarRightArrow:
1763 case kScrollbarUpArrow:
1764 return SBP_ARROWBTN;
1765 case kScrollbarHorizontalThumb:
1766 return SBP_THUMBBTNHORZ;
1767 case kScrollbarVerticalThumb:
1768 return SBP_THUMBBTNVERT;
1769 case kWindowResizeGripper:
1770 return SP_GRIPPER;
1771 case kComboboxArrow:
1772 case kInnerSpinButton:
1773 case kMenuList:
1774 case kMenuCheckBackground:
1775 case kMenuPopupBackground:
1776 case kMenuItemBackground:
1777 case kProgressBar:
1778 case kScrollbarHorizontalTrack:
1779 case kScrollbarVerticalTrack:
1780 case kScrollbarHorizontalGripper:
1781 case kScrollbarVerticalGripper:
1782 case kScrollbarCorner:
1783 case kSliderTrack:
1784 case kSliderThumb:
1785 case kTabPanelBackground:
1786 case kTextField:
1787 case kTrackbarThumb:
1788 case kTrackbarTrack:
1789 case kMaxPart:
1790 NOTREACHED();
1792 return 0;
1795 int NativeThemeWin::GetWindowsState(Part part,
1796 State state,
1797 const ExtraParams& extra) {
1798 switch (part) {
1799 case kCheckbox:
1800 switch (state) {
1801 case kDisabled:
1802 return CBS_UNCHECKEDDISABLED;
1803 case kHovered:
1804 return CBS_UNCHECKEDHOT;
1805 case kNormal:
1806 return CBS_UNCHECKEDNORMAL;
1807 case kPressed:
1808 return CBS_UNCHECKEDPRESSED;
1809 case kNumStates:
1810 NOTREACHED();
1811 return 0;
1813 case kMenuCheck:
1814 switch (state) {
1815 case kDisabled:
1816 return extra.menu_check.is_radio ?
1817 MC_BULLETDISABLED : MC_CHECKMARKDISABLED;
1818 case kHovered:
1819 case kNormal:
1820 case kPressed:
1821 return extra.menu_check.is_radio ?
1822 MC_BULLETNORMAL : MC_CHECKMARKNORMAL;
1823 case kNumStates:
1824 NOTREACHED();
1825 return 0;
1827 case kMenuPopupArrow:
1828 case kMenuPopupGutter:
1829 case kMenuPopupSeparator:
1830 switch (state) {
1831 case kDisabled:
1832 return MBI_DISABLED;
1833 case kHovered:
1834 return MBI_HOT;
1835 case kNormal:
1836 return MBI_NORMAL;
1837 case kPressed:
1838 return MBI_PUSHED;
1839 case kNumStates:
1840 NOTREACHED();
1841 return 0;
1843 case kPushButton:
1844 switch (state) {
1845 case kDisabled:
1846 return PBS_DISABLED;
1847 case kHovered:
1848 return PBS_HOT;
1849 case kNormal:
1850 return PBS_NORMAL;
1851 case kPressed:
1852 return PBS_PRESSED;
1853 case kNumStates:
1854 NOTREACHED();
1855 return 0;
1857 case kRadio:
1858 switch (state) {
1859 case kDisabled:
1860 return RBS_UNCHECKEDDISABLED;
1861 case kHovered:
1862 return RBS_UNCHECKEDHOT;
1863 case kNormal:
1864 return RBS_UNCHECKEDNORMAL;
1865 case kPressed:
1866 return RBS_UNCHECKEDPRESSED;
1867 case kNumStates:
1868 NOTREACHED();
1869 return 0;
1871 case kScrollbarDownArrow:
1872 switch (state) {
1873 case kDisabled:
1874 return ABS_DOWNDISABLED;
1875 case kHovered:
1876 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1877 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1878 ABS_DOWNHOT : ABS_DOWNHOVER;
1879 case kNormal:
1880 return ABS_DOWNNORMAL;
1881 case kPressed:
1882 return ABS_DOWNPRESSED;
1883 case kNumStates:
1884 NOTREACHED();
1885 return 0;
1887 case kScrollbarLeftArrow:
1888 switch (state) {
1889 case kDisabled:
1890 return ABS_LEFTDISABLED;
1891 case kHovered:
1892 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1893 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1894 ABS_LEFTHOT : ABS_LEFTHOVER;
1895 case kNormal:
1896 return ABS_LEFTNORMAL;
1897 case kPressed:
1898 return ABS_LEFTPRESSED;
1899 case kNumStates:
1900 NOTREACHED();
1901 return 0;
1903 case kScrollbarRightArrow:
1904 switch (state) {
1905 case kDisabled:
1906 return ABS_RIGHTDISABLED;
1907 case kHovered:
1908 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1909 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1910 ABS_RIGHTHOT : ABS_RIGHTHOVER;
1911 case kNormal:
1912 return ABS_RIGHTNORMAL;
1913 case kPressed:
1914 return ABS_RIGHTPRESSED;
1915 case kNumStates:
1916 NOTREACHED();
1917 return 0;
1919 break;
1920 case kScrollbarUpArrow:
1921 switch (state) {
1922 case kDisabled:
1923 return ABS_UPDISABLED;
1924 case kHovered:
1925 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit.
1926 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1927 ABS_UPHOT : ABS_UPHOVER;
1928 case kNormal:
1929 return ABS_UPNORMAL;
1930 case kPressed:
1931 return ABS_UPPRESSED;
1932 case kNumStates:
1933 NOTREACHED();
1934 return 0;
1936 break;
1937 case kScrollbarHorizontalThumb:
1938 case kScrollbarVerticalThumb:
1939 switch (state) {
1940 case kDisabled:
1941 return SCRBS_DISABLED;
1942 case kHovered:
1943 // Mimic WebKit's behaviour in ScrollbarThemeChromiumWin.cpp.
1944 return base::win::GetVersion() < base::win::VERSION_VISTA ?
1945 SCRBS_HOT : SCRBS_HOVER;
1946 case kNormal:
1947 return SCRBS_NORMAL;
1948 case kPressed:
1949 return SCRBS_PRESSED;
1950 case kNumStates:
1951 NOTREACHED();
1952 return 0;
1954 case kWindowResizeGripper:
1955 switch (state) {
1956 case kDisabled:
1957 case kHovered:
1958 case kNormal:
1959 case kPressed:
1960 return 1; // gripper has no windows state
1961 case kNumStates:
1962 NOTREACHED();
1963 return 0;
1965 case kComboboxArrow:
1966 case kInnerSpinButton:
1967 case kMenuList:
1968 case kMenuCheckBackground:
1969 case kMenuPopupBackground:
1970 case kMenuItemBackground:
1971 case kProgressBar:
1972 case kScrollbarHorizontalTrack:
1973 case kScrollbarVerticalTrack:
1974 case kScrollbarHorizontalGripper:
1975 case kScrollbarVerticalGripper:
1976 case kScrollbarCorner:
1977 case kSliderTrack:
1978 case kSliderThumb:
1979 case kTabPanelBackground:
1980 case kTextField:
1981 case kTrackbarThumb:
1982 case kTrackbarTrack:
1983 case kMaxPart:
1984 NOTREACHED();
1986 return 0;
1989 HRESULT NativeThemeWin::GetThemeInt(ThemeName theme,
1990 int part_id,
1991 int state_id,
1992 int prop_id,
1993 int *value) const {
1994 HANDLE handle = GetThemeHandle(theme);
1995 return (handle && get_theme_int_) ?
1996 get_theme_int_(handle, part_id, state_id, prop_id, value) : E_NOTIMPL;
1999 HRESULT NativeThemeWin::PaintFrameControl(HDC hdc,
2000 const gfx::Rect& rect,
2001 UINT type,
2002 UINT state,
2003 bool is_selected,
2004 State control_state) const {
2005 const int width = rect.width();
2006 const int height = rect.height();
2008 // DrawFrameControl for menu arrow/check wants a monochrome bitmap.
2009 base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
2011 if (mask_bitmap == NULL)
2012 return E_OUTOFMEMORY;
2014 base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(NULL));
2015 base::win::ScopedSelectObject select_bitmap(bitmap_dc.Get(), mask_bitmap);
2016 RECT local_rect = { 0, 0, width, height };
2017 DrawFrameControl(bitmap_dc.Get(), &local_rect, type, state);
2019 // We're going to use BitBlt with a b&w mask. This results in using the dest
2020 // dc's text color for the black bits in the mask, and the dest dc's
2021 // background color for the white bits in the mask. DrawFrameControl draws the
2022 // check in black, and the background in white.
2023 int bg_color_key = COLOR_MENU;
2024 int text_color_key = COLOR_MENUTEXT;
2025 switch (control_state) {
2026 case kDisabled:
2027 bg_color_key = is_selected ? COLOR_HIGHLIGHT : COLOR_MENU;
2028 text_color_key = COLOR_GRAYTEXT;
2029 break;
2030 case kHovered:
2031 bg_color_key = COLOR_HIGHLIGHT;
2032 text_color_key = COLOR_HIGHLIGHTTEXT;
2033 break;
2034 case kNormal:
2035 break;
2036 case kPressed:
2037 case kNumStates:
2038 NOTREACHED();
2039 break;
2041 COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key));
2042 COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key));
2043 BitBlt(hdc, rect.x(), rect.y(), width, height, bitmap_dc.Get(), 0, 0,
2044 SRCCOPY);
2045 SetBkColor(hdc, old_bg_color);
2046 SetTextColor(hdc, old_text_color);
2048 return S_OK;
2051 HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const {
2052 if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
2053 return 0;
2055 if (theme_handles_[theme_name])
2056 return theme_handles_[theme_name];
2058 // Not found, try to load it.
2059 HANDLE handle = 0;
2060 switch (theme_name) {
2061 case BUTTON:
2062 handle = open_theme_(NULL, L"Button");
2063 break;
2064 case LIST:
2065 handle = open_theme_(NULL, L"Listview");
2066 break;
2067 case MENU:
2068 handle = open_theme_(NULL, L"Menu");
2069 break;
2070 case MENULIST:
2071 handle = open_theme_(NULL, L"Combobox");
2072 break;
2073 case SCROLLBAR:
2074 handle = open_theme_(NULL, L"Scrollbar");
2075 break;
2076 case STATUS:
2077 handle = open_theme_(NULL, L"Status");
2078 break;
2079 case TAB:
2080 handle = open_theme_(NULL, L"Tab");
2081 break;
2082 case TEXTFIELD:
2083 handle = open_theme_(NULL, L"Edit");
2084 break;
2085 case TRACKBAR:
2086 handle = open_theme_(NULL, L"Trackbar");
2087 break;
2088 case WINDOW:
2089 handle = open_theme_(NULL, L"Window");
2090 break;
2091 case PROGRESS:
2092 handle = open_theme_(NULL, L"Progress");
2093 break;
2094 case SPIN:
2095 handle = open_theme_(NULL, L"Spin");
2096 break;
2097 case LAST:
2098 NOTREACHED();
2099 break;
2101 theme_handles_[theme_name] = handle;
2102 return handle;
2105 } // namespace ui