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