Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc.
      3  * Copyright (C) 2009 Kenneth Rohde Christiansen
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     18  * Boston, MA 02111-1307, USA.
     19  *
     20  */
     21 
     22 #include "config.h"
     23 #include "RenderThemeWin.h"
     24 
     25 #include "CSSValueKeywords.h"
     26 #include "Element.h"
     27 #include "Frame.h"
     28 #include "GraphicsContext.h"
     29 #include "RenderSlider.h"
     30 #include "Settings.h"
     31 #include "SoftLinking.h"
     32 #include "SystemInfo.h"
     33 #include "UserAgentStyleSheets.h"
     34 
     35 #if ENABLE(VIDEO)
     36 #include "RenderMediaControls.h"
     37 #endif
     38 
     39 #include <tchar.h>
     40 
     41 /*
     42  * The following constants are used to determine how a widget is drawn using
     43  * Windows' Theme API. For more information on theme parts and states see
     44  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
     45  */
     46 
     47 // Generic state constants
     48 #define TS_NORMAL    1
     49 #define TS_HOVER     2
     50 #define TS_ACTIVE    3
     51 #define TS_DISABLED  4
     52 #define TS_FOCUSED   5
     53 
     54 // Button constants
     55 #define BP_BUTTON    1
     56 #define BP_RADIO     2
     57 #define BP_CHECKBOX  3
     58 
     59 // Textfield constants
     60 #define TFP_TEXTFIELD 1
     61 #define EP_EDITBORDER_NOSCROLL 6
     62 #define TFS_READONLY  6
     63 
     64 // ComboBox constants (from vsstyle.h)
     65 #define CP_DROPDOWNBUTTON 1
     66 #define CP_BORDER 4
     67 #define CP_READONLY 5
     68 #define CP_DROPDOWNBUTTONRIGHT 6
     69 
     70 // TrackBar (slider) parts
     71 #define TKP_TRACK       1
     72 #define TKP_TRACKVERT   2
     73 
     74 // TrackBar (slider) thumb parts
     75 #define TKP_THUMBBOTTOM 4
     76 #define TKP_THUMBTOP    5
     77 #define TKP_THUMBLEFT   7
     78 #define TKP_THUMBRIGHT  8
     79 
     80 // Trackbar (slider) thumb states
     81 #define TUS_NORMAL      1
     82 #define TUS_HOT         2
     83 #define TUS_PRESSED     3
     84 #define TUS_FOCUSED     4
     85 #define TUS_DISABLED    5
     86 
     87 // button states
     88 #define PBS_NORMAL      1
     89 #define PBS_HOT         2
     90 #define PBS_PRESSED     3
     91 #define PBS_DISABLED    4
     92 #define PBS_DEFAULTED   5
     93 
     94 SOFT_LINK_LIBRARY(uxtheme)
     95 SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
     96 SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
     97 SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
     98 SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
     99 SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
    100 
    101 static bool haveTheme;
    102 
    103 static const unsigned vistaMenuListButtonOutset = 1;
    104 
    105 using namespace std;
    106 
    107 namespace WebCore {
    108 
    109 // This is the fixed width IE and Firefox use for buttons on dropdown menus
    110 static const int dropDownButtonWidth = 17;
    111 
    112 static const int shell32MagnifierIconIndex = 22;
    113 
    114 // Default font size to match Firefox.
    115 static const float defaultControlFontPixelSize = 13;
    116 
    117 static const float defaultCancelButtonSize = 9;
    118 static const float minCancelButtonSize = 5;
    119 static const float maxCancelButtonSize = 21;
    120 static const float defaultSearchFieldResultsDecorationSize = 13;
    121 static const float minSearchFieldResultsDecorationSize = 9;
    122 static const float maxSearchFieldResultsDecorationSize = 30;
    123 static const float defaultSearchFieldResultsButtonWidth = 18;
    124 
    125 static bool gWebKitIsBeingUnloaded;
    126 
    127 static bool documentIsInApplicationChromeMode(const Document* document)
    128 {
    129     Settings* settings = document->settings();
    130     return settings && settings->inApplicationChromeMode();
    131 }
    132 
    133 void RenderThemeWin::setWebKitIsBeingUnloaded()
    134 {
    135     gWebKitIsBeingUnloaded = true;
    136 }
    137 
    138 PassRefPtr<RenderTheme> RenderThemeWin::create()
    139 {
    140     return adoptRef(new RenderThemeWin);
    141 }
    142 
    143 #if !USE(SAFARI_THEME)
    144 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
    145 {
    146     static RenderTheme* winTheme = RenderThemeWin::create().releaseRef();
    147     return winTheme;
    148 }
    149 #endif
    150 
    151 RenderThemeWin::RenderThemeWin()
    152     : m_buttonTheme(0)
    153     , m_textFieldTheme(0)
    154     , m_menuListTheme(0)
    155     , m_sliderTheme(0)
    156 {
    157     haveTheme = uxthemeLibrary() && IsThemeActive();
    158 }
    159 
    160 RenderThemeWin::~RenderThemeWin()
    161 {
    162     // If WebKit is being unloaded, then uxtheme.dll is no longer available.
    163     if (gWebKitIsBeingUnloaded || !uxthemeLibrary())
    164         return;
    165     close();
    166 }
    167 
    168 HANDLE RenderThemeWin::buttonTheme() const
    169 {
    170     if (haveTheme && !m_buttonTheme)
    171         m_buttonTheme = OpenThemeData(0, L"Button");
    172     return m_buttonTheme;
    173 }
    174 
    175 HANDLE RenderThemeWin::textFieldTheme() const
    176 {
    177     if (haveTheme && !m_textFieldTheme)
    178         m_textFieldTheme = OpenThemeData(0, L"Edit");
    179     return m_textFieldTheme;
    180 }
    181 
    182 HANDLE RenderThemeWin::menuListTheme() const
    183 {
    184     if (haveTheme && !m_menuListTheme)
    185         m_menuListTheme = OpenThemeData(0, L"ComboBox");
    186     return m_menuListTheme;
    187 }
    188 
    189 HANDLE RenderThemeWin::sliderTheme() const
    190 {
    191     if (haveTheme && !m_sliderTheme)
    192         m_sliderTheme = OpenThemeData(0, L"TrackBar");
    193     return m_sliderTheme;
    194 }
    195 
    196 void RenderThemeWin::close()
    197 {
    198     // This method will need to be called when the OS theme changes to flush our cached themes.
    199     if (m_buttonTheme)
    200         CloseThemeData(m_buttonTheme);
    201     if (m_textFieldTheme)
    202         CloseThemeData(m_textFieldTheme);
    203     if (m_menuListTheme)
    204         CloseThemeData(m_menuListTheme);
    205     if (m_sliderTheme)
    206         CloseThemeData(m_sliderTheme);
    207     m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = 0;
    208 
    209     haveTheme = uxthemeLibrary() && IsThemeActive();
    210 }
    211 
    212 void RenderThemeWin::themeChanged()
    213 {
    214     close();
    215 }
    216 
    217 String RenderThemeWin::extraDefaultStyleSheet()
    218 {
    219     return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
    220 }
    221 
    222 String RenderThemeWin::extraQuirksStyleSheet()
    223 {
    224     return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
    225 }
    226 
    227 bool RenderThemeWin::supportsHover(const RenderStyle*) const
    228 {
    229     // The Classic/2k look has no hover effects.
    230     return haveTheme;
    231 }
    232 
    233 Color RenderThemeWin::platformActiveSelectionBackgroundColor() const
    234 {
    235     COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
    236     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
    237 }
    238 
    239 Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const
    240 {
    241     // This color matches Firefox.
    242     return Color(176, 176, 176);
    243 }
    244 
    245 Color RenderThemeWin::platformActiveSelectionForegroundColor() const
    246 {
    247     COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
    248     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
    249 }
    250 
    251 Color RenderThemeWin::platformInactiveSelectionForegroundColor() const
    252 {
    253     return platformActiveSelectionForegroundColor();
    254 }
    255 
    256 static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont, float fontSize)
    257 {
    258     fontDescription.setIsAbsoluteSize(true);
    259     fontDescription.setGenericFamily(FontDescription::NoFamily);
    260     fontDescription.firstFamily().setFamily(String(logFont.lfFaceName));
    261     fontDescription.setSpecifiedSize(fontSize);
    262     fontDescription.setWeight(logFont.lfWeight >= 700 ? FontWeightBold : FontWeightNormal); // FIXME: Use real weight.
    263     fontDescription.setItalic(logFont.lfItalic);
    264 }
    265 
    266 static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont)
    267 {
    268     fillFontDescription(fontDescription, logFont, abs(logFont.lfHeight));
    269 }
    270 
    271 void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) const
    272 {
    273     static FontDescription captionFont;
    274     static FontDescription controlFont;
    275     static FontDescription smallCaptionFont;
    276     static FontDescription menuFont;
    277     static FontDescription iconFont;
    278     static FontDescription messageBoxFont;
    279     static FontDescription statusBarFont;
    280     static FontDescription systemFont;
    281 
    282     static bool initialized;
    283     static NONCLIENTMETRICS ncm;
    284 
    285     if (!initialized) {
    286         initialized = true;
    287         ncm.cbSize = sizeof(NONCLIENTMETRICS);
    288         ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
    289     }
    290 
    291     switch (propId) {
    292         case CSSValueIcon: {
    293             if (!iconFont.isAbsoluteSize()) {
    294                 LOGFONT logFont;
    295                 ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
    296                 fillFontDescription(iconFont, logFont);
    297             }
    298             fontDescription = iconFont;
    299             break;
    300         }
    301         case CSSValueMenu:
    302             if (!menuFont.isAbsoluteSize())
    303                 fillFontDescription(menuFont, ncm.lfMenuFont);
    304             fontDescription = menuFont;
    305             break;
    306         case CSSValueMessageBox:
    307             if (!messageBoxFont.isAbsoluteSize())
    308                 fillFontDescription(messageBoxFont, ncm.lfMessageFont);
    309             fontDescription = messageBoxFont;
    310             break;
    311         case CSSValueStatusBar:
    312             if (!statusBarFont.isAbsoluteSize())
    313                 fillFontDescription(statusBarFont, ncm.lfStatusFont);
    314             fontDescription = statusBarFont;
    315             break;
    316         case CSSValueCaption:
    317             if (!captionFont.isAbsoluteSize())
    318                 fillFontDescription(captionFont, ncm.lfCaptionFont);
    319             fontDescription = captionFont;
    320             break;
    321         case CSSValueSmallCaption:
    322             if (!smallCaptionFont.isAbsoluteSize())
    323                 fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont);
    324             fontDescription = smallCaptionFont;
    325             break;
    326         case CSSValueWebkitSmallControl:
    327         case CSSValueWebkitMiniControl: // Just map to small.
    328         case CSSValueWebkitControl: // Just map to small.
    329             if (!controlFont.isAbsoluteSize()) {
    330                 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
    331                 if (hGDI) {
    332                     LOGFONT logFont;
    333                     if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
    334                         fillFontDescription(controlFont, logFont, defaultControlFontPixelSize);
    335                 }
    336             }
    337             fontDescription = controlFont;
    338             break;
    339         default: { // Everything else uses the stock GUI font.
    340             if (!systemFont.isAbsoluteSize()) {
    341                 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
    342                 if (hGDI) {
    343                     LOGFONT logFont;
    344                     if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
    345                         fillFontDescription(systemFont, logFont);
    346                 }
    347             }
    348             fontDescription = systemFont;
    349         }
    350     }
    351 }
    352 
    353 bool RenderThemeWin::supportsFocus(ControlPart appearance) const
    354 {
    355     switch (appearance) {
    356         case PushButtonPart:
    357         case ButtonPart:
    358         case DefaultButtonPart:
    359             return true;
    360         default:
    361             return false;
    362     }
    363 }
    364 
    365 bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const
    366 {
    367     return supportsFocus(style->appearance());
    368 }
    369 
    370 unsigned RenderThemeWin::determineClassicState(RenderObject* o)
    371 {
    372     unsigned state = 0;
    373     switch (o->style()->appearance()) {
    374         case PushButtonPart:
    375         case ButtonPart:
    376         case DefaultButtonPart:
    377             state = DFCS_BUTTONPUSH;
    378             if (!isEnabled(o))
    379                 state |= DFCS_INACTIVE;
    380             else if (isPressed(o))
    381                 state |= DFCS_PUSHED;
    382             break;
    383         case RadioPart:
    384         case CheckboxPart:
    385             state = (o->style()->appearance() == RadioPart) ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
    386             if (isChecked(o))
    387                 state |= DFCS_CHECKED;
    388             if (!isEnabled(o))
    389                 state |= DFCS_INACTIVE;
    390             else if (isPressed(o))
    391                 state |= DFCS_PUSHED;
    392             break;
    393         case MenulistPart:
    394             state = DFCS_SCROLLCOMBOBOX;
    395             if (!isEnabled(o))
    396                 state |= DFCS_INACTIVE;
    397             else if (isPressed(o))
    398                 state |= DFCS_PUSHED;
    399         default:
    400             break;
    401     }
    402     return state;
    403 }
    404 
    405 unsigned RenderThemeWin::determineState(RenderObject* o)
    406 {
    407     unsigned result = TS_NORMAL;
    408     ControlPart appearance = o->style()->appearance();
    409     if (!isEnabled(o))
    410         result = TS_DISABLED;
    411     else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance))
    412         result = TFS_READONLY; // Readonly is supported on textfields.
    413     else if (isPressed(o)) // Active overrides hover and focused.
    414         result = TS_ACTIVE;
    415     else if (supportsFocus(appearance) && isFocused(o))
    416         result = TS_FOCUSED;
    417     else if (isHovered(o))
    418         result = TS_HOVER;
    419     if (isChecked(o))
    420         result += 4; // 4 unchecked states, 4 checked states.
    421     return result;
    422 }
    423 
    424 unsigned RenderThemeWin::determineSliderThumbState(RenderObject* o)
    425 {
    426     unsigned result = TUS_NORMAL;
    427     if (!isEnabled(o->parent()))
    428         result = TUS_DISABLED;
    429     else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent()))
    430         result = TUS_FOCUSED;
    431     else if (toRenderSlider(o->parent())->inDragMode())
    432         result = TUS_PRESSED;
    433     else if (isHovered(o))
    434         result = TUS_HOT;
    435     return result;
    436 }
    437 
    438 unsigned RenderThemeWin::determineButtonState(RenderObject* o)
    439 {
    440     unsigned result = PBS_NORMAL;
    441     if (!isEnabled(o))
    442         result = PBS_DISABLED;
    443     else if (isPressed(o))
    444         result = PBS_PRESSED;
    445     else if (supportsFocus(o->style()->appearance()) && isFocused(o))
    446         result = PBS_DEFAULTED;
    447     else if (isHovered(o))
    448         result = PBS_HOT;
    449     else if (isDefault(o))
    450         result = PBS_DEFAULTED;
    451     return result;
    452 }
    453 
    454 ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o)
    455 {
    456     ThemeData result;
    457     switch (o->style()->appearance()) {
    458         case PushButtonPart:
    459         case ButtonPart:
    460         case DefaultButtonPart:
    461         case CheckboxPart:
    462         case RadioPart:
    463             result.m_part = DFC_BUTTON;
    464             result.m_state = determineClassicState(o);
    465             break;
    466         case MenulistPart:
    467             result.m_part = DFC_SCROLL;
    468             result.m_state = determineClassicState(o);
    469             break;
    470         case SearchFieldPart:
    471         case TextFieldPart:
    472         case TextAreaPart:
    473             result.m_part = TFP_TEXTFIELD;
    474             result.m_state = determineState(o);
    475             break;
    476         case SliderHorizontalPart:
    477             result.m_part = TKP_TRACK;
    478             result.m_state = TS_NORMAL;
    479             break;
    480         case SliderVerticalPart:
    481             result.m_part = TKP_TRACKVERT;
    482             result.m_state = TS_NORMAL;
    483             break;
    484         case SliderThumbHorizontalPart:
    485             result.m_part = TKP_THUMBBOTTOM;
    486             result.m_state = determineSliderThumbState(o);
    487             break;
    488         case SliderThumbVerticalPart:
    489             result.m_part = TKP_THUMBRIGHT;
    490             result.m_state = determineSliderThumbState(o);
    491             break;
    492         default:
    493             break;
    494     }
    495     return result;
    496 }
    497 
    498 ThemeData RenderThemeWin::getThemeData(RenderObject* o)
    499 {
    500     if (!haveTheme)
    501         return getClassicThemeData(o);
    502 
    503     ThemeData result;
    504     switch (o->style()->appearance()) {
    505         case PushButtonPart:
    506         case ButtonPart:
    507         case DefaultButtonPart:
    508             result.m_part = BP_BUTTON;
    509             result.m_state = determineButtonState(o);
    510             break;
    511         case CheckboxPart:
    512             result.m_part = BP_CHECKBOX;
    513             result.m_state = determineState(o);
    514             break;
    515         case MenulistPart:
    516         case MenulistButtonPart:
    517             result.m_part = isRunningOnVistaOrLater() ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON;
    518             if (isRunningOnVistaOrLater() && documentIsInApplicationChromeMode(o->document())) {
    519                 // The "readonly" look we use in application chrome mode
    520                 // only uses a "normal" look for the drop down button.
    521                 result.m_state = TS_NORMAL;
    522             } else
    523                 result.m_state = determineState(o);
    524             break;
    525         case RadioPart:
    526             result.m_part = BP_RADIO;
    527             result.m_state = determineState(o);
    528             break;
    529         case SearchFieldPart:
    530         case TextFieldPart:
    531         case TextAreaPart:
    532             result.m_part = isRunningOnVistaOrLater() ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD;
    533             result.m_state = determineState(o);
    534             break;
    535         case SliderHorizontalPart:
    536             result.m_part = TKP_TRACK;
    537             result.m_state = TS_NORMAL;
    538             break;
    539         case SliderVerticalPart:
    540             result.m_part = TKP_TRACKVERT;
    541             result.m_state = TS_NORMAL;
    542             break;
    543         case SliderThumbHorizontalPart:
    544             result.m_part = TKP_THUMBBOTTOM;
    545             result.m_state = determineSliderThumbState(o);
    546             break;
    547         case SliderThumbVerticalPart:
    548             result.m_part = TKP_THUMBRIGHT;
    549             result.m_state = determineSliderThumbState(o);
    550             break;
    551     }
    552 
    553     return result;
    554 }
    555 
    556 static void drawControl(GraphicsContext* context, RenderObject* o, HANDLE theme, const ThemeData& themeData, const IntRect& r)
    557 {
    558     bool alphaBlend = false;
    559     if (theme)
    560         alphaBlend = IsThemeBackgroundPartiallyTransparent(theme, themeData.m_part, themeData.m_state);
    561     HDC hdc = context->getWindowsContext(r, alphaBlend);
    562     RECT widgetRect = r;
    563     if (theme)
    564         DrawThemeBackground(theme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
    565     else {
    566         if (themeData.m_part == TFP_TEXTFIELD) {
    567             ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
    568             if (themeData.m_state == TS_DISABLED || themeData.m_state ==  TFS_READONLY)
    569                 ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_BTNFACE+1));
    570             else
    571                 ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_WINDOW+1));
    572         } else if (themeData.m_part == TKP_TRACK || themeData.m_part == TKP_TRACKVERT) {
    573             ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
    574             ::FillRect(hdc, &widgetRect, (HBRUSH)GetStockObject(GRAY_BRUSH));
    575         } else if ((o->style()->appearance() == SliderThumbHorizontalPart ||
    576                     o->style()->appearance() == SliderThumbVerticalPart) &&
    577                    (themeData.m_part == TKP_THUMBBOTTOM || themeData.m_part == TKP_THUMBTOP ||
    578                     themeData.m_part == TKP_THUMBLEFT || themeData.m_part == TKP_THUMBRIGHT)) {
    579             ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
    580             if (themeData.m_state == TUS_DISABLED) {
    581                 static WORD patternBits[8] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
    582                 HBITMAP patternBmp = ::CreateBitmap(8, 8, 1, 1, patternBits);
    583                 if (patternBmp) {
    584                     HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patternBmp);
    585                     COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(COLOR_3DFACE));
    586                     COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
    587                     POINT p;
    588                     ::GetViewportOrgEx(hdc, &p);
    589                     ::SetBrushOrgEx(hdc, p.x + widgetRect.left, p.y + widgetRect.top, NULL);
    590                     HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush);
    591                     ::FillRect(hdc, &widgetRect, brush);
    592                     ::SetTextColor(hdc, oldForeColor);
    593                     ::SetBkColor(hdc, oldBackColor);
    594                     ::SelectObject(hdc, oldBrush);
    595                     ::DeleteObject(brush);
    596                 } else
    597                     ::FillRect(hdc, &widgetRect, (HBRUSH)COLOR_3DHILIGHT);
    598                 ::DeleteObject(patternBmp);
    599             }
    600         } else {
    601             // Push buttons, buttons, checkboxes and radios, and the dropdown arrow in menulists.
    602             if (o->style()->appearance() == DefaultButtonPart) {
    603                 HBRUSH brush = ::GetSysColorBrush(COLOR_3DDKSHADOW);
    604                 ::FrameRect(hdc, &widgetRect, brush);
    605                 ::InflateRect(&widgetRect, -1, -1);
    606                 ::DrawEdge(hdc, &widgetRect, BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE);
    607             }
    608             ::DrawFrameControl(hdc, &widgetRect, themeData.m_part, themeData.m_state);
    609         }
    610     }
    611     context->releaseWindowsContext(hdc, r, alphaBlend);
    612 }
    613 
    614 bool RenderThemeWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    615 {
    616     drawControl(i.context,  o, buttonTheme(), getThemeData(o), r);
    617     return false;
    618 }
    619 
    620 void RenderThemeWin::setCheckboxSize(RenderStyle* style) const
    621 {
    622     // If the width and height are both specified, then we have nothing to do.
    623     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
    624         return;
    625 
    626     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
    627     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
    628     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
    629     // metrics.
    630     if (style->width().isIntrinsicOrAuto())
    631         style->setWidth(Length(13, Fixed));
    632     if (style->height().isAuto())
    633         style->setHeight(Length(13, Fixed));
    634 }
    635 
    636 bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    637 {
    638     drawControl(i.context,  o, textFieldTheme(), getThemeData(o), r);
    639     return false;
    640 }
    641 
    642 bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    643 {
    644     HANDLE theme;
    645     int part;
    646     if (haveTheme && isRunningOnVistaOrLater()) {
    647         theme = menuListTheme();
    648         if (documentIsInApplicationChromeMode(o->document()))
    649             part = CP_READONLY;
    650         else
    651             part = CP_BORDER;
    652     } else {
    653         theme = textFieldTheme();
    654         part = TFP_TEXTFIELD;
    655     }
    656 
    657     drawControl(i.context,  o, theme, ThemeData(part, determineState(o)), r);
    658 
    659     return paintMenuListButton(o, i, r);
    660 }
    661 
    662 void RenderThemeWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    663 {
    664     style->resetBorder();
    665     adjustMenuListButtonStyle(selector, style, e);
    666 }
    667 
    668 void RenderThemeWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    669 {
    670     // These are the paddings needed to place the text correctly in the <select> box
    671     const int dropDownBoxPaddingTop    = 2;
    672     const int dropDownBoxPaddingRight  = style->direction() == LTR ? 4 + dropDownButtonWidth : 4;
    673     const int dropDownBoxPaddingBottom = 2;
    674     const int dropDownBoxPaddingLeft   = style->direction() == LTR ? 4 : 4 + dropDownButtonWidth;
    675     // The <select> box must be at least 12px high for the button to render nicely on Windows
    676     const int dropDownBoxMinHeight = 12;
    677 
    678     // Position the text correctly within the select box and make the box wide enough to fit the dropdown button
    679     style->setPaddingTop(Length(dropDownBoxPaddingTop, Fixed));
    680     style->setPaddingRight(Length(dropDownBoxPaddingRight, Fixed));
    681     style->setPaddingBottom(Length(dropDownBoxPaddingBottom, Fixed));
    682     style->setPaddingLeft(Length(dropDownBoxPaddingLeft, Fixed));
    683 
    684     // Height is locked to auto
    685     style->setHeight(Length(Auto));
    686 
    687     // Calculate our min-height
    688     int minHeight = style->font().height();
    689     minHeight = max(minHeight, dropDownBoxMinHeight);
    690 
    691     style->setMinHeight(Length(minHeight, Fixed));
    692 
    693     // White-space is locked to pre
    694     style->setWhiteSpace(PRE);
    695 }
    696 
    697 bool RenderThemeWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    698 {
    699     // FIXME: Don't make hardcoded assumptions about the thickness of the textfield border.
    700     int borderThickness = haveTheme ? 1 : 2;
    701 
    702     // Paint the dropdown button on the inner edge of the text field,
    703     // leaving space for the text field's 1px border
    704     IntRect buttonRect(r);
    705     buttonRect.inflate(-borderThickness);
    706     if (o->style()->direction() == LTR)
    707         buttonRect.setX(buttonRect.right() - dropDownButtonWidth);
    708     buttonRect.setWidth(dropDownButtonWidth);
    709 
    710     if (isRunningOnVistaOrLater()) {
    711         // Outset the top, right, and bottom borders of the button so that they coincide with the <select>'s border.
    712         buttonRect.setY(buttonRect.y() - vistaMenuListButtonOutset);
    713         buttonRect.setHeight(buttonRect.height() + 2 * vistaMenuListButtonOutset);
    714         buttonRect.setWidth(buttonRect.width() + vistaMenuListButtonOutset);
    715     }
    716 
    717     drawControl(i.context, o, menuListTheme(), getThemeData(o), buttonRect);
    718 
    719     return false;
    720 }
    721 
    722 const int trackWidth = 4;
    723 
    724 bool RenderThemeWin::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    725 {
    726     IntRect bounds = r;
    727 
    728     if (o->style()->appearance() ==  SliderHorizontalPart) {
    729         bounds.setHeight(trackWidth);
    730         bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
    731     } else if (o->style()->appearance() == SliderVerticalPart) {
    732         bounds.setWidth(trackWidth);
    733         bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
    734     }
    735 
    736     drawControl(i.context,  o, sliderTheme(), getThemeData(o), bounds);
    737     return false;
    738 }
    739 
    740 bool RenderThemeWin::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    741 {
    742     drawControl(i.context,  o, sliderTheme(), getThemeData(o), r);
    743     return false;
    744 }
    745 
    746 const int sliderThumbWidth = 7;
    747 const int sliderThumbHeight = 15;
    748 
    749 void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const
    750 {
    751     if (o->style()->appearance() == SliderThumbVerticalPart) {
    752         o->style()->setWidth(Length(sliderThumbHeight, Fixed));
    753         o->style()->setHeight(Length(sliderThumbWidth, Fixed));
    754     } else if (o->style()->appearance() == SliderThumbHorizontalPart) {
    755         o->style()->setWidth(Length(sliderThumbWidth, Fixed));
    756         o->style()->setHeight(Length(sliderThumbHeight, Fixed));
    757     }
    758 #if ENABLE(VIDEO)
    759     else if (o->style()->appearance() == MediaSliderThumbPart)
    760         RenderMediaControls::adjustMediaSliderThumbSize(o);
    761 #endif
    762 }
    763 
    764 int RenderThemeWin::buttonInternalPaddingLeft() const
    765 {
    766     return 3;
    767 }
    768 
    769 int RenderThemeWin::buttonInternalPaddingRight() const
    770 {
    771     return 3;
    772 }
    773 
    774 int RenderThemeWin::buttonInternalPaddingTop() const
    775 {
    776     return 1;
    777 }
    778 
    779 int RenderThemeWin::buttonInternalPaddingBottom() const
    780 {
    781     return 1;
    782 }
    783 
    784 bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    785 {
    786     return paintTextField(o, i, r);
    787 }
    788 
    789 void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    790 {
    791     // Override paddingSize to match AppKit text positioning.
    792     const int padding = 1;
    793     style->setPaddingLeft(Length(padding, Fixed));
    794     style->setPaddingRight(Length(padding, Fixed));
    795     style->setPaddingTop(Length(padding, Fixed));
    796     style->setPaddingBottom(Length(padding, Fixed));
    797     if (e && e->focused() && e->document()->frame()->selection()->isFocusedAndActive())
    798         style->setOutlineOffset(-2);
    799 }
    800 
    801 bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    802 {
    803     IntRect bounds = r;
    804     ASSERT(o->parent());
    805     if (!o->parent() || !o->parent()->isBox())
    806         return false;
    807 
    808     RenderBox* parentRenderBox = toRenderBox(o->parent());
    809 
    810     IntRect parentBox = parentRenderBox->absoluteContentBox();
    811 
    812     // Make sure the scaled button stays square and will fit in its parent's box
    813     bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height())));
    814     bounds.setWidth(bounds.height());
    815 
    816     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
    817     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    818     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
    819 
    820     static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef();
    821     static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef();
    822     paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, o->style()->colorSpace(), bounds);
    823     return false;
    824 }
    825 
    826 void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    827 {
    828     // Scale the button size based on the font size
    829     float fontScale = style->fontSize() / defaultControlFontPixelSize;
    830     int cancelButtonSize = lroundf(min(max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
    831     style->setWidth(Length(cancelButtonSize, Fixed));
    832     style->setHeight(Length(cancelButtonSize, Fixed));
    833 }
    834 
    835 void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    836 {
    837     IntSize emptySize(1, 11);
    838     style->setWidth(Length(emptySize.width(), Fixed));
    839     style->setHeight(Length(emptySize.height(), Fixed));
    840 }
    841 
    842 void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    843 {
    844     // Scale the decoration size based on the font size
    845     float fontScale = style->fontSize() / defaultControlFontPixelSize;
    846     int magnifierSize = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
    847                                      maxSearchFieldResultsDecorationSize));
    848     style->setWidth(Length(magnifierSize, Fixed));
    849     style->setHeight(Length(magnifierSize, Fixed));
    850 }
    851 
    852 bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    853 {
    854     IntRect bounds = r;
    855     ASSERT(o->parent());
    856     if (!o->parent() || !o->parent()->isBox())
    857         return false;
    858 
    859     RenderBox* parentRenderBox = toRenderBox(o->parent());
    860     IntRect parentBox = parentRenderBox->absoluteContentBox();
    861 
    862     // Make sure the scaled decoration stays square and will fit in its parent's box
    863     bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height())));
    864     bounds.setWidth(bounds.height());
    865 
    866     // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
    867     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    868     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
    869 
    870     static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef();
    871     paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
    872     return false;
    873 }
    874 
    875 void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    876 {
    877     // Scale the button size based on the font size
    878     float fontScale = style->fontSize() / defaultControlFontPixelSize;
    879     int magnifierHeight = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
    880                                    maxSearchFieldResultsDecorationSize));
    881     int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
    882     style->setWidth(Length(magnifierWidth, Fixed));
    883     style->setHeight(Length(magnifierHeight, Fixed));
    884 }
    885 
    886 bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    887 {
    888     IntRect bounds = r;
    889     ASSERT(o->parent());
    890     if (!o->parent())
    891         return false;
    892     if (!o->parent() || !o->parent()->isBox())
    893         return false;
    894 
    895     RenderBox* parentRenderBox = toRenderBox(o->parent());
    896     IntRect parentBox = parentRenderBox->absoluteContentBox();
    897 
    898     // Make sure the scaled decoration will fit in its parent's box
    899     bounds.setHeight(min(parentBox.height(), bounds.height()));
    900     bounds.setWidth(min(parentBox.width(), static_cast<int>(bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize)));
    901 
    902     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
    903     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    904     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
    905 
    906     static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef();
    907     paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
    908     return false;
    909 }
    910 
    911 // Map a CSSValue* system color to an index understood by GetSysColor
    912 static int cssValueIdToSysColorIndex(int cssValueId)
    913 {
    914     switch (cssValueId) {
    915         case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
    916         case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
    917         case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
    918         case CSSValueBackground: return COLOR_BACKGROUND;
    919         case CSSValueButtonface: return COLOR_BTNFACE;
    920         case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
    921         case CSSValueButtonshadow: return COLOR_BTNSHADOW;
    922         case CSSValueButtontext: return COLOR_BTNTEXT;
    923         case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
    924         case CSSValueGraytext: return COLOR_GRAYTEXT;
    925         case CSSValueHighlight: return COLOR_HIGHLIGHT;
    926         case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
    927         case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
    928         case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
    929         case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
    930         case CSSValueInfobackground: return COLOR_INFOBK;
    931         case CSSValueInfotext: return COLOR_INFOTEXT;
    932         case CSSValueMenu: return COLOR_MENU;
    933         case CSSValueMenutext: return COLOR_MENUTEXT;
    934         case CSSValueScrollbar: return COLOR_SCROLLBAR;
    935         case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
    936         case CSSValueThreedface: return COLOR_3DFACE;
    937         case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
    938         case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
    939         case CSSValueThreedshadow: return COLOR_3DSHADOW;
    940         case CSSValueWindow: return COLOR_WINDOW;
    941         case CSSValueWindowframe: return COLOR_WINDOWFRAME;
    942         case CSSValueWindowtext: return COLOR_WINDOWTEXT;
    943         default: return -1; // Unsupported CSSValue
    944     }
    945 }
    946 
    947 Color RenderThemeWin::systemColor(int cssValueId) const
    948 {
    949     int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
    950     if (sysColorIndex == -1)
    951         return RenderTheme::systemColor(cssValueId);
    952 
    953     COLORREF color = GetSysColor(sysColorIndex);
    954     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
    955 }
    956 
    957 #if ENABLE(VIDEO)
    958 
    959 bool RenderThemeWin::shouldRenderMediaControlPart(ControlPart part, Element* element)
    960 {
    961     if (part == MediaToggleClosedCaptionsButtonPart) {
    962         // We rely on QuickTime to render captions so only enable the button for a video element.
    963 #if SAFARI_THEME_VERSION >= 4
    964         if (!element->hasTagName(videoTag))
    965             return false;
    966 #else
    967         return false;
    968 #endif
    969     }
    970 
    971     return RenderTheme::shouldRenderMediaControlPart(part, element);
    972 }
    973 
    974 
    975 bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    976 {
    977     return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r);
    978 }
    979 
    980 bool RenderThemeWin::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    981 {
    982     return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r);
    983 }
    984 
    985 bool RenderThemeWin::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    986 {
    987     return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r);
    988 }
    989 
    990 bool RenderThemeWin::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    991 {
    992     return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r);
    993 }
    994 
    995 bool RenderThemeWin::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    996 {
    997     return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r);
    998 }
    999 
   1000 bool RenderThemeWin::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
   1001 {
   1002     return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r);
   1003 }
   1004 
   1005 bool RenderThemeWin::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
   1006 {
   1007     return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r);
   1008 }
   1009 
   1010 bool RenderThemeWin::paintMediaToggleClosedCaptionsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
   1011 {
   1012     return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
   1013 }
   1014 
   1015 #endif
   1016 
   1017 }
   1018