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