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