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