OSDN Git Service

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