Fix Build.
[WebKit.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     LocalCurrentGraphicsContext localContext(paintInfo.context);
830
831     // Becaue NSLevelIndicatorCell doesn't support vertical gauge, we use a portable version 
832     if (rect.width() < rect.height())
833         return RenderTheme::paintMeter(renderObject, paintInfo, rect);
834
835     NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
836     paintInfo.context->save();
837     [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
838     [cell setControlView:nil];
839     paintInfo.context->restore();
840
841     return false;
842 }
843
844 bool RenderThemeMac::supportsMeter(ControlPart part, bool isHorizontal) const
845 {
846     switch (part) {
847     case RelevancyLevelIndicatorPart:
848     case DiscreteCapacityLevelIndicatorPart:
849     case RatingLevelIndicatorPart:
850     case MeterPart:
851     case ContinuousCapacityLevelIndicatorPart:
852         return isHorizontal;
853     default:
854         return false;
855     }
856 }
857
858 NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
859 {
860     switch (part) {
861     case RelevancyLevelIndicatorPart:
862         return NSRelevancyLevelIndicatorStyle;
863     case DiscreteCapacityLevelIndicatorPart:
864         return NSDiscreteCapacityLevelIndicatorStyle;
865     case RatingLevelIndicatorPart:
866         return NSRatingLevelIndicatorStyle;
867     case MeterPart:
868     case ContinuousCapacityLevelIndicatorPart:
869     default:
870         return NSContinuousCapacityLevelIndicatorStyle;
871     }
872     
873 }
874
875 NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* renderMeter) const
876 {
877     RenderStyle* style = renderMeter->style();
878     ASSERT(style->appearance() != NoControlPart);
879
880     if (!m_levelIndicator)
881         m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
882     NSLevelIndicatorCell* cell = m_levelIndicator.get();
883
884     HTMLMeterElement* element = static_cast<HTMLMeterElement*>(renderMeter->node());
885     double value = element->value();
886
887     // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
888     // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
889     switch (element->gaugeRegion()) {
890     case HTMLMeterElement::GaugeRegionOptimum:
891         // Make meter the green
892         [cell setWarningValue:value + 1];
893         [cell setCriticalValue:value + 2];
894         break;
895     case HTMLMeterElement::GaugeRegionSuboptimal:
896         // Make the meter yellow
897         [cell setWarningValue:value - 1];
898         [cell setCriticalValue:value + 1];
899         break;
900     case HTMLMeterElement::GaugeRegionEvenLessGood:
901         // Make the meter red
902         [cell setWarningValue:value - 2];
903         [cell setCriticalValue:value - 1];
904         break;
905     }
906
907     [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
908     [cell setBaseWritingDirection:style->direction() == LTR ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
909     [cell setMinValue:element->min()];
910     [cell setMaxValue:element->max()];
911     RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
912     [cell setObjectValue:valueObject.get()];
913
914     return cell;
915 }
916
917 #endif
918
919 #if ENABLE(PROGRESS_TAG)
920
921 double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
922 {
923     return progressAnimationFrameRate;
924 }
925
926 double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const
927 {
928     return progressAnimationNumFrames * progressAnimationFrameRate;
929 }
930
931 void RenderThemeMac::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const
932 {
933 }
934
935 bool RenderThemeMac::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
936 {
937     if (!renderObject->isProgress())
938         return true;
939
940     RenderProgress* renderProgress = toRenderProgress(renderObject);
941     HIThemeTrackDrawInfo trackInfo;
942     trackInfo.version = 0;
943     trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
944     trackInfo.bounds = IntRect(IntPoint(), rect.size());
945     trackInfo.min = 0;
946     trackInfo.max = numeric_limits<SInt32>::max();
947     trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0));
948     trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0));
949     trackInfo.attributes = kThemeTrackHorizontal;
950     trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
951     trackInfo.reserved = 0;
952     trackInfo.filler1 = 0;
953
954     OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(rect.size());
955     if (!imageBuffer)
956         return true;
957
958     HIThemeDrawTrack(&trackInfo, 0, imageBuffer->context()->platformContext(), kHIThemeOrientationNormal);
959
960     paintInfo.context->save();
961
962     if (renderProgress->style()->direction() == RTL) {
963         paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
964         paintInfo.context->scale(FloatSize(-1, 1));
965     }
966     paintInfo.context->drawImage(imageBuffer->image(), DeviceColorSpace, rect.location());
967
968     paintInfo.context->restore();
969     return false;
970 }    
971 #endif
972
973 const float baseFontSize = 11.0f;
974 const float baseArrowHeight = 4.0f;
975 const float baseArrowWidth = 5.0f;
976 const float baseSpaceBetweenArrows = 2.0f;
977 const int arrowPaddingLeft = 6;
978 const int arrowPaddingRight = 6;
979 const int paddingBeforeSeparator = 4;
980 const int baseBorderRadius = 5;
981 const int styledPopupPaddingLeft = 8;
982 const int styledPopupPaddingTop = 1;
983 const int styledPopupPaddingBottom = 2;
984
985 static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
986 {
987     static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
988     static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
989     float a = inData[0];
990     int i = 0;
991     for (i = 0; i < 4; i++)
992         outData[i] = (1.0f - a) * dark[i] + a * light[i];
993 }
994
995 static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
996 {
997     static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
998     static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
999     float a = inData[0];
1000     int i = 0;
1001     for (i = 0; i < 4; i++)
1002         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1003 }
1004
1005 static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1006 {
1007     static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1008     static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1009     float a = inData[0];
1010     int i = 0;
1011     for (i = 0; i < 4; i++)
1012         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1013 }
1014
1015 static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1016 {
1017     static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1018     static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1019     float a = inData[0];
1020     int i = 0;
1021     for (i = 0; i < 4; i++)
1022         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1023 }
1024
1025 void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1026 {
1027     if (r.isEmpty())
1028         return;
1029
1030     CGContextRef context = paintInfo.context->platformContext();
1031
1032     paintInfo.context->save();
1033
1034     IntSize topLeftRadius;
1035     IntSize topRightRadius;
1036     IntSize bottomLeftRadius;
1037     IntSize bottomRightRadius;
1038
1039     o->style()->getBorderRadiiForRect(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
1040
1041     int radius = topLeftRadius.width();
1042
1043     RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
1044
1045     FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1046     struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1047     RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1048     RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false));
1049
1050     FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1051     struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1052     RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1053     RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(),  bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false));
1054
1055     struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1056     RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1057     RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(),  r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false));
1058
1059     RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(),  r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1060
1061     RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(),  r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false));
1062     paintInfo.context->save();
1063     CGContextClipToRect(context, r);
1064     paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
1065     CGContextDrawShading(context, mainShading.get());
1066     paintInfo.context->restore();
1067
1068     paintInfo.context->save();
1069     CGContextClipToRect(context, topGradient);
1070     paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), topLeftRadius, topRightRadius, IntSize(), IntSize());
1071     CGContextDrawShading(context, topShading.get());
1072     paintInfo.context->restore();
1073
1074     if (!bottomGradient.isEmpty()) {
1075         paintInfo.context->save();
1076         CGContextClipToRect(context, bottomGradient);
1077         paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bottomLeftRadius, bottomRightRadius);
1078         CGContextDrawShading(context, bottomShading.get());
1079         paintInfo.context->restore();
1080     }
1081
1082     paintInfo.context->save();
1083     CGContextClipToRect(context, r);
1084     paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
1085     CGContextDrawShading(context, leftShading.get());
1086     CGContextDrawShading(context, rightShading.get());
1087     paintInfo.context->restore();
1088
1089     paintInfo.context->restore();
1090 }
1091
1092 bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1093 {
1094     IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
1095                              r.y() + o->style()->borderTopWidth(),
1096                              r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
1097                              r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
1098     // Draw the gradients to give the styled popup menu a button appearance
1099     paintMenuListButtonGradients(o, paintInfo, bounds);
1100
1101     // 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
1102     float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1103     float centerY = bounds.y() + bounds.height() / 2.0f;
1104     float arrowHeight = baseArrowHeight * fontScale;
1105     float arrowWidth = baseArrowWidth * fontScale;
1106     float leftEdge = bounds.right() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth;
1107     float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1108
1109     if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
1110         return false;
1111     
1112     paintInfo.context->save();
1113
1114     paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace());
1115     paintInfo.context->setStrokeStyle(NoStroke);
1116
1117     FloatPoint arrow1[3];
1118     arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1119     arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1120     arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1121
1122     // Draw the top arrow
1123     paintInfo.context->drawConvexPolygon(3, arrow1, true);
1124
1125     FloatPoint arrow2[3];
1126     arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1127     arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1128     arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1129
1130     // Draw the bottom arrow
1131     paintInfo.context->drawConvexPolygon(3, arrow2, true);
1132
1133     Color leftSeparatorColor(0, 0, 0, 40);
1134     Color rightSeparatorColor(255, 255, 255, 40);
1135
1136     // FIXME: Should the separator thickness and space be scaled up by fontScale?
1137     int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1138     int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round?
1139
1140     // Draw the separator to the left of the arrows
1141     paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
1142     paintInfo.context->setStrokeStyle(SolidStroke);
1143     paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace);
1144     paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1145                                 IntPoint(leftEdgeOfSeparator, bounds.bottom()));
1146
1147     paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace);
1148     paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1149                                 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
1150
1151     paintInfo.context->restore();
1152     return false;
1153 }
1154
1155 static const IntSize* menuListButtonSizes()
1156 {
1157     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1158     return sizes;
1159 }
1160
1161 void RenderThemeMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1162 {
1163     NSControlSize controlSize = controlSizeForFont(style);
1164
1165     style->resetBorder();
1166     style->resetPadding();
1167     
1168     // Height is locked to auto.
1169     style->setHeight(Length(Auto));
1170
1171     // White-space is locked to pre
1172     style->setWhiteSpace(PRE);
1173
1174     // Set the foreground color to black or gray when we have the aqua look.
1175     // Cast to RGB32 is to work around a compiler bug.
1176     style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1177
1178     // Set the button's vertical size.
1179     setSizeFromFont(style, menuListButtonSizes());
1180
1181     // 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
1182     // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1183     // system font for the control size instead.
1184     setFontFromControlSize(selector, style, controlSize);
1185
1186     style->setBoxShadow(0);
1187 }
1188
1189 int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const
1190 {
1191     if (style->appearance() == MenulistPart)
1192         return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
1193     if (style->appearance() == MenulistButtonPart)
1194         return styledPopupPaddingLeft * style->effectiveZoom();
1195     return 0;
1196 }
1197
1198 int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const
1199 {
1200     if (style->appearance() == MenulistPart)
1201         return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
1202     if (style->appearance() == MenulistButtonPart) {
1203         float fontScale = style->fontSize() / baseFontSize;
1204         float arrowWidth = baseArrowWidth * fontScale;
1205         return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
1206     }
1207     return 0;
1208 }
1209
1210 int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const
1211 {
1212     if (style->appearance() == MenulistPart)
1213         return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
1214     if (style->appearance() == MenulistButtonPart)
1215         return styledPopupPaddingTop * style->effectiveZoom();
1216     return 0;
1217 }
1218
1219 int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const
1220 {
1221     if (style->appearance() == MenulistPart)
1222         return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
1223     if (style->appearance() == MenulistButtonPart)
1224         return styledPopupPaddingBottom * style->effectiveZoom();
1225     return 0;
1226 }
1227
1228 void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1229 {
1230     float fontScale = style->fontSize() / baseFontSize;
1231
1232     style->resetPadding();
1233     style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1234
1235     const int minHeight = 15;
1236     style->setMinHeight(Length(minHeight, Fixed));
1237     
1238     style->setLineHeight(RenderStyle::initialLineHeight());
1239 }
1240
1241 void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
1242 {
1243     NSPopUpButtonCell* popupButton = this->popupButton();
1244
1245     // Set the control size based off the rectangle we're painting into.
1246     setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
1247
1248     // Update the various states we respond to.
1249     updateActiveState(popupButton, o);
1250     updateCheckedState(popupButton, o);
1251     updateEnabledState(popupButton, o);
1252     updatePressedState(popupButton, o);
1253     updateFocusedState(popupButton, o);
1254 }
1255
1256 const IntSize* RenderThemeMac::menuListSizes() const
1257 {
1258     static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1259     return sizes;
1260 }
1261
1262 int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const
1263 {
1264     return sizeForSystemFont(style, menuListSizes()).width();
1265 }
1266
1267 const int trackWidth = 5;
1268 const int trackRadius = 2;
1269
1270 void RenderThemeMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1271 {
1272     style->setBoxShadow(0);
1273 }
1274
1275 bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1276 {
1277     IntRect bounds = r;
1278     float zoomLevel = o->style()->effectiveZoom();
1279     float zoomedTrackWidth = trackWidth * zoomLevel;
1280
1281     if (o->style()->appearance() ==  SliderHorizontalPart || o->style()->appearance() ==  MediaSliderPart) {
1282         bounds.setHeight(zoomedTrackWidth);
1283         bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1284     } else if (o->style()->appearance() == SliderVerticalPart) {
1285         bounds.setWidth(zoomedTrackWidth);
1286         bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1287     }
1288
1289     LocalCurrentGraphicsContext localContext(paintInfo.context);
1290     CGContextRef context = paintInfo.context->platformContext();
1291     RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
1292
1293     paintInfo.context->save();
1294     CGContextClipToRect(context, bounds);
1295
1296     struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1297     RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1298     RetainPtr<CGShadingRef> mainShading;
1299     if (o->style()->appearance() == SliderVerticalPart)
1300         mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(),  bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false));
1301     else
1302         mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(),  bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false));
1303
1304     IntSize radius(trackRadius, trackRadius);
1305     paintInfo.context->addRoundedRectClip(bounds,
1306         radius, radius,
1307         radius, radius);
1308     CGContextDrawShading(context, mainShading.get());
1309     paintInfo.context->restore();
1310     
1311     return false;
1312 }
1313
1314 void RenderThemeMac::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1315 {
1316     style->setBoxShadow(0);
1317 }
1318
1319 const float verticalSliderHeightPadding = 0.1f;
1320
1321 bool RenderThemeMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1322 {
1323     ASSERT(o->parent()->isSlider());
1324
1325     NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart
1326         ? sliderThumbVertical()
1327         : sliderThumbHorizontal();
1328
1329     LocalCurrentGraphicsContext localContext(paintInfo.context);
1330
1331     // Update the various states we respond to.
1332     updateActiveState(sliderThumbCell, o->parent());
1333     updateEnabledState(sliderThumbCell, o->parent());
1334     updateFocusedState(sliderThumbCell, o->parent());
1335
1336     // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1337     bool oldPressed;
1338     if (o->style()->appearance() == SliderThumbVerticalPart)
1339         oldPressed = m_isSliderThumbVerticalPressed;
1340     else
1341         oldPressed = m_isSliderThumbHorizontalPressed;
1342
1343     bool pressed = toRenderSlider(o->parent())->inDragMode();
1344
1345     if (o->style()->appearance() == SliderThumbVerticalPart)
1346         m_isSliderThumbVerticalPressed = pressed;
1347     else
1348         m_isSliderThumbHorizontalPressed = pressed;
1349
1350     if (pressed != oldPressed) {
1351         if (pressed)
1352             [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1353         else
1354             [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1355     }
1356
1357     FloatRect bounds = r;
1358     // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1359     if (o->style()->appearance() == SliderThumbVerticalPart)
1360         bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom());
1361
1362     paintInfo.context->save();
1363     float zoomLevel = o->style()->effectiveZoom();
1364     
1365     FloatRect unzoomedRect = bounds;
1366     if (zoomLevel != 1.0f) {
1367         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1368         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1369         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1370         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1371         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1372     }
1373
1374     [sliderThumbCell drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1375     [sliderThumbCell setControlView:nil];
1376
1377     paintInfo.context->restore();
1378
1379     return false;
1380 }
1381
1382 bool RenderThemeMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1383 {
1384     LocalCurrentGraphicsContext localContext(paintInfo.context);
1385     NSSearchFieldCell* search = this->search();
1386
1387     setSearchCellState(o, r);
1388
1389     paintInfo.context->save();
1390
1391     float zoomLevel = o->style()->effectiveZoom();
1392
1393     IntRect unzoomedRect = r;
1394     
1395     if (zoomLevel != 1.0f) {
1396         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1397         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1398         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1399         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1400         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1401     }
1402
1403     // Set the search button to nil before drawing.  Then reset it so we can draw it later.
1404     [search setSearchButtonCell:nil];
1405
1406     [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1407 #ifdef BUILDING_ON_TIGER
1408     if ([search showsFirstResponder])
1409         wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect));
1410 #endif
1411
1412     [search setControlView:nil];
1413     [search resetSearchButtonCell];
1414
1415     paintInfo.context->restore();
1416
1417     return false;
1418 }
1419
1420 void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&)
1421 {
1422     NSSearchFieldCell* search = this->search();
1423
1424     [search setControlSize:controlSizeForFont(o->style())];
1425
1426     // Update the various states we respond to.
1427     updateActiveState(search, o);
1428     updateEnabledState(search, o);
1429     updateFocusedState(search, o);
1430 }
1431
1432 const IntSize* RenderThemeMac::searchFieldSizes() const
1433 {
1434     static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1435     return sizes;
1436 }
1437
1438 void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const
1439 {
1440     // If the width and height are both specified, then we have nothing to do.
1441     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1442         return;
1443     
1444     // Use the font size to determine the intrinsic width of the control.
1445     setSizeFromFont(style, searchFieldSizes());
1446 }
1447
1448 void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const
1449 {
1450     // Override border.
1451     style->resetBorder();
1452     const short borderWidth = 2 * style->effectiveZoom();
1453     style->setBorderLeftWidth(borderWidth);
1454     style->setBorderLeftStyle(INSET);
1455     style->setBorderRightWidth(borderWidth);
1456     style->setBorderRightStyle(INSET);
1457     style->setBorderBottomWidth(borderWidth);
1458     style->setBorderBottomStyle(INSET);
1459     style->setBorderTopWidth(borderWidth);
1460     style->setBorderTopStyle(INSET);    
1461     
1462     // Override height.
1463     style->setHeight(Length(Auto));
1464     setSearchFieldSize(style);
1465     
1466     // Override padding size to match AppKit text positioning.
1467     const int padding = 1 * style->effectiveZoom();
1468     style->setPaddingLeft(Length(padding, Fixed));
1469     style->setPaddingRight(Length(padding, Fixed));
1470     style->setPaddingTop(Length(padding, Fixed));
1471     style->setPaddingBottom(Length(padding, Fixed));
1472     
1473     NSControlSize controlSize = controlSizeForFont(style);
1474     setFontFromControlSize(selector, style, controlSize);
1475
1476     style->setBoxShadow(0);
1477 }
1478
1479 bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1480 {
1481     Node* input = o->node()->shadowAncestorNode();
1482     if (!input->renderer()->isBox())
1483         return false;
1484
1485     LocalCurrentGraphicsContext localContext(paintInfo.context);
1486     setSearchCellState(input->renderer(), r);
1487
1488     NSSearchFieldCell* search = this->search();
1489
1490     updateActiveState([search cancelButtonCell], o);
1491     updatePressedState([search cancelButtonCell], o);
1492
1493     paintInfo.context->save();
1494
1495     float zoomLevel = o->style()->effectiveZoom();
1496
1497     FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
1498
1499 #if ENABLE(INPUT_SPEECH)
1500     // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g.
1501     // when speech input is enabled for the input element.
1502     IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect();
1503     int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight();
1504     int spaceToRightOfCancelButton = absRight - (r.x() + r.width());
1505     localBounds.setX(localBounds.x() - spaceToRightOfCancelButton);
1506 #endif
1507
1508     localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1509
1510     FloatRect unzoomedRect(localBounds);
1511     if (zoomLevel != 1.0f) {
1512         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1513         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1514         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1515         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1516         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1517     }
1518
1519     [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1520     [[search cancelButtonCell] setControlView:nil];
1521
1522     paintInfo.context->restore();
1523     return false;
1524 }
1525
1526 const IntSize* RenderThemeMac::cancelButtonSizes() const
1527 {
1528     static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1529     return sizes;
1530 }
1531
1532 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1533 {
1534     IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1535     style->setWidth(Length(size.width(), Fixed));
1536     style->setHeight(Length(size.height(), Fixed));
1537     style->setBoxShadow(0);
1538 }
1539
1540 const IntSize* RenderThemeMac::resultsButtonSizes() const
1541 {
1542     static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1543     return sizes;
1544 }
1545
1546 const int emptyResultsOffset = 9;
1547 void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1548 {
1549     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1550     style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1551     style->setHeight(Length(size.height(), Fixed));
1552     style->setBoxShadow(0);
1553 }
1554
1555 bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1556 {
1557     return false;
1558 }
1559
1560 void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1561 {
1562     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1563     style->setWidth(Length(size.width(), Fixed));
1564     style->setHeight(Length(size.height(), Fixed));
1565     style->setBoxShadow(0);
1566 }
1567
1568 bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1569 {
1570     Node* input = o->node()->shadowAncestorNode();
1571     if (!input->renderer()->isBox())
1572         return false;
1573
1574     LocalCurrentGraphicsContext localContext(paintInfo.context);
1575     setSearchCellState(input->renderer(), r);
1576
1577     NSSearchFieldCell* search = this->search();
1578
1579     if ([search searchMenuTemplate] != nil)
1580         [search setSearchMenuTemplate:nil];
1581
1582     updateActiveState([search searchButtonCell], o);
1583
1584     FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
1585     localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1586
1587     [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
1588     [[search searchButtonCell] setControlView:nil];
1589     return false;
1590 }
1591
1592 const int resultsArrowWidth = 5;
1593 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1594 {
1595     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1596     style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1597     style->setHeight(Length(size.height(), Fixed));
1598     style->setBoxShadow(0);
1599 }
1600
1601 bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1602 {
1603     Node* input = o->node()->shadowAncestorNode();
1604     if (!input->renderer()->isBox())
1605         return false;
1606
1607     LocalCurrentGraphicsContext localContext(paintInfo.context);
1608     setSearchCellState(input->renderer(), r);
1609
1610     NSSearchFieldCell* search = this->search();
1611
1612     updateActiveState([search searchButtonCell], o);
1613
1614     if (![search searchMenuTemplate])
1615         [search setSearchMenuTemplate:searchMenuTemplate()];
1616
1617     paintInfo.context->save();
1618
1619     float zoomLevel = o->style()->effectiveZoom();
1620
1621     FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
1622     localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1623     
1624     IntRect unzoomedRect(localBounds);
1625     if (zoomLevel != 1.0f) {
1626         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1627         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1628         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1629         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1630         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1631     }
1632
1633     [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1634     [[search searchButtonCell] setControlView:nil];
1635     
1636     paintInfo.context->restore();
1637
1638     return false;
1639 }
1640
1641 #if ENABLE(VIDEO)
1642 typedef enum {
1643     MediaControllerThemeClassic   = 1,
1644     MediaControllerThemeQuickTime = 2
1645 } MediaControllerThemeStyle;
1646
1647 static int mediaControllerTheme()
1648 {
1649     static int controllerTheme = -1;
1650     
1651     if (controllerTheme != -1)
1652         return controllerTheme;
1653
1654     controllerTheme = MediaControllerThemeClassic;
1655
1656     Boolean validKey;
1657     Boolean useQTMediaUIPref = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey);
1658
1659 #if !defined(BUILDING_ON_TIGER)
1660     if (validKey && !useQTMediaUIPref)
1661         return controllerTheme;
1662 #else
1663     if (!validKey || !useQTMediaUIPref)
1664         return controllerTheme;
1665 #endif
1666
1667     controllerTheme = MediaControllerThemeQuickTime;
1668     return controllerTheme;
1669 }
1670 #endif
1671
1672 const int sliderThumbWidth = 15;
1673 const int sliderThumbHeight = 15;
1674 const int mediaSliderThumbWidth = 13;
1675 const int mediaSliderThumbHeight = 14;
1676
1677 void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const
1678 {
1679     float zoomLevel = o->style()->effectiveZoom();
1680     if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) {
1681         o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1682         o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1683     } 
1684
1685 #if ENABLE(VIDEO)
1686     adjustMediaSliderThumbSize(o);
1687 #endif
1688 }
1689
1690 #if ENABLE(VIDEO)
1691
1692 void RenderThemeMac::adjustMediaSliderThumbSize(RenderObject* o) const
1693 {
1694     ControlPart part = o->style()->appearance();
1695
1696     if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart) {
1697         int width = mediaSliderThumbWidth;
1698         int height = mediaSliderThumbHeight;
1699         
1700         if (mediaControllerTheme() == MediaControllerThemeQuickTime) {
1701             CGSize  size;
1702             
1703             wkMeasureMediaUIPart(part == MediaSliderThumbPart ? MediaSliderThumb : MediaVolumeSliderThumb, MediaControllerThemeQuickTime, NULL, &size);
1704             width = size.width;
1705             height = size.height;
1706         }
1707
1708         float zoomLevel = o->style()->effectiveZoom();
1709         o->style()->setWidth(Length(static_cast<int>(width * zoomLevel), Fixed));
1710         o->style()->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed));
1711     }
1712 }
1713
1714 enum WKMediaControllerThemeState { 
1715     MediaUIPartDisabledFlag = 1 << 0,
1716     MediaUIPartPressedFlag = 1 << 1,
1717     MediaUIPartDrawEndCapsFlag = 1 << 3,
1718 };
1719
1720 static unsigned getMediaUIPartStateFlags(Node* node)
1721 {
1722     unsigned flags = 0;
1723
1724     if (node->disabled())
1725         flags |= MediaUIPartDisabledFlag;
1726     else if (node->active())
1727         flags |= MediaUIPartPressedFlag;
1728     return flags;
1729 }
1730
1731 // Utility to scale when the UI part are not scaled by wkDrawMediaUIPart
1732 static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const PaintInfo& paintInfo, const IntRect &originalRect)
1733 {
1734     float zoomLevel = o->style()->effectiveZoom();
1735     FloatRect unzoomedRect(originalRect);
1736     if (zoomLevel != 1.0f && mediaControllerTheme() == MediaControllerThemeQuickTime) {
1737         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1738         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1739         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1740         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1741         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1742     }
1743     return unzoomedRect;
1744 }
1745
1746
1747 bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1748 {
1749     Node* node = o->node();
1750     if (!node)
1751         return false;
1752
1753     LocalCurrentGraphicsContext localContext(paintInfo.context);
1754     wkDrawMediaUIPart(MediaFullscreenButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1755     return false;
1756 }
1757
1758 bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1759 {
1760     Node* node = o->node();
1761     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1762     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1763         return false;
1764
1765     if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(node)) {
1766         LocalCurrentGraphicsContext localContext(paintInfo.context);
1767         wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1768
1769     }
1770     return false;
1771 }
1772
1773 bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1774 {
1775     Node* node = o->node();
1776     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1777     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1778         return false;
1779
1780     if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(node)) {
1781         LocalCurrentGraphicsContext localContext(paintInfo.context);
1782         wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1783     }
1784     return false;
1785 }
1786
1787 bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1788 {
1789     Node* node = o->node();
1790     if (!node)
1791         return false;
1792
1793     LocalCurrentGraphicsContext localContext(paintInfo.context);
1794     wkDrawMediaUIPart(MediaSeekBackButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1795     return false;
1796 }
1797
1798 bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1799 {
1800     Node* node = o->node();
1801     if (!node)
1802         return false;
1803
1804     LocalCurrentGraphicsContext localContext(paintInfo.context);
1805     wkDrawMediaUIPart(MediaSeekForwardButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1806     return false;
1807 }
1808
1809 bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1810 {
1811     Node* node = o->node();
1812     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1813     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1814         return false;
1815
1816     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1817     if (!mediaElement)
1818         return false;
1819
1820     RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
1821     ExceptionCode ignoredException;
1822     float timeLoaded = timeRanges->length() ? timeRanges->end(0, ignoredException) : 0;
1823     float currentTime = mediaElement->currentTime();
1824     float duration = mediaElement->duration();
1825     if (isnan(duration))
1826         duration = 0;
1827  
1828     paintInfo.context->save();
1829     FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
1830     wkDrawMediaSliderTrack(mediaControllerTheme(), paintInfo.context->platformContext(), unzoomedRect, 
1831         timeLoaded, currentTime, duration, getMediaUIPartStateFlags(node));
1832     
1833     paintInfo.context->restore();
1834     return false;
1835 }
1836
1837 bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1838 {
1839     Node* node = o->node();
1840     if (!node)
1841         return false;
1842
1843     LocalCurrentGraphicsContext localContext(paintInfo.context);
1844     wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1845     return false;
1846 }
1847     
1848 bool RenderThemeMac::paintMediaRewindButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1849 {
1850     Node* node = o->node();
1851     if (!node)
1852         return false;
1853     
1854     LocalCurrentGraphicsContext localContext(paintInfo.context);
1855     wkDrawMediaUIPart(MediaRewindButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1856     return false;
1857 }
1858
1859 bool RenderThemeMac::paintMediaReturnToRealtimeButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1860 {
1861     Node* node = o->node();
1862     if (!node)
1863         return false;
1864     
1865     LocalCurrentGraphicsContext localContext(paintInfo.context);
1866     wkDrawMediaUIPart(MediaReturnToRealtimeButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1867     return false;
1868 }
1869
1870 bool RenderThemeMac::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1871 {
1872     HTMLInputElement* node = static_cast<HTMLInputElement*>(o->node());
1873     if (!node)
1874         return false;
1875     
1876     MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(node);
1877     if (!btn)
1878         return false;
1879
1880     LocalCurrentGraphicsContext localContext(paintInfo.context);
1881     wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1882
1883     return false;
1884 }
1885  
1886 bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1887 {
1888     Node* node = o->node();
1889     if (!node)
1890         return false;
1891
1892     LocalCurrentGraphicsContext localContext(paintInfo.context);
1893     wkDrawMediaUIPart(MediaTimelineContainer, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1894     return false;
1895 }
1896
1897 bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1898 {
1899     Node* node = o->node();
1900     if (!node)
1901         return false;
1902
1903     paintInfo.context->save();
1904     FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
1905     wkDrawMediaUIPart(MediaCurrentTimeDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), unzoomedRect, getMediaUIPartStateFlags(node));
1906     paintInfo.context->restore();
1907     return false;
1908 }
1909
1910 bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1911 {
1912     Node* node = o->node();
1913     if (!node)
1914         return false;
1915
1916     paintInfo.context->save();
1917     FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
1918     wkDrawMediaUIPart(MediaTimeRemainingDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), unzoomedRect, getMediaUIPartStateFlags(node));
1919     paintInfo.context->restore();
1920     return false;
1921 }
1922
1923 bool RenderThemeMac::paintMediaVolumeSliderContainer(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1924 {
1925     Node* node = o->node();
1926     if (!node)
1927         return false;
1928
1929     LocalCurrentGraphicsContext localContext(paintInfo.context);
1930     wkDrawMediaUIPart(MediaVolumeSliderContainer, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1931     return false;
1932 }
1933
1934 bool RenderThemeMac::paintMediaVolumeSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1935 {
1936     Node* node = o->node();
1937     if (!node)
1938         return false;
1939
1940     LocalCurrentGraphicsContext localContext(paintInfo.context);
1941     wkDrawMediaUIPart(MediaVolumeSlider, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1942     return false;
1943 }
1944     
1945 bool RenderThemeMac::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1946 {
1947     Node* node = o->node();
1948     if (!node)
1949         return false;
1950
1951     LocalCurrentGraphicsContext localContext(paintInfo.context);
1952     wkDrawMediaUIPart(MediaVolumeSliderThumb, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
1953     return false;
1954 }
1955     
1956 String RenderThemeMac::extraMediaControlsStyleSheet()
1957 {
1958 #if PLATFORM(MAC)
1959     if (mediaControllerTheme() == MediaControllerThemeQuickTime)
1960         return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet));
1961
1962     return String();
1963 #else
1964     ASSERT_NOT_REACHED();
1965     return String();
1966 #endif
1967 }
1968
1969 bool RenderThemeMac::shouldRenderMediaControlPart(ControlPart part, Element* element)
1970 {
1971     switch (part) {
1972     case MediaVolumeSliderContainerPart:
1973     case MediaVolumeSliderPart:
1974     case MediaVolumeSliderMuteButtonPart:
1975     case MediaVolumeSliderThumbPart: {
1976         HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1977         return mediaControllerTheme() == MediaControllerThemeQuickTime && mediaElement->hasAudio();
1978     }
1979     case MediaToggleClosedCaptionsButtonPart:
1980         // We rely on QTKit to render captions so don't enable the button unless it will be able to do so.
1981         if (!element->hasTagName(videoTag))
1982             return false;
1983     default:
1984         break;
1985     }
1986
1987     return RenderTheme::shouldRenderMediaControlPart(part, element);
1988 }
1989
1990 IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const
1991 {
1992     static const int xOffset = -4;
1993     static const int yOffset = 5;
1994
1995     float zoomLevel = muteButton->renderer()->style()->effectiveZoom();
1996     int y = yOffset * zoomLevel + muteButton->renderBox()->offsetHeight() - size.height();
1997     FloatPoint absPoint = muteButton->renderer()->localToAbsolute(FloatPoint(muteButton->renderBox()->offsetLeft(), y), true, true);
1998     if (absPoint.y() < 0)
1999         y = muteButton->renderBox()->height();
2000     return IntPoint(xOffset * zoomLevel, y);
2001 }
2002
2003 #endif // ENABLE(VIDEO)
2004
2005 NSPopUpButtonCell* RenderThemeMac::popupButton() const
2006 {
2007     if (!m_popupButton) {
2008         m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
2009         [m_popupButton.get() setUsesItemFromMenu:NO];
2010         [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
2011     }
2012     
2013     return m_popupButton.get();
2014 }
2015
2016 NSSearchFieldCell* RenderThemeMac::search() const
2017 {
2018     if (!m_search) {
2019         m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
2020         [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
2021         [m_search.get() setBezeled:YES];
2022         [m_search.get() setEditable:YES];
2023         [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
2024     }
2025
2026     return m_search.get();
2027 }
2028
2029 NSMenu* RenderThemeMac::searchMenuTemplate() const
2030 {
2031     if (!m_searchMenuTemplate)
2032         m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]);
2033
2034     return m_searchMenuTemplate.get();
2035 }
2036
2037 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
2038 {
2039     if (!m_sliderThumbHorizontal) {
2040         m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]);
2041         [m_sliderThumbHorizontal.get() setTitle:nil];
2042         [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
2043         [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
2044         [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
2045     }
2046     
2047     return m_sliderThumbHorizontal.get();
2048 }
2049
2050 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
2051 {
2052     if (!m_sliderThumbVertical) {
2053         m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]);
2054         [m_sliderThumbVertical.get() setTitle:nil];
2055         [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
2056         [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
2057         [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
2058     }
2059     
2060     return m_sliderThumbVertical.get();
2061 }
2062
2063 } // namespace WebCore