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