Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderThemeChromiumMac.mm
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.
69 const double progressAnimationFrameRate = 0.033;
70
71 // Mac OS X progress bar animation seems to have 256 frames.
72 const 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.
143 extern "C" {
144 void _NSDrawCarbonThemeBezel(NSRect frame, BOOL enabled, BOOL flipped);
145 // Request for public API: rdar://13787640
146 void _NSDrawCarbonThemeListBox(NSRect frame, BOOL enabled, BOOL flipped, BOOL always_yes);
147 }
148
149 namespace blink {
150
151 using namespace HTMLNames;
152
153 RenderThemeChromiumMac::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
162 RenderThemeChromiumMac::~RenderThemeChromiumMac()
163 {
164     [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
165 }
166
167 Color 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
173 Color 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
179 Color RenderThemeChromiumMac::platformActiveSelectionForegroundColor() const
180 {
181     return Color::black;
182 }
183
184 Color 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
190 Color RenderThemeChromiumMac::platformActiveListBoxSelectionForegroundColor() const
191 {
192     return Color::white;
193 }
194
195 Color RenderThemeChromiumMac::platformInactiveListBoxSelectionForegroundColor() const
196 {
197     return Color::black;
198 }
199
200 Color RenderThemeChromiumMac::platformFocusRingColor() const
201 {
202     static const RGBA32 oldAquaFocusRingColor = 0xFF7DADD9;
203     if (usesTestModeFocusRingColor())
204         return oldAquaFocusRingColor;
205
206     return systemColor(CSSValueWebkitFocusRingColor);
207 }
208
209 Color RenderThemeChromiumMac::platformInactiveListBoxSelectionBackgroundColor() const
210 {
211     return platformInactiveSelectionBackgroundColor();
212 }
213
214 static 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
241 void 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
302 static 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
342 static 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
370 void RenderThemeChromiumMac::platformColorsDidChange()
371 {
372     m_systemColorCache.clear();
373     RenderTheme::platformColorsDidChange();
374 }
375
376 Color 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
499 bool 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
520 const int sliderThumbShadowBlur = 1;
521
522 void 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
553 FloatRect 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
575 void 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
591 void 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
599 void 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
607 void 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
615 NSControlSize 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.
628 static 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
638 void 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
655 IntSize 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
664 IntSize 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
673 void 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
684 void 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
702 NSControlSize 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
715 bool 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
747 bool 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
808 bool 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
815 const 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
826 const 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
832 const 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
843 bool 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
885 IntSize 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
897 bool 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
912 bool 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
926 NSLevelIndicatorStyle 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
942 NSLevelIndicatorCell* 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
985 const 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
991 const 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
1002 int RenderThemeChromiumMac::minimumProgressBarHeight(RenderStyle* style) const
1003 {
1004     return sizeForSystemFont(style, progressBarSizes()).height();
1005 }
1006
1007 double RenderThemeChromiumMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
1008 {
1009     return progressAnimationFrameRate;
1010 }
1011
1012 double RenderThemeChromiumMac::animationDurationForProgressBar(RenderProgress*) const
1013 {
1014     return progressAnimationNumFrames * progressAnimationFrameRate;
1015 }
1016
1017 bool 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     ContextContainer cgContextContainer(imageBuffer->context());
1056     CGContextRef cgContext = cgContextContainer.context();
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
1071 const float baseFontSize = 11.0f;
1072 const float baseArrowHeight = 4.0f;
1073 const float baseArrowWidth = 5.0f;
1074 const float baseSpaceBetweenArrows = 2.0f;
1075 const int arrowPaddingLeft = 6;
1076 const int arrowPaddingRight = 6;
1077 const int paddingBeforeSeparator = 4;
1078 const int baseBorderRadius = 5;
1079 const int styledPopupPaddingLeft = 8;
1080 const int styledPopupPaddingTop = 1;
1081 const int styledPopupPaddingBottom = 2;
1082
1083 bool 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
1124 static const IntSize* menuListButtonSizes()
1125 {
1126     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1127     return sizes;
1128 }
1129
1130 void 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
1158 const 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.
1166 int 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
1178 int 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
1193 int 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
1202 int 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
1211 void 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
1224 void 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
1241 const 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
1247 int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const
1248 {
1249     return sizeForSystemFont(style, menuListSizes()).width();
1250 }
1251
1252 const int sliderTrackWidth = 5;
1253 const int sliderTrackBorderWidth = 1;
1254
1255 bool 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
1331 const int sliderThumbWidth = 15;
1332 const int sliderThumbHeight = 15;
1333 const int sliderThumbBorderWidth = 1;
1334
1335 bool 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
1410 bool 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
1444 void 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
1454 const 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
1460 static const int* searchFieldHorizontalPaddings()
1461 {
1462     static const int sizes[3] = { 3, 2, 1 };
1463     return sizes;
1464 }
1465
1466 void 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
1476 const int searchFieldBorderWidth = 2;
1477 void 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
1510 bool 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
1567 const 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
1573 void 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
1581 const 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
1587 void 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
1597 bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
1598 {
1599     return false;
1600 }
1601
1602 void 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
1610 bool 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
1647 IntSize RenderThemeChromiumMac::sliderTickSize() const
1648 {
1649     return IntSize(1, 3);
1650 }
1651
1652 int RenderThemeChromiumMac::sliderTickOffsetFromTrackCenter() const
1653 {
1654     return -9;
1655 }
1656
1657 void 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
1668 NSPopUpButtonCell* 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
1679 NSSearchFieldCell* 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
1702 NSTextFieldCell* 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
1723 String 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
1745 NSView* FlippedView()
1746 {
1747     static NSView* view = [[RTCMFlippedView alloc] init];
1748     return view;
1749 }
1750
1751 RenderTheme& RenderTheme::theme()
1752 {
1753     DEFINE_STATIC_REF(RenderTheme, renderTheme, (RenderThemeChromiumMac::create()));
1754     return *renderTheme;
1755 }
1756
1757 PassRefPtr<RenderTheme> RenderThemeChromiumMac::create()
1758 {
1759     return adoptRef(new RenderThemeChromiumMac);
1760 }
1761
1762 bool RenderThemeChromiumMac::usesTestModeFocusRingColor() const
1763 {
1764     return LayoutTestSupport::isRunningLayoutTest();
1765 }
1766
1767 NSView* 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.
1781 void 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
1791 bool RenderThemeChromiumMac::shouldShowPlaceholderWhenFocused() const
1792 {
1793     return true;
1794 }
1795
1796 void RenderThemeChromiumMac::adjustMediaSliderThumbSize(RenderStyle* style) const
1797 {
1798     RenderMediaControls::adjustMediaSliderThumbSize(style);
1799 }
1800
1801 bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1802 {
1803     return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
1804 }
1805
1806 bool RenderThemeChromiumMac::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1807 {
1808     return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect);
1809 }
1810
1811 bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1812 {
1813     return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
1814 }
1815
1816 bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1817 {
1818     return RenderMediaControls::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
1819 }
1820
1821 String RenderThemeChromiumMac::extraFullScreenStyleSheet()
1822 {
1823     // FIXME: Chromium may wish to style its default media controls differently in fullscreen.
1824     return String();
1825 }
1826
1827 String RenderThemeChromiumMac::extraDefaultStyleSheet()
1828 {
1829     return RenderTheme::extraDefaultStyleSheet() +
1830         String(themeChromiumCss, sizeof(themeChromiumCss)) +
1831         String(themeInputMultipleFieldsCss, sizeof(themeInputMultipleFieldsCss)) +
1832         String(themeMacCss, sizeof(themeMacCss));
1833 }
1834
1835 bool RenderThemeChromiumMac::paintMediaVolumeSliderContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1836 {
1837     return true;
1838 }
1839
1840 bool RenderThemeChromiumMac::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1841 {
1842     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
1843 }
1844
1845 bool RenderThemeChromiumMac::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1846 {
1847     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
1848 }
1849
1850 bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1851 {
1852     return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
1853 }
1854
1855 String RenderThemeChromiumMac::formatMediaControlsTime(float time) const
1856 {
1857     return RenderMediaControls::formatMediaControlsTime(time);
1858 }
1859
1860 String RenderThemeChromiumMac::formatMediaControlsCurrentTime(float currentTime, float duration) const
1861 {
1862     return RenderMediaControls::formatMediaControlsCurrentTime(currentTime, duration);
1863 }
1864
1865 bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1866 {
1867     return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
1868 }
1869
1870 bool RenderThemeChromiumMac::paintMediaToggleClosedCaptionsButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
1871 {
1872     return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, object, paintInfo, rect);
1873 }
1874
1875 bool 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