Reviewed by Sam.
[WebKit-https.git] / WebCore / rendering / RenderThemeMac.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008 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 "CSSStyleSelector.h"
25 #import "CSSValueKeywords.h"
26 #import "Document.h"
27 #import "Element.h"
28 #import "FoundationExtras.h"
29 #import "FrameView.h"
30 #import "GraphicsContext.h"
31 #import "HTMLInputElement.h"
32 #import "HTMLMediaElement.h"
33 #import "HTMLNames.h"
34 #import "Image.h"
35 #import "LocalCurrentGraphicsContext.h"
36 #import "RenderSlider.h"
37 #import "RenderView.h"
38 #import "SharedBuffer.h"
39 #import "WebCoreSystemInterface.h"
40 #import <Cocoa/Cocoa.h>
41 #import <wtf/RetainPtr.h>
42 #import <math.h>
43
44 #ifdef BUILDING_ON_TIGER
45 typedef unsigned NSUInteger;
46 #endif
47
48 using std::min;
49
50 // The methods in this file are specific to the Mac OS X platform.
51
52 // FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. 
53
54 @interface WebCoreRenderThemeNotificationObserver : NSObject
55 {
56     WebCore::RenderTheme *_theme;
57 }
58
59 - (id)initWithTheme:(WebCore::RenderTheme *)theme;
60 - (void)systemColorsDidChange:(NSNotification *)notification;
61
62 @end
63
64 @implementation WebCoreRenderThemeNotificationObserver
65
66 - (id)initWithTheme:(WebCore::RenderTheme *)theme
67 {
68     [super init];
69     _theme = theme;
70     
71     return self;
72 }
73
74 - (void)systemColorsDidChange:(NSNotification *)notification
75 {
76     ASSERT([[notification name] isEqualToString:NSSystemColorsDidChangeNotification]);
77     _theme->platformColorsDidChange();
78 }
79
80 @end
81
82 namespace WebCore {
83
84 using namespace HTMLNames;
85
86 enum {
87     topMargin,
88     rightMargin,
89     bottomMargin,
90     leftMargin
91 };
92
93 enum {
94     topPadding,
95     rightPadding,
96     bottomPadding,
97     leftPadding
98 };
99
100 RenderTheme* theme()
101 {
102     static RenderThemeMac* macTheme = new RenderThemeMac;
103     return macTheme;
104 }
105
106 RenderThemeMac::RenderThemeMac()
107     : m_resizeCornerImage(0)
108     , m_isSliderThumbHorizontalPressed(false)
109     , m_isSliderThumbVerticalPressed(false)
110     , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this])
111 {
112     [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
113                                                         selector:@selector(systemColorsDidChange:)
114                                                             name:NSSystemColorsDidChangeNotification
115                                                           object:nil];
116 }
117
118 RenderThemeMac::~RenderThemeMac()
119 {
120     [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
121     delete m_resizeCornerImage;
122 }
123
124 Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
125 {
126     NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
127     return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
128 }
129
130 Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
131 {
132     NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
133     return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
134 }
135
136 Color RenderThemeMac::activeListBoxSelectionBackgroundColor() const
137 {
138     NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
139     return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
140 }
141
142 void RenderThemeMac::systemFont(int cssValueId, FontDescription& fontDescription) const
143 {
144     static FontDescription systemFont;
145     static FontDescription smallSystemFont;
146     static FontDescription menuFont;
147     static FontDescription labelFont;
148     static FontDescription miniControlFont;
149     static FontDescription smallControlFont;
150     static FontDescription controlFont;
151
152     FontDescription* cachedDesc;
153     NSFont* font = nil;
154     switch (cssValueId) {
155         case CSS_VAL_SMALL_CAPTION:
156             cachedDesc = &smallSystemFont;
157             if (!smallSystemFont.isAbsoluteSize())
158                 font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
159             break;
160         case CSS_VAL_MENU:
161             cachedDesc = &menuFont;
162             if (!menuFont.isAbsoluteSize())
163                 font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
164             break;
165         case CSS_VAL_STATUS_BAR:
166             cachedDesc = &labelFont;
167             if (!labelFont.isAbsoluteSize())
168                 font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
169             break;
170         case CSS_VAL__WEBKIT_MINI_CONTROL:
171             cachedDesc = &miniControlFont;
172             if (!miniControlFont.isAbsoluteSize())
173                 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
174             break;
175         case CSS_VAL__WEBKIT_SMALL_CONTROL:
176             cachedDesc = &smallControlFont;
177             if (!smallControlFont.isAbsoluteSize())
178                 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
179             break;
180         case CSS_VAL__WEBKIT_CONTROL:
181             cachedDesc = &controlFont;
182             if (!controlFont.isAbsoluteSize())
183                 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
184             break;
185         default:
186             cachedDesc = &systemFont;
187             if (!systemFont.isAbsoluteSize())
188                 font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
189     }
190
191     if (font) {
192         cachedDesc->setIsAbsoluteSize(true);
193         cachedDesc->setGenericFamily(FontDescription::NoFamily);
194         cachedDesc->firstFamily().setFamily([font familyName]);
195         cachedDesc->setSpecifiedSize([font pointSize]);
196         NSFontTraitMask traits = [[NSFontManager sharedFontManager] traitsOfFont:font];
197         cachedDesc->setBold(traits & NSBoldFontMask);
198         cachedDesc->setItalic(traits & NSItalicFontMask);
199     }
200     fontDescription = *cachedDesc;
201 }
202
203 static RGBA32 convertNSColorToColor(NSColor *color)
204 {
205     NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
206     if (colorInColorSpace) {
207         static const double scaleFactor = nextafter(256.0, 0.0);
208         return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
209             static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
210             static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
211     }
212
213     // This conversion above can fail if the NSColor in question is an NSPatternColor 
214     // (as many system colors are). These colors are actually a repeating pattern
215     // not just a solid color. To work around this we simply draw a 1x1 image of
216     // the color and use that pixel's color. It might be better to use an average of
217     // the colors in the pattern instead.
218     NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
219                                                                              pixelsWide:1
220                                                                              pixelsHigh:1
221                                                                           bitsPerSample:8
222                                                                         samplesPerPixel:4
223                                                                                hasAlpha:YES
224                                                                                isPlanar:NO
225                                                                          colorSpaceName:NSCalibratedRGBColorSpace
226                                                                             bytesPerRow:4
227                                                                            bitsPerPixel:32];
228
229     [NSGraphicsContext saveGraphicsState];
230     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
231     NSEraseRect(NSMakeRect(0, 0, 1, 1));
232     [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
233     [NSGraphicsContext restoreGraphicsState];
234
235     NSUInteger pixel[4];
236     [offscreenRep getPixel:pixel atX:0 y:0];
237
238     [offscreenRep release];
239
240     return makeRGB(pixel[0], pixel[1], pixel[2]);
241 }
242
243 void RenderThemeMac::platformColorsDidChange()
244 {
245     m_systemColorCache.clear();
246     RenderTheme::platformColorsDidChange();
247 }
248
249 Color RenderThemeMac::systemColor(int cssValueId) const
250 {
251     if (m_systemColorCache.contains(cssValueId))
252         return m_systemColorCache.get(cssValueId);
253     
254     Color color;
255     switch (cssValueId) {
256         case CSS_VAL_ACTIVEBORDER:
257             color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
258             break;
259         case CSS_VAL_ACTIVECAPTION:
260             color = convertNSColorToColor([NSColor windowFrameTextColor]);
261             break;
262         case CSS_VAL_APPWORKSPACE:
263             color = convertNSColorToColor([NSColor headerColor]);
264             break;
265         case CSS_VAL_BACKGROUND:
266             // Use theme independent default
267             break;
268         case CSS_VAL_BUTTONFACE:
269             // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
270             // We may want to change this to use the NSColor in future.
271             color = 0xFFC0C0C0;
272             break;
273         case CSS_VAL_BUTTONHIGHLIGHT:
274             color = convertNSColorToColor([NSColor controlHighlightColor]);
275             break;
276         case CSS_VAL_BUTTONSHADOW:
277             color = convertNSColorToColor([NSColor controlShadowColor]);
278             break;
279         case CSS_VAL_BUTTONTEXT:
280             color = convertNSColorToColor([NSColor controlTextColor]);
281             break;
282         case CSS_VAL_CAPTIONTEXT:
283             color = convertNSColorToColor([NSColor textColor]);
284             break;
285         case CSS_VAL_GRAYTEXT:
286             color = convertNSColorToColor([NSColor disabledControlTextColor]);
287             break;
288         case CSS_VAL_HIGHLIGHT:
289             color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
290             break;
291         case CSS_VAL_HIGHLIGHTTEXT:
292             color = convertNSColorToColor([NSColor selectedTextColor]);
293             break;
294         case CSS_VAL_INACTIVEBORDER:
295             color = convertNSColorToColor([NSColor controlBackgroundColor]);
296             break;
297         case CSS_VAL_INACTIVECAPTION:
298             color = convertNSColorToColor([NSColor controlBackgroundColor]);
299             break;
300         case CSS_VAL_INACTIVECAPTIONTEXT:
301             color = convertNSColorToColor([NSColor textColor]);
302             break;
303         case CSS_VAL_INFOBACKGROUND:
304             // There is no corresponding NSColor for this so we use a hard coded value.
305             color = 0xFFFBFCC5;
306             break;
307         case CSS_VAL_INFOTEXT:
308             color = convertNSColorToColor([NSColor textColor]);
309             break;
310         case CSS_VAL_MENU:
311             color = convertNSColorToColor([NSColor selectedMenuItemColor]);
312             break;
313         case CSS_VAL_MENUTEXT:
314             color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
315             break;
316         case CSS_VAL_SCROLLBAR:
317             color = convertNSColorToColor([NSColor scrollBarColor]);
318             break;
319         case CSS_VAL_TEXT:
320             color = convertNSColorToColor([NSColor textColor]);
321             break;
322         case CSS_VAL_THREEDDARKSHADOW:
323             color = convertNSColorToColor([NSColor controlDarkShadowColor]);
324             break;
325         case CSS_VAL_THREEDSHADOW:
326             color = convertNSColorToColor([NSColor shadowColor]);
327             break;
328         case CSS_VAL_THREEDFACE:
329             // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
330             // We may want to change this to use the NSColor in future.
331             color = 0xFFC0C0C0;
332             break;
333         case CSS_VAL_THREEDHIGHLIGHT:
334             color = convertNSColorToColor([NSColor highlightColor]);
335             break;
336         case CSS_VAL_THREEDLIGHTSHADOW:
337             color = convertNSColorToColor([NSColor controlLightHighlightColor]);
338             break;
339         case CSS_VAL_WINDOW:
340             color = convertNSColorToColor([NSColor windowBackgroundColor]);
341             break;
342         case CSS_VAL_WINDOWFRAME:
343             color = convertNSColorToColor([NSColor windowFrameColor]);
344             break;
345         case CSS_VAL_WINDOWTEXT:
346             color = convertNSColorToColor([NSColor windowFrameTextColor]);
347             break;
348     }
349
350     if (!color.isValid())
351         color = RenderTheme::systemColor(cssValueId);
352
353     if (color.isValid())
354         m_systemColorCache.set(cssValueId, color.rgb());
355
356     return color;
357 }
358
359 bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border,
360                                      const BackgroundLayer& background, const Color& backgroundColor) const
361 {
362     if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance || style->appearance() == ListboxAppearance)
363         return style->border() != border;
364     return RenderTheme::isControlStyled(style, border, background, backgroundColor);
365 }
366
367 void RenderThemeMac::paintResizeControl(GraphicsContext* c, const IntRect& r)
368 {
369     Image* resizeCornerImage = this->resizeCornerImage();
370     IntPoint imagePoint(r.right() - resizeCornerImage->width(), r.bottom() - resizeCornerImage->height());
371     c->drawImage(resizeCornerImage, imagePoint);
372 }
373
374 void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r)
375 {
376     switch (o->style()->appearance()) {
377         case CheckboxAppearance: {
378             // Since we query the prototype cell, we need to update its state to match.
379             setCheckboxCellState(o, r);
380
381             // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
382             // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
383             r = inflateRect(r, checkboxSizes()[[checkbox() controlSize]], checkboxMargins());
384             break;
385         }
386         case RadioAppearance: {
387             // Since we query the prototype cell, we need to update its state to match.
388             setRadioCellState(o, r);
389
390             // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
391             // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
392             r = inflateRect(r, radioSizes()[[radio() controlSize]], radioMargins());
393             break;
394         }
395         case PushButtonAppearance:
396         case ButtonAppearance: {
397             // Since we query the prototype cell, we need to update its state to match.
398             setButtonCellState(o, r);
399
400             // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
401             // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
402             if ([button() bezelStyle] == NSRoundedBezelStyle)
403                 r = inflateRect(r, buttonSizes()[[button() controlSize]], buttonMargins());
404             break;
405         }
406         case MenulistAppearance: {
407             setPopupButtonCellState(o, r);
408             r = inflateRect(r, popupButtonSizes()[[popupButton() controlSize]], popupButtonMargins());
409             break;
410         }
411         default:
412             break;
413     }
414 }
415
416 IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins) const
417 {
418     // Only do the inflation if the available width/height are too small.  Otherwise try to
419     // fit the glow/check space into the available box's width/height.
420     int widthDelta = r.width() - (size.width() + margins[leftMargin] + margins[rightMargin]);
421     int heightDelta = r.height() - (size.height() + margins[topMargin] + margins[bottomMargin]);
422     IntRect result(r);
423     if (widthDelta < 0) {
424         result.setX(result.x() - margins[leftMargin]);
425         result.setWidth(result.width() - widthDelta);
426     }
427     if (heightDelta < 0) {
428         result.setY(result.y() - margins[topMargin]);
429         result.setHeight(result.height() - heightDelta);
430     }
431     return result;
432 }
433
434 void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject* o)
435 {
436     bool oldIndeterminate = [cell state] == NSMixedState;
437     bool indeterminate = isIndeterminate(o);
438     bool checked = isChecked(o);
439
440     if (oldIndeterminate != indeterminate) {
441         [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
442         return;
443     }
444
445     bool oldChecked = [cell state] == NSOnState;
446     if (checked != oldChecked)
447         [cell setState:checked ? NSOnState : NSOffState];
448 }
449
450 void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject* o)
451 {
452     bool oldEnabled = [cell isEnabled];
453     bool enabled = isEnabled(o);
454     if (enabled != oldEnabled)
455         [cell setEnabled:enabled];
456 }
457
458 void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o)
459 {
460     bool oldFocused = [cell showsFirstResponder];
461     bool focused = isFocused(o) && o->style()->outlineStyleIsAuto();
462     if (focused != oldFocused)
463         [cell setShowsFirstResponder:focused];
464 }
465
466 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o)
467 {
468     bool oldPressed = [cell isHighlighted];
469     bool pressed = (o->element() && o->element()->active());
470     if (pressed != oldPressed)
471         [cell setHighlighted:pressed];
472 }
473
474 short RenderThemeMac::baselinePosition(const RenderObject* o) const
475 {
476     if (o->style()->appearance() == CheckboxAppearance || o->style()->appearance() == RadioAppearance)
477         return o->marginTop() + o->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
478     return RenderTheme::baselinePosition(o);
479 }
480
481 bool RenderThemeMac::controlSupportsTints(const RenderObject* o) const
482 {
483     // An alternate way to implement this would be to get the appropriate cell object
484     // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
485     // that would be that we would match AppKit behavior more closely, but a disadvantage
486     // would be that we would rely on an AppKit SPI method.
487
488     if (!isEnabled(o))
489         return false;
490
491     // Checkboxes only have tint when checked.
492     if (o->style()->appearance() == CheckboxAppearance)
493         return isChecked(o);
494
495     // For now assume other controls have tint if enabled.
496     return true;
497 }
498
499 NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const
500 {
501     int fontSize = style->fontSize();
502     if (fontSize >= 16)
503         return NSRegularControlSize;
504     if (fontSize >= 11)
505         return NSSmallControlSize;
506     return NSMiniControlSize;
507 }
508
509 void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize)
510 {
511     NSControlSize size;
512     if (minSize.width() >= sizes[NSRegularControlSize].width() &&
513         minSize.height() >= sizes[NSRegularControlSize].height())
514         size = NSRegularControlSize;
515     else if (minSize.width() >= sizes[NSSmallControlSize].width() &&
516              minSize.height() >= sizes[NSSmallControlSize].height())
517         size = NSSmallControlSize;
518     else
519         size = NSMiniControlSize;
520     if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
521         [cell setControlSize:size];
522 }
523
524 IntSize RenderThemeMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const
525 {
526     return sizes[controlSizeForFont(style)];
527 }
528
529 IntSize RenderThemeMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
530 {
531     return sizes[controlSizeForSystemFont(style)];
532 }
533
534 void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
535 {
536     // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
537     IntSize size = sizeForFont(style, sizes);
538     if (style->width().isIntrinsicOrAuto() && size.width() > 0)
539         style->setWidth(Length(size.width(), Fixed));
540     if (style->height().isAuto() && size.height() > 0)
541         style->setHeight(Length(size.height(), Fixed));
542 }
543
544 void RenderThemeMac::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const
545 {
546     FontDescription fontDescription;
547     fontDescription.setIsAbsoluteSize(true);
548     fontDescription.setGenericFamily(FontDescription::SerifFamily);
549
550     NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
551     fontDescription.firstFamily().setFamily([font familyName]);
552     fontDescription.setComputedSize([font pointSize]);
553     fontDescription.setSpecifiedSize([font pointSize]);
554
555     // Reset line height
556     style->setLineHeight(RenderStyle::initialLineHeight());
557
558     if (style->setFontDescription(fontDescription))
559         style->font().update(0);
560 }
561
562 NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle* style) const
563 {
564     int fontSize = style->fontSize();
565     if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
566         return NSRegularControlSize;
567     if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
568         return NSSmallControlSize;
569     return NSMiniControlSize;
570 }
571
572 bool RenderThemeMac::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo&, const IntRect& r)
573 {
574     // Determine the width and height needed for the control and prepare the cell for painting.
575     setCheckboxCellState(o, r);
576
577     // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
578     // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
579     NSButtonCell* checkbox = this->checkbox();
580     IntRect inflatedRect = inflateRect(r, checkboxSizes()[[checkbox controlSize]], checkboxMargins());
581     [checkbox drawWithFrame:NSRect(inflatedRect) inView:o->view()->frameView()->getDocumentView()];
582     [checkbox setControlView:nil];
583
584     return false;
585 }
586
587 const IntSize* RenderThemeMac::checkboxSizes() const
588 {
589     static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
590     return sizes;
591 }
592
593 const int* RenderThemeMac::checkboxMargins() const
594 {
595     static const int margins[3][4] =
596     {
597         { 3, 4, 4, 2 },
598         { 4, 3, 3, 3 },
599         { 4, 3, 3, 3 },
600     };
601     return margins[[checkbox() controlSize]];
602 }
603
604 void RenderThemeMac::setCheckboxCellState(const RenderObject* o, const IntRect& r)
605 {
606     NSButtonCell* checkbox = this->checkbox();
607
608     // Set the control size based off the rectangle we're painting into.
609     setControlSize(checkbox, checkboxSizes(), r.size());
610
611     // Update the various states we respond to.
612     updateCheckedState(checkbox, o);
613     updateEnabledState(checkbox, o);
614     updatePressedState(checkbox, o);
615     updateFocusedState(checkbox, o);
616 }
617
618 void RenderThemeMac::setCheckboxSize(RenderStyle* style) const
619 {
620     // If the width and height are both specified, then we have nothing to do.
621     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
622         return;
623
624     // Use the font size to determine the intrinsic width of the control.
625     setSizeFromFont(style, checkboxSizes());
626 }
627
628 bool RenderThemeMac::paintRadio(RenderObject* o, const RenderObject::PaintInfo&, const IntRect& r)
629 {
630     // Determine the width and height needed for the control and prepare the cell for painting.
631     setRadioCellState(o, r);
632
633     // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
634     // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
635     NSButtonCell* radio = this->radio();
636     IntRect inflatedRect = inflateRect(r, radioSizes()[[radio controlSize]], radioMargins());
637     [radio drawWithFrame:NSRect(inflatedRect) inView:o->view()->frameView()->getDocumentView()];
638     [radio setControlView:nil];
639
640     return false;
641 }
642
643 const IntSize* RenderThemeMac::radioSizes() const
644 {
645     static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
646     return sizes;
647 }
648
649 const int* RenderThemeMac::radioMargins() const
650 {
651     static const int margins[3][4] =
652     {
653         { 2, 2, 4, 2 },
654         { 3, 2, 3, 2 },
655         { 1, 0, 2, 0 },
656     };
657     return margins[[radio() controlSize]];
658 }
659
660 void RenderThemeMac::setRadioCellState(const RenderObject* o, const IntRect& r)
661 {
662     NSButtonCell* radio = this->radio();
663
664     // Set the control size based off the rectangle we're painting into.
665     setControlSize(radio, radioSizes(), r.size());
666
667     // Update the various states we respond to.
668     updateCheckedState(radio, o);
669     updateEnabledState(radio, o);
670     updatePressedState(radio, o);
671     updateFocusedState(radio, o);
672 }
673
674
675 void RenderThemeMac::setRadioSize(RenderStyle* style) const
676 {
677     // If the width and height are both specified, then we have nothing to do.
678     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
679         return;
680
681     // Use the font size to determine the intrinsic width of the control.
682     setSizeFromFont(style, radioSizes());
683 }
684
685 void RenderThemeMac::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const
686 {
687     // Just use 8px.  AppKit wants to use 11px for mini buttons, but that padding is just too large
688     // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
689     // by definition constrained, since we select mini only for small cramped environments.
690     // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent
691     // padding.
692     const int padding = 8;
693     style->setPaddingLeft(Length(padding, Fixed));
694     style->setPaddingRight(Length(padding, Fixed));
695     style->setPaddingTop(Length(0, Fixed));
696     style->setPaddingBottom(Length(0, Fixed));
697 }
698
699 void RenderThemeMac::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
700 {
701     // There are three appearance constants for buttons.
702     // (1) Push-button is the constant for the default Aqua system button.  Push buttons will not scale vertically and will not allow
703     // custom fonts or colors.  <input>s use this constant.  This button will allow custom colors and font weights/variants but won't
704     // scale vertically.
705     // (2) square-button is the constant for the square button.  This button will allow custom fonts and colors and will scale vertically.
706     // (3) Button is the constant that means "pick the best button as appropriate."  <button>s use this constant.  This button will
707     // also scale vertically and allow custom fonts and colors.  It will attempt to use Aqua if possible and will make this determination
708     // solely on the rectangle of the control.
709
710     // Determine our control size based off our font.
711     NSControlSize controlSize = controlSizeForFont(style);
712
713     if (style->appearance() == PushButtonAppearance) {
714         // Ditch the border.
715         style->resetBorder();
716
717         // Height is locked to auto.
718         style->setHeight(Length(Auto));
719
720         // White-space is locked to pre
721         style->setWhiteSpace(PRE);
722
723         // Set the button's vertical size.
724         setButtonSize(style);
725
726         // Add in the padding that we'd like to use.
727         setButtonPaddingFromControlSize(style, controlSize);
728
729         // 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
730         // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
731         // system font for the control size instead.
732         setFontFromControlSize(selector, style, controlSize);
733     } else {
734         // Set a min-height so that we can't get smaller than the mini button.
735         style->setMinHeight(Length(15, Fixed));
736
737         // Reset the top and bottom borders.
738         style->resetBorderTop();
739         style->resetBorderBottom();
740     }
741
742     style->setBoxShadow(0);
743 }
744
745 const IntSize* RenderThemeMac::buttonSizes() const
746 {
747     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
748     return sizes;
749 }
750
751 const int* RenderThemeMac::buttonMargins() const
752 {
753     static const int margins[3][4] =
754     {
755         { 4, 6, 7, 6 },
756         { 4, 5, 6, 5 },
757         { 0, 1, 1, 1 },
758     };
759     return margins[[button() controlSize]];
760 }
761
762 void RenderThemeMac::setButtonSize(RenderStyle* style) const
763 {
764     // If the width and height are both specified, then we have nothing to do.
765     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
766         return;
767
768     // Use the font size to determine the intrinsic width of the control.
769     setSizeFromFont(style, buttonSizes());
770 }
771
772 void RenderThemeMac::setButtonCellState(const RenderObject* o, const IntRect& r)
773 {
774     NSButtonCell* button = this->button();
775
776     // Set the control size based off the rectangle we're painting into.
777     if (o->style()->appearance() == SquareButtonAppearance ||
778         r.height() > buttonSizes()[NSRegularControlSize].height()) {
779         // Use the square button
780         if ([button bezelStyle] != NSShadowlessSquareBezelStyle)
781             [button setBezelStyle:NSShadowlessSquareBezelStyle];
782     } else if ([button bezelStyle] != NSRoundedBezelStyle)
783         [button setBezelStyle:NSRoundedBezelStyle];
784
785     setControlSize(button, buttonSizes(), r.size());
786
787     // Update the various states we respond to.
788     updateCheckedState(button, o);
789     updateEnabledState(button, o);
790     updatePressedState(button, o);
791     updateFocusedState(button, o);
792 }
793
794 bool RenderThemeMac::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
795 {
796     NSButtonCell* button = this->button();
797     LocalCurrentGraphicsContext localContext(paintInfo.context);
798
799     // Determine the width and height needed for the control and prepare the cell for painting.
800     setButtonCellState(o, r);
801
802     // We inflate the rect as needed to account for padding included in the cell to accommodate the button
803     // shadow.  We don't consider this part of the bounds of the control in WebKit.
804     IntSize size = buttonSizes()[[button controlSize]];
805     size.setWidth(r.width());
806     IntRect inflatedRect = r;
807     if ([button bezelStyle] == NSRoundedBezelStyle) {
808         // Center the button within the available space.
809         if (inflatedRect.height() > size.height()) {
810             inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2);
811             inflatedRect.setHeight(size.height());
812         }
813
814         // Now inflate it to account for the shadow.
815         inflatedRect = inflateRect(inflatedRect, size, buttonMargins());
816     }
817
818     [button drawWithFrame:NSRect(inflatedRect) inView:o->view()->frameView()->getDocumentView()];
819     [button setControlView:nil];
820
821     return false;
822 }
823
824 bool RenderThemeMac::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
825 {
826     LocalCurrentGraphicsContext localContext(paintInfo.context);
827     wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o));
828     return false;
829 }
830
831 void RenderThemeMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
832 {
833 }
834
835 bool RenderThemeMac::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
836 {
837     if (paintInfo.context->paintingDisabled())
838         return true;
839
840     LocalCurrentGraphicsContext localContext(paintInfo.context);
841     wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r);
842     
843     return false;
844 }
845
846 bool RenderThemeMac::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
847 {
848     LocalCurrentGraphicsContext localContext(paintInfo.context);
849     wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
850     return false;
851 }
852
853 void RenderThemeMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const
854 {
855 }
856
857 const int* RenderThemeMac::popupButtonMargins() const
858 {
859     static const int margins[3][4] =
860     {
861         { 0, 3, 1, 3 },
862         { 0, 3, 2, 3 },
863         { 0, 1, 0, 1 }
864     };
865     return margins[[popupButton() controlSize]];
866 }
867
868 const IntSize* RenderThemeMac::popupButtonSizes() const
869 {
870     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
871     return sizes;
872 }
873
874 const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
875 {
876     static const int padding[3][4] =
877     {
878         { 2, 26, 3, 8 },
879         { 2, 23, 3, 8 },
880         { 2, 22, 3, 10 }
881     };
882     return padding[size];
883 }
884
885 bool RenderThemeMac::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
886 {
887     setPopupButtonCellState(o, r);
888
889     NSPopUpButtonCell* popupButton = this->popupButton();
890
891     IntRect inflatedRect = r;
892     IntSize size = popupButtonSizes()[[popupButton controlSize]];
893     size.setWidth(r.width());
894
895     // Now inflate it to account for the shadow.
896     if (r.width() >= minimumMenuListSize(o->style()))
897         inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins());
898
899 #ifndef BUILDING_ON_TIGER
900     // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
901     paintInfo.context->save();
902     paintInfo.context->clip(inflatedRect);
903 #endif
904
905     [popupButton drawWithFrame:inflatedRect inView:o->view()->frameView()->getDocumentView()];
906     [popupButton setControlView:nil];
907
908 #ifndef BUILDING_ON_TIGER
909     paintInfo.context->restore();
910 #endif
911
912     return false;
913 }
914
915 const float baseFontSize = 11.0f;
916 const float baseArrowHeight = 4.0f;
917 const float baseArrowWidth = 5.0f;
918 const float baseSpaceBetweenArrows = 2.0f;
919 const int arrowPaddingLeft = 6;
920 const int arrowPaddingRight = 6;
921 const int paddingBeforeSeparator = 4;
922 const int baseBorderRadius = 5;
923 const int styledPopupPaddingLeft = 8;
924 const int styledPopupPaddingTop = 1;
925 const int styledPopupPaddingBottom = 2;
926
927 static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
928 {
929     static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
930     static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
931     float a = inData[0];
932     int i = 0;
933     for (i = 0; i < 4; i++)
934         outData[i] = (1.0f - a) * dark[i] + a * light[i];
935 }
936
937 static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
938 {
939     static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
940     static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
941     float a = inData[0];
942     int i = 0;
943     for (i = 0; i < 4; i++)
944         outData[i] = (1.0f - a) * dark[i] + a * light[i];
945 }
946
947 static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
948 {
949     static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
950     static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
951     float a = inData[0];
952     int i = 0;
953     for (i = 0; i < 4; i++)
954         outData[i] = (1.0f - a) * dark[i] + a * light[i];
955 }
956
957 static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
958 {
959     static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
960     static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
961     float a = inData[0];
962     int i = 0;
963     for (i = 0; i < 4; i++)
964         outData[i] = (1.0f - a) * dark[i] + a * light[i];
965 }
966
967 void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
968 {
969     CGContextRef context = paintInfo.context->platformContext();
970
971     paintInfo.context->save();
972
973     int radius = o->style()->borderTopLeftRadius().width();
974
975     RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
976
977     FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
978     struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
979     RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
980     RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false));
981
982     FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
983     struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
984     RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
985     RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(),  bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false));
986
987     struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
988     RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
989     RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(),  r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false));
990
991     RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(),  r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
992
993     RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(),  r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false));
994     paintInfo.context->save();
995     CGContextClipToRect(context, r);
996     paintInfo.context->addRoundedRectClip(r,
997         o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
998         o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
999     CGContextDrawShading(context, mainShading.get());
1000     paintInfo.context->restore();
1001
1002     paintInfo.context->save();
1003     CGContextClipToRect(context, topGradient);
1004     paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient),
1005         o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
1006         IntSize(), IntSize());
1007     CGContextDrawShading(context, topShading.get());
1008     paintInfo.context->restore();
1009
1010     paintInfo.context->save();
1011     CGContextClipToRect(context, bottomGradient);
1012     paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient),
1013         IntSize(), IntSize(),
1014         o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
1015     CGContextDrawShading(context, bottomShading.get());
1016     paintInfo.context->restore();
1017
1018     paintInfo.context->save();
1019     CGContextClipToRect(context, r);
1020     paintInfo.context->addRoundedRectClip(r,
1021         o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
1022         o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
1023     CGContextDrawShading(context, leftShading.get());
1024     CGContextDrawShading(context, rightShading.get());
1025     paintInfo.context->restore();
1026
1027     paintInfo.context->restore();
1028 }
1029
1030 bool RenderThemeMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1031 {
1032     paintInfo.context->save();
1033
1034     IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
1035                              r.y() + o->style()->borderTopWidth(),
1036                              r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
1037                              r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
1038     // Draw the gradients to give the styled popup menu a button appearance
1039     paintMenuListButtonGradients(o, paintInfo, bounds);
1040
1041     // 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
1042     float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1043     float centerY = bounds.y() + bounds.height() / 2.0f;
1044     float arrowHeight = baseArrowHeight * fontScale;
1045     float arrowWidth = baseArrowWidth * fontScale;
1046     float leftEdge = bounds.right() - arrowPaddingRight - arrowWidth;
1047     float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1048
1049     if (bounds.width() < arrowWidth + arrowPaddingLeft)
1050         return false;
1051     
1052     paintInfo.context->setFillColor(o->style()->color());
1053     paintInfo.context->setStrokeStyle(NoStroke);
1054
1055     FloatPoint arrow1[3];
1056     arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1057     arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1058     arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1059
1060     // Draw the top arrow
1061     paintInfo.context->drawConvexPolygon(3, arrow1, true);
1062
1063     FloatPoint arrow2[3];
1064     arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1065     arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1066     arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1067
1068     // Draw the bottom arrow
1069     paintInfo.context->drawConvexPolygon(3, arrow2, true);
1070
1071     Color leftSeparatorColor(0, 0, 0, 40);
1072     Color rightSeparatorColor(255, 255, 255, 40);
1073
1074     // FIXME: Should the separator thickness and space be scaled up by fontScale?
1075     int separatorSpace = 2;
1076     int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft); // FIXME: Round?
1077
1078     // Draw the separator to the left of the arrows
1079     paintInfo.context->setStrokeThickness(1.0f);
1080     paintInfo.context->setStrokeStyle(SolidStroke);
1081     paintInfo.context->setStrokeColor(leftSeparatorColor);
1082     paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1083                                 IntPoint(leftEdgeOfSeparator, bounds.bottom()));
1084
1085     paintInfo.context->setStrokeColor(rightSeparatorColor);
1086     paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1087                                 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
1088
1089     paintInfo.context->restore();
1090     return false;
1091 }
1092
1093 void RenderThemeMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1094 {
1095     NSControlSize controlSize = controlSizeForFont(style);
1096
1097     style->resetBorder();
1098     style->resetPadding();
1099     
1100     // Height is locked to auto.
1101     style->setHeight(Length(Auto));
1102
1103     // White-space is locked to pre
1104     style->setWhiteSpace(PRE);
1105
1106     // Set the foreground color to black or gray when we have the aqua look.
1107     // Cast to RGB32 is to work around a compiler bug.
1108     style->setColor(e->isEnabled() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1109
1110     // Set the button's vertical size.
1111     setButtonSize(style);
1112
1113     // 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
1114     // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1115     // system font for the control size instead.
1116     setFontFromControlSize(selector, style, controlSize);
1117
1118     style->setBoxShadow(0);
1119 }
1120
1121 int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const
1122 {
1123     if (style->appearance() == MenulistAppearance)
1124         return popupButtonPadding(controlSizeForFont(style))[leftPadding];
1125     if (style->appearance() == MenulistButtonAppearance)
1126         return styledPopupPaddingLeft;
1127     return 0;
1128 }
1129
1130 int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const
1131 {
1132     if (style->appearance() == MenulistAppearance)
1133         return popupButtonPadding(controlSizeForFont(style))[rightPadding];
1134     if (style->appearance() == MenulistButtonAppearance) {
1135         float fontScale = style->fontSize() / baseFontSize;
1136         float arrowWidth = baseArrowWidth * fontScale;
1137         return static_cast<int>(ceilf(arrowWidth + arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator));
1138     }
1139     return 0;
1140 }
1141
1142 int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const
1143 {
1144     if (style->appearance() == MenulistAppearance)
1145         return popupButtonPadding(controlSizeForFont(style))[topPadding];
1146     if (style->appearance() == MenulistButtonAppearance)
1147         return styledPopupPaddingTop;
1148     return 0;
1149 }
1150
1151 int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const
1152 {
1153     if (style->appearance() == MenulistAppearance)
1154         return popupButtonPadding(controlSizeForFont(style))[bottomPadding];
1155     if (style->appearance() == MenulistButtonAppearance)
1156         return styledPopupPaddingBottom;
1157     return 0;
1158 }
1159
1160 void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1161 {
1162     float fontScale = style->fontSize() / baseFontSize;
1163
1164     style->resetPadding();
1165     style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1166
1167     const int minHeight = 15;
1168     style->setMinHeight(Length(minHeight, Fixed));
1169     
1170     style->setLineHeight(RenderStyle::initialLineHeight());
1171 }
1172
1173 void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
1174 {
1175     NSPopUpButtonCell* popupButton = this->popupButton();
1176
1177     // Set the control size based off the rectangle we're painting into.
1178     setControlSize(popupButton, popupButtonSizes(), r.size());
1179
1180     // Update the various states we respond to.
1181     updateCheckedState(popupButton, o);
1182     updateEnabledState(popupButton, o);
1183     updatePressedState(popupButton, o);
1184     updateFocusedState(popupButton, o);
1185 }
1186
1187 const IntSize* RenderThemeMac::menuListSizes() const
1188 {
1189     static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1190     return sizes;
1191 }
1192
1193 int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const
1194 {
1195     return sizeForSystemFont(style, menuListSizes()).width();
1196 }
1197
1198 const int trackWidth = 5;
1199 const int trackRadius = 2;
1200
1201 void RenderThemeMac::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1202 {
1203     style->setBoxShadow(0);
1204 }
1205
1206 bool RenderThemeMac::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1207 {
1208     IntRect bounds = r;
1209
1210     if (o->style()->appearance() ==  SliderHorizontalAppearance || o->style()->appearance() ==  MediaSliderAppearance) {
1211         bounds.setHeight(trackWidth);
1212         bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
1213     } else if (o->style()->appearance() == SliderVerticalAppearance) {
1214         bounds.setWidth(trackWidth);
1215         bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
1216     }
1217
1218     LocalCurrentGraphicsContext localContext(paintInfo.context);
1219     CGContextRef context = paintInfo.context->platformContext();
1220     RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
1221
1222     paintInfo.context->save();
1223     CGContextClipToRect(context, bounds);
1224
1225     struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1226     RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1227     RetainPtr<CGShadingRef> mainShading;
1228     if (o->style()->appearance() == SliderVerticalAppearance)
1229         mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(),  bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false));
1230     else
1231         mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(),  bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false));
1232
1233     IntSize radius(trackRadius, trackRadius);
1234     paintInfo.context->addRoundedRectClip(bounds,
1235         radius, radius,
1236         radius, radius);
1237     CGContextDrawShading(context, mainShading.get());
1238     paintInfo.context->restore();
1239     
1240     return false;
1241 }
1242
1243 void RenderThemeMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1244 {
1245     style->setBoxShadow(0);
1246 }
1247
1248 const float verticalSliderHeightPadding = 0.1f;
1249
1250 bool RenderThemeMac::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1251 {
1252     ASSERT(o->parent()->isSlider());
1253
1254     NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalAppearance
1255         ? sliderThumbVertical()
1256         : sliderThumbHorizontal();
1257
1258     LocalCurrentGraphicsContext localContext(paintInfo.context);
1259
1260     // Update the various states we respond to.
1261     updateEnabledState(sliderThumbCell, o->parent());
1262     updateFocusedState(sliderThumbCell, o->parent());
1263
1264     // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1265     bool oldPressed;
1266     if (o->style()->appearance() == SliderThumbVerticalAppearance)
1267         oldPressed = m_isSliderThumbVerticalPressed;
1268     else
1269         oldPressed = m_isSliderThumbHorizontalPressed;
1270
1271     bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode();
1272
1273     if (o->style()->appearance() == SliderThumbVerticalAppearance)
1274         m_isSliderThumbVerticalPressed = pressed;
1275     else
1276         m_isSliderThumbHorizontalPressed = pressed;
1277
1278     if (pressed != oldPressed) {
1279         if (pressed)
1280             [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1281         else
1282             [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1283     }
1284
1285     FloatRect bounds = r;
1286     // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1287     if (o->style()->appearance() == SliderThumbVerticalAppearance)
1288         bounds.setHeight(bounds.height() + verticalSliderHeightPadding);
1289
1290     [sliderThumbCell drawWithFrame:NSRect(bounds) inView:o->view()->frameView()->getDocumentView()];
1291     [sliderThumbCell setControlView:nil];
1292
1293     return false;
1294 }
1295
1296 const int sliderThumbWidth = 15;
1297 const int sliderThumbHeight = 15;
1298 const int mediaSliderThumbWidth = 13;
1299 const int mediaSliderThumbHeight = 14;
1300
1301 void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const
1302 {
1303     if (o->style()->appearance() == SliderThumbHorizontalAppearance || o->style()->appearance() == SliderThumbVerticalAppearance) {
1304         o->style()->setWidth(Length(sliderThumbWidth, Fixed));
1305         o->style()->setHeight(Length(sliderThumbHeight, Fixed));
1306     } else if (o->style()->appearance() == MediaSliderThumbAppearance) {
1307         o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed));
1308         o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed));
1309     }
1310 }
1311
1312 bool RenderThemeMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1313 {
1314     NSSearchFieldCell* search = this->search();
1315     LocalCurrentGraphicsContext localContext(paintInfo.context);
1316
1317     setSearchCellState(o, r);
1318
1319     // Set the search button to nil before drawing.  Then reset it so we can draw it later.
1320     [search setSearchButtonCell:nil];
1321
1322     [search drawWithFrame:NSRect(r) inView:o->view()->frameView()->getDocumentView()];
1323 #ifdef BUILDING_ON_TIGER
1324     if ([search showsFirstResponder])
1325         wkDrawTextFieldCellFocusRing(search, NSRect(r));
1326 #endif
1327
1328     [search setControlView:nil];
1329     [search resetSearchButtonCell];
1330
1331     return false;
1332 }
1333
1334 void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect& r)
1335 {
1336     NSSearchFieldCell* search = this->search();
1337
1338     [search setControlSize:controlSizeForFont(o->style())];
1339
1340     // Update the various states we respond to.
1341     updateEnabledState(search, o);
1342     updateFocusedState(search, o);
1343 }
1344
1345 const IntSize* RenderThemeMac::searchFieldSizes() const
1346 {
1347     static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1348     return sizes;
1349 }
1350
1351 void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const
1352 {
1353     // If the width and height are both specified, then we have nothing to do.
1354     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1355         return;
1356     
1357     // Use the font size to determine the intrinsic width of the control.
1358     setSizeFromFont(style, searchFieldSizes());
1359 }
1360
1361 void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1362 {
1363     // Override border.
1364     style->resetBorder();
1365     const short borderWidth = 2;
1366     style->setBorderLeftWidth(borderWidth);
1367     style->setBorderLeftStyle(INSET);
1368     style->setBorderRightWidth(borderWidth);
1369     style->setBorderRightStyle(INSET);
1370     style->setBorderBottomWidth(borderWidth);
1371     style->setBorderBottomStyle(INSET);
1372     style->setBorderTopWidth(borderWidth);
1373     style->setBorderTopStyle(INSET);    
1374     
1375     // Override height.
1376     style->setHeight(Length(Auto));
1377     setSearchFieldSize(style);
1378     
1379     // Override padding size to match AppKit text positioning.
1380     const int padding = 1;
1381     style->setPaddingLeft(Length(padding, Fixed));
1382     style->setPaddingRight(Length(padding, Fixed));
1383     style->setPaddingTop(Length(padding, Fixed));
1384     style->setPaddingBottom(Length(padding, Fixed));
1385     
1386     NSControlSize controlSize = controlSizeForFont(style);
1387     setFontFromControlSize(selector, style, controlSize);
1388
1389     style->setBoxShadow(0);
1390 }
1391
1392 bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1393 {
1394     Node* input = o->node()->shadowAncestorNode();
1395     setSearchCellState(input->renderer(), r);
1396
1397     NSSearchFieldCell* search = this->search();
1398
1399     updatePressedState([search cancelButtonCell], o);
1400
1401     NSRect bounds = [search cancelButtonRectForBounds:NSRect(input->renderer()->absoluteBoundingBoxRect())];
1402     [[search cancelButtonCell] drawWithFrame:bounds inView:o->view()->frameView()->getDocumentView()];
1403     [[search cancelButtonCell] setControlView:nil];
1404
1405     return false;
1406 }
1407
1408 const IntSize* RenderThemeMac::cancelButtonSizes() const
1409 {
1410     static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1411     return sizes;
1412 }
1413
1414 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1415 {
1416     IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1417     style->setWidth(Length(size.width(), Fixed));
1418     style->setHeight(Length(size.height(), Fixed));
1419     style->setBoxShadow(0);
1420 }
1421
1422 const IntSize* RenderThemeMac::resultsButtonSizes() const
1423 {
1424     static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1425     return sizes;
1426 }
1427
1428 const int emptyResultsOffset = 9;
1429 void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1430 {
1431     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1432     style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1433     style->setHeight(Length(size.height(), Fixed));
1434     style->setBoxShadow(0);
1435 }
1436
1437 bool RenderThemeMac::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1438 {
1439     return false;
1440 }
1441
1442 void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1443 {
1444     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1445     style->setWidth(Length(size.width(), Fixed));
1446     style->setHeight(Length(size.height(), Fixed));
1447     style->setBoxShadow(0);
1448 }
1449
1450 bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1451 {
1452     Node* input = o->node()->shadowAncestorNode();
1453     setSearchCellState(input->renderer(), r);
1454
1455     NSSearchFieldCell* search = this->search();
1456
1457     if ([search searchMenuTemplate] != nil)
1458         [search setSearchMenuTemplate:nil];
1459
1460     NSRect bounds = [search searchButtonRectForBounds:NSRect(input->renderer()->absoluteBoundingBoxRect())];
1461     [[search searchButtonCell] drawWithFrame:bounds inView:o->view()->frameView()->getDocumentView()];
1462     [[search searchButtonCell] setControlView:nil];
1463     return false;
1464 }
1465
1466 const int resultsArrowWidth = 5;
1467 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
1468 {
1469     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1470     style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1471     style->setHeight(Length(size.height(), Fixed));
1472     style->setBoxShadow(0);
1473 }
1474
1475 bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1476 {
1477     Node* input = o->node()->shadowAncestorNode();
1478     setSearchCellState(input->renderer(), r);
1479
1480     NSSearchFieldCell* search = this->search();
1481
1482     if (![search searchMenuTemplate])
1483         [search setSearchMenuTemplate:searchMenuTemplate()];
1484
1485     NSRect bounds = [search searchButtonRectForBounds:NSRect(input->renderer()->absoluteBoundingBoxRect())];
1486     [[search searchButtonCell] drawWithFrame:bounds inView:o->view()->frameView()->getDocumentView()];
1487     [[search searchButtonCell] setControlView:nil];
1488     return false;
1489 }
1490
1491 bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1492 {
1493     Node* node = o->element();
1494     if (!node)
1495         return false;
1496
1497     LocalCurrentGraphicsContext localContext(paintInfo.context);
1498     wkDrawMediaFullscreenButton(paintInfo.context->platformContext(), r, node->active());
1499     return false;
1500 }
1501
1502 bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1503 {
1504     Node* node = o->element();
1505     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1506     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1507         return false;
1508
1509     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1510     if (!mediaElement)
1511         return false;
1512     
1513     LocalCurrentGraphicsContext localContext(paintInfo.context);
1514     if (mediaElement->muted())
1515         wkDrawMediaUnMuteButton(paintInfo.context->platformContext(), r, node->active());
1516     else
1517         wkDrawMediaMuteButton(paintInfo.context->platformContext(), r, node->active());        
1518     return false;
1519 }
1520
1521 bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1522 {
1523     Node* node = o->element();
1524     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1525     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1526         return false;
1527
1528     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1529     if (!mediaElement)
1530         return false;
1531
1532     LocalCurrentGraphicsContext localContext(paintInfo.context);
1533     if (mediaElement->canPlay())
1534         wkDrawMediaPlayButton(paintInfo.context->platformContext(), r, node->active());
1535     else
1536         wkDrawMediaPauseButton(paintInfo.context->platformContext(), r, node->active());        
1537     return false;
1538 }
1539
1540 bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1541 {
1542     Node* node = o->element();
1543     if (!node)
1544         return false;
1545
1546     LocalCurrentGraphicsContext localContext(paintInfo.context);
1547     wkDrawMediaSeekBackButton(paintInfo.context->platformContext(), r, node->active());
1548     return false;
1549 }
1550
1551 bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1552 {
1553     Node* node = o->element();
1554     if (!node)
1555         return false;
1556
1557     LocalCurrentGraphicsContext localContext(paintInfo.context);
1558     wkDrawMediaSeekForwardButton(paintInfo.context->platformContext(), r, node->active());
1559     return false;
1560 }
1561
1562 bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1563 {
1564     Node* node = o->element();
1565     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
1566     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1567         return false;
1568
1569     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1570     if (!mediaElement)
1571         return false;
1572
1573     float percentLoaded = 0;
1574     if (MediaPlayer* player = mediaElement->player())
1575         if (player->duration())
1576             percentLoaded = player->maxTimeBuffered() / player->duration();
1577
1578     wkDrawMediaSliderTrack(paintInfo.context->platformContext(), r, percentLoaded);
1579     return false;
1580 }
1581
1582 bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
1583 {
1584     Node* node = o->element();
1585     if (!node)
1586         return false;
1587
1588     LocalCurrentGraphicsContext localContext(paintInfo.context);
1589     wkDrawMediaSliderThumb(paintInfo.context->platformContext(), r, node->active());
1590     return false;
1591 }
1592
1593 NSButtonCell* RenderThemeMac::checkbox() const
1594 {
1595     if (!m_checkbox) {
1596         m_checkbox.adoptNS([[NSButtonCell alloc] init]);
1597         [m_checkbox.get() setButtonType:NSSwitchButton];
1598         [m_checkbox.get() setTitle:nil];
1599         [m_checkbox.get() setAllowsMixedState:YES];
1600         [m_checkbox.get() setFocusRingType:NSFocusRingTypeExterior];
1601     }
1602     
1603     return m_checkbox.get();
1604 }
1605
1606 NSButtonCell* RenderThemeMac::radio() const
1607 {
1608     if (!m_radio) {
1609         m_radio.adoptNS([[NSButtonCell alloc] init]);
1610         [m_radio.get() setButtonType:NSRadioButton];
1611         [m_radio.get() setTitle:nil];
1612         [m_radio.get() setFocusRingType:NSFocusRingTypeExterior];
1613     }
1614     
1615     return m_radio.get();
1616 }
1617
1618 NSButtonCell* RenderThemeMac::button() const
1619 {
1620     if (!m_button) {
1621         m_button.adoptNS([[NSButtonCell alloc] init]);
1622         [m_button.get() setTitle:nil];
1623         [m_button.get() setButtonType:NSMomentaryPushInButton];
1624     }
1625     
1626     return m_button.get();
1627 }
1628
1629 NSPopUpButtonCell* RenderThemeMac::popupButton() const
1630 {
1631     if (!m_popupButton) {
1632         m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
1633         [m_popupButton.get() setUsesItemFromMenu:NO];
1634         [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
1635     }
1636     
1637     return m_popupButton.get();
1638 }
1639
1640 NSSearchFieldCell* RenderThemeMac::search() const
1641 {
1642     if (!m_search) {
1643         m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
1644         [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
1645         [m_search.get() setBezeled:YES];
1646         [m_search.get() setEditable:YES];
1647         [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
1648     }
1649
1650     return m_search.get();
1651 }
1652
1653 NSMenu* RenderThemeMac::searchMenuTemplate() const
1654 {
1655     if (!m_searchMenuTemplate)
1656         m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]);
1657
1658     return m_searchMenuTemplate.get();
1659 }
1660
1661 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
1662 {
1663     if (!m_sliderThumbHorizontal) {
1664         m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]);
1665         [m_sliderThumbHorizontal.get() setTitle:nil];
1666         [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
1667         [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
1668         [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
1669     }
1670     
1671     return m_sliderThumbHorizontal.get();
1672 }
1673
1674 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
1675 {
1676     if (!m_sliderThumbVertical) {
1677         m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]);
1678         [m_sliderThumbVertical.get() setTitle:nil];
1679         [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
1680         [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
1681         [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
1682     }
1683     
1684     return m_sliderThumbVertical.get();
1685 }
1686
1687 Image* RenderThemeMac::resizeCornerImage() const
1688 {
1689     if (!m_resizeCornerImage)
1690         m_resizeCornerImage = Image::loadPlatformResource("textAreaResizeCorner");
1691     return m_resizeCornerImage;
1692 }
1693
1694 } // namespace WebCore