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