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