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