• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.
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 "Frame.h"
28 #include "GraphicsContext.h"
29 #include "RenderSlider.h"
30 #include "Settings.h"
31 #include "SoftLinking.h"
32 #include "SystemInfo.h"
33 #include "UserAgentStyleSheets.h"
34 
35 #if ENABLE(VIDEO)
36 #include "RenderMediaControls.h"
37 #endif
38 
39 #include <tchar.h>
40 
41 /*
42  * The following constants are used to determine how a widget is drawn using
43  * Windows' Theme API. For more information on theme parts and states see
44  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
45  */
46 
47 // Generic state constants
48 #define TS_NORMAL    1
49 #define TS_HOVER     2
50 #define TS_ACTIVE    3
51 #define TS_DISABLED  4
52 #define TS_FOCUSED   5
53 
54 // Button constants
55 #define BP_BUTTON    1
56 #define BP_RADIO     2
57 #define BP_CHECKBOX  3
58 
59 // Textfield constants
60 #define TFP_TEXTFIELD 1
61 #define EP_EDITBORDER_NOSCROLL 6
62 #define TFS_READONLY  6
63 
64 // ComboBox constants (from vsstyle.h)
65 #define CP_DROPDOWNBUTTON 1
66 #define CP_BORDER 4
67 #define CP_READONLY 5
68 #define CP_DROPDOWNBUTTONRIGHT 6
69 
70 // TrackBar (slider) parts
71 #define TKP_TRACK       1
72 #define TKP_TRACKVERT   2
73 
74 // TrackBar (slider) thumb parts
75 #define TKP_THUMBBOTTOM 4
76 #define TKP_THUMBTOP    5
77 #define TKP_THUMBLEFT   7
78 #define TKP_THUMBRIGHT  8
79 
80 // Trackbar (slider) thumb states
81 #define TUS_NORMAL      1
82 #define TUS_HOT         2
83 #define TUS_PRESSED     3
84 #define TUS_FOCUSED     4
85 #define TUS_DISABLED    5
86 
87 // button states
88 #define PBS_NORMAL      1
89 #define PBS_HOT         2
90 #define PBS_PRESSED     3
91 #define PBS_DISABLED    4
92 #define PBS_DEFAULTED   5
93 
94 SOFT_LINK_LIBRARY(uxtheme)
95 SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
96 SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
97 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))
98 SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
99 SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
100 
101 static bool haveTheme;
102 
103 static const unsigned vistaMenuListButtonOutset = 1;
104 
105 using namespace std;
106 
107 namespace WebCore {
108 
109 // This is the fixed width IE and Firefox use for buttons on dropdown menus
110 static const int dropDownButtonWidth = 17;
111 
112 static const int shell32MagnifierIconIndex = 22;
113 
114 // Default font size to match Firefox.
115 static const float defaultControlFontPixelSize = 13;
116 
117 static const float defaultCancelButtonSize = 9;
118 static const float minCancelButtonSize = 5;
119 static const float maxCancelButtonSize = 21;
120 static const float defaultSearchFieldResultsDecorationSize = 13;
121 static const float minSearchFieldResultsDecorationSize = 9;
122 static const float maxSearchFieldResultsDecorationSize = 30;
123 static const float defaultSearchFieldResultsButtonWidth = 18;
124 
125 static bool gWebKitIsBeingUnloaded;
126 
documentIsInApplicationChromeMode(const Document * document)127 static bool documentIsInApplicationChromeMode(const Document* document)
128 {
129     Settings* settings = document->settings();
130     return settings && settings->inApplicationChromeMode();
131 }
132 
setWebKitIsBeingUnloaded()133 void RenderThemeWin::setWebKitIsBeingUnloaded()
134 {
135     gWebKitIsBeingUnloaded = true;
136 }
137 
create()138 PassRefPtr<RenderTheme> RenderThemeWin::create()
139 {
140     return adoptRef(new RenderThemeWin);
141 }
142 
143 #if !USE(SAFARI_THEME)
themeForPage(Page * page)144 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
145 {
146     static RenderTheme* winTheme = RenderThemeWin::create().releaseRef();
147     return winTheme;
148 }
149 #endif
150 
RenderThemeWin()151 RenderThemeWin::RenderThemeWin()
152     : m_buttonTheme(0)
153     , m_textFieldTheme(0)
154     , m_menuListTheme(0)
155     , m_sliderTheme(0)
156 {
157     haveTheme = uxthemeLibrary() && IsThemeActive();
158 }
159 
~RenderThemeWin()160 RenderThemeWin::~RenderThemeWin()
161 {
162     // If WebKit is being unloaded, then uxtheme.dll is no longer available.
163     if (gWebKitIsBeingUnloaded || !uxthemeLibrary())
164         return;
165     close();
166 }
167 
buttonTheme() const168 HANDLE RenderThemeWin::buttonTheme() const
169 {
170     if (haveTheme && !m_buttonTheme)
171         m_buttonTheme = OpenThemeData(0, L"Button");
172     return m_buttonTheme;
173 }
174 
textFieldTheme() const175 HANDLE RenderThemeWin::textFieldTheme() const
176 {
177     if (haveTheme && !m_textFieldTheme)
178         m_textFieldTheme = OpenThemeData(0, L"Edit");
179     return m_textFieldTheme;
180 }
181 
menuListTheme() const182 HANDLE RenderThemeWin::menuListTheme() const
183 {
184     if (haveTheme && !m_menuListTheme)
185         m_menuListTheme = OpenThemeData(0, L"ComboBox");
186     return m_menuListTheme;
187 }
188 
sliderTheme() const189 HANDLE RenderThemeWin::sliderTheme() const
190 {
191     if (haveTheme && !m_sliderTheme)
192         m_sliderTheme = OpenThemeData(0, L"TrackBar");
193     return m_sliderTheme;
194 }
195 
close()196 void RenderThemeWin::close()
197 {
198     // This method will need to be called when the OS theme changes to flush our cached themes.
199     if (m_buttonTheme)
200         CloseThemeData(m_buttonTheme);
201     if (m_textFieldTheme)
202         CloseThemeData(m_textFieldTheme);
203     if (m_menuListTheme)
204         CloseThemeData(m_menuListTheme);
205     if (m_sliderTheme)
206         CloseThemeData(m_sliderTheme);
207     m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = 0;
208 
209     haveTheme = uxthemeLibrary() && IsThemeActive();
210 }
211 
themeChanged()212 void RenderThemeWin::themeChanged()
213 {
214     close();
215 }
216 
extraDefaultStyleSheet()217 String RenderThemeWin::extraDefaultStyleSheet()
218 {
219     return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
220 }
221 
extraQuirksStyleSheet()222 String RenderThemeWin::extraQuirksStyleSheet()
223 {
224     return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
225 }
226 
supportsHover(const RenderStyle *) const227 bool RenderThemeWin::supportsHover(const RenderStyle*) const
228 {
229     // The Classic/2k look has no hover effects.
230     return haveTheme;
231 }
232 
platformActiveSelectionBackgroundColor() const233 Color RenderThemeWin::platformActiveSelectionBackgroundColor() const
234 {
235     COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
236     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
237 }
238 
platformInactiveSelectionBackgroundColor() const239 Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const
240 {
241     // This color matches Firefox.
242     return Color(176, 176, 176);
243 }
244 
platformActiveSelectionForegroundColor() const245 Color RenderThemeWin::platformActiveSelectionForegroundColor() const
246 {
247     COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
248     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
249 }
250 
platformInactiveSelectionForegroundColor() const251 Color RenderThemeWin::platformInactiveSelectionForegroundColor() const
252 {
253     return platformActiveSelectionForegroundColor();
254 }
255 
fillFontDescription(FontDescription & fontDescription,LOGFONT & logFont,float fontSize)256 static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont, float fontSize)
257 {
258     fontDescription.setIsAbsoluteSize(true);
259     fontDescription.setGenericFamily(FontDescription::NoFamily);
260     fontDescription.firstFamily().setFamily(String(logFont.lfFaceName));
261     fontDescription.setSpecifiedSize(fontSize);
262     fontDescription.setWeight(logFont.lfWeight >= 700 ? FontWeightBold : FontWeightNormal); // FIXME: Use real weight.
263     fontDescription.setItalic(logFont.lfItalic);
264 }
265 
fillFontDescription(FontDescription & fontDescription,LOGFONT & logFont)266 static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont)
267 {
268     fillFontDescription(fontDescription, logFont, abs(logFont.lfHeight));
269 }
270 
systemFont(int propId,FontDescription & fontDescription) const271 void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) const
272 {
273     static FontDescription captionFont;
274     static FontDescription controlFont;
275     static FontDescription smallCaptionFont;
276     static FontDescription menuFont;
277     static FontDescription iconFont;
278     static FontDescription messageBoxFont;
279     static FontDescription statusBarFont;
280     static FontDescription systemFont;
281 
282     static bool initialized;
283     static NONCLIENTMETRICS ncm;
284 
285     if (!initialized) {
286         initialized = true;
287         ncm.cbSize = sizeof(NONCLIENTMETRICS);
288         ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
289     }
290 
291     switch (propId) {
292         case CSSValueIcon: {
293             if (!iconFont.isAbsoluteSize()) {
294                 LOGFONT logFont;
295                 ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
296                 fillFontDescription(iconFont, logFont);
297             }
298             fontDescription = iconFont;
299             break;
300         }
301         case CSSValueMenu:
302             if (!menuFont.isAbsoluteSize())
303                 fillFontDescription(menuFont, ncm.lfMenuFont);
304             fontDescription = menuFont;
305             break;
306         case CSSValueMessageBox:
307             if (!messageBoxFont.isAbsoluteSize())
308                 fillFontDescription(messageBoxFont, ncm.lfMessageFont);
309             fontDescription = messageBoxFont;
310             break;
311         case CSSValueStatusBar:
312             if (!statusBarFont.isAbsoluteSize())
313                 fillFontDescription(statusBarFont, ncm.lfStatusFont);
314             fontDescription = statusBarFont;
315             break;
316         case CSSValueCaption:
317             if (!captionFont.isAbsoluteSize())
318                 fillFontDescription(captionFont, ncm.lfCaptionFont);
319             fontDescription = captionFont;
320             break;
321         case CSSValueSmallCaption:
322             if (!smallCaptionFont.isAbsoluteSize())
323                 fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont);
324             fontDescription = smallCaptionFont;
325             break;
326         case CSSValueWebkitSmallControl:
327         case CSSValueWebkitMiniControl: // Just map to small.
328         case CSSValueWebkitControl: // Just map to small.
329             if (!controlFont.isAbsoluteSize()) {
330                 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
331                 if (hGDI) {
332                     LOGFONT logFont;
333                     if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
334                         fillFontDescription(controlFont, logFont, defaultControlFontPixelSize);
335                 }
336             }
337             fontDescription = controlFont;
338             break;
339         default: { // Everything else uses the stock GUI font.
340             if (!systemFont.isAbsoluteSize()) {
341                 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
342                 if (hGDI) {
343                     LOGFONT logFont;
344                     if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
345                         fillFontDescription(systemFont, logFont);
346                 }
347             }
348             fontDescription = systemFont;
349         }
350     }
351 }
352 
supportsFocus(ControlPart appearance) const353 bool RenderThemeWin::supportsFocus(ControlPart appearance) const
354 {
355     switch (appearance) {
356         case PushButtonPart:
357         case ButtonPart:
358         case DefaultButtonPart:
359             return true;
360         default:
361             return false;
362     }
363 }
364 
supportsFocusRing(const RenderStyle * style) const365 bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const
366 {
367     return supportsFocus(style->appearance());
368 }
369 
determineClassicState(RenderObject * o)370 unsigned RenderThemeWin::determineClassicState(RenderObject* o)
371 {
372     unsigned state = 0;
373     switch (o->style()->appearance()) {
374         case PushButtonPart:
375         case ButtonPart:
376         case DefaultButtonPart:
377             state = DFCS_BUTTONPUSH;
378             if (!isEnabled(o))
379                 state |= DFCS_INACTIVE;
380             else if (isPressed(o))
381                 state |= DFCS_PUSHED;
382             break;
383         case RadioPart:
384         case CheckboxPart:
385             state = (o->style()->appearance() == RadioPart) ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
386             if (isChecked(o))
387                 state |= DFCS_CHECKED;
388             if (!isEnabled(o))
389                 state |= DFCS_INACTIVE;
390             else if (isPressed(o))
391                 state |= DFCS_PUSHED;
392             break;
393         case MenulistPart:
394             state = DFCS_SCROLLCOMBOBOX;
395             if (!isEnabled(o))
396                 state |= DFCS_INACTIVE;
397             else if (isPressed(o))
398                 state |= DFCS_PUSHED;
399         default:
400             break;
401     }
402     return state;
403 }
404 
determineState(RenderObject * o)405 unsigned RenderThemeWin::determineState(RenderObject* o)
406 {
407     unsigned result = TS_NORMAL;
408     ControlPart appearance = o->style()->appearance();
409     if (!isEnabled(o))
410         result = TS_DISABLED;
411     else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance))
412         result = TFS_READONLY; // Readonly is supported on textfields.
413     else if (isPressed(o)) // Active overrides hover and focused.
414         result = TS_ACTIVE;
415     else if (supportsFocus(appearance) && isFocused(o))
416         result = TS_FOCUSED;
417     else if (isHovered(o))
418         result = TS_HOVER;
419     if (isChecked(o))
420         result += 4; // 4 unchecked states, 4 checked states.
421     return result;
422 }
423 
determineSliderThumbState(RenderObject * o)424 unsigned RenderThemeWin::determineSliderThumbState(RenderObject* o)
425 {
426     unsigned result = TUS_NORMAL;
427     if (!isEnabled(o->parent()))
428         result = TUS_DISABLED;
429     else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent()))
430         result = TUS_FOCUSED;
431     else if (toRenderSlider(o->parent())->inDragMode())
432         result = TUS_PRESSED;
433     else if (isHovered(o))
434         result = TUS_HOT;
435     return result;
436 }
437 
determineButtonState(RenderObject * o)438 unsigned RenderThemeWin::determineButtonState(RenderObject* o)
439 {
440     unsigned result = PBS_NORMAL;
441     if (!isEnabled(o))
442         result = PBS_DISABLED;
443     else if (isPressed(o))
444         result = PBS_PRESSED;
445     else if (supportsFocus(o->style()->appearance()) && isFocused(o))
446         result = PBS_DEFAULTED;
447     else if (isHovered(o))
448         result = PBS_HOT;
449     else if (isDefault(o))
450         result = PBS_DEFAULTED;
451     return result;
452 }
453 
getClassicThemeData(RenderObject * o)454 ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o)
455 {
456     ThemeData result;
457     switch (o->style()->appearance()) {
458         case PushButtonPart:
459         case ButtonPart:
460         case DefaultButtonPart:
461         case CheckboxPart:
462         case RadioPart:
463             result.m_part = DFC_BUTTON;
464             result.m_state = determineClassicState(o);
465             break;
466         case MenulistPart:
467             result.m_part = DFC_SCROLL;
468             result.m_state = determineClassicState(o);
469             break;
470         case SearchFieldPart:
471         case TextFieldPart:
472         case TextAreaPart:
473             result.m_part = TFP_TEXTFIELD;
474             result.m_state = determineState(o);
475             break;
476         case SliderHorizontalPart:
477             result.m_part = TKP_TRACK;
478             result.m_state = TS_NORMAL;
479             break;
480         case SliderVerticalPart:
481             result.m_part = TKP_TRACKVERT;
482             result.m_state = TS_NORMAL;
483             break;
484         case SliderThumbHorizontalPart:
485             result.m_part = TKP_THUMBBOTTOM;
486             result.m_state = determineSliderThumbState(o);
487             break;
488         case SliderThumbVerticalPart:
489             result.m_part = TKP_THUMBRIGHT;
490             result.m_state = determineSliderThumbState(o);
491             break;
492         default:
493             break;
494     }
495     return result;
496 }
497 
getThemeData(RenderObject * o)498 ThemeData RenderThemeWin::getThemeData(RenderObject* o)
499 {
500     if (!haveTheme)
501         return getClassicThemeData(o);
502 
503     ThemeData result;
504     switch (o->style()->appearance()) {
505         case PushButtonPart:
506         case ButtonPart:
507         case DefaultButtonPart:
508             result.m_part = BP_BUTTON;
509             result.m_state = determineButtonState(o);
510             break;
511         case CheckboxPart:
512             result.m_part = BP_CHECKBOX;
513             result.m_state = determineState(o);
514             break;
515         case MenulistPart:
516         case MenulistButtonPart:
517             result.m_part = isRunningOnVistaOrLater() ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON;
518             if (isRunningOnVistaOrLater() && documentIsInApplicationChromeMode(o->document())) {
519                 // The "readonly" look we use in application chrome mode
520                 // only uses a "normal" look for the drop down button.
521                 result.m_state = TS_NORMAL;
522             } else
523                 result.m_state = determineState(o);
524             break;
525         case RadioPart:
526             result.m_part = BP_RADIO;
527             result.m_state = determineState(o);
528             break;
529         case SearchFieldPart:
530         case TextFieldPart:
531         case TextAreaPart:
532             result.m_part = isRunningOnVistaOrLater() ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD;
533             result.m_state = determineState(o);
534             break;
535         case SliderHorizontalPart:
536             result.m_part = TKP_TRACK;
537             result.m_state = TS_NORMAL;
538             break;
539         case SliderVerticalPart:
540             result.m_part = TKP_TRACKVERT;
541             result.m_state = TS_NORMAL;
542             break;
543         case SliderThumbHorizontalPart:
544             result.m_part = TKP_THUMBBOTTOM;
545             result.m_state = determineSliderThumbState(o);
546             break;
547         case SliderThumbVerticalPart:
548             result.m_part = TKP_THUMBRIGHT;
549             result.m_state = determineSliderThumbState(o);
550             break;
551     }
552 
553     return result;
554 }
555 
drawControl(GraphicsContext * context,RenderObject * o,HANDLE theme,const ThemeData & themeData,const IntRect & r)556 static void drawControl(GraphicsContext* context, RenderObject* o, HANDLE theme, const ThemeData& themeData, const IntRect& r)
557 {
558     bool alphaBlend = false;
559     if (theme)
560         alphaBlend = IsThemeBackgroundPartiallyTransparent(theme, themeData.m_part, themeData.m_state);
561     HDC hdc = context->getWindowsContext(r, alphaBlend);
562     RECT widgetRect = r;
563     if (theme)
564         DrawThemeBackground(theme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
565     else {
566         if (themeData.m_part == TFP_TEXTFIELD) {
567             ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
568             if (themeData.m_state == TS_DISABLED || themeData.m_state ==  TFS_READONLY)
569                 ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_BTNFACE+1));
570             else
571                 ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_WINDOW+1));
572         } else if (themeData.m_part == TKP_TRACK || themeData.m_part == TKP_TRACKVERT) {
573             ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
574             ::FillRect(hdc, &widgetRect, (HBRUSH)GetStockObject(GRAY_BRUSH));
575         } else if ((o->style()->appearance() == SliderThumbHorizontalPart ||
576                     o->style()->appearance() == SliderThumbVerticalPart) &&
577                    (themeData.m_part == TKP_THUMBBOTTOM || themeData.m_part == TKP_THUMBTOP ||
578                     themeData.m_part == TKP_THUMBLEFT || themeData.m_part == TKP_THUMBRIGHT)) {
579             ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
580             if (themeData.m_state == TUS_DISABLED) {
581                 static WORD patternBits[8] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
582                 HBITMAP patternBmp = ::CreateBitmap(8, 8, 1, 1, patternBits);
583                 if (patternBmp) {
584                     HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patternBmp);
585                     COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(COLOR_3DFACE));
586                     COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
587                     POINT p;
588                     ::GetViewportOrgEx(hdc, &p);
589                     ::SetBrushOrgEx(hdc, p.x + widgetRect.left, p.y + widgetRect.top, NULL);
590                     HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush);
591                     ::FillRect(hdc, &widgetRect, brush);
592                     ::SetTextColor(hdc, oldForeColor);
593                     ::SetBkColor(hdc, oldBackColor);
594                     ::SelectObject(hdc, oldBrush);
595                     ::DeleteObject(brush);
596                 } else
597                     ::FillRect(hdc, &widgetRect, (HBRUSH)COLOR_3DHILIGHT);
598                 ::DeleteObject(patternBmp);
599             }
600         } else {
601             // Push buttons, buttons, checkboxes and radios, and the dropdown arrow in menulists.
602             if (o->style()->appearance() == DefaultButtonPart) {
603                 HBRUSH brush = ::GetSysColorBrush(COLOR_3DDKSHADOW);
604                 ::FrameRect(hdc, &widgetRect, brush);
605                 ::InflateRect(&widgetRect, -1, -1);
606                 ::DrawEdge(hdc, &widgetRect, BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE);
607             }
608             ::DrawFrameControl(hdc, &widgetRect, themeData.m_part, themeData.m_state);
609         }
610     }
611     context->releaseWindowsContext(hdc, r, alphaBlend);
612 }
613 
paintButton(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)614 bool RenderThemeWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
615 {
616     drawControl(i.context,  o, buttonTheme(), getThemeData(o), r);
617     return false;
618 }
619 
setCheckboxSize(RenderStyle * style) const620 void RenderThemeWin::setCheckboxSize(RenderStyle* style) const
621 {
622     // If the width and height are both specified, then we have nothing to do.
623     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
624         return;
625 
626     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
627     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
628     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
629     // metrics.
630     if (style->width().isIntrinsicOrAuto())
631         style->setWidth(Length(13, Fixed));
632     if (style->height().isAuto())
633         style->setHeight(Length(13, Fixed));
634 }
635 
paintTextField(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)636 bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
637 {
638     drawControl(i.context,  o, textFieldTheme(), getThemeData(o), r);
639     return false;
640 }
641 
paintMenuList(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)642 bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
643 {
644     HANDLE theme;
645     int part;
646     if (haveTheme && isRunningOnVistaOrLater()) {
647         theme = menuListTheme();
648         if (documentIsInApplicationChromeMode(o->document()))
649             part = CP_READONLY;
650         else
651             part = CP_BORDER;
652     } else {
653         theme = textFieldTheme();
654         part = TFP_TEXTFIELD;
655     }
656 
657     drawControl(i.context,  o, theme, ThemeData(part, determineState(o)), r);
658 
659     return paintMenuListButton(o, i, r);
660 }
661 
adjustMenuListStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const662 void RenderThemeWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
663 {
664     style->resetBorder();
665     adjustMenuListButtonStyle(selector, style, e);
666 }
667 
adjustMenuListButtonStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const668 void RenderThemeWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
669 {
670     // These are the paddings needed to place the text correctly in the <select> box
671     const int dropDownBoxPaddingTop    = 2;
672     const int dropDownBoxPaddingRight  = style->direction() == LTR ? 4 + dropDownButtonWidth : 4;
673     const int dropDownBoxPaddingBottom = 2;
674     const int dropDownBoxPaddingLeft   = style->direction() == LTR ? 4 : 4 + dropDownButtonWidth;
675     // The <select> box must be at least 12px high for the button to render nicely on Windows
676     const int dropDownBoxMinHeight = 12;
677 
678     // Position the text correctly within the select box and make the box wide enough to fit the dropdown button
679     style->setPaddingTop(Length(dropDownBoxPaddingTop, Fixed));
680     style->setPaddingRight(Length(dropDownBoxPaddingRight, Fixed));
681     style->setPaddingBottom(Length(dropDownBoxPaddingBottom, Fixed));
682     style->setPaddingLeft(Length(dropDownBoxPaddingLeft, Fixed));
683 
684     // Height is locked to auto
685     style->setHeight(Length(Auto));
686 
687     // Calculate our min-height
688     int minHeight = style->font().height();
689     minHeight = max(minHeight, dropDownBoxMinHeight);
690 
691     style->setMinHeight(Length(minHeight, Fixed));
692 
693     // White-space is locked to pre
694     style->setWhiteSpace(PRE);
695 }
696 
paintMenuListButton(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)697 bool RenderThemeWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
698 {
699     // FIXME: Don't make hardcoded assumptions about the thickness of the textfield border.
700     int borderThickness = haveTheme ? 1 : 2;
701 
702     // Paint the dropdown button on the inner edge of the text field,
703     // leaving space for the text field's 1px border
704     IntRect buttonRect(r);
705     buttonRect.inflate(-borderThickness);
706     if (o->style()->direction() == LTR)
707         buttonRect.setX(buttonRect.right() - dropDownButtonWidth);
708     buttonRect.setWidth(dropDownButtonWidth);
709 
710     if (isRunningOnVistaOrLater()) {
711         // Outset the top, right, and bottom borders of the button so that they coincide with the <select>'s border.
712         buttonRect.setY(buttonRect.y() - vistaMenuListButtonOutset);
713         buttonRect.setHeight(buttonRect.height() + 2 * vistaMenuListButtonOutset);
714         buttonRect.setWidth(buttonRect.width() + vistaMenuListButtonOutset);
715     }
716 
717     drawControl(i.context, o, menuListTheme(), getThemeData(o), buttonRect);
718 
719     return false;
720 }
721 
722 const int trackWidth = 4;
723 
paintSliderTrack(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)724 bool RenderThemeWin::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
725 {
726     IntRect bounds = r;
727 
728     if (o->style()->appearance() ==  SliderHorizontalPart) {
729         bounds.setHeight(trackWidth);
730         bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
731     } else if (o->style()->appearance() == SliderVerticalPart) {
732         bounds.setWidth(trackWidth);
733         bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
734     }
735 
736     drawControl(i.context,  o, sliderTheme(), getThemeData(o), bounds);
737     return false;
738 }
739 
paintSliderThumb(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)740 bool RenderThemeWin::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
741 {
742     drawControl(i.context,  o, sliderTheme(), getThemeData(o), r);
743     return false;
744 }
745 
746 const int sliderThumbWidth = 7;
747 const int sliderThumbHeight = 15;
748 
adjustSliderThumbSize(RenderObject * o) const749 void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const
750 {
751     if (o->style()->appearance() == SliderThumbVerticalPart) {
752         o->style()->setWidth(Length(sliderThumbHeight, Fixed));
753         o->style()->setHeight(Length(sliderThumbWidth, Fixed));
754     } else if (o->style()->appearance() == SliderThumbHorizontalPart) {
755         o->style()->setWidth(Length(sliderThumbWidth, Fixed));
756         o->style()->setHeight(Length(sliderThumbHeight, Fixed));
757     }
758 #if ENABLE(VIDEO)
759     else if (o->style()->appearance() == MediaSliderThumbPart)
760         RenderMediaControls::adjustMediaSliderThumbSize(o);
761 #endif
762 }
763 
buttonInternalPaddingLeft() const764 int RenderThemeWin::buttonInternalPaddingLeft() const
765 {
766     return 3;
767 }
768 
buttonInternalPaddingRight() const769 int RenderThemeWin::buttonInternalPaddingRight() const
770 {
771     return 3;
772 }
773 
buttonInternalPaddingTop() const774 int RenderThemeWin::buttonInternalPaddingTop() const
775 {
776     return 1;
777 }
778 
buttonInternalPaddingBottom() const779 int RenderThemeWin::buttonInternalPaddingBottom() const
780 {
781     return 1;
782 }
783 
paintSearchField(RenderObject * o,const RenderObject::PaintInfo & i,const IntRect & r)784 bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
785 {
786     return paintTextField(o, i, r);
787 }
788 
adjustSearchFieldStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const789 void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
790 {
791     // Override paddingSize to match AppKit text positioning.
792     const int padding = 1;
793     style->setPaddingLeft(Length(padding, Fixed));
794     style->setPaddingRight(Length(padding, Fixed));
795     style->setPaddingTop(Length(padding, Fixed));
796     style->setPaddingBottom(Length(padding, Fixed));
797     if (e && e->focused() && e->document()->frame()->selection()->isFocusedAndActive())
798         style->setOutlineOffset(-2);
799 }
800 
paintSearchFieldCancelButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)801 bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
802 {
803     IntRect bounds = r;
804     ASSERT(o->parent());
805     if (!o->parent() || !o->parent()->isBox())
806         return false;
807 
808     RenderBox* parentRenderBox = toRenderBox(o->parent());
809 
810     IntRect parentBox = parentRenderBox->absoluteContentBox();
811 
812     // Make sure the scaled button stays square and will fit in its parent's box
813     bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height())));
814     bounds.setWidth(bounds.height());
815 
816     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
817     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
818     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
819 
820     static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef();
821     static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef();
822     paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds);
823     return false;
824 }
825 
adjustSearchFieldCancelButtonStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const826 void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
827 {
828     // Scale the button size based on the font size
829     float fontScale = style->fontSize() / defaultControlFontPixelSize;
830     int cancelButtonSize = lroundf(min(max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
831     style->setWidth(Length(cancelButtonSize, Fixed));
832     style->setHeight(Length(cancelButtonSize, Fixed));
833 }
834 
adjustSearchFieldDecorationStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const835 void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
836 {
837     IntSize emptySize(1, 11);
838     style->setWidth(Length(emptySize.width(), Fixed));
839     style->setHeight(Length(emptySize.height(), Fixed));
840 }
841 
adjustSearchFieldResultsDecorationStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const842 void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
843 {
844     // Scale the decoration size based on the font size
845     float fontScale = style->fontSize() / defaultControlFontPixelSize;
846     int magnifierSize = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
847                                      maxSearchFieldResultsDecorationSize));
848     style->setWidth(Length(magnifierSize, Fixed));
849     style->setHeight(Length(magnifierSize, Fixed));
850 }
851 
paintSearchFieldResultsDecoration(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)852 bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
853 {
854     IntRect bounds = r;
855     ASSERT(o->parent());
856     if (!o->parent() || !o->parent()->isBox())
857         return false;
858 
859     RenderBox* parentRenderBox = toRenderBox(o->parent());
860     IntRect parentBox = parentRenderBox->absoluteContentBox();
861 
862     // Make sure the scaled decoration stays square and will fit in its parent's box
863     bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height())));
864     bounds.setWidth(bounds.height());
865 
866     // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
867     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
868     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
869 
870     static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef();
871     paintInfo.context->drawImage(magnifierImage, bounds);
872     return false;
873 }
874 
adjustSearchFieldResultsButtonStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const875 void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
876 {
877     // Scale the button size based on the font size
878     float fontScale = style->fontSize() / defaultControlFontPixelSize;
879     int magnifierHeight = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
880                                    maxSearchFieldResultsDecorationSize));
881     int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
882     style->setWidth(Length(magnifierWidth, Fixed));
883     style->setHeight(Length(magnifierHeight, Fixed));
884 }
885 
paintSearchFieldResultsButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)886 bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
887 {
888     IntRect bounds = r;
889     ASSERT(o->parent());
890     if (!o->parent())
891         return false;
892     if (!o->parent() || !o->parent()->isBox())
893         return false;
894 
895     RenderBox* parentRenderBox = toRenderBox(o->parent());
896     IntRect parentBox = parentRenderBox->absoluteContentBox();
897 
898     // Make sure the scaled decoration will fit in its parent's box
899     bounds.setHeight(min(parentBox.height(), bounds.height()));
900     bounds.setWidth(min(parentBox.width(), static_cast<int>(bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize)));
901 
902     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
903     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
904     bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
905 
906     static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef();
907     paintInfo.context->drawImage(magnifierImage, bounds);
908     return false;
909 }
910 
911 // Map a CSSValue* system color to an index understood by GetSysColor
cssValueIdToSysColorIndex(int cssValueId)912 static int cssValueIdToSysColorIndex(int cssValueId)
913 {
914     switch (cssValueId) {
915         case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
916         case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
917         case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
918         case CSSValueBackground: return COLOR_BACKGROUND;
919         case CSSValueButtonface: return COLOR_BTNFACE;
920         case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
921         case CSSValueButtonshadow: return COLOR_BTNSHADOW;
922         case CSSValueButtontext: return COLOR_BTNTEXT;
923         case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
924         case CSSValueGraytext: return COLOR_GRAYTEXT;
925         case CSSValueHighlight: return COLOR_HIGHLIGHT;
926         case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
927         case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
928         case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
929         case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
930         case CSSValueInfobackground: return COLOR_INFOBK;
931         case CSSValueInfotext: return COLOR_INFOTEXT;
932         case CSSValueMenu: return COLOR_MENU;
933         case CSSValueMenutext: return COLOR_MENUTEXT;
934         case CSSValueScrollbar: return COLOR_SCROLLBAR;
935         case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
936         case CSSValueThreedface: return COLOR_3DFACE;
937         case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
938         case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
939         case CSSValueThreedshadow: return COLOR_3DSHADOW;
940         case CSSValueWindow: return COLOR_WINDOW;
941         case CSSValueWindowframe: return COLOR_WINDOWFRAME;
942         case CSSValueWindowtext: return COLOR_WINDOWTEXT;
943         default: return -1; // Unsupported CSSValue
944     }
945 }
946 
systemColor(int cssValueId) const947 Color RenderThemeWin::systemColor(int cssValueId) const
948 {
949     int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
950     if (sysColorIndex == -1)
951         return RenderTheme::systemColor(cssValueId);
952 
953     COLORREF color = GetSysColor(sysColorIndex);
954     return Color(GetRValue(color), GetGValue(color), GetBValue(color));
955 }
956 
957 #if ENABLE(VIDEO)
paintMediaFullscreenButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)958 bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
959 {
960     return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r);
961 }
962 
paintMediaMuteButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)963 bool RenderThemeWin::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
964 {
965     return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r);
966 }
967 
paintMediaPlayButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)968 bool RenderThemeWin::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
969 {
970     return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r);
971 }
972 
paintMediaSeekBackButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)973 bool RenderThemeWin::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
974 {
975     return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r);
976 }
977 
paintMediaSeekForwardButton(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)978 bool RenderThemeWin::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
979 {
980     return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r);
981 }
982 
paintMediaSliderTrack(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)983 bool RenderThemeWin::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
984 {
985     return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r);
986 }
987 
paintMediaSliderThumb(RenderObject * o,const RenderObject::PaintInfo & paintInfo,const IntRect & r)988 bool RenderThemeWin::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
989 {
990     return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r);
991 }
992 #endif
993 
994 }
995