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