1/*
2 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3 *
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.
8 *
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.
13 *
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.
18 */
19
20#import "config.h"
21#import "RenderThemeMac.h"
22
23#import "BitmapImage.h"
24#import "CSSValueKeywords.h"
25#import "CSSValueList.h"
26#import "ColorMac.h"
27#import "Document.h"
28#import "Element.h"
29#import "ExceptionCodePlaceholder.h"
30#import "FileList.h"
31#import "FrameView.h"
32#import "GraphicsContextCG.h"
33#import "HTMLInputElement.h"
34#import "HTMLMediaElement.h"
35#import "HTMLNames.h"
36#import "HTMLPlugInImageElement.h"
37#import "Image.h"
38#import "ImageBuffer.h"
39#import "LocalCurrentGraphicsContext.h"
40#import "LocalizedStrings.h"
41#import "MediaControlElements.h"
42#import "PaintInfo.h"
43#import "RenderLayer.h"
44#import "RenderMedia.h"
45#import "RenderMediaControlElements.h"
46#import "RenderMediaControls.h"
47#import "RenderProgress.h"
48#import "RenderSlider.h"
49#import "RenderSnapshottedPlugIn.h"
50#import "RenderView.h"
51#import "SharedBuffer.h"
52#import "StringTruncator.h"
53#import "StyleResolver.h"
54#import "ThemeMac.h"
55#import "TimeRanges.h"
56#import "UserAgentStyleSheets.h"
57#import "WebCoreNSCellExtras.h"
58#import "WebCoreSystemInterface.h"
59#import <wtf/RetainPtr.h>
60#import <wtf/RetainPtr.h>
61#import <wtf/StdLibExtras.h>
62#import <Carbon/Carbon.h>
63#import <Cocoa/Cocoa.h>
64#import <math.h>
65
66#if ENABLE(METER_ELEMENT)
67#include "RenderMeter.h"
68#include "HTMLMeterElement.h"
69#endif
70
71using namespace std;
72
73// The methods in this file are specific to the Mac OS X platform.
74
75// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
76
77// We estimate the animation rate of a Mac OS X progress bar is 33 fps.
78// Hard code the value here because we haven't found API for it.
79const double progressAnimationFrameRate = 0.033;
80
81// Mac OS X progress bar animation seems to have 256 frames.
82const double progressAnimationNumFrames = 256;
83
84@interface WebCoreRenderThemeNotificationObserver : NSObject
85{
86    WebCore::RenderTheme *_theme;
87}
88
89- (id)initWithTheme:(WebCore::RenderTheme *)theme;
90- (void)systemColorsDidChange:(NSNotification *)notification;
91
92@end
93
94@implementation WebCoreRenderThemeNotificationObserver
95
96- (id)initWithTheme:(WebCore::RenderTheme *)theme
97{
98    if (!(self = [super init]))
99        return nil;
100
101    _theme = theme;
102    return self;
103}
104
105- (void)systemColorsDidChange:(NSNotification *)unusedNotification
106{
107    ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
108    _theme->platformColorsDidChange();
109}
110
111@end
112
113@interface NSTextFieldCell (WKDetails)
114- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
115@end
116
117
118@interface WebCoreTextFieldCell : NSTextFieldCell
119- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
120@end
121
122@implementation WebCoreTextFieldCell
123- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
124{
125    // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
126    CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
127    CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
128    return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
129}
130@end
131
132namespace WebCore {
133
134using namespace HTMLNames;
135
136enum {
137    topMargin,
138    rightMargin,
139    bottomMargin,
140    leftMargin
141};
142
143enum {
144    topPadding,
145    rightPadding,
146    bottomPadding,
147    leftPadding
148};
149
150PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
151{
152    static RenderTheme* rt = RenderThemeMac::create().leakRef();
153    return rt;
154}
155
156PassRefPtr<RenderTheme> RenderThemeMac::create()
157{
158    return adoptRef(new RenderThemeMac);
159}
160
161RenderThemeMac::RenderThemeMac()
162    : m_isSliderThumbHorizontalPressed(false)
163    , m_isSliderThumbVerticalPressed(false)
164    , m_notificationObserver(adoptNS([[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]))
165{
166    [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
167                                                        selector:@selector(systemColorsDidChange:)
168                                                            name:NSSystemColorsDidChangeNotification
169                                                          object:nil];
170}
171
172RenderThemeMac::~RenderThemeMac()
173{
174    [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
175}
176
177NSView* RenderThemeMac::documentViewFor(RenderObject* o) const
178{
179    return ThemeMac::ensuredView(o->view()->frameView());
180}
181
182#if ENABLE(VIDEO)
183
184typedef enum {
185    MediaControllerThemeClassic   = 1,
186    MediaControllerThemeQuickTime = 2
187} MediaControllerThemeStyle;
188
189static int mediaControllerTheme()
190{
191    static int controllerTheme = -1;
192
193    if (controllerTheme != -1)
194        return controllerTheme;
195
196    controllerTheme = MediaControllerThemeClassic;
197
198    Boolean validKey;
199    Boolean useQTMediaUIPref = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey);
200
201    if (validKey && !useQTMediaUIPref)
202        return controllerTheme;
203
204    controllerTheme = MediaControllerThemeQuickTime;
205    return controllerTheme;
206}
207
208const int mediaSliderThumbWidth = 13;
209const int mediaSliderThumbHeight = 14;
210
211void RenderThemeMac::adjustMediaSliderThumbSize(RenderStyle* style) const
212{
213    int wkPart;
214    switch (style->appearance()) {
215    case MediaSliderThumbPart:
216        wkPart = MediaSliderThumb;
217        break;
218    case MediaVolumeSliderThumbPart:
219        wkPart = MediaVolumeSliderThumb;
220        break;
221    case MediaFullScreenVolumeSliderThumbPart:
222        wkPart = MediaFullScreenVolumeSliderThumb;
223        break;
224    default:
225        return;
226    }
227
228    int width = mediaSliderThumbWidth;
229    int height = mediaSliderThumbHeight;
230
231    if (mediaControllerTheme() == MediaControllerThemeQuickTime) {
232        CGSize size;
233        wkMeasureMediaUIPart(wkPart, MediaControllerThemeQuickTime, NULL, &size);
234        width = size.width;
235        height = size.height;
236    }
237
238    float zoomLevel = style->effectiveZoom();
239    style->setWidth(Length(static_cast<int>(width * zoomLevel), Fixed));
240    style->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed));
241}
242
243enum WKMediaControllerThemeState {
244    MediaUIPartDisabledFlag = 1 << 0,
245    MediaUIPartPressedFlag = 1 << 1,
246    MediaUIPartDrawEndCapsFlag = 1 << 3,
247};
248
249static unsigned getMediaUIPartStateFlags(Node* node)
250{
251    unsigned flags = 0;
252
253    if (isDisabledFormControl(node))
254        flags |= MediaUIPartDisabledFlag;
255    else if (node->isElementNode() && toElement(node)->active())
256        flags |= MediaUIPartPressedFlag;
257    return flags;
258}
259
260// Utility to scale when the UI part are not scaled by wkDrawMediaUIPart
261static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const PaintInfo& paintInfo, const IntRect &originalRect)
262{
263    float zoomLevel = o->style()->effectiveZoom();
264    FloatRect unzoomedRect(originalRect);
265    if (zoomLevel != 1.0f && mediaControllerTheme() == MediaControllerThemeQuickTime) {
266        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
267        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
268        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
269        paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
270        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
271    }
272    return unzoomedRect;
273}
274
275bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
276{
277    Node* node = o->node();
278    if (!node)
279        return false;
280
281    if (node->isMediaControlElement()) {
282        LocalCurrentGraphicsContext localContext(paintInfo.context);
283        wkDrawMediaUIPart(mediaControlElementType(node), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
284    }
285    return false;
286}
287
288bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
289{
290    Node* node = o->node();
291    Node* mediaNode = node ? node->shadowHost() : 0;
292    if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
293        return false;
294
295    if (node->isMediaControlElement()) {
296        LocalCurrentGraphicsContext localContext(paintInfo.context);
297        wkDrawMediaUIPart(mediaControlElementType(node), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
298    }
299    return false;
300}
301
302bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
303{
304    Node* node = o->node();
305    Node* mediaNode = node ? node->shadowHost() : 0;
306    if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
307        return false;
308
309    if (node->isMediaControlElement()) {
310        LocalCurrentGraphicsContext localContext(paintInfo.context);
311        wkDrawMediaUIPart(mediaControlElementType(node), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
312    }
313    return false;
314}
315
316bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
317{
318    Node* node = o->node();
319    if (!node)
320        return false;
321
322    LocalCurrentGraphicsContext localContext(paintInfo.context);
323    wkDrawMediaUIPart(MediaSeekBackButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
324    return false;
325}
326
327bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
328{
329    Node* node = o->node();
330    if (!node)
331        return false;
332
333    LocalCurrentGraphicsContext localContext(paintInfo.context);
334    wkDrawMediaUIPart(MediaSeekForwardButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
335    return false;
336}
337
338bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
339{
340    Node* node = o->node();
341    Element* mediaNode = node ? node->shadowHost() : 0;
342    if (!mediaNode || !mediaNode->isMediaElement())
343        return false;
344
345    HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
346    if (!mediaElement)
347        return false;
348
349    RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
350    float timeLoaded = timeRanges->length() ? timeRanges->end(0, IGNORE_EXCEPTION) : 0;
351    float currentTime = mediaElement->currentTime();
352    float duration = mediaElement->duration();
353    if (std::isnan(duration))
354        duration = 0;
355
356    ContextContainer cgContextContainer(paintInfo.context);
357    CGContextRef context = cgContextContainer.context();
358    GraphicsContextStateSaver stateSaver(*paintInfo.context);
359    FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
360    wkDrawMediaSliderTrack(mediaControllerTheme(), context, unzoomedRect,
361        timeLoaded, currentTime, duration, getMediaUIPartStateFlags(node));
362    return false;
363}
364
365bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
366{
367    Node* node = o->node();
368    if (!node)
369        return false;
370
371    LocalCurrentGraphicsContext localContext(paintInfo.context);
372    wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
373    return false;
374}
375
376bool RenderThemeMac::paintMediaRewindButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
377{
378    Node* node = o->node();
379    if (!node)
380        return false;
381
382    LocalCurrentGraphicsContext localContext(paintInfo.context);
383    wkDrawMediaUIPart(MediaRewindButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
384    return false;
385}
386
387bool RenderThemeMac::paintMediaReturnToRealtimeButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
388{
389    Node* node = o->node();
390    if (!node)
391        return false;
392
393    LocalCurrentGraphicsContext localContext(paintInfo.context);
394    wkDrawMediaUIPart(MediaReturnToRealtimeButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
395    return false;
396}
397
398bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
399{
400    Node* node = o->node();
401    if (!node)
402        return false;
403
404    LocalCurrentGraphicsContext localContext(paintInfo.context);
405    wkDrawMediaUIPart(MediaTimelineContainer, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
406    return false;
407}
408
409bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
410{
411    Node* node = o->node();
412    if (!node)
413        return false;
414
415    ContextContainer cgContextContainer(paintInfo.context);
416    GraphicsContextStateSaver stateSaver(*paintInfo.context);
417    FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
418    wkDrawMediaUIPart(MediaCurrentTimeDisplay, mediaControllerTheme(), cgContextContainer.context(), unzoomedRect, getMediaUIPartStateFlags(node));
419    return false;
420}
421
422bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
423{
424    Node* node = o->node();
425    if (!node)
426        return false;
427
428    ContextContainer cgContextContainer(paintInfo.context);
429    GraphicsContextStateSaver stateSaver(*paintInfo.context);
430    FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
431    wkDrawMediaUIPart(MediaTimeRemainingDisplay, mediaControllerTheme(), cgContextContainer.context(), unzoomedRect, getMediaUIPartStateFlags(node));
432    return false;
433}
434
435bool RenderThemeMac::paintMediaVolumeSliderContainer(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
436{
437    Node* node = o->node();
438    if (!node)
439        return false;
440
441    LocalCurrentGraphicsContext localContext(paintInfo.context);
442    wkDrawMediaUIPart(MediaVolumeSliderContainer, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
443    return false;
444}
445
446bool RenderThemeMac::paintMediaVolumeSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
447{
448    Node* node = o->node();
449    if (!node)
450        return false;
451
452    LocalCurrentGraphicsContext localContext(paintInfo.context);
453    wkDrawMediaUIPart(MediaVolumeSlider, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
454    return false;
455}
456
457bool RenderThemeMac::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
458{
459    Node* node = o->node();
460    if (!node)
461        return false;
462
463    LocalCurrentGraphicsContext localContext(paintInfo.context);
464    wkDrawMediaUIPart(MediaVolumeSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
465    return false;
466}
467
468bool RenderThemeMac::paintMediaFullScreenVolumeSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
469{
470    Node* node = o->node();
471    if (!node)
472        return false;
473
474    LocalCurrentGraphicsContext localContext(paintInfo.context);
475    wkDrawMediaUIPart(MediaFullScreenVolumeSlider, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
476    return false;
477}
478
479bool RenderThemeMac::paintMediaFullScreenVolumeSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
480{
481    Node* node = o->node();
482    if (!node)
483        return false;
484
485    LocalCurrentGraphicsContext localContext(paintInfo.context);
486    wkDrawMediaUIPart(MediaFullScreenVolumeSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
487    return false;
488}
489
490String RenderThemeMac::extraMediaControlsStyleSheet()
491{
492    if (mediaControllerTheme() == MediaControllerThemeQuickTime)
493        return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet));
494
495    return String();
496}
497
498#if ENABLE(FULLSCREEN_API)
499String RenderThemeMac::extraFullScreenStyleSheet()
500{
501    if (mediaControllerTheme() == MediaControllerThemeQuickTime)
502        return String(fullscreenQuickTimeUserAgentStyleSheet, sizeof(fullscreenQuickTimeUserAgentStyleSheet));
503
504    return String();
505}
506#endif
507
508bool RenderThemeMac::hasOwnDisabledStateHandlingFor(ControlPart part) const
509{
510    if (part == MediaMuteButtonPart)
511        return false;
512
513    return mediaControllerTheme() == MediaControllerThemeClassic;
514}
515
516bool RenderThemeMac::usesMediaControlStatusDisplay()
517{
518    return mediaControllerTheme() == MediaControllerThemeQuickTime;
519}
520
521bool RenderThemeMac::usesMediaControlVolumeSlider() const
522{
523    return mediaControllerTheme() == MediaControllerThemeQuickTime;
524}
525
526IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const
527{
528    return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size);
529}
530
531#endif // ENABLE(VIDEO)
532
533Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
534{
535    NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
536    return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
537}
538
539Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
540{
541    NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
542    return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
543}
544
545Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const
546{
547    NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
548    return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
549}
550
551Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const
552{
553    return Color::white;
554}
555
556Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const
557{
558    return Color::black;
559}
560
561Color RenderThemeMac::platformFocusRingColor() const
562{
563    if (usesTestModeFocusRingColor())
564        return oldAquaFocusRingColor();
565
566    return systemColor(CSSValueWebkitFocusRingColor);
567}
568
569Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const
570{
571    return platformInactiveSelectionBackgroundColor();
572}
573
574static FontWeight toFontWeight(NSInteger appKitFontWeight)
575{
576    ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
577    if (appKitFontWeight > 14)
578        appKitFontWeight = 14;
579    else if (appKitFontWeight < 1)
580        appKitFontWeight = 1;
581
582    static FontWeight fontWeights[] = {
583        FontWeight100,
584        FontWeight100,
585        FontWeight200,
586        FontWeight300,
587        FontWeight400,
588        FontWeight500,
589        FontWeight600,
590        FontWeight600,
591        FontWeight700,
592        FontWeight800,
593        FontWeight800,
594        FontWeight900,
595        FontWeight900,
596        FontWeight900
597    };
598    return fontWeights[appKitFontWeight - 1];
599}
600
601void RenderThemeMac::systemFont(int cssValueId, FontDescription& fontDescription) const
602{
603    DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
604    DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
605    DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
606    DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
607    DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
608    DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
609    DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
610
611    FontDescription* cachedDesc;
612    NSFont* font = nil;
613    switch (cssValueId) {
614        case CSSValueSmallCaption:
615            cachedDesc = &smallSystemFont;
616            if (!smallSystemFont.isAbsoluteSize())
617                font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
618            break;
619        case CSSValueMenu:
620            cachedDesc = &menuFont;
621            if (!menuFont.isAbsoluteSize())
622                font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
623            break;
624        case CSSValueStatusBar:
625            cachedDesc = &labelFont;
626            if (!labelFont.isAbsoluteSize())
627                font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
628            break;
629        case CSSValueWebkitMiniControl:
630            cachedDesc = &miniControlFont;
631            if (!miniControlFont.isAbsoluteSize())
632                font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
633            break;
634        case CSSValueWebkitSmallControl:
635            cachedDesc = &smallControlFont;
636            if (!smallControlFont.isAbsoluteSize())
637                font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
638            break;
639        case CSSValueWebkitControl:
640            cachedDesc = &controlFont;
641            if (!controlFont.isAbsoluteSize())
642                font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
643            break;
644        default:
645            cachedDesc = &systemFont;
646            if (!systemFont.isAbsoluteSize())
647                font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
648    }
649
650    if (font) {
651        NSFontManager *fontManager = [NSFontManager sharedFontManager];
652        cachedDesc->setIsAbsoluteSize(true);
653        cachedDesc->setGenericFamily(FontDescription::NoFamily);
654        cachedDesc->setOneFamily([font webCoreFamilyName]);
655        cachedDesc->setSpecifiedSize([font pointSize]);
656        cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font]));
657        cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
658    }
659    fontDescription = *cachedDesc;
660}
661
662static RGBA32 convertNSColorToColor(NSColor *color)
663{
664    NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
665    if (colorInColorSpace) {
666        static const double scaleFactor = nextafter(256.0, 0.0);
667        return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
668            static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
669            static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
670    }
671
672    // This conversion above can fail if the NSColor in question is an NSPatternColor
673    // (as many system colors are). These colors are actually a repeating pattern
674    // not just a solid color. To work around this we simply draw a 1x1 image of
675    // the color and use that pixel's color. It might be better to use an average of
676    // the colors in the pattern instead.
677    NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
678                                                                             pixelsWide:1
679                                                                             pixelsHigh:1
680                                                                          bitsPerSample:8
681                                                                        samplesPerPixel:4
682                                                                               hasAlpha:YES
683                                                                               isPlanar:NO
684                                                                         colorSpaceName:NSDeviceRGBColorSpace
685                                                                            bytesPerRow:4
686                                                                           bitsPerPixel:32];
687
688    [NSGraphicsContext saveGraphicsState];
689    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
690    NSEraseRect(NSMakeRect(0, 0, 1, 1));
691    [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
692    [NSGraphicsContext restoreGraphicsState];
693
694    NSUInteger pixel[4];
695    [offscreenRep getPixel:pixel atX:0 y:0];
696
697    [offscreenRep release];
698
699    return makeRGB(pixel[0], pixel[1], pixel[2]);
700}
701
702static RGBA32 menuBackgroundColor()
703{
704    NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
705                                                                             pixelsWide:1
706                                                                             pixelsHigh:1
707                                                                          bitsPerSample:8
708                                                                        samplesPerPixel:4
709                                                                               hasAlpha:YES
710                                                                               isPlanar:NO
711                                                                         colorSpaceName:NSDeviceRGBColorSpace
712                                                                            bytesPerRow:4
713                                                                           bitsPerPixel:32];
714
715    CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
716    CGRect rect = CGRectMake(0, 0, 1, 1);
717    HIThemeMenuDrawInfo drawInfo;
718    drawInfo.version =  0;
719    drawInfo.menuType = kThemeMenuTypePopUp;
720    HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
721
722    NSUInteger pixel[4];
723    [offscreenRep getPixel:pixel atX:0 y:0];
724
725    [offscreenRep release];
726
727    return makeRGB(pixel[0], pixel[1], pixel[2]);
728}
729
730void RenderThemeMac::platformColorsDidChange()
731{
732    m_systemColorCache.clear();
733    RenderTheme::platformColorsDidChange();
734}
735
736Color RenderThemeMac::systemColor(int cssValueId) const
737{
738    {
739        HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
740        if (it != m_systemColorCache.end())
741            return it->value;
742    }
743
744    Color color;
745    switch (cssValueId) {
746        case CSSValueActiveborder:
747            color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
748            break;
749        case CSSValueActivecaption:
750            color = convertNSColorToColor([NSColor windowFrameTextColor]);
751            break;
752        case CSSValueAppworkspace:
753            color = convertNSColorToColor([NSColor headerColor]);
754            break;
755        case CSSValueBackground:
756            // Use theme independent default
757            break;
758        case CSSValueButtonface:
759            // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
760            // We may want to change this to use the NSColor in future.
761            color = 0xFFC0C0C0;
762            break;
763        case CSSValueButtonhighlight:
764            color = convertNSColorToColor([NSColor controlHighlightColor]);
765            break;
766        case CSSValueButtonshadow:
767            color = convertNSColorToColor([NSColor controlShadowColor]);
768            break;
769        case CSSValueButtontext:
770            color = convertNSColorToColor([NSColor controlTextColor]);
771            break;
772        case CSSValueCaptiontext:
773            color = convertNSColorToColor([NSColor textColor]);
774            break;
775        case CSSValueGraytext:
776            color = convertNSColorToColor([NSColor disabledControlTextColor]);
777            break;
778        case CSSValueHighlight:
779            color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
780            break;
781        case CSSValueHighlighttext:
782            color = convertNSColorToColor([NSColor selectedTextColor]);
783            break;
784        case CSSValueInactiveborder:
785            color = convertNSColorToColor([NSColor controlBackgroundColor]);
786            break;
787        case CSSValueInactivecaption:
788            color = convertNSColorToColor([NSColor controlBackgroundColor]);
789            break;
790        case CSSValueInactivecaptiontext:
791            color = convertNSColorToColor([NSColor textColor]);
792            break;
793        case CSSValueInfobackground:
794            // There is no corresponding NSColor for this so we use a hard coded value.
795            color = 0xFFFBFCC5;
796            break;
797        case CSSValueInfotext:
798            color = convertNSColorToColor([NSColor textColor]);
799            break;
800        case CSSValueMenu:
801            color = menuBackgroundColor();
802            break;
803        case CSSValueMenutext:
804            color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
805            break;
806        case CSSValueScrollbar:
807            color = convertNSColorToColor([NSColor scrollBarColor]);
808            break;
809        case CSSValueText:
810            color = convertNSColorToColor([NSColor textColor]);
811            break;
812        case CSSValueThreeddarkshadow:
813            color = convertNSColorToColor([NSColor controlDarkShadowColor]);
814            break;
815        case CSSValueThreedshadow:
816            color = convertNSColorToColor([NSColor shadowColor]);
817            break;
818        case CSSValueThreedface:
819            // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
820            // We may want to change this to use the NSColor in future.
821            color = 0xFFC0C0C0;
822            break;
823        case CSSValueThreedhighlight:
824            color = convertNSColorToColor([NSColor highlightColor]);
825            break;
826        case CSSValueThreedlightshadow:
827            color = convertNSColorToColor([NSColor controlLightHighlightColor]);
828            break;
829        case CSSValueWebkitFocusRingColor:
830            color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
831            break;
832        case CSSValueWindow:
833            color = convertNSColorToColor([NSColor windowBackgroundColor]);
834            break;
835        case CSSValueWindowframe:
836            color = convertNSColorToColor([NSColor windowFrameColor]);
837            break;
838        case CSSValueWindowtext:
839            color = convertNSColorToColor([NSColor windowFrameTextColor]);
840            break;
841    }
842
843    if (!color.isValid())
844        color = RenderTheme::systemColor(cssValueId);
845
846    if (color.isValid())
847        m_systemColorCache.set(cssValueId, color.rgb());
848
849    return color;
850}
851
852bool RenderThemeMac::usesTestModeFocusRingColor() const
853{
854    return WebCore::usesTestModeFocusRingColor();
855}
856
857bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border,
858                                     const FillLayer& background, const Color& backgroundColor) const
859{
860    if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
861        return style->border() != border;
862
863    // FIXME: This is horrible, but there is not much else that can be done.  Menu lists cannot draw properly when
864    // scaled.  They can't really draw properly when transformed either.  We can't detect the transform case at style
865    // adjustment time so that will just have to stay broken.  We can however detect that we're zooming.  If zooming
866    // is in effect we treat it like the control is styled.
867    if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f)
868        return true;
869
870    return RenderTheme::isControlStyled(style, border, background, backgroundColor);
871}
872
873void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r)
874{
875    ControlPart part = o->style()->appearance();
876
877#if USE(NEW_THEME)
878    switch (part) {
879        case CheckboxPart:
880        case RadioPart:
881        case PushButtonPart:
882        case SquareButtonPart:
883        case DefaultButtonPart:
884        case ButtonPart:
885        case InnerSpinButtonPart:
886            return RenderTheme::adjustRepaintRect(o, r);
887        default:
888            break;
889    }
890#endif
891
892    float zoomLevel = o->style()->effectiveZoom();
893
894    if (part == MenulistPart) {
895        setPopupButtonCellState(o, r);
896        IntSize size = popupButtonSizes()[[popupButton() controlSize]];
897        size.setHeight(size.height() * zoomLevel);
898        size.setWidth(r.width());
899        r = inflateRect(r, size, popupButtonMargins(), zoomLevel);
900    }
901}
902
903IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const
904{
905    // Only do the inflation if the available width/height are too small.  Otherwise try to
906    // fit the glow/check space into the available box's width/height.
907    int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
908    int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
909    IntRect result(r);
910    if (widthDelta < 0) {
911        result.setX(result.x() - margins[leftMargin] * zoomLevel);
912        result.setWidth(result.width() - widthDelta);
913    }
914    if (heightDelta < 0) {
915        result.setY(result.y() - margins[topMargin] * zoomLevel);
916        result.setHeight(result.height() - heightDelta);
917    }
918    return result;
919}
920
921FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const
922{
923    FloatRect partRect(inputRect);
924
925    // Compute an offset between the part renderer and the input renderer
926    FloatSize offsetFromInputRenderer;
927    const RenderObject* renderer = partRenderer;
928    while (renderer && renderer != inputRenderer) {
929        RenderObject* containingRenderer = renderer->container();
930        offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint()));
931        renderer = containingRenderer;
932    }
933    // If the input renderer was not a container, something went wrong
934    ASSERT(renderer == inputRenderer);
935    // Move the rect into partRenderer's coords
936    partRect.move(offsetFromInputRenderer);
937    // Account for the local drawing offset (tx, ty)
938    partRect.move(r.x(), r.y());
939
940    return partRect;
941}
942
943void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject* o)
944{
945    bool oldIndeterminate = [cell state] == NSMixedState;
946    bool indeterminate = isIndeterminate(o);
947    bool checked = isChecked(o);
948
949    if (oldIndeterminate != indeterminate) {
950        [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
951        return;
952    }
953
954    bool oldChecked = [cell state] == NSOnState;
955    if (checked != oldChecked)
956        [cell setState:checked ? NSOnState : NSOffState];
957}
958
959void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject* o)
960{
961    bool oldEnabled = [cell isEnabled];
962    bool enabled = isEnabled(o);
963    if (enabled != oldEnabled)
964        [cell setEnabled:enabled];
965}
966
967void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o)
968{
969    bool oldFocused = [cell showsFirstResponder];
970    bool focused = isFocused(o) && o->style()->outlineStyleIsAuto();
971    if (focused != oldFocused)
972        [cell setShowsFirstResponder:focused];
973}
974
975void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o)
976{
977    bool oldPressed = [cell isHighlighted];
978    bool pressed = o->node() && o->node()->isElementNode() && toElement(o->node())->active();
979    if (pressed != oldPressed)
980        [cell setHighlighted:pressed];
981}
982
983bool RenderThemeMac::controlSupportsTints(const RenderObject* o) const
984{
985    // An alternate way to implement this would be to get the appropriate cell object
986    // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
987    // that would be that we would match AppKit behavior more closely, but a disadvantage
988    // would be that we would rely on an AppKit SPI method.
989
990    if (!isEnabled(o))
991        return false;
992
993    // Checkboxes only have tint when checked.
994    if (o->style()->appearance() == CheckboxPart)
995        return isChecked(o);
996
997    // For now assume other controls have tint if enabled.
998    return true;
999}
1000
1001NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const
1002{
1003    int fontSize = style->fontSize();
1004    if (fontSize >= 16)
1005        return NSRegularControlSize;
1006    if (fontSize >= 11)
1007        return NSSmallControlSize;
1008    return NSMiniControlSize;
1009}
1010
1011void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
1012{
1013    NSControlSize size;
1014    if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) &&
1015        minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
1016        size = NSRegularControlSize;
1017    else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) &&
1018             minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
1019        size = NSSmallControlSize;
1020    else
1021        size = NSMiniControlSize;
1022    if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
1023        [cell setControlSize:size];
1024}
1025
1026IntSize RenderThemeMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const
1027{
1028    if (style->effectiveZoom() != 1.0f) {
1029        IntSize result = sizes[controlSizeForFont(style)];
1030        return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
1031    }
1032    return sizes[controlSizeForFont(style)];
1033}
1034
1035IntSize RenderThemeMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
1036{
1037    if (style->effectiveZoom() != 1.0f) {
1038        IntSize result = sizes[controlSizeForSystemFont(style)];
1039        return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
1040    }
1041    return sizes[controlSizeForSystemFont(style)];
1042}
1043
1044void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
1045{
1046    // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
1047    IntSize size = sizeForFont(style, sizes);
1048    if (style->width().isIntrinsicOrAuto() && size.width() > 0)
1049        style->setWidth(Length(size.width(), Fixed));
1050    if (style->height().isAuto() && size.height() > 0)
1051        style->setHeight(Length(size.height(), Fixed));
1052}
1053
1054void RenderThemeMac::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const
1055{
1056    FontDescription fontDescription;
1057    fontDescription.setIsAbsoluteSize(true);
1058    fontDescription.setGenericFamily(FontDescription::SerifFamily);
1059
1060    NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
1061    fontDescription.setOneFamily([font webCoreFamilyName]);
1062    fontDescription.setComputedSize([font pointSize] * style->effectiveZoom());
1063    fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom());
1064
1065    // Reset line height
1066    style->setLineHeight(RenderStyle::initialLineHeight());
1067
1068    if (style->setFontDescription(fontDescription))
1069        style->font().update(0);
1070}
1071
1072NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle* style) const
1073{
1074    int fontSize = style->fontSize();
1075    if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
1076        return NSRegularControlSize;
1077    if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
1078        return NSSmallControlSize;
1079    return NSMiniControlSize;
1080}
1081
1082bool RenderThemeMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1083{
1084    LocalCurrentGraphicsContext localContext(paintInfo.context);
1085
1086#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
1087    bool useNSTextFieldCell = o->style()->hasAppearance()
1088        && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white
1089        && !o->style()->hasBackgroundImage();
1090
1091    // We do not use NSTextFieldCell to draw styled text fields on Lion and SnowLeopard because
1092    // there are a number of bugs on those platforms that require NSTextFieldCell to be in charge
1093    // of painting its own background. We need WebCore to paint styled backgrounds, so we'll use
1094    // this WebCoreSystemInterface function instead.
1095    if (!useNSTextFieldCell) {
1096        wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o));
1097        return false;
1098    }
1099#endif
1100
1101    NSTextFieldCell *textField = this->textField();
1102
1103    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1104
1105    [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
1106    [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
1107
1108    [textField setControlView:nil];
1109
1110    return false;
1111}
1112
1113void RenderThemeMac::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const
1114{
1115}
1116
1117bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r)
1118{
1119    if (paintInfo.context->paintingDisabled())
1120        return true;
1121
1122    LocalCurrentGraphicsContext localContext(paintInfo.context);
1123    wkDrawCapsLockIndicator(localContext.cgContext(), r);
1124
1125    return false;
1126}
1127
1128bool RenderThemeMac::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1129{
1130    LocalCurrentGraphicsContext localContext(paintInfo.context);
1131    wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
1132    return false;
1133}
1134
1135void RenderThemeMac::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
1136{
1137}
1138
1139const int* RenderThemeMac::popupButtonMargins() const
1140{
1141    static const int margins[3][4] =
1142    {
1143        { 0, 3, 1, 3 },
1144        { 0, 3, 2, 3 },
1145        { 0, 1, 0, 1 }
1146    };
1147    return margins[[popupButton() controlSize]];
1148}
1149
1150const IntSize* RenderThemeMac::popupButtonSizes() const
1151{
1152    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1153    return sizes;
1154}
1155
1156const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
1157{
1158    static const int padding[3][4] =
1159    {
1160        { 2, 26, 3, 8 },
1161        { 2, 23, 3, 8 },
1162        { 2, 22, 3, 10 }
1163    };
1164    return padding[size];
1165}
1166
1167bool RenderThemeMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1168{
1169    LocalCurrentGraphicsContext localContext(paintInfo.context);
1170    setPopupButtonCellState(o, r);
1171
1172    NSPopUpButtonCell* popupButton = this->popupButton();
1173
1174    float zoomLevel = o->style()->effectiveZoom();
1175    IntSize size = popupButtonSizes()[[popupButton controlSize]];
1176    size.setHeight(size.height() * zoomLevel);
1177    size.setWidth(r.width());
1178
1179    // Now inflate it to account for the shadow.
1180    IntRect inflatedRect = r;
1181    if (r.width() >= minimumMenuListSize(o->style()))
1182        inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel);
1183
1184    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1185
1186    // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
1187    paintInfo.context->clip(inflatedRect);
1188
1189    if (zoomLevel != 1.0f) {
1190        inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
1191        inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
1192        paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
1193        paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1194        paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
1195    }
1196
1197    NSView *view = documentViewFor(o);
1198    [popupButton drawWithFrame:inflatedRect inView:view];
1199#if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
1200    if (isFocused(o) && o->style()->outlineStyleIsAuto())
1201        [popupButton _web_drawFocusRingWithFrame:inflatedRect inView:view];
1202#endif
1203    [popupButton setControlView:nil];
1204
1205    return false;
1206}
1207
1208#if ENABLE(METER_ELEMENT)
1209
1210IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const
1211{
1212    if (NoControlPart == renderMeter->style()->appearance())
1213        return bounds.size();
1214
1215    NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
1216    // Makes enough room for cell's intrinsic size.
1217    NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
1218    return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
1219                   bounds.height() < cellSize.height ? cellSize.height : bounds.height());
1220}
1221
1222bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1223{
1224    if (!renderObject->isMeter())
1225        return true;
1226
1227    LocalCurrentGraphicsContext localContext(paintInfo.context);
1228
1229    NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
1230    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1231
1232    [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
1233    [cell setControlView:nil];
1234    return false;
1235}
1236
1237bool RenderThemeMac::supportsMeter(ControlPart part) const
1238{
1239    switch (part) {
1240    case RelevancyLevelIndicatorPart:
1241    case DiscreteCapacityLevelIndicatorPart:
1242    case RatingLevelIndicatorPart:
1243    case MeterPart:
1244    case ContinuousCapacityLevelIndicatorPart:
1245        return true;
1246    default:
1247        return false;
1248    }
1249}
1250
1251NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
1252{
1253    switch (part) {
1254    case RelevancyLevelIndicatorPart:
1255        return NSRelevancyLevelIndicatorStyle;
1256    case DiscreteCapacityLevelIndicatorPart:
1257        return NSDiscreteCapacityLevelIndicatorStyle;
1258    case RatingLevelIndicatorPart:
1259        return NSRatingLevelIndicatorStyle;
1260    case MeterPart:
1261    case ContinuousCapacityLevelIndicatorPart:
1262    default:
1263        return NSContinuousCapacityLevelIndicatorStyle;
1264    }
1265
1266}
1267
1268NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* renderMeter) const
1269{
1270    RenderStyle* style = renderMeter->style();
1271    ASSERT(style->appearance() != NoControlPart);
1272
1273    if (!m_levelIndicator)
1274        m_levelIndicator = adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
1275    NSLevelIndicatorCell* cell = m_levelIndicator.get();
1276
1277    HTMLMeterElement* element = renderMeter->meterElement();
1278    double value = element->value();
1279
1280    // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
1281    // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
1282    switch (element->gaugeRegion()) {
1283    case HTMLMeterElement::GaugeRegionOptimum:
1284        // Make meter the green
1285        [cell setWarningValue:value + 1];
1286        [cell setCriticalValue:value + 2];
1287        break;
1288    case HTMLMeterElement::GaugeRegionSuboptimal:
1289        // Make the meter yellow
1290        [cell setWarningValue:value - 1];
1291        [cell setCriticalValue:value + 1];
1292        break;
1293    case HTMLMeterElement::GaugeRegionEvenLessGood:
1294        // Make the meter red
1295        [cell setWarningValue:value - 2];
1296        [cell setCriticalValue:value - 1];
1297        break;
1298    }
1299
1300    [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
1301    [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
1302    [cell setMinValue:element->min()];
1303    [cell setMaxValue:element->max()];
1304    RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
1305    [cell setObjectValue:valueObject.get()];
1306
1307    return cell;
1308}
1309
1310#endif
1311
1312#if ENABLE(PROGRESS_ELEMENT)
1313const IntSize* RenderThemeMac::progressBarSizes() const
1314{
1315    static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
1316    return sizes;
1317}
1318
1319const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const
1320{
1321    static const int margins[3][4] =
1322    {
1323        { 0, 0, 1, 0 },
1324        { 0, 0, 1, 0 },
1325        { 0, 0, 1, 0 },
1326    };
1327    return margins[controlSize];
1328}
1329
1330int RenderThemeMac::minimumProgressBarHeight(RenderStyle* style) const
1331{
1332    return sizeForSystemFont(style, progressBarSizes()).height();
1333}
1334
1335double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
1336{
1337    return progressAnimationFrameRate;
1338}
1339
1340double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const
1341{
1342    return progressAnimationNumFrames * progressAnimationFrameRate;
1343}
1344
1345void RenderThemeMac::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const
1346{
1347}
1348
1349bool RenderThemeMac::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1350{
1351    if (!renderObject->isProgress())
1352        return true;
1353
1354    float zoomLevel = renderObject->style()->effectiveZoom();
1355    int controlSize = controlSizeForFont(renderObject->style());
1356    IntSize size = progressBarSizes()[controlSize];
1357    size.setHeight(size.height() * zoomLevel);
1358    size.setWidth(rect.width());
1359
1360    // Now inflate it to account for the shadow.
1361    IntRect inflatedRect = rect;
1362    if (rect.height() <= minimumProgressBarHeight(renderObject->style()))
1363        inflatedRect = inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel);
1364
1365    RenderProgress* renderProgress = toRenderProgress(renderObject);
1366    HIThemeTrackDrawInfo trackInfo;
1367    trackInfo.version = 0;
1368    if (controlSize == NSRegularControlSize)
1369        trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
1370    else
1371        trackInfo.kind = renderProgress->position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
1372
1373    trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
1374    trackInfo.min = 0;
1375    trackInfo.max = numeric_limits<SInt32>::max();
1376    trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0));
1377    trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0));
1378    trackInfo.attributes = kThemeTrackHorizontal;
1379    trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
1380    trackInfo.reserved = 0;
1381    trackInfo.filler1 = 0;
1382
1383    OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size(), 1);
1384    if (!imageBuffer)
1385        return true;
1386
1387    ContextContainer cgContextContainer(imageBuffer->context());
1388    CGContextRef cgContext = cgContextContainer.context();
1389    HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
1390
1391    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1392
1393    if (!renderProgress->style()->isLeftToRightDirection()) {
1394        paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
1395        paintInfo.context->scale(FloatSize(-1, 1));
1396    }
1397
1398    paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location());
1399    return false;
1400}
1401#endif
1402
1403const float baseFontSize = 11.0f;
1404const float baseArrowHeight = 4.0f;
1405const float baseArrowWidth = 5.0f;
1406const float baseSpaceBetweenArrows = 2.0f;
1407const int arrowPaddingLeft = 6;
1408const int arrowPaddingRight = 6;
1409const int paddingBeforeSeparator = 4;
1410const int baseBorderRadius = 5;
1411const int styledPopupPaddingLeft = 8;
1412const int styledPopupPaddingTop = 1;
1413const int styledPopupPaddingBottom = 2;
1414
1415static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1416{
1417    static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
1418    static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
1419    float a = inData[0];
1420    int i = 0;
1421    for (i = 0; i < 4; i++)
1422        outData[i] = (1.0f - a) * dark[i] + a * light[i];
1423}
1424
1425static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1426{
1427    static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
1428    static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
1429    float a = inData[0];
1430    int i = 0;
1431    for (i = 0; i < 4; i++)
1432        outData[i] = (1.0f - a) * dark[i] + a * light[i];
1433}
1434
1435static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1436{
1437    static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1438    static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1439    float a = inData[0];
1440    int i = 0;
1441    for (i = 0; i < 4; i++)
1442        outData[i] = (1.0f - a) * dark[i] + a * light[i];
1443}
1444
1445static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1446{
1447    static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1448    static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1449    float a = inData[0];
1450    int i = 0;
1451    for (i = 0; i < 4; i++)
1452        outData[i] = (1.0f - a) * dark[i] + a * light[i];
1453}
1454
1455void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1456{
1457    if (r.isEmpty())
1458        return;
1459
1460    ContextContainer cgContextContainer(paintInfo.context);
1461    CGContextRef context = cgContextContainer.context();
1462
1463    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1464
1465    RoundedRect border = o->style()->getRoundedBorderFor(r, o->view());
1466    int radius = border.radii().topLeft().width();
1467
1468    CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1469
1470    FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1471    struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1472    RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1473    RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
1474
1475    FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1476    struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1477    RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1478    RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(),  bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
1479
1480    struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1481    RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1482    RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
1483
1484    RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1485
1486    RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(),  r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
1487
1488    {
1489        GraphicsContextStateSaver stateSaver(*paintInfo.context);
1490        CGContextClipToRect(context, r);
1491        paintInfo.context->clipRoundedRect(border);
1492        context = cgContextContainer.context();
1493        CGContextDrawShading(context, mainShading.get());
1494    }
1495
1496    {
1497        GraphicsContextStateSaver stateSaver(*paintInfo.context);
1498        CGContextClipToRect(context, topGradient);
1499        paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
1500        context = cgContextContainer.context();
1501        CGContextDrawShading(context, topShading.get());
1502    }
1503
1504    if (!bottomGradient.isEmpty()) {
1505        GraphicsContextStateSaver stateSaver(*paintInfo.context);
1506        CGContextClipToRect(context, bottomGradient);
1507        paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
1508        context = cgContextContainer.context();
1509        CGContextDrawShading(context, bottomShading.get());
1510    }
1511
1512    {
1513        GraphicsContextStateSaver stateSaver(*paintInfo.context);
1514        CGContextClipToRect(context, r);
1515        paintInfo.context->clipRoundedRect(border);
1516        context = cgContextContainer.context();
1517        CGContextDrawShading(context, leftShading.get());
1518        CGContextDrawShading(context, rightShading.get());
1519    }
1520}
1521
1522bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1523{
1524    IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
1525                             r.y() + o->style()->borderTopWidth(),
1526                             r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
1527                             r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
1528    // Draw the gradients to give the styled popup menu a button appearance
1529    paintMenuListButtonGradients(o, paintInfo, bounds);
1530
1531    // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds
1532    float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1533    float centerY = bounds.y() + bounds.height() / 2.0f;
1534    float arrowHeight = baseArrowHeight * fontScale;
1535    float arrowWidth = baseArrowWidth * fontScale;
1536    float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth;
1537    float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1538
1539    if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
1540        return false;
1541
1542    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1543
1544    paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace());
1545    paintInfo.context->setStrokeStyle(NoStroke);
1546
1547    FloatPoint arrow1[3];
1548    arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1549    arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1550    arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1551
1552    // Draw the top arrow
1553    paintInfo.context->drawConvexPolygon(3, arrow1, true);
1554
1555    FloatPoint arrow2[3];
1556    arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1557    arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1558    arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1559
1560    // Draw the bottom arrow
1561    paintInfo.context->drawConvexPolygon(3, arrow2, true);
1562
1563    Color leftSeparatorColor(0, 0, 0, 40);
1564    Color rightSeparatorColor(255, 255, 255, 40);
1565
1566    // FIXME: Should the separator thickness and space be scaled up by fontScale?
1567    int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1568    int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round?
1569
1570    // Draw the separator to the left of the arrows
1571    paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
1572    paintInfo.context->setStrokeStyle(SolidStroke);
1573    paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
1574    paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1575                                IntPoint(leftEdgeOfSeparator, bounds.maxY()));
1576
1577    paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
1578    paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1579                                IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
1580    return false;
1581}
1582
1583static const IntSize* menuListButtonSizes()
1584{
1585    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1586    return sizes;
1587}
1588
1589void RenderThemeMac::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
1590{
1591    NSControlSize controlSize = controlSizeForFont(style);
1592
1593    style->resetBorder();
1594    style->resetPadding();
1595
1596    // Height is locked to auto.
1597    style->setHeight(Length(Auto));
1598
1599    // White-space is locked to pre
1600    style->setWhiteSpace(PRE);
1601
1602    // Set the foreground color to black or gray when we have the aqua look.
1603    // Cast to RGB32 is to work around a compiler bug.
1604    style->setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1605
1606    // Set the button's vertical size.
1607    setSizeFromFont(style, menuListButtonSizes());
1608
1609    // 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
1610    // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1611    // system font for the control size instead.
1612    setFontFromControlSize(styleResolver, style, controlSize);
1613
1614    style->setBoxShadow(nullptr);
1615}
1616
1617int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const
1618{
1619    if (style->appearance() == MenulistPart)
1620        return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
1621    if (style->appearance() == MenulistButtonPart)
1622        return styledPopupPaddingLeft * style->effectiveZoom();
1623    return 0;
1624}
1625
1626int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const
1627{
1628    if (style->appearance() == MenulistPart)
1629        return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
1630    if (style->appearance() == MenulistButtonPart) {
1631        float fontScale = style->fontSize() / baseFontSize;
1632        float arrowWidth = baseArrowWidth * fontScale;
1633        return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
1634    }
1635    return 0;
1636}
1637
1638int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const
1639{
1640    if (style->appearance() == MenulistPart)
1641        return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
1642    if (style->appearance() == MenulistButtonPart)
1643        return styledPopupPaddingTop * style->effectiveZoom();
1644    return 0;
1645}
1646
1647int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const
1648{
1649    if (style->appearance() == MenulistPart)
1650        return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
1651    if (style->appearance() == MenulistButtonPart)
1652        return styledPopupPaddingBottom * style->effectiveZoom();
1653    return 0;
1654}
1655
1656void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1657{
1658    float fontScale = style->fontSize() / baseFontSize;
1659
1660    style->resetPadding();
1661    style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1662
1663    const int minHeight = 15;
1664    style->setMinHeight(Length(minHeight, Fixed));
1665
1666    style->setLineHeight(RenderStyle::initialLineHeight());
1667}
1668
1669void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
1670{
1671    NSPopUpButtonCell* popupButton = this->popupButton();
1672
1673    // Set the control size based off the rectangle we're painting into.
1674    setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
1675
1676    // Update the various states we respond to.
1677    updateActiveState(popupButton, o);
1678    updateCheckedState(popupButton, o);
1679    updateEnabledState(popupButton, o);
1680    updatePressedState(popupButton, o);
1681#if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
1682    updateFocusedState(popupButton, o);
1683#endif
1684}
1685
1686const IntSize* RenderThemeMac::menuListSizes() const
1687{
1688    static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1689    return sizes;
1690}
1691
1692int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const
1693{
1694    return sizeForSystemFont(style, menuListSizes()).width();
1695}
1696
1697const int trackWidth = 5;
1698const int trackRadius = 2;
1699
1700void RenderThemeMac::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
1701{
1702    style->setBoxShadow(nullptr);
1703}
1704
1705bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1706{
1707    IntRect bounds = r;
1708    float zoomLevel = o->style()->effectiveZoom();
1709    float zoomedTrackWidth = trackWidth * zoomLevel;
1710
1711    if (o->style()->appearance() ==  SliderHorizontalPart || o->style()->appearance() ==  MediaSliderPart) {
1712        bounds.setHeight(zoomedTrackWidth);
1713        bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1714    } else if (o->style()->appearance() == SliderVerticalPart) {
1715        bounds.setWidth(zoomedTrackWidth);
1716        bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1717    }
1718
1719    LocalCurrentGraphicsContext localContext(paintInfo.context);
1720    CGContextRef context = localContext.cgContext();
1721    CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1722
1723#if ENABLE(DATALIST_ELEMENT)
1724    paintSliderTicks(o, paintInfo, r);
1725#endif
1726
1727    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1728    CGContextClipToRect(context, bounds);
1729
1730    struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1731    RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1732    RetainPtr<CGShadingRef> mainShading;
1733    if (o->style()->appearance() == SliderVerticalPart)
1734        mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(),  bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
1735    else
1736        mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(),  bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
1737
1738    IntSize radius(trackRadius, trackRadius);
1739    paintInfo.context->clipRoundedRect(RoundedRect(bounds, radius, radius, radius, radius));
1740    context = localContext.cgContext();
1741    CGContextDrawShading(context, mainShading.get());
1742
1743    return false;
1744}
1745
1746void RenderThemeMac::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
1747{
1748    RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
1749    style->setBoxShadow(nullptr);
1750}
1751
1752const float verticalSliderHeightPadding = 0.1f;
1753
1754bool RenderThemeMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1755{
1756    NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart
1757        ? sliderThumbVertical()
1758        : sliderThumbHorizontal();
1759
1760    LocalCurrentGraphicsContext localContext(paintInfo.context);
1761
1762    // Update the various states we respond to.
1763    updateActiveState(sliderThumbCell, o);
1764    updateEnabledState(sliderThumbCell, o);
1765    Element* focusDelegate = (o->node() && o->node()->isElementNode()) ? toElement(o->node())->focusDelegate() : 0;
1766    updateFocusedState(sliderThumbCell, focusDelegate ? focusDelegate->renderer() : 0);
1767
1768    // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1769    bool oldPressed;
1770    if (o->style()->appearance() == SliderThumbVerticalPart)
1771        oldPressed = m_isSliderThumbVerticalPressed;
1772    else
1773        oldPressed = m_isSliderThumbHorizontalPressed;
1774
1775    bool pressed = isPressed(o);
1776
1777    if (o->style()->appearance() == SliderThumbVerticalPart)
1778        m_isSliderThumbVerticalPressed = pressed;
1779    else
1780        m_isSliderThumbHorizontalPressed = pressed;
1781
1782    if (pressed != oldPressed) {
1783        if (pressed)
1784            [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1785        else
1786            [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1787    }
1788
1789    FloatRect bounds = r;
1790    // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1791    if (o->style()->appearance() == SliderThumbVerticalPart)
1792        bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom());
1793
1794    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1795    float zoomLevel = o->style()->effectiveZoom();
1796
1797    FloatRect unzoomedRect = bounds;
1798    if (zoomLevel != 1.0f) {
1799        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1800        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1801        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1802        paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1803        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1804    }
1805
1806    [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
1807    [sliderThumbCell setControlView:nil];
1808
1809    return false;
1810}
1811
1812bool RenderThemeMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1813{
1814    LocalCurrentGraphicsContext localContext(paintInfo.context);
1815    NSSearchFieldCell* search = this->search();
1816
1817    setSearchCellState(o, r);
1818
1819    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1820
1821    float zoomLevel = o->style()->effectiveZoom();
1822
1823    IntRect unzoomedRect = r;
1824
1825    if (zoomLevel != 1.0f) {
1826        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1827        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1828        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1829        paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1830        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1831    }
1832
1833    // Set the search button to nil before drawing.  Then reset it so we can draw it later.
1834    [search setSearchButtonCell:nil];
1835
1836    [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1837
1838    [search setControlView:nil];
1839    [search resetSearchButtonCell];
1840
1841    return false;
1842}
1843
1844void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&)
1845{
1846    NSSearchFieldCell* search = this->search();
1847
1848    [search setControlSize:controlSizeForFont(o->style())];
1849
1850    // Update the various states we respond to.
1851    updateActiveState(search, o);
1852    updateEnabledState(search, o);
1853    updateFocusedState(search, o);
1854}
1855
1856const IntSize* RenderThemeMac::searchFieldSizes() const
1857{
1858    static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1859    return sizes;
1860}
1861
1862void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const
1863{
1864    // If the width and height are both specified, then we have nothing to do.
1865    if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1866        return;
1867
1868    // Use the font size to determine the intrinsic width of the control.
1869    setSizeFromFont(style, searchFieldSizes());
1870}
1871
1872void RenderThemeMac::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const
1873{
1874    // Override border.
1875    style->resetBorder();
1876    const short borderWidth = 2 * style->effectiveZoom();
1877    style->setBorderLeftWidth(borderWidth);
1878    style->setBorderLeftStyle(INSET);
1879    style->setBorderRightWidth(borderWidth);
1880    style->setBorderRightStyle(INSET);
1881    style->setBorderBottomWidth(borderWidth);
1882    style->setBorderBottomStyle(INSET);
1883    style->setBorderTopWidth(borderWidth);
1884    style->setBorderTopStyle(INSET);
1885
1886    // Override height.
1887    style->setHeight(Length(Auto));
1888    setSearchFieldSize(style);
1889
1890    // Override padding size to match AppKit text positioning.
1891    const int padding = 1 * style->effectiveZoom();
1892    style->setPaddingLeft(Length(padding, Fixed));
1893    style->setPaddingRight(Length(padding, Fixed));
1894    style->setPaddingTop(Length(padding, Fixed));
1895    style->setPaddingBottom(Length(padding, Fixed));
1896
1897    NSControlSize controlSize = controlSizeForFont(style);
1898    setFontFromControlSize(styleResolver, style, controlSize);
1899
1900    style->setBoxShadow(nullptr);
1901}
1902
1903bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1904{
1905    Element* input = o->node()->shadowHost();
1906    if (!input)
1907        input = toElement(o->node());
1908
1909    if (!input->renderer()->isBox())
1910        return false;
1911
1912    LocalCurrentGraphicsContext localContext(paintInfo.context);
1913    setSearchCellState(input->renderer(), r);
1914
1915    NSSearchFieldCell* search = this->search();
1916
1917    if (!input->isDisabledFormControl() && (input->isTextFormControl() && !toHTMLTextFormControlElement(input)->isReadOnly())) {
1918        updateActiveState([search cancelButtonCell], o);
1919        updatePressedState([search cancelButtonCell], o);
1920    }
1921    else if ([[search cancelButtonCell] isHighlighted])
1922        [[search cancelButtonCell] setHighlighted:NO];
1923
1924    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1925
1926    float zoomLevel = o->style()->effectiveZoom();
1927
1928    FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1929
1930#if ENABLE(INPUT_SPEECH)
1931    // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g.
1932    // when speech input is enabled for the input element.
1933    IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect();
1934    int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight();
1935    int spaceToRightOfCancelButton = absRight - (r.x() + r.width());
1936    localBounds.setX(localBounds.x() - spaceToRightOfCancelButton);
1937#endif
1938
1939    localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1940
1941    FloatRect unzoomedRect(localBounds);
1942    if (zoomLevel != 1.0f) {
1943        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1944        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1945        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1946        paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1947        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1948    }
1949
1950    [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1951    [[search cancelButtonCell] setControlView:nil];
1952    return false;
1953}
1954
1955const IntSize* RenderThemeMac::cancelButtonSizes() const
1956{
1957    static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1958    return sizes;
1959}
1960
1961void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1962{
1963    IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1964    style->setWidth(Length(size.width(), Fixed));
1965    style->setHeight(Length(size.height(), Fixed));
1966    style->setBoxShadow(nullptr);
1967}
1968
1969const IntSize* RenderThemeMac::resultsButtonSizes() const
1970{
1971    static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1972    return sizes;
1973}
1974
1975const int emptyResultsOffset = 9;
1976void RenderThemeMac::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
1977{
1978    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1979    style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1980    style->setHeight(Length(size.height(), Fixed));
1981    style->setBoxShadow(nullptr);
1982}
1983
1984bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1985{
1986    return false;
1987}
1988
1989void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
1990{
1991    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1992    style->setWidth(Length(size.width(), Fixed));
1993    style->setHeight(Length(size.height(), Fixed));
1994    style->setBoxShadow(nullptr);
1995}
1996
1997bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1998{
1999    Node* input = o->node()->shadowHost();
2000    if (!input)
2001        input = o->node();
2002    if (!input->renderer()->isBox())
2003        return false;
2004
2005    LocalCurrentGraphicsContext localContext(paintInfo.context);
2006    setSearchCellState(input->renderer(), r);
2007
2008    NSSearchFieldCell* search = this->search();
2009
2010    if ([search searchMenuTemplate] != nil)
2011        [search setSearchMenuTemplate:nil];
2012
2013    updateActiveState([search searchButtonCell], o);
2014
2015    FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
2016    localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
2017
2018    [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
2019    [[search searchButtonCell] setControlView:nil];
2020    return false;
2021}
2022
2023const int resultsArrowWidth = 5;
2024void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
2025{
2026    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
2027    style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
2028    style->setHeight(Length(size.height(), Fixed));
2029    style->setBoxShadow(nullptr);
2030}
2031
2032bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
2033{
2034    Node* input = o->node()->shadowHost();
2035    if (!input)
2036        input = o->node();
2037    if (!input->renderer()->isBox())
2038        return false;
2039
2040    LocalCurrentGraphicsContext localContext(paintInfo.context);
2041    setSearchCellState(input->renderer(), r);
2042
2043    NSSearchFieldCell* search = this->search();
2044
2045    updateActiveState([search searchButtonCell], o);
2046
2047    if (![search searchMenuTemplate])
2048        [search setSearchMenuTemplate:searchMenuTemplate()];
2049
2050    GraphicsContextStateSaver stateSaver(*paintInfo.context);
2051    float zoomLevel = o->style()->effectiveZoom();
2052
2053    FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
2054    localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
2055
2056    IntRect unzoomedRect(localBounds);
2057    if (zoomLevel != 1.0f) {
2058        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
2059        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
2060        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
2061        paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
2062        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
2063    }
2064
2065    [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
2066    [[search searchButtonCell] setControlView:nil];
2067
2068    return false;
2069}
2070
2071bool RenderThemeMac::paintSnapshottedPluginOverlay(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
2072{
2073    if (paintInfo.phase != PaintPhaseBlockBackground)
2074        return true;
2075
2076    if (!o->isRenderBlock())
2077        return true;
2078
2079    RenderBlock* renderBlock = toRenderBlock(o);
2080
2081    LayoutUnit contentWidth = renderBlock->contentWidth();
2082    LayoutUnit contentHeight = renderBlock->contentHeight();
2083    if (!contentWidth || !contentHeight)
2084        return true;
2085
2086    GraphicsContext* context = paintInfo.context;
2087
2088    LayoutSize contentSize(contentWidth, contentHeight);
2089    LayoutPoint contentLocation = renderBlock->location();
2090    contentLocation.move(renderBlock->borderLeft() + renderBlock->paddingLeft(), renderBlock->borderTop() + renderBlock->paddingTop());
2091
2092    LayoutRect rect(contentLocation, contentSize);
2093    IntRect alignedRect = pixelSnappedIntRect(rect);
2094    if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
2095        return true;
2096
2097    // We need to get the snapshot image from the plugin element, which should be available
2098    // from our node. Assuming this node is the plugin overlay element, we should get to the
2099    // plugin itself by asking for the shadow root parent, and then its parent.
2100
2101    if (!renderBlock->node()->isHTMLElement())
2102        return true;
2103
2104    HTMLElement* plugInOverlay = toHTMLElement(renderBlock->node());
2105    Element* parent = plugInOverlay->parentOrShadowHostElement();
2106    while (parent && !parent->isPluginElement())
2107        parent = parent->parentOrShadowHostElement();
2108
2109    if (!parent)
2110        return true;
2111
2112    HTMLPlugInElement* plugInElement = toHTMLPlugInElement(parent);
2113    if (!plugInElement->isPlugInImageElement())
2114        return true;
2115
2116    HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(plugInElement);
2117
2118    Image* snapshot = plugInImageElement->snapshotImage();
2119    if (!snapshot)
2120        return true;
2121
2122    RenderSnapshottedPlugIn* plugInRenderer = toRenderSnapshottedPlugIn(plugInImageElement->renderer());
2123    FloatPoint snapshotAbsPos = plugInRenderer->localToAbsolute();
2124    snapshotAbsPos.move(plugInRenderer->borderLeft() + plugInRenderer->paddingLeft(), plugInRenderer->borderTop() + plugInRenderer->paddingTop());
2125
2126    // We could draw the snapshot with that coordinates, but we need to make sure there
2127    // isn't a composited layer between us and the plugInRenderer.
2128    RenderBox* renderBox = toRenderBox(o);
2129    while (renderBox != plugInRenderer) {
2130        if (renderBox->hasLayer() && renderBox->layer() && renderBox->layer()->isComposited()) {
2131            snapshotAbsPos = -renderBox->location();
2132            break;
2133        }
2134        renderBox = renderBox->parentBox();
2135    }
2136
2137    LayoutSize pluginSize(plugInRenderer->contentWidth(), plugInRenderer->contentHeight());
2138    LayoutRect pluginRect(snapshotAbsPos, pluginSize);
2139    IntRect alignedPluginRect = pixelSnappedIntRect(pluginRect);
2140
2141    if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
2142        return true;
2143
2144    context->drawImage(snapshot, plugInRenderer->style()->colorSpace(), alignedPluginRect, CompositeSourceOver);
2145    return false;
2146}
2147
2148#if ENABLE(DATALIST_ELEMENT)
2149IntSize RenderThemeMac::sliderTickSize() const
2150{
2151    return IntSize(1, 3);
2152}
2153
2154int RenderThemeMac::sliderTickOffsetFromTrackCenter() const
2155{
2156    return -9;
2157}
2158#endif
2159
2160const int sliderThumbWidth = 15;
2161const int sliderThumbHeight = 15;
2162
2163void RenderThemeMac::adjustSliderThumbSize(RenderStyle* style, Element*) const
2164{
2165    float zoomLevel = style->effectiveZoom();
2166    if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
2167        style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
2168        style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
2169    }
2170
2171#if ENABLE(VIDEO)
2172    adjustMediaSliderThumbSize(style);
2173#endif
2174}
2175
2176bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const
2177{
2178#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
2179    return true;
2180#else
2181    return false;
2182#endif
2183}
2184
2185NSPopUpButtonCell* RenderThemeMac::popupButton() const
2186{
2187    if (!m_popupButton) {
2188        m_popupButton = adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
2189        [m_popupButton.get() setUsesItemFromMenu:NO];
2190        [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
2191    }
2192
2193    return m_popupButton.get();
2194}
2195
2196NSSearchFieldCell* RenderThemeMac::search() const
2197{
2198    if (!m_search) {
2199        m_search = adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
2200        [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
2201        [m_search.get() setBezeled:YES];
2202        [m_search.get() setEditable:YES];
2203        [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
2204    }
2205
2206    return m_search.get();
2207}
2208
2209NSMenu* RenderThemeMac::searchMenuTemplate() const
2210{
2211    if (!m_searchMenuTemplate)
2212        m_searchMenuTemplate = adoptNS([[NSMenu alloc] initWithTitle:@""]);
2213
2214    return m_searchMenuTemplate.get();
2215}
2216
2217NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
2218{
2219    if (!m_sliderThumbHorizontal) {
2220        m_sliderThumbHorizontal = adoptNS([[NSSliderCell alloc] init]);
2221        [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
2222        [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
2223        [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
2224    }
2225
2226    return m_sliderThumbHorizontal.get();
2227}
2228
2229NSSliderCell* RenderThemeMac::sliderThumbVertical() const
2230{
2231    if (!m_sliderThumbVertical) {
2232        m_sliderThumbVertical = adoptNS([[NSSliderCell alloc] init]);
2233        [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
2234        [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
2235        [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
2236    }
2237
2238    return m_sliderThumbVertical.get();
2239}
2240
2241NSTextFieldCell* RenderThemeMac::textField() const
2242{
2243    if (!m_textField) {
2244        m_textField = adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
2245        [m_textField.get() setBezeled:YES];
2246        [m_textField.get() setEditable:YES];
2247        [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
2248#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
2249        [m_textField.get() setDrawsBackground:YES];
2250        [m_textField.get() setBackgroundColor:[NSColor whiteColor]];
2251#else
2252        // Post-Lion, WebCore can be in charge of paintinng the background thanks to
2253        // the workaround in place for <rdar://problem/11385461>, which is implemented
2254        // above as _coreUIDrawOptionsWithFrame.
2255        [m_textField.get() setDrawsBackground:NO];
2256#endif
2257    }
2258
2259    return m_textField.get();
2260}
2261
2262String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
2263{
2264    if (width <= 0)
2265        return String();
2266
2267    String strToTruncate;
2268    if (fileList->isEmpty())
2269        strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
2270    else if (fileList->length() == 1)
2271        strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
2272    else
2273        return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
2274
2275    return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
2276}
2277
2278
2279} // namespace WebCore
2280