[chromium] Convert uses of GetDC to HWndDC.
[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 "HWndDC.h"
40 #include "MediaControlElements.h"
41 #include "PaintInfo.h"
42 #include "PlatformSupport.h"
43 #include "RenderBox.h"
44 #include "RenderProgress.h"
45 #include "RenderSlider.h"
46 #include "ScrollbarTheme.h"
47 #include "SystemInfo.h"
48 #include "TransparencyWin.h"
49
50 // FIXME: This dependency should eventually be removed.
51 #include <skia/ext/skia_utils_win.h>
52
53 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
54     offsetof(structName, member) + \
55     (sizeof static_cast<structName*>(0)->member)
56 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \
57     SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
58
59 namespace WebCore {
60
61 // The standard width for the menu list drop-down button when run under
62 // layout test mode. Use the value that's currently captured in most baselines.
63 static const int kStandardMenuListButtonWidth = 17;
64
65 namespace {
66 // We must not create multiple ThemePainter instances.
67 class ThemePainter {
68 public:
69     ThemePainter(GraphicsContext* context, const IntRect& r)
70     {
71 #ifndef NDEBUG
72         ASSERT(!s_hasInstance);
73         s_hasInstance = true;
74 #endif
75         TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM());
76         m_helper.init(context, getLayerMode(context, transformMode), transformMode, r);
77
78         if (!m_helper.context()) {
79             // TransparencyWin doesn't have well-defined copy-ctor nor op=()
80             // so we re-initialize it instead of assigning a fresh istance.
81             // On the reinitialization, we fallback to use NoLayer mode.
82             // Note that the original initialization failure can be caused by
83             // a failure of an internal buffer allocation and NoLayer mode
84             // does not have such buffer allocations.
85             m_helper.~TransparencyWin();
86             new (&m_helper) TransparencyWin();
87             m_helper.init(context, TransparencyWin::NoLayer, transformMode, r);
88         }
89     }
90
91     ~ThemePainter()
92     {
93         m_helper.composite();
94 #ifndef NDEBUG
95         s_hasInstance = false;
96 #endif
97     }
98
99     GraphicsContext* context() { return m_helper.context(); }
100     const IntRect& drawRect() { return m_helper.drawRect(); }
101
102 private:
103
104     static bool canvasHasMultipleLayers(const SkCanvas* canvas)
105     {
106         SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
107         iter.next(); // There is always at least one layer.
108         return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
109     }
110
111     static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode)
112     {
113         if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background.
114             return TransparencyWin::WhiteLayer;
115         if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help.
116             return TransparencyWin::OpaqueCompositeLayer;
117         // Nothing interesting.
118         return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer;
119     }
120
121     static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix)
122     {
123         if (matrix.b() || matrix.c()) // Skew.
124             return TransparencyWin::Untransform;
125         if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale.
126             return TransparencyWin::ScaleTransform;
127         // Nothing interesting.
128         return TransparencyWin::KeepTransform;
129     }
130
131     TransparencyWin m_helper;
132 #ifndef NDEBUG
133     static bool s_hasInstance;
134 #endif
135 };
136
137 #ifndef NDEBUG
138 bool ThemePainter::s_hasInstance = false;
139 #endif
140
141 } // namespace
142
143 static void getNonClientMetrics(NONCLIENTMETRICS* metrics)
144 {
145     static UINT size = (windowsVersion() >= WindowsVista) ?
146         (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
147     metrics->cbSize = size;
148     bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0);
149     ASSERT(success);
150 }
151
152 static FontDescription smallSystemFont;
153 static FontDescription menuFont;
154 static FontDescription labelFont;
155
156 // Internal static helper functions.  We don't put them in an anonymous
157 // namespace so they have easier access to the WebCore namespace.
158
159 static bool supportsFocus(ControlPart appearance)
160 {
161     switch (appearance) {
162     case SquareButtonPart:
163     case PushButtonPart:
164     case ButtonPart:
165     case DefaultButtonPart:
166     case SearchFieldPart:
167     case TextFieldPart:
168     case TextAreaPart:
169         return true;
170     }
171     return false;
172 }
173
174 // Return the height of system font |font| in pixels.  We use this size by
175 // default for some non-form-control elements.
176 static float systemFontSize(const LOGFONT& font)
177 {
178     float size = -font.lfHeight;
179     if (size < 0) {
180         HFONT hFont = CreateFontIndirect(&font);
181         if (hFont) {
182             HWndDC hdc(0); // What about printing? Is this the right DC?
183             if (hdc) {
184                 HGDIOBJ hObject = SelectObject(hdc, hFont);
185                 TEXTMETRIC tm;
186                 GetTextMetrics(hdc, &tm);
187                 SelectObject(hdc, hObject);
188                 size = tm.tmAscent;
189             }
190             DeleteObject(hFont);
191         }
192     }
193
194     // The "codepage 936" bit here is from Gecko; apparently this helps make
195     // fonts more legible in Simplified Chinese where the default font size is
196     // too small.
197     //
198     // FIXME: http://b/1119883 Since this is only used for "small caption",
199     // "menu", and "status bar" objects, I'm not sure how much this even
200     // matters.  Plus the Gecko patch went in back in 2002, and maybe this
201     // isn't even relevant anymore.  We should investigate whether this should
202     // be removed, or perhaps broadened to be "any CJK locale".
203     //
204     return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size;
205 }
206
207 // Converts |points| to pixels.  One point is 1/72 of an inch.
208 static float pointsToPixels(float points)
209 {
210     static float pixelsPerInch = 0.0f;
211     if (!pixelsPerInch) {
212         HWndDC hdc(0); // What about printing? Is this the right DC?
213         if (hdc) // Can this ever actually be NULL?
214             pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
215         else
216             pixelsPerInch = 96.0f;
217     }
218
219     static const float pointsPerInch = 72.0f;
220     return points / pointsPerInch * pixelsPerInch;
221 }
222
223 static double querySystemBlinkInterval(double defaultInterval)
224 {
225     UINT blinkTime = GetCaretBlinkTime();
226     if (!blinkTime)
227         return defaultInterval;
228     if (blinkTime == INFINITE)
229         return 0;
230     return blinkTime / 1000.0;
231 }
232
233 PassRefPtr<RenderTheme> RenderThemeChromiumWin::create()
234 {
235     return adoptRef(new RenderThemeChromiumWin);
236 }
237
238 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
239 {
240     static RenderTheme* rt = RenderThemeChromiumWin::create().leakRef();
241     return rt;
242 }
243
244 bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const
245 {
246     // Let webkit draw one of its halo rings around any focused element,
247     // except push buttons. For buttons we use the windows PBS_DEFAULTED
248     // styling to give it a blue border.
249     return style->appearance() == ButtonPart
250             || style->appearance() == PushButtonPart
251             || style->appearance() == SquareButtonPart;
252 }
253
254 Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
255 {
256     if (PlatformSupport::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 (PlatformSupport::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 (PlatformSupport::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 (PlatformSupport::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(RenderStyle* style) const
401 {
402     // These sizes match what WinXP draws for various menus.
403     const int sliderThumbAlongAxis = 11;
404     const int sliderThumbAcrossAxis = 21;
405     if (style->appearance() == SliderThumbHorizontalPart) {
406         style->setWidth(Length(sliderThumbAlongAxis, Fixed));
407         style->setHeight(Length(sliderThumbAcrossAxis, Fixed));
408     } else if (style->appearance() == SliderThumbVerticalPart) {
409         style->setWidth(Length(sliderThumbAcrossAxis, Fixed));
410         style->setHeight(Length(sliderThumbAlongAxis, Fixed));
411     } else
412         RenderThemeChromiumSkia::adjustSliderThumbSize(style);
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     PlatformSupport::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     PlatformSupport::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 = PlatformSupport::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     PlatformSupport::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))
564         result = TUS_DISABLED;
565     else if (supportsFocus(o->style()->appearance()) && isFocused(o))
566         result = TUS_FOCUSED;
567     else if (isPressed(o))
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))
590             result = DFCS_INACTIVE;
591         else if (isPressed(o)) // 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 SquareButtonPart:
627     case PushButtonPart:
628     case ButtonPart:
629         result.m_part = BP_PUSHBUTTON;
630         result.m_state = determineState(o);
631         result.m_classicState = DFCS_BUTTONPUSH;
632         break;
633     case SliderHorizontalPart:
634         result.m_part = TKP_TRACK;
635         result.m_state = TRS_NORMAL;
636         break;
637     case SliderVerticalPart:
638         result.m_part = TKP_TRACKVERT;
639         result.m_state = TRVS_NORMAL;
640         break;
641     case SliderThumbHorizontalPart:
642         result.m_part = TKP_THUMBBOTTOM;
643         result.m_state = determineSliderThumbState(o);
644         break;
645     case SliderThumbVerticalPart:
646         result.m_part = TKP_THUMBVERT;
647         result.m_state = determineSliderThumbState(o);
648         break;
649     case ListboxPart:
650     case MenulistPart:
651     case MenulistButtonPart:
652     case SearchFieldPart:
653     case TextFieldPart:
654     case TextAreaPart:
655         result.m_part = EP_EDITTEXT;
656         result.m_state = determineState(o);
657         break;
658     case InnerSpinButtonPart:
659         result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
660         result.m_state = determineState(o, subPart);
661         result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
662         break;
663     }
664
665     result.m_classicState |= determineClassicState(o, subPart);
666
667     return result;
668 }
669
670 bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
671                                                     const PaintInfo& i,
672                                                     const IntRect& r,
673                                                     bool drawEdges)
674 {
675     // Fallback to white if the specified color object is invalid.
676     // (Note PlatformSupport::paintTextField duplicates this check).
677     Color backgroundColor(Color::white);
678     if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
679         backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
680
681     // If we have background-image, don't fill the content area to expose the
682     // parent's background. Also, we shouldn't fill the content area if the
683     // alpha of the color is 0. The API of Windows GDI ignores the alpha.
684     //
685     // Note that we should paint the content area white if we have neither the
686     // background color nor background image explicitly specified to keep the
687     // appearance of select element consistent with other browsers.
688     bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha();
689
690     if (o->style()->hasBorderRadius()) {
691         // If the style has rounded borders, setup the context to clip the
692         // background (themed or filled) appropriately.
693         // FIXME: make sure we do the right thing if css background-clip is set.
694         i.context->save();
695         i.context->addRoundedRectClip(o->style()->getRoundedBorderFor(r));
696     }
697     {
698         const ThemeData& themeData = getThemeData(o);
699         ThemePainter painter(i.context, r);
700         PlatformSupport::paintTextField(painter.context(),
701                                         themeData.m_part,
702                                         themeData.m_state,
703                                         themeData.m_classicState,
704                                         painter.drawRect(),
705                                         backgroundColor,
706                                         fillContentArea,
707                                         drawEdges);
708         // End of block commits the painter before restoring context.
709     }
710     if (o->style()->hasBorderRadius())
711         i.context->restore();
712     return false;
713 }
714
715 void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
716 {
717     int width = ScrollbarTheme::theme()->scrollbarThickness();
718     style->setWidth(Length(width, Fixed));
719     style->setMinWidth(Length(width, Fixed));
720 }
721
722 bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
723 {
724     IntRect half = rect;
725
726     // Need explicit blocks to avoid to create multiple ThemePainter instances.
727     {
728         half.setHeight(rect.height() / 2);
729         const ThemeData& upThemeData = getThemeData(object, SpinButtonUp);
730         ThemePainter upPainter(info.context, half);
731         PlatformSupport::paintSpinButton(upPainter.context(),
732                                          upThemeData.m_part,
733                                          upThemeData.m_state,
734                                          upThemeData.m_classicState,
735                                          upPainter.drawRect());
736     }
737
738     {
739         half.setY(rect.y() + rect.height() / 2);
740         const ThemeData& downThemeData = getThemeData(object, SpinButtonDown);
741         ThemePainter downPainter(info.context, half);
742         PlatformSupport::paintSpinButton(downPainter.context(),
743                                          downThemeData.m_part,
744                                          downThemeData.m_state,
745                                          downThemeData.m_classicState,
746                                          downPainter.drawRect());
747     }
748     return false;
749 }
750
751 #if ENABLE(PROGRESS_TAG)
752
753 // MSDN says that update intervals for the bar is 30ms.
754 // http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx
755 static const double progressAnimationFrameRate = 0.033;
756
757 double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const
758 {
759     return progressAnimationFrameRate;
760 }
761
762 double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const
763 {
764     // On Chromium Windows port, animationProgress() and associated values aren't used.
765     // So here we can return arbitrary positive value.
766     return progressAnimationFrameRate;
767 }
768
769 void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const
770 {
771 }
772
773 bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r)
774 {
775     if (!o->isProgress())
776         return true;
777
778     RenderProgress* renderProgress = toRenderProgress(o);
779     // For indeterminate bar, valueRect is ignored and it is computed by the theme engine
780     // because the animation is a platform detail and WebKit doesn't need to know how.
781     IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0);
782     double animatedSeconds = renderProgress->animationStartTime() ?  WTF::currentTime() - renderProgress->animationStartTime() : 0;
783     ThemePainter painter(i.context, r);
784     PlatformSupport::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds);
785     return false;
786 }
787
788 #endif
789
790 } // namespace WebCore