2 * Copyright (C) 2007, 2008 Apple Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include "RenderThemeSafari.h"
24 #ifdef USE_SAFARI_THEME
26 #include "CSSValueKeywords.h"
29 #include "FrameView.h"
30 #include "GraphicsContext.h"
31 #include "HTMLInputElement.h"
32 #include "HTMLMediaElement.h"
33 #include "HTMLNames.h"
34 #include "RenderSlider.h"
35 #include "RenderView.h"
36 #include "RetainPtr.h"
37 #include "SoftLinking.h"
38 #include "cssstyleselector.h"
39 #include <CoreGraphics/CoreGraphics.h>
43 // FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeMac.
47 using namespace HTMLNames;
48 using namespace SafariTheme;
66 static RenderThemeSafari safariTheme;
70 #if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME)
71 SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
73 SOFT_LINK_LIBRARY(SafariTheme)
76 SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state))
77 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
78 SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value))
81 ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const
83 ThemeControlState result = 0;
84 if (isEnabled(o) && !isReadOnlyControl(o))
85 result |= SafariTheme::EnabledState;
87 result |= SafariTheme::PressedState;
89 result |= SafariTheme::CheckedState;
90 if (isIndeterminate(o))
91 result |= SafariTheme::IndeterminateCheckedState;
93 result |= SafariTheme::FocusedState;
97 static NSControlSize controlSizeFromRect(const IntRect& rect, const IntSize sizes[])
99 if (sizes[NSRegularControlSize].height() == rect.height())
100 return NSRegularControlSize;
101 else if (sizes[NSMiniControlSize].height() == rect.height())
102 return NSMiniControlSize;
104 return NSSmallControlSize;
107 RenderThemeSafari::RenderThemeSafari()
111 RenderThemeSafari::~RenderThemeSafari()
115 Color RenderThemeSafari::platformActiveSelectionBackgroundColor() const
117 return Color(181, 213, 255);
120 Color RenderThemeSafari::platformInactiveSelectionBackgroundColor() const
122 return Color(212, 212, 212);
125 Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const
127 // FIXME: This should probably just be a darker version of the platformActiveSelectionBackgroundColor
128 return Color(56, 117, 215);
131 static float systemFontSizeForControlSize(NSControlSize controlSize)
133 static float sizes[] = { 13.0f, 11.0f, 9.0f };
135 return sizes[controlSize];
138 void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription) const
140 static FontDescription systemFont;
141 static FontDescription smallSystemFont;
142 static FontDescription menuFont;
143 static FontDescription labelFont;
144 static FontDescription miniControlFont;
145 static FontDescription smallControlFont;
146 static FontDescription controlFont;
148 FontDescription* cachedDesc;
151 case CSS_VAL_SMALL_CAPTION:
152 cachedDesc = &smallSystemFont;
153 if (!smallSystemFont.isAbsoluteSize())
154 fontSize = systemFontSizeForControlSize(NSSmallControlSize);
157 cachedDesc = &menuFont;
158 if (!menuFont.isAbsoluteSize())
159 fontSize = systemFontSizeForControlSize(NSRegularControlSize);
161 case CSS_VAL_STATUS_BAR:
162 cachedDesc = &labelFont;
163 if (!labelFont.isAbsoluteSize())
166 case CSS_VAL__WEBKIT_MINI_CONTROL:
167 cachedDesc = &miniControlFont;
168 if (!miniControlFont.isAbsoluteSize())
169 fontSize = systemFontSizeForControlSize(NSMiniControlSize);
171 case CSS_VAL__WEBKIT_SMALL_CONTROL:
172 cachedDesc = &smallControlFont;
173 if (!smallControlFont.isAbsoluteSize())
174 fontSize = systemFontSizeForControlSize(NSSmallControlSize);
176 case CSS_VAL__WEBKIT_CONTROL:
177 cachedDesc = &controlFont;
178 if (!controlFont.isAbsoluteSize())
179 fontSize = systemFontSizeForControlSize(NSRegularControlSize);
182 cachedDesc = &systemFont;
183 if (!systemFont.isAbsoluteSize())
188 cachedDesc->setIsAbsoluteSize(true);
189 cachedDesc->setGenericFamily(FontDescription::NoFamily);
190 cachedDesc->firstFamily().setFamily("Lucida Grande");
191 cachedDesc->setSpecifiedSize(fontSize);
192 cachedDesc->setBold(false);
193 cachedDesc->setItalic(false);
195 fontDescription = *cachedDesc;
198 bool RenderThemeSafari::isControlStyled(const RenderStyle* style, const BorderData& border,
199 const BackgroundLayer& background, const Color& backgroundColor) const
201 // If we didn't find SafariTheme.dll we won't be able to paint any themed controls.
202 if (!SafariThemeLibrary())
205 if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance || style->appearance() == ListboxAppearance)
206 return style->border() != border;
207 #if !defined(SAFARI_THEME_VERSION) || SAFARI_THEME_VERSION < 2
208 if (style->appearance() == MediaFullscreenButtonAppearance || style->appearance() == MediaMuteButtonAppearance ||
209 style->appearance() == MediaPlayButtonAppearance || style->appearance() == MediaSeekBackButtonAppearance ||
210 style->appearance() == MediaSeekForwardButtonAppearance || style->appearance() == MediaSliderAppearance ||
211 style->appearance() == MediaSliderThumbAppearance)
214 return RenderTheme::isControlStyled(style, border, background, backgroundColor);
217 void RenderThemeSafari::adjustRepaintRect(const RenderObject* o, IntRect& r)
219 NSControlSize controlSize = controlSizeForFont(o->style());
221 switch (o->style()->appearance()) {
222 case CheckboxAppearance: {
223 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
224 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
225 r = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
228 case RadioAppearance: {
229 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
230 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
231 r = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
234 case PushButtonAppearance:
235 case ButtonAppearance: {
236 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
237 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
238 if (r.height() <= buttonSizes()[NSRegularControlSize].height())
239 r = inflateRect(r, buttonSizes()[controlSize], buttonMargins(controlSize));
242 case MenulistAppearance: {
243 r = inflateRect(r, popupButtonSizes()[controlSize], popupButtonMargins(controlSize));
251 IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, const int* margins) const
253 // Only do the inflation if the available width/height are too small. Otherwise try to
254 // fit the glow/check space into the available box's width/height.
255 int widthDelta = r.width() - (size.width() + margins[leftMargin] + margins[rightMargin]);
256 int heightDelta = r.height() - (size.height() + margins[topMargin] + margins[bottomMargin]);
258 if (widthDelta < 0) {
259 result.setX(result.x() - margins[leftMargin]);
260 result.setWidth(result.width() - widthDelta);
262 if (heightDelta < 0) {
263 result.setY(result.y() - margins[topMargin]);
264 result.setHeight(result.height() - heightDelta);
269 short RenderThemeSafari::baselinePosition(const RenderObject* o) const
271 if (o->style()->appearance() == CheckboxAppearance || o->style()->appearance() == RadioAppearance)
272 return o->marginTop() + o->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
273 return RenderTheme::baselinePosition(o);
276 bool RenderThemeSafari::controlSupportsTints(const RenderObject* o) const
281 // Checkboxes only have tint when checked.
282 if (o->style()->appearance() == CheckboxAppearance)
285 // For now assume other controls have tint if enabled.
289 NSControlSize RenderThemeSafari::controlSizeForFont(RenderStyle* style) const
291 int fontSize = style->fontSize();
293 return NSRegularControlSize;
295 return NSSmallControlSize;
296 return NSMiniControlSize;
299 void RenderThemeSafari::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize)
302 if (minSize.width() >= sizes[NSRegularControlSize].width() &&
303 minSize.height() >= sizes[NSRegularControlSize].height())
304 size = NSRegularControlSize;
305 else if (minSize.width() >= sizes[NSSmallControlSize].width() &&
306 minSize.height() >= sizes[NSSmallControlSize].height())
307 size = NSSmallControlSize;
309 size = NSMiniControlSize;
310 if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
311 [cell setControlSize:size];
314 IntSize RenderThemeSafari::sizeForFont(RenderStyle* style, const IntSize* sizes) const
316 return sizes[controlSizeForFont(style)];
319 IntSize RenderThemeSafari::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
321 return sizes[controlSizeForSystemFont(style)];
324 void RenderThemeSafari::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
326 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
327 IntSize size = sizeForFont(style, sizes);
328 if (style->width().isIntrinsicOrAuto() && size.width() > 0)
329 style->setWidth(Length(size.width(), Fixed));
330 if (style->height().isAuto() && size.height() > 0)
331 style->setHeight(Length(size.height(), Fixed));
334 void RenderThemeSafari::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const
336 FontDescription fontDescription;
337 fontDescription.setIsAbsoluteSize(true);
338 fontDescription.setGenericFamily(FontDescription::SerifFamily);
340 float fontSize = systemFontSizeForControlSize(controlSize);
341 fontDescription.firstFamily().setFamily("Lucida Grande");
342 fontDescription.setComputedSize(fontSize);
343 fontDescription.setSpecifiedSize(fontSize);
346 style->setLineHeight(RenderStyle::initialLineHeight());
348 if (style->setFontDescription(fontDescription))
349 style->font().update(selector->fontSelector());
352 NSControlSize RenderThemeSafari::controlSizeForSystemFont(RenderStyle* style) const
354 int fontSize = style->fontSize();
356 return NSRegularControlSize;
358 return NSSmallControlSize;
359 return NSMiniControlSize;
362 bool RenderThemeSafari::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
364 ASSERT(SafariThemeLibrary());
366 NSControlSize controlSize = controlSizeForFont(o->style());
368 IntRect inflatedRect = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
369 paintThemePart(CheckboxPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
374 const IntSize* RenderThemeSafari::checkboxSizes() const
376 static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
380 const int* RenderThemeSafari::checkboxMargins(NSControlSize controlSize) const
382 static const int margins[3][4] =
388 return margins[controlSize];
391 void RenderThemeSafari::setCheckboxSize(RenderStyle* style) const
393 // If the width and height are both specified, then we have nothing to do.
394 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
397 // Use the font size to determine the intrinsic width of the control.
398 setSizeFromFont(style, checkboxSizes());
401 bool RenderThemeSafari::paintRadio(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
403 ASSERT(SafariThemeLibrary());
405 NSControlSize controlSize = controlSizeForFont(o->style());
407 IntRect inflatedRect = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
408 paintThemePart(RadioButtonPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
413 const IntSize* RenderThemeSafari::radioSizes() const
415 static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
419 const int* RenderThemeSafari::radioMargins(NSControlSize controlSize) const
421 static const int margins[3][4] =
427 return margins[controlSize];
430 void RenderThemeSafari::setRadioSize(RenderStyle* style) const
432 // If the width and height are both specified, then we have nothing to do.
433 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
436 // Use the font size to determine the intrinsic width of the control.
437 setSizeFromFont(style, radioSizes());
440 void RenderThemeSafari::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const
442 // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large
443 // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
444 // by definition constrained, since we select mini only for small cramped environments.
445 // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent
447 const int padding = 8;
448 style->setPaddingLeft(Length(padding, Fixed));
449 style->setPaddingRight(Length(padding, Fixed));
450 style->setPaddingTop(Length(0, Fixed));
451 style->setPaddingBottom(Length(0, Fixed));
454 void RenderThemeSafari::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
456 // There are three appearance constants for buttons.
457 // (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow
458 // custom fonts or colors. <input>s use this constant. This button will allow custom colors and font weights/variants but won't
460 // (2) square-button is the constant for the square button. This button will allow custom fonts and colors and will scale vertically.
461 // (3) Button is the constant that means "pick the best button as appropriate." <button>s use this constant. This button will
462 // also scale vertically and allow custom fonts and colors. It will attempt to use Aqua if possible and will make this determination
463 // solely on the rectangle of the control.
465 // Determine our control size based off our font.
466 NSControlSize controlSize = controlSizeForFont(style);
468 if (style->appearance() == PushButtonAppearance) {
470 style->resetBorder();
472 // Height is locked to auto.
473 style->setHeight(Length(Auto));
475 // White-space is locked to pre
476 style->setWhiteSpace(PRE);
478 // Set the button's vertical size.
479 setButtonSize(style);
481 // Add in the padding that we'd like to use.
482 setButtonPaddingFromControlSize(style, controlSize);
484 // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out
485 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
486 // system font for the control size instead.
487 setFontFromControlSize(selector, style, controlSize);
489 // Set a min-height so that we can't get smaller than the mini button.
490 style->setMinHeight(Length(15, Fixed));
492 // Reset the top and bottom borders.
493 style->resetBorderTop();
494 style->resetBorderBottom();
498 const IntSize* RenderThemeSafari::buttonSizes() const
500 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
504 const int* RenderThemeSafari::buttonMargins(NSControlSize controlSize) const
506 static const int margins[3][4] =
512 return margins[controlSize];
515 void RenderThemeSafari::setButtonSize(RenderStyle* style) const
517 // If the width and height are both specified, then we have nothing to do.
518 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
521 // Use the font size to determine the intrinsic width of the control.
522 setSizeFromFont(style, buttonSizes());
525 bool RenderThemeSafari::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
527 ASSERT(SafariThemeLibrary());
529 // We inflate the rect as needed to account for padding included in the cell to accommodate the button
530 // shadow. We don't consider this part of the bounds of the control in WebKit.
532 NSControlSize controlSize = controlSizeFromRect(r, buttonSizes());
533 IntRect inflatedRect = r;
536 if (r.height() <= buttonSizes()[NSRegularControlSize].height()) {
538 part = PushButtonPart;
540 IntSize size = buttonSizes()[controlSize];
541 size.setWidth(r.width());
543 // Center the button within the available space.
544 if (inflatedRect.height() > size.height()) {
545 inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2);
546 inflatedRect.setHeight(size.height());
549 // Now inflate it to account for the shadow.
550 inflatedRect = inflateRect(inflatedRect, size, buttonMargins(controlSize));
552 part = SquareButtonPart;
554 paintThemePart(part, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
558 bool RenderThemeSafari::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
560 ASSERT(SafariThemeLibrary());
562 paintThemePart(TextFieldPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
566 void RenderThemeSafari::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
570 bool RenderThemeSafari::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
572 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 1
573 ASSERT(SafariThemeLibrary());
575 if (paintInfo.context->paintingDisabled())
578 paintThemePart(CapsLockPart, paintInfo.context->platformContext(), r, (NSControlSize)0, (ThemeControlState)0);
586 bool RenderThemeSafari::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
588 ASSERT(SafariThemeLibrary());
590 paintThemePart(TextAreaPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
594 void RenderThemeSafari::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const
598 const int* RenderThemeSafari::popupButtonMargins(NSControlSize size) const
600 static const int margins[3][4] =
606 return margins[size];
609 const IntSize* RenderThemeSafari::popupButtonSizes() const
611 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
615 const int* RenderThemeSafari::popupButtonPadding(NSControlSize size) const
617 static const int padding[3][4] =
623 return padding[size];
626 bool RenderThemeSafari::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& info, const IntRect& r)
628 ASSERT(SafariThemeLibrary());
630 NSControlSize controlSize = controlSizeFromRect(r, popupButtonSizes());
631 IntRect inflatedRect = r;
632 IntSize size = popupButtonSizes()[controlSize];
633 size.setWidth(r.width());
635 // Now inflate it to account for the shadow.
636 if (r.width() >= minimumMenuListSize(o->style()))
637 inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(controlSize));
639 paintThemePart(DropDownButtonPart, info.context->platformContext(), inflatedRect, controlSize, determineState(o));
644 const float baseFontSize = 11.0f;
645 const float baseArrowHeight = 5.0f;
646 const float baseArrowWidth = 7.0f;
647 const int arrowPaddingLeft = 5;
648 const int arrowPaddingRight = 5;
649 const int paddingBeforeSeparator = 4;
650 const int baseBorderRadius = 5;
651 const int styledPopupPaddingLeft = 8;
652 const int styledPopupPaddingTop = 1;
653 const int styledPopupPaddingBottom = 2;
655 static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
657 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
658 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
661 for (i = 0; i < 4; i++)
662 outData[i] = (1.0f - a) * dark[i] + a * light[i];
665 static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
667 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
668 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
671 for (i = 0; i < 4; i++)
672 outData[i] = (1.0f - a) * dark[i] + a * light[i];
675 static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
677 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
678 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
681 for (i = 0; i < 4; i++)
682 outData[i] = (1.0f - a) * dark[i] + a * light[i];
685 static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
687 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
688 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
691 for (i = 0; i < 4; i++)
692 outData[i] = (1.0f - a) * dark[i] + a * light[i];
695 void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
697 CGContextRef context = paintInfo.context->platformContext();
699 paintInfo.context->save();
701 int radius = o->style()->borderTopLeftRadius().width();
703 RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
705 FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
706 struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
707 RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
708 RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false));
710 FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
711 struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
712 RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
713 RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false));
715 struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
716 RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
717 RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false));
719 RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
721 RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false));
722 paintInfo.context->save();
723 CGContextClipToRect(context, r);
724 paintInfo.context->addRoundedRectClip(r,
725 o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
726 o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
727 CGContextDrawShading(context, mainShading.get());
728 paintInfo.context->restore();
730 paintInfo.context->save();
731 CGContextClipToRect(context, topGradient);
732 paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient),
733 o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
734 IntSize(), IntSize());
735 CGContextDrawShading(context, topShading.get());
736 paintInfo.context->restore();
738 paintInfo.context->save();
739 CGContextClipToRect(context, bottomGradient);
740 paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient),
741 IntSize(), IntSize(),
742 o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
743 CGContextDrawShading(context, bottomShading.get());
744 paintInfo.context->restore();
746 paintInfo.context->save();
747 CGContextClipToRect(context, r);
748 paintInfo.context->addRoundedRectClip(r,
749 o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
750 o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
751 CGContextDrawShading(context, leftShading.get());
752 CGContextDrawShading(context, rightShading.get());
753 paintInfo.context->restore();
755 paintInfo.context->restore();
758 bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
760 paintInfo.context->save();
762 IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
763 r.y() + o->style()->borderTopWidth(),
764 r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
765 r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
766 // Draw the gradients to give the styled popup menu a button appearance
767 paintMenuListButtonGradients(o, paintInfo, bounds);
769 // Since we actually know the size of the control here, we restrict the font scale to make sure the arrow will fit vertically in the bounds
770 float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / baseArrowHeight);
771 float centerY = bounds.y() + bounds.height() / 2.0f;
772 float arrowHeight = baseArrowHeight * fontScale;
773 float arrowWidth = baseArrowWidth * fontScale;
774 float leftEdge = bounds.right() - arrowPaddingRight - arrowWidth;
776 if (bounds.width() < arrowWidth + arrowPaddingLeft)
779 paintInfo.context->setFillColor(o->style()->color());
780 paintInfo.context->setStrokeColor(NoStroke);
783 arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f);
784 arrow[1] = FloatPoint(leftEdge + arrowWidth, centerY - arrowHeight / 2.0f);
785 arrow[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + arrowHeight / 2.0f);
788 paintInfo.context->drawConvexPolygon(3, arrow, true);
790 Color leftSeparatorColor(0, 0, 0, 40);
791 Color rightSeparatorColor(255, 255, 255, 40);
793 // FIXME: Should the separator thickness and space be scaled up by fontScale?
794 int separatorSpace = 2;
795 int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft); // FIXME: Round?
797 // Draw the separator to the left of the arrows
798 paintInfo.context->setStrokeThickness(1.0f);
799 paintInfo.context->setStrokeStyle(SolidStroke);
800 paintInfo.context->setStrokeColor(leftSeparatorColor);
801 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
802 IntPoint(leftEdgeOfSeparator, bounds.bottom()));
804 paintInfo.context->setStrokeColor(rightSeparatorColor);
805 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
806 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
808 paintInfo.context->restore();
812 void RenderThemeSafari::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
814 NSControlSize controlSize = controlSizeForFont(style);
816 style->resetBorder();
817 style->resetPadding();
819 // Height is locked to auto.
820 style->setHeight(Length(Auto));
822 // White-space is locked to pre
823 style->setWhiteSpace(PRE);
825 // Set the foreground color to black or gray when we have the aqua look.
826 // Cast to RGB32 is to work around a compiler bug.
827 style->setColor(e->isEnabled() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
829 // Set the button's vertical size.
830 setButtonSize(style);
832 // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out
833 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
834 // system font for the control size instead.
835 setFontFromControlSize(selector, style, controlSize);
838 int RenderThemeSafari::popupInternalPaddingLeft(RenderStyle* style) const
840 if (style->appearance() == MenulistAppearance)
841 return popupButtonPadding(controlSizeForFont(style))[leftPadding];
842 if (style->appearance() == MenulistButtonAppearance)
843 return styledPopupPaddingLeft;
847 int RenderThemeSafari::popupInternalPaddingRight(RenderStyle* style) const
849 if (style->appearance() == MenulistAppearance)
850 return popupButtonPadding(controlSizeForFont(style))[rightPadding];
851 if (style->appearance() == MenulistButtonAppearance) {
852 float fontScale = style->fontSize() / baseFontSize;
853 float arrowWidth = baseArrowWidth * fontScale;
854 return static_cast<int>(ceilf(arrowWidth + arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator));
859 int RenderThemeSafari::popupInternalPaddingTop(RenderStyle* style) const
861 if (style->appearance() == MenulistAppearance)
862 return popupButtonPadding(controlSizeForFont(style))[topPadding];
863 if (style->appearance() == MenulistButtonAppearance)
864 return styledPopupPaddingTop;
868 int RenderThemeSafari::popupInternalPaddingBottom(RenderStyle* style) const
870 if (style->appearance() == MenulistAppearance)
871 return popupButtonPadding(controlSizeForFont(style))[bottomPadding];
872 if (style->appearance() == MenulistButtonAppearance)
873 return styledPopupPaddingBottom;
877 void RenderThemeSafari::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
879 float fontScale = style->fontSize() / baseFontSize;
881 style->resetPadding();
882 style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
884 const int minHeight = 15;
885 style->setMinHeight(Length(minHeight, Fixed));
887 style->setLineHeight(RenderStyle::initialLineHeight());
890 const IntSize* RenderThemeSafari::menuListSizes() const
892 static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
896 int RenderThemeSafari::minimumMenuListSize(RenderStyle* style) const
898 return sizeForSystemFont(style, menuListSizes()).width();
901 const int trackWidth = 5;
902 const int trackRadius = 2;
904 bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
908 if (o->style()->appearance() == SliderHorizontalAppearance ||
909 o->style()->appearance() == MediaSliderAppearance) {
910 bounds.setHeight(trackWidth);
911 bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
912 } else if (o->style()->appearance() == SliderVerticalAppearance) {
913 bounds.setWidth(trackWidth);
914 bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
917 CGContextRef context = paintInfo.context->platformContext();
918 RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
920 paintInfo.context->save();
921 CGContextClipToRect(context, bounds);
923 struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
924 RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
925 RetainPtr<CGShadingRef> mainShading;
926 if (o->style()->appearance() == SliderVerticalAppearance)
927 mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false));
929 mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false));
931 IntSize radius(trackRadius, trackRadius);
932 paintInfo.context->addRoundedRectClip(bounds,
935 CGContextDrawShading(context, mainShading.get());
936 paintInfo.context->restore();
941 void RenderThemeSafari::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
943 style->setBoxShadow(0);
946 const float verticalSliderHeightPadding = 0.1f;
948 bool RenderThemeSafari::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
950 ASSERT(SafariThemeLibrary());
952 ASSERT(o->parent()->isSlider());
954 bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode();
955 ThemeControlState state = determineState(o->parent());
956 state &= ~SafariTheme::PressedState;
958 state |= SafariTheme::PressedState;
960 paintThemePart(SliderThumbPart, paintInfo.context->platformContext(), r, NSSmallControlSize, state);
964 const int sliderThumbWidth = 15;
965 const int sliderThumbHeight = 15;
966 const int mediaSliderThumbWidth = 13;
967 const int mediaSliderThumbHeight = 14;
969 void RenderThemeSafari::adjustSliderThumbSize(RenderObject* o) const
971 if (o->style()->appearance() == SliderThumbHorizontalAppearance || o->style()->appearance() == SliderThumbVerticalAppearance) {
972 o->style()->setWidth(Length(sliderThumbWidth, Fixed));
973 o->style()->setHeight(Length(sliderThumbHeight, Fixed));
974 } else if (o->style()->appearance() == MediaSliderThumbAppearance) {
975 o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed));
976 o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed));
981 bool RenderThemeSafari::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
983 ASSERT(SafariThemeLibrary());
985 paintThemePart(SearchFieldPart, paintInfo.context->platformContext(), r, controlSizeFromRect(r, searchFieldSizes()), determineState(o));
989 const IntSize* RenderThemeSafari::searchFieldSizes() const
991 static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 15) };
995 void RenderThemeSafari::setSearchFieldSize(RenderStyle* style) const
997 // If the width and height are both specified, then we have nothing to do.
998 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1001 // Use the font size to determine the intrinsic width of the control.
1002 setSizeFromFont(style, searchFieldSizes());
1005 void RenderThemeSafari::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1008 style->resetBorder();
1009 const short borderWidth = 2;
1010 style->setBorderLeftWidth(borderWidth);
1011 style->setBorderLeftStyle(INSET);
1012 style->setBorderRightWidth(borderWidth);
1013 style->setBorderRightStyle(INSET);
1014 style->setBorderBottomWidth(borderWidth);
1015 style->setBorderBottomStyle(INSET);
1016 style->setBorderTopWidth(borderWidth);
1017 style->setBorderTopStyle(INSET);
1020 style->setHeight(Length(Auto));
1021 setSearchFieldSize(style);
1023 // Override padding size to match AppKit text positioning.
1024 const int padding = 1;
1025 style->setPaddingLeft(Length(padding, Fixed));
1026 style->setPaddingRight(Length(padding, Fixed));
1027 style->setPaddingTop(Length(padding, Fixed));
1028 style->setPaddingBottom(Length(padding, Fixed));
1030 NSControlSize controlSize = controlSizeForFont(style);
1031 setFontFromControlSize(selector, style, controlSize);
1034 bool RenderThemeSafari::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect&)
1036 ASSERT(SafariThemeLibrary());
1038 Node* input = o->node()->shadowAncestorNode();
1040 RenderObject* renderer = input->renderer();
1043 IntRect searchRect = renderer->absoluteBoundingBoxRect();
1045 paintThemePart(SearchFieldCancelButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1049 const IntSize* RenderThemeSafari::cancelButtonSizes() const
1051 static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1055 void RenderThemeSafari::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1057 IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1058 style->setWidth(Length(size.width(), Fixed));
1059 style->setHeight(Length(size.height(), Fixed));
1062 const IntSize* RenderThemeSafari::resultsButtonSizes() const
1064 static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1068 const int emptyResultsOffset = 9;
1069 void RenderThemeSafari::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1071 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1072 style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1073 style->setHeight(Length(size.height(), Fixed));
1076 bool RenderThemeSafari::paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
1081 void RenderThemeSafari::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1083 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1084 style->setWidth(Length(size.width(), Fixed));
1085 style->setHeight(Length(size.height(), Fixed));
1088 bool RenderThemeSafari::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect&)
1090 ASSERT(SafariThemeLibrary());
1092 Node* input = o->node()->shadowAncestorNode();
1094 RenderObject* renderer = input->renderer();
1097 IntRect searchRect = renderer->absoluteBoundingBoxRect();
1099 paintThemePart(SearchFieldResultsDecorationPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1103 const int resultsArrowWidth = 5;
1104 void RenderThemeSafari::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1106 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1107 style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1108 style->setHeight(Length(size.height(), Fixed));
1111 bool RenderThemeSafari::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect&)
1113 ASSERT(SafariThemeLibrary());
1115 Node* input = o->node()->shadowAncestorNode();
1117 RenderObject* renderer = input->renderer();
1120 IntRect searchRect = renderer->absoluteBoundingBoxRect();
1122 paintThemePart(SearchFieldResultsButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1126 bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1128 ASSERT(SafariThemeLibrary());
1130 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1131 paintThemePart(MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
1137 bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1139 ASSERT(SafariThemeLibrary());
1141 Node* node = o->element();
1142 Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1143 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1146 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1150 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1151 paintThemePart(mediaElement->muted() ? MediaUnMuteButtonPart : MediaMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
1157 bool RenderThemeSafari::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1159 ASSERT(SafariThemeLibrary());
1161 Node* node = o->element();
1162 Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1163 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1166 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1170 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1171 paintThemePart(mediaElement->canPlay() ? MediaPlayButtonPart : MediaPauseButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
1177 bool RenderThemeSafari::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1179 ASSERT(SafariThemeLibrary());
1181 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1182 paintThemePart(MediaSeekBackButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
1188 bool RenderThemeSafari::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1190 ASSERT(SafariThemeLibrary());
1192 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1193 paintThemePart(MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
1199 bool RenderThemeSafari::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1201 Node* node = o->element();
1202 Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1203 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1206 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1210 float percentLoaded = 0;
1211 if (MediaPlayer* player = mediaElement->player())
1212 if (player->duration())
1213 percentLoaded = player->maxTimeBuffered() / player->duration();
1215 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1216 STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, percentLoaded);
1221 bool RenderThemeSafari::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1223 ASSERT(SafariThemeLibrary());
1225 #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
1226 paintThemePart(MediaSliderThumbPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
1233 } // namespace WebCore
1235 #endif // defined(USE_SAFARI_THEME)