1/*
2 * Copyright (C) 2007, 2008, 2009, 2013 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., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#include "config.h"
23#include "RenderThemeSafari.h"
24#include "RenderThemeWin.h"
25#include "Settings.h"
26
27#if USE(SAFARI_THEME)
28
29#include "CSSFontSelector.h"
30#include "CSSValueKeywords.h"
31#include "Document.h"
32#include "Element.h"
33#include "Frame.h"
34#include "FrameView.h"
35#include "GraphicsContextCG.h"
36#include "HTMLInputElement.h"
37#include "HTMLMediaElement.h"
38#include "HTMLMeterElement.h"
39#include "HTMLNames.h"
40#include "PaintInfo.h"
41#include "RenderMediaControls.h"
42#include "RenderMeter.h"
43#include "RenderSlider.h"
44#include "RenderView.h"
45#include "SoftLinking.h"
46#include "StyleResolver.h"
47#include <CoreGraphics/CoreGraphics.h>
48#include <wtf/RetainPtr.h>
49
50using std::min;
51
52// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeMac.
53
54namespace WebCore {
55
56using namespace HTMLNames;
57using namespace SafariTheme;
58
59enum {
60    topMargin,
61    rightMargin,
62    bottomMargin,
63    leftMargin
64};
65
66enum {
67    topPadding,
68    rightPadding,
69    bottomPadding,
70    leftPadding
71};
72
73PassRefPtr<RenderTheme> RenderThemeSafari::create()
74{
75    return adoptRef(new RenderThemeSafari);
76}
77
78PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
79{
80    static RenderTheme* safariTheme = RenderThemeSafari::create().leakRef();
81    static RenderTheme* windowsTheme = RenderThemeWin::create().leakRef();
82
83    // FIXME: This is called before Settings has been initialized by WebKit, so will return a
84    // potentially wrong answer the very first time it's called (see
85    // <https://bugs.webkit.org/show_bug.cgi?id=26493>).
86    if (Settings::shouldPaintNativeControls()) {
87        RenderTheme::setCustomFocusRingColor(safariTheme->platformFocusRingColor());
88        return windowsTheme; // keep the reference of one.
89    }
90    return safariTheme; // keep the reference of one.
91}
92
93#ifdef DEBUG_ALL
94SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
95#else
96SOFT_LINK_LIBRARY(SafariTheme)
97#endif
98
99SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state))
100#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
101SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value))
102#endif
103SOFT_LINK_OPTIONAL(SafariTheme, STCopyThemeColor, CGColorRef, APIENTRY, (unsigned color, SafariTheme::ThemeControlState));
104
105static const unsigned stFocusRingColorID = 4;
106
107static const unsigned aquaFocusRingColor = 0xFF7DADD9;
108
109static RGBA32 makeRGBAFromCGColor(CGColorRef color)
110{
111    const CGFloat* components = CGColorGetComponents(color);
112    return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]);
113}
114
115ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const
116{
117    ThemeControlState result = 0;
118    if (isActive(o))
119        result |= SafariTheme::ActiveState;
120    if (isEnabled(o) && !isReadOnlyControl(o))
121        result |= SafariTheme::EnabledState;
122    if (isPressed(o))
123        result |= SafariTheme::PressedState;
124    if (isChecked(o))
125        result |= SafariTheme::CheckedState;
126    if (isIndeterminate(o))
127        result |= SafariTheme::IndeterminateCheckedState;
128    if (isFocused(o))
129        result |= SafariTheme::FocusedState;
130    if (isDefault(o))
131        result |= SafariTheme::DefaultState;
132    return result;
133}
134
135static NSControlSize controlSizeFromRect(const IntRect& rect, const IntSize sizes[])
136{
137    if (sizes[NSRegularControlSize].height() == rect.height())
138        return NSRegularControlSize;
139    else if (sizes[NSMiniControlSize].height() == rect.height())
140        return NSMiniControlSize;
141
142    return NSSmallControlSize;
143}
144
145RenderThemeSafari::RenderThemeSafari()
146{
147}
148
149RenderThemeSafari::~RenderThemeSafari()
150{
151}
152
153Color RenderThemeSafari::platformActiveSelectionBackgroundColor() const
154{
155    return Color(181, 213, 255);
156}
157
158Color RenderThemeSafari::platformInactiveSelectionBackgroundColor() const
159{
160    return Color(212, 212, 212);
161}
162
163Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const
164{
165    // FIXME: This should probably just be a darker version of the platformActiveSelectionBackgroundColor
166    return Color(56, 117, 215);
167}
168
169Color RenderThemeSafari::platformFocusRingColor() const
170{
171    static Color focusRingColor;
172
173    if (!focusRingColor.isValid()) {
174        if (STCopyThemeColorPtr()) {
175            RetainPtr<CGColorRef> color = adoptCF(STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState));
176            focusRingColor = makeRGBAFromCGColor(color.get());
177        }
178        if (!focusRingColor.isValid())
179            focusRingColor = aquaFocusRingColor;
180    }
181
182    return focusRingColor;
183}
184
185static float systemFontSizeForControlSize(NSControlSize controlSize)
186{
187    static float sizes[] = { 13.0f, 11.0f, 9.0f };
188
189    return sizes[controlSize];
190}
191
192void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription) const
193{
194    static FontDescription systemFont;
195    static FontDescription smallSystemFont;
196    static FontDescription menuFont;
197    static FontDescription labelFont;
198    static FontDescription miniControlFont;
199    static FontDescription smallControlFont;
200    static FontDescription controlFont;
201
202    FontDescription* cachedDesc;
203    float fontSize = 0;
204    switch (propId) {
205        case CSSValueSmallCaption:
206            cachedDesc = &smallSystemFont;
207            if (!smallSystemFont.isAbsoluteSize())
208                fontSize = systemFontSizeForControlSize(NSSmallControlSize);
209            break;
210        case CSSValueMenu:
211            cachedDesc = &menuFont;
212            if (!menuFont.isAbsoluteSize())
213                fontSize = systemFontSizeForControlSize(NSRegularControlSize);
214            break;
215        case CSSValueStatusBar:
216            cachedDesc = &labelFont;
217            if (!labelFont.isAbsoluteSize())
218                fontSize = 10.0f;
219            break;
220        case CSSValueWebkitMiniControl:
221            cachedDesc = &miniControlFont;
222            if (!miniControlFont.isAbsoluteSize())
223                fontSize = systemFontSizeForControlSize(NSMiniControlSize);
224            break;
225        case CSSValueWebkitSmallControl:
226            cachedDesc = &smallControlFont;
227            if (!smallControlFont.isAbsoluteSize())
228                fontSize = systemFontSizeForControlSize(NSSmallControlSize);
229            break;
230        case CSSValueWebkitControl:
231            cachedDesc = &controlFont;
232            if (!controlFont.isAbsoluteSize())
233                fontSize = systemFontSizeForControlSize(NSRegularControlSize);
234            break;
235        default:
236            cachedDesc = &systemFont;
237            if (!systemFont.isAbsoluteSize())
238                fontSize = 13.0f;
239    }
240
241    if (fontSize) {
242        cachedDesc->setIsAbsoluteSize(true);
243        cachedDesc->setGenericFamily(FontDescription::NoFamily);
244        cachedDesc->setOneFamily("Lucida Grande");
245        cachedDesc->setSpecifiedSize(fontSize);
246        cachedDesc->setWeight(FontWeightNormal);
247        cachedDesc->setItalic(false);
248    }
249    fontDescription = *cachedDesc;
250}
251
252bool RenderThemeSafari::isControlStyled(const RenderStyle* style, const BorderData& border,
253                                     const FillLayer& background, const Color& backgroundColor) const
254{
255    // If we didn't find SafariTheme.dll we won't be able to paint any themed controls.
256    if (!SafariThemeLibrary())
257        return true;
258
259    if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
260        return style->border() != border;
261    return RenderTheme::isControlStyled(style, border, background, backgroundColor);
262}
263
264void RenderThemeSafari::adjustRepaintRect(const RenderObject* o, IntRect& r)
265{
266    NSControlSize controlSize = controlSizeForFont(o->style());
267
268    switch (o->style()->appearance()) {
269        case CheckboxPart: {
270            // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
271            // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
272            r = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
273            break;
274        }
275        case RadioPart: {
276            // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
277            // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
278            r = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
279            break;
280        }
281        case PushButtonPart:
282        case DefaultButtonPart:
283        case ButtonPart: {
284            // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
285            // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
286            if (r.height() <= buttonSizes()[NSRegularControlSize].height())
287                r = inflateRect(r, buttonSizes()[controlSize], buttonMargins(controlSize));
288            break;
289        }
290        case MenulistPart: {
291            r = inflateRect(r, popupButtonSizes()[controlSize], popupButtonMargins(controlSize));
292            break;
293        }
294        default:
295            break;
296    }
297}
298
299IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, const int* margins) const
300{
301    // Only do the inflation if the available width/height are too small.  Otherwise try to
302    // fit the glow/check space into the available box's width/height.
303    int widthDelta = r.width() - (size.width() + margins[leftMargin] + margins[rightMargin]);
304    int heightDelta = r.height() - (size.height() + margins[topMargin] + margins[bottomMargin]);
305    IntRect result(r);
306    if (widthDelta < 0) {
307        result.setX(result.x() - margins[leftMargin]);
308        result.setWidth(result.width() - widthDelta);
309    }
310    if (heightDelta < 0) {
311        result.setY(result.y() - margins[topMargin]);
312        result.setHeight(result.height() - heightDelta);
313    }
314    return result;
315}
316
317int RenderThemeSafari::baselinePosition(const RenderObject* o) const
318{
319    if (!o->isBox())
320        return 0;
321
322    if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) {
323        const RenderBox* box = toRenderBox(o);
324        return box->marginTop() + box->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
325    }
326
327    return RenderTheme::baselinePosition(o);
328}
329
330bool RenderThemeSafari::controlSupportsTints(const RenderObject* o) const
331{
332    if (!isEnabled(o))
333        return false;
334
335    // Checkboxes only have tint when checked.
336    if (o->style()->appearance() == CheckboxPart)
337        return isChecked(o);
338
339    // For now assume other controls have tint if enabled.
340    return true;
341}
342
343NSControlSize RenderThemeSafari::controlSizeForFont(RenderStyle* style) const
344{
345    int fontSize = style->fontSize();
346    if (fontSize >= 16)
347        return NSRegularControlSize;
348    if (fontSize >= 11)
349        return NSSmallControlSize;
350    return NSMiniControlSize;
351}
352/*
353void RenderThemeSafari::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize)
354{
355    NSControlSize size;
356    if (minSize.width() >= sizes[NSRegularControlSize].width() &&
357        minSize.height() >= sizes[NSRegularControlSize].height())
358        size = NSRegularControlSize;
359    else if (minSize.width() >= sizes[NSSmallControlSize].width() &&
360             minSize.height() >= sizes[NSSmallControlSize].height())
361        size = NSSmallControlSize;
362    else
363        size = NSMiniControlSize;
364    if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
365        [cell setControlSize:size];
366}
367*/
368IntSize RenderThemeSafari::sizeForFont(RenderStyle* style, const IntSize* sizes) const
369{
370    return sizes[controlSizeForFont(style)];
371}
372
373IntSize RenderThemeSafari::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
374{
375    return sizes[controlSizeForSystemFont(style)];
376}
377
378void RenderThemeSafari::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
379{
380    // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
381    IntSize size = sizeForFont(style, sizes);
382    if (style->width().isIntrinsicOrAuto() && size.width() > 0)
383        style->setWidth(Length(size.width(), Fixed));
384    if (style->height().isAuto() && size.height() > 0)
385        style->setHeight(Length(size.height(), Fixed));
386}
387
388void RenderThemeSafari::setFontFromControlSize(StyleResolver* styleResolver, RenderStyle* style, NSControlSize controlSize) const
389{
390    FontDescription fontDescription;
391    fontDescription.setIsAbsoluteSize(true);
392    fontDescription.setGenericFamily(FontDescription::SerifFamily);
393
394    float fontSize = systemFontSizeForControlSize(controlSize);
395    fontDescription.setOneFamily("Lucida Grande");
396    fontDescription.setComputedSize(fontSize);
397    fontDescription.setSpecifiedSize(fontSize);
398
399    // Reset line height
400    style->setLineHeight(RenderStyle::initialLineHeight());
401
402    if (style->setFontDescription(fontDescription))
403        style->font().update(styleResolver->fontSelector());
404}
405
406NSControlSize RenderThemeSafari::controlSizeForSystemFont(RenderStyle* style) const
407{
408    int fontSize = style->fontSize();
409    if (fontSize >= 13)
410        return NSRegularControlSize;
411    if (fontSize >= 11)
412        return NSSmallControlSize;
413    return NSMiniControlSize;
414}
415
416bool RenderThemeSafari::paintCheckbox(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
417{
418    ASSERT(SafariThemeLibrary());
419
420    NSControlSize controlSize = controlSizeForFont(o->style());
421
422    IntRect inflatedRect = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
423    paintThemePart(SafariTheme::CheckboxPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
424
425    return false;
426}
427
428const IntSize* RenderThemeSafari::checkboxSizes() const
429{
430    static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
431    return sizes;
432}
433
434const int* RenderThemeSafari::checkboxMargins(NSControlSize controlSize) const
435{
436    static const int margins[3][4] =
437    {
438        { 2, 2, 2, 2 },
439        { 2, 2, 2, 1 },
440        { 1, 0, 0, 0 },
441    };
442    return margins[controlSize];
443}
444
445void RenderThemeSafari::setCheckboxSize(RenderStyle* style) const
446{
447    // If the width and height are both specified, then we have nothing to do.
448    if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
449        return;
450
451    // Use the font size to determine the intrinsic width of the control.
452    setSizeFromFont(style, checkboxSizes());
453}
454
455bool RenderThemeSafari::paintRadio(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
456{
457    ASSERT(SafariThemeLibrary());
458
459    NSControlSize controlSize = controlSizeForFont(o->style());
460
461    IntRect inflatedRect = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
462    paintThemePart(RadioButtonPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
463
464    return false;
465}
466
467const IntSize* RenderThemeSafari::radioSizes() const
468{
469    static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
470    return sizes;
471}
472
473const int* RenderThemeSafari::radioMargins(NSControlSize controlSize) const
474{
475    static const int margins[3][4] =
476    {
477        { 1, 2, 2, 2 },
478        { 0, 1, 2, 1 },
479        { 0, 0, 1, 0 },
480     };
481    return margins[controlSize];
482}
483
484void RenderThemeSafari::setRadioSize(RenderStyle* style) const
485{
486    // If the width and height are both specified, then we have nothing to do.
487    if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
488        return;
489
490    // Use the font size to determine the intrinsic width of the control.
491    setSizeFromFont(style, radioSizes());
492}
493
494void RenderThemeSafari::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const
495{
496    // Just use 8px.  AppKit wants to use 11px for mini buttons, but that padding is just too large
497    // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
498    // by definition constrained, since we select mini only for small cramped environments.
499    // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent
500    // padding.
501    const int padding = 8;
502    style->setPaddingLeft(Length(padding, Fixed));
503    style->setPaddingRight(Length(padding, Fixed));
504    style->setPaddingTop(Length(0, Fixed));
505    style->setPaddingBottom(Length(0, Fixed));
506}
507
508void RenderThemeSafari::adjustButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
509{
510    // There are three appearance constants for buttons.
511    // (1) Push-button is the constant for the default Aqua system button.  Push buttons will not scale vertically and will not allow
512    // custom fonts or colors.  <input>s use this constant.  This button will allow custom colors and font weights/variants but won't
513    // scale vertically.
514    // (2) square-button is the constant for the square button.  This button will allow custom fonts and colors and will scale vertically.
515    // (3) Button is the constant that means "pick the best button as appropriate."  <button>s use this constant.  This button will
516    // also scale vertically and allow custom fonts and colors.  It will attempt to use Aqua if possible and will make this determination
517    // solely on the rectangle of the control.
518
519    // Determine our control size based off our font.
520    NSControlSize controlSize = controlSizeForFont(style);
521
522    if (style->appearance() == PushButtonPart) {
523        // Ditch the border.
524        style->resetBorder();
525
526        // Height is locked to auto.
527        style->setHeight(Length(Auto));
528
529        // White-space is locked to pre
530        style->setWhiteSpace(PRE);
531
532        // Set the button's vertical size.
533        setButtonSize(style);
534
535        // Add in the padding that we'd like to use.
536        setButtonPaddingFromControlSize(style, controlSize);
537
538        // 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
539        // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
540        // system font for the control size instead.
541        setFontFromControlSize(styleResolver, style, controlSize);
542    } else {
543        // Set a min-height so that we can't get smaller than the mini button.
544        style->setMinHeight(Length(15, Fixed));
545
546        // Reset the top and bottom borders.
547        style->resetBorderTop();
548        style->resetBorderBottom();
549    }
550}
551
552const IntSize* RenderThemeSafari::buttonSizes() const
553{
554    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
555    return sizes;
556}
557
558const int* RenderThemeSafari::buttonMargins(NSControlSize controlSize) const
559{
560    static const int margins[3][4] =
561    {
562        { 4, 6, 7, 6 },
563        { 4, 5, 6, 5 },
564        { 0, 1, 1, 1 },
565    };
566    return margins[controlSize];
567}
568
569void RenderThemeSafari::setButtonSize(RenderStyle* style) const
570{
571    // If the width and height are both specified, then we have nothing to do.
572    if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
573        return;
574
575    // Use the font size to determine the intrinsic width of the control.
576    setSizeFromFont(style, buttonSizes());
577}
578
579bool RenderThemeSafari::paintButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
580{
581    ASSERT(SafariThemeLibrary());
582
583    // We inflate the rect as needed to account for padding included in the cell to accommodate the button
584    // shadow.  We don't consider this part of the bounds of the control in WebKit.
585
586    NSControlSize controlSize = controlSizeFromRect(r, buttonSizes());
587    IntRect inflatedRect = r;
588
589    ThemePart part;
590    if (r.height() <= buttonSizes()[NSRegularControlSize].height()) {
591        // Push button
592        part = SafariTheme::PushButtonPart;
593
594        IntSize size = buttonSizes()[controlSize];
595        size.setWidth(r.width());
596
597        // Center the button within the available space.
598        if (inflatedRect.height() > size.height()) {
599            inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2);
600            inflatedRect.setHeight(size.height());
601        }
602
603        // Now inflate it to account for the shadow.
604        inflatedRect = inflateRect(inflatedRect, size, buttonMargins(controlSize));
605    } else
606        part = SafariTheme::SquareButtonPart;
607
608    paintThemePart(part, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
609    return false;
610}
611
612bool RenderThemeSafari::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
613{
614    ASSERT(SafariThemeLibrary());
615
616    paintThemePart(SafariTheme::TextFieldPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
617    return false;
618}
619
620void RenderThemeSafari::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const
621{
622}
623
624bool RenderThemeSafari::paintCapsLockIndicator(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
625{
626#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 1
627    ASSERT(SafariThemeLibrary());
628
629    if (paintInfo.context->paintingDisabled())
630        return true;
631
632    paintThemePart(CapsLockPart, paintInfo.context->platformContext(), r, (NSControlSize)0, (ThemeControlState)0);
633
634    return false;
635#else
636    return true;
637#endif
638}
639
640bool RenderThemeSafari::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
641{
642    ASSERT(SafariThemeLibrary());
643
644    paintThemePart(SafariTheme::TextAreaPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
645    return false;
646}
647
648void RenderThemeSafari::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
649{
650}
651
652const int* RenderThemeSafari::popupButtonMargins(NSControlSize size) const
653{
654    static const int margins[3][4] =
655    {
656        { 2, 3, 3, 3 },
657        { 1, 3, 3, 3 },
658        { 0, 1, 0, 1 }
659    };
660    return margins[size];
661}
662
663const IntSize* RenderThemeSafari::popupButtonSizes() const
664{
665    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
666    return sizes;
667}
668
669const int* RenderThemeSafari::popupButtonPadding(NSControlSize size) const
670{
671    static const int padding[3][4] =
672    {
673        { 2, 26, 3, 8 },
674        { 2, 23, 3, 8 },
675        { 2, 22, 3, 10 }
676    };
677    return padding[size];
678}
679
680bool RenderThemeSafari::paintMenuList(RenderObject* o, const PaintInfo& info, const IntRect& r)
681{
682    ASSERT(SafariThemeLibrary());
683
684    NSControlSize controlSize = controlSizeFromRect(r, popupButtonSizes());
685    IntRect inflatedRect = r;
686    IntSize size = popupButtonSizes()[controlSize];
687    size.setWidth(r.width());
688
689    // Now inflate it to account for the shadow.
690    if (r.width() >= minimumMenuListSize(o->style()))
691        inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(controlSize));
692
693    paintThemePart(DropDownButtonPart, info.context->platformContext(), inflatedRect, controlSize, determineState(o));
694
695    return false;
696}
697
698const float baseFontSize = 11.0f;
699const float baseArrowHeight = 5.0f;
700const float baseArrowWidth = 7.0f;
701const int arrowPaddingLeft = 5;
702const int arrowPaddingRight = 5;
703const int paddingBeforeSeparator = 4;
704const int baseBorderRadius = 5;
705const int styledPopupPaddingLeft = 8;
706const int styledPopupPaddingTop = 1;
707const int styledPopupPaddingBottom = 2;
708
709static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
710{
711    static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
712    static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
713    float a = inData[0];
714    int i = 0;
715    for (i = 0; i < 4; i++)
716        outData[i] = (1.0f - a) * dark[i] + a * light[i];
717}
718
719static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
720{
721    static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
722    static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
723    float a = inData[0];
724    int i = 0;
725    for (i = 0; i < 4; i++)
726        outData[i] = (1.0f - a) * dark[i] + a * light[i];
727}
728
729static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
730{
731    static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
732    static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
733    float a = inData[0];
734    int i = 0;
735    for (i = 0; i < 4; i++)
736        outData[i] = (1.0f - a) * dark[i] + a * light[i];
737}
738
739static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
740{
741    static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
742    static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
743    float a = inData[0];
744    int i = 0;
745    for (i = 0; i < 4; i++)
746        outData[i] = (1.0f - a) * dark[i] + a * light[i];
747}
748
749void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
750{
751    if (r.isEmpty())
752        return;
753
754    CGContextRef context = paintInfo.context->platformContext();
755
756    paintInfo.context->save();
757
758    RoundedRect bound = o->style()->getRoundedBorderFor(r);
759    int radius = bound.radii().topLeft().width();
760
761    CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
762
763    FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
764    struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
765    RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
766    RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
767
768    FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
769    struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
770    RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
771    RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(),  bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
772
773    struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
774    RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
775    RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
776
777    RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
778
779    RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(),  r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
780    paintInfo.context->save();
781    CGContextClipToRect(context, bound.rect());
782    paintInfo.context->clipRoundedRect(bound);
783    CGContextDrawShading(context, mainShading.get());
784    paintInfo.context->restore();
785
786    paintInfo.context->save();
787    CGContextClipToRect(context, topGradient);
788    paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(topGradient), bound.radii().topLeft(), bound.radii().topRight(), IntSize(), IntSize()));
789    CGContextDrawShading(context, topShading.get());
790    paintInfo.context->restore();
791
792    if (!bottomGradient.isEmpty()) {
793        paintInfo.context->save();
794        CGContextClipToRect(context, bottomGradient);
795        paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bound.radii().bottomLeft(), bound.radii().bottomRight()));
796        CGContextDrawShading(context, bottomShading.get());
797        paintInfo.context->restore();
798    }
799
800    paintInfo.context->save();
801    CGContextClipToRect(context, bound.rect());
802    paintInfo.context->clipRoundedRect(bound);
803    CGContextDrawShading(context, leftShading.get());
804    CGContextDrawShading(context, rightShading.get());
805    paintInfo.context->restore();
806
807    paintInfo.context->restore();
808}
809
810bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
811{
812    IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
813                             r.y() + o->style()->borderTopWidth(),
814                             r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
815                             r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
816    // Draw the gradients to give the styled popup menu a button appearance
817    paintMenuListButtonGradients(o, paintInfo, bounds);
818
819    // 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
820    float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / baseArrowHeight);
821    float centerY = bounds.y() + bounds.height() / 2.0f;
822    float arrowHeight = baseArrowHeight * fontScale;
823    float arrowWidth = baseArrowWidth * fontScale;
824    float leftEdge = bounds.maxX() - arrowPaddingRight - arrowWidth;
825
826    if (bounds.width() < arrowWidth + arrowPaddingLeft)
827        return false;
828
829    paintInfo.context->save();
830
831    paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
832    paintInfo.context->setStrokeColor(NoStroke, ColorSpaceDeviceRGB);
833
834    FloatPoint arrow[3];
835    arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f);
836    arrow[1] = FloatPoint(leftEdge + arrowWidth, centerY - arrowHeight / 2.0f);
837    arrow[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + arrowHeight / 2.0f);
838
839    // Draw the arrow
840    paintInfo.context->drawConvexPolygon(3, arrow, true);
841
842    Color leftSeparatorColor(0, 0, 0, 40);
843    Color rightSeparatorColor(255, 255, 255, 40);
844
845    // FIXME: Should the separator thickness and space be scaled up by fontScale?
846    int separatorSpace = 2;
847    int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft); // FIXME: Round?
848
849    // Draw the separator to the left of the arrows
850    paintInfo.context->setStrokeThickness(1.0f);
851    paintInfo.context->setStrokeStyle(SolidStroke);
852    paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
853    paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
854                                IntPoint(leftEdgeOfSeparator, bounds.maxY()));
855
856    paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
857    paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
858                                IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
859
860    paintInfo.context->restore();
861    return false;
862}
863
864void RenderThemeSafari::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
865{
866    NSControlSize controlSize = controlSizeForFont(style);
867
868    style->resetBorder();
869    style->resetPadding();
870
871    // Height is locked to auto.
872    style->setHeight(Length(Auto));
873
874    // White-space is locked to pre
875    style->setWhiteSpace(PRE);
876
877    // Set the foreground color to black or gray when we have the aqua look.
878    // Cast to RGB32 is to work around a compiler bug.
879    style->setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
880
881    // Set the button's vertical size.
882    setButtonSize(style);
883
884    // 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
885    // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
886    // system font for the control size instead.
887    setFontFromControlSize(styleResolver, style, controlSize);
888}
889
890int RenderThemeSafari::popupInternalPaddingLeft(RenderStyle* style) const
891{
892    if (style->appearance() == MenulistPart)
893        return popupButtonPadding(controlSizeForFont(style))[leftPadding];
894    if (style->appearance() == MenulistButtonPart)
895        return styledPopupPaddingLeft;
896    return 0;
897}
898
899int RenderThemeSafari::popupInternalPaddingRight(RenderStyle* style) const
900{
901    if (style->appearance() == MenulistPart)
902        return popupButtonPadding(controlSizeForFont(style))[rightPadding];
903    if (style->appearance() == MenulistButtonPart) {
904        float fontScale = style->fontSize() / baseFontSize;
905        float arrowWidth = baseArrowWidth * fontScale;
906        return static_cast<int>(ceilf(arrowWidth + arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator));
907    }
908    return 0;
909}
910
911int RenderThemeSafari::popupInternalPaddingTop(RenderStyle* style) const
912{
913    if (style->appearance() == MenulistPart)
914        return popupButtonPadding(controlSizeForFont(style))[topPadding];
915    if (style->appearance() == MenulistButtonPart)
916        return styledPopupPaddingTop;
917    return 0;
918}
919
920int RenderThemeSafari::popupInternalPaddingBottom(RenderStyle* style) const
921{
922    if (style->appearance() == MenulistPart)
923        return popupButtonPadding(controlSizeForFont(style))[bottomPadding];
924    if (style->appearance() == MenulistButtonPart)
925        return styledPopupPaddingBottom;
926    return 0;
927}
928
929void RenderThemeSafari::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
930{
931    float fontScale = style->fontSize() / baseFontSize;
932
933    style->resetPadding();
934    style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
935
936    const int minHeight = 15;
937    style->setMinHeight(Length(minHeight, Fixed));
938
939    style->setLineHeight(RenderStyle::initialLineHeight());
940}
941
942const IntSize* RenderThemeSafari::menuListSizes() const
943{
944    static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
945    return sizes;
946}
947
948int RenderThemeSafari::minimumMenuListSize(RenderStyle* style) const
949{
950    return sizeForSystemFont(style, menuListSizes()).width();
951}
952
953const int trackWidth = 5;
954const int trackRadius = 2;
955
956bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
957{
958    IntSize radius(trackRadius, trackRadius);
959    RoundedRect bounds(r, radius, radius, radius, radius);
960
961    if (o->style()->appearance() ==  SliderHorizontalPart)
962        bounds.setRect(IntRect(r.x(),
963                               r.y() + r.height() / 2 - trackWidth / 2,
964                               r.width(),
965                               trackWidth));
966    else if (o->style()->appearance() == SliderVerticalPart)
967        bounds.setRect(IntRect(r.x() + r.width() / 2 - trackWidth / 2,
968                               r.y(),
969                               trackWidth,
970                               r.height()));
971
972    CGContextRef context = paintInfo.context->platformContext();
973    CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
974
975    paintInfo.context->save();
976    CGContextClipToRect(context, bounds.rect());
977
978    struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
979    RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
980    RetainPtr<CGShadingRef> mainShading;
981    if (o->style()->appearance() == SliderVerticalPart)
982        mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(),  bounds.rect().maxY()), CGPointMake(bounds.rect().maxX(), bounds.rect().maxY()), mainFunction.get(), false, false));
983    else
984        mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(),  bounds.rect().y()), CGPointMake(bounds.rect().x(), bounds.rect().maxY()), mainFunction.get(), false, false));
985
986    paintInfo.context->clipRoundedRect(bounds);
987    CGContextDrawShading(context, mainShading.get());
988    paintInfo.context->restore();
989
990    return false;
991}
992
993void RenderThemeSafari::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
994{
995    RenderTheme::adjustSliderThumbStyle(styleResolver, style, e);
996    style->setBoxShadow(nullptr);
997}
998
999const float verticalSliderHeightPadding = 0.1f;
1000
1001bool RenderThemeSafari::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1002{
1003    ASSERT(SafariThemeLibrary());
1004    paintThemePart(SliderThumbPart, paintInfo.context->platformContext(), r, NSSmallControlSize, determineState(o));
1005    return false;
1006}
1007
1008const int sliderThumbWidth = 15;
1009const int sliderThumbHeight = 15;
1010
1011void RenderThemeSafari::adjustSliderThumbSize(RenderStyle* style, Element*) const
1012{
1013    if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
1014        style->setWidth(Length(sliderThumbWidth, Fixed));
1015        style->setHeight(Length(sliderThumbHeight, Fixed));
1016    }
1017#if ENABLE(VIDEO)
1018    else if (style->appearance() == MediaSliderThumbPart)
1019        RenderMediaControls::adjustMediaSliderThumbSize(style);
1020#endif
1021}
1022
1023bool RenderThemeSafari::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1024{
1025    ASSERT(SafariThemeLibrary());
1026
1027    paintThemePart(SafariTheme::SearchFieldPart, paintInfo.context->platformContext(), r, controlSizeFromRect(r, searchFieldSizes()), determineState(o));
1028    return false;
1029}
1030
1031const IntSize* RenderThemeSafari::searchFieldSizes() const
1032{
1033    static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 15) };
1034    return sizes;
1035}
1036
1037void RenderThemeSafari::setSearchFieldSize(RenderStyle* style) const
1038{
1039    // If the width and height are both specified, then we have nothing to do.
1040    if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1041        return;
1042
1043    // Use the font size to determine the intrinsic width of the control.
1044    setSizeFromFont(style, searchFieldSizes());
1045}
1046
1047void RenderThemeSafari::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
1048{
1049    // Override border.
1050    style->resetBorder();
1051    const short borderWidth = 2;
1052    style->setBorderLeftWidth(borderWidth);
1053    style->setBorderLeftStyle(INSET);
1054    style->setBorderRightWidth(borderWidth);
1055    style->setBorderRightStyle(INSET);
1056    style->setBorderBottomWidth(borderWidth);
1057    style->setBorderBottomStyle(INSET);
1058    style->setBorderTopWidth(borderWidth);
1059    style->setBorderTopStyle(INSET);
1060
1061    // Override height.
1062    style->setHeight(Length(Auto));
1063    setSearchFieldSize(style);
1064
1065    // Override padding size to match AppKit text positioning.
1066    const int padding = 1;
1067    style->setPaddingLeft(Length(padding, Fixed));
1068    style->setPaddingRight(Length(padding, Fixed));
1069    style->setPaddingTop(Length(padding, Fixed));
1070    style->setPaddingBottom(Length(padding, Fixed));
1071
1072    NSControlSize controlSize = controlSizeForFont(style);
1073    setFontFromControlSize(styleResolver, style, controlSize);
1074}
1075
1076bool RenderThemeSafari::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
1077{
1078    ASSERT(SafariThemeLibrary());
1079
1080    Node* input = o->node()->shadowHost();
1081    if (!input)
1082        input = o->node();
1083    RenderObject* renderer = input->renderer();
1084    ASSERT(renderer);
1085
1086    IntRect searchRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
1087
1088    paintThemePart(SafariTheme::SearchFieldCancelButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1089    return false;
1090}
1091
1092const IntSize* RenderThemeSafari::cancelButtonSizes() const
1093{
1094    static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1095    return sizes;
1096}
1097
1098void RenderThemeSafari::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1099{
1100    IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1101    style->setWidth(Length(size.width(), Fixed));
1102    style->setHeight(Length(size.height(), Fixed));
1103}
1104
1105const IntSize* RenderThemeSafari::resultsButtonSizes() const
1106{
1107    static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1108    return sizes;
1109}
1110
1111const int emptyResultsOffset = 9;
1112void RenderThemeSafari::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
1113{
1114    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1115    style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1116    style->setHeight(Length(size.height(), Fixed));
1117}
1118
1119bool RenderThemeSafari::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1120{
1121    return false;
1122}
1123
1124void RenderThemeSafari::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
1125{
1126    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1127    style->setWidth(Length(size.width(), Fixed));
1128    style->setHeight(Length(size.height(), Fixed));
1129}
1130
1131bool RenderThemeSafari::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
1132{
1133    ASSERT(SafariThemeLibrary());
1134
1135    Node* input = o->node()->shadowHost();
1136    if (!input)
1137        input = o->node();
1138    RenderObject* renderer = input->renderer();
1139    ASSERT(renderer);
1140
1141    IntRect searchRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
1142
1143    paintThemePart(SafariTheme::SearchFieldResultsDecorationPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1144    return false;
1145}
1146
1147const int resultsArrowWidth = 5;
1148void RenderThemeSafari::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1149{
1150    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1151    style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1152    style->setHeight(Length(size.height(), Fixed));
1153}
1154
1155bool RenderThemeSafari::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
1156{
1157    ASSERT(SafariThemeLibrary());
1158
1159    Node* input = o->node()->shadowHost();
1160    if (!input)
1161        input = o->node();
1162    RenderObject* renderer = input->renderer();
1163    ASSERT(renderer);
1164
1165    IntRect searchRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
1166
1167    paintThemePart(SafariTheme::SearchFieldResultsButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1168    return false;
1169}
1170#if ENABLE(VIDEO)
1171bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1172{
1173    return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, o, paintInfo, r);
1174}
1175
1176bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1177{
1178    return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r);
1179}
1180
1181bool RenderThemeSafari::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1182{
1183    return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r);
1184}
1185
1186bool RenderThemeSafari::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1187{
1188    return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r);
1189}
1190
1191bool RenderThemeSafari::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1192{
1193    return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r);
1194}
1195
1196bool RenderThemeSafari::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1197{
1198    return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r);
1199}
1200
1201bool RenderThemeSafari::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1202{
1203    return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r);
1204}
1205#endif
1206
1207#if ENABLE(METER_ELEMENT)
1208void RenderThemeSafari::adjustMeterStyle(StyleResolver*, RenderStyle* style, Element*) const
1209{
1210    style->setBoxShadow(nullptr);
1211}
1212
1213bool RenderThemeSafari::supportsMeter(ControlPart part) const
1214{
1215    switch (part) {
1216    case MeterPart:
1217        return true;
1218    default:
1219        return false;
1220    }
1221}
1222
1223IntSize RenderThemeSafari::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const
1224{
1225    return bounds.size();
1226}
1227
1228bool RenderThemeSafari::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1229{
1230    // NOTE: This routine is for testing only. It should be fleshed out with a real CG-based implementation.
1231    // Right now it uses a slider, with the thumb positioned at the meter point.
1232    if (!renderObject->isMeter())
1233        return true;
1234
1235    HTMLMeterElement* element = toRenderMeter(renderObject)->meterElement();
1236
1237    int remaining = static_cast<int>((1.0 - element->valueRatio()) * static_cast<double>(rect.size().width()));
1238
1239    // Draw the background
1240    paintSliderTrack(renderObject, paintInfo, rect);
1241
1242    // Draw the progress portion
1243    IntRect completedRect(rect);
1244    completedRect.contract(remaining, 0);
1245
1246    paintSliderThumb(renderObject, paintInfo, completedRect);
1247
1248    return true;
1249}
1250
1251#endif
1252
1253} // namespace WebCore
1254
1255#endif // #if USE(SAFARI_THEME)
1256