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