2 * Copyright (C) 2006, 2007 Apple Inc.
3 * Copyright (C) 2009 Kenneth Rohde Christiansen
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.
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.
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.
23 #include "RenderThemeWin.h"
25 #include "CSSValueKeywords.h"
28 #include "GraphicsContext.h"
29 #include "LocalWindowsContext.h"
30 #include "PaintInfo.h"
31 #include "RenderSlider.h"
33 #include "SoftLinking.h"
34 #include "SystemInfo.h"
35 #include "UserAgentStyleSheets.h"
38 #include "RenderMediaControls.h"
44 * The following constants are used to determine how a widget is drawn using
45 * Windows' Theme API. For more information on theme parts and states see
46 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
49 // Generic state constants
61 // Textfield constants
62 #define TFP_TEXTFIELD 1
63 #define EP_EDITBORDER_NOSCROLL 6
64 #define TFS_READONLY 6
66 // ComboBox constants (from vsstyle.h)
67 #define CP_DROPDOWNBUTTON 1
70 #define CP_DROPDOWNBUTTONRIGHT 6
72 // TrackBar (slider) parts
74 #define TKP_TRACKVERT 2
76 // TrackBar (slider) thumb parts
77 #define TKP_THUMBBOTTOM 4
78 #define TKP_THUMBTOP 5
79 #define TKP_THUMBLEFT 7
80 #define TKP_THUMBRIGHT 8
82 // Trackbar (slider) thumb states
87 #define TUS_DISABLED 5
93 #define PBS_DISABLED 4
94 #define PBS_DEFAULTED 5
100 // Spin button states
103 #define DNS_PRESSED 3
104 #define DNS_DISABLED 4
107 #define UPS_PRESSED 3
108 #define UPS_DISABLED 4
111 SOFT_LINK_LIBRARY(uxtheme)
112 SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
113 SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
114 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))
115 SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
116 SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
118 static bool haveTheme;
120 static const unsigned vistaMenuListButtonOutset = 1;
126 // This is the fixed width IE and Firefox use for buttons on dropdown menus
127 static const int dropDownButtonWidth = 17;
129 static const int shell32MagnifierIconIndex = 22;
131 // Default font size to match Firefox.
132 static const float defaultControlFontPixelSize = 13;
134 static const float defaultCancelButtonSize = 9;
135 static const float minCancelButtonSize = 5;
136 static const float maxCancelButtonSize = 21;
137 static const float defaultSearchFieldResultsDecorationSize = 13;
138 static const float minSearchFieldResultsDecorationSize = 9;
139 static const float maxSearchFieldResultsDecorationSize = 30;
140 static const float defaultSearchFieldResultsButtonWidth = 18;
142 static bool gWebKitIsBeingUnloaded;
144 static bool documentIsInApplicationChromeMode(const Document* document)
146 Settings* settings = document->settings();
147 return settings && settings->inApplicationChromeMode();
150 void RenderThemeWin::setWebKitIsBeingUnloaded()
152 gWebKitIsBeingUnloaded = true;
155 PassRefPtr<RenderTheme> RenderThemeWin::create()
157 return adoptRef(new RenderThemeWin);
160 #if !USE(SAFARI_THEME)
161 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
163 static RenderTheme* winTheme = RenderThemeWin::create().leakRef();
168 RenderThemeWin::RenderThemeWin()
170 , m_textFieldTheme(0)
173 , m_spinButtonTheme(0)
175 haveTheme = uxthemeLibrary() && IsThemeActive();
178 RenderThemeWin::~RenderThemeWin()
180 // If WebKit is being unloaded, then uxtheme.dll is no longer available.
181 if (gWebKitIsBeingUnloaded || !uxthemeLibrary())
186 HANDLE RenderThemeWin::buttonTheme() const
188 if (haveTheme && !m_buttonTheme)
189 m_buttonTheme = OpenThemeData(0, L"Button");
190 return m_buttonTheme;
193 HANDLE RenderThemeWin::textFieldTheme() const
195 if (haveTheme && !m_textFieldTheme)
196 m_textFieldTheme = OpenThemeData(0, L"Edit");
197 return m_textFieldTheme;
200 HANDLE RenderThemeWin::menuListTheme() const
202 if (haveTheme && !m_menuListTheme)
203 m_menuListTheme = OpenThemeData(0, L"ComboBox");
204 return m_menuListTheme;
207 HANDLE RenderThemeWin::sliderTheme() const
209 if (haveTheme && !m_sliderTheme)
210 m_sliderTheme = OpenThemeData(0, L"TrackBar");
211 return m_sliderTheme;
214 HANDLE RenderThemeWin::spinButtonTheme() const
216 if (haveTheme && !m_spinButtonTheme)
217 m_spinButtonTheme = OpenThemeData(0, L"Spin");
218 return m_spinButtonTheme;
221 void RenderThemeWin::close()
223 // This method will need to be called when the OS theme changes to flush our cached themes.
225 CloseThemeData(m_buttonTheme);
226 if (m_textFieldTheme)
227 CloseThemeData(m_textFieldTheme);
229 CloseThemeData(m_menuListTheme);
231 CloseThemeData(m_sliderTheme);
232 if (m_spinButtonTheme)
233 CloseThemeData(m_spinButtonTheme);
234 m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = m_spinButtonTheme = 0;
236 haveTheme = uxthemeLibrary() && IsThemeActive();
239 void RenderThemeWin::themeChanged()
244 String RenderThemeWin::extraDefaultStyleSheet()
246 return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
249 String RenderThemeWin::extraQuirksStyleSheet()
251 return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
254 bool RenderThemeWin::supportsHover(const RenderStyle*) const
256 // The Classic/2k look has no hover effects.
260 Color RenderThemeWin::platformActiveSelectionBackgroundColor() const
262 COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
263 return Color(GetRValue(color), GetGValue(color), GetBValue(color));
266 Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const
268 // This color matches Firefox.
269 return Color(176, 176, 176);
272 Color RenderThemeWin::platformActiveSelectionForegroundColor() const
274 COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
275 return Color(GetRValue(color), GetGValue(color), GetBValue(color));
278 Color RenderThemeWin::platformInactiveSelectionForegroundColor() const
280 return platformActiveSelectionForegroundColor();
283 static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont, float fontSize)
285 fontDescription.setIsAbsoluteSize(true);
286 fontDescription.setGenericFamily(FontDescription::NoFamily);
287 fontDescription.firstFamily().setFamily(String(logFont.lfFaceName));
288 fontDescription.setSpecifiedSize(fontSize);
289 fontDescription.setWeight(logFont.lfWeight >= 700 ? FontWeightBold : FontWeightNormal); // FIXME: Use real weight.
290 fontDescription.setItalic(logFont.lfItalic);
293 static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont)
295 fillFontDescription(fontDescription, logFont, abs(logFont.lfHeight));
298 void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) const
300 static FontDescription captionFont;
301 static FontDescription controlFont;
302 static FontDescription smallCaptionFont;
303 static FontDescription menuFont;
304 static FontDescription iconFont;
305 static FontDescription messageBoxFont;
306 static FontDescription statusBarFont;
307 static FontDescription systemFont;
309 static bool initialized;
310 static NONCLIENTMETRICS ncm;
314 ncm.cbSize = sizeof(NONCLIENTMETRICS);
315 ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
320 if (!iconFont.isAbsoluteSize()) {
322 ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
323 fillFontDescription(iconFont, logFont);
325 fontDescription = iconFont;
329 if (!menuFont.isAbsoluteSize())
330 fillFontDescription(menuFont, ncm.lfMenuFont);
331 fontDescription = menuFont;
333 case CSSValueMessageBox:
334 if (!messageBoxFont.isAbsoluteSize())
335 fillFontDescription(messageBoxFont, ncm.lfMessageFont);
336 fontDescription = messageBoxFont;
338 case CSSValueStatusBar:
339 if (!statusBarFont.isAbsoluteSize())
340 fillFontDescription(statusBarFont, ncm.lfStatusFont);
341 fontDescription = statusBarFont;
343 case CSSValueCaption:
344 if (!captionFont.isAbsoluteSize())
345 fillFontDescription(captionFont, ncm.lfCaptionFont);
346 fontDescription = captionFont;
348 case CSSValueSmallCaption:
349 if (!smallCaptionFont.isAbsoluteSize())
350 fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont);
351 fontDescription = smallCaptionFont;
353 case CSSValueWebkitSmallControl:
354 case CSSValueWebkitMiniControl: // Just map to small.
355 case CSSValueWebkitControl: // Just map to small.
356 if (!controlFont.isAbsoluteSize()) {
357 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
360 if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
361 fillFontDescription(controlFont, logFont, defaultControlFontPixelSize);
364 fontDescription = controlFont;
366 default: { // Everything else uses the stock GUI font.
367 if (!systemFont.isAbsoluteSize()) {
368 HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
371 if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
372 fillFontDescription(systemFont, logFont);
375 fontDescription = systemFont;
380 bool RenderThemeWin::supportsFocus(ControlPart appearance) const
382 switch (appearance) {
385 case DefaultButtonPart:
392 bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const
394 return supportsFocus(style->appearance());
397 unsigned RenderThemeWin::determineClassicState(RenderObject* o, ControlSubPart subPart)
400 switch (o->style()->appearance()) {
403 case DefaultButtonPart:
404 state = DFCS_BUTTONPUSH;
406 state |= DFCS_INACTIVE;
407 else if (isPressed(o))
408 state |= DFCS_PUSHED;
412 state = (o->style()->appearance() == RadioPart) ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
414 state |= DFCS_CHECKED;
416 state |= DFCS_INACTIVE;
417 else if (isPressed(o))
418 state |= DFCS_PUSHED;
421 state = DFCS_SCROLLCOMBOBOX;
423 state |= DFCS_INACTIVE;
424 else if (isPressed(o))
425 state |= DFCS_PUSHED;
427 case InnerSpinButtonPart: {
428 bool isUpButton = subPart == SpinButtonUp;
429 state = isUpButton ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
430 if (!isEnabled(o) || isReadOnlyControl(o))
431 state |= DFCS_INACTIVE;
432 else if (isPressed(o) && isUpButton == isSpinUpButtonPartPressed(o))
433 state |= DFCS_PUSHED;
434 else if (isHovered(o) && isUpButton == isSpinUpButtonPartHovered(o))
444 unsigned RenderThemeWin::determineState(RenderObject* o)
446 unsigned result = TS_NORMAL;
447 ControlPart appearance = o->style()->appearance();
449 result = TS_DISABLED;
450 else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance))
451 result = TFS_READONLY; // Readonly is supported on textfields.
452 else if (isPressed(o)) // Active overrides hover and focused.
454 else if (supportsFocus(appearance) && isFocused(o))
456 else if (isHovered(o))
459 result += 4; // 4 unchecked states, 4 checked states.
460 else if (isIndeterminate(o) && appearance == CheckboxPart)
465 unsigned RenderThemeWin::determineSliderThumbState(RenderObject* o)
467 unsigned result = TUS_NORMAL;
469 result = TUS_DISABLED;
470 else if (supportsFocus(o->style()->appearance()) && isFocused(o))
471 result = TUS_FOCUSED;
472 else if (isPressed(o))
473 result = TUS_PRESSED;
474 else if (isHovered(o))
479 unsigned RenderThemeWin::determineButtonState(RenderObject* o)
481 unsigned result = PBS_NORMAL;
483 result = PBS_DISABLED;
484 else if (isPressed(o))
485 result = PBS_PRESSED;
486 else if (supportsFocus(o->style()->appearance()) && isFocused(o))
487 result = PBS_DEFAULTED;
488 else if (isHovered(o))
490 else if (isDefault(o))
491 result = PBS_DEFAULTED;
495 unsigned RenderThemeWin::determineSpinButtonState(RenderObject* o, ControlSubPart subPart)
497 bool isUpButton = subPart == SpinButtonUp;
498 unsigned result = isUpButton ? UPS_NORMAL : DNS_NORMAL;
499 if (!isEnabled(o) || isReadOnlyControl(o))
500 result = isUpButton ? UPS_DISABLED : DNS_DISABLED;
501 else if (isPressed(o) && isUpButton == isSpinUpButtonPartPressed(o))
502 result = isUpButton ? UPS_PRESSED : DNS_PRESSED;
503 else if (isHovered(o) && isUpButton == isSpinUpButtonPartHovered(o))
504 result = isUpButton ? UPS_HOT : DNS_HOT;
508 ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o, ControlSubPart subPart)
511 switch (o->style()->appearance()) {
514 case DefaultButtonPart:
517 result.m_part = DFC_BUTTON;
518 result.m_state = determineClassicState(o);
521 result.m_part = DFC_SCROLL;
522 result.m_state = determineClassicState(o);
524 case SearchFieldPart:
527 result.m_part = TFP_TEXTFIELD;
528 result.m_state = determineState(o);
530 case SliderHorizontalPart:
531 result.m_part = TKP_TRACK;
532 result.m_state = TS_NORMAL;
534 case SliderVerticalPart:
535 result.m_part = TKP_TRACKVERT;
536 result.m_state = TS_NORMAL;
538 case SliderThumbHorizontalPart:
539 result.m_part = TKP_THUMBBOTTOM;
540 result.m_state = determineSliderThumbState(o);
542 case SliderThumbVerticalPart:
543 result.m_part = TKP_THUMBRIGHT;
544 result.m_state = determineSliderThumbState(o);
546 case InnerSpinButtonPart:
547 result.m_part = DFC_SCROLL;
548 result.m_state = determineClassicState(o, subPart);
556 ThemeData RenderThemeWin::getThemeData(RenderObject* o, ControlSubPart subPart)
559 return getClassicThemeData(o, subPart);
562 switch (o->style()->appearance()) {
565 case DefaultButtonPart:
566 result.m_part = BP_BUTTON;
567 result.m_state = determineButtonState(o);
570 result.m_part = BP_CHECKBOX;
571 result.m_state = determineState(o);
574 case MenulistButtonPart: {
575 const bool isVistaOrLater = (windowsVersion() >= WindowsVista);
576 result.m_part = isVistaOrLater ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON;
577 if (isVistaOrLater && documentIsInApplicationChromeMode(o->document())) {
578 // The "readonly" look we use in application chrome mode
579 // only uses a "normal" look for the drop down button.
580 result.m_state = TS_NORMAL;
582 result.m_state = determineState(o);
586 result.m_part = BP_RADIO;
587 result.m_state = determineState(o);
589 case SearchFieldPart:
592 result.m_part = (windowsVersion() >= WindowsVista) ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD;
593 result.m_state = determineState(o);
595 case SliderHorizontalPart:
596 result.m_part = TKP_TRACK;
597 result.m_state = TS_NORMAL;
599 case SliderVerticalPart:
600 result.m_part = TKP_TRACKVERT;
601 result.m_state = TS_NORMAL;
603 case SliderThumbHorizontalPart:
604 result.m_part = TKP_THUMBBOTTOM;
605 result.m_state = determineSliderThumbState(o);
607 case SliderThumbVerticalPart:
608 result.m_part = TKP_THUMBRIGHT;
609 result.m_state = determineSliderThumbState(o);
611 case InnerSpinButtonPart:
612 result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
613 result.m_state = determineSpinButtonState(o, subPart);
620 static void drawControl(GraphicsContext* context, RenderObject* o, HANDLE theme, const ThemeData& themeData, const IntRect& r)
622 bool alphaBlend = false;
624 alphaBlend = IsThemeBackgroundPartiallyTransparent(theme, themeData.m_part, themeData.m_state);
625 LocalWindowsContext windowsContext(context, r, alphaBlend);
628 DrawThemeBackground(theme, windowsContext.hdc(), themeData.m_part, themeData.m_state, &widgetRect, 0);
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));
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 HBITMAP patternBmp = ::CreateBitmap(8, 8, 1, 1, patternBits);
649 HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patternBmp);
650 COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(COLOR_3DFACE));
651 COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
653 ::GetViewportOrgEx(hdc, &p);
654 ::SetBrushOrgEx(hdc, p.x + widgetRect.left, p.y + widgetRect.top, NULL);
655 HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush);
656 ::FillRect(hdc, &widgetRect, brush);
657 ::SetTextColor(hdc, oldForeColor);
658 ::SetBkColor(hdc, oldBackColor);
659 ::SelectObject(hdc, oldBrush);
660 ::DeleteObject(brush);
662 ::FillRect(hdc, &widgetRect, (HBRUSH)COLOR_3DHILIGHT);
663 ::DeleteObject(patternBmp);
666 // Push buttons, buttons, checkboxes and radios, and the dropdown arrow in menulists.
667 if (o->style()->appearance() == DefaultButtonPart) {
668 HBRUSH brush = ::GetSysColorBrush(COLOR_3DDKSHADOW);
669 ::FrameRect(hdc, &widgetRect, brush);
670 ::InflateRect(&widgetRect, -1, -1);
671 ::DrawEdge(hdc, &widgetRect, BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE);
673 ::DrawFrameControl(hdc, &widgetRect, themeData.m_part, themeData.m_state);
679 if (!alphaBlend && !context->isInTransparencyLayer())
680 DIBPixelData::setRGBABitmapAlpha(windowsContext.hdc(), r, 255);
684 bool RenderThemeWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
686 drawControl(i.context, o, buttonTheme(), getThemeData(o), r);
690 void RenderThemeWin::adjustInnerSpinButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
692 int width = ::GetSystemMetrics(SM_CXVSCROLL);
694 width = 17; // Vista's default.
695 style->setWidth(Length(width, Fixed));
696 style->setMinWidth(Length(width, Fixed));
699 bool RenderThemeWin::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
701 // We split the specified rectangle into two vertically. We can't draw a
702 // spin button of which height is less than 2px.
706 upRect.setHeight(r.height() / 2);
708 downRect.setY(upRect.maxY());
709 downRect.setHeight(r.height() - upRect.height());
710 drawControl(i.context, o, spinButtonTheme(), getThemeData(o, SpinButtonUp), upRect);
711 drawControl(i.context, o, spinButtonTheme(), getThemeData(o, SpinButtonDown), downRect);
715 void RenderThemeWin::setCheckboxSize(RenderStyle* style) const
717 // If the width and height are both specified, then we have nothing to do.
718 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
721 // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox.
722 // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
723 // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
725 if (style->width().isIntrinsicOrAuto())
726 style->setWidth(Length(13, Fixed));
727 if (style->height().isAuto())
728 style->setHeight(Length(13, Fixed));
731 bool RenderThemeWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
733 drawControl(i.context, o, textFieldTheme(), getThemeData(o), r);
737 bool RenderThemeWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
741 if (haveTheme && (windowsVersion() >= WindowsVista)) {
742 theme = menuListTheme();
743 if (documentIsInApplicationChromeMode(o->document()))
748 theme = textFieldTheme();
749 part = TFP_TEXTFIELD;
752 drawControl(i.context, o, theme, ThemeData(part, determineState(o)), r);
754 return paintMenuListButton(o, i, r);
757 void RenderThemeWin::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
759 style->resetBorder();
760 adjustMenuListButtonStyle(styleResolver, style, e);
763 void RenderThemeWin::adjustMenuListButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
765 // These are the paddings needed to place the text correctly in the <select> box
766 const int dropDownBoxPaddingTop = 2;
767 const int dropDownBoxPaddingRight = style->direction() == LTR ? 4 + dropDownButtonWidth : 4;
768 const int dropDownBoxPaddingBottom = 2;
769 const int dropDownBoxPaddingLeft = style->direction() == LTR ? 4 : 4 + dropDownButtonWidth;
770 // The <select> box must be at least 12px high for the button to render nicely on Windows
771 const int dropDownBoxMinHeight = 12;
773 // Position the text correctly within the select box and make the box wide enough to fit the dropdown button
774 style->setPaddingTop(Length(dropDownBoxPaddingTop, Fixed));
775 style->setPaddingRight(Length(dropDownBoxPaddingRight, Fixed));
776 style->setPaddingBottom(Length(dropDownBoxPaddingBottom, Fixed));
777 style->setPaddingLeft(Length(dropDownBoxPaddingLeft, Fixed));
779 // Height is locked to auto
780 style->setHeight(Length(Auto));
782 // Calculate our min-height
783 int minHeight = style->fontMetrics().height();
784 minHeight = max(minHeight, dropDownBoxMinHeight);
786 style->setMinHeight(Length(minHeight, Fixed));
788 // White-space is locked to pre
789 style->setWhiteSpace(PRE);
792 bool RenderThemeWin::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
794 // FIXME: Don't make hardcoded assumptions about the thickness of the textfield border.
795 int borderThickness = haveTheme ? 1 : 2;
797 // Paint the dropdown button on the inner edge of the text field,
798 // leaving space for the text field's 1px border
799 IntRect buttonRect(r);
800 buttonRect.inflate(-borderThickness);
801 if (o->style()->direction() == LTR)
802 buttonRect.setX(buttonRect.maxX() - dropDownButtonWidth);
803 buttonRect.setWidth(dropDownButtonWidth);
805 if ((windowsVersion() >= WindowsVista)) {
806 // Outset the top, right, and bottom borders of the button so that they coincide with the <select>'s border.
807 buttonRect.setY(buttonRect.y() - vistaMenuListButtonOutset);
808 buttonRect.setHeight(buttonRect.height() + 2 * vistaMenuListButtonOutset);
809 buttonRect.setWidth(buttonRect.width() + vistaMenuListButtonOutset);
812 drawControl(i.context, o, menuListTheme(), getThemeData(o), buttonRect);
817 const int trackWidth = 4;
819 bool RenderThemeWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
823 if (o->style()->appearance() == SliderHorizontalPart) {
824 bounds.setHeight(trackWidth);
825 bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
826 } else if (o->style()->appearance() == SliderVerticalPart) {
827 bounds.setWidth(trackWidth);
828 bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
831 drawControl(i.context, o, sliderTheme(), getThemeData(o), bounds);
835 bool RenderThemeWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
837 drawControl(i.context, o, sliderTheme(), getThemeData(o), r);
841 const int sliderThumbWidth = 7;
842 const int sliderThumbHeight = 15;
844 void RenderThemeWin::adjustSliderThumbSize(RenderStyle* style, Element*) const
846 ControlPart part = style->appearance();
847 if (part == SliderThumbVerticalPart) {
848 style->setWidth(Length(sliderThumbHeight, Fixed));
849 style->setHeight(Length(sliderThumbWidth, Fixed));
850 } else if (part == SliderThumbHorizontalPart) {
851 style->setWidth(Length(sliderThumbWidth, Fixed));
852 style->setHeight(Length(sliderThumbHeight, Fixed));
855 else if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart)
856 RenderMediaControls::adjustMediaSliderThumbSize(style);
860 bool RenderThemeWin::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
862 return paintTextField(o, i, r);
865 void RenderThemeWin::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
867 // Override paddingSize to match AppKit text positioning.
868 const int padding = 1;
869 style->setPaddingLeft(Length(padding, Fixed));
870 style->setPaddingRight(Length(padding, Fixed));
871 style->setPaddingTop(Length(padding, Fixed));
872 style->setPaddingBottom(Length(padding, Fixed));
873 if (e && e->focused() && e->document()->frame()->selection()->isFocusedAndActive())
874 style->setOutlineOffset(-2);
877 bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
881 if (!o->parent() || !o->parent()->isBox())
884 RenderBox* parentRenderBox = toRenderBox(o->parent());
886 IntRect parentBox = parentRenderBox->absoluteContentBox();
888 // Make sure the scaled button stays square and will fit in its parent's box
889 bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height())));
890 bounds.setWidth(bounds.height());
892 // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will
893 // be one pixel closer to the bottom of the field. This tends to look better with the text.
894 bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
896 static Image* cancelImage = Image::loadPlatformResource("searchCancel").leakRef();
897 static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").leakRef();
898 paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, o->style()->colorSpace(), bounds);
902 void RenderThemeWin::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
904 // Scale the button size based on the font size
905 float fontScale = style->fontSize() / defaultControlFontPixelSize;
906 int cancelButtonSize = lroundf(min(max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
907 style->setWidth(Length(cancelButtonSize, Fixed));
908 style->setHeight(Length(cancelButtonSize, Fixed));
911 void RenderThemeWin::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
913 IntSize emptySize(1, 11);
914 style->setWidth(Length(emptySize.width(), Fixed));
915 style->setHeight(Length(emptySize.height(), Fixed));
918 void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
920 // Scale the decoration size based on the font size
921 float fontScale = style->fontSize() / defaultControlFontPixelSize;
922 int magnifierSize = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
923 maxSearchFieldResultsDecorationSize));
924 style->setWidth(Length(magnifierSize, Fixed));
925 style->setHeight(Length(magnifierSize, Fixed));
928 bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
932 if (!o->parent() || !o->parent()->isBox())
935 RenderBox* parentRenderBox = toRenderBox(o->parent());
936 IntRect parentBox = parentRenderBox->absoluteContentBox();
938 // Make sure the scaled decoration stays square and will fit in its parent's box
939 bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height())));
940 bounds.setWidth(bounds.height());
942 // Center the decoration vertically. Round up though, so if it has to be one pixel off-center, it will
943 // be one pixel closer to the bottom of the field. This tends to look better with the text.
944 bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
946 static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").leakRef();
947 paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
951 void RenderThemeWin::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
953 // Scale the button size based on the font size
954 float fontScale = style->fontSize() / defaultControlFontPixelSize;
955 int magnifierHeight = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
956 maxSearchFieldResultsDecorationSize));
957 int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
958 style->setWidth(Length(magnifierWidth, Fixed));
959 style->setHeight(Length(magnifierHeight, Fixed));
962 bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
968 if (!o->parent() || !o->parent()->isBox())
971 RenderBox* parentRenderBox = toRenderBox(o->parent());
972 IntRect parentBox = parentRenderBox->absoluteContentBox();
974 // Make sure the scaled decoration will fit in its parent's box
975 bounds.setHeight(min(parentBox.height(), bounds.height()));
976 bounds.setWidth(min<int>(parentBox.width(), bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize));
978 // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will
979 // be one pixel closer to the bottom of the field. This tends to look better with the text.
980 bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
982 static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").leakRef();
983 paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
987 // Map a CSSValue* system color to an index understood by GetSysColor
988 static int cssValueIdToSysColorIndex(int cssValueId)
990 switch (cssValueId) {
991 case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
992 case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
993 case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
994 case CSSValueBackground: return COLOR_BACKGROUND;
995 case CSSValueButtonface: return COLOR_BTNFACE;
996 case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
997 case CSSValueButtonshadow: return COLOR_BTNSHADOW;
998 case CSSValueButtontext: return COLOR_BTNTEXT;
999 case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
1000 case CSSValueGraytext: return COLOR_GRAYTEXT;
1001 case CSSValueHighlight: return COLOR_HIGHLIGHT;
1002 case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
1003 case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
1004 case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
1005 case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
1006 case CSSValueInfobackground: return COLOR_INFOBK;
1007 case CSSValueInfotext: return COLOR_INFOTEXT;
1008 case CSSValueMenu: return COLOR_MENU;
1009 case CSSValueMenutext: return COLOR_MENUTEXT;
1010 case CSSValueScrollbar: return COLOR_SCROLLBAR;
1011 case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
1012 case CSSValueThreedface: return COLOR_3DFACE;
1013 case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
1014 case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
1015 case CSSValueThreedshadow: return COLOR_3DSHADOW;
1016 case CSSValueWindow: return COLOR_WINDOW;
1017 case CSSValueWindowframe: return COLOR_WINDOWFRAME;
1018 case CSSValueWindowtext: return COLOR_WINDOWTEXT;
1019 default: return -1; // Unsupported CSSValue
1023 Color RenderThemeWin::systemColor(int cssValueId) const
1025 int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
1026 if (sysColorIndex == -1)
1027 return RenderTheme::systemColor(cssValueId);
1029 COLORREF color = GetSysColor(sysColorIndex);
1030 return Color(GetRValue(color), GetGValue(color), GetBValue(color));
1035 String RenderThemeWin::extraMediaControlsStyleSheet()
1037 return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet));
1040 #if ENABLE(FULLSCREEN_API)
1041 String RenderThemeWin::extraFullScreenStyleSheet()
1043 return String(fullscreenQuickTimeUserAgentStyleSheet, sizeof(fullscreenQuickTimeUserAgentStyleSheet));
1047 bool RenderThemeWin::supportsClosedCaptioning() const
1049 // We rely on QuickTime to render captions so only enable the button for a video element.
1050 #if SAFARI_THEME_VERSION >= 4
1057 bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1059 return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, o, paintInfo, r);
1062 bool RenderThemeWin::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1064 return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r);
1067 bool RenderThemeWin::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1069 return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r);
1072 bool RenderThemeWin::paintMediaRewindButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1074 return RenderMediaControls::paintMediaControlsPart(MediaRewindButton, o, paintInfo, r);
1077 bool RenderThemeWin::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1079 return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r);
1082 bool RenderThemeWin::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1084 return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r);
1087 bool RenderThemeWin::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1089 return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r);
1092 bool RenderThemeWin::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1094 return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r);
1097 bool RenderThemeWin::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1099 return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
1102 bool RenderThemeWin::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1104 return RenderMediaControls::paintMediaControlsPart(MediaTimelineContainer, o, paintInfo, r);
1107 bool RenderThemeWin::paintMediaVolumeSliderContainer(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1109 return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderContainer, o, paintInfo, r);
1112 bool RenderThemeWin::paintMediaVolumeSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1114 return RenderMediaControls::paintMediaControlsPart(MediaVolumeSlider, o, paintInfo, r);
1117 bool RenderThemeWin::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1119 return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, o, paintInfo, r);
1122 IntPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const
1124 return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size);