2
* Copyright (C) 2007, 2008, 2009 Apple Inc.
3
* Copyright (C) 2009 Kenneth Rohde Christiansen
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Library General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Library General Public License for more details.
15
* You should have received a copy of the GNU Library General Public License
16
* along with this library; see the file COPYING.LIB. If not, write to
17
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301, USA.
23
#include "RenderThemeSafari.h"
24
#include "RenderThemeWin.h"
29
#include "CSSFontSelector.h"
30
#include "CSSValueKeywords.h"
34
#include "FrameView.h"
35
#include "GraphicsContextCG.h"
36
#include "HTMLInputElement.h"
37
#include "HTMLMediaElement.h"
38
#include "HTMLNames.h"
39
#include "PaintInfo.h"
40
#include "RenderMediaControls.h"
41
#include "RenderSlider.h"
42
#include "RenderView.h"
43
#include "SoftLinking.h"
44
#include "StyleResolver.h"
45
#include <CoreGraphics/CoreGraphics.h>
46
#include <wtf/RetainPtr.h>
50
// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeMac.
54
using namespace HTMLNames;
55
using namespace SafariTheme;
71
PassRefPtr<RenderTheme> RenderThemeSafari::create()
73
return adoptRef(new RenderThemeSafari);
76
PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
78
static RenderTheme* safariTheme = RenderThemeSafari::create().leakRef();
79
static RenderTheme* windowsTheme = RenderThemeWin::create().leakRef();
81
// FIXME: This is called before Settings has been initialized by WebKit, so will return a
82
// potentially wrong answer the very first time it's called (see
83
// <https://bugs.webkit.org/show_bug.cgi?id=26493>).
84
if (Settings::shouldPaintNativeControls()) {
85
RenderTheme::setCustomFocusRingColor(safariTheme->platformFocusRingColor());
86
return windowsTheme; // keep the reference of one.
88
return safariTheme; // keep the reference of one.
92
SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
94
SOFT_LINK_LIBRARY(SafariTheme)
97
SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state))
98
#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
99
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))
101
SOFT_LINK_OPTIONAL(SafariTheme, STCopyThemeColor, CGColorRef, APIENTRY, (unsigned color, SafariTheme::ThemeControlState));
103
static const unsigned stFocusRingColorID = 4;
105
static const unsigned aquaFocusRingColor = 0xFF7DADD9;
107
static RGBA32 makeRGBAFromCGColor(CGColorRef color)
109
const CGFloat* components = CGColorGetComponents(color);
110
return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]);
113
ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const
115
ThemeControlState result = 0;
117
result |= SafariTheme::ActiveState;
118
if (isEnabled(o) && !isReadOnlyControl(o))
119
result |= SafariTheme::EnabledState;
121
result |= SafariTheme::PressedState;
123
result |= SafariTheme::CheckedState;
124
if (isIndeterminate(o))
125
result |= SafariTheme::IndeterminateCheckedState;
127
result |= SafariTheme::FocusedState;
129
result |= SafariTheme::DefaultState;
133
static NSControlSize controlSizeFromRect(const IntRect& rect, const IntSize sizes[])
135
if (sizes[NSRegularControlSize].height() == rect.height())
136
return NSRegularControlSize;
137
else if (sizes[NSMiniControlSize].height() == rect.height())
138
return NSMiniControlSize;
140
return NSSmallControlSize;
143
RenderThemeSafari::RenderThemeSafari()
147
RenderThemeSafari::~RenderThemeSafari()
151
Color RenderThemeSafari::platformActiveSelectionBackgroundColor() const
153
return Color(181, 213, 255);
156
Color RenderThemeSafari::platformInactiveSelectionBackgroundColor() const
158
return Color(212, 212, 212);
161
Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const
163
// FIXME: This should probably just be a darker version of the platformActiveSelectionBackgroundColor
164
return Color(56, 117, 215);
167
Color RenderThemeSafari::platformFocusRingColor() const
169
static Color focusRingColor;
171
if (!focusRingColor.isValid()) {
172
if (STCopyThemeColorPtr()) {
173
RetainPtr<CGColorRef> color(AdoptCF, STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState));
174
focusRingColor = makeRGBAFromCGColor(color.get());
176
if (!focusRingColor.isValid())
177
focusRingColor = aquaFocusRingColor;
180
return focusRingColor;
183
static float systemFontSizeForControlSize(NSControlSize controlSize)
185
static float sizes[] = { 13.0f, 11.0f, 9.0f };
187
return sizes[controlSize];
190
void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription) const
192
static FontDescription systemFont;
193
static FontDescription smallSystemFont;
194
static FontDescription menuFont;
195
static FontDescription labelFont;
196
static FontDescription miniControlFont;
197
static FontDescription smallControlFont;
198
static FontDescription controlFont;
200
FontDescription* cachedDesc;
203
case CSSValueSmallCaption:
204
cachedDesc = &smallSystemFont;
205
if (!smallSystemFont.isAbsoluteSize())
206
fontSize = systemFontSizeForControlSize(NSSmallControlSize);
209
cachedDesc = &menuFont;
210
if (!menuFont.isAbsoluteSize())
211
fontSize = systemFontSizeForControlSize(NSRegularControlSize);
213
case CSSValueStatusBar:
214
cachedDesc = &labelFont;
215
if (!labelFont.isAbsoluteSize())
218
case CSSValueWebkitMiniControl:
219
cachedDesc = &miniControlFont;
220
if (!miniControlFont.isAbsoluteSize())
221
fontSize = systemFontSizeForControlSize(NSMiniControlSize);
223
case CSSValueWebkitSmallControl:
224
cachedDesc = &smallControlFont;
225
if (!smallControlFont.isAbsoluteSize())
226
fontSize = systemFontSizeForControlSize(NSSmallControlSize);
228
case CSSValueWebkitControl:
229
cachedDesc = &controlFont;
230
if (!controlFont.isAbsoluteSize())
231
fontSize = systemFontSizeForControlSize(NSRegularControlSize);
234
cachedDesc = &systemFont;
235
if (!systemFont.isAbsoluteSize())
240
cachedDesc->setIsAbsoluteSize(true);
241
cachedDesc->setGenericFamily(FontDescription::NoFamily);
242
cachedDesc->firstFamily().setFamily("Lucida Grande");
243
cachedDesc->setSpecifiedSize(fontSize);
244
cachedDesc->setWeight(FontWeightNormal);
245
cachedDesc->setItalic(false);
247
fontDescription = *cachedDesc;
250
bool RenderThemeSafari::isControlStyled(const RenderStyle* style, const BorderData& border,
251
const FillLayer& background, const Color& backgroundColor) const
253
// If we didn't find SafariTheme.dll we won't be able to paint any themed controls.
254
if (!SafariThemeLibrary())
257
if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
258
return style->border() != border;
259
return RenderTheme::isControlStyled(style, border, background, backgroundColor);
262
void RenderThemeSafari::adjustRepaintRect(const RenderObject* o, IntRect& r)
264
NSControlSize controlSize = controlSizeForFont(o->style());
266
switch (o->style()->appearance()) {
268
// We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
269
// shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
270
r = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
274
// We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
275
// shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
276
r = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
280
case DefaultButtonPart:
282
// We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
283
// shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
284
if (r.height() <= buttonSizes()[NSRegularControlSize].height())
285
r = inflateRect(r, buttonSizes()[controlSize], buttonMargins(controlSize));
289
r = inflateRect(r, popupButtonSizes()[controlSize], popupButtonMargins(controlSize));
297
IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, const int* margins) const
299
// Only do the inflation if the available width/height are too small. Otherwise try to
300
// fit the glow/check space into the available box's width/height.
301
int widthDelta = r.width() - (size.width() + margins[leftMargin] + margins[rightMargin]);
302
int heightDelta = r.height() - (size.height() + margins[topMargin] + margins[bottomMargin]);
304
if (widthDelta < 0) {
305
result.setX(result.x() - margins[leftMargin]);
306
result.setWidth(result.width() - widthDelta);
308
if (heightDelta < 0) {
309
result.setY(result.y() - margins[topMargin]);
310
result.setHeight(result.height() - heightDelta);
315
int RenderThemeSafari::baselinePosition(const RenderObject* o) const
320
if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) {
321
const RenderBox* box = toRenderBox(o);
322
return box->marginTop() + box->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
325
return RenderTheme::baselinePosition(o);
328
bool RenderThemeSafari::controlSupportsTints(const RenderObject* o) const
333
// Checkboxes only have tint when checked.
334
if (o->style()->appearance() == CheckboxPart)
337
// For now assume other controls have tint if enabled.
341
NSControlSize RenderThemeSafari::controlSizeForFont(RenderStyle* style) const
343
int fontSize = style->fontSize();
345
return NSRegularControlSize;
347
return NSSmallControlSize;
348
return NSMiniControlSize;
351
void RenderThemeSafari::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize)
354
if (minSize.width() >= sizes[NSRegularControlSize].width() &&
355
minSize.height() >= sizes[NSRegularControlSize].height())
356
size = NSRegularControlSize;
357
else if (minSize.width() >= sizes[NSSmallControlSize].width() &&
358
minSize.height() >= sizes[NSSmallControlSize].height())
359
size = NSSmallControlSize;
361
size = NSMiniControlSize;
362
if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
363
[cell setControlSize:size];
366
IntSize RenderThemeSafari::sizeForFont(RenderStyle* style, const IntSize* sizes) const
368
return sizes[controlSizeForFont(style)];
371
IntSize RenderThemeSafari::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
373
return sizes[controlSizeForSystemFont(style)];
376
void RenderThemeSafari::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
378
// FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
379
IntSize size = sizeForFont(style, sizes);
380
if (style->width().isIntrinsicOrAuto() && size.width() > 0)
381
style->setWidth(Length(size.width(), Fixed));
382
if (style->height().isAuto() && size.height() > 0)
383
style->setHeight(Length(size.height(), Fixed));
386
void RenderThemeSafari::setFontFromControlSize(StyleResolver* styleResolver, RenderStyle* style, NSControlSize controlSize) const
388
FontDescription fontDescription;
389
fontDescription.setIsAbsoluteSize(true);
390
fontDescription.setGenericFamily(FontDescription::SerifFamily);
392
float fontSize = systemFontSizeForControlSize(controlSize);
393
fontDescription.firstFamily().setFamily("Lucida Grande");
394
fontDescription.setComputedSize(fontSize);
395
fontDescription.setSpecifiedSize(fontSize);
398
style->setLineHeight(RenderStyle::initialLineHeight());
400
if (style->setFontDescription(fontDescription))
401
style->font().update(styleResolver->fontSelector());
404
NSControlSize RenderThemeSafari::controlSizeForSystemFont(RenderStyle* style) const
406
int fontSize = style->fontSize();
408
return NSRegularControlSize;
410
return NSSmallControlSize;
411
return NSMiniControlSize;
414
bool RenderThemeSafari::paintCheckbox(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
416
ASSERT(SafariThemeLibrary());
418
NSControlSize controlSize = controlSizeForFont(o->style());
420
IntRect inflatedRect = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
421
paintThemePart(SafariTheme::CheckboxPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
426
const IntSize* RenderThemeSafari::checkboxSizes() const
428
static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
432
const int* RenderThemeSafari::checkboxMargins(NSControlSize controlSize) const
434
static const int margins[3][4] =
440
return margins[controlSize];
443
void RenderThemeSafari::setCheckboxSize(RenderStyle* style) const
445
// If the width and height are both specified, then we have nothing to do.
446
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
449
// Use the font size to determine the intrinsic width of the control.
450
setSizeFromFont(style, checkboxSizes());
453
bool RenderThemeSafari::paintRadio(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
455
ASSERT(SafariThemeLibrary());
457
NSControlSize controlSize = controlSizeForFont(o->style());
459
IntRect inflatedRect = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
460
paintThemePart(RadioButtonPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
465
const IntSize* RenderThemeSafari::radioSizes() const
467
static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
471
const int* RenderThemeSafari::radioMargins(NSControlSize controlSize) const
473
static const int margins[3][4] =
479
return margins[controlSize];
482
void RenderThemeSafari::setRadioSize(RenderStyle* style) const
484
// If the width and height are both specified, then we have nothing to do.
485
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
488
// Use the font size to determine the intrinsic width of the control.
489
setSizeFromFont(style, radioSizes());
492
void RenderThemeSafari::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const
494
// Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large
495
// for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
496
// by definition constrained, since we select mini only for small cramped environments.
497
// This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent
499
const int padding = 8;
500
style->setPaddingLeft(Length(padding, Fixed));
501
style->setPaddingRight(Length(padding, Fixed));
502
style->setPaddingTop(Length(0, Fixed));
503
style->setPaddingBottom(Length(0, Fixed));
506
void RenderThemeSafari::adjustButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
508
// There are three appearance constants for buttons.
509
// (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow
510
// custom fonts or colors. <input>s use this constant. This button will allow custom colors and font weights/variants but won't
512
// (2) square-button is the constant for the square button. This button will allow custom fonts and colors and will scale vertically.
513
// (3) Button is the constant that means "pick the best button as appropriate." <button>s use this constant. This button will
514
// also scale vertically and allow custom fonts and colors. It will attempt to use Aqua if possible and will make this determination
515
// solely on the rectangle of the control.
517
// Determine our control size based off our font.
518
NSControlSize controlSize = controlSizeForFont(style);
520
if (style->appearance() == PushButtonPart) {
522
style->resetBorder();
524
// Height is locked to auto.
525
style->setHeight(Length(Auto));
527
// White-space is locked to pre
528
style->setWhiteSpace(PRE);
530
// Set the button's vertical size.
531
setButtonSize(style);
533
// Add in the padding that we'd like to use.
534
setButtonPaddingFromControlSize(style, controlSize);
536
// 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
537
// a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
538
// system font for the control size instead.
539
setFontFromControlSize(styleResolver, style, controlSize);
541
// Set a min-height so that we can't get smaller than the mini button.
542
style->setMinHeight(Length(15, Fixed));
544
// Reset the top and bottom borders.
545
style->resetBorderTop();
546
style->resetBorderBottom();
550
const IntSize* RenderThemeSafari::buttonSizes() const
552
static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
556
const int* RenderThemeSafari::buttonMargins(NSControlSize controlSize) const
558
static const int margins[3][4] =
564
return margins[controlSize];
567
void RenderThemeSafari::setButtonSize(RenderStyle* style) const
569
// If the width and height are both specified, then we have nothing to do.
570
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
573
// Use the font size to determine the intrinsic width of the control.
574
setSizeFromFont(style, buttonSizes());
577
bool RenderThemeSafari::paintButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
579
ASSERT(SafariThemeLibrary());
581
// We inflate the rect as needed to account for padding included in the cell to accommodate the button
582
// shadow. We don't consider this part of the bounds of the control in WebKit.
584
NSControlSize controlSize = controlSizeFromRect(r, buttonSizes());
585
IntRect inflatedRect = r;
588
if (r.height() <= buttonSizes()[NSRegularControlSize].height()) {
590
part = SafariTheme::PushButtonPart;
592
IntSize size = buttonSizes()[controlSize];
593
size.setWidth(r.width());
595
// Center the button within the available space.
596
if (inflatedRect.height() > size.height()) {
597
inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2);
598
inflatedRect.setHeight(size.height());
601
// Now inflate it to account for the shadow.
602
inflatedRect = inflateRect(inflatedRect, size, buttonMargins(controlSize));
604
part = SafariTheme::SquareButtonPart;
606
paintThemePart(part, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
610
bool RenderThemeSafari::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
612
ASSERT(SafariThemeLibrary());
614
paintThemePart(SafariTheme::TextFieldPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
618
void RenderThemeSafari::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const
622
bool RenderThemeSafari::paintCapsLockIndicator(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
624
#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 1
625
ASSERT(SafariThemeLibrary());
627
if (paintInfo.context->paintingDisabled())
630
paintThemePart(CapsLockPart, paintInfo.context->platformContext(), r, (NSControlSize)0, (ThemeControlState)0);
638
bool RenderThemeSafari::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
640
ASSERT(SafariThemeLibrary());
642
paintThemePart(SafariTheme::TextAreaPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
646
void RenderThemeSafari::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
650
const int* RenderThemeSafari::popupButtonMargins(NSControlSize size) const
652
static const int margins[3][4] =
658
return margins[size];
661
const IntSize* RenderThemeSafari::popupButtonSizes() const
663
static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
667
const int* RenderThemeSafari::popupButtonPadding(NSControlSize size) const
669
static const int padding[3][4] =
675
return padding[size];
678
bool RenderThemeSafari::paintMenuList(RenderObject* o, const PaintInfo& info, const IntRect& r)
680
ASSERT(SafariThemeLibrary());
682
NSControlSize controlSize = controlSizeFromRect(r, popupButtonSizes());
683
IntRect inflatedRect = r;
684
IntSize size = popupButtonSizes()[controlSize];
685
size.setWidth(r.width());
687
// Now inflate it to account for the shadow.
688
if (r.width() >= minimumMenuListSize(o->style()))
689
inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(controlSize));
691
paintThemePart(DropDownButtonPart, info.context->platformContext(), inflatedRect, controlSize, determineState(o));
696
const float baseFontSize = 11.0f;
697
const float baseArrowHeight = 5.0f;
698
const float baseArrowWidth = 7.0f;
699
const int arrowPaddingLeft = 5;
700
const int arrowPaddingRight = 5;
701
const int paddingBeforeSeparator = 4;
702
const int baseBorderRadius = 5;
703
const int styledPopupPaddingLeft = 8;
704
const int styledPopupPaddingTop = 1;
705
const int styledPopupPaddingBottom = 2;
707
static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
709
static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
710
static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
713
for (i = 0; i < 4; i++)
714
outData[i] = (1.0f - a) * dark[i] + a * light[i];
717
static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
719
static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
720
static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
723
for (i = 0; i < 4; i++)
724
outData[i] = (1.0f - a) * dark[i] + a * light[i];
727
static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
729
static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
730
static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
733
for (i = 0; i < 4; i++)
734
outData[i] = (1.0f - a) * dark[i] + a * light[i];
737
static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
739
static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
740
static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
743
for (i = 0; i < 4; i++)
744
outData[i] = (1.0f - a) * dark[i] + a * light[i];
747
void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
752
CGContextRef context = paintInfo.context->platformContext();
754
paintInfo.context->save();
756
RoundedRect bound = o->style()->getRoundedBorderFor(r);
757
int radius = bound.radii().topLeft().width();
759
CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
761
FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
762
struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
763
RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
764
RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
766
FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
767
struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
768
RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
769
RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
771
struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
772
RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
773
RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
775
RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
777
RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
778
paintInfo.context->save();
779
CGContextClipToRect(context, bound.rect());
780
paintInfo.context->addRoundedRectClip(bound);
781
CGContextDrawShading(context, mainShading.get());
782
paintInfo.context->restore();
784
paintInfo.context->save();
785
CGContextClipToRect(context, topGradient);
786
paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(topGradient), bound.radii().topLeft(), bound.radii().topRight(), IntSize(), IntSize()));
787
CGContextDrawShading(context, topShading.get());
788
paintInfo.context->restore();
790
if (!bottomGradient.isEmpty()) {
791
paintInfo.context->save();
792
CGContextClipToRect(context, bottomGradient);
793
paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bound.radii().bottomLeft(), bound.radii().bottomRight()));
794
CGContextDrawShading(context, bottomShading.get());
795
paintInfo.context->restore();
798
paintInfo.context->save();
799
CGContextClipToRect(context, bound.rect());
800
paintInfo.context->addRoundedRectClip(bound);
801
CGContextDrawShading(context, leftShading.get());
802
CGContextDrawShading(context, rightShading.get());
803
paintInfo.context->restore();
805
paintInfo.context->restore();
808
bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
810
IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
811
r.y() + o->style()->borderTopWidth(),
812
r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
813
r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
814
// Draw the gradients to give the styled popup menu a button appearance
815
paintMenuListButtonGradients(o, paintInfo, bounds);
817
// 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
818
float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / baseArrowHeight);
819
float centerY = bounds.y() + bounds.height() / 2.0f;
820
float arrowHeight = baseArrowHeight * fontScale;
821
float arrowWidth = baseArrowWidth * fontScale;
822
float leftEdge = bounds.maxX() - arrowPaddingRight - arrowWidth;
824
if (bounds.width() < arrowWidth + arrowPaddingLeft)
827
paintInfo.context->save();
829
paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
830
paintInfo.context->setStrokeColor(NoStroke, ColorSpaceDeviceRGB);
833
arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f);
834
arrow[1] = FloatPoint(leftEdge + arrowWidth, centerY - arrowHeight / 2.0f);
835
arrow[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + arrowHeight / 2.0f);
838
paintInfo.context->drawConvexPolygon(3, arrow, true);
840
Color leftSeparatorColor(0, 0, 0, 40);
841
Color rightSeparatorColor(255, 255, 255, 40);
843
// FIXME: Should the separator thickness and space be scaled up by fontScale?
844
int separatorSpace = 2;
845
int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft); // FIXME: Round?
847
// Draw the separator to the left of the arrows
848
paintInfo.context->setStrokeThickness(1.0f);
849
paintInfo.context->setStrokeStyle(SolidStroke);
850
paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
851
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
852
IntPoint(leftEdgeOfSeparator, bounds.maxY()));
854
paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
855
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
856
IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
858
paintInfo.context->restore();
862
void RenderThemeSafari::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
864
NSControlSize controlSize = controlSizeForFont(style);
866
style->resetBorder();
867
style->resetPadding();
869
// Height is locked to auto.
870
style->setHeight(Length(Auto));
872
// White-space is locked to pre
873
style->setWhiteSpace(PRE);
875
// Set the foreground color to black or gray when we have the aqua look.
876
// Cast to RGB32 is to work around a compiler bug.
877
style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
879
// Set the button's vertical size.
880
setButtonSize(style);
882
// 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
883
// a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
884
// system font for the control size instead.
885
setFontFromControlSize(styleResolver, style, controlSize);
888
int RenderThemeSafari::popupInternalPaddingLeft(RenderStyle* style) const
890
if (style->appearance() == MenulistPart)
891
return popupButtonPadding(controlSizeForFont(style))[leftPadding];
892
if (style->appearance() == MenulistButtonPart)
893
return styledPopupPaddingLeft;
897
int RenderThemeSafari::popupInternalPaddingRight(RenderStyle* style) const
899
if (style->appearance() == MenulistPart)
900
return popupButtonPadding(controlSizeForFont(style))[rightPadding];
901
if (style->appearance() == MenulistButtonPart) {
902
float fontScale = style->fontSize() / baseFontSize;
903
float arrowWidth = baseArrowWidth * fontScale;
904
return static_cast<int>(ceilf(arrowWidth + arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator));
909
int RenderThemeSafari::popupInternalPaddingTop(RenderStyle* style) const
911
if (style->appearance() == MenulistPart)
912
return popupButtonPadding(controlSizeForFont(style))[topPadding];
913
if (style->appearance() == MenulistButtonPart)
914
return styledPopupPaddingTop;
918
int RenderThemeSafari::popupInternalPaddingBottom(RenderStyle* style) const
920
if (style->appearance() == MenulistPart)
921
return popupButtonPadding(controlSizeForFont(style))[bottomPadding];
922
if (style->appearance() == MenulistButtonPart)
923
return styledPopupPaddingBottom;
927
void RenderThemeSafari::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
929
float fontScale = style->fontSize() / baseFontSize;
931
style->resetPadding();
932
style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
934
const int minHeight = 15;
935
style->setMinHeight(Length(minHeight, Fixed));
937
style->setLineHeight(RenderStyle::initialLineHeight());
940
const IntSize* RenderThemeSafari::menuListSizes() const
942
static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
946
int RenderThemeSafari::minimumMenuListSize(RenderStyle* style) const
948
return sizeForSystemFont(style, menuListSizes()).width();
951
const int trackWidth = 5;
952
const int trackRadius = 2;
954
bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
956
IntSize radius(trackRadius, trackRadius);
957
RoundedRect bounds(r, radius, radius, radius, radius);
959
if (o->style()->appearance() == SliderHorizontalPart)
960
bounds.setRect(IntRect(r.x(),
961
r.y() + r.height() / 2 - trackWidth / 2,
964
else if (o->style()->appearance() == SliderVerticalPart)
965
bounds.setRect(IntRect(r.x() + r.width() / 2 - trackWidth / 2,
970
CGContextRef context = paintInfo.context->platformContext();
971
CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
973
paintInfo.context->save();
974
CGContextClipToRect(context, bounds.rect());
976
struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
977
RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
978
RetainPtr<CGShadingRef> mainShading;
979
if (o->style()->appearance() == SliderVerticalPart)
980
mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().maxY()), CGPointMake(bounds.rect().maxX(), bounds.rect().maxY()), mainFunction.get(), false, false));
982
mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().y()), CGPointMake(bounds.rect().x(), bounds.rect().maxY()), mainFunction.get(), false, false));
984
paintInfo.context->addRoundedRectClip(bounds);
985
CGContextDrawShading(context, mainShading.get());
986
paintInfo.context->restore();
991
void RenderThemeSafari::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
993
RenderTheme::adjustSliderThumbStyle(styleResolver, style, e);
994
style->setBoxShadow(nullptr);
997
const float verticalSliderHeightPadding = 0.1f;
999
bool RenderThemeSafari::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1001
ASSERT(SafariThemeLibrary());
1002
paintThemePart(SliderThumbPart, paintInfo.context->platformContext(), r, NSSmallControlSize, determineState(o));
1006
const int sliderThumbWidth = 15;
1007
const int sliderThumbHeight = 15;
1009
void RenderThemeSafari::adjustSliderThumbSize(RenderStyle* style, Element*) const
1011
if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
1012
style->setWidth(Length(sliderThumbWidth, Fixed));
1013
style->setHeight(Length(sliderThumbHeight, Fixed));
1016
else if (style->appearance() == MediaSliderThumbPart)
1017
RenderMediaControls::adjustMediaSliderThumbSize(style);
1021
bool RenderThemeSafari::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1023
ASSERT(SafariThemeLibrary());
1025
paintThemePart(SafariTheme::SearchFieldPart, paintInfo.context->platformContext(), r, controlSizeFromRect(r, searchFieldSizes()), determineState(o));
1029
const IntSize* RenderThemeSafari::searchFieldSizes() const
1031
static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 15) };
1035
void RenderThemeSafari::setSearchFieldSize(RenderStyle* style) const
1037
// If the width and height are both specified, then we have nothing to do.
1038
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1041
// Use the font size to determine the intrinsic width of the control.
1042
setSizeFromFont(style, searchFieldSizes());
1045
void RenderThemeSafari::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
1048
style->resetBorder();
1049
const short borderWidth = 2;
1050
style->setBorderLeftWidth(borderWidth);
1051
style->setBorderLeftStyle(INSET);
1052
style->setBorderRightWidth(borderWidth);
1053
style->setBorderRightStyle(INSET);
1054
style->setBorderBottomWidth(borderWidth);
1055
style->setBorderBottomStyle(INSET);
1056
style->setBorderTopWidth(borderWidth);
1057
style->setBorderTopStyle(INSET);
1060
style->setHeight(Length(Auto));
1061
setSearchFieldSize(style);
1063
// Override padding size to match AppKit text positioning.
1064
const int padding = 1;
1065
style->setPaddingLeft(Length(padding, Fixed));
1066
style->setPaddingRight(Length(padding, Fixed));
1067
style->setPaddingTop(Length(padding, Fixed));
1068
style->setPaddingBottom(Length(padding, Fixed));
1070
NSControlSize controlSize = controlSizeForFont(style);
1071
setFontFromControlSize(styleResolver, style, controlSize);
1074
bool RenderThemeSafari::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
1076
ASSERT(SafariThemeLibrary());
1078
Node* input = o->node()->shadowHost();
1081
RenderObject* renderer = input->renderer();
1084
IntRect searchRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
1086
paintThemePart(SafariTheme::SearchFieldCancelButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1090
const IntSize* RenderThemeSafari::cancelButtonSizes() const
1092
static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1096
void RenderThemeSafari::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1098
IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1099
style->setWidth(Length(size.width(), Fixed));
1100
style->setHeight(Length(size.height(), Fixed));
1103
const IntSize* RenderThemeSafari::resultsButtonSizes() const
1105
static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1109
const int emptyResultsOffset = 9;
1110
void RenderThemeSafari::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
1112
IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1113
style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1114
style->setHeight(Length(size.height(), Fixed));
1117
bool RenderThemeSafari::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1122
void RenderThemeSafari::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
1124
IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1125
style->setWidth(Length(size.width(), Fixed));
1126
style->setHeight(Length(size.height(), Fixed));
1129
bool RenderThemeSafari::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
1131
ASSERT(SafariThemeLibrary());
1133
Node* input = o->node()->shadowHost();
1136
RenderObject* renderer = input->renderer();
1139
IntRect searchRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
1141
paintThemePart(SafariTheme::SearchFieldResultsDecorationPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1145
const int resultsArrowWidth = 5;
1146
void RenderThemeSafari::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1148
IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1149
style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1150
style->setHeight(Length(size.height(), Fixed));
1153
bool RenderThemeSafari::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
1155
ASSERT(SafariThemeLibrary());
1157
Node* input = o->node()->shadowHost();
1160
RenderObject* renderer = input->renderer();
1163
IntRect searchRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
1165
paintThemePart(SafariTheme::SearchFieldResultsButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
1169
bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1171
return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, o, paintInfo, r);
1174
bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1176
return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r);
1179
bool RenderThemeSafari::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1181
return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r);
1184
bool RenderThemeSafari::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1186
return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r);
1189
bool RenderThemeSafari::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1191
return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r);
1194
bool RenderThemeSafari::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1196
return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r);
1199
bool RenderThemeSafari::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1201
return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r);
1205
} // namespace WebCore
1207
#endif // #if USE(SAFARI_THEME)