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_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
   2070