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 "core/rendering/RenderThemeChromiumWin.h"
     27 
     28 #include <windows.h>
     29 #include <uxtheme.h>
     30 #include <vssym32.h>
     31 
     32 #include "CSSValueKeywords.h"
     33 #include "HTMLNames.h"
     34 #include "core/html/HTMLMediaElement.h"
     35 #include "core/html/shadow/MediaControlElements.h"
     36 #include "core/rendering/PaintInfo.h"
     37 #include "core/rendering/RenderBox.h"
     38 #include "core/rendering/RenderProgress.h"
     39 #include "core/rendering/RenderSlider.h"
     40 #include "platform/LayoutTestSupport.h"
     41 #include "platform/fonts/FontSelector.h"
     42 #include "platform/graphics/GraphicsContext.h"
     43 #include "platform/graphics/win/TransparencyWin.h"
     44 #include "platform/scroll/ScrollbarTheme.h"
     45 #include "platform/win/SystemInfo.h"
     46 #include "public/platform/Platform.h"
     47 #include "public/platform/WebColor.h"
     48 #include "public/platform/WebRect.h"
     49 #include "public/platform/win/WebThemeEngine.h"
     50 #include "wtf/CurrentTime.h"
     51 #include "wtf/StdLibExtras.h"
     52 
     53 // FIXME: This dependency should eventually be removed.
     54 #include <skia/ext/skia_utils_win.h>
     55 
     56 namespace WebCore {
     57 
     58 // The standard width for the menu list drop-down button when run under
     59 // layout test mode. Use the value that's currently captured in most baselines.
     60 static const int kStandardMenuListButtonWidth = 17;
     61 
     62 namespace {
     63 // We must not create multiple ThemePainter instances.
     64 class ThemePainter {
     65 public:
     66     ThemePainter(GraphicsContext* context, const IntRect& r)
     67     {
     68 #ifndef NDEBUG
     69         ASSERT(!s_hasInstance);
     70         s_hasInstance = true;
     71 #endif
     72         TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM());
     73         m_helper.init(context, getLayerMode(context, transformMode), transformMode, r);
     74 
     75         if (!m_helper.context()) {
     76             // TransparencyWin doesn't have well-defined copy-ctor nor op=()
     77             // so we re-initialize it instead of assigning a fresh istance.
     78             // On the reinitialization, we fallback to use NoLayer mode.
     79             // Note that the original initialization failure can be caused by
     80             // a failure of an internal buffer allocation and NoLayer mode
     81             // does not have such buffer allocations.
     82             m_helper.~TransparencyWin();
     83             new (&m_helper) TransparencyWin();
     84             m_helper.init(context, TransparencyWin::NoLayer, transformMode, r);
     85         }
     86     }
     87 
     88     ~ThemePainter()
     89     {
     90         m_helper.composite();
     91 #ifndef NDEBUG
     92         s_hasInstance = false;
     93 #endif
     94     }
     95 
     96     GraphicsContext* context() { return m_helper.context(); }
     97     const IntRect& drawRect() { return m_helper.drawRect(); }
     98 
     99 private:
    100 
    101     static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode)
    102     {
    103         if (!context->isCertainlyOpaque()) // Might have transparent background.
    104             return TransparencyWin::WhiteLayer;
    105         if (context->canvas()->isDrawingToLayer()) // Needs antialiasing help.
    106             return TransparencyWin::OpaqueCompositeLayer;
    107         // Nothing interesting.
    108         return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer;
    109     }
    110 
    111     static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix)
    112     {
    113         if (matrix.b() || matrix.c()) // Skew.
    114             return TransparencyWin::Untransform;
    115         if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale.
    116             return TransparencyWin::ScaleTransform;
    117         // Nothing interesting.
    118         return TransparencyWin::KeepTransform;
    119     }
    120 
    121     TransparencyWin m_helper;
    122 #ifndef NDEBUG
    123     static bool s_hasInstance;
    124 #endif
    125 };
    126 
    127 #ifndef NDEBUG
    128 bool ThemePainter::s_hasInstance = false;
    129 #endif
    130 
    131 } // namespace
    132 
    133 // Internal static helper functions.  We don't put them in an anonymous
    134 // namespace so they have easier access to the WebCore namespace.
    135 
    136 static bool supportsFocus(ControlPart appearance)
    137 {
    138     switch (appearance) {
    139     case SquareButtonPart:
    140     case PushButtonPart:
    141     case ButtonPart:
    142     case SearchFieldPart:
    143     case TextFieldPart:
    144     case TextAreaPart:
    145         return true;
    146     }
    147     return false;
    148 }
    149 
    150 static double querySystemBlinkInterval(double defaultInterval)
    151 {
    152     UINT blinkTime = GetCaretBlinkTime();
    153     if (!blinkTime)
    154         return defaultInterval;
    155     if (blinkTime == INFINITE)
    156         return 0;
    157     return blinkTime / 1000.0;
    158 }
    159 
    160 PassRefPtr<RenderTheme> RenderThemeChromiumWin::create()
    161 {
    162     return adoptRef(new RenderThemeChromiumWin);
    163 }
    164 
    165 RenderTheme& RenderTheme::theme()
    166 {
    167     DEFINE_STATIC_REF(RenderTheme, renderTheme, (RenderThemeChromiumWin::create()));
    168     return *renderTheme;
    169 }
    170 
    171 bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const
    172 {
    173     // Let webkit draw one of its halo rings around any focused element,
    174     // except push buttons. For buttons we use the windows PBS_DEFAULTED
    175     // styling to give it a blue border.
    176     return style->appearance() == ButtonPart
    177             || style->appearance() == PushButtonPart
    178             || style->appearance() == SquareButtonPart;
    179 }
    180 
    181 Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
    182 {
    183     if (isRunningLayoutTest())
    184         return Color(0x00, 0x00, 0xff); // Royal blue.
    185     COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
    186     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
    187 }
    188 
    189 Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const
    190 {
    191     if (isRunningLayoutTest())
    192         return Color(0x99, 0x99, 0x99); // Medium gray.
    193     COLORREF color = GetSysColor(COLOR_GRAYTEXT);
    194     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
    195 }
    196 
    197 Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const
    198 {
    199     if (isRunningLayoutTest())
    200         return Color(0xff, 0xff, 0xcc); // Pale yellow.
    201     COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
    202     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
    203 }
    204 
    205 Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const
    206 {
    207     return Color::white;
    208 }
    209 
    210 Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const
    211 {
    212     return Color(0xff, 0x96, 0x32); // Orange.
    213 }
    214 
    215 Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const
    216 {
    217     return Color(0xff, 0xff, 0x96); // Yellow.
    218 }
    219 
    220 // Map a CSSValue* system color to an index understood by GetSysColor().
    221 static int cssValueIdToSysColorIndex(int cssValueId)
    222 {
    223     switch (cssValueId) {
    224     case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
    225     case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
    226     case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
    227     case CSSValueBackground: return COLOR_BACKGROUND;
    228     case CSSValueButtonface: return COLOR_BTNFACE;
    229     case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
    230     case CSSValueButtonshadow: return COLOR_BTNSHADOW;
    231     case CSSValueButtontext: return COLOR_BTNTEXT;
    232     case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
    233     case CSSValueGraytext: return COLOR_GRAYTEXT;
    234     case CSSValueHighlight: return COLOR_HIGHLIGHT;
    235     case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
    236     case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
    237     case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
    238     case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
    239     case CSSValueInfobackground: return COLOR_INFOBK;
    240     case CSSValueInfotext: return COLOR_INFOTEXT;
    241     case CSSValueMenu: return COLOR_MENU;
    242     case CSSValueMenutext: return COLOR_MENUTEXT;
    243     case CSSValueScrollbar: return COLOR_SCROLLBAR;
    244     case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
    245     case CSSValueThreedface: return COLOR_3DFACE;
    246     case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
    247     case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
    248     case CSSValueThreedshadow: return COLOR_3DSHADOW;
    249     case CSSValueWindow: return COLOR_WINDOW;
    250     case CSSValueWindowframe: return COLOR_WINDOWFRAME;
    251     case CSSValueWindowtext: return COLOR_WINDOWTEXT;
    252     default: return -1; // Unsupported CSSValue
    253     }
    254 }
    255 
    256 Color RenderThemeChromiumWin::systemColor(CSSValueID cssValueId) const
    257 {
    258     int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
    259     if (isRunningLayoutTest() || (sysColorIndex == -1))
    260         return RenderTheme::systemColor(cssValueId);
    261 
    262     COLORREF color = GetSysColor(sysColorIndex);
    263     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
    264 }
    265 
    266 IntSize RenderThemeChromiumWin::sliderTickSize() const
    267 {
    268     return IntSize(1, 3);
    269 }
    270 
    271 int RenderThemeChromiumWin::sliderTickOffsetFromTrackCenter() const
    272 {
    273     return 11;
    274 }
    275 
    276 void RenderThemeChromiumWin::adjustSliderThumbSize(RenderStyle* style, Element* element) const
    277 {
    278     // These sizes match what WinXP draws for various menus.
    279     const int sliderThumbAlongAxis = 11;
    280     const int sliderThumbAcrossAxis = 21;
    281     if (style->appearance() == SliderThumbHorizontalPart) {
    282         style->setWidth(Length(sliderThumbAlongAxis, Fixed));
    283         style->setHeight(Length(sliderThumbAcrossAxis, Fixed));
    284     } else if (style->appearance() == SliderThumbVerticalPart) {
    285         style->setWidth(Length(sliderThumbAcrossAxis, Fixed));
    286         style->setHeight(Length(sliderThumbAlongAxis, Fixed));
    287     } else
    288         RenderThemeChromiumSkia::adjustSliderThumbSize(style, element);
    289 }
    290 
    291 bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
    292 {
    293     return paintButton(o, i, r);
    294 }
    295 bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
    296 {
    297     return paintButton(o, i, r);
    298 }
    299 
    300 bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
    301 {
    302     const ThemeData& themeData = getThemeData(o);
    303 
    304     ThemePainter painter(i.context, r);
    305     blink::WebCanvas* canvas = painter.context()->canvas();
    306     blink::Platform::current()->themeEngine()->paintButton(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect()));
    307     return false;
    308 }
    309 
    310 bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
    311 {
    312     return paintTextFieldInternal(o, i, r, true);
    313 }
    314 
    315 bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
    316 {
    317     const ThemeData& themeData = getThemeData(o);
    318 
    319     ThemePainter painter(i.context, r);
    320     blink::WebCanvas* canvas = painter.context()->canvas();
    321     blink::Platform::current()->themeEngine()->paintTrackbar(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect()));
    322 
    323     paintSliderTicks(o, i, r);
    324 
    325     return false;
    326 }
    327 
    328 bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
    329 {
    330     const ThemeData& themeData = getThemeData(o);
    331 
    332     ThemePainter painter(i.context, r);
    333     blink::WebCanvas* canvas = painter.context()->canvas();
    334     blink::Platform::current()->themeEngine()->paintTrackbar(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect()));
    335 
    336     return false;
    337 }
    338 
    339 static int menuListButtonWidth()
    340 {
    341     static int width = isRunningLayoutTest() ? kStandardMenuListButtonWidth :
    342         IntSize(blink::Platform::current()->themeEngine()->getSize(SBP_ARROWBTN)).width();
    343     return width;
    344 }
    345 
    346 // Used to paint unstyled menulists (i.e. with the default border)
    347 bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
    348 {
    349     if (!o->isBox())
    350         return false;
    351 
    352     const RenderBox* box = toRenderBox(o);
    353     int borderRight = box->borderRight();
    354     int borderLeft = box->borderLeft();
    355     int borderTop = box->borderTop();
    356     int borderBottom = box->borderBottom();
    357 
    358     // If all the borders are 0, then tell skia not to paint the border on the
    359     // textfield.  FIXME: http://b/1210017 Figure out how to get Windows to not
    360     // draw individual borders and then pass that to skia so we can avoid
    361     // drawing any borders that are set to 0. For non-zero borders, we draw the
    362     // border, but webkit just draws over it.
    363     bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom);
    364 
    365     paintTextFieldInternal(o, i, r, drawEdges);
    366     return paintMenuListButton(o, i, r);
    367 }
    368 
    369 bool RenderThemeChromiumWin::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
    370 {
    371     if (!o->isBox())
    372         return false;
    373 
    374     const RenderBox* box = toRenderBox(o);
    375     // Take padding and border into account.  If the MenuList is smaller than
    376     // the size of a button, make sure to shrink it appropriately and not put
    377     // its x position to the left of the menulist.
    378     const int buttonWidth = menuListButtonWidth();
    379     int spacingLeft = box->borderLeft() + box->paddingLeft();
    380     int spacingRight = box->borderRight() + box->paddingRight();
    381     int spacingTop = box->borderTop() + box->paddingTop();
    382     int spacingBottom = box->borderBottom() + box->paddingBottom();
    383 
    384     int buttonX;
    385     if (r.maxX() - r.x() < buttonWidth)
    386         buttonX = r.x();
    387     else
    388         buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft;
    389 
    390     // Compute the rectangle of the button in the destination image.
    391     IntRect rect(buttonX,
    392                  r.y() + spacingTop,
    393                  std::min(buttonWidth, r.maxX() - r.x()),
    394                  r.height() - (spacingTop + spacingBottom));
    395 
    396     // Get the correct theme data for a textfield and paint the menu.
    397     ThemePainter painter(i.context, rect);
    398     blink::WebCanvas* canvas = painter.context()->canvas();
    399     blink::Platform::current()->themeEngine()->paintMenuList(canvas, CP_DROPDOWNBUTTON, determineState(o), determineClassicState(o), blink::WebRect(painter.drawRect()));
    400     return false;
    401 }
    402 
    403 double RenderThemeChromiumWin::caretBlinkIntervalInternal() const
    404 {
    405     // This involves a system call, so we cache the result.
    406     static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval());
    407     return blinkInterval;
    408 }
    409 
    410 unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart)
    411 {
    412     unsigned result = TS_NORMAL;
    413     ControlPart appearance = o->style()->appearance();
    414     if (!isEnabled(o))
    415         result = TS_DISABLED;
    416     else if (isReadOnlyControl(o))
    417         result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED;
    418     // Active overrides hover and focused.
    419     else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
    420         result = TS_PRESSED;
    421     else if (supportsFocus(appearance) && isFocused(o))
    422         result = ETS_FOCUSED;
    423     else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
    424         result = TS_HOT;
    425 
    426     // CBS_UNCHECKED*: 1-4
    427     // CBS_CHECKED*: 5-8
    428     // CBS_MIXED*: 9-12
    429     if (isIndeterminate(o))
    430         result += 8;
    431     else if (isChecked(o))
    432         result += 4;
    433     return result;
    434 }
    435 
    436 unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o)
    437 {
    438     unsigned result = TUS_NORMAL;
    439     if (!isEnabled(o))
    440         result = TUS_DISABLED;
    441     else if (supportsFocus(o->style()->appearance()) && isFocused(o))
    442         result = TUS_FOCUSED;
    443     else if (isPressed(o))
    444         result = TUS_PRESSED;
    445     else if (isHovered(o))
    446         result = TUS_HOT;
    447     return result;
    448 }
    449 
    450 unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart)
    451 {
    452     unsigned result = 0;
    453 
    454     ControlPart part = o->style()->appearance();
    455 
    456     // Sliders are always in the normal state.
    457     if (part == SliderHorizontalPart || part == SliderVerticalPart)
    458         return result;
    459 
    460     // So are readonly text fields.
    461     if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart))
    462         return result;
    463 
    464     if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
    465         if (!isEnabled(o))
    466             result = DFCS_INACTIVE;
    467         else if (isPressed(o)) // Active supersedes hover
    468             result = DFCS_PUSHED;
    469         else if (isHovered(o))
    470             result = DFCS_HOT;
    471     } else {
    472         if (!isEnabled(o) || isReadOnlyControl(o))
    473             result = DFCS_INACTIVE;
    474         // Active supersedes hover
    475         else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
    476             result = DFCS_PUSHED;
    477         else if (supportsFocus(part) && isFocused(o)) // So does focused
    478             result = 0;
    479         else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
    480             result = DFCS_HOT;
    481         // Classic theme can't represent indeterminate states. Use unchecked appearance.
    482         if (isChecked(o) && !isIndeterminate(o))
    483             result |= DFCS_CHECKED;
    484     }
    485     return result;
    486 }
    487 
    488 ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart)
    489 {
    490     ThemeData result;
    491     switch (o->style()->appearance()) {
    492     case CheckboxPart:
    493         result.m_part = BP_CHECKBOX;
    494         result.m_state = determineState(o);
    495         result.m_classicState = DFCS_BUTTONCHECK;
    496         break;
    497     case RadioPart:
    498         result.m_part = BP_RADIOBUTTON;
    499         result.m_state = determineState(o);
    500         result.m_classicState = DFCS_BUTTONRADIO;
    501         break;
    502     case SquareButtonPart:
    503     case PushButtonPart:
    504     case ButtonPart:
    505         result.m_part = BP_PUSHBUTTON;
    506         result.m_state = determineState(o);
    507         result.m_classicState = DFCS_BUTTONPUSH;
    508         break;
    509     case SliderHorizontalPart:
    510         result.m_part = TKP_TRACK;
    511         result.m_state = TRS_NORMAL;
    512         break;
    513     case SliderVerticalPart:
    514         result.m_part = TKP_TRACKVERT;
    515         result.m_state = TRVS_NORMAL;
    516         break;
    517     case SliderThumbHorizontalPart:
    518         result.m_part = TKP_THUMBBOTTOM;
    519         result.m_state = determineSliderThumbState(o);
    520         break;
    521     case SliderThumbVerticalPart:
    522         result.m_part = TKP_THUMBVERT;
    523         result.m_state = determineSliderThumbState(o);
    524         break;
    525     case ListboxPart:
    526     case MenulistPart:
    527     case MenulistButtonPart:
    528     case SearchFieldPart:
    529     case TextFieldPart:
    530     case TextAreaPart:
    531         result.m_part = EP_EDITTEXT;
    532         result.m_state = determineState(o);
    533         break;
    534     case InnerSpinButtonPart:
    535         result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
    536         result.m_state = determineState(o, subPart);
    537         result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
    538         break;
    539     }
    540 
    541     result.m_classicState |= determineClassicState(o, subPart);
    542 
    543     return result;
    544 }
    545 
    546 bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
    547                                                     const PaintInfo& i,
    548                                                     const IntRect& r,
    549                                                     bool drawEdges)
    550 {
    551     // Fallback to white if the specified color object is invalid.
    552     Color backgroundColor(Color::white);
    553     if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
    554         backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
    555 
    556     // If we have background-image, don't fill the content area to expose the
    557     // parent's background. Also, we shouldn't fill the content area if the
    558     // alpha of the color is 0. The API of Windows GDI ignores the alpha.
    559     //
    560     // Note that we should paint the content area white if we have neither the
    561     // background color nor background image explicitly specified to keep the
    562     // appearance of select element consistent with other browsers.
    563     bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha();
    564 
    565     if (o->style()->hasBorderRadius()) {
    566         // If the style has rounded borders, setup the context to clip the
    567         // background (themed or filled) appropriately.
    568         // FIXME: make sure we do the right thing if css background-clip is set.
    569         i.context->save();
    570         i.context->clipRoundedRect(o->style()->getRoundedBorderFor(r));
    571     }
    572     {
    573         const ThemeData& themeData = getThemeData(o);
    574         ThemePainter painter(i.context, r);
    575         blink::WebCanvas* canvas = painter.context()->canvas();
    576         blink::Platform::current()->themeEngine()->paintTextField(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect()), backgroundColor.rgb(), fillContentArea, drawEdges);
    577         // End of block commits the painter before restoring context.
    578     }
    579     if (o->style()->hasBorderRadius())
    580         i.context->restore();
    581     return false;
    582 }
    583 
    584 void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(RenderStyle* style, Element*) const
    585 {
    586     int width = ScrollbarTheme::theme()->scrollbarThickness();
    587     style->setWidth(Length(width, Fixed));
    588     style->setMinWidth(Length(width, Fixed));
    589 }
    590 
    591 bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
    592 {
    593     IntRect half = rect;
    594 
    595     // Need explicit blocks to avoid to create multiple ThemePainter instances.
    596     {
    597         half.setHeight(rect.height() / 2);
    598         const ThemeData& upThemeData = getThemeData(object, SpinButtonUp);
    599         ThemePainter upPainter(info.context, half);
    600         blink::WebCanvas* canvas = upPainter.context()->canvas();
    601         blink::Platform::current()->themeEngine()->paintSpinButton(canvas, upThemeData.m_part, upThemeData.m_state, upThemeData.m_classicState, blink::WebRect(upPainter.drawRect()));
    602     }
    603 
    604     {
    605         half.setY(rect.y() + rect.height() / 2);
    606         const ThemeData& downThemeData = getThemeData(object, SpinButtonDown);
    607         ThemePainter downPainter(info.context, half);
    608         blink::WebCanvas* canvas = downPainter.context()->canvas();
    609         blink::Platform::current()->themeEngine()->paintSpinButton(canvas, downThemeData.m_part, downThemeData.m_state, downThemeData.m_classicState, blink::WebRect(downPainter.drawRect()));
    610     }
    611     return false;
    612 }
    613 
    614 // MSDN says that update intervals for the bar is 30ms.
    615 // http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx
    616 static const double progressAnimationFrameRate = 0.033;
    617 
    618 double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const
    619 {
    620     return progressAnimationFrameRate;
    621 }
    622 
    623 double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const
    624 {
    625     // On Chromium Windows port, animationProgress() and associated values aren't used.
    626     // So here we can return arbitrary positive value.
    627     return progressAnimationFrameRate;
    628 }
    629 
    630 bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r)
    631 {
    632     if (!o->isProgress())
    633         return true;
    634 
    635     RenderProgress* renderProgress = toRenderProgress(o);
    636     // For indeterminate bar, valueRect is ignored and it is computed by the theme engine
    637     // because the animation is a platform detail and WebKit doesn't need to know how.
    638     IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0);
    639     double animatedSeconds = renderProgress->animationStartTime() ?  WTF::currentTime() - renderProgress->animationStartTime() : 0;
    640     ThemePainter painter(i.context, r);
    641     DirectionFlippingScope scope(o, i, r);
    642     blink::WebCanvas* canvas = painter.context()->canvas();
    643     blink::Platform::current()->themeEngine()->paintProgressBar(canvas, blink::WebRect(r), blink::WebRect(valueRect), renderProgress->isDeterminate(), animatedSeconds);
    644     return false;
    645 }
    646 
    647 bool RenderThemeChromiumWin::shouldOpenPickerWithF4Key() const
    648 {
    649     return true;
    650 }
    651 
    652 bool RenderThemeChromiumWin::shouldUseFallbackTheme(RenderStyle* style) const
    653 {
    654     ControlPart part = style->appearance();
    655     if (part == CheckboxPart || part == RadioPart)
    656         return style->effectiveZoom() != 1;
    657     return false;
    658 }
    659 
    660 } // namespace WebCore
    661