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