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