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