[Win] Remove -DUCHAR_TYPE=wchar_t stopgap and learn to live with char16_t.
[WebKit-https.git] / Source / WebCore / rendering / RenderThemeWin.cpp
1 /*
2  * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2009 Kenneth Rohde Christiansen
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "RenderThemeWin.h"
24
25 #include "CSSValueKeywords.h"
26 #include "Element.h"
27 #include "FontMetrics.h"
28 #include "Frame.h"
29 #include "FrameSelection.h"
30 #include "GraphicsContext.h"
31 #include "HTMLMeterElement.h"
32 #include "LocalWindowsContext.h"
33 #include "PaintInfo.h"
34 #include "RenderMeter.h"
35 #include "RenderSlider.h"
36 #include "Settings.h"
37 #include "SystemInfo.h"
38 #include "UserAgentStyleSheets.h"
39 #include "WebCoreBundleWin.h"
40 #include <wtf/FileSystem.h>
41 #include <wtf/SoftLinking.h>
42 #include <wtf/text/StringBuilder.h>
43 #include <wtf/win/GDIObject.h>
44
45 #if ENABLE(VIDEO)
46 #include "RenderMediaControls.h"
47 #endif
48
49 #include <tchar.h>
50
51 /* 
52  * The following constants are used to determine how a widget is drawn using
53  * Windows' Theme API. For more information on theme parts and states see
54  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
55  */
56
57 // Generic state constants
58 #define TS_NORMAL    1
59 #define TS_HOVER     2
60 #define TS_ACTIVE    3
61 #define TS_DISABLED  4
62 #define TS_FOCUSED   5
63
64 // Button constants
65 #define BP_BUTTON    1
66 #define BP_RADIO     2
67 #define BP_CHECKBOX  3
68
69 // Textfield constants
70 #define TFP_TEXTFIELD 1
71 #define EP_EDITBORDER_NOSCROLL 6
72 #define TFS_READONLY  6
73
74 // ComboBox constants (from vsstyle.h)
75 #define CP_DROPDOWNBUTTON 1
76 #define CP_BORDER 4
77 #define CP_READONLY 5
78 #define CP_DROPDOWNBUTTONRIGHT 6
79
80 // TrackBar (slider) parts
81 #define TKP_TRACK       1
82 #define TKP_TRACKVERT   2
83
84 // TrackBar (slider) thumb parts
85 #define TKP_THUMBBOTTOM 4
86 #define TKP_THUMBTOP    5
87 #define TKP_THUMBLEFT   7
88 #define TKP_THUMBRIGHT  8
89
90 // Trackbar (slider) thumb states
91 #define TUS_NORMAL      1
92 #define TUS_HOT         2
93 #define TUS_PRESSED     3
94 #define TUS_FOCUSED     4
95 #define TUS_DISABLED    5
96
97 // button states
98 #define PBS_NORMAL      1
99 #define PBS_HOT         2
100 #define PBS_PRESSED     3
101 #define PBS_DISABLED    4
102 #define PBS_DEFAULTED   5
103
104 // Spin button parts
105 #define SPNP_UP         1
106 #define SPNP_DOWN       2
107
108 // Spin button states
109 #define DNS_NORMAL      1
110 #define DNS_HOT         2
111 #define DNS_PRESSED     3
112 #define DNS_DISABLED    4
113 #define UPS_NORMAL      1
114 #define UPS_HOT         2
115 #define UPS_PRESSED     3
116 #define UPS_DISABLED    4
117
118 // Progress bar parts
119 #define PP_BAR          1
120 #define PP_BARVERT      2
121 #define PP_CHUNK        3
122 #define PP_CHUNKVERT    4
123 #define PP_FILL         5
124 #define PP_FILLVERT     6
125 #define PP_PULSEOVERLAY 7
126 #define PP_MOVEOVERLAY  8
127 #define PP_PULSEOVERLAYVERT 9
128 #define PP_MOVEOVERLAYVERT  10
129 #define PP_TRANSPARENTBAR   11
130 #define PP_TRANSPARENTBARVERT 12
131
132 // Progress bar states
133 #define PBBS_NORMAL     1
134 #define PBBS_PARTIAL    2
135 #define PBBVS_NORMAL    1 // Vertical
136 #define PBBVS_PARTIAL   2
137
138 // Progress bar fill states
139 #define PBFS_NORMAL     1
140 #define PBFS_ERROR      2
141 #define PBFS_PAUSED     3
142 #define PBFS_PARTIAL    4
143 #define PBFVS_NORMAL    1 // Vertical
144 #define PBFVS_ERROR     2
145 #define PBFVS_PAUSED    3
146 #define PBFVS_PARTIAL   4
147
148
149 SOFT_LINK_LIBRARY(uxtheme)
150 SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
151 SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
152 SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
153 SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
154 SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
155
156 static bool haveTheme;
157
158 static const unsigned vistaMenuListButtonOutset = 1;
159
160
161 namespace WebCore {
162
163 // This is the fixed width IE and Firefox use for buttons on dropdown menus
164 static const int dropDownButtonWidth = 17;
165
166 static const int shell32MagnifierIconIndex = 22;
167
168 // Default font size to match Firefox.
169 static const float defaultControlFontPixelSize = 13;
170
171 static const float defaultCancelButtonSize = 9;
172 static const float minCancelButtonSize = 5;
173 static const float maxCancelButtonSize = 21;
174 static const float defaultSearchFieldResultsDecorationSize = 13;
175 static const float minSearchFieldResultsDecorationSize = 9;
176 static const float maxSearchFieldResultsDecorationSize = 30;
177 static const float defaultSearchFieldResultsButtonWidth = 18;
178
179 static bool gWebKitIsBeingUnloaded;
180
181 void RenderThemeWin::setWebKitIsBeingUnloaded()
182 {
183     gWebKitIsBeingUnloaded = true;
184 }
185
186 RenderTheme& RenderTheme::singleton()
187 {
188     static NeverDestroyed<RenderThemeWin> theme;
189     return theme;
190 }
191
192 RenderThemeWin::RenderThemeWin()
193     : m_buttonTheme(0)
194     , m_textFieldTheme(0)
195     , m_menuListTheme(0)
196     , m_sliderTheme(0)
197     , m_spinButtonTheme(0)
198     , m_progressBarTheme(0)
199 {
200     haveTheme = uxthemeLibrary() && IsThemeActive();
201 }
202
203 RenderThemeWin::~RenderThemeWin()
204 {
205     // If WebKit is being unloaded, then uxtheme.dll is no longer available.
206     if (gWebKitIsBeingUnloaded || !uxthemeLibrary())
207         return;
208     close();
209 }
210
211 HANDLE RenderThemeWin::buttonTheme() const
212 {
213     if (haveTheme && !m_buttonTheme)
214         m_buttonTheme = OpenThemeData(0, L"Button");
215     return m_buttonTheme;
216 }
217
218 HANDLE RenderThemeWin::textFieldTheme() const
219 {
220     if (haveTheme && !m_textFieldTheme)
221         m_textFieldTheme = OpenThemeData(0, L"Edit");
222     return m_textFieldTheme;
223 }
224
225 HANDLE RenderThemeWin::menuListTheme() const
226 {
227     if (haveTheme && !m_menuListTheme)
228         m_menuListTheme = OpenThemeData(0, L"ComboBox");
229     return m_menuListTheme;
230 }
231
232 HANDLE RenderThemeWin::sliderTheme() const
233 {
234     if (haveTheme && !m_sliderTheme)
235         m_sliderTheme = OpenThemeData(0, L"TrackBar");
236     return m_sliderTheme;
237 }
238
239 HANDLE RenderThemeWin::spinButtonTheme() const
240 {
241     if (haveTheme && !m_spinButtonTheme)
242         m_spinButtonTheme = OpenThemeData(0, L"Spin");
243     return m_spinButtonTheme;
244 }
245
246 HANDLE RenderThemeWin::progressBarTheme() const
247 {
248     if (haveTheme && !m_progressBarTheme)
249         m_progressBarTheme = OpenThemeData(0, L"Progress");
250     return m_progressBarTheme;
251 }
252
253 void RenderThemeWin::close()
254 {
255     // This method will need to be called when the OS theme changes to flush our cached themes.
256     if (m_buttonTheme)
257         CloseThemeData(m_buttonTheme);
258     if (m_textFieldTheme)
259         CloseThemeData(m_textFieldTheme);
260     if (m_menuListTheme)
261         CloseThemeData(m_menuListTheme);
262     if (m_sliderTheme)
263         CloseThemeData(m_sliderTheme);
264     if (m_spinButtonTheme)
265         CloseThemeData(m_spinButtonTheme);
266     if (m_progressBarTheme)
267         CloseThemeData(m_progressBarTheme);
268     m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = m_spinButtonTheme = m_progressBarTheme = 0;
269
270     haveTheme = uxthemeLibrary() && IsThemeActive();
271 }
272
273 void RenderThemeWin::themeChanged()
274 {
275     close();
276 }
277
278 String RenderThemeWin::extraDefaultStyleSheet()
279 {
280     return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
281 }
282
283 String RenderThemeWin::extraQuirksStyleSheet()
284 {
285     return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
286 }
287
288 bool RenderThemeWin::supportsHover(const RenderStyle&) const
289 {
290     // The Classic/2k look has no hover effects.
291     return haveTheme;
292 }
293
294 Color RenderThemeWin::platformActiveSelectionBackgroundColor(OptionSet<StyleColor::Options>) const
295 {
296     COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
297     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
298 }
299
300 Color RenderThemeWin::platformInactiveSelectionBackgroundColor(OptionSet<StyleColor::Options>) const
301 {
302     // This color matches Firefox.
303     return Color(176, 176, 176);
304 }
305
306 Color RenderThemeWin::platformActiveSelectionForegroundColor(OptionSet<StyleColor::Options>) const
307 {
308     COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
309     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
310 }
311
312 Color RenderThemeWin::platformInactiveSelectionForegroundColor(OptionSet<StyleColor::Options> options) const
313 {
314     return platformActiveSelectionForegroundColor(options);
315 }
316
317 static void fillFontDescription(FontCascadeDescription& fontDescription, LOGFONT& logFont, float fontSize)
318 {    
319     fontDescription.setIsAbsoluteSize(true);
320     fontDescription.setOneFamily(logFont.lfFaceName);
321     fontDescription.setSpecifiedSize(fontSize);
322     fontDescription.setWeight(logFont.lfWeight >= 700 ? boldWeightValue() : normalWeightValue()); // FIXME: Use real weight.
323     fontDescription.setIsItalic(logFont.lfItalic);
324 }
325
326 void RenderThemeWin::updateCachedSystemFontDescription(CSSValueID valueID, FontCascadeDescription& fontDescription) const
327 {
328     static bool initialized;
329     static NONCLIENTMETRICS ncm;
330
331     if (!initialized) {
332         initialized = true;
333         ncm.cbSize = sizeof(NONCLIENTMETRICS);
334         ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
335     }
336  
337     LOGFONT logFont;
338     bool shouldUseDefaultControlFontPixelSize = false;
339     switch (valueID) {
340     case CSSValueIcon:
341         ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
342         break;
343     case CSSValueMenu:
344         logFont = ncm.lfMenuFont;
345         break;
346     case CSSValueMessageBox:
347         logFont = ncm.lfMessageFont;
348         break;
349     case CSSValueStatusBar:
350         logFont = ncm.lfStatusFont;
351         break;
352     case CSSValueCaption:
353         logFont = ncm.lfCaptionFont;
354         break;
355     case CSSValueSmallCaption:
356         logFont = ncm.lfSmCaptionFont;
357         break;
358     case CSSValueWebkitSmallControl:
359     case CSSValueWebkitMiniControl: // Just map to small.
360     case CSSValueWebkitControl: // Just map to small.
361         shouldUseDefaultControlFontPixelSize = true;
362         FALLTHROUGH;
363     default: { // Everything else uses the stock GUI font.
364         HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
365         if (!hGDI)
366             return;
367         if (::GetObject(hGDI, sizeof(logFont), &logFont) <= 0)
368             return;
369     }
370     }
371     fillFontDescription(fontDescription, logFont, shouldUseDefaultControlFontPixelSize ? defaultControlFontPixelSize : abs(logFont.lfHeight));
372 }
373
374 bool RenderThemeWin::supportsFocus(ControlPart appearance) const
375 {
376     switch (appearance) {
377         case PushButtonPart:
378         case ButtonPart:
379         case DefaultButtonPart:
380             return true;
381         default:
382             return false;
383     }
384 }
385
386 bool RenderThemeWin::supportsFocusRing(const RenderStyle& style) const
387 {
388     return supportsFocus(style.appearance());
389 }
390
391 unsigned RenderThemeWin::determineClassicState(const RenderObject& o, ControlSubPart subPart)
392 {
393     unsigned state = 0;
394     switch (o.style().appearance()) {
395         case PushButtonPart:
396         case ButtonPart:
397         case DefaultButtonPart:
398             state = DFCS_BUTTONPUSH;
399             if (!isEnabled(o))
400                 state |= DFCS_INACTIVE;
401             else if (isPressed(o))
402                 state |= DFCS_PUSHED;
403             break;
404         case RadioPart:
405         case CheckboxPart:
406             state = (o.style().appearance() == RadioPart) ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
407             if (isChecked(o))
408                 state |= DFCS_CHECKED;
409             if (!isEnabled(o))
410                 state |= DFCS_INACTIVE;
411             else if (isPressed(o))
412                 state |= DFCS_PUSHED;
413             break;
414         case MenulistPart:
415             state = DFCS_SCROLLCOMBOBOX;
416             if (!isEnabled(o))
417                 state |= DFCS_INACTIVE;
418             else if (isPressed(o))
419                 state |= DFCS_PUSHED;
420             break;
421         case InnerSpinButtonPart: {
422             bool isUpButton = subPart == SpinButtonUp;
423             state = isUpButton ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
424             if (!isEnabled(o) || isReadOnlyControl(o))
425                 state |= DFCS_INACTIVE;
426             else if (isPressed(o) && isUpButton == isSpinUpButtonPartPressed(o))
427                 state |= DFCS_PUSHED;
428             else if (isHovered(o) && isUpButton == isSpinUpButtonPartHovered(o))
429                 state |= DFCS_HOT;
430             break;
431         }
432         default:
433             break;
434     }
435     return state;
436 }
437
438 unsigned RenderThemeWin::determineState(const RenderObject& o)
439 {
440     unsigned result = TS_NORMAL;
441     ControlPart appearance = o.style().appearance();
442     if (!isEnabled(o))
443         result = TS_DISABLED;
444     else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance))
445         result = TFS_READONLY; // Readonly is supported on textfields.
446     else if (isPressed(o)) // Active overrides hover and focused.
447         result = TS_ACTIVE;
448     else if (supportsFocus(appearance) && isFocused(o))
449         result = TS_FOCUSED;
450     else if (isHovered(o))
451         result = TS_HOVER;
452     if (isChecked(o))
453         result += 4; // 4 unchecked states, 4 checked states.
454     else if (isIndeterminate(o) && appearance == CheckboxPart)
455         result += 8;
456     return result;
457 }
458
459 unsigned RenderThemeWin::determineSliderThumbState(const RenderObject& o)
460 {
461     unsigned result = TUS_NORMAL;
462     if (!isEnabled(o))
463         result = TUS_DISABLED;
464     else if (supportsFocus(o.style().appearance()) && isFocused(o))
465         result = TUS_FOCUSED;
466     else if (isPressed(o))
467         result = TUS_PRESSED;
468     else if (isHovered(o))
469         result = TUS_HOT;
470     return result;
471 }
472
473 unsigned RenderThemeWin::determineButtonState(const RenderObject& o)
474 {
475     unsigned result = PBS_NORMAL;
476     if (!isEnabled(o))
477         result = PBS_DISABLED;
478     else if (isPressed(o))
479         result = PBS_PRESSED;
480     else if (supportsFocus(o.style().appearance()) && isFocused(o))
481         result = PBS_DEFAULTED;
482     else if (isHovered(o))
483         result = PBS_HOT;
484     else if (isDefault(o))
485         result = PBS_DEFAULTED;
486     return result;
487 }
488
489 unsigned RenderThemeWin::determineSpinButtonState(const RenderObject& o, ControlSubPart subPart)
490 {
491     bool isUpButton = subPart == SpinButtonUp;
492     unsigned result = isUpButton ? UPS_NORMAL : DNS_NORMAL;
493     if (!isEnabled(o) || isReadOnlyControl(o))
494         result = isUpButton ? UPS_DISABLED : DNS_DISABLED;
495     else if (isPressed(o) && isUpButton == isSpinUpButtonPartPressed(o))
496         result = isUpButton ? UPS_PRESSED : DNS_PRESSED;
497     else if (isHovered(o) && isUpButton == isSpinUpButtonPartHovered(o))
498         result = isUpButton ? UPS_HOT : DNS_HOT;
499     return result;
500 }
501
502 ThemeData RenderThemeWin::getClassicThemeData(const RenderObject& o, ControlSubPart subPart)
503 {
504     ThemeData result;
505     switch (o.style().appearance()) {
506         case PushButtonPart:
507         case ButtonPart:
508         case DefaultButtonPart:
509         case CheckboxPart:
510         case RadioPart:
511             result.m_part = DFC_BUTTON;
512             result.m_state = determineClassicState(o);
513             break;
514         case MenulistPart:
515             result.m_part = DFC_SCROLL;
516             result.m_state = determineClassicState(o);
517             break;
518         case MeterPart:
519             result.m_part = PP_BAR;
520             result.m_state = determineState(o);
521             break;
522         case SearchFieldPart:
523         case TextFieldPart:
524         case TextAreaPart:
525             result.m_part = TFP_TEXTFIELD;
526             result.m_state = determineState(o);
527             break;
528         case SliderHorizontalPart:
529             result.m_part = TKP_TRACK;
530             result.m_state = TS_NORMAL;
531             break;
532         case SliderVerticalPart:
533             result.m_part = TKP_TRACKVERT;
534             result.m_state = TS_NORMAL;
535             break;
536         case SliderThumbHorizontalPart:
537             result.m_part = TKP_THUMBBOTTOM;
538             result.m_state = determineSliderThumbState(o);
539             break;
540         case SliderThumbVerticalPart:
541             result.m_part = TKP_THUMBRIGHT;
542             result.m_state = determineSliderThumbState(o);
543             break;
544         case InnerSpinButtonPart:
545             result.m_part = DFC_SCROLL;
546             result.m_state = determineClassicState(o, subPart);
547             break;
548         default:
549             break;
550     }
551     return result;
552 }
553
554 ThemeData RenderThemeWin::getThemeData(const RenderObject& o, ControlSubPart subPart)
555 {
556     if (!haveTheme)
557         return getClassicThemeData(o, subPart);
558
559     ThemeData result;
560     switch (o.style().appearance()) {
561         case PushButtonPart:
562         case ButtonPart:
563         case DefaultButtonPart:
564             result.m_part = BP_BUTTON;
565             result.m_state = determineButtonState(o);
566             break;
567         case CheckboxPart:
568             result.m_part = BP_CHECKBOX;
569             result.m_state = determineState(o);
570             break;
571         case MenulistPart:
572         case MenulistButtonPart: {
573             const bool isVistaOrLater = (windowsVersion() >= WindowsVista);
574             result.m_part = isVistaOrLater ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON;
575             if (isVistaOrLater) {
576                 result.m_state = TS_NORMAL;
577             } else
578                 result.m_state = determineState(o);
579             break;
580         }
581         case MeterPart:
582             result.m_part = PP_BAR;
583             result.m_state = determineState(o);
584             break;
585         case RadioPart:
586             result.m_part = BP_RADIO;
587             result.m_state = determineState(o);
588             break;
589         case SearchFieldPart:
590         case TextFieldPart:
591         case TextAreaPart:
592             result.m_part = (windowsVersion() >= WindowsVista) ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD;
593             result.m_state = determineState(o);
594             break;
595         case SliderHorizontalPart:
596             result.m_part = TKP_TRACK;
597             result.m_state = TS_NORMAL;
598             break;
599         case SliderVerticalPart:
600             result.m_part = TKP_TRACKVERT;
601             result.m_state = TS_NORMAL;
602             break;
603         case SliderThumbHorizontalPart:
604             result.m_part = TKP_THUMBBOTTOM;
605             result.m_state = determineSliderThumbState(o);
606             break;
607         case SliderThumbVerticalPart:
608             result.m_part = TKP_THUMBRIGHT;
609             result.m_state = determineSliderThumbState(o);
610             break;
611         case InnerSpinButtonPart:
612             result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
613             result.m_state = determineSpinButtonState(o, subPart);
614             break;
615     }
616
617     return result;
618 }
619
620 static void drawControl(GraphicsContext& context, const RenderObject& o, HANDLE theme, const ThemeData& themeData, const IntRect& r)
621 {
622     bool alphaBlend = false;
623     if (theme)
624         alphaBlend = IsThemeBackgroundPartiallyTransparent(theme, themeData.m_part, themeData.m_state);
625     LocalWindowsContext windowsContext(context, r, alphaBlend);
626     RECT widgetRect = r;
627     if (theme)
628         DrawThemeBackground(theme, windowsContext.hdc(), themeData.m_part, themeData.m_state, &widgetRect, 0);
629     else {
630         HDC hdc = windowsContext.hdc();
631         if (themeData.m_part == TFP_TEXTFIELD) {
632             ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
633             if (themeData.m_state == TS_DISABLED || themeData.m_state ==  TFS_READONLY)
634                 ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_BTNFACE+1));
635             else
636                 ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_WINDOW+1));
637         } else if (themeData.m_part == TKP_TRACK || themeData.m_part == TKP_TRACKVERT) {
638             ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
639             ::FillRect(hdc, &widgetRect, (HBRUSH)GetStockObject(GRAY_BRUSH));
640         } else if ((o.style().appearance() == SliderThumbHorizontalPart
641         || o.style().appearance() == SliderThumbVerticalPart)
642         && (themeData.m_part == TKP_THUMBBOTTOM || themeData.m_part == TKP_THUMBTOP
643         || themeData.m_part == TKP_THUMBLEFT || themeData.m_part == TKP_THUMBRIGHT)) {
644             ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
645             if (themeData.m_state == TUS_DISABLED) {
646                 static WORD patternBits[8] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
647                 auto patternBmp = adoptGDIObject(::CreateBitmap(8, 8, 1, 1, patternBits));
648                 if (patternBmp) {
649                     auto brush = adoptGDIObject(::CreatePatternBrush(patternBmp.get()));
650                     COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(COLOR_3DFACE));
651                     COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
652                     POINT p;
653                     ::GetViewportOrgEx(hdc, &p);
654                     ::SetBrushOrgEx(hdc, p.x + widgetRect.left, p.y + widgetRect.top, NULL);
655                     HGDIOBJ oldBrush = ::SelectObject(hdc, brush.get());
656                     ::FillRect(hdc, &widgetRect, brush.get());
657                     ::SetTextColor(hdc, oldForeColor);
658                     ::SetBkColor(hdc, oldBackColor);
659                     ::SelectObject(hdc, oldBrush);
660                 } else
661                     ::FillRect(hdc, &widgetRect, (HBRUSH)COLOR_3DHILIGHT);
662             }
663         } else {
664             // Push buttons, buttons, checkboxes and radios, and the dropdown arrow in menulists.
665             if (o.style().appearance() == DefaultButtonPart) {
666                 HBRUSH brush = ::GetSysColorBrush(COLOR_3DDKSHADOW);
667                 ::FrameRect(hdc, &widgetRect, brush);
668                 ::InflateRect(&widgetRect, -1, -1);
669                 ::DrawEdge(hdc, &widgetRect, BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE);
670             }
671             ::DrawFrameControl(hdc, &widgetRect, themeData.m_part, themeData.m_state);
672         }
673     }
674
675     if (!alphaBlend && !context.isInTransparencyLayer())
676         DIBPixelData::setRGBABitmapAlpha(windowsContext.hdc(), r, 255);
677 }
678
679 bool RenderThemeWin::paintButton(const RenderObject& o, const PaintInfo& i, const IntRect& r)
680 {  
681     drawControl(i.context(),  o, buttonTheme(), getThemeData(o), r);
682     return false;
683 }
684
685 void RenderThemeWin::adjustInnerSpinButtonStyle(StyleResolver& styleResolver, RenderStyle& style, const Element*) const
686 {
687     int width = ::GetSystemMetrics(SM_CXVSCROLL);
688     if (width <= 0)
689         width = 17; // Vista's default.
690     style.setWidth(Length(width, Fixed));
691     style.setMinWidth(Length(width, Fixed));
692 }
693
694 bool RenderThemeWin::paintInnerSpinButton(const RenderObject& o, const PaintInfo& i, const IntRect& r)
695 {
696     // We split the specified rectangle into two vertically. We can't draw a
697     // spin button of which height is less than 2px.
698     if (r.height() < 2)
699         return false;
700     IntRect upRect(r);
701     upRect.setHeight(r.height() / 2);
702     IntRect downRect(r);
703     downRect.setY(upRect.maxY());
704     downRect.setHeight(r.height() - upRect.height());
705     drawControl(i.context(), o, spinButtonTheme(), getThemeData(o, SpinButtonUp), upRect);
706     drawControl(i.context(), o, spinButtonTheme(), getThemeData(o, SpinButtonDown), downRect);
707     return false;
708 }
709
710 void RenderThemeWin::setCheckboxSize(RenderStyle& style) const
711 {
712     // If the width and height are both specified, then we have nothing to do.
713     if (!style.width().isIntrinsicOrAuto() && !style.height().isAuto())
714         return;
715
716     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
717     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
718     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
719     // metrics.
720     if (style.width().isIntrinsicOrAuto())
721         style.setWidth(Length(13, Fixed));
722     if (style.height().isAuto())
723         style.setHeight(Length(13, Fixed));
724 }
725
726 bool RenderThemeWin::paintTextField(const RenderObject& o, const PaintInfo& i, const FloatRect& r)
727 {
728     drawControl(i.context(),  o, textFieldTheme(), getThemeData(o), IntRect(r));
729     return false;
730 }
731
732 bool RenderThemeWin::paintMenuList(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
733 {
734     HANDLE theme;
735     int part;
736     if (haveTheme && (windowsVersion() >= WindowsVista)) {
737         theme = menuListTheme();
738         part = CP_READONLY;
739     } else {
740         theme = textFieldTheme();
741         part = TFP_TEXTFIELD;
742     }
743
744     drawControl(paintInfo.context(), renderer, theme, ThemeData(part, determineState(renderer)), IntRect(rect));
745     
746     return paintMenuListButtonDecorations(downcast<RenderBox>(renderer), paintInfo, FloatRect(rect));
747 }
748
749 void RenderThemeWin::adjustMenuListStyle(StyleResolver& styleResolver, RenderStyle& style, const Element* e) const
750 {
751     style.resetBorder();
752     adjustMenuListButtonStyle(styleResolver, style, e);
753 }
754
755 void RenderThemeWin::adjustMenuListButtonStyle(StyleResolver& styleResolver, RenderStyle& style, const Element*) const
756 {
757     // These are the paddings needed to place the text correctly in the <select> box
758     const int dropDownBoxPaddingTop    = 2;
759     const int dropDownBoxPaddingRight  = style.direction() == TextDirection::LTR ? 4 + dropDownButtonWidth : 4;
760     const int dropDownBoxPaddingBottom = 2;
761     const int dropDownBoxPaddingLeft   = style.direction() == TextDirection::LTR ? 4 : 4 + dropDownButtonWidth;
762     // The <select> box must be at least 12px high for the button to render nicely on Windows
763     const int dropDownBoxMinHeight = 12;
764     
765     // Position the text correctly within the select box and make the box wide enough to fit the dropdown button
766     style.setPaddingTop(Length(dropDownBoxPaddingTop, Fixed));
767     style.setPaddingRight(Length(dropDownBoxPaddingRight, Fixed));
768     style.setPaddingBottom(Length(dropDownBoxPaddingBottom, Fixed));
769     style.setPaddingLeft(Length(dropDownBoxPaddingLeft, Fixed));
770
771     // Height is locked to auto
772     style.setHeight(Length(Auto));
773
774     // Calculate our min-height
775     int minHeight = style.fontMetrics().height();
776     minHeight = std::max(minHeight, dropDownBoxMinHeight);
777
778     style.setMinHeight(Length(minHeight, Fixed));
779
780     style.setLineHeight(RenderStyle::initialLineHeight());
781     
782     // White-space is locked to pre
783     style.setWhiteSpace(WhiteSpace::Pre);
784 }
785
786 bool RenderThemeWin::paintMenuListButtonDecorations(const RenderBox& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
787 {
788     // FIXME: Don't make hardcoded assumptions about the thickness of the textfield border.
789     int borderThickness = haveTheme ? 1 : 2;
790
791     // Paint the dropdown button on the inner edge of the text field,
792     // leaving space for the text field's 1px border
793     IntRect buttonRect(rect);
794     buttonRect.inflate(-borderThickness);
795     if (renderer.style().direction() == TextDirection::LTR)
796         buttonRect.setX(buttonRect.maxX() - dropDownButtonWidth);
797     buttonRect.setWidth(dropDownButtonWidth);
798
799     if ((windowsVersion() >= WindowsVista)) {
800         // Outset the top, right, and bottom borders of the button so that they coincide with the <select>'s border.
801         buttonRect.setY(buttonRect.y() - vistaMenuListButtonOutset);
802         buttonRect.setHeight(buttonRect.height() + 2 * vistaMenuListButtonOutset);
803         buttonRect.setWidth(buttonRect.width() + vistaMenuListButtonOutset);
804     }
805
806     drawControl(paintInfo.context(), renderer, menuListTheme(), getThemeData(renderer), buttonRect);
807
808     return false;
809 }
810
811 const int trackWidth = 4;
812
813 bool RenderThemeWin::paintSliderTrack(const RenderObject& o, const PaintInfo& i, const IntRect& r)
814 {
815     IntRect bounds = r;
816     
817     if (o.style().appearance() ==  SliderHorizontalPart) {
818         bounds.setHeight(trackWidth);
819         bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
820     } else if (o.style().appearance() == SliderVerticalPart) {
821         bounds.setWidth(trackWidth);
822         bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
823     }
824     
825     drawControl(i.context(),  o, sliderTheme(), getThemeData(o), bounds);
826     return false;
827 }
828
829 bool RenderThemeWin::paintSliderThumb(const RenderObject& o, const PaintInfo& i, const IntRect& r)
830 {   
831     drawControl(i.context(),  o, sliderTheme(), getThemeData(o), r);
832     return false;
833 }
834
835 const int sliderThumbWidth = 7;
836 const int sliderThumbHeight = 15;
837
838 void RenderThemeWin::adjustSliderThumbSize(RenderStyle& style, const Element*) const
839 {
840     ControlPart part = style.appearance();
841     if (part == SliderThumbVerticalPart) {
842         style.setWidth(Length(sliderThumbHeight, Fixed));
843         style.setHeight(Length(sliderThumbWidth, Fixed));
844     } else if (part == SliderThumbHorizontalPart) {
845         style.setWidth(Length(sliderThumbWidth, Fixed));
846         style.setHeight(Length(sliderThumbHeight, Fixed));
847     }
848 #if ENABLE(VIDEO) && USE(CG)
849     else if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart) 
850         RenderMediaControls::adjustMediaSliderThumbSize(style);
851 #endif
852 }
853
854 bool RenderThemeWin::paintSearchField(const RenderObject& o, const PaintInfo& i, const IntRect& r)
855 {
856     return paintTextField(o, i, r);
857 }
858
859 void RenderThemeWin::adjustSearchFieldStyle(StyleResolver& styleResolver, RenderStyle& style, const Element* e) const
860 {
861     // Override paddingSize to match AppKit text positioning.
862     const int padding = 1;
863     style.setPaddingLeft(Length(padding, Fixed));
864     style.setPaddingRight(Length(padding, Fixed));
865     style.setPaddingTop(Length(padding, Fixed));
866     style.setPaddingBottom(Length(padding, Fixed));
867     if (e && e->focused() && e->document().frame()->selection().isFocusedAndActive())
868         style.setOutlineOffset(-2);
869 }
870
871 bool RenderThemeWin::paintSearchFieldCancelButton(const RenderBox& o, const PaintInfo& paintInfo, const IntRect& r)
872 {
873     IntRect bounds = r;
874     ASSERT(o.parent());
875     if (!is<RenderBox>(o.parent()))
876         return false;
877
878     IntRect parentBox = downcast<RenderBox>(*o.parent()).absoluteContentBox();
879     
880     // Make sure the scaled button stays square and will fit in its parent's box
881     bounds.setHeight(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height())));
882     bounds.setWidth(bounds.height());
883
884     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
885     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
886     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
887
888     static Image& cancelImage = Image::loadPlatformResource("searchCancel").leakRef();
889     static Image& cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").leakRef();
890     paintInfo.context().drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds);
891     return false;
892 }
893
894 void RenderThemeWin::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
895 {
896     // Scale the button size based on the font size
897     float fontScale = style.computedFontPixelSize() / defaultControlFontPixelSize;
898     int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
899     style.setWidth(Length(cancelButtonSize, Fixed));
900     style.setHeight(Length(cancelButtonSize, Fixed));
901 }
902
903 void RenderThemeWin::adjustSearchFieldDecorationPartStyle(StyleResolver&, RenderStyle& style, const Element*) const
904 {
905     IntSize emptySize(1, 11);
906     style.setWidth(Length(emptySize.width(), Fixed));
907     style.setHeight(Length(emptySize.height(), Fixed));
908 }
909
910 void RenderThemeWin::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle& style, const Element*) const
911 {
912     // Scale the decoration size based on the font size
913     float fontScale = style.computedFontPixelSize() / defaultControlFontPixelSize;
914     int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), 
915                                      maxSearchFieldResultsDecorationSize));
916     style.setWidth(Length(magnifierSize, Fixed));
917     style.setHeight(Length(magnifierSize, Fixed));
918 }
919
920 bool RenderThemeWin::paintSearchFieldResultsDecorationPart(const RenderBox& o, const PaintInfo& paintInfo, const IntRect& r)
921 {
922     IntRect bounds = r;
923     ASSERT(o.parent());
924     if (!is<RenderBox>(o.parent()))
925         return false;
926     
927     IntRect parentBox = downcast<RenderBox>(*o.parent()).absoluteContentBox();
928     
929     // Make sure the scaled decoration stays square and will fit in its parent's box
930     bounds.setHeight(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height())));
931     bounds.setWidth(bounds.height());
932
933     // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
934     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
935     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
936     
937     static Image& magnifierImage = Image::loadPlatformResource("searchMagnifier").leakRef();
938     paintInfo.context().drawImage(magnifierImage, bounds);
939     return false;
940 }
941
942 void RenderThemeWin::adjustSearchFieldResultsButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
943 {
944     // Scale the button size based on the font size
945     float fontScale = style.computedFontPixelSize() / defaultControlFontPixelSize;
946     int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), 
947                                    maxSearchFieldResultsDecorationSize));
948     int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
949     style.setWidth(Length(magnifierWidth, Fixed));
950     style.setHeight(Length(magnifierHeight, Fixed));
951 }
952
953 bool RenderThemeWin::paintSearchFieldResultsButton(const RenderBox& o, const PaintInfo& paintInfo, const IntRect& r)
954 {
955     IntRect bounds = r;
956     ASSERT(o.parent());
957     if (!o.parent())
958         return false;
959     if (!is<RenderBox>(o.parent()))
960         return false;
961     
962     IntRect parentBox = downcast<RenderBox>(*o.parent()).absoluteContentBox();
963     
964     // Make sure the scaled decoration will fit in its parent's box
965     bounds.setHeight(std::min(parentBox.height(), bounds.height()));
966     bounds.setWidth(std::min<int>(parentBox.width(), bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize));
967
968     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
969     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
970     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
971
972     static Image& magnifierImage = Image::loadPlatformResource("searchMagnifierResults").leakRef();
973     paintInfo.context().drawImage(magnifierImage, bounds);
974     return false;
975 }
976
977 // Map a CSSValue* system color to an index understood by GetSysColor
978 static int cssValueIdToSysColorIndex(CSSValueID cssValueId)
979 {
980     switch (cssValueId) {
981     case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
982     case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
983     case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
984     case CSSValueBackground: return COLOR_BACKGROUND;
985     case CSSValueButtonface: return COLOR_BTNFACE;
986     case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
987     case CSSValueButtonshadow: return COLOR_BTNSHADOW;
988     case CSSValueButtontext: return COLOR_BTNTEXT;
989     case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
990     case CSSValueGraytext: return COLOR_GRAYTEXT;
991     case CSSValueHighlight: return COLOR_HIGHLIGHT;
992     case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
993     case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
994     case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
995     case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
996     case CSSValueInfobackground: return COLOR_INFOBK;
997     case CSSValueInfotext: return COLOR_INFOTEXT;
998     case CSSValueMenu: return COLOR_MENU;
999     case CSSValueMenutext: return COLOR_MENUTEXT;
1000     case CSSValueScrollbar: return COLOR_SCROLLBAR;
1001     case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
1002     case CSSValueThreedface: return COLOR_3DFACE;
1003     case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
1004     case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
1005     case CSSValueThreedshadow: return COLOR_3DSHADOW;
1006     case CSSValueWindow: return COLOR_WINDOW;
1007     case CSSValueWindowframe: return COLOR_WINDOWFRAME;
1008     case CSSValueWindowtext: return COLOR_WINDOWTEXT;
1009     default: return -1; // Unsupported CSSValue
1010     }
1011 }
1012
1013 Color RenderThemeWin::systemColor(CSSValueID cssValueId, OptionSet<StyleColor::Options> options) const
1014 {
1015     int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
1016     if (sysColorIndex == -1)
1017         return RenderTheme::systemColor(cssValueId, options);
1018
1019     COLORREF color = GetSysColor(sysColorIndex);
1020     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
1021 }
1022
1023 #if ENABLE(VIDEO)
1024 static const size_t maximumReasonableBufferSize = 32768;
1025
1026 static void fillBufferWithContentsOfFile(FileSystem::PlatformFileHandle file, long long filesize, Vector<char>& buffer)
1027 {
1028     // Load the file content into buffer
1029     buffer.resize(filesize + 1);
1030
1031     int bufferPosition = 0;
1032     int bufferReadSize = 4096;
1033     int bytesRead = 0;
1034     while (filesize > bufferPosition) {
1035         if (filesize - bufferPosition < bufferReadSize)
1036             bufferReadSize = filesize - bufferPosition;
1037
1038         bytesRead = FileSystem::readFromFile(file, buffer.data() + bufferPosition, bufferReadSize);
1039         if (bytesRead != bufferReadSize) {
1040             buffer.clear();
1041             return;
1042         }
1043
1044         bufferPosition += bufferReadSize;
1045     }
1046
1047     buffer[filesize] = 0;
1048 }
1049
1050 String RenderThemeWin::stringWithContentsOfFile(const String& name, const String& type)
1051 {
1052 #if USE(CF)
1053     RetainPtr<CFURLRef> requestedURLRef = adoptCF(CFBundleCopyResourceURL(webKitBundle(), name.createCFString().get(), type.createCFString().get(), 0));
1054     if (!requestedURLRef)
1055         return String();
1056
1057     UInt8 requestedFilePath[MAX_PATH];
1058     if (!CFURLGetFileSystemRepresentation(requestedURLRef.get(), false, requestedFilePath, MAX_PATH))
1059         return String();
1060
1061     FileSystem::PlatformFileHandle requestedFileHandle = FileSystem::openFile(requestedFilePath, FileSystem::FileOpenMode::Read);
1062     if (!FileSystem::isHandleValid(requestedFileHandle))
1063         return String();
1064
1065     long long filesize = -1;
1066     if (!FileSystem::getFileSize(requestedFileHandle, filesize)) {
1067         FileSystem::closeFile(requestedFileHandle);
1068         return String();
1069     }
1070
1071     Vector<char> fileContents;
1072     fillBufferWithContentsOfFile(requestedFileHandle, filesize, fileContents);
1073     FileSystem::closeFile(requestedFileHandle);
1074
1075     return String(fileContents.data(), static_cast<size_t>(filesize));
1076 #else
1077     return emptyString();
1078 #endif
1079 }
1080
1081 String RenderThemeWin::mediaControlsStyleSheet()
1082 {
1083 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1084     if (m_mediaControlsStyleSheet.isEmpty())
1085         m_mediaControlsStyleSheet = stringWithContentsOfFile("mediaControlsApple"_s, "css"_s);
1086     return m_mediaControlsStyleSheet;
1087 #else
1088     return emptyString();
1089 #endif
1090 }
1091
1092 String RenderThemeWin::mediaControlsScript()
1093 {
1094 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1095     if (m_mediaControlsScript.isEmpty()) {
1096         StringBuilder scriptBuilder;
1097         scriptBuilder.append(stringWithContentsOfFile("mediaControlsLocalizedStrings"_s, "js"_s));
1098         scriptBuilder.append(stringWithContentsOfFile("mediaControlsApple"_s, "js"_s));
1099         m_mediaControlsScript = scriptBuilder.toString();
1100     }
1101     return m_mediaControlsScript;
1102 #else
1103     return emptyString();
1104 #endif
1105 }
1106 #endif
1107
1108 #if ENABLE(METER_ELEMENT)
1109 void RenderThemeWin::adjustMeterStyle(StyleResolver&, RenderStyle& style, const Element*) const
1110 {
1111     style.setBoxShadow(nullptr);
1112 }
1113
1114 bool RenderThemeWin::supportsMeter(ControlPart part) const
1115 {
1116     switch (part) {
1117     case MeterPart:
1118         return true;
1119     default:
1120         return false;
1121     }
1122 }
1123
1124 IntSize RenderThemeWin::meterSizeForBounds(const RenderMeter&, const IntRect& bounds) const
1125 {
1126     return bounds.size();
1127 }
1128
1129 bool RenderThemeWin::paintMeter(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1130 {
1131     if (!is<RenderMeter>(renderObject))
1132         return true;
1133
1134     HTMLMeterElement* element = downcast<RenderMeter>(renderObject).meterElement();
1135
1136     ThemeData theme = getThemeData(renderObject);
1137
1138     int remaining = static_cast<int>((1.0 - element->valueRatio()) * static_cast<double>(rect.size().width()));
1139
1140     // Draw the background
1141     drawControl(paintInfo.context(), renderObject, progressBarTheme(), theme, rect);
1142
1143     // Draw the progress portion
1144     IntRect completedRect(rect);
1145     completedRect.contract(remaining, 0);
1146
1147     theme.m_part = PP_FILL;
1148     drawControl(paintInfo.context(), renderObject, progressBarTheme(), theme, completedRect);
1149
1150     return true;
1151 }
1152
1153 #endif
1154
1155
1156 }