1/*
2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008, 2009 Google, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#import "config.h"
22#import "core/rendering/RenderThemeChromiumMac.h"
23
24#import "core/CSSValueKeywords.h"
25#import "core/HTMLNames.h"
26#import "core/UserAgentStyleSheets.h"
27#import "core/css/CSSValueList.h"
28#import "core/dom/Document.h"
29#import "core/dom/Element.h"
30#import "core/fileapi/FileList.h"
31#import "core/frame/FrameView.h"
32#import "core/html/HTMLInputElement.h"
33#import "core/html/HTMLMediaElement.h"
34#import "core/html/HTMLMeterElement.h"
35#import "core/html/TimeRanges.h"
36#import "core/html/shadow/MediaControlElements.h"
37#import "core/rendering/PaintInfo.h"
38#import "core/rendering/RenderLayer.h"
39#import "core/rendering/RenderMedia.h"
40#import "core/rendering/RenderMediaControls.h"
41#import "core/rendering/RenderMeter.h"
42#import "core/rendering/RenderProgress.h"
43#import "core/rendering/RenderSlider.h"
44#import "core/rendering/RenderView.h"
45#import "core/rendering/style/ShadowList.h"
46#import "platform/LayoutTestSupport.h"
47#import "platform/SharedBuffer.h"
48#import "platform/graphics/BitmapImage.h"
49#import "platform/graphics/GraphicsContextStateSaver.h"
50#import "platform/graphics/Image.h"
51#import "platform/graphics/ImageBuffer.h"
52#import "platform/mac/ColorMac.h"
53#import "platform/mac/LocalCurrentGraphicsContext.h"
54#import "platform/mac/ThemeMac.h"
55#import "platform/mac/WebCoreNSCellExtras.h"
56#import "platform/text/PlatformLocale.h"
57#import "platform/text/StringTruncator.h"
58#import <AvailabilityMacros.h>
59#import <Carbon/Carbon.h>
60#import <Cocoa/Cocoa.h>
61#import <math.h>
62#import <wtf/RetainPtr.h>
63#import <wtf/StdLibExtras.h>
64
65// The methods in this file are specific to the Mac OS X platform.
66
67// We estimate the animation rate of a Mac OS X progress bar is 33 fps.
68// Hard code the value here because we haven't found API for it.
69const double progressAnimationFrameRate = 0.033;
70
71// Mac OS X progress bar animation seems to have 256 frames.
72const double progressAnimationNumFrames = 256;
73
74@interface WebCoreRenderThemeNotificationObserver : NSObject
75{
76    blink::RenderTheme *_theme;
77}
78
79- (id)initWithTheme:(blink::RenderTheme *)theme;
80- (void)systemColorsDidChange:(NSNotification *)notification;
81
82@end
83
84@implementation WebCoreRenderThemeNotificationObserver
85
86- (id)initWithTheme:(blink::RenderTheme *)theme
87{
88    if (!(self = [super init]))
89        return nil;
90
91    _theme = theme;
92    return self;
93}
94
95- (void)systemColorsDidChange:(NSNotification *)unusedNotification
96{
97    ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
98    _theme->platformColorsDidChange();
99}
100
101@end
102
103@interface NSTextFieldCell (WKDetails)
104- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
105@end
106
107
108@interface WebCoreTextFieldCell : NSTextFieldCell
109- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
110@end
111
112@implementation WebCoreTextFieldCell
113- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
114{
115    // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
116    CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
117    CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
118    return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
119}
120@end
121
122@interface RTCMFlippedView : NSView
123{}
124
125- (BOOL)isFlipped;
126- (NSText *)currentEditor;
127
128@end
129
130@implementation RTCMFlippedView
131
132- (BOOL)isFlipped {
133    return [[NSGraphicsContext currentContext] isFlipped];
134}
135
136- (NSText *)currentEditor {
137    return nil;
138}
139
140@end
141
142// Forward declare Mac SPIs.
143extern "C" {
144void _NSDrawCarbonThemeBezel(NSRect frame, BOOL enabled, BOOL flipped);
145// Request for public API: rdar://13787640
146void _NSDrawCarbonThemeListBox(NSRect frame, BOOL enabled, BOOL flipped, BOOL always_yes);
147}
148
149namespace blink {
150
151using namespace HTMLNames;
152
153RenderThemeChromiumMac::RenderThemeChromiumMac()
154    : m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this])
155{
156    [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
157                                             selector:@selector(systemColorsDidChange:)
158                                                 name:NSSystemColorsDidChangeNotification
159                                               object:nil];
160}
161
162RenderThemeChromiumMac::~RenderThemeChromiumMac()
163{
164    [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
165}
166
167Color RenderThemeChromiumMac::platformActiveSelectionBackgroundColor() const
168{
169    NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
170    return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
171}
172
173Color RenderThemeChromiumMac::platformInactiveSelectionBackgroundColor() const
174{
175    NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
176    return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
177}
178
179Color RenderThemeChromiumMac::platformActiveSelectionForegroundColor() const
180{
181    return Color::black;
182}
183
184Color RenderThemeChromiumMac::platformActiveListBoxSelectionBackgroundColor() const
185{
186    NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
187    return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
188}
189
190Color RenderThemeChromiumMac::platformActiveListBoxSelectionForegroundColor() const
191{
192    return Color::white;
193}
194
195Color RenderThemeChromiumMac::platformInactiveListBoxSelectionForegroundColor() const
196{
197    return Color::black;
198}
199
200Color RenderThemeChromiumMac::platformFocusRingColor() const
201{
202    static const RGBA32 oldAquaFocusRingColor = 0xFF7DADD9;
203    if (usesTestModeFocusRingColor())
204        return oldAquaFocusRingColor;
205
206    return systemColor(CSSValueWebkitFocusRingColor);
207}
208
209Color RenderThemeChromiumMac::platformInactiveListBoxSelectionBackgroundColor() const
210{
211    return platformInactiveSelectionBackgroundColor();
212}
213
214static FontWeight toFontWeight(NSInteger appKitFontWeight)
215{
216    ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
217    if (appKitFontWeight > 14)
218        appKitFontWeight = 14;
219    else if (appKitFontWeight < 1)
220        appKitFontWeight = 1;
221
222    static FontWeight fontWeights[] = {
223        FontWeight100,
224        FontWeight100,
225        FontWeight200,
226        FontWeight300,
227        FontWeight400,
228        FontWeight500,
229        FontWeight600,
230        FontWeight600,
231        FontWeight700,
232        FontWeight800,
233        FontWeight800,
234        FontWeight900,
235        FontWeight900,
236        FontWeight900
237    };
238    return fontWeights[appKitFontWeight - 1];
239}
240
241void RenderThemeChromiumMac::systemFont(CSSValueID cssValueId, FontDescription& fontDescription) const
242{
243    DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
244    DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
245    DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
246    DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
247    DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
248    DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
249    DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
250
251    FontDescription* cachedDesc;
252    NSFont* font = nil;
253    switch (cssValueId) {
254    case CSSValueSmallCaption:
255        cachedDesc = &smallSystemFont;
256        if (!smallSystemFont.isAbsoluteSize())
257            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
258        break;
259    case CSSValueMenu:
260        cachedDesc = &menuFont;
261        if (!menuFont.isAbsoluteSize())
262            font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
263        break;
264    case CSSValueStatusBar:
265        cachedDesc = &labelFont;
266        if (!labelFont.isAbsoluteSize())
267            font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
268        break;
269    case CSSValueWebkitMiniControl:
270        cachedDesc = &miniControlFont;
271        if (!miniControlFont.isAbsoluteSize())
272            font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
273        break;
274    case CSSValueWebkitSmallControl:
275        cachedDesc = &smallControlFont;
276        if (!smallControlFont.isAbsoluteSize())
277            font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
278        break;
279    case CSSValueWebkitControl:
280        cachedDesc = &controlFont;
281        if (!controlFont.isAbsoluteSize())
282            font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
283        break;
284    default:
285        cachedDesc = &systemFont;
286        if (!systemFont.isAbsoluteSize())
287            font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
288    }
289
290    if (font) {
291        NSFontManager *fontManager = [NSFontManager sharedFontManager];
292        cachedDesc->setIsAbsoluteSize(true);
293        cachedDesc->setGenericFamily(FontDescription::NoFamily);
294        cachedDesc->firstFamily().setFamily([font webCoreFamilyName]);
295        cachedDesc->setSpecifiedSize([font pointSize]);
296        cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font]));
297        cachedDesc->setStyle([fontManager traitsOfFont:font] & NSItalicFontMask ? FontStyleItalic : FontStyleNormal);
298    }
299    fontDescription = *cachedDesc;
300}
301
302static RGBA32 convertNSColorToColor(NSColor *color)
303{
304    NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
305    if (colorInColorSpace) {
306        static const double scaleFactor = nextafter(256.0, 0.0);
307        return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
308            static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
309            static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
310    }
311
312    // This conversion above can fail if the NSColor in question is an NSPatternColor
313    // (as many system colors are). These colors are actually a repeating pattern
314    // not just a solid color. To work around this we simply draw a 1x1 image of
315    // the color and use that pixel's color. It might be better to use an average of
316    // the colors in the pattern instead.
317    NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
318                                                                             pixelsWide:1
319                                                                             pixelsHigh:1
320                                                                          bitsPerSample:8
321                                                                        samplesPerPixel:4
322                                                                               hasAlpha:YES
323                                                                               isPlanar:NO
324                                                                         colorSpaceName:NSDeviceRGBColorSpace
325                                                                            bytesPerRow:4
326                                                                           bitsPerPixel:32];
327
328    [NSGraphicsContext saveGraphicsState];
329    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
330    NSEraseRect(NSMakeRect(0, 0, 1, 1));
331    [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
332    [NSGraphicsContext restoreGraphicsState];
333
334    NSUInteger pixel[4];
335    [offscreenRep getPixel:pixel atX:0 y:0];
336
337    [offscreenRep release];
338
339    return makeRGB(pixel[0], pixel[1], pixel[2]);
340}
341
342static RGBA32 menuBackgroundColor()
343{
344    NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
345                                                                             pixelsWide:1
346                                                                             pixelsHigh:1
347                                                                          bitsPerSample:8
348                                                                        samplesPerPixel:4
349                                                                               hasAlpha:YES
350                                                                               isPlanar:NO
351                                                                         colorSpaceName:NSDeviceRGBColorSpace
352                                                                            bytesPerRow:4
353                                                                           bitsPerPixel:32];
354
355    CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
356    CGRect rect = CGRectMake(0, 0, 1, 1);
357    HIThemeMenuDrawInfo drawInfo;
358    drawInfo.version =  0;
359    drawInfo.menuType = kThemeMenuTypePopUp;
360    HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
361
362    NSUInteger pixel[4];
363    [offscreenRep getPixel:pixel atX:0 y:0];
364
365    [offscreenRep release];
366
367    return makeRGB(pixel[0], pixel[1], pixel[2]);
368}
369
370void RenderThemeChromiumMac::platformColorsDidChange()
371{
372    m_systemColorCache.clear();
373    RenderTheme::platformColorsDidChange();
374}
375
376Color RenderThemeChromiumMac::systemColor(CSSValueID cssValueId) const
377{
378    {
379        HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
380        if (it != m_systemColorCache.end())
381            return it->value;
382    }
383
384    Color color;
385    bool needsFallback = false;
386    switch (cssValueId) {
387    case CSSValueActiveborder:
388        color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
389        break;
390    case CSSValueActivecaption:
391        color = convertNSColorToColor([NSColor windowFrameTextColor]);
392        break;
393    case CSSValueAppworkspace:
394        color = convertNSColorToColor([NSColor headerColor]);
395        break;
396    case CSSValueBackground:
397        // Use theme independent default
398        needsFallback = true;
399        break;
400    case CSSValueButtonface:
401        // We use this value instead of NSColor's controlColor to avoid website
402        // incompatibilities. We may want to change this to use the NSColor in
403        // future.
404        color = 0xFFC0C0C0;
405        break;
406    case CSSValueButtonhighlight:
407        color = convertNSColorToColor([NSColor controlHighlightColor]);
408        break;
409    case CSSValueButtonshadow:
410        color = convertNSColorToColor([NSColor controlShadowColor]);
411        break;
412    case CSSValueButtontext:
413        color = convertNSColorToColor([NSColor controlTextColor]);
414        break;
415    case CSSValueCaptiontext:
416        color = convertNSColorToColor([NSColor textColor]);
417        break;
418    case CSSValueGraytext:
419        color = convertNSColorToColor([NSColor disabledControlTextColor]);
420        break;
421    case CSSValueHighlight:
422        color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
423        break;
424    case CSSValueHighlighttext:
425        color = convertNSColorToColor([NSColor selectedTextColor]);
426        break;
427    case CSSValueInactiveborder:
428        color = convertNSColorToColor([NSColor controlBackgroundColor]);
429        break;
430    case CSSValueInactivecaption:
431        color = convertNSColorToColor([NSColor controlBackgroundColor]);
432        break;
433    case CSSValueInactivecaptiontext:
434        color = convertNSColorToColor([NSColor textColor]);
435        break;
436    case CSSValueInfobackground:
437        // There is no corresponding NSColor for this so we use a hard coded
438        // value.
439        color = 0xFFFBFCC5;
440        break;
441    case CSSValueInfotext:
442        color = convertNSColorToColor([NSColor textColor]);
443        break;
444    case CSSValueMenu:
445        color = menuBackgroundColor();
446        break;
447    case CSSValueMenutext:
448        color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
449        break;
450    case CSSValueScrollbar:
451        color = convertNSColorToColor([NSColor scrollBarColor]);
452        break;
453    case CSSValueText:
454        color = convertNSColorToColor([NSColor textColor]);
455        break;
456    case CSSValueThreeddarkshadow:
457        color = convertNSColorToColor([NSColor controlDarkShadowColor]);
458        break;
459    case CSSValueThreedshadow:
460        color = convertNSColorToColor([NSColor shadowColor]);
461        break;
462    case CSSValueThreedface:
463        // We use this value instead of NSColor's controlColor to avoid website
464        // incompatibilities. We may want to change this to use the NSColor in
465        // future.
466        color = 0xFFC0C0C0;
467        break;
468    case CSSValueThreedhighlight:
469        color = convertNSColorToColor([NSColor highlightColor]);
470        break;
471    case CSSValueThreedlightshadow:
472        color = convertNSColorToColor([NSColor controlLightHighlightColor]);
473        break;
474    case CSSValueWebkitFocusRingColor:
475        color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
476        break;
477    case CSSValueWindow:
478        color = convertNSColorToColor([NSColor windowBackgroundColor]);
479        break;
480    case CSSValueWindowframe:
481        color = convertNSColorToColor([NSColor windowFrameColor]);
482        break;
483    case CSSValueWindowtext:
484        color = convertNSColorToColor([NSColor windowFrameTextColor]);
485        break;
486    default:
487        needsFallback = true;
488        break;
489    }
490
491    if (needsFallback)
492        color = RenderTheme::systemColor(cssValueId);
493
494    m_systemColorCache.set(cssValueId, color.rgb());
495
496    return color;
497}
498
499bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const CachedUAStyle* uaStyle) const
500{
501    ASSERT(uaStyle);
502    if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart)
503        return style->border() != uaStyle->border || style->boxShadow();
504
505    // FIXME: This is horrible, but there is not much else that can be done.
506    // Menu lists cannot draw properly when scaled. They can't really draw
507    // properly when transformed either. We can't detect the transform case at
508    // style adjustment time so that will just have to stay broken.  We can
509    // however detect that we're zooming. If zooming is in effect we treat it
510    // like the control is styled.
511    if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f)
512        return true;
513    // FIXME: NSSearchFieldCell doesn't work well when scaled.
514    if (style->appearance() == SearchFieldPart && style->effectiveZoom() != 1)
515        return true;
516
517    return RenderTheme::isControlStyled(style, uaStyle);
518}
519
520const int sliderThumbShadowBlur = 1;
521
522void RenderThemeChromiumMac::adjustPaintInvalidationRect(const RenderObject* o, IntRect& r)
523{
524    ControlPart part = o->style()->appearance();
525
526#if USE(NEW_THEME)
527    switch (part) {
528    case CheckboxPart:
529    case RadioPart:
530    case PushButtonPart:
531    case SquareButtonPart:
532    case ButtonPart:
533    case InnerSpinButtonPart:
534        return RenderTheme::adjustPaintInvalidationRect(o, r);
535    default:
536        break;
537    }
538#endif
539
540    float zoomLevel = o->style()->effectiveZoom();
541
542    if (part == MenulistPart) {
543        setPopupButtonCellState(o, r);
544        IntSize size = popupButtonSizes()[[popupButton() controlSize]];
545        size.setHeight(size.height() * zoomLevel);
546        size.setWidth(r.width());
547        r = ThemeMac::inflateRect(r, size, popupButtonMargins(), zoomLevel);
548    } else if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
549        r.setHeight(r.height() + sliderThumbShadowBlur);
550    }
551}
552
553FloatRect RenderThemeChromiumMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const
554{
555    FloatRect partRect(inputRect);
556
557    // Compute an offset between the part renderer and the input renderer.
558    FloatSize offsetFromInputRenderer;
559    const RenderObject* renderer = partRenderer;
560    while (renderer && renderer != inputRenderer) {
561        RenderObject* containingRenderer = renderer->container();
562        offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint()));
563        renderer = containingRenderer;
564    }
565    // If the input renderer was not a container, something went wrong.
566    ASSERT(renderer == inputRenderer);
567    // Move the rect into partRenderer's coords.
568    partRect.move(offsetFromInputRenderer);
569    // Account for the local drawing offset (tx, ty).
570    partRect.move(r.x(), r.y());
571
572    return partRect;
573}
574
575void RenderThemeChromiumMac::updateCheckedState(NSCell* cell, const RenderObject* o)
576{
577    bool oldIndeterminate = [cell state] == NSMixedState;
578    bool indeterminate = isIndeterminate(o);
579    bool checked = isChecked(o);
580
581    if (oldIndeterminate != indeterminate) {
582        [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
583        return;
584    }
585
586    bool oldChecked = [cell state] == NSOnState;
587    if (checked != oldChecked)
588        [cell setState:checked ? NSOnState : NSOffState];
589}
590
591void RenderThemeChromiumMac::updateEnabledState(NSCell* cell, const RenderObject* o)
592{
593    bool oldEnabled = [cell isEnabled];
594    bool enabled = isEnabled(o);
595    if (enabled != oldEnabled)
596        [cell setEnabled:enabled];
597}
598
599void RenderThemeChromiumMac::updateFocusedState(NSCell* cell, const RenderObject* o)
600{
601    bool oldFocused = [cell showsFirstResponder];
602    bool focused = isFocused(o) && o->style()->outlineStyleIsAuto();
603    if (focused != oldFocused)
604        [cell setShowsFirstResponder:focused];
605}
606
607void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject* o)
608{
609    bool oldPressed = [cell isHighlighted];
610    bool pressed = o->node() && o->node()->active();
611    if (pressed != oldPressed)
612        [cell setHighlighted:pressed];
613}
614
615NSControlSize RenderThemeChromiumMac::controlSizeForFont(RenderStyle* style) const
616{
617    int fontSize = style->fontSize();
618    if (fontSize >= 16)
619        return NSRegularControlSize;
620    if (fontSize >= 11)
621        return NSSmallControlSize;
622    return NSMiniControlSize;
623}
624
625// We don't use controlSizeForFont() for search field decorations because it
626// needs to fit into the search field. The font size will already be modified by
627// setFontFromControlSize() called on the search field.
628static NSControlSize searchFieldControlSizeForFont(RenderStyle* style)
629{
630    int fontSize = style->fontSize();
631    if (fontSize >= 13)
632        return NSRegularControlSize;
633    if (fontSize >= 11)
634        return NSSmallControlSize;
635    return NSMiniControlSize;
636}
637
638void RenderThemeChromiumMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
639{
640    NSControlSize size;
641    if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) &&
642        minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
643        size = NSRegularControlSize;
644    else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) &&
645             minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
646        size = NSSmallControlSize;
647    else
648        size = NSMiniControlSize;
649    // Only update if we have to, since AppKit does work even if the size is the
650    // same.
651    if (size != [cell controlSize])
652        [cell setControlSize:size];
653}
654
655IntSize RenderThemeChromiumMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const
656{
657    if (style->effectiveZoom() != 1.0f) {
658        IntSize result = sizes[controlSizeForFont(style)];
659        return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
660    }
661    return sizes[controlSizeForFont(style)];
662}
663
664IntSize RenderThemeChromiumMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
665{
666    if (style->effectiveZoom() != 1.0f) {
667        IntSize result = sizes[controlSizeForSystemFont(style)];
668        return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
669    }
670    return sizes[controlSizeForSystemFont(style)];
671}
672
673void RenderThemeChromiumMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
674{
675    // FIXME: Check is flawed, since it doesn't take min-width/max-width into
676    // account.
677    IntSize size = sizeForFont(style, sizes);
678    if (style->width().isIntrinsicOrAuto() && size.width() > 0)
679        style->setWidth(Length(size.width(), Fixed));
680    if (style->height().isAuto() && size.height() > 0)
681        style->setHeight(Length(size.height(), Fixed));
682}
683
684void RenderThemeChromiumMac::setFontFromControlSize(RenderStyle* style, NSControlSize controlSize) const
685{
686    FontDescription fontDescription;
687    fontDescription.setIsAbsoluteSize(true);
688    fontDescription.setGenericFamily(FontDescription::SerifFamily);
689
690    NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
691    fontDescription.firstFamily().setFamily([font webCoreFamilyName]);
692    fontDescription.setComputedSize([font pointSize] * style->effectiveZoom());
693    fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom());
694
695    // Reset line height.
696    style->setLineHeight(RenderStyle::initialLineHeight());
697
698    if (style->setFontDescription(fontDescription))
699        style->font().update(nullptr);
700}
701
702NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* style) const
703{
704    float fontSize = style->fontSize();
705    float zoomLevel = style->effectiveZoom();
706    if (zoomLevel != 1)
707        fontSize /= zoomLevel;
708    if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
709        return NSRegularControlSize;
710    if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
711        return NSSmallControlSize;
712    return NSMiniControlSize;
713}
714
715bool RenderThemeChromiumMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
716{
717    LocalCurrentGraphicsContext localContext(paintInfo.context, r);
718
719#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
720    bool useNSTextFieldCell = o->style()->hasAppearance()
721        && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white
722        && !o->style()->hasBackgroundImage();
723
724    // We do not use NSTextFieldCell to draw styled text fields on Lion and
725    // SnowLeopard because there are a number of bugs on those platforms that
726    // require NSTextFieldCell to be in charge of painting its own
727    // background. We need WebCore to paint styled backgrounds, so we'll use
728    // this AppKit SPI function instead.
729    if (!useNSTextFieldCell) {
730        _NSDrawCarbonThemeBezel(r, isEnabled(o) && !isReadOnlyControl(o), YES);
731        return false;
732    }
733#endif
734
735    NSTextFieldCell *textField = this->textField();
736
737    GraphicsContextStateSaver stateSaver(*paintInfo.context);
738
739    [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
740    [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
741
742    [textField setControlView:nil];
743
744    return false;
745}
746
747bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r)
748{
749    // This draws the caps lock indicator as it was done by
750    // WKDrawCapsLockIndicator.
751    LocalCurrentGraphicsContext localContext(paintInfo.context, r);
752    CGContextRef c = localContext.cgContext();
753    CGMutablePathRef shape = CGPathCreateMutable();
754
755    // To draw the caps lock indicator, draw the shape into a small
756    // square that is then scaled to the size of r.
757    const CGFloat kSquareSize = 17;
758
759    // Create a rounted square shape.
760    CGPathMoveToPoint(shape, NULL, 16.5, 4.5);
761    CGPathAddArc(shape, NULL, 12.5, 12.5, 4, 0,        M_PI_2,   false);
762    CGPathAddArc(shape, NULL, 4.5,  12.5, 4, M_PI_2,   M_PI,     false);
763    CGPathAddArc(shape, NULL, 4.5,  4.5,  4, M_PI,     3*M_PI/2, false);
764    CGPathAddArc(shape, NULL, 12.5, 4.5,  4, 3*M_PI/2, 0,        false);
765
766    // Draw the arrow - note this is drawing in a flipped coordinate system, so
767    // the arrow is pointing down.
768    CGPathMoveToPoint(shape, NULL, 8.5, 2);  // Tip point.
769    CGPathAddLineToPoint(shape, NULL, 4,     7);
770    CGPathAddLineToPoint(shape, NULL, 6.25,  7);
771    CGPathAddLineToPoint(shape, NULL, 6.25,  10.25);
772    CGPathAddLineToPoint(shape, NULL, 10.75, 10.25);
773    CGPathAddLineToPoint(shape, NULL, 10.75, 7);
774    CGPathAddLineToPoint(shape, NULL, 13,    7);
775    CGPathAddLineToPoint(shape, NULL, 8.5,   2);
776
777    // Draw the rectangle that underneath (or above in the flipped system) the
778    // arrow.
779    CGPathAddLineToPoint(shape, NULL, 10.75, 12);
780    CGPathAddLineToPoint(shape, NULL, 6.25,  12);
781    CGPathAddLineToPoint(shape, NULL, 6.25,  14.25);
782    CGPathAddLineToPoint(shape, NULL, 10.75, 14.25);
783    CGPathAddLineToPoint(shape, NULL, 10.75, 12);
784
785    // Scale and translate the shape.
786    CGRect cgr = r;
787    CGFloat maxX = CGRectGetMaxX(cgr);
788    CGFloat minY = CGRectGetMinY(cgr);
789    CGFloat heightScale = r.height() / kSquareSize;
790    CGAffineTransform transform = CGAffineTransformMake(
791        heightScale, 0,  // A  B
792        0, heightScale,  // C  D
793        maxX - r.height(), minY);  // Tx Ty
794
795    CGMutablePathRef paintPath = CGPathCreateMutable();
796    CGPathAddPath(paintPath, &transform, shape);
797    CGPathRelease(shape);
798
799    CGContextSetRGBFillColor(c, 0, 0, 0, 0.4);
800    CGContextBeginPath(c);
801    CGContextAddPath(c, paintPath);
802    CGContextFillPath(c);
803    CGPathRelease(paintPath);
804
805    return false;
806}
807
808bool RenderThemeChromiumMac::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
809{
810    LocalCurrentGraphicsContext localContext(paintInfo.context, r);
811    _NSDrawCarbonThemeListBox(r, isEnabled(o) && !isReadOnlyControl(o), YES, YES);
812    return false;
813}
814
815const int* RenderThemeChromiumMac::popupButtonMargins() const
816{
817    static const int margins[3][4] =
818    {
819        { 0, 3, 1, 3 },
820        { 0, 3, 2, 3 },
821        { 0, 1, 0, 1 }
822    };
823    return margins[[popupButton() controlSize]];
824}
825
826const IntSize* RenderThemeChromiumMac::popupButtonSizes() const
827{
828    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
829    return sizes;
830}
831
832const int* RenderThemeChromiumMac::popupButtonPadding(NSControlSize size) const
833{
834    static const int padding[3][4] =
835    {
836        { 2, 26, 3, 8 },
837        { 2, 23, 3, 8 },
838        { 2, 22, 3, 10 }
839    };
840    return padding[size];
841}
842
843bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
844{
845    setPopupButtonCellState(o, r);
846
847    NSPopUpButtonCell* popupButton = this->popupButton();
848
849    float zoomLevel = o->style()->effectiveZoom();
850    IntSize size = popupButtonSizes()[[popupButton controlSize]];
851    size.setHeight(size.height() * zoomLevel);
852    size.setWidth(r.width());
853
854    // Now inflate it to account for the shadow.
855    IntRect inflatedRect = r;
856    if (r.width() >= minimumMenuListSize(o->style()))
857        inflatedRect = ThemeMac::inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel);
858
859    LocalCurrentGraphicsContext localContext(paintInfo.context, ThemeMac::inflateRectForFocusRing(inflatedRect));
860    GraphicsContextStateSaver stateSaver(*paintInfo.context);
861
862    // On Leopard, the cell will draw outside of the given rect, so we have to
863    // clip to the rect.
864    paintInfo.context->clip(inflatedRect);
865
866    if (zoomLevel != 1.0f) {
867        inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
868        inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
869        paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
870        paintInfo.context->scale(zoomLevel, zoomLevel);
871        paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
872    }
873
874    NSView *view = documentViewFor(o);
875    [popupButton drawWithFrame:inflatedRect inView:view];
876#if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
877    if (isFocused(o) && o->style()->outlineStyleIsAuto())
878        [popupButton _web_drawFocusRingWithFrame:inflatedRect inView:view];
879#endif
880    [popupButton setControlView:nil];
881
882    return false;
883}
884
885IntSize RenderThemeChromiumMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const
886{
887    if (NoControlPart == renderMeter->style()->appearance())
888        return bounds.size();
889
890    NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
891    // Makes enough room for cell's intrinsic size.
892    NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
893    return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
894                   bounds.height() < cellSize.height ? cellSize.height : bounds.height());
895}
896
897bool RenderThemeChromiumMac::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
898{
899    if (!renderObject->isMeter())
900        return true;
901
902    LocalCurrentGraphicsContext localContext(paintInfo.context, rect);
903
904    NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
905    GraphicsContextStateSaver stateSaver(*paintInfo.context);
906
907    [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
908    [cell setControlView:nil];
909    return false;
910}
911
912bool RenderThemeChromiumMac::supportsMeter(ControlPart part) const
913{
914    switch (part) {
915    case RelevancyLevelIndicatorPart:
916    case DiscreteCapacityLevelIndicatorPart:
917    case RatingLevelIndicatorPart:
918    case MeterPart:
919    case ContinuousCapacityLevelIndicatorPart:
920        return true;
921    default:
922        return false;
923    }
924}
925
926NSLevelIndicatorStyle RenderThemeChromiumMac::levelIndicatorStyleFor(ControlPart part) const
927{
928    switch (part) {
929    case RelevancyLevelIndicatorPart:
930        return NSRelevancyLevelIndicatorStyle;
931    case DiscreteCapacityLevelIndicatorPart:
932        return NSDiscreteCapacityLevelIndicatorStyle;
933    case RatingLevelIndicatorPart:
934        return NSRatingLevelIndicatorStyle;
935    case MeterPart:
936    case ContinuousCapacityLevelIndicatorPart:
937    default:
938        return NSContinuousCapacityLevelIndicatorStyle;
939    }
940}
941
942NSLevelIndicatorCell* RenderThemeChromiumMac::levelIndicatorFor(const RenderMeter* renderMeter) const
943{
944    RenderStyle* style = renderMeter->style();
945    ASSERT(style->appearance() != NoControlPart);
946
947    if (!m_levelIndicator)
948        m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
949    NSLevelIndicatorCell* cell = m_levelIndicator.get();
950
951    HTMLMeterElement* element = renderMeter->meterElement();
952    double value = element->value();
953
954    // Because NSLevelIndicatorCell does not support optimum-in-the-middle type
955    // coloring, we explicitly control the color instead giving low and high
956    // value to NSLevelIndicatorCell as is.
957    switch (element->gaugeRegion()) {
958    case HTMLMeterElement::GaugeRegionOptimum:
959        // Make meter the green.
960        [cell setWarningValue:value + 1];
961        [cell setCriticalValue:value + 2];
962        break;
963    case HTMLMeterElement::GaugeRegionSuboptimal:
964        // Make the meter yellow.
965        [cell setWarningValue:value - 1];
966        [cell setCriticalValue:value + 1];
967        break;
968    case HTMLMeterElement::GaugeRegionEvenLessGood:
969        // Make the meter red.
970        [cell setWarningValue:value - 2];
971        [cell setCriticalValue:value - 1];
972        break;
973    }
974
975    [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
976    [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
977    [cell setMinValue:element->min()];
978    [cell setMaxValue:element->max()];
979    RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
980    [cell setObjectValue:valueObject.get()];
981
982    return cell;
983}
984
985const IntSize* RenderThemeChromiumMac::progressBarSizes() const
986{
987    static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
988    return sizes;
989}
990
991const int* RenderThemeChromiumMac::progressBarMargins(NSControlSize controlSize) const
992{
993    static const int margins[3][4] =
994    {
995        { 0, 0, 1, 0 },
996        { 0, 0, 1, 0 },
997        { 0, 0, 1, 0 },
998    };
999    return margins[controlSize];
1000}
1001
1002int RenderThemeChromiumMac::minimumProgressBarHeight(RenderStyle* style) const
1003{
1004    return sizeForSystemFont(style, progressBarSizes()).height();
1005}
1006
1007double RenderThemeChromiumMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
1008{
1009    return progressAnimationFrameRate;
1010}
1011
1012double RenderThemeChromiumMac::animationDurationForProgressBar(RenderProgress*) const
1013{
1014    return progressAnimationNumFrames * progressAnimationFrameRate;
1015}
1016
1017bool RenderThemeChromiumMac::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1018{
1019    if (!renderObject->isProgress())
1020        return true;
1021
1022    float zoomLevel = renderObject->style()->effectiveZoom();
1023    int controlSize = controlSizeForFont(renderObject->style());
1024    IntSize size = progressBarSizes()[controlSize];
1025    size.setHeight(size.height() * zoomLevel);
1026    size.setWidth(rect.width());
1027
1028    // Now inflate it to account for the shadow.
1029    IntRect inflatedRect = rect;
1030    if (rect.height() <= minimumProgressBarHeight(renderObject->style()))
1031        inflatedRect = ThemeMac::inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel);
1032
1033    RenderProgress* renderProgress = toRenderProgress(renderObject);
1034    HIThemeTrackDrawInfo trackInfo;
1035    trackInfo.version = 0;
1036    if (controlSize == NSRegularControlSize)
1037        trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
1038    else
1039        trackInfo.kind = renderProgress->position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
1040
1041    trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
1042    trackInfo.min = 0;
1043    trackInfo.max = std::numeric_limits<SInt32>::max();
1044    trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0));
1045    trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0));
1046    trackInfo.attributes = kThemeTrackHorizontal;
1047    trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
1048    trackInfo.reserved = 0;
1049    trackInfo.filler1 = 0;
1050
1051    OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size());
1052    if (!imageBuffer)
1053        return true;
1054
1055    LocalCurrentGraphicsContext localContext(imageBuffer->context(), IntRect(IntPoint(), inflatedRect.size()));
1056    CGContextRef cgContext = localContext.cgContext();
1057    HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
1058
1059    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1060
1061    if (!renderProgress->style()->isLeftToRightDirection()) {
1062        paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
1063        paintInfo.context->scale(-1, 1);
1064    }
1065
1066    paintInfo.context->drawImageBuffer(imageBuffer.get(),
1067        FloatRect(inflatedRect.location(), imageBuffer->size()));
1068    return false;
1069}
1070
1071const float baseFontSize = 11.0f;
1072const float baseArrowHeight = 4.0f;
1073const float baseArrowWidth = 5.0f;
1074const float baseSpaceBetweenArrows = 2.0f;
1075const int arrowPaddingLeft = 6;
1076const int arrowPaddingRight = 6;
1077const int paddingBeforeSeparator = 4;
1078const int baseBorderRadius = 5;
1079const int styledPopupPaddingLeft = 8;
1080const int styledPopupPaddingTop = 1;
1081const int styledPopupPaddingBottom = 2;
1082
1083bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1084{
1085    IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
1086                             r.y() + o->style()->borderTopWidth(),
1087                             r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
1088                             r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
1089    // Since we actually know the size of the control here, we restrict the font
1090    // scale to make sure the arrows will fit vertically in the bounds
1091    float fontScale = std::min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1092    float centerY = bounds.y() + bounds.height() / 2.0f;
1093    float arrowHeight = baseArrowHeight * fontScale;
1094    float arrowWidth = baseArrowWidth * fontScale;
1095    float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth;
1096    float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1097
1098    if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
1099        return false;
1100
1101    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1102
1103    paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor));
1104    paintInfo.context->setStrokeStyle(NoStroke);
1105
1106    FloatPoint arrow1[3];
1107    arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1108    arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1109    arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1110
1111    // Draw the top arrow.
1112    paintInfo.context->drawConvexPolygon(3, arrow1, true);
1113
1114    FloatPoint arrow2[3];
1115    arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1116    arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1117    arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1118
1119    // Draw the bottom arrow.
1120    paintInfo.context->drawConvexPolygon(3, arrow2, true);
1121    return false;
1122}
1123
1124static const IntSize* menuListButtonSizes()
1125{
1126    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1127    return sizes;
1128}
1129
1130void RenderThemeChromiumMac::adjustMenuListStyle(RenderStyle* style, Element* e) const
1131{
1132    NSControlSize controlSize = controlSizeForFont(style);
1133
1134    style->resetBorder();
1135    style->resetPadding();
1136
1137    // Height is locked to auto.
1138    style->setHeight(Length(Auto));
1139
1140    // White-space is locked to pre.
1141    style->setWhiteSpace(PRE);
1142
1143    // Set the foreground color to black or gray when we have the aqua look.
1144    // Cast to RGB32 is to work around a compiler bug.
1145    style->setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1146
1147    // Set the button's vertical size.
1148    setSizeFromFont(style, menuListButtonSizes());
1149
1150    // Our font is locked to the appropriate system font size for the
1151    // control. To clarify, we first use the CSS-specified font to figure out a
1152    // reasonable control size, but once that control size is determined, we
1153    // throw that font away and use the appropriate system font for the control
1154    // size instead.
1155    setFontFromControlSize(style, controlSize);
1156}
1157
1158const int autofillPopupHorizontalPadding = 4;
1159
1160// These functions are called with MenuListPart or MenulistButtonPart appearance
1161// by RenderMenuList, or with TextFieldPart appearance by
1162// AutofillPopupMenuClient. We assume only AutofillPopupMenuClient gives
1163// TexfieldPart appearance here. We want to change only Autofill padding.  In
1164// the future, we have to separate Autofill popup window logic from WebKit to
1165// Chromium.
1166int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const
1167{
1168    if (style->appearance() == TextFieldPart)
1169        return autofillPopupHorizontalPadding;
1170
1171    if (style->appearance() == MenulistPart)
1172        return popupButtonPadding(controlSizeForFont(style))[ThemeMac::LeftMargin] * style->effectiveZoom();
1173    if (style->appearance() == MenulistButtonPart)
1174        return styledPopupPaddingLeft * style->effectiveZoom();
1175    return 0;
1176}
1177
1178int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const
1179{
1180    if (style->appearance() == TextFieldPart)
1181        return autofillPopupHorizontalPadding;
1182
1183    if (style->appearance() == MenulistPart)
1184        return popupButtonPadding(controlSizeForFont(style))[ThemeMac::RightMargin] * style->effectiveZoom();
1185    if (style->appearance() == MenulistButtonPart) {
1186        float fontScale = style->fontSize() / baseFontSize;
1187        float arrowWidth = baseArrowWidth * fontScale;
1188        return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
1189    }
1190    return 0;
1191}
1192
1193int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const
1194{
1195    if (style->appearance() == MenulistPart)
1196        return popupButtonPadding(controlSizeForFont(style))[ThemeMac::TopMargin] * style->effectiveZoom();
1197    if (style->appearance() == MenulistButtonPart)
1198        return styledPopupPaddingTop * style->effectiveZoom();
1199    return 0;
1200}
1201
1202int RenderThemeChromiumMac::popupInternalPaddingBottom(RenderStyle* style) const
1203{
1204    if (style->appearance() == MenulistPart)
1205        return popupButtonPadding(controlSizeForFont(style))[ThemeMac::BottomMargin] * style->effectiveZoom();
1206    if (style->appearance() == MenulistButtonPart)
1207        return styledPopupPaddingBottom * style->effectiveZoom();
1208    return 0;
1209}
1210
1211void RenderThemeChromiumMac::adjustMenuListButtonStyle(RenderStyle* style, Element*) const
1212{
1213    float fontScale = style->fontSize() / baseFontSize;
1214
1215    style->resetPadding();
1216    style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1217
1218    const int minHeight = 15;
1219    style->setMinHeight(Length(minHeight, Fixed));
1220
1221    style->setLineHeight(RenderStyle::initialLineHeight());
1222}
1223
1224void RenderThemeChromiumMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
1225{
1226    NSPopUpButtonCell* popupButton = this->popupButton();
1227
1228    // Set the control size based off the rectangle we're painting into.
1229    setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
1230
1231    // Update the various states we respond to.
1232    updateActiveState(popupButton, o);
1233    updateCheckedState(popupButton, o);
1234    updateEnabledState(popupButton, o);
1235    updatePressedState(popupButton, o);
1236#if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
1237    updateFocusedState(popupButton, o);
1238#endif
1239}
1240
1241const IntSize* RenderThemeChromiumMac::menuListSizes() const
1242{
1243    static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1244    return sizes;
1245}
1246
1247int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const
1248{
1249    return sizeForSystemFont(style, menuListSizes()).width();
1250}
1251
1252const int sliderTrackWidth = 5;
1253const int sliderTrackBorderWidth = 1;
1254
1255bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1256{
1257    paintSliderTicks(o, paintInfo, r);
1258
1259    float zoomLevel = o->style()->effectiveZoom();
1260    FloatRect unzoomedRect = r;
1261
1262    if (o->style()->appearance() ==  SliderHorizontalPart || o->style()->appearance() ==  MediaSliderPart) {
1263        unzoomedRect.setY(ceilf(unzoomedRect.y() + unzoomedRect.height() / 2 - zoomLevel * sliderTrackWidth / 2));
1264        unzoomedRect.setHeight(zoomLevel * sliderTrackWidth);
1265    } else if (o->style()->appearance() == SliderVerticalPart) {
1266        unzoomedRect.setX(ceilf(unzoomedRect.x() + unzoomedRect.width() / 2 - zoomLevel * sliderTrackWidth / 2));
1267        unzoomedRect.setWidth(zoomLevel * sliderTrackWidth);
1268    }
1269
1270    if (zoomLevel != 1) {
1271        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1272        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1273    }
1274
1275    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1276    if (zoomLevel != 1) {
1277        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1278        paintInfo.context->scale(zoomLevel, zoomLevel);
1279        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1280    }
1281
1282    Color fillColor(205, 205, 205);
1283    Color borderGradientTopColor(109, 109, 109);
1284    Color borderGradientBottomColor(181, 181, 181);
1285    Color shadowColor(0, 0, 0, 118);
1286
1287    if (!isEnabled(o)) {
1288        Color tintColor(255, 255, 255, 128);
1289        fillColor = fillColor.blend(tintColor);
1290        borderGradientTopColor = borderGradientTopColor.blend(tintColor);
1291        borderGradientBottomColor = borderGradientBottomColor.blend(tintColor);
1292        shadowColor = shadowColor.blend(tintColor);
1293    }
1294
1295    Color tintColor;
1296    if (!isEnabled(o))
1297        tintColor = Color(255, 255, 255, 128);
1298
1299    bool isVerticalSlider = o->style()->appearance() == SliderVerticalPart;
1300
1301    int fillRadiusSize = (sliderTrackWidth - sliderTrackBorderWidth) / 2;
1302    IntSize fillRadius(fillRadiusSize, fillRadiusSize);
1303    IntRect fillBounds = enclosedIntRect(unzoomedRect);
1304    RoundedRect fillRect(fillBounds, fillRadius, fillRadius, fillRadius, fillRadius);
1305    paintInfo.context->fillRoundedRect(fillRect, fillColor);
1306
1307    IntSize shadowOffset(isVerticalSlider ? 1 : 0,
1308                         isVerticalSlider ? 0 : 1);
1309    int shadowBlur = 3;
1310    int shadowSpread = 0;
1311    paintInfo.context->save();
1312    paintInfo.context->drawInnerShadow(fillRect, shadowColor, shadowOffset, shadowBlur, shadowSpread);
1313    paintInfo.context->restore();
1314
1315    RefPtr<Gradient> borderGradient = Gradient::create(fillBounds.minXMinYCorner(),
1316        isVerticalSlider ? fillBounds.maxXMinYCorner() : fillBounds.minXMaxYCorner());
1317    borderGradient->addColorStop(0.0, borderGradientTopColor);
1318    borderGradient->addColorStop(1.0, borderGradientBottomColor);
1319    Path borderPath;
1320    FloatRect borderRect(unzoomedRect);
1321    borderRect.inflate(-sliderTrackBorderWidth / 2.0);
1322    float borderRadiusSize = (isVerticalSlider ? borderRect.width() : borderRect.height()) / 2;
1323    FloatSize borderRadius(borderRadiusSize, borderRadiusSize);
1324    borderPath.addRoundedRect(borderRect, borderRadius, borderRadius, borderRadius, borderRadius);
1325    paintInfo.context->setStrokeGradient(borderGradient);
1326    paintInfo.context->setStrokeThickness(sliderTrackBorderWidth);
1327    paintInfo.context->strokePath(borderPath);
1328    return false;
1329}
1330
1331const int sliderThumbWidth = 15;
1332const int sliderThumbHeight = 15;
1333const int sliderThumbBorderWidth = 1;
1334
1335bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1336{
1337    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1338    float zoomLevel = o->style()->effectiveZoom();
1339
1340    FloatRect unzoomedRect(r.x(), r.y(), sliderThumbWidth, sliderThumbHeight);
1341    if (zoomLevel != 1.0f) {
1342        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1343        paintInfo.context->scale(zoomLevel, zoomLevel);
1344        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1345    }
1346
1347    Color fillGradientTopColor(250, 250, 250);
1348    Color fillGradientUpperMiddleColor(244, 244, 244);
1349    Color fillGradientLowerMiddleColor(236, 236, 236);
1350    Color fillGradientBottomColor(238, 238, 238);
1351    Color borderGradientTopColor(151, 151, 151);
1352    Color borderGradientBottomColor(128, 128, 128);
1353    Color shadowColor(0, 0, 0, 36);
1354
1355    if (!isEnabled(o)) {
1356        Color tintColor(255, 255, 255, 128);
1357        fillGradientTopColor = fillGradientTopColor.blend(tintColor);
1358        fillGradientUpperMiddleColor = fillGradientUpperMiddleColor.blend(tintColor);
1359        fillGradientLowerMiddleColor = fillGradientLowerMiddleColor.blend(tintColor);
1360        fillGradientBottomColor = fillGradientBottomColor.blend(tintColor);
1361        borderGradientTopColor = borderGradientTopColor.blend(tintColor);
1362        borderGradientBottomColor = borderGradientBottomColor.blend(tintColor);
1363        shadowColor = shadowColor.blend(tintColor);
1364    } else if (isPressed(o)) {
1365        Color tintColor(0, 0, 0, 32);
1366        fillGradientTopColor = fillGradientTopColor.blend(tintColor);
1367        fillGradientUpperMiddleColor = fillGradientUpperMiddleColor.blend(tintColor);
1368        fillGradientLowerMiddleColor = fillGradientLowerMiddleColor.blend(tintColor);
1369        fillGradientBottomColor = fillGradientBottomColor.blend(tintColor);
1370        borderGradientTopColor = borderGradientTopColor.blend(tintColor);
1371        borderGradientBottomColor = borderGradientBottomColor.blend(tintColor);
1372        shadowColor = shadowColor.blend(tintColor);
1373    }
1374
1375    FloatRect borderBounds = unzoomedRect;
1376    borderBounds.inflate(sliderThumbBorderWidth / 2.0);
1377
1378    borderBounds.inflate(-sliderThumbBorderWidth);
1379    FloatSize shadowOffset(0, 1);
1380    paintInfo.context->setShadow(shadowOffset, sliderThumbShadowBlur, shadowColor);
1381    paintInfo.context->setFillColor(Color::black);
1382    paintInfo.context->fillEllipse(borderBounds);
1383    paintInfo.context->clearShadow();
1384
1385    IntRect fillBounds = enclosedIntRect(unzoomedRect);
1386    RefPtr<Gradient> fillGradient = Gradient::create(fillBounds.minXMinYCorner(), fillBounds.minXMaxYCorner());
1387    fillGradient->addColorStop(0.0, fillGradientTopColor);
1388    fillGradient->addColorStop(0.52, fillGradientUpperMiddleColor);
1389    fillGradient->addColorStop(0.52, fillGradientLowerMiddleColor);
1390    fillGradient->addColorStop(1.0, fillGradientBottomColor);
1391    paintInfo.context->setFillGradient(fillGradient);
1392    paintInfo.context->fillEllipse(borderBounds);
1393
1394    RefPtr<Gradient> borderGradient = Gradient::create(fillBounds.minXMinYCorner(), fillBounds.minXMaxYCorner());
1395    borderGradient->addColorStop(0.0, borderGradientTopColor);
1396    borderGradient->addColorStop(1.0, borderGradientBottomColor);
1397    paintInfo.context->setStrokeGradient(borderGradient);
1398    paintInfo.context->setStrokeThickness(sliderThumbBorderWidth);
1399    paintInfo.context->strokeEllipse(borderBounds);
1400
1401    if (isFocused(o)) {
1402        Path borderPath;
1403        borderPath.addEllipse(borderBounds);
1404        paintInfo.context->drawFocusRing(borderPath, 5, -2, focusRingColor());
1405    }
1406
1407    return false;
1408}
1409
1410bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1411{
1412    LocalCurrentGraphicsContext localContext(paintInfo.context, r);
1413
1414    NSSearchFieldCell* search = this->search();
1415    setSearchCellState(o, r);
1416    [search setControlSize:searchFieldControlSizeForFont(o->style())];
1417
1418    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1419
1420    float zoomLevel = o->style()->effectiveZoom();
1421
1422    IntRect unzoomedRect = r;
1423
1424    if (zoomLevel != 1.0f) {
1425        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1426        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1427        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1428        paintInfo.context->scale(zoomLevel, zoomLevel);
1429        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1430    }
1431
1432    // Set the search button to nil before drawing. Then reset it so we can
1433    // draw it later.
1434    [search setSearchButtonCell:nil];
1435
1436    [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1437
1438    [search setControlView:nil];
1439    [search resetSearchButtonCell];
1440
1441    return false;
1442}
1443
1444void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect&)
1445{
1446    NSSearchFieldCell* search = this->search();
1447
1448    // Update the various states we respond to.
1449    updateActiveState(search, o);
1450    updateEnabledState(search, o);
1451    updateFocusedState(search, o);
1452}
1453
1454const IntSize* RenderThemeChromiumMac::searchFieldSizes() const
1455{
1456    static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 15) };
1457    return sizes;
1458}
1459
1460static const int* searchFieldHorizontalPaddings()
1461{
1462    static const int sizes[3] = { 3, 2, 1 };
1463    return sizes;
1464}
1465
1466void RenderThemeChromiumMac::setSearchFieldSize(RenderStyle* style) const
1467{
1468    // If the width and height are both specified, then we have nothing to do.
1469    if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1470        return;
1471
1472    // Use the font size to determine the intrinsic width of the control.
1473    setSizeFromFont(style, searchFieldSizes());
1474}
1475
1476const int searchFieldBorderWidth = 2;
1477void RenderThemeChromiumMac::adjustSearchFieldStyle(RenderStyle* style, Element*) const
1478{
1479    // Override border.
1480    style->resetBorder();
1481    const short borderWidth = searchFieldBorderWidth * style->effectiveZoom();
1482    style->setBorderLeftWidth(borderWidth);
1483    style->setBorderLeftStyle(INSET);
1484    style->setBorderRightWidth(borderWidth);
1485    style->setBorderRightStyle(INSET);
1486    style->setBorderBottomWidth(borderWidth);
1487    style->setBorderBottomStyle(INSET);
1488    style->setBorderTopWidth(borderWidth);
1489    style->setBorderTopStyle(INSET);
1490
1491    // Override height.
1492    style->setHeight(Length(Auto));
1493    setSearchFieldSize(style);
1494
1495    NSControlSize controlSize = controlSizeForFont(style);
1496
1497    // Override padding size to match AppKit text positioning.
1498    const int verticalPadding = 1 * style->effectiveZoom();
1499    const int horizontalPadding = searchFieldHorizontalPaddings()[controlSize] * style->effectiveZoom();
1500    style->setPaddingLeft(Length(horizontalPadding, Fixed));
1501    style->setPaddingRight(Length(horizontalPadding, Fixed));
1502    style->setPaddingTop(Length(verticalPadding, Fixed));
1503    style->setPaddingBottom(Length(verticalPadding, Fixed));
1504
1505    setFontFromControlSize(style, controlSize);
1506
1507    style->setBoxShadow(nullptr);
1508}
1509
1510bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1511{
1512    if (!o->node())
1513        return false;
1514    Element* input = o->node()->shadowHost();
1515    if (!input)
1516        input = toElement(o->node());
1517
1518    if (!input->renderer()->isBox())
1519        return false;
1520
1521    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1522
1523    float zoomLevel = o->style()->effectiveZoom();
1524    FloatRect unzoomedRect(r);
1525    if (zoomLevel != 1.0f) {
1526        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1527        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1528        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1529        paintInfo.context->scale(zoomLevel, zoomLevel);
1530        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1531    }
1532
1533    Color fillColor(200, 200, 200);
1534
1535    if (isPressed(o)) {
1536        Color tintColor(0, 0, 0, 32);
1537        fillColor = fillColor.blend(tintColor);
1538    }
1539
1540    float centerX = unzoomedRect.x() + unzoomedRect.width() / 2;
1541    float centerY = unzoomedRect.y() + unzoomedRect.height() / 2;
1542    // The line width is 3px on a regular sized, high DPI NSCancelButtonCell
1543    // (which is 28px wide).
1544    float lineWidth = unzoomedRect.width() * 3 / 28;
1545    // The line length is 16px on a regular sized, high DPI NSCancelButtonCell.
1546    float lineLength = unzoomedRect.width() * 16 / 28;
1547
1548    Path xPath;
1549    FloatSize lineRectRadius(lineWidth / 2, lineWidth / 2);
1550    xPath.addRoundedRect(FloatRect(-lineLength / 2, -lineWidth / 2, lineLength, lineWidth),
1551        lineRectRadius, lineRectRadius, lineRectRadius, lineRectRadius);
1552    xPath.addRoundedRect(FloatRect(-lineWidth / 2, -lineLength / 2, lineWidth, lineLength),
1553        lineRectRadius, lineRectRadius, lineRectRadius, lineRectRadius);
1554
1555    paintInfo.context->translate(centerX, centerY);
1556    paintInfo.context->rotate(deg2rad(45.0));
1557    paintInfo.context->clipOut(xPath);
1558    paintInfo.context->rotate(deg2rad(-45.0));
1559    paintInfo.context->translate(-centerX, -centerY);
1560
1561    paintInfo.context->setFillColor(fillColor);
1562    paintInfo.context->fillEllipse(unzoomedRect);
1563
1564    return false;
1565}
1566
1567const IntSize* RenderThemeChromiumMac::cancelButtonSizes() const
1568{
1569    static const IntSize sizes[3] = { IntSize(14, 14), IntSize(11, 11), IntSize(9, 9) };
1570    return sizes;
1571}
1572
1573void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(RenderStyle* style, Element*) const
1574{
1575    IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1576    style->setWidth(Length(size.width(), Fixed));
1577    style->setHeight(Length(size.height(), Fixed));
1578    style->setBoxShadow(nullptr);
1579}
1580
1581const IntSize* RenderThemeChromiumMac::resultsButtonSizes() const
1582{
1583    static const IntSize sizes[3] = { IntSize(15, 14), IntSize(16, 13), IntSize(14, 11) };
1584    return sizes;
1585}
1586
1587void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(RenderStyle* style, Element*) const
1588{
1589    NSControlSize controlSize = controlSizeForSystemFont(style);
1590    IntSize searchFieldSize = searchFieldSizes()[controlSize];
1591    int width = searchFieldSize.height() / 2 - searchFieldBorderWidth - searchFieldHorizontalPaddings()[controlSize];
1592    style->setWidth(Length(width, Fixed));
1593    style->setHeight(Length(0, Fixed));
1594    style->setBoxShadow(nullptr);
1595}
1596
1597bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1598{
1599    return false;
1600}
1601
1602void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(RenderStyle* style, Element*) const
1603{
1604    IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1605    style->setWidth(Length(size.width(), Fixed));
1606    style->setHeight(Length(size.height(), Fixed));
1607    style->setBoxShadow(nullptr);
1608}
1609
1610bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
1611{
1612    if (!o->node())
1613        return false;
1614    Node* input = o->node()->shadowHost();
1615    if (!input)
1616        input = o->node();
1617    if (!input->renderer()->isBox())
1618        return false;
1619
1620    GraphicsContextStateSaver stateSaver(*paintInfo.context);
1621
1622    float zoomLevel = o->style()->effectiveZoom();
1623    FloatRect unzoomedRect(r);
1624    if (zoomLevel != 1) {
1625        unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1626        unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1627        paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1628        paintInfo.context->scale(zoomLevel, zoomLevel);
1629        paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1630    }
1631
1632    LocalCurrentGraphicsContext localContext(paintInfo.context, r);
1633
1634    NSSearchFieldCell* search = this->search();
1635    setSearchCellState(input->renderer(), r);
1636    [search setControlSize:searchFieldControlSizeForFont(o->style())];
1637    if ([search searchMenuTemplate] != nil)
1638        [search setSearchMenuTemplate:nil];
1639
1640    updateActiveState([search searchButtonCell], o);
1641
1642    [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1643    [[search searchButtonCell] setControlView:nil];
1644    return false;
1645}
1646
1647IntSize RenderThemeChromiumMac::sliderTickSize() const
1648{
1649    return IntSize(1, 3);
1650}
1651
1652int RenderThemeChromiumMac::sliderTickOffsetFromTrackCenter() const
1653{
1654    return -9;
1655}
1656
1657void RenderThemeChromiumMac::adjustSliderThumbSize(RenderStyle* style, Element*) const
1658{
1659    float zoomLevel = style->effectiveZoom();
1660    if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
1661        style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1662        style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1663    }
1664
1665    adjustMediaSliderThumbSize(style);
1666}
1667
1668NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const
1669{
1670    if (!m_popupButton) {
1671        m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
1672        [m_popupButton.get() setUsesItemFromMenu:NO];
1673        [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
1674    }
1675
1676    return m_popupButton.get();
1677}
1678
1679NSSearchFieldCell* RenderThemeChromiumMac::search() const
1680{
1681    if (!m_search) {
1682        m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
1683        [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
1684        [m_search.get() setBezeled:YES];
1685        [m_search.get() setEditable:YES];
1686        [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
1687        SEL sel = @selector(setCenteredLook:);
1688        if ([m_search.get() respondsToSelector:sel]) {
1689            BOOL boolValue = NO;
1690            NSMethodSignature* signature = [NSSearchFieldCell instanceMethodSignatureForSelector:sel];
1691            NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
1692            [invocation setTarget:m_search.get()];
1693            [invocation setSelector:sel];
1694            [invocation setArgument:&boolValue atIndex:2];
1695            [invocation invoke];
1696        }
1697    }
1698
1699    return m_search.get();
1700}
1701
1702NSTextFieldCell* RenderThemeChromiumMac::textField() const
1703{
1704    if (!m_textField) {
1705        m_textField.adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
1706        [m_textField.get() setBezeled:YES];
1707        [m_textField.get() setEditable:YES];
1708        [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
1709#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
1710        [m_textField.get() setDrawsBackground:YES];
1711        [m_textField.get() setBackgroundColor:[NSColor whiteColor]];
1712#else
1713        // Post-Lion, WebCore can be in charge of paintinng the background
1714        // thanks to the workaround in place for <rdar://problem/11385461>,
1715        // which is implemented above as _coreUIDrawOptionsWithFrame.
1716        [m_textField.get() setDrawsBackground:NO];
1717#endif
1718    }
1719
1720    return m_textField.get();
1721}
1722
1723String RenderThemeChromiumMac::fileListNameForWidth(Locale& locale, const FileList* fileList, const Font& font, int width) const
1724{
1725    if (width <= 0)
1726        return String();
1727
1728    String strToTruncate;
1729    if (fileList->isEmpty()) {
1730        strToTruncate = locale.queryString(WebLocalizedString::FileButtonNoFileSelectedLabel);
1731    } else if (fileList->length() == 1) {
1732        File* file = fileList->item(0);
1733        if (file->userVisibility() == File::IsUserVisible)
1734            strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
1735        else
1736            strToTruncate = file->name();
1737    } else {
1738        // FIXME: Localization of fileList->length().
1739        return StringTruncator::rightTruncate(locale.queryString(WebLocalizedString::MultipleFileUploadText, String::number(fileList->length())), width, font);
1740    }
1741
1742    return StringTruncator::centerTruncate(strToTruncate, width, font);
1743}
1744
1745NSView* FlippedView()
1746{
1747    static NSView* view = [[RTCMFlippedView alloc] init];
1748    return view;
1749}
1750
1751RenderTheme& RenderTheme::theme()
1752{
1753    DEFINE_STATIC_REF(RenderTheme, renderTheme, (RenderThemeChromiumMac::create()));
1754    return *renderTheme;
1755}
1756
1757PassRefPtr<RenderTheme> RenderThemeChromiumMac::create()
1758{
1759    return adoptRef(new RenderThemeChromiumMac);
1760}
1761
1762bool RenderThemeChromiumMac::usesTestModeFocusRingColor() const
1763{
1764    return LayoutTestSupport::isRunningLayoutTest();
1765}
1766
1767NSView* RenderThemeChromiumMac::documentViewFor(RenderObject*) const
1768{
1769    return FlippedView();
1770}
1771
1772// Updates the control tint (a.k.a. active state) of |cell| (from |o|).  In the
1773// Chromium port, the renderer runs as a background process and controls'
1774// NSCell(s) lack a parent NSView. Therefore controls don't have their tint
1775// color updated correctly when the application is activated/deactivated.
1776// FocusController's setActive() is called when the application is
1777// activated/deactivated, which causes a paint invalidation at which time this
1778// code is called.
1779// This function should be called before drawing any NSCell-derived controls,
1780// unless you're sure it isn't needed.
1781void RenderThemeChromiumMac::updateActiveState(NSCell* cell, const RenderObject* o)
1782{
1783    NSControlTint oldTint = [cell controlTint];
1784    NSControlTint tint = isActive(o) ? [NSColor currentControlTint] :
1785                                       static_cast<NSControlTint>(NSClearControlTint);
1786
1787    if (tint != oldTint)
1788        [cell setControlTint:tint];
1789}
1790
1791bool RenderThemeChromiumMac::shouldShowPlaceholderWhenFocused() const
1792{
1793    return true;
1794}
1795
1796void RenderThemeChromiumMac::adjustMediaSliderThumbSize(RenderStyle* style) const
1797{
1798    RenderMediaControls::adjustMediaSliderThumbSize(style);
1799}
1800
1801bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1802{
1803    return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
1804}
1805
1806bool RenderThemeChromiumMac::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1807{
1808    return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect);
1809}
1810
1811bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1812{
1813    return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
1814}
1815
1816bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1817{
1818    return RenderMediaControls::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
1819}
1820
1821String RenderThemeChromiumMac::extraFullScreenStyleSheet()
1822{
1823    // FIXME: Chromium may wish to style its default media controls differently in fullscreen.
1824    return String();
1825}
1826
1827String RenderThemeChromiumMac::extraDefaultStyleSheet()
1828{
1829    return RenderTheme::extraDefaultStyleSheet() +
1830        String(themeChromiumCss, sizeof(themeChromiumCss)) +
1831        String(themeInputMultipleFieldsCss, sizeof(themeInputMultipleFieldsCss)) +
1832        String(themeMacCss, sizeof(themeMacCss));
1833}
1834
1835bool RenderThemeChromiumMac::paintMediaVolumeSliderContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1836{
1837    return true;
1838}
1839
1840bool RenderThemeChromiumMac::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1841{
1842    return RenderMediaControls::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
1843}
1844
1845bool RenderThemeChromiumMac::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1846{
1847    return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
1848}
1849
1850bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1851{
1852    return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
1853}
1854
1855String RenderThemeChromiumMac::formatMediaControlsTime(float time) const
1856{
1857    return RenderMediaControls::formatMediaControlsTime(time);
1858}
1859
1860String RenderThemeChromiumMac::formatMediaControlsCurrentTime(float currentTime, float duration) const
1861{
1862    return RenderMediaControls::formatMediaControlsCurrentTime(currentTime, duration);
1863}
1864
1865bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1866{
1867    return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
1868}
1869
1870bool RenderThemeChromiumMac::paintMediaToggleClosedCaptionsButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1871{
1872    return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, object, paintInfo, rect);
1873}
1874
1875bool RenderThemeChromiumMac::shouldUseFallbackTheme(RenderStyle* style) const
1876{
1877    ControlPart part = style->appearance();
1878    if (part == CheckboxPart || part == RadioPart)
1879        return style->effectiveZoom() != 1;
1880    return false;
1881}
1882
1883} // namespace blink
1884