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