initial import
[vuplus_webkit] / 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 "LocalizedStrings.h"
38 #import "MediaControlElements.h"
39 #import "PaintInfo.h"
40 #import "RenderMedia.h"
41 #import "RenderMediaControls.h"
42 #import "RenderSlider.h"
43 #import "RenderView.h"
44 #import "SharedBuffer.h"
45 #import "StringTruncator.h"
46 #import "TimeRanges.h"
47 #import "ThemeMac.h"
48 #import "WebCoreSystemInterface.h"
49 #import "UserAgentStyleSheets.h"
50 #import <Carbon/Carbon.h>
51 #import <Cocoa/Cocoa.h>
52 #import <wtf/RetainPtr.h>
53 #import <wtf/StdLibExtras.h>
54 #import <math.h>
55
56 #import "RenderProgress.h"
57
58 #if ENABLE(METER_TAG)
59 #include "RenderMeter.h"
60 #include "HTMLMeterElement.h"
61 #endif
62
63
64 using namespace std;
65
66 // The methods in this file are specific to the Mac OS X platform.
67
68 // FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. 
69
70 // We estimate the animation rate of a Mac OS X progress bar is 33 fps.
71 // Hard code the value here because we haven't found API for it.
72 const double progressAnimationFrameRate = 0.033;
73
74 // Mac OS X progress bar animation seems to have 256 frames.
75 const double progressAnimationNumFrames = 256;
76
77 @interface WebCoreRenderThemeNotificationObserver : NSObject
78 {
79     WebCore::RenderTheme *_theme;
80 }
81
82 - (id)initWithTheme:(WebCore::RenderTheme *)theme;
83 - (void)systemColorsDidChange:(NSNotification *)notification;
84
85 @end
86
87 @implementation WebCoreRenderThemeNotificationObserver
88
89 - (id)initWithTheme:(WebCore::RenderTheme *)theme
90 {
91     if (!(self = [super init]))
92         return nil;
93
94     _theme = theme;    
95     return self;
96 }
97
98 - (void)systemColorsDidChange:(NSNotification *)unusedNotification
99 {
100     ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
101     _theme->platformColorsDidChange();
102 }
103
104 @end
105
106 namespace WebCore {
107
108 using namespace HTMLNames;
109
110 enum {
111     topMargin,
112     rightMargin,
113     bottomMargin,
114     leftMargin
115 };
116
117 enum {
118     topPadding,
119     rightPadding,
120     bottomPadding,
121     leftPadding
122 };
123
124 #if PLATFORM(MAC)
125 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
126 {
127     static RenderTheme* rt = RenderThemeMac::create().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 InnerSpinButtonPart:
514             return RenderTheme::adjustRepaintRect(o, r);
515         default:
516             break;
517     }
518 #endif
519
520     float zoomLevel = o->style()->effectiveZoom();
521
522     if (part == MenulistPart) {
523         setPopupButtonCellState(o, r);
524         IntSize size = popupButtonSizes()[[popupButton() controlSize]];
525         size.setHeight(size.height() * zoomLevel);
526         size.setWidth(r.width());
527         r = inflateRect(r, size, popupButtonMargins(), zoomLevel);
528     }
529 }
530
531 IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const
532 {
533     // Only do the inflation if the available width/height are too small.  Otherwise try to
534     // fit the glow/check space into the available box's width/height.
535     int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
536     int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
537     IntRect result(r);
538     if (widthDelta < 0) {
539         result.setX(result.x() - margins[leftMargin] * zoomLevel);
540         result.setWidth(result.width() - widthDelta);
541     }
542     if (heightDelta < 0) {
543         result.setY(result.y() - margins[topMargin] * zoomLevel);
544         result.setHeight(result.height() - heightDelta);
545     }
546     return result;
547 }
548
549 FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const
550 {
551     FloatRect partRect(inputRect);
552     
553     // Compute an offset between the part renderer and the input renderer
554     FloatSize offsetFromInputRenderer;
555     const RenderObject* renderer = partRenderer;
556     while (renderer && renderer != inputRenderer) {
557         RenderObject* containingRenderer = renderer->container();
558         offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer, LayoutPoint());
559         renderer = containingRenderer;
560     }
561     // If the input renderer was not a container, something went wrong
562     ASSERT(renderer == inputRenderer);
563     // Move the rect into partRenderer's coords
564     partRect.move(offsetFromInputRenderer);
565     // Account for the local drawing offset (tx, ty)
566     partRect.move(r.x(), r.y());
567
568     return partRect;
569 }
570
571 void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject* o)
572 {
573     bool oldIndeterminate = [cell state] == NSMixedState;
574     bool indeterminate = isIndeterminate(o);
575     bool checked = isChecked(o);
576
577     if (oldIndeterminate != indeterminate) {
578         [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
579         return;
580     }
581
582     bool oldChecked = [cell state] == NSOnState;
583     if (checked != oldChecked)
584         [cell setState:checked ? NSOnState : NSOffState];
585 }
586
587 void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject* o)
588 {
589     bool oldEnabled = [cell isEnabled];
590     bool enabled = isEnabled(o);
591     if (enabled != oldEnabled)
592         [cell setEnabled:enabled];
593 }
594
595 void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o)
596 {
597     bool oldFocused = [cell showsFirstResponder];
598     bool focused = isFocused(o) && o->style()->outlineStyleIsAuto();
599     if (focused != oldFocused)
600         [cell setShowsFirstResponder:focused];
601 }
602
603 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o)
604 {
605     bool oldPressed = [cell isHighlighted];
606     bool pressed = (o->node() && o->node()->active());
607     if (pressed != oldPressed)
608         [cell setHighlighted:pressed];
609 }
610
611 bool RenderThemeMac::controlSupportsTints(const RenderObject* o) const
612 {
613     // An alternate way to implement this would be to get the appropriate cell object
614     // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
615     // that would be that we would match AppKit behavior more closely, but a disadvantage
616     // would be that we would rely on an AppKit SPI method.
617
618     if (!isEnabled(o))
619         return false;
620
621     // Checkboxes only have tint when checked.
622     if (o->style()->appearance() == CheckboxPart)
623         return isChecked(o);
624
625     // For now assume other controls have tint if enabled.
626     return true;
627 }
628
629 NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const
630 {
631     int fontSize = style->fontSize();
632     if (fontSize >= 16)
633         return NSRegularControlSize;
634     if (fontSize >= 11)
635         return NSSmallControlSize;
636     return NSMiniControlSize;
637 }
638
639 void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
640 {
641     NSControlSize size;
642     if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) &&
643         minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
644         size = NSRegularControlSize;
645     else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) &&
646              minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
647         size = NSSmallControlSize;
648     else
649         size = NSMiniControlSize;
650     if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
651         [cell setControlSize:size];
652 }
653
654 IntSize RenderThemeMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const
655 {
656     if (style->effectiveZoom() != 1.0f) {
657         IntSize result = sizes[controlSizeForFont(style)];
658         return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
659     }
660     return sizes[controlSizeForFont(style)];
661 }
662
663 IntSize RenderThemeMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
664 {
665     if (style->effectiveZoom() != 1.0f) {
666         IntSize result = sizes[controlSizeForSystemFont(style)];
667         return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
668     }
669     return sizes[controlSizeForSystemFont(style)];
670 }
671
672 void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
673 {
674     // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
675     IntSize size = sizeForFont(style, sizes);
676     if (style->width().isIntrinsicOrAuto() && size.width() > 0)
677         style->setWidth(Length(size.width(), Fixed));
678     if (style->height().isAuto() && size.height() > 0)
679         style->setHeight(Length(size.height(), Fixed));
680 }
681
682 void RenderThemeMac::setFontFromControlSize(CSSStyleSelector*, RenderStyle* style, NSControlSize controlSize) const
683 {
684     FontDescription fontDescription;
685     fontDescription.setIsAbsoluteSize(true);
686     fontDescription.setGenericFamily(FontDescription::SerifFamily);
687
688     NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
689     fontDescription.firstFamily().setFamily([font familyName]);
690     fontDescription.setComputedSize([font pointSize] * style->effectiveZoom());
691     fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom());
692
693     // Reset line height
694     style->setLineHeight(RenderStyle::initialLineHeight());
695
696     if (style->setFontDescription(fontDescription))
697         style->font().update(0);
698 }
699
700 NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle* style) const
701 {
702     int fontSize = style->fontSize();
703     if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
704         return NSRegularControlSize;
705     if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
706         return NSSmallControlSize;
707     return NSMiniControlSize;
708 }
709
710 bool RenderThemeMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
711 {
712     LocalCurrentGraphicsContext localContext(paintInfo.context);
713     wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o));
714     return false;
715 }
716
717 void RenderThemeMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
718 {
719 }
720
721 bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r)
722 {
723     if (paintInfo.context->paintingDisabled())
724         return true;
725
726     LocalCurrentGraphicsContext localContext(paintInfo.context);
727     wkDrawCapsLockIndicator(localContext.cgContext(), r);
728     
729     return false;
730 }
731
732 bool RenderThemeMac::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
733 {
734     LocalCurrentGraphicsContext localContext(paintInfo.context);
735     wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
736     return false;
737 }
738
739 void RenderThemeMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const
740 {
741 }
742
743 const int* RenderThemeMac::popupButtonMargins() const
744 {
745     static const int margins[3][4] =
746     {
747         { 0, 3, 1, 3 },
748         { 0, 3, 2, 3 },
749         { 0, 1, 0, 1 }
750     };
751     return margins[[popupButton() controlSize]];
752 }
753
754 const IntSize* RenderThemeMac::popupButtonSizes() const
755 {
756     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
757     return sizes;
758 }
759
760 const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
761 {
762     static const int padding[3][4] =
763     {
764         { 2, 26, 3, 8 },
765         { 2, 23, 3, 8 },
766         { 2, 22, 3, 10 }
767     };
768     return padding[size];
769 }
770
771 bool RenderThemeMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
772 {
773     LocalCurrentGraphicsContext localContext(paintInfo.context);
774     setPopupButtonCellState(o, r);
775
776     NSPopUpButtonCell* popupButton = this->popupButton();
777
778     float zoomLevel = o->style()->effectiveZoom();
779     IntSize size = popupButtonSizes()[[popupButton controlSize]];
780     size.setHeight(size.height() * zoomLevel);
781     size.setWidth(r.width());
782
783     // Now inflate it to account for the shadow.
784     IntRect inflatedRect = r;
785     if (r.width() >= minimumMenuListSize(o->style()))
786         inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel);
787
788     GraphicsContextStateSaver stateSaver(*paintInfo.context);
789     
790     // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
791     paintInfo.context->clip(inflatedRect);
792
793     if (zoomLevel != 1.0f) {
794         inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
795         inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
796         paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
797         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
798         paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
799     }
800
801     [popupButton drawWithFrame:inflatedRect inView:documentViewFor(o)];
802     [popupButton setControlView:nil];
803
804     return false;
805 }
806
807 #if ENABLE(METER_TAG)
808
809 IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const
810 {
811     if (NoControlPart == renderMeter->style()->appearance())
812         return bounds.size();
813
814     NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
815     // Makes enough room for cell's intrinsic size.
816     NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
817     return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
818                    bounds.height() < cellSize.height ? cellSize.height : bounds.height());
819 }
820
821 bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
822 {
823     if (!renderObject->isMeter())
824         return true;
825
826     LocalCurrentGraphicsContext localContext(paintInfo.context);
827
828     NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
829     GraphicsContextStateSaver stateSaver(*paintInfo.context);
830
831     [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
832     [cell setControlView:nil];
833     return false;
834 }
835
836 bool RenderThemeMac::supportsMeter(ControlPart part) const
837 {
838     switch (part) {
839     case RelevancyLevelIndicatorPart:
840     case DiscreteCapacityLevelIndicatorPart:
841     case RatingLevelIndicatorPart:
842     case MeterPart:
843     case ContinuousCapacityLevelIndicatorPart:
844         return true;
845     default:
846         return false;
847     }
848 }
849
850 NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
851 {
852     switch (part) {
853     case RelevancyLevelIndicatorPart:
854         return NSRelevancyLevelIndicatorStyle;
855     case DiscreteCapacityLevelIndicatorPart:
856         return NSDiscreteCapacityLevelIndicatorStyle;
857     case RatingLevelIndicatorPart:
858         return NSRatingLevelIndicatorStyle;
859     case MeterPart:
860     case ContinuousCapacityLevelIndicatorPart:
861     default:
862         return NSContinuousCapacityLevelIndicatorStyle;
863     }
864     
865 }
866
867 NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* renderMeter) const
868 {
869     RenderStyle* style = renderMeter->style();
870     ASSERT(style->appearance() != NoControlPart);
871
872     if (!m_levelIndicator)
873         m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
874     NSLevelIndicatorCell* cell = m_levelIndicator.get();
875
876     HTMLMeterElement* element = static_cast<HTMLMeterElement*>(renderMeter->node());
877     double value = element->value();
878
879     // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
880     // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
881     switch (element->gaugeRegion()) {
882     case HTMLMeterElement::GaugeRegionOptimum:
883         // Make meter the green
884         [cell setWarningValue:value + 1];
885         [cell setCriticalValue:value + 2];
886         break;
887     case HTMLMeterElement::GaugeRegionSuboptimal:
888         // Make the meter yellow
889         [cell setWarningValue:value - 1];
890         [cell setCriticalValue:value + 1];
891         break;
892     case HTMLMeterElement::GaugeRegionEvenLessGood:
893         // Make the meter red
894         [cell setWarningValue:value - 2];
895         [cell setCriticalValue:value - 1];
896         break;
897     }
898
899     [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
900     [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
901     [cell setMinValue:element->min()];
902     [cell setMaxValue:element->max()];
903     RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
904     [cell setObjectValue:valueObject.get()];
905
906     return cell;
907 }
908
909 #endif
910
911 #if ENABLE(PROGRESS_TAG)
912
913 double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
914 {
915     return progressAnimationFrameRate;
916 }
917
918 double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const
919 {
920     return progressAnimationNumFrames * progressAnimationFrameRate;
921 }
922
923 void RenderThemeMac::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const
924 {
925 }
926
927 bool RenderThemeMac::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
928 {
929     if (!renderObject->isProgress())
930         return true;
931
932     RenderProgress* renderProgress = toRenderProgress(renderObject);
933     HIThemeTrackDrawInfo trackInfo;
934     trackInfo.version = 0;
935     trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
936     trackInfo.bounds = IntRect(IntPoint(), rect.size());
937     trackInfo.min = 0;
938     trackInfo.max = numeric_limits<SInt32>::max();
939     trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0));
940     trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0));
941     trackInfo.attributes = kThemeTrackHorizontal;
942     trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
943     trackInfo.reserved = 0;
944     trackInfo.filler1 = 0;
945
946     OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(rect.size());
947     if (!imageBuffer)
948         return true;
949
950     ContextContainer cgContextContainer(imageBuffer->context());
951     CGContextRef cgContext = cgContextContainer.context();
952     HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
953
954     GraphicsContextStateSaver stateSaver(*paintInfo.context);
955
956     if (!renderProgress->style()->isLeftToRightDirection()) {
957         paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
958         paintInfo.context->scale(FloatSize(-1, 1));
959     }
960     
961     paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, rect.location());
962     return false;
963 }    
964 #endif
965
966 const float baseFontSize = 11.0f;
967 const float baseArrowHeight = 4.0f;
968 const float baseArrowWidth = 5.0f;
969 const float baseSpaceBetweenArrows = 2.0f;
970 const int arrowPaddingLeft = 6;
971 const int arrowPaddingRight = 6;
972 const int paddingBeforeSeparator = 4;
973 const int baseBorderRadius = 5;
974 const int styledPopupPaddingLeft = 8;
975 const int styledPopupPaddingTop = 1;
976 const int styledPopupPaddingBottom = 2;
977
978 static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
979 {
980     static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
981     static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
982     float a = inData[0];
983     int i = 0;
984     for (i = 0; i < 4; i++)
985         outData[i] = (1.0f - a) * dark[i] + a * light[i];
986 }
987
988 static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
989 {
990     static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
991     static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
992     float a = inData[0];
993     int i = 0;
994     for (i = 0; i < 4; i++)
995         outData[i] = (1.0f - a) * dark[i] + a * light[i];
996 }
997
998 static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
999 {
1000     static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1001     static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1002     float a = inData[0];
1003     int i = 0;
1004     for (i = 0; i < 4; i++)
1005         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1006 }
1007
1008 static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1009 {
1010     static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1011     static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1012     float a = inData[0];
1013     int i = 0;
1014     for (i = 0; i < 4; i++)
1015         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1016 }
1017
1018 void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1019 {
1020     if (r.isEmpty())
1021         return;
1022
1023     ContextContainer cgContextContainer(paintInfo.context);
1024     CGContextRef context = cgContextContainer.context();
1025
1026     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1027
1028     RoundedRect border = o->style()->getRoundedBorderFor(r);
1029     int radius = border.radii().topLeft().width();
1030
1031     CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1032
1033     FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1034     struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1035     RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1036     RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
1037
1038     FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1039     struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1040     RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1041     RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(),  bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
1042
1043     struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1044     RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1045     RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
1046
1047     RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1048
1049     RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(),  r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
1050
1051     {
1052         GraphicsContextStateSaver stateSaver(*paintInfo.context);
1053         CGContextClipToRect(context, r);
1054         paintInfo.context->addRoundedRectClip(border);
1055         context = cgContextContainer.context();
1056         CGContextDrawShading(context, mainShading.get());
1057     }
1058     
1059     {
1060         GraphicsContextStateSaver stateSaver(*paintInfo.context);
1061         CGContextClipToRect(context, topGradient);
1062         paintInfo.context->addRoundedRectClip(RoundedRect(enclosingLayoutRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
1063         context = cgContextContainer.context();
1064         CGContextDrawShading(context, topShading.get());
1065     }
1066     
1067     if (!bottomGradient.isEmpty()) {
1068         GraphicsContextStateSaver stateSaver(*paintInfo.context);
1069         CGContextClipToRect(context, bottomGradient);
1070         paintInfo.context->addRoundedRectClip(RoundedRect(enclosingLayoutRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
1071         context = cgContextContainer.context();
1072         CGContextDrawShading(context, bottomShading.get());
1073     }
1074
1075     {
1076         GraphicsContextStateSaver stateSaver(*paintInfo.context);
1077         CGContextClipToRect(context, r);
1078         paintInfo.context->addRoundedRectClip(border);
1079         context = cgContextContainer.context();
1080         CGContextDrawShading(context, leftShading.get());
1081         CGContextDrawShading(context, rightShading.get());
1082     }
1083 }
1084
1085 bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1086 {
1087     IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
1088                              r.y() + o->style()->borderTopWidth(),
1089                              r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
1090                              r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
1091     // Draw the gradients to give the styled popup menu a button appearance
1092     paintMenuListButtonGradients(o, paintInfo, bounds);
1093
1094     // 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
1095     float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1096     float centerY = bounds.y() + bounds.height() / 2.0f;
1097     float arrowHeight = baseArrowHeight * fontScale;
1098     float arrowWidth = baseArrowWidth * fontScale;
1099     float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth;
1100     float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1101
1102     if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
1103         return false;
1104     
1105     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1106
1107     paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace());
1108     paintInfo.context->setStrokeStyle(NoStroke);
1109
1110     FloatPoint arrow1[3];
1111     arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1112     arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1113     arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1114
1115     // Draw the top arrow
1116     paintInfo.context->drawConvexPolygon(3, arrow1, true);
1117
1118     FloatPoint arrow2[3];
1119     arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1120     arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1121     arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1122
1123     // Draw the bottom arrow
1124     paintInfo.context->drawConvexPolygon(3, arrow2, true);
1125
1126     Color leftSeparatorColor(0, 0, 0, 40);
1127     Color rightSeparatorColor(255, 255, 255, 40);
1128
1129     // FIXME: Should the separator thickness and space be scaled up by fontScale?
1130     int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1131     int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round?
1132
1133     // Draw the separator to the left of the arrows
1134     paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
1135     paintInfo.context->setStrokeStyle(SolidStroke);
1136     paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
1137     paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1138                                 IntPoint(leftEdgeOfSeparator, bounds.maxY()));
1139
1140     paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
1141     paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1142                                 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
1143     return false;
1144 }
1145
1146 static const IntSize* menuListButtonSizes()
1147 {
1148     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1149     return sizes;
1150 }
1151
1152 void RenderThemeMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1153 {
1154     NSControlSize controlSize = controlSizeForFont(style);
1155
1156     style->resetBorder();
1157     style->resetPadding();
1158     
1159     // Height is locked to auto.
1160     style->setHeight(Length(Auto));
1161
1162     // White-space is locked to pre
1163     style->setWhiteSpace(PRE);
1164
1165     // Set the foreground color to black or gray when we have the aqua look.
1166     // Cast to RGB32 is to work around a compiler bug.
1167     style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1168
1169     // Set the button's vertical size.
1170     setSizeFromFont(style, menuListButtonSizes());
1171
1172     // 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
1173     // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1174     // system font for the control size instead.
1175     setFontFromControlSize(selector, style, controlSize);
1176
1177     style->setBoxShadow(nullptr);
1178 }
1179
1180 int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const
1181 {
1182     if (style->appearance() == MenulistPart)
1183         return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
1184     if (style->appearance() == MenulistButtonPart)
1185         return styledPopupPaddingLeft * style->effectiveZoom();
1186     return 0;
1187 }
1188
1189 int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const
1190 {
1191     if (style->appearance() == MenulistPart)
1192         return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
1193     if (style->appearance() == MenulistButtonPart) {
1194         float fontScale = style->fontSize() / baseFontSize;
1195         float arrowWidth = baseArrowWidth * fontScale;
1196         return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
1197     }
1198     return 0;
1199 }
1200
1201 int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const
1202 {
1203     if (style->appearance() == MenulistPart)
1204         return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
1205     if (style->appearance() == MenulistButtonPart)
1206         return styledPopupPaddingTop * style->effectiveZoom();
1207     return 0;
1208 }
1209
1210 int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const
1211 {
1212     if (style->appearance() == MenulistPart)
1213         return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
1214     if (style->appearance() == MenulistButtonPart)
1215         return styledPopupPaddingBottom * style->effectiveZoom();
1216     return 0;
1217 }
1218
1219 void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1220 {
1221     float fontScale = style->fontSize() / baseFontSize;
1222
1223     style->resetPadding();
1224     style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1225
1226     const int minHeight = 15;
1227     style->setMinHeight(Length(minHeight, Fixed));
1228     
1229     style->setLineHeight(RenderStyle::initialLineHeight());
1230 }
1231
1232 void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
1233 {
1234     NSPopUpButtonCell* popupButton = this->popupButton();
1235
1236     // Set the control size based off the rectangle we're painting into.
1237     setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
1238
1239     // Update the various states we respond to.
1240     updateActiveState(popupButton, o);
1241     updateCheckedState(popupButton, o);
1242     updateEnabledState(popupButton, o);
1243     updatePressedState(popupButton, o);
1244     updateFocusedState(popupButton, o);
1245 }
1246
1247 const IntSize* RenderThemeMac::menuListSizes() const
1248 {
1249     static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1250     return sizes;
1251 }
1252
1253 int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const
1254 {
1255     return sizeForSystemFont(style, menuListSizes()).width();
1256 }
1257
1258 const int trackWidth = 5;
1259 const int trackRadius = 2;
1260
1261 void RenderThemeMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1262 {
1263     style->setBoxShadow(nullptr);
1264 }
1265
1266 bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1267 {
1268     IntRect bounds = r;
1269     float zoomLevel = o->style()->effectiveZoom();
1270     float zoomedTrackWidth = trackWidth * zoomLevel;
1271
1272     if (o->style()->appearance() ==  SliderHorizontalPart || o->style()->appearance() ==  MediaSliderPart) {
1273         bounds.setHeight(zoomedTrackWidth);
1274         bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1275     } else if (o->style()->appearance() == SliderVerticalPart) {
1276         bounds.setWidth(zoomedTrackWidth);
1277         bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1278     }
1279
1280     LocalCurrentGraphicsContext localContext(paintInfo.context);
1281     CGContextRef context = localContext.cgContext();
1282     CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1283
1284     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1285     CGContextClipToRect(context, bounds);
1286
1287     struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1288     RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1289     RetainPtr<CGShadingRef> mainShading;
1290     if (o->style()->appearance() == SliderVerticalPart)
1291         mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(),  bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
1292     else
1293         mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(),  bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
1294
1295     IntSize radius(trackRadius, trackRadius);
1296     paintInfo.context->addRoundedRectClip(RoundedRect(bounds, radius, radius, radius, radius));
1297     context = localContext.cgContext();
1298     CGContextDrawShading(context, mainShading.get());
1299     
1300     return false;
1301 }
1302
1303 void RenderThemeMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1304 {
1305     RenderTheme::adjustSliderThumbStyle(selector, style, element);
1306     style->setBoxShadow(nullptr);
1307 }
1308
1309 const float verticalSliderHeightPadding = 0.1f;
1310
1311 bool RenderThemeMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1312 {
1313     NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart
1314         ? sliderThumbVertical()
1315         : sliderThumbHorizontal();
1316
1317     LocalCurrentGraphicsContext localContext(paintInfo.context);
1318
1319     // Update the various states we respond to.
1320     updateActiveState(sliderThumbCell, o);
1321     updateEnabledState(sliderThumbCell, o);
1322     updateFocusedState(sliderThumbCell, (o->node() && o->node()->focusDelegate()->renderer()) ? o->node()->focusDelegate()->renderer() : o);
1323
1324     // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1325     bool oldPressed;
1326     if (o->style()->appearance() == SliderThumbVerticalPart)
1327         oldPressed = m_isSliderThumbVerticalPressed;
1328     else
1329         oldPressed = m_isSliderThumbHorizontalPressed;
1330
1331     bool pressed = isPressed(o);
1332
1333     if (o->style()->appearance() == SliderThumbVerticalPart)
1334         m_isSliderThumbVerticalPressed = pressed;
1335     else
1336         m_isSliderThumbHorizontalPressed = pressed;
1337
1338     if (pressed != oldPressed) {
1339         if (pressed)
1340             [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1341         else
1342             [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1343     }
1344
1345     FloatRect bounds = r;
1346     // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1347     if (o->style()->appearance() == SliderThumbVerticalPart)
1348         bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom());
1349
1350     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1351     float zoomLevel = o->style()->effectiveZoom();
1352     
1353     FloatRect unzoomedRect = bounds;
1354     if (zoomLevel != 1.0f) {
1355         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1356         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1357         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1358         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1359         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1360     }
1361     
1362 #if PLATFORM(MAC)
1363     // Workaround for <rdar://problem/9421781>.
1364     if (!o->view()->frameView()->documentView()) {
1365         paintInfo.context->translate(0, unzoomedRect.y());
1366         paintInfo.context->scale(FloatSize(1, -1));
1367         paintInfo.context->translate(0, -(unzoomedRect.y() + unzoomedRect.height()));
1368     }
1369 #elif PLATFORM(CHROMIUM)
1370     paintInfo.context->translate(0, unzoomedRect.y());
1371     paintInfo.context->scale(FloatSize(1, -1));
1372     paintInfo.context->translate(0, -(unzoomedRect.y() + unzoomedRect.height()));
1373 #endif
1374     
1375     [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
1376     [sliderThumbCell setControlView:nil];
1377
1378     return false;
1379 }
1380
1381 bool RenderThemeMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1382 {
1383     LocalCurrentGraphicsContext localContext(paintInfo.context);
1384     NSSearchFieldCell* search = this->search();
1385
1386     setSearchCellState(o, r);
1387
1388     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1389
1390     float zoomLevel = o->style()->effectiveZoom();
1391
1392     IntRect unzoomedRect = r;
1393     
1394     if (zoomLevel != 1.0f) {
1395         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1396         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1397         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1398         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1399         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1400     }
1401
1402     // Set the search button to nil before drawing.  Then reset it so we can draw it later.
1403     [search setSearchButtonCell:nil];
1404
1405     [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1406
1407     [search setControlView:nil];
1408     [search resetSearchButtonCell];
1409
1410     return false;
1411 }
1412
1413 void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&)
1414 {
1415     NSSearchFieldCell* search = this->search();
1416
1417     [search setControlSize:controlSizeForFont(o->style())];
1418
1419     // Update the various states we respond to.
1420     updateActiveState(search, o);
1421     updateEnabledState(search, o);
1422     updateFocusedState(search, o);
1423 }
1424
1425 const IntSize* RenderThemeMac::searchFieldSizes() const
1426 {
1427     static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1428     return sizes;
1429 }
1430
1431 void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const
1432 {
1433     // If the width and height are both specified, then we have nothing to do.
1434     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1435         return;
1436     
1437     // Use the font size to determine the intrinsic width of the control.
1438     setSizeFromFont(style, searchFieldSizes());
1439 }
1440
1441 void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const
1442 {
1443     // Override border.
1444     style->resetBorder();
1445     const short borderWidth = 2 * style->effectiveZoom();
1446     style->setBorderLeftWidth(borderWidth);
1447     style->setBorderLeftStyle(INSET);
1448     style->setBorderRightWidth(borderWidth);
1449     style->setBorderRightStyle(INSET);
1450     style->setBorderBottomWidth(borderWidth);
1451     style->setBorderBottomStyle(INSET);
1452     style->setBorderTopWidth(borderWidth);
1453     style->setBorderTopStyle(INSET);    
1454     
1455     // Override height.
1456     style->setHeight(Length(Auto));
1457     setSearchFieldSize(style);
1458     
1459     // Override padding size to match AppKit text positioning.
1460     const int padding = 1 * style->effectiveZoom();
1461     style->setPaddingLeft(Length(padding, Fixed));
1462     style->setPaddingRight(Length(padding, Fixed));
1463     style->setPaddingTop(Length(padding, Fixed));
1464     style->setPaddingBottom(Length(padding, Fixed));
1465     
1466     NSControlSize controlSize = controlSizeForFont(style);
1467     setFontFromControlSize(selector, style, controlSize);
1468
1469     style->setBoxShadow(nullptr);
1470 }
1471
1472 bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1473 {
1474     Node* input = o->node()->shadowAncestorNode();
1475     if (!input->renderer()->isBox())
1476         return false;
1477
1478     LocalCurrentGraphicsContext localContext(paintInfo.context);
1479     setSearchCellState(input->renderer(), r);
1480
1481     NSSearchFieldCell* search = this->search();
1482
1483     updateActiveState([search cancelButtonCell], o);
1484     updatePressedState([search cancelButtonCell], o);
1485
1486     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1487
1488     float zoomLevel = o->style()->effectiveZoom();
1489
1490     FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
1491
1492 #if ENABLE(INPUT_SPEECH)
1493     // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g.
1494     // when speech input is enabled for the input element.
1495     IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect();
1496     int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight();
1497     int spaceToRightOfCancelButton = absRight - (r.x() + r.width());
1498     localBounds.setX(localBounds.x() - spaceToRightOfCancelButton);
1499 #endif
1500
1501     localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1502
1503     FloatRect unzoomedRect(localBounds);
1504     if (zoomLevel != 1.0f) {
1505         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1506         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1507         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1508         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1509         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1510     }
1511
1512     [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1513     [[search cancelButtonCell] setControlView:nil];
1514     return false;
1515 }
1516
1517 const IntSize* RenderThemeMac::cancelButtonSizes() const
1518 {
1519     static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1520     return sizes;
1521 }
1522
1523 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1524 {
1525     IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1526     style->setWidth(Length(size.width(), Fixed));
1527     style->setHeight(Length(size.height(), Fixed));
1528     style->setBoxShadow(nullptr);
1529 }
1530
1531 const IntSize* RenderThemeMac::resultsButtonSizes() const
1532 {
1533     static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1534     return sizes;
1535 }
1536
1537 const int emptyResultsOffset = 9;
1538 void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1539 {
1540     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1541     style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1542     style->setHeight(Length(size.height(), Fixed));
1543     style->setBoxShadow(nullptr);
1544 }
1545
1546 bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1547 {
1548     return false;
1549 }
1550
1551 void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1552 {
1553     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1554     style->setWidth(Length(size.width(), Fixed));
1555     style->setHeight(Length(size.height(), Fixed));
1556     style->setBoxShadow(nullptr);
1557 }
1558
1559 bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1560 {
1561     Node* input = o->node()->shadowAncestorNode();
1562     if (!input->renderer()->isBox())
1563         return false;
1564
1565     LocalCurrentGraphicsContext localContext(paintInfo.context);
1566     setSearchCellState(input->renderer(), r);
1567
1568     NSSearchFieldCell* search = this->search();
1569
1570     if ([search searchMenuTemplate] != nil)
1571         [search setSearchMenuTemplate:nil];
1572
1573     updateActiveState([search searchButtonCell], o);
1574
1575     FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
1576     localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1577
1578     [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
1579     [[search searchButtonCell] setControlView:nil];
1580     return false;
1581 }
1582
1583 const int resultsArrowWidth = 5;
1584 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
1585 {
1586     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1587     style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1588     style->setHeight(Length(size.height(), Fixed));
1589     style->setBoxShadow(nullptr);
1590 }
1591
1592 bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1593 {
1594     Node* input = o->node()->shadowAncestorNode();
1595     if (!input->renderer()->isBox())
1596         return false;
1597
1598     LocalCurrentGraphicsContext localContext(paintInfo.context);
1599     setSearchCellState(input->renderer(), r);
1600
1601     NSSearchFieldCell* search = this->search();
1602
1603     updateActiveState([search searchButtonCell], o);
1604
1605     if (![search searchMenuTemplate])
1606         [search setSearchMenuTemplate:searchMenuTemplate()];
1607
1608     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1609     float zoomLevel = o->style()->effectiveZoom();
1610
1611     FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
1612     localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
1613     
1614     IntRect unzoomedRect(localBounds);
1615     if (zoomLevel != 1.0f) {
1616         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1617         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1618         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1619         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1620         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1621     }
1622
1623     [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1624     [[search searchButtonCell] setControlView:nil];
1625     
1626     return false;
1627 }
1628
1629 #if ENABLE(VIDEO)
1630 typedef enum {
1631     MediaControllerThemeClassic   = 1,
1632     MediaControllerThemeQuickTime = 2
1633 } MediaControllerThemeStyle;
1634
1635 static int mediaControllerTheme()
1636 {
1637     static int controllerTheme = -1;
1638     
1639     if (controllerTheme != -1)
1640         return controllerTheme;
1641
1642     controllerTheme = MediaControllerThemeClassic;
1643
1644     Boolean validKey;
1645     Boolean useQTMediaUIPref = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey);
1646
1647     if (validKey && !useQTMediaUIPref)
1648         return controllerTheme;
1649
1650     controllerTheme = MediaControllerThemeQuickTime;
1651     return controllerTheme;
1652 }
1653 #endif
1654
1655 const int sliderThumbWidth = 15;
1656 const int sliderThumbHeight = 15;
1657 const int mediaSliderThumbWidth = 13;
1658 const int mediaSliderThumbHeight = 14;
1659
1660 void RenderThemeMac::adjustSliderThumbSize(RenderStyle* style) const
1661 {
1662     float zoomLevel = style->effectiveZoom();
1663     if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
1664         style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1665         style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1666     } 
1667
1668 #if ENABLE(VIDEO)
1669     adjustMediaSliderThumbSize(style);
1670 #endif
1671 }
1672
1673 #if ENABLE(VIDEO)
1674
1675 void RenderThemeMac::adjustMediaSliderThumbSize(RenderStyle* style) const
1676 {
1677     ControlPart part = style->appearance();
1678
1679     if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart) {
1680         int width = mediaSliderThumbWidth;
1681         int height = mediaSliderThumbHeight;
1682         
1683         if (mediaControllerTheme() == MediaControllerThemeQuickTime) {
1684             CGSize size;
1685             
1686             wkMeasureMediaUIPart(part == MediaSliderThumbPart ? MediaSliderThumb : MediaVolumeSliderThumb, MediaControllerThemeQuickTime, NULL, &size);
1687             width = size.width;
1688             height = size.height;
1689         }
1690
1691         float zoomLevel = style->effectiveZoom();
1692         style->setWidth(Length(static_cast<int>(width * zoomLevel), Fixed));
1693         style->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed));
1694     }
1695 }
1696
1697 enum WKMediaControllerThemeState { 
1698     MediaUIPartDisabledFlag = 1 << 0,
1699     MediaUIPartPressedFlag = 1 << 1,
1700     MediaUIPartDrawEndCapsFlag = 1 << 3,
1701 };
1702
1703 static unsigned getMediaUIPartStateFlags(Node* node)
1704 {
1705     unsigned flags = 0;
1706
1707     if (node->disabled())
1708         flags |= MediaUIPartDisabledFlag;
1709     else if (node->active())
1710         flags |= MediaUIPartPressedFlag;
1711     return flags;
1712 }
1713
1714 // Utility to scale when the UI part are not scaled by wkDrawMediaUIPart
1715 static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const PaintInfo& paintInfo, const IntRect &originalRect)
1716 {
1717     float zoomLevel = o->style()->effectiveZoom();
1718     FloatRect unzoomedRect(originalRect);
1719     if (zoomLevel != 1.0f && mediaControllerTheme() == MediaControllerThemeQuickTime) {
1720         unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1721         unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1722         paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1723         paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1724         paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1725     }
1726     return unzoomedRect;
1727 }
1728
1729
1730 bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1731 {
1732     Node* node = o->node();
1733     if (!node)
1734         return false;
1735
1736     LocalCurrentGraphicsContext localContext(paintInfo.context);
1737     wkDrawMediaUIPart(MediaFullscreenButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1738     return false;
1739 }
1740
1741 bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1742 {
1743     Node* node = o->node();
1744     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1745     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1746         return false;
1747
1748     if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(node)) {
1749         LocalCurrentGraphicsContext localContext(paintInfo.context);
1750         wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1751
1752     }
1753     return false;
1754 }
1755
1756 bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1757 {
1758     Node* node = o->node();
1759     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1760     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1761         return false;
1762
1763     if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(node)) {
1764         LocalCurrentGraphicsContext localContext(paintInfo.context);
1765         wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1766     }
1767     return false;
1768 }
1769
1770 bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1771 {
1772     Node* node = o->node();
1773     if (!node)
1774         return false;
1775
1776     LocalCurrentGraphicsContext localContext(paintInfo.context);
1777     wkDrawMediaUIPart(MediaSeekBackButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1778     return false;
1779 }
1780
1781 bool RenderThemeMac::paintMediaSeekForwardButton(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(MediaSeekForwardButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1789     return false;
1790 }
1791
1792 bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1793 {
1794     Node* node = o->node();
1795     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1796     if (!mediaNode || !mediaNode->isElementNode() || !static_cast<Element*>(mediaNode)->isMediaElement())
1797         return false;
1798
1799     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1800     if (!mediaElement)
1801         return false;
1802
1803     RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
1804     ExceptionCode ignoredException;
1805     float timeLoaded = timeRanges->length() ? timeRanges->end(0, ignoredException) : 0;
1806     float currentTime = mediaElement->currentTime();
1807     float duration = mediaElement->duration();
1808     if (isnan(duration))
1809         duration = 0;
1810  
1811     ContextContainer cgContextContainer(paintInfo.context);
1812     CGContextRef context = cgContextContainer.context();
1813     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1814     FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
1815     wkDrawMediaSliderTrack(mediaControllerTheme(), context, unzoomedRect, 
1816         timeLoaded, currentTime, duration, getMediaUIPartStateFlags(node));
1817     return false;
1818 }
1819
1820 bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1821 {
1822     Node* node = o->node();
1823     if (!node)
1824         return false;
1825
1826     LocalCurrentGraphicsContext localContext(paintInfo.context);
1827     wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1828     return false;
1829 }
1830     
1831 bool RenderThemeMac::paintMediaRewindButton(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(MediaRewindButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1839     return false;
1840 }
1841
1842 bool RenderThemeMac::paintMediaReturnToRealtimeButton(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(MediaReturnToRealtimeButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1850     return false;
1851 }
1852
1853 bool RenderThemeMac::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1854 {
1855     HTMLInputElement* node = static_cast<HTMLInputElement*>(o->node());
1856     if (!node)
1857         return false;
1858     
1859     MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(node);
1860     if (!btn)
1861         return false;
1862
1863     LocalCurrentGraphicsContext localContext(paintInfo.context);
1864     wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1865
1866     return false;
1867 }
1868  
1869 bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1870 {
1871     Node* node = o->node();
1872     if (!node)
1873         return false;
1874
1875     LocalCurrentGraphicsContext localContext(paintInfo.context);
1876     wkDrawMediaUIPart(MediaTimelineContainer, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1877     return false;
1878 }
1879
1880 bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1881 {
1882     Node* node = o->node();
1883     if (!node)
1884         return false;
1885
1886     ContextContainer cgContextContainer(paintInfo.context);
1887     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1888     FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
1889     wkDrawMediaUIPart(MediaCurrentTimeDisplay, mediaControllerTheme(), cgContextContainer.context(), unzoomedRect, getMediaUIPartStateFlags(node));
1890     return false;
1891 }
1892
1893 bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1894 {
1895     Node* node = o->node();
1896     if (!node)
1897         return false;
1898
1899     ContextContainer cgContextContainer(paintInfo.context);
1900     GraphicsContextStateSaver stateSaver(*paintInfo.context);
1901     FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
1902     wkDrawMediaUIPart(MediaTimeRemainingDisplay, mediaControllerTheme(), cgContextContainer.context(), unzoomedRect, getMediaUIPartStateFlags(node));
1903     return false;
1904 }
1905
1906 bool RenderThemeMac::paintMediaVolumeSliderContainer(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1907 {
1908     Node* node = o->node();
1909     if (!node)
1910         return false;
1911
1912     LocalCurrentGraphicsContext localContext(paintInfo.context);
1913     wkDrawMediaUIPart(MediaVolumeSliderContainer, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1914     return false;
1915 }
1916
1917 bool RenderThemeMac::paintMediaVolumeSliderTrack(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(MediaVolumeSlider, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1925     return false;
1926 }
1927     
1928 bool RenderThemeMac::paintMediaVolumeSliderThumb(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(MediaVolumeSliderThumb, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
1936     return false;
1937 }
1938     
1939 String RenderThemeMac::extraMediaControlsStyleSheet()
1940 {
1941 #if PLATFORM(MAC)
1942     if (mediaControllerTheme() == MediaControllerThemeQuickTime)
1943         return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet));
1944
1945     return String();
1946 #else
1947     ASSERT_NOT_REACHED();
1948     return String();
1949 #endif
1950 }
1951
1952 #if ENABLE(FULLSCREEN_API)
1953 String RenderThemeMac::extraFullScreenStyleSheet()
1954 {
1955 #if PLATFORM(MAC)
1956     if (mediaControllerTheme() == MediaControllerThemeQuickTime)
1957         return String(fullscreenQuickTimeUserAgentStyleSheet, sizeof(fullscreenQuickTimeUserAgentStyleSheet));
1958     
1959     return String();
1960 #else
1961     ASSERT_NOT_REACHED();
1962     return String();
1963 #endif
1964 }
1965 #endif
1966
1967 bool RenderThemeMac::hasOwnDisabledStateHandlingFor(ControlPart part) const
1968 {
1969     if (part == MediaMuteButtonPart)
1970         return false;
1971
1972     return mediaControllerTheme() == MediaControllerThemeClassic;
1973 }
1974
1975 bool RenderThemeMac::usesMediaControlStatusDisplay()
1976 {
1977     return mediaControllerTheme() == MediaControllerThemeQuickTime;
1978 }
1979
1980 bool RenderThemeMac::usesMediaControlVolumeSlider() const
1981 {
1982     return mediaControllerTheme() == MediaControllerThemeQuickTime;
1983 }
1984
1985 IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const
1986 {
1987     return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size);
1988 }
1989
1990 bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const
1991 {
1992 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
1993     return true;
1994 #else
1995     return false;
1996 #endif
1997 }
1998
1999 #endif // ENABLE(VIDEO)
2000
2001 NSPopUpButtonCell* RenderThemeMac::popupButton() const
2002 {
2003     if (!m_popupButton) {
2004         m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
2005         [m_popupButton.get() setUsesItemFromMenu:NO];
2006         [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
2007     }
2008     
2009     return m_popupButton.get();
2010 }
2011
2012 NSSearchFieldCell* RenderThemeMac::search() const
2013 {
2014     if (!m_search) {
2015         m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
2016         [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
2017         [m_search.get() setBezeled:YES];
2018         [m_search.get() setEditable:YES];
2019         [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
2020     }
2021
2022     return m_search.get();
2023 }
2024
2025 NSMenu* RenderThemeMac::searchMenuTemplate() const
2026 {
2027     if (!m_searchMenuTemplate)
2028         m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]);
2029
2030     return m_searchMenuTemplate.get();
2031 }
2032
2033 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
2034 {
2035     if (!m_sliderThumbHorizontal) {
2036         m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]);
2037         [m_sliderThumbHorizontal.get() setTitle:nil];
2038         [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
2039         [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
2040         [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
2041     }
2042     
2043     return m_sliderThumbHorizontal.get();
2044 }
2045
2046 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
2047 {
2048     if (!m_sliderThumbVertical) {
2049         m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]);
2050         [m_sliderThumbVertical.get() setTitle:nil];
2051         [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
2052         [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
2053         [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
2054     }
2055     
2056     return m_sliderThumbVertical.get();
2057 }
2058
2059 String RenderThemeMac::fileListNameForWidth(const Vector<String>& filenames, const Font& font, int width)
2060 {
2061     if (width <= 0)
2062         return String();
2063
2064     String strToTruncate;
2065     if (filenames.isEmpty())
2066         strToTruncate = fileButtonNoFileSelectedLabel();
2067     else if (filenames.size() == 1)
2068         strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(filenames[0])];
2069     else
2070         return StringTruncator::rightTruncate(multipleFileUploadText(filenames.size()), width, font, StringTruncator::EnableRoundingHacks);
2071
2072     return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
2073 }
2074
2075 } // namespace WebCore