Home | History | Annotate | Download | only in rendering
      1 /*
      2  * This file is part of the WebKit project.
      3  *
      4  * Copyright (C) 2006 Apple Computer, Inc.
      5  * Copyright (C) 2008, 2009 Google, Inc.
      6  * Copyright (C) 2009 Kenneth Rohde Christiansen
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     21  * Boston, MA 02111-1307, USA.
     22  *
     23  */
     24 
     25 #include "config.h"
     26 #include "RenderThemeChromiumWin.h"
     27 
     28 #include <windows.h>
     29 #include <uxtheme.h>
     30 #include <vssym32.h>
     31 
     32 #include "CSSValueKeywords.h"
     33 #include "CurrentTime.h"
     34 #include "FontSelector.h"
     35 #include "FontUtilsChromiumWin.h"
     36 #include "GraphicsContext.h"
     37 #include "HTMLMediaElement.h"
     38 #include "HTMLNames.h"
     39 #include "MediaControlElements.h"
     40 #include "PaintInfo.h"
     41 #include "PlatformBridge.h"
     42 #include "RenderBox.h"
     43 #include "RenderProgress.h"
     44 #include "RenderSlider.h"
     45 #include "ScrollbarTheme.h"
     46 #include "SystemInfo.h"
     47 #include "TransparencyWin.h"
     48 
     49 // FIXME: This dependency should eventually be removed.
     50 #include <skia/ext/skia_utils_win.h>
     51 
     52 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
     53     offsetof(structName, member) + \
     54     (sizeof static_cast<structName*>(0)->member)
     55 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \
     56     SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
     57 
     58 namespace WebCore {
     59 
     60 // The standard width for the menu list drop-down button when run under
     61 // layout test mode. Use the value that's currently captured in most baselines.
     62 static const int kStandardMenuListButtonWidth = 17;
     63 
     64 namespace {
     65 // We must not create multiple ThemePainter instances.
     66 class ThemePainter {
     67 public:
     68     ThemePainter(GraphicsContext* context, const IntRect& r)
     69     {
     70 #ifndef NDEBUG
     71         ASSERT(!s_hasInstance);
     72         s_hasInstance = true;
     73 #endif
     74         TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM());
     75         m_helper.init(context, getLayerMode(context, transformMode), transformMode, r);
     76 
     77         if (!m_helper.context()) {
     78             // TransparencyWin doesn't have well-defined copy-ctor nor op=()
     79             // so we re-initialize it instead of assigning a fresh istance.
     80             // On the reinitialization, we fallback to use NoLayer mode.
     81             // Note that the original initialization failure can be caused by
     82             // a failure of an internal buffer allocation and NoLayer mode
     83             // does not have such buffer allocations.
     84             m_helper.~TransparencyWin();
     85             new (&m_helper) TransparencyWin();
     86             m_helper.init(context, TransparencyWin::NoLayer, transformMode, r);
     87         }
     88     }
     89 
     90     ~ThemePainter()
     91     {
     92         m_helper.composite();
     93 #ifndef NDEBUG
     94         s_hasInstance = false;
     95 #endif
     96     }
     97 
     98     GraphicsContext* context() { return m_helper.context(); }
     99     const IntRect& drawRect() { return m_helper.drawRect(); }
    100 
    101 private:
    102 
    103     static bool canvasHasMultipleLayers(const SkCanvas* canvas)
    104     {
    105         SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
    106         iter.next(); // There is always at least one layer.
    107         return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
    108     }
    109 
    110     static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode)
    111     {
    112         if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background.
    113             return TransparencyWin::WhiteLayer;
    114         if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help.
    115             return TransparencyWin::OpaqueCompositeLayer;
    116         // Nothing interesting.
    117         return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer;
    118     }
    119 
    120     static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix)
    121     {
    122         if (matrix.b() || matrix.c()) // Skew.
    123             return TransparencyWin::Untransform;
    124         if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale.
    125             return TransparencyWin::ScaleTransform;
    126         // Nothing interesting.
    127         return TransparencyWin::KeepTransform;
    128     }
    129 
    130     TransparencyWin m_helper;
    131 #ifndef NDEBUG
    132     static bool s_hasInstance;
    133 #endif
    134 };
    135 
    136 #ifndef NDEBUG
    137 bool ThemePainter::s_hasInstance = false;
    138 #endif
    139 
    140 } // namespace
    141 
    142 static void getNonClientMetrics(NONCLIENTMETRICS* metrics)
    143 {
    144     static UINT size = (windowsVersion() >= WindowsVista) ?
    145         (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
    146     metrics->cbSize = size;
    147     bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0);
    148     ASSERT(success);
    149 }
    150 
    151 static FontDescription smallSystemFont;
    152 static FontDescription menuFont;
    153 static FontDescription labelFont;
    154 
    155 // Internal static helper functions.  We don't put them in an anonymous
    156 // namespace so they have easier access to the WebCore namespace.
    157 
    158 static bool supportsFocus(ControlPart appearance)
    159 {
    160     switch (appearance) {
    161     case PushButtonPart:
    162     case ButtonPart:
    163     case DefaultButtonPart:
    164     case SearchFieldPart:
    165     case TextFieldPart:
    166     case TextAreaPart:
    167         return true;
    168     }
    169     return false;
    170 }
    171 
    172 // Return the height of system font |font| in pixels.  We use this size by
    173 // default for some non-form-control elements.
    174 static float systemFontSize(const LOGFONT& font)
    175 {
    176     float size = -font.lfHeight;
    177     if (size < 0) {
    178         HFONT hFont = CreateFontIndirect(&font);
    179         if (hFont) {
    180             HDC hdc = GetDC(0); // What about printing?  Is this the right DC?
    181             if (hdc) {
    182                 HGDIOBJ hObject = SelectObject(hdc, hFont);
    183                 TEXTMETRIC tm;
    184                 GetTextMetrics(hdc, &tm);
    185                 SelectObject(hdc, hObject);
    186                 ReleaseDC(0, hdc);
    187                 size = tm.tmAscent;
    188             }
    189             DeleteObject(hFont);
    190         }
    191     }
    192 
    193     // The "codepage 936" bit here is from Gecko; apparently this helps make
    194     // fonts more legible in Simplified Chinese where the default font size is
    195     // too small.
    196     //
    197     // FIXME: http://b/1119883 Since this is only used for "small caption",
    198     // "menu", and "status bar" objects, I'm not sure how much this even
    199     // matters.  Plus the Gecko patch went in back in 2002, and maybe this
    200     // isn't even relevant anymore.  We should investigate whether this should
    201     // be removed, or perhaps broadened to be "any CJK locale".
    202     //
    203     return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size;
    204 }
    205 
    206 // Converts |points| to pixels.  One point is 1/72 of an inch.
    207 static float pointsToPixels(float points)
    208 {
    209     static float pixelsPerInch = 0.0f;
    210     if (!pixelsPerInch) {
    211         HDC hdc = GetDC(0); // What about printing?  Is this the right DC?
    212         if (hdc) { // Can this ever actually be NULL?
    213             pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
    214             ReleaseDC(0, hdc);
    215         } else {
    216             pixelsPerInch = 96.0f;
    217         }
    218     }
    219 
    220     static const float pointsPerInch = 72.0f;
    221     return points / pointsPerInch * pixelsPerInch;
    222 }
    223 
    224 static double querySystemBlinkInterval(double defaultInterval)
    225 {
    226     UINT blinkTime = GetCaretBlinkTime();
    227     if (!blinkTime)
    228         return defaultInterval;
    229     if (blinkTime == INFINITE)
    230         return 0;
    231     return blinkTime / 1000.0;
    232 }
    233 
    234 PassRefPtr<RenderTheme> RenderThemeChromiumWin::create()
    235 {
    236     return adoptRef(new RenderThemeChromiumWin);
    237 }
    238 
    239 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
    240 {
    241     static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef();
    242     return rt;
    243 }
    244 
    245 bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const
    246 {
    247     // Let webkit draw one of its halo rings around any focused element,
    248     // except push buttons. For buttons we use the windows PBS_DEFAULTED
    249     // styling to give it a blue border.
    250     return style->appearance() == ButtonPart
    251             || style->appearance() == PushButtonPart;
    252 }
    253 
    254 Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
    255 {
    256     if (PlatformBridge::layoutTestMode())
    257         return Color(0x00, 0x00, 0xff); // Royal blue.
    258     COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
    259     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
    260 }
    261 
    262 Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const
    263 {
    264     if (PlatformBridge::layoutTestMode())
    265         return Color(0x99, 0x99, 0x99); // Medium gray.
    266     COLORREF color = GetSysColor(COLOR_GRAYTEXT);
    267     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
    268 }
    269 
    270 Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const
    271 {
    272     if (PlatformBridge::layoutTestMode())
    273         return Color(0xff, 0xff, 0xcc); // Pale yellow.
    274     COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
    275     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
    276 }
    277 
    278 Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const
    279 {
    280     return Color::white;
    281 }
    282 
    283 Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const
    284 {
    285     return Color(0xff, 0x96, 0x32); // Orange.
    286 }
    287 
    288 Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const
    289 {
    290     return Color(0xff, 0xff, 0x96); // Yellow.
    291 }
    292 
    293 void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const
    294 {
    295     // This logic owes much to RenderThemeSafari.cpp.
    296     FontDescription* cachedDesc = 0;
    297     AtomicString faceName;
    298     float fontSize = 0;
    299     switch (propId) {
    300     case CSSValueSmallCaption:
    301         cachedDesc = &smallSystemFont;
    302         if (!smallSystemFont.isAbsoluteSize()) {
    303             NONCLIENTMETRICS metrics;
    304             getNonClientMetrics(&metrics);
    305             faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName));
    306             fontSize = systemFontSize(metrics.lfSmCaptionFont);
    307         }
    308         break;
    309     case CSSValueMenu:
    310         cachedDesc = &menuFont;
    311         if (!menuFont.isAbsoluteSize()) {
    312             NONCLIENTMETRICS metrics;
    313             getNonClientMetrics(&metrics);
    314             faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName));
    315             fontSize = systemFontSize(metrics.lfMenuFont);
    316         }
    317         break;
    318     case CSSValueStatusBar:
    319         cachedDesc = &labelFont;
    320         if (!labelFont.isAbsoluteSize()) {
    321             NONCLIENTMETRICS metrics;
    322             getNonClientMetrics(&metrics);
    323             faceName = metrics.lfStatusFont.lfFaceName;
    324             fontSize = systemFontSize(metrics.lfStatusFont);
    325         }
    326         break;
    327     case CSSValueWebkitMiniControl:
    328     case CSSValueWebkitSmallControl:
    329     case CSSValueWebkitControl:
    330         faceName = defaultGUIFont();
    331         // Why 2 points smaller?  Because that's what Gecko does.
    332         fontSize = defaultFontSize - pointsToPixels(2);
    333         break;
    334     default:
    335         faceName = defaultGUIFont();
    336         fontSize = defaultFontSize;
    337         break;
    338     }
    339 
    340     if (!cachedDesc)
    341         cachedDesc = &fontDescription;
    342 
    343     if (fontSize) {
    344         cachedDesc->firstFamily().setFamily(faceName);
    345         cachedDesc->setIsAbsoluteSize(true);
    346         cachedDesc->setGenericFamily(FontDescription::NoFamily);
    347         cachedDesc->setSpecifiedSize(fontSize);
    348         cachedDesc->setWeight(FontWeightNormal);
    349         cachedDesc->setItalic(false);
    350     }
    351     fontDescription = *cachedDesc;
    352 }
    353 
    354 // Map a CSSValue* system color to an index understood by GetSysColor().
    355 static int cssValueIdToSysColorIndex(int cssValueId)
    356 {
    357     switch (cssValueId) {
    358     case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
    359     case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
    360     case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
    361     case CSSValueBackground: return COLOR_BACKGROUND;
    362     case CSSValueButtonface: return COLOR_BTNFACE;
    363     case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
    364     case CSSValueButtonshadow: return COLOR_BTNSHADOW;
    365     case CSSValueButtontext: return COLOR_BTNTEXT;
    366     case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
    367     case CSSValueGraytext: return COLOR_GRAYTEXT;
    368     case CSSValueHighlight: return COLOR_HIGHLIGHT;
    369     case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
    370     case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
    371     case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
    372     case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
    373     case CSSValueInfobackground: return COLOR_INFOBK;
    374     case CSSValueInfotext: return COLOR_INFOTEXT;
    375     case CSSValueMenu: return COLOR_MENU;
    376     case CSSValueMenutext: return COLOR_MENUTEXT;
    377     case CSSValueScrollbar: return COLOR_SCROLLBAR;
    378     case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
    379     case CSSValueThreedface: return COLOR_3DFACE;
    380     case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
    381     case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
    382     case CSSValueThreedshadow: return COLOR_3DSHADOW;
    383     case CSSValueWindow: return COLOR_WINDOW;
    384     case CSSValueWindowframe: return COLOR_WINDOWFRAME;
    385     case CSSValueWindowtext: return COLOR_WINDOWTEXT;
    386     default: return -1; // Unsupported CSSValue
    387     }
    388 }
    389 
    390 Color RenderThemeChromiumWin::systemColor(int cssValueId) const
    391 {
    392     int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
    393     if (PlatformBridge::layoutTestMode() || (sysColorIndex == -1))
    394         return RenderTheme::systemColor(cssValueId);
    395 
    396     COLORREF color = GetSysColor(sysColorIndex);
    397     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
    398 }
    399 
    400 void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const
    401 {
    402     // These sizes match what WinXP draws for various menus.
    403     const int sliderThumbAlongAxis = 11;
    404     const int sliderThumbAcrossAxis = 21;
    405     if (o->style()->appearance() == SliderThumbHorizontalPart) {
    406         o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed));
    407         o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed));
    408     } else if (o->style()->appearance() == SliderThumbVerticalPart) {
    409         o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed));
    410         o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed));
    411     } else
    412         RenderThemeChromiumSkia::adjustSliderThumbSize(o);
    413 }
    414 
    415 bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
    416 {
    417     return paintButton(o, i, r);
    418 }
    419 bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
    420 {
    421     return paintButton(o, i, r);
    422 }
    423 
    424 bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
    425 {
    426     const ThemeData& themeData = getThemeData(o);
    427 
    428     ThemePainter painter(i.context, r);
    429     PlatformBridge::paintButton(painter.context(),
    430                                 themeData.m_part,
    431                                 themeData.m_state,
    432                                 themeData.m_classicState,
    433                                 painter.drawRect());
    434     return false;
    435 }
    436 
    437 bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
    438 {
    439     return paintTextFieldInternal(o, i, r, true);
    440 }
    441 
    442 bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
    443 {
    444     const ThemeData& themeData = getThemeData(o);
    445 
    446     ThemePainter painter(i.context, r);
    447     PlatformBridge::paintTrackbar(painter.context(),
    448                                   themeData.m_part,
    449                                   themeData.m_state,
    450                                   themeData.m_classicState,
    451                                   painter.drawRect());
    452     return false;
    453 }
    454 
    455 bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
    456 {
    457     return paintSliderTrack(o, i, r);
    458 }
    459 
    460 static int menuListButtonWidth()
    461 {
    462     static int width = PlatformBridge::layoutTestMode() ? kStandardMenuListButtonWidth : GetSystemMetrics(SM_CXVSCROLL);
    463     return width;
    464 }
    465 
    466 // Used to paint unstyled menulists (i.e. with the default border)
    467 bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
    468 {
    469     if (!o->isBox())
    470         return false;
    471 
    472     const RenderBox* box = toRenderBox(o);
    473     int borderRight = box->borderRight();
    474     int borderLeft = box->borderLeft();
    475     int borderTop = box->borderTop();
    476     int borderBottom = box->borderBottom();
    477 
    478     // If all the borders are 0, then tell skia not to paint the border on the
    479     // textfield.  FIXME: http://b/1210017 Figure out how to get Windows to not
    480     // draw individual borders and then pass that to skia so we can avoid
    481     // drawing any borders that are set to 0. For non-zero borders, we draw the
    482     // border, but webkit just draws over it.
    483     bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom);
    484 
    485     paintTextFieldInternal(o, i, r, drawEdges);
    486 
    487     // Take padding and border into account.  If the MenuList is smaller than
    488     // the size of a button, make sure to shrink it appropriately and not put
    489     // its x position to the left of the menulist.
    490     const int buttonWidth = menuListButtonWidth();
    491     int spacingLeft = borderLeft + box->paddingLeft();
    492     int spacingRight = borderRight + box->paddingRight();
    493     int spacingTop = borderTop + box->paddingTop();
    494     int spacingBottom = borderBottom + box->paddingBottom();
    495 
    496     int buttonX;
    497     if (r.maxX() - r.x() < buttonWidth)
    498         buttonX = r.x();
    499     else
    500         buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft;
    501 
    502     // Compute the rectangle of the button in the destination image.
    503     IntRect rect(buttonX,
    504                  r.y() + spacingTop,
    505                  std::min(buttonWidth, r.maxX() - r.x()),
    506                  r.height() - (spacingTop + spacingBottom));
    507 
    508     // Get the correct theme data for a textfield and paint the menu.
    509     ThemePainter painter(i.context, rect);
    510     PlatformBridge::paintMenuList(painter.context(),
    511                                   CP_DROPDOWNBUTTON,
    512                                   determineState(o),
    513                                   determineClassicState(o),
    514                                   painter.drawRect());
    515     return false;
    516 }
    517 
    518 // static
    519 void RenderThemeChromiumWin::setDefaultFontSize(int fontSize)
    520 {
    521     RenderThemeChromiumSkia::setDefaultFontSize(fontSize);
    522 
    523     // Reset cached fonts.
    524     smallSystemFont = menuFont = labelFont = FontDescription();
    525 }
    526 
    527 double RenderThemeChromiumWin::caretBlinkIntervalInternal() const
    528 {
    529     // This involves a system call, so we cache the result.
    530     static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval());
    531     return blinkInterval;
    532 }
    533 
    534 unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart)
    535 {
    536     unsigned result = TS_NORMAL;
    537     ControlPart appearance = o->style()->appearance();
    538     if (!isEnabled(o))
    539         result = TS_DISABLED;
    540     else if (isReadOnlyControl(o))
    541         result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED;
    542     // Active overrides hover and focused.
    543     else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
    544         result = TS_PRESSED;
    545     else if (supportsFocus(appearance) && isFocused(o))
    546         result = ETS_FOCUSED;
    547     else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
    548         result = TS_HOT;
    549 
    550     // CBS_UNCHECKED*: 1-4
    551     // CBS_CHECKED*: 5-8
    552     // CBS_MIXED*: 9-12
    553     if (isIndeterminate(o))
    554         result += 8;
    555     else if (isChecked(o))
    556         result += 4;
    557     return result;
    558 }
    559 
    560 unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o)
    561 {
    562     unsigned result = TUS_NORMAL;
    563     if (!isEnabled(o->parent()))
    564         result = TUS_DISABLED;
    565     else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent()))
    566         result = TUS_FOCUSED;
    567     else if (toRenderSlider(o->parent())->inDragMode())
    568         result = TUS_PRESSED;
    569     else if (isHovered(o))
    570         result = TUS_HOT;
    571     return result;
    572 }
    573 
    574 unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart)
    575 {
    576     unsigned result = 0;
    577 
    578     ControlPart part = o->style()->appearance();
    579 
    580     // Sliders are always in the normal state.
    581     if (part == SliderHorizontalPart || part == SliderVerticalPart)
    582         return result;
    583 
    584     // So are readonly text fields.
    585     if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart))
    586         return result;
    587 
    588     if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
    589         if (!isEnabled(o->parent()))
    590             result = DFCS_INACTIVE;
    591         else if (toRenderSlider(o->parent())->inDragMode()) // Active supersedes hover
    592             result = DFCS_PUSHED;
    593         else if (isHovered(o))
    594             result = DFCS_HOT;
    595     } else {
    596         if (!isEnabled(o) || isReadOnlyControl(o))
    597             result = DFCS_INACTIVE;
    598         // Active supersedes hover
    599         else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
    600             result = DFCS_PUSHED;
    601         else if (supportsFocus(part) && isFocused(o)) // So does focused
    602             result = 0;
    603         else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
    604             result = DFCS_HOT;
    605         // Classic theme can't represent indeterminate states. Use unchecked appearance.
    606         if (isChecked(o) && !isIndeterminate(o))
    607             result |= DFCS_CHECKED;
    608     }
    609     return result;
    610 }
    611 
    612 ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart)
    613 {
    614     ThemeData result;
    615     switch (o->style()->appearance()) {
    616     case CheckboxPart:
    617         result.m_part = BP_CHECKBOX;
    618         result.m_state = determineState(o);
    619         result.m_classicState = DFCS_BUTTONCHECK;
    620         break;
    621     case RadioPart:
    622         result.m_part = BP_RADIOBUTTON;
    623         result.m_state = determineState(o);
    624         result.m_classicState = DFCS_BUTTONRADIO;
    625         break;
    626     case PushButtonPart:
    627     case ButtonPart:
    628         result.m_part = BP_PUSHBUTTON;
    629         result.m_state = determineState(o);
    630         result.m_classicState = DFCS_BUTTONPUSH;
    631         break;
    632     case SliderHorizontalPart:
    633         result.m_part = TKP_TRACK;
    634         result.m_state = TRS_NORMAL;
    635         break;
    636     case SliderVerticalPart:
    637         result.m_part = TKP_TRACKVERT;
    638         result.m_state = TRVS_NORMAL;
    639         break;
    640     case SliderThumbHorizontalPart:
    641         result.m_part = TKP_THUMBBOTTOM;
    642         result.m_state = determineSliderThumbState(o);
    643         break;
    644     case SliderThumbVerticalPart:
    645         result.m_part = TKP_THUMBVERT;
    646         result.m_state = determineSliderThumbState(o);
    647         break;
    648     case ListboxPart:
    649     case MenulistPart:
    650     case MenulistButtonPart:
    651     case SearchFieldPart:
    652     case TextFieldPart:
    653     case TextAreaPart:
    654         result.m_part = EP_EDITTEXT;
    655         result.m_state = determineState(o);
    656         break;
    657     case InnerSpinButtonPart:
    658         result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
    659         result.m_state = determineState(o, subPart);
    660         result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
    661         break;
    662     }
    663 
    664     result.m_classicState |= determineClassicState(o, subPart);
    665 
    666     return result;
    667 }
    668 
    669 bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
    670                                                     const PaintInfo& i,
    671                                                     const IntRect& r,
    672                                                     bool drawEdges)
    673 {
    674     // Fallback to white if the specified color object is invalid.
    675     // (Note PlatformBridge::paintTextField duplicates this check).
    676     Color backgroundColor(Color::white);
    677     if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
    678         backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
    679 
    680     // If we have background-image, don't fill the content area to expose the
    681     // parent's background. Also, we shouldn't fill the content area if the
    682     // alpha of the color is 0. The API of Windows GDI ignores the alpha.
    683     //
    684     // Note that we should paint the content area white if we have neither the
    685     // background color nor background image explicitly specified to keep the
    686     // appearance of select element consistent with other browsers.
    687     bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha();
    688 
    689     if (o->style()->hasBorderRadius()) {
    690         // If the style has rounded borders, setup the context to clip the
    691         // background (themed or filled) appropriately.
    692         // FIXME: make sure we do the right thing if css background-clip is set.
    693         i.context->save();
    694         i.context->addRoundedRectClip(o->style()->getRoundedBorderFor(r));
    695     }
    696     {
    697         const ThemeData& themeData = getThemeData(o);
    698         ThemePainter painter(i.context, r);
    699         PlatformBridge::paintTextField(painter.context(),
    700                                        themeData.m_part,
    701                                        themeData.m_state,
    702                                        themeData.m_classicState,
    703                                        painter.drawRect(),
    704                                        backgroundColor,
    705                                        fillContentArea,
    706                                        drawEdges);
    707         // End of block commits the painter before restoring context.
    708     }
    709     if (o->style()->hasBorderRadius())
    710         i.context->restore();
    711     return false;
    712 }
    713 
    714 void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    715 {
    716     int width = ScrollbarTheme::nativeTheme()->scrollbarThickness();
    717     style->setWidth(Length(width, Fixed));
    718     style->setMinWidth(Length(width, Fixed));
    719 }
    720 
    721 bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
    722 {
    723     IntRect half = rect;
    724 
    725     // Need explicit blocks to avoid to create multiple ThemePainter instances.
    726     {
    727         half.setHeight(rect.height() / 2);
    728         const ThemeData& upThemeData = getThemeData(object, SpinButtonUp);
    729         ThemePainter upPainter(info.context, half);
    730         PlatformBridge::paintSpinButton(upPainter.context(),
    731                                         upThemeData.m_part,
    732                                         upThemeData.m_state,
    733                                         upThemeData.m_classicState,
    734                                         upPainter.drawRect());
    735     }
    736 
    737     {
    738         half.setY(rect.y() + rect.height() / 2);
    739         const ThemeData& downThemeData = getThemeData(object, SpinButtonDown);
    740         ThemePainter downPainter(info.context, half);
    741         PlatformBridge::paintSpinButton(downPainter.context(),
    742                                         downThemeData.m_part,
    743                                         downThemeData.m_state,
    744                                         downThemeData.m_classicState,
    745                                         downPainter.drawRect());
    746     }
    747     return false;
    748 }
    749 
    750 #if ENABLE(PROGRESS_TAG)
    751 
    752 // MSDN says that update intervals for the bar is 30ms.
    753 // http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx
    754 static const double progressAnimationFrameRate = 0.033;
    755 
    756 double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const
    757 {
    758     return progressAnimationFrameRate;
    759 }
    760 
    761 double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const
    762 {
    763     // On Chromium Windows port, animationProgress() and associated values aren't used.
    764     // So here we can return arbitrary positive value.
    765     return progressAnimationFrameRate;
    766 }
    767 
    768 void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const
    769 {
    770 }
    771 
    772 bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r)
    773 {
    774     if (!o->isProgress())
    775         return true;
    776 
    777     RenderProgress* renderProgress = toRenderProgress(o);
    778     // For indeterminate bar, valueRect is ignored and it is computed by the theme engine
    779     // because the animation is a platform detail and WebKit doesn't need to know how.
    780     IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0);
    781     double animatedSeconds = renderProgress->animationStartTime() ?  WTF::currentTime() - renderProgress->animationStartTime() : 0;
    782     ThemePainter painter(i.context, r);
    783     PlatformBridge::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds);
    784     return false;
    785 }
    786 
    787 #endif
    788 
    789 } // namespace WebCore
    790