Ensure system appearance is default for web content
[WebKit-https.git] / Source / WebCore / rendering / RenderThemeMac.mm
1 /*
2  * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #import "config.h"
21 #import "RenderThemeMac.h"
22
23 #if PLATFORM(MAC)
24
25 #import "BitmapImage.h"
26 #import "CSSValueKeywords.h"
27 #import "CSSValueList.h"
28 #import "ColorMac.h"
29 #import "Document.h"
30 #import "Element.h"
31 #import "FileList.h"
32 #import "FloatRoundedRect.h"
33 #import "FocusController.h"
34 #import "Frame.h"
35 #import "FrameSelection.h"
36 #import "FrameView.h"
37 #import "GeometryUtilities.h"
38 #import "GraphicsContextCG.h"
39 #import "HTMLAttachmentElement.h"
40 #import "HTMLInputElement.h"
41 #import "HTMLMediaElement.h"
42 #import "HTMLNames.h"
43 #import "HTMLPlugInImageElement.h"
44 #import "Icon.h"
45 #import "Image.h"
46 #import "ImageBuffer.h"
47 #import "LocalCurrentGraphicsContext.h"
48 #import "LocalDefaultSystemAppearance.h"
49 #import "LocalizedStrings.h"
50 #import "MediaControlElements.h"
51 #import "Page.h"
52 #import "PaintInfo.h"
53 #import "PathUtilities.h"
54 #import "RenderAttachment.h"
55 #import "RenderLayer.h"
56 #import "RenderMedia.h"
57 #import "RenderMediaControlElements.h"
58 #import "RenderProgress.h"
59 #import "RenderSlider.h"
60 #import "RenderSnapshottedPlugIn.h"
61 #import "RenderView.h"
62 #import "RuntimeEnabledFeatures.h"
63 #import "SharedBuffer.h"
64 #import "StringTruncator.h"
65 #import "StyleResolver.h"
66 #import "ThemeMac.h"
67 #import "TimeRanges.h"
68 #import "UTIUtilities.h"
69 #import "UserAgentScripts.h"
70 #import "UserAgentStyleSheets.h"
71 #import <Carbon/Carbon.h>
72 #import <Cocoa/Cocoa.h>
73 #import <math.h>
74 #import <pal/spi/cg/CoreGraphicsSPI.h>
75 #import <pal/spi/cocoa/NSColorSPI.h>
76 #import <pal/spi/mac/NSCellSPI.h>
77 #import <pal/spi/mac/NSSharingServicePickerSPI.h>
78 #import <wtf/MathExtras.h>
79 #import <wtf/ObjcRuntimeExtras.h>
80 #import <wtf/RetainPtr.h>
81 #import <wtf/StdLibExtras.h>
82 #import <wtf/text/StringBuilder.h>
83
84 #if ENABLE(METER_ELEMENT)
85 #import "RenderMeter.h"
86 #import "HTMLMeterElement.h"
87 #endif
88
89 #if defined(__LP64__) && __LP64__
90 #define HAVE_APPKIT_SERVICE_CONTROLS_SUPPORT 1
91 #else
92 #define HAVE_APPKIT_SERVICE_CONTROLS_SUPPORT 0
93 #endif
94
95 #if ENABLE(SERVICE_CONTROLS) && HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
96
97 // FIXME: This should go into an SPI.h file in the spi directory.
98 #if USE(APPLE_INTERNAL_SDK)
99 #import <AppKit/AppKitDefines_Private.h>
100 #import <AppKit/NSServicesRolloverButtonCell.h>
101 #else
102 #define APPKIT_PRIVATE_CLASS
103 @interface NSServicesRolloverButtonCell : NSButtonCell
104 @end
105 #endif
106
107 // FIXME: This should go into an SPI.h file in the spi directory.
108 @interface NSServicesRolloverButtonCell ()
109 + (NSServicesRolloverButtonCell *)serviceRolloverButtonCellForStyle:(NSSharingServicePickerStyle)style;
110 - (NSRect)rectForBounds:(NSRect)bounds preferredEdge:(NSRectEdge)preferredEdge;
111 @end
112
113 #endif // ENABLE(SERVICE_CONTROLS)
114
115 // FIXME: This should go into an SPI.h file in the spi directory.
116 @interface NSTextFieldCell ()
117 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
118 @end
119
120 // FIXME: This should go into an SPI.h file in the spi directory.
121 @interface NSSearchFieldCell ()
122 @property (getter=isCenteredLook) BOOL centeredLook;
123 @end
124
125 static const Seconds progressAnimationFrameRate = 33_ms; // 30 fps
126 static const double progressAnimationNumFrames = 256;
127
128 @interface WebCoreRenderThemeNotificationObserver : NSObject
129 @end
130
131 @implementation WebCoreRenderThemeNotificationObserver
132
133 - (id)init
134 {
135     self = [super init];
136     if (!self)
137         return nil;
138     [[NSNotificationCenter defaultCenter] addObserver:self
139         selector:@selector(systemColorsDidChange:) name:NSSystemColorsDidChangeNotification object:nil];
140     return self;
141 }
142
143 - (void)systemColorsDidChange:(NSNotification *)unusedNotification
144 {
145     ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
146     WebCore::RenderTheme::singleton().platformColorsDidChange();
147 }
148
149 @end
150
151 @interface WebCoreTextFieldCell : NSTextFieldCell
152 @end
153
154 @implementation WebCoreTextFieldCell
155
156 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
157 {
158     // FIXME: This is a workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
159     CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
160     CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
161     CFAutorelease(coreUIDrawOptions);
162     return coreUIDrawOptions;
163 }
164
165 @end
166
167 @interface WebCoreRenderThemeBundle : NSObject
168 @end
169
170 @implementation WebCoreRenderThemeBundle
171 @end
172
173 namespace WebCore {
174
175 using namespace HTMLNames;
176
177 enum {
178     topMargin,
179     rightMargin,
180     bottomMargin,
181     leftMargin
182 };
183
184 enum {
185     topPadding,
186     rightPadding,
187     bottomPadding,
188     leftPadding
189 };
190
191 RenderTheme& RenderTheme::singleton()
192 {
193     static NeverDestroyed<RenderThemeMac> theme;
194     return theme;
195 }
196
197 RenderThemeMac::RenderThemeMac()
198     : m_notificationObserver(adoptNS([[WebCoreRenderThemeNotificationObserver alloc] init]))
199 {
200 }
201
202 NSView *RenderThemeMac::documentViewFor(const RenderObject& o) const
203 {
204     ControlStates states(extractControlStatesForRenderer(o));
205     return ThemeMac::ensuredView(&o.view().frameView(), states);
206 }
207
208 #if ENABLE(VIDEO)
209
210 String RenderThemeMac::mediaControlsStyleSheet()
211 {
212 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
213     if (m_legacyMediaControlsStyleSheet.isEmpty())
214         m_legacyMediaControlsStyleSheet = [NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"css"] encoding:NSUTF8StringEncoding error:nil];
215     return m_legacyMediaControlsStyleSheet;
216 #else
217     return emptyString();
218 #endif
219 }
220
221 String RenderThemeMac::modernMediaControlsStyleSheet()
222 {
223 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
224     if (RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled()) {
225         if (m_mediaControlsStyleSheet.isEmpty())
226             m_mediaControlsStyleSheet = [NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"modern-media-controls" ofType:@"css" inDirectory:@"modern-media-controls"] encoding:NSUTF8StringEncoding error:nil];
227         return m_mediaControlsStyleSheet;
228     }
229     return emptyString();
230 #else
231     return emptyString();
232 #endif
233 }
234
235 void RenderThemeMac::purgeCaches()
236 {
237     m_legacyMediaControlsScript.clearImplIfNotShared();
238     m_mediaControlsScript.clearImplIfNotShared();
239     m_legacyMediaControlsStyleSheet.clearImplIfNotShared();
240     m_mediaControlsStyleSheet.clearImplIfNotShared();
241 }
242
243 String RenderThemeMac::mediaControlsScript()
244 {
245 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
246     if (RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled()) {
247         if (m_mediaControlsScript.isEmpty()) {
248             NSBundle *bundle = [NSBundle bundleForClass:[WebCoreRenderThemeBundle class]];
249             NSString *localizedStrings = [NSString stringWithContentsOfFile:[bundle pathForResource:@"modern-media-controls-localized-strings" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
250             NSString *script = [NSString stringWithContentsOfFile:[bundle pathForResource:@"modern-media-controls" ofType:@"js" inDirectory:@"modern-media-controls"] encoding:NSUTF8StringEncoding error:nil];
251             m_mediaControlsScript = makeString(String { localizedStrings }, String { script });
252         }
253         return m_mediaControlsScript;
254     }
255
256     if (m_legacyMediaControlsScript.isEmpty()) {
257         NSBundle *bundle = [NSBundle bundleForClass:[WebCoreRenderThemeBundle class]];
258         NSString *localizedStrings = [NSString stringWithContentsOfFile:[bundle pathForResource:@"mediaControlsLocalizedStrings" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
259         NSString *script = [NSString stringWithContentsOfFile:[bundle pathForResource:@"mediaControlsApple" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
260         m_legacyMediaControlsScript = makeString(String { localizedStrings }, String { script });
261     }
262     return m_legacyMediaControlsScript;
263 #else
264     return emptyString();
265 #endif
266 }
267
268 String RenderThemeMac::mediaControlsBase64StringForIconNameAndType(const String& iconName, const String& iconType)
269 {
270 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
271     if (!RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled())
272         return emptyString();
273
274     NSString *directory = @"modern-media-controls/images";
275     NSBundle *bundle = [NSBundle bundleForClass:[WebCoreRenderThemeBundle class]];
276     return [[NSData dataWithContentsOfFile:[bundle pathForResource:iconName ofType:iconType inDirectory:directory]] base64EncodedStringWithOptions:0];
277 #else
278     return emptyString();
279 #endif
280 }
281
282 #endif // ENABLE(VIDEO)
283
284 #if ENABLE(SERVICE_CONTROLS)
285
286 String RenderThemeMac::imageControlsStyleSheet() const
287 {
288     return String(imageControlsMacUserAgentStyleSheet, sizeof(imageControlsMacUserAgentStyleSheet));
289 }
290
291 #endif
292
293 Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
294 {
295 #pragma clang diagnostic push
296 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
297     NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
298 #pragma clang diagnostic pop
299     return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
300 }
301
302 Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
303 {
304 #pragma clang diagnostic push
305 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
306     NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
307 #pragma clang diagnostic pop
308     return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
309 }
310
311 Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const
312 {
313 #pragma clang diagnostic push
314 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
315     NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
316 #pragma clang diagnostic pop
317     return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
318 }
319
320 Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const
321 {
322     return Color::white;
323 }
324
325 Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const
326 {
327     return Color::black;
328 }
329
330 Color RenderThemeMac::platformFocusRingColor() const
331 {
332     if (usesTestModeFocusRingColor())
333         return oldAquaFocusRingColor();
334
335     return systemColor(CSSValueWebkitFocusRingColor);
336 }
337
338 Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const
339 {
340     return platformInactiveSelectionBackgroundColor();
341 }
342
343 static FontSelectionValue toFontWeight(NSInteger appKitFontWeight)
344 {
345     ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
346     if (appKitFontWeight > 14)
347         appKitFontWeight = 14;
348     else if (appKitFontWeight < 1)
349         appKitFontWeight = 1;
350
351     static const FontSelectionValue fontWeights[] = {
352         FontSelectionValue(100),
353         FontSelectionValue(100),
354         FontSelectionValue(200),
355         FontSelectionValue(300),
356         FontSelectionValue(400),
357         FontSelectionValue(500),
358         FontSelectionValue(600),
359         FontSelectionValue(600),
360         FontSelectionValue(700),
361         FontSelectionValue(800),
362         FontSelectionValue(800),
363         FontSelectionValue(900),
364         FontSelectionValue(900),
365         FontSelectionValue(900)
366     };
367     return fontWeights[appKitFontWeight - 1];
368 }
369
370 void RenderThemeMac::updateCachedSystemFontDescription(CSSValueID cssValueId, FontCascadeDescription& fontDescription) const
371 {
372     NSFont* font;
373     // System-font-ness can't be encapsulated by simply a font name. Instead, we must use a token
374     // which FontCache will look for.
375     // Make sure we keep this list of possible tokens in sync with FontCascade::primaryFontIsSystemFont()
376     AtomicString fontName;
377     switch (cssValueId) {
378         case CSSValueSmallCaption:
379             font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
380             break;
381         case CSSValueMenu:
382             font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
383             fontName = AtomicString("-apple-menu", AtomicString::ConstructFromLiteral);
384             break;
385         case CSSValueStatusBar:
386             font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
387             fontName = AtomicString("-apple-status-bar", AtomicString::ConstructFromLiteral);
388             break;
389         case CSSValueWebkitMiniControl:
390             font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeMini]];
391             break;
392         case CSSValueWebkitSmallControl:
393             font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]];
394             break;
395         case CSSValueWebkitControl:
396             font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeRegular]];
397             break;
398         default:
399             font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
400     }
401
402     if (!font)
403         return;
404
405     if (fontName.isNull())
406         fontName = AtomicString("system-ui", AtomicString::ConstructFromLiteral);
407
408     NSFontManager *fontManager = [NSFontManager sharedFontManager];
409     fontDescription.setIsAbsoluteSize(true);
410     fontDescription.setOneFamily(fontName);
411     fontDescription.setSpecifiedSize([font pointSize]);
412     fontDescription.setWeight(toFontWeight([fontManager weightOfFont:font]));
413     fontDescription.setIsItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
414 }
415
416 static RGBA32 convertNSColorToColor(NSColor *color)
417 {
418 #pragma clang diagnostic push
419 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
420     NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
421 #pragma clang diagnostic pop
422     if (colorInColorSpace) {
423         static const double scaleFactor = nextafter(256.0, 0.0);
424         return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
425             static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
426             static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
427     }
428
429     // This conversion above can fail if the NSColor in question is an NSPatternColor
430     // (as many system colors are). These colors are actually a repeating pattern
431     // not just a solid color. To work around this we simply draw a 1x1 image of
432     // the color and use that pixel's color. It might be better to use an average of
433     // the colors in the pattern instead.
434     NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
435                                                                              pixelsWide:1
436                                                                              pixelsHigh:1
437                                                                           bitsPerSample:8
438                                                                         samplesPerPixel:4
439                                                                                hasAlpha:YES
440                                                                                isPlanar:NO
441                                                                          colorSpaceName:NSDeviceRGBColorSpace
442                                                                             bytesPerRow:4
443                                                                            bitsPerPixel:32];
444
445     [NSGraphicsContext saveGraphicsState];
446     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
447     NSEraseRect(NSMakeRect(0, 0, 1, 1));
448     [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
449     [NSGraphicsContext restoreGraphicsState];
450
451     NSUInteger pixel[4];
452     [offscreenRep getPixel:pixel atX:0 y:0];
453
454     [offscreenRep release];
455
456     return makeRGB(pixel[0], pixel[1], pixel[2]);
457 }
458
459 static RGBA32 menuBackgroundColor()
460 {
461     NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
462                                                                              pixelsWide:1
463                                                                              pixelsHigh:1
464                                                                           bitsPerSample:8
465                                                                         samplesPerPixel:4
466                                                                                hasAlpha:YES
467                                                                                isPlanar:NO
468                                                                          colorSpaceName:NSDeviceRGBColorSpace
469                                                                             bytesPerRow:4
470                                                                            bitsPerPixel:32];
471
472 #pragma clang diagnostic push
473 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
474     CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
475 #pragma clang diagnostic pop
476     CGRect rect = CGRectMake(0, 0, 1, 1);
477     HIThemeMenuDrawInfo drawInfo;
478     drawInfo.version =  0;
479     drawInfo.menuType = kThemeMenuTypePopUp;
480     HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
481
482     NSUInteger pixel[4];
483     [offscreenRep getPixel:pixel atX:0 y:0];
484
485     [offscreenRep release];
486
487     return makeRGB(pixel[0], pixel[1], pixel[2]);
488 }
489
490 void RenderThemeMac::platformColorsDidChange()
491 {
492     m_systemColorCache.clear();
493     RenderTheme::platformColorsDidChange();
494 }
495
496 Color RenderThemeMac::systemColor(CSSValueID cssValueID) const
497 {
498     LocalDefaultSystemAppearance localAppearence;
499     return m_systemColorCache.ensure(cssValueID, [this, cssValueID] () -> Color {
500         auto selectCocoaColor = [cssValueID] () -> SEL {
501             switch (cssValueID) {
502             case CSSValueActiveborder:
503                 return @selector(keyboardFocusIndicatorColor);
504             case CSSValueActivecaption:
505                 return @selector(windowFrameTextColor);
506             case CSSValueAppworkspace:
507                 return @selector(headerColor);
508             case CSSValueButtonhighlight:
509                 return @selector(controlHighlightColor);
510             case CSSValueButtonshadow:
511                 return @selector(controlShadowColor);
512             case CSSValueButtontext:
513                 return @selector(controlTextColor);
514             case CSSValueCaptiontext:
515                 return @selector(textColor);
516             case CSSValueGraytext:
517                 return @selector(disabledControlTextColor);
518             case CSSValueHighlight:
519                 return @selector(selectedTextBackgroundColor);
520             case CSSValueHighlighttext:
521                 return @selector(selectedTextColor);
522             case CSSValueInactiveborder:
523                 return @selector(controlBackgroundColor);
524             case CSSValueInactivecaption:
525                 return @selector(controlBackgroundColor);
526             case CSSValueInactivecaptiontext:
527                 return @selector(textColor);
528             case CSSValueInfotext:
529                 return @selector(textColor);
530             case CSSValueMenutext:
531                 return @selector(selectedMenuItemTextColor);
532             case CSSValueScrollbar:
533                 return @selector(scrollBarColor);
534             case CSSValueText:
535                 return @selector(textColor);
536             case CSSValueThreeddarkshadow:
537                 return @selector(controlDarkShadowColor);
538             case CSSValueThreedshadow:
539                 return @selector(shadowColor);
540             case CSSValueThreedhighlight:
541                 return @selector(highlightColor);
542             case CSSValueThreedlightshadow:
543                 return @selector(controlLightHighlightColor);
544             case CSSValueWebkitFocusRingColor:
545                 return @selector(keyboardFocusIndicatorColor);
546             case CSSValueWindow:
547                 return @selector(windowBackgroundColor);
548             case CSSValueWindowframe:
549                 return @selector(windowFrameColor);
550             case CSSValueWindowtext:
551                 return @selector(windowFrameTextColor);
552             case CSSValueAppleWirelessPlaybackTargetActive:
553                 return @selector(systemBlueColor);
554             case CSSValueAppleSystemBlue:
555                 return @selector(systemBlueColor);
556             case CSSValueAppleSystemBrown:
557                 return @selector(systemBrownColor);
558             case CSSValueAppleSystemGray:
559                 return @selector(systemGrayColor);
560             case CSSValueAppleSystemGreen:
561                 return @selector(systemGreenColor);
562             case CSSValueAppleSystemOrange:
563                 return @selector(systemOrangeColor);
564             case CSSValueAppleSystemPink:
565                 return @selector(systemPinkColor);
566             case CSSValueAppleSystemPurple:
567                 return @selector(systemPurpleColor);
568             case CSSValueAppleSystemRed:
569                 return @selector(systemRedColor);
570             case CSSValueAppleSystemYellow:
571                 return @selector(systemYellowColor);
572             default:
573                 return nullptr;
574             }
575         };
576         if (auto selector = selectCocoaColor()) {
577             if (auto color = wtfObjcMsgSend<NSColor *>([NSColor class], selector))
578                 return convertNSColorToColor(color);
579         }
580         switch (cssValueID) {
581         case CSSValueActivebuttontext:
582             // No corresponding NSColor for this so we use a hard coded value.
583             return Color::white;
584         case CSSValueButtonface:
585         case CSSValueThreedface:
586             // We selected this value instead of [NSColor controlColor] to avoid website incompatibilities.
587             // We may want to consider changing to [NSColor controlColor] some day.
588             return 0xFFC0C0C0;
589         case CSSValueInfobackground:
590             // No corresponding NSColor for this so we use a hard coded value.
591             return 0xFFFBFCC5;
592         case CSSValueMenu:
593             return menuBackgroundColor();
594         case CSSValueBackground:
595             // Use platform-independent value returned by base class.
596             FALLTHROUGH;
597         default:
598             return RenderTheme::systemColor(cssValueID);
599         }
600     }).iterator->value;
601 }
602
603 bool RenderThemeMac::usesTestModeFocusRingColor() const
604 {
605     return WebCore::usesTestModeFocusRingColor();
606 }
607
608 bool RenderThemeMac::isControlStyled(const RenderStyle& style, const BorderData& border,
609                                      const FillLayer& background, const Color& backgroundColor) const
610 {
611     if (style.appearance() == TextFieldPart || style.appearance() == TextAreaPart || style.appearance() == ListboxPart)
612         return style.border() != border;
613
614     // FIXME: This is horrible, but there is not much else that can be done.  Menu lists cannot draw properly when
615     // scaled.  They can't really draw properly when transformed either.  We can't detect the transform case at style
616     // adjustment time so that will just have to stay broken.  We can however detect that we're zooming.  If zooming
617     // is in effect we treat it like the control is styled.
618     if (style.appearance() == MenulistPart && style.effectiveZoom() != 1.0f)
619         return true;
620
621     return RenderTheme::isControlStyled(style, border, background, backgroundColor);
622 }
623
624 static FloatRect inflateRect(const FloatRect& rect, const IntSize& size, const int* margins, float zoomLevel)
625 {
626     // Only do the inflation if the available width/height are too small. Otherwise try to
627     // fit the glow/check space into the available box's width/height.
628     int widthDelta = rect.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
629     int heightDelta = rect.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
630     FloatRect result(rect);
631     if (widthDelta < 0) {
632         result.setX(result.x() - margins[leftMargin] * zoomLevel);
633         result.setWidth(result.width() - widthDelta);
634     }
635     if (heightDelta < 0) {
636         result.setY(result.y() - margins[topMargin] * zoomLevel);
637         result.setHeight(result.height() - heightDelta);
638     }
639     return result;
640 }
641
642 void RenderThemeMac::adjustRepaintRect(const RenderObject& renderer, FloatRect& rect)
643 {
644     ControlPart part = renderer.style().appearance();
645
646 #if USE(NEW_THEME)
647     switch (part) {
648         case CheckboxPart:
649         case RadioPart:
650         case PushButtonPart:
651         case SquareButtonPart:
652         case DefaultButtonPart:
653         case ButtonPart:
654         case InnerSpinButtonPart:
655             return RenderTheme::adjustRepaintRect(renderer, rect);
656         default:
657             break;
658     }
659 #endif
660
661     float zoomLevel = renderer.style().effectiveZoom();
662
663     if (part == MenulistPart) {
664         setPopupButtonCellState(renderer, IntSize(rect.size()));
665         IntSize size = popupButtonSizes()[[popupButton() controlSize]];
666         size.setHeight(size.height() * zoomLevel);
667         size.setWidth(rect.width());
668         rect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
669     }
670 }
671
672 static FloatPoint convertToPaintingPosition(const RenderBox& inputRenderer, const RenderBox& customButtonRenderer, const FloatPoint& customButtonLocalPosition,
673     const IntPoint& paintOffset)
674 {
675     IntPoint offsetFromInputRenderer = roundedIntPoint(customButtonRenderer.localToContainerPoint(customButtonRenderer.contentBoxRect().location(), &inputRenderer));
676     FloatPoint paintingPosition = customButtonLocalPosition;
677     paintingPosition.moveBy(-offsetFromInputRenderer);
678     paintingPosition.moveBy(paintOffset);
679     return paintingPosition;
680 }
681
682 void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject& o)
683 {
684     bool oldIndeterminate = [cell state] == NSControlStateValueMixed;
685     bool indeterminate = isIndeterminate(o);
686     bool checked = isChecked(o);
687
688     if (oldIndeterminate != indeterminate) {
689         [cell setState:indeterminate ? NSControlStateValueMixed : (checked ? NSControlStateValueOn : NSControlStateValueOff)];
690         return;
691     }
692
693     bool oldChecked = [cell state] == NSControlStateValueOn;
694     if (checked != oldChecked)
695         [cell setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
696 }
697
698 void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject& o)
699 {
700     bool oldEnabled = [cell isEnabled];
701     bool enabled = isEnabled(o);
702     if (enabled != oldEnabled)
703         [cell setEnabled:enabled];
704 }
705
706 void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject& o)
707 {
708     bool oldFocused = [cell showsFirstResponder];
709     bool focused = isFocused(o) && o.style().outlineStyleIsAuto();
710     if (focused != oldFocused)
711         [cell setShowsFirstResponder:focused];
712 }
713
714 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject& o)
715 {
716     bool oldPressed = [cell isHighlighted];
717     bool pressed = is<Element>(o.node()) && downcast<Element>(*o.node()).active();
718     if (pressed != oldPressed)
719         [cell setHighlighted:pressed];
720 }
721
722 bool RenderThemeMac::controlSupportsTints(const RenderObject& o) const
723 {
724     // An alternate way to implement this would be to get the appropriate cell object
725     // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
726     // that would be that we would match AppKit behavior more closely, but a disadvantage
727     // would be that we would rely on an AppKit SPI method.
728
729     if (!isEnabled(o))
730         return false;
731
732     // Checkboxes only have tint when checked.
733     if (o.style().appearance() == CheckboxPart)
734         return isChecked(o);
735
736     // For now assume other controls have tint if enabled.
737     return true;
738 }
739
740 NSControlSize RenderThemeMac::controlSizeForFont(const RenderStyle& style) const
741 {
742     int fontSize = style.computedFontPixelSize();
743     if (fontSize >= 16)
744         return NSControlSizeRegular;
745     if (fontSize >= 11)
746         return NSControlSizeSmall;
747     return NSControlSizeMini;
748 }
749
750 NSControlSize RenderThemeMac::controlSizeForCell(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel) const
751 {
752     if (minSize.width() >= static_cast<int>(sizes[NSControlSizeRegular].width() * zoomLevel)
753         && minSize.height() >= static_cast<int>(sizes[NSControlSizeRegular].height() * zoomLevel))
754         return NSControlSizeRegular;
755
756     if (minSize.width() >= static_cast<int>(sizes[NSControlSizeSmall].width() * zoomLevel)
757         && minSize.height() >= static_cast<int>(sizes[NSControlSizeSmall].height() * zoomLevel))
758         return NSControlSizeSmall;
759
760     return NSControlSizeMini;
761 }
762
763 void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
764 {
765     NSControlSize size = controlSizeForCell(cell, sizes, minSize, zoomLevel);
766     if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
767         [cell setControlSize:size];
768 }
769
770 IntSize RenderThemeMac::sizeForFont(const RenderStyle& style, const IntSize* sizes) const
771 {
772     if (style.effectiveZoom() != 1.0f) {
773         IntSize result = sizes[controlSizeForFont(style)];
774         return IntSize(result.width() * style.effectiveZoom(), result.height() * style.effectiveZoom());
775     }
776     return sizes[controlSizeForFont(style)];
777 }
778
779 IntSize RenderThemeMac::sizeForSystemFont(const RenderStyle& style, const IntSize* sizes) const
780 {
781     if (style.effectiveZoom() != 1.0f) {
782         IntSize result = sizes[controlSizeForSystemFont(style)];
783         return IntSize(result.width() * style.effectiveZoom(), result.height() * style.effectiveZoom());
784     }
785     return sizes[controlSizeForSystemFont(style)];
786 }
787
788 void RenderThemeMac::setSizeFromFont(RenderStyle& style, const IntSize* sizes) const
789 {
790     // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
791     IntSize size = sizeForFont(style, sizes);
792     if (style.width().isIntrinsicOrAuto() && size.width() > 0)
793         style.setWidth(Length(size.width(), Fixed));
794     if (style.height().isAuto() && size.height() > 0)
795         style.setHeight(Length(size.height(), Fixed));
796 }
797
798 void RenderThemeMac::setFontFromControlSize(StyleResolver&, RenderStyle& style, NSControlSize controlSize) const
799 {
800     FontCascadeDescription fontDescription;
801     fontDescription.setIsAbsoluteSize(true);
802
803     NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
804     fontDescription.setOneFamily(AtomicString("-apple-system", AtomicString::ConstructFromLiteral));
805     fontDescription.setComputedSize([font pointSize] * style.effectiveZoom());
806     fontDescription.setSpecifiedSize([font pointSize] * style.effectiveZoom());
807
808     // Reset line height
809     style.setLineHeight(RenderStyle::initialLineHeight());
810
811     if (style.setFontDescription(fontDescription))
812         style.fontCascade().update(0);
813 }
814
815 NSControlSize RenderThemeMac::controlSizeForSystemFont(const RenderStyle& style) const
816 {
817     int fontSize = style.computedFontPixelSize();
818     if (fontSize >= [NSFont systemFontSizeForControlSize:NSControlSizeRegular])
819         return NSControlSizeRegular;
820     if (fontSize >= [NSFont systemFontSizeForControlSize:NSControlSizeSmall])
821         return NSControlSizeSmall;
822     return NSControlSizeMini;
823 }
824
825 bool RenderThemeMac::paintTextField(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
826 {
827     LocalCurrentGraphicsContext localContext(paintInfo.context());
828
829     // <rdar://problem/22896977> We adjust the paint rect here to account for how AppKit draws the text
830     // field cell slightly smaller than the rect we pass to drawWithFrame.
831     FloatRect adjustedPaintRect(r);
832     AffineTransform transform = paintInfo.context().getCTM();
833     if (transform.xScale() > 1 || transform.yScale() > 1) {
834         adjustedPaintRect.inflateX(1 / transform.xScale());
835         adjustedPaintRect.inflateY(1 / transform.yScale());
836     }
837     NSTextFieldCell *textField = this->textField();
838
839     GraphicsContextStateSaver stateSaver(paintInfo.context());
840
841     [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
842     [textField drawWithFrame:NSRect(adjustedPaintRect) inView:documentViewFor(o)];
843
844     [textField setControlView:nil];
845
846     return false;
847 }
848
849 void RenderThemeMac::adjustTextFieldStyle(StyleResolver&, RenderStyle&, const Element*) const
850 {
851 }
852
853 bool RenderThemeMac::paintTextArea(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
854 {
855     LocalCurrentGraphicsContext localContext(paintInfo.context());
856     _NSDrawCarbonThemeListBox(r, isEnabled(o) && !isReadOnlyControl(o), YES, YES);
857     return false;
858 }
859
860 void RenderThemeMac::adjustTextAreaStyle(StyleResolver&, RenderStyle&, const Element*) const
861 {
862 }
863
864 const int* RenderThemeMac::popupButtonMargins() const
865 {
866     static const int margins[3][4] =
867     {
868         { 0, 3, 1, 3 },
869         { 0, 3, 2, 3 },
870         { 0, 1, 0, 1 }
871     };
872     return margins[[popupButton() controlSize]];
873 }
874
875 const IntSize* RenderThemeMac::popupButtonSizes() const
876 {
877     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
878     return sizes;
879 }
880
881 const int* RenderThemeMac::popupButtonPadding(NSControlSize size, bool isRTL) const
882 {
883     static const int paddingLTR[3][4] =
884     {
885         { 2, 26, 3, 8 },
886         { 2, 23, 3, 8 },
887         { 2, 22, 3, 10 }
888     };
889     static const int paddingRTL[3][4] =
890     {
891         { 2, 8, 3, 26 },
892         { 2, 8, 3, 23 },
893         { 2, 8, 3, 22 }
894     };
895     return isRTL ? paddingRTL[size] : paddingLTR[size];
896 }
897
898 bool RenderThemeMac::paintMenuList(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
899 {
900     LocalCurrentGraphicsContext localContext(paintInfo.context());
901     setPopupButtonCellState(renderer, IntSize(rect.size()));
902
903     NSPopUpButtonCell* popupButton = this->popupButton();
904
905     float zoomLevel = renderer.style().effectiveZoom();
906     IntSize size = popupButtonSizes()[[popupButton controlSize]];
907     size.setHeight(size.height() * zoomLevel);
908     size.setWidth(rect.width());
909
910     // Now inflate it to account for the shadow.
911     FloatRect inflatedRect = rect;
912     if (rect.width() >= minimumMenuListSize(renderer.style()))
913         inflatedRect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
914
915     GraphicsContextStateSaver stateSaver(paintInfo.context());
916
917     if (zoomLevel != 1.0f) {
918         inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
919         inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
920         paintInfo.context().translate(inflatedRect.location());
921         paintInfo.context().scale(zoomLevel);
922         paintInfo.context().translate(-inflatedRect.location());
923     }
924
925     paintCellAndSetFocusedElementNeedsRepaintIfNecessary(popupButton, renderer, paintInfo, inflatedRect);
926     [popupButton setControlView:nil];
927
928     return false;
929 }
930
931 #if ENABLE(METER_ELEMENT)
932
933 IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter& renderMeter, const IntRect& bounds) const
934 {
935     if (NoControlPart == renderMeter.style().appearance())
936         return bounds.size();
937
938     NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
939     // Makes enough room for cell's intrinsic size.
940     NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
941     return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
942                    bounds.height() < cellSize.height ? cellSize.height : bounds.height());
943 }
944
945 bool RenderThemeMac::paintMeter(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
946 {
947     if (!is<RenderMeter>(renderObject))
948         return true;
949
950     LocalCurrentGraphicsContext localContext(paintInfo.context());
951
952     NSLevelIndicatorCell* cell = levelIndicatorFor(downcast<RenderMeter>(renderObject));
953     GraphicsContextStateSaver stateSaver(paintInfo.context());
954
955     [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
956     [cell setControlView:nil];
957     return false;
958 }
959
960 bool RenderThemeMac::supportsMeter(ControlPart part) const
961 {
962     switch (part) {
963     case RelevancyLevelIndicatorPart:
964     case DiscreteCapacityLevelIndicatorPart:
965     case RatingLevelIndicatorPart:
966     case MeterPart:
967     case ContinuousCapacityLevelIndicatorPart:
968         return true;
969     default:
970         return false;
971     }
972 }
973
974 NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
975 {
976     switch (part) {
977     case RelevancyLevelIndicatorPart:
978         return NSLevelIndicatorStyleRelevancy;
979     case DiscreteCapacityLevelIndicatorPart:
980         return NSLevelIndicatorStyleDiscreteCapacity;
981     case RatingLevelIndicatorPart:
982         return NSLevelIndicatorStyleRating;
983     case MeterPart:
984     case ContinuousCapacityLevelIndicatorPart:
985     default:
986         return NSLevelIndicatorStyleContinuousCapacity;
987     }
988
989 }
990
991 NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter& renderMeter) const
992 {
993     const RenderStyle& style = renderMeter.style();
994     ASSERT(style.appearance() != NoControlPart);
995
996     if (!m_levelIndicator)
997         m_levelIndicator = adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSLevelIndicatorStyleContinuousCapacity]);
998     NSLevelIndicatorCell* cell = m_levelIndicator.get();
999
1000     HTMLMeterElement* element = renderMeter.meterElement();
1001     double value = element->value();
1002
1003     // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
1004     // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
1005     switch (element->gaugeRegion()) {
1006     case HTMLMeterElement::GaugeRegionOptimum:
1007         // Make meter the green
1008         [cell setWarningValue:value + 1];
1009         [cell setCriticalValue:value + 2];
1010         break;
1011     case HTMLMeterElement::GaugeRegionSuboptimal:
1012         // Make the meter yellow
1013         [cell setWarningValue:value - 1];
1014         [cell setCriticalValue:value + 1];
1015         break;
1016     case HTMLMeterElement::GaugeRegionEvenLessGood:
1017         // Make the meter red
1018         [cell setWarningValue:value - 2];
1019         [cell setCriticalValue:value - 1];
1020         break;
1021     }
1022
1023     [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style.appearance())];
1024     [cell setUserInterfaceLayoutDirection:style.isLeftToRightDirection() ? NSUserInterfaceLayoutDirectionLeftToRight : NSUserInterfaceLayoutDirectionRightToLeft];
1025     [cell setMinValue:element->min()];
1026     [cell setMaxValue:element->max()];
1027     [cell setObjectValue:@(value)];
1028
1029     return cell;
1030 }
1031
1032 #endif
1033
1034 const IntSize* RenderThemeMac::progressBarSizes() const
1035 {
1036     static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
1037     return sizes;
1038 }
1039
1040 const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const
1041 {
1042     static const int margins[3][4] =
1043     {
1044         { 0, 0, 1, 0 },
1045         { 0, 0, 1, 0 },
1046         { 0, 0, 1, 0 },
1047     };
1048     return margins[controlSize];
1049 }
1050
1051 IntRect RenderThemeMac::progressBarRectForBounds(const RenderObject& renderObject, const IntRect& bounds) const
1052 {
1053     // Workaround until <rdar://problem/15855086> is fixed.
1054     int maxDimension = static_cast<int>(std::numeric_limits<ushort>::max());
1055     IntRect progressBarBounds(bounds.x(), bounds.y(), std::min(bounds.width(), maxDimension), std::min(bounds.height(), maxDimension));
1056     if (NoControlPart == renderObject.style().appearance())
1057         return progressBarBounds;
1058
1059     float zoomLevel = renderObject.style().effectiveZoom();
1060     NSControlSize controlSize = controlSizeForFont(renderObject.style());
1061     IntSize size = progressBarSizes()[controlSize];
1062     size.setHeight(size.height() * zoomLevel);
1063     size.setWidth(progressBarBounds.width());
1064
1065     // Now inflate it to account for the shadow.
1066     IntRect inflatedRect = progressBarBounds;
1067     if (progressBarBounds.height() <= minimumProgressBarHeight(renderObject.style()))
1068         inflatedRect = IntRect(inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel));
1069
1070     return inflatedRect;
1071 }
1072
1073 int RenderThemeMac::minimumProgressBarHeight(const RenderStyle& style) const
1074 {
1075     return sizeForSystemFont(style, progressBarSizes()).height();
1076 }
1077
1078 Seconds RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress&) const
1079 {
1080     return progressAnimationFrameRate;
1081 }
1082
1083 Seconds RenderThemeMac::animationDurationForProgressBar(RenderProgress&) const
1084 {
1085     return progressAnimationFrameRate * progressAnimationNumFrames;
1086 }
1087
1088 void RenderThemeMac::adjustProgressBarStyle(StyleResolver&, RenderStyle&, const Element*) const
1089 {
1090 }
1091
1092 bool RenderThemeMac::paintProgressBar(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1093 {
1094     if (!is<RenderProgress>(renderObject))
1095         return true;
1096
1097     IntRect inflatedRect = progressBarRectForBounds(renderObject, rect);
1098     NSControlSize controlSize = controlSizeForFont(renderObject.style());
1099
1100     const auto& renderProgress = downcast<RenderProgress>(renderObject);
1101     HIThemeTrackDrawInfo trackInfo;
1102     trackInfo.version = 0;
1103     if (controlSize == NSControlSizeRegular)
1104         trackInfo.kind = renderProgress.position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
1105     else
1106         trackInfo.kind = renderProgress.position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
1107
1108     float deviceScaleFactor = renderObject.document().deviceScaleFactor();
1109     trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
1110     trackInfo.min = 0;
1111     trackInfo.max = std::numeric_limits<SInt32>::max();
1112     trackInfo.value = lround(renderProgress.position() * nextafter(trackInfo.max, 0));
1113     trackInfo.trackInfo.progress.phase = lround(renderProgress.animationProgress() * nextafter(progressAnimationNumFrames, 0) * deviceScaleFactor);
1114     trackInfo.attributes = kThemeTrackHorizontal;
1115     trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
1116     trackInfo.reserved = 0;
1117     trackInfo.filler1 = 0;
1118
1119     std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::createCompatibleBuffer(inflatedRect.size(), deviceScaleFactor, ColorSpaceSRGB, paintInfo.context());
1120     if (!imageBuffer)
1121         return true;
1122
1123     ContextContainer cgContextContainer(imageBuffer->context());
1124     CGContextRef cgContext = cgContextContainer.context();
1125     HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
1126
1127     GraphicsContextStateSaver stateSaver(paintInfo.context());
1128
1129     if (!renderProgress.style().isLeftToRightDirection()) {
1130         paintInfo.context().translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
1131         paintInfo.context().scale(FloatSize(-1, 1));
1132     }
1133
1134     paintInfo.context().drawConsumingImageBuffer(WTFMove(imageBuffer), inflatedRect.location());
1135     return false;
1136 }
1137
1138 const float baseFontSize = 11.0f;
1139 const float baseArrowHeight = 4.0f;
1140 const float baseArrowWidth = 5.0f;
1141 const float baseSpaceBetweenArrows = 2.0f;
1142 const int arrowPaddingBefore = 6;
1143 const int arrowPaddingAfter = 6;
1144 const int paddingBeforeSeparator = 4;
1145 const int baseBorderRadius = 5;
1146 const int styledPopupPaddingLeft = 8;
1147 const int styledPopupPaddingTop = 1;
1148 const int styledPopupPaddingBottom = 2;
1149
1150 static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1151 {
1152     static const float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
1153     static const float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
1154     float a = inData[0];
1155     int i = 0;
1156     for (i = 0; i < 4; i++)
1157         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1158 }
1159
1160 static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1161 {
1162     static const float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
1163     static const float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
1164     float a = inData[0];
1165     int i = 0;
1166     for (i = 0; i < 4; i++)
1167         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1168 }
1169
1170 static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1171 {
1172     static const float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1173     static const float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1174     float a = inData[0];
1175     int i = 0;
1176     for (i = 0; i < 4; i++)
1177         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1178 }
1179
1180 static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1181 {
1182     static const float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1183     static const float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1184     float a = inData[0];
1185     int i = 0;
1186     for (i = 0; i < 4; i++)
1187         outData[i] = (1.0f - a) * dark[i] + a * light[i];
1188 }
1189
1190 void RenderThemeMac::paintMenuListButtonGradients(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1191 {
1192     if (r.isEmpty())
1193         return;
1194
1195     ContextContainer cgContextContainer(paintInfo.context());
1196     CGContextRef context = cgContextContainer.context();
1197
1198     GraphicsContextStateSaver stateSaver(paintInfo.context());
1199
1200     FloatRoundedRect border = FloatRoundedRect(o.style().getRoundedBorderFor(r));
1201     int radius = border.radii().topLeft().width();
1202
1203     CGColorSpaceRef cspace = sRGBColorSpaceRef();
1204
1205     FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1206     struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1207     RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1208     RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
1209
1210     FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1211     struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1212     RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1213     RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(),  bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
1214
1215     struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1216     RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1217     RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
1218
1219     RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(),  r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1220
1221     RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(),  r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
1222
1223     {
1224         GraphicsContextStateSaver stateSaver(paintInfo.context());
1225         CGContextClipToRect(context, r);
1226         paintInfo.context().clipRoundedRect(border);
1227         context = cgContextContainer.context();
1228         CGContextDrawShading(context, mainShading.get());
1229     }
1230
1231     {
1232         GraphicsContextStateSaver stateSaver(paintInfo.context());
1233         CGContextClipToRect(context, topGradient);
1234         paintInfo.context().clipRoundedRect(FloatRoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
1235         context = cgContextContainer.context();
1236         CGContextDrawShading(context, topShading.get());
1237     }
1238
1239     if (!bottomGradient.isEmpty()) {
1240         GraphicsContextStateSaver stateSaver(paintInfo.context());
1241         CGContextClipToRect(context, bottomGradient);
1242         paintInfo.context().clipRoundedRect(FloatRoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
1243         context = cgContextContainer.context();
1244         CGContextDrawShading(context, bottomShading.get());
1245     }
1246
1247     {
1248         GraphicsContextStateSaver stateSaver(paintInfo.context());
1249         CGContextClipToRect(context, r);
1250         paintInfo.context().clipRoundedRect(border);
1251         context = cgContextContainer.context();
1252         CGContextDrawShading(context, leftShading.get());
1253         CGContextDrawShading(context, rightShading.get());
1254     }
1255 }
1256
1257 bool RenderThemeMac::paintMenuListButtonDecorations(const RenderBox& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
1258 {
1259     bool isRTL = renderer.style().direction() == RTL;
1260     IntRect bounds = IntRect(rect.x() + renderer.style().borderLeftWidth(),
1261         rect.y() + renderer.style().borderTopWidth(),
1262         rect.width() - renderer.style().borderLeftWidth() - renderer.style().borderRightWidth(),
1263         rect.height() - renderer.style().borderTopWidth() - renderer.style().borderBottomWidth());
1264     // Draw the gradients to give the styled popup menu a button appearance
1265     paintMenuListButtonGradients(renderer, paintInfo, bounds);
1266
1267     // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds
1268     float fontScale = std::min(renderer.style().computedFontPixelSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1269     float centerY = bounds.y() + bounds.height() / 2.0f;
1270     float arrowHeight = baseArrowHeight * fontScale;
1271     float arrowWidth = baseArrowWidth * fontScale;
1272     float leftEdge;
1273     if (isRTL)
1274         leftEdge = bounds.x() + arrowPaddingAfter * renderer.style().effectiveZoom();
1275     else
1276         leftEdge = bounds.maxX() - arrowPaddingAfter * renderer.style().effectiveZoom() - arrowWidth;
1277     float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1278
1279     if (bounds.width() < arrowWidth + arrowPaddingBefore * renderer.style().effectiveZoom())
1280         return false;
1281
1282     GraphicsContextStateSaver stateSaver(paintInfo.context());
1283
1284     paintInfo.context().setFillColor(renderer.style().visitedDependentColor(CSSPropertyColor));
1285     paintInfo.context().setStrokeStyle(NoStroke);
1286
1287     // Draw the top arrow
1288     Vector<FloatPoint> arrow1 = {
1289         { leftEdge, centerY - spaceBetweenArrows / 2.0f },
1290         { leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f },
1291         { leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight }
1292     };
1293     paintInfo.context().fillPath(Path::polygonPathFromPoints(arrow1));
1294
1295     // Draw the bottom arrow
1296     Vector<FloatPoint> arrow2 = {
1297         { leftEdge, centerY + spaceBetweenArrows / 2.0f },
1298         { leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f },
1299         { leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight }
1300     };
1301     paintInfo.context().fillPath(Path::polygonPathFromPoints(arrow2));
1302
1303     Color leftSeparatorColor(0, 0, 0, 40);
1304     Color rightSeparatorColor(255, 255, 255, 40);
1305
1306     // FIXME: Should the separator thickness and space be scaled up by fontScale?
1307     int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1308     int leftEdgeOfSeparator;
1309     if (isRTL)
1310         leftEdgeOfSeparator = static_cast<int>(roundf(leftEdge + arrowWidth + arrowPaddingBefore * renderer.style().effectiveZoom()));
1311     else
1312         leftEdgeOfSeparator = static_cast<int>(roundf(leftEdge - arrowPaddingBefore * renderer.style().effectiveZoom()));
1313
1314     // Draw the separator to the left of the arrows
1315     paintInfo.context().setStrokeThickness(1); // Deliberately ignores zoom since it looks nicer if it stays thin.
1316     paintInfo.context().setStrokeStyle(SolidStroke);
1317     paintInfo.context().setStrokeColor(leftSeparatorColor);
1318     paintInfo.context().drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1319         IntPoint(leftEdgeOfSeparator, bounds.maxY()));
1320
1321     paintInfo.context().setStrokeColor(rightSeparatorColor);
1322     paintInfo.context().drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1323         IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
1324     return false;
1325 }
1326
1327 static const IntSize* menuListButtonSizes()
1328 {
1329     static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1330     return sizes;
1331 }
1332
1333 void RenderThemeMac::adjustMenuListStyle(StyleResolver& styleResolver, RenderStyle& style, const Element* e) const
1334 {
1335     NSControlSize controlSize = controlSizeForFont(style);
1336
1337     style.resetBorder();
1338     style.resetPadding();
1339
1340     // Height is locked to auto.
1341     style.setHeight(Length(Auto));
1342
1343     // White-space is locked to pre
1344     style.setWhiteSpace(PRE);
1345
1346     // Set the foreground color to black or gray when we have the aqua look.
1347     // Cast to RGB32 is to work around a compiler bug.
1348     style.setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1349
1350     // Set the button's vertical size.
1351     setSizeFromFont(style, menuListButtonSizes());
1352
1353     // Our font is locked to the appropriate system font size for the control.  To clarify, we first use the CSS-specified font to figure out
1354     // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1355     // system font for the control size instead.
1356     setFontFromControlSize(styleResolver, style, controlSize);
1357
1358     style.setBoxShadow(nullptr);
1359 }
1360
1361 LengthBox RenderThemeMac::popupInternalPaddingBox(const RenderStyle& style) const
1362 {
1363     if (style.appearance() == MenulistPart) {
1364         const int* padding = popupButtonPadding(controlSizeForFont(style), style.direction() == RTL);
1365         return { static_cast<int>(padding[topPadding] * style.effectiveZoom()),
1366             static_cast<int>(padding[rightPadding] * style.effectiveZoom()),
1367             static_cast<int>(padding[bottomPadding] * style.effectiveZoom()),
1368             static_cast<int>(padding[leftPadding] * style.effectiveZoom()) };
1369     }
1370
1371     if (style.appearance() == MenulistButtonPart) {
1372         float arrowWidth = baseArrowWidth * (style.computedFontPixelSize() / baseFontSize);
1373         float rightPadding = ceilf(arrowWidth + (arrowPaddingBefore + arrowPaddingAfter + paddingBeforeSeparator) * style.effectiveZoom());
1374         float leftPadding = styledPopupPaddingLeft * style.effectiveZoom();
1375         if (style.direction() == RTL)
1376             std::swap(rightPadding, leftPadding);
1377         return { static_cast<int>(styledPopupPaddingTop * style.effectiveZoom()),
1378             static_cast<int>(rightPadding),
1379             static_cast<int>(styledPopupPaddingBottom * style.effectiveZoom()),
1380             static_cast<int>(leftPadding) };
1381     }
1382
1383     return { 0, 0, 0, 0 };
1384 }
1385
1386 PopupMenuStyle::PopupMenuSize RenderThemeMac::popupMenuSize(const RenderStyle& style, IntRect& rect) const
1387 {
1388     NSPopUpButtonCell* popupButton = this->popupButton();
1389     NSControlSize size = controlSizeForCell(popupButton, popupButtonSizes(), rect.size(), style.effectiveZoom());
1390     switch (size) {
1391     case NSControlSizeRegular:
1392         return PopupMenuStyle::PopupMenuSizeNormal;
1393     case NSControlSizeSmall:
1394         return PopupMenuStyle::PopupMenuSizeSmall;
1395     case NSControlSizeMini:
1396         return PopupMenuStyle::PopupMenuSizeMini;
1397     default:
1398         return PopupMenuStyle::PopupMenuSizeNormal;
1399     }
1400 }
1401
1402 void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
1403 {
1404     float fontScale = style.computedFontPixelSize() / baseFontSize;
1405
1406     style.resetPadding();
1407     style.setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1408
1409     const int minHeight = 15;
1410     style.setMinHeight(Length(minHeight, Fixed));
1411
1412     style.setLineHeight(RenderStyle::initialLineHeight());
1413 }
1414
1415 void RenderThemeMac::setPopupButtonCellState(const RenderObject& o, const IntSize& buttonSize)
1416 {
1417     NSPopUpButtonCell* popupButton = this->popupButton();
1418
1419     // Set the control size based off the rectangle we're painting into.
1420     setControlSize(popupButton, popupButtonSizes(), buttonSize, o.style().effectiveZoom());
1421
1422     popupButton.userInterfaceLayoutDirection = o.style().direction() == LTR ? NSUserInterfaceLayoutDirectionLeftToRight : NSUserInterfaceLayoutDirectionRightToLeft;
1423
1424     // Update the various states we respond to.
1425     updateCheckedState(popupButton, o);
1426     updateEnabledState(popupButton, o);
1427     updatePressedState(popupButton, o);
1428 }
1429
1430 void RenderThemeMac::paintCellAndSetFocusedElementNeedsRepaintIfNecessary(NSCell* cell, const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
1431 {
1432     bool shouldDrawFocusRing = isFocused(renderer) && renderer.style().outlineStyleIsAuto();
1433     bool shouldUseImageBuffer = renderer.style().effectiveZoom() != 1 || renderer.page().pageScaleFactor() != 1;
1434     bool shouldDrawCell = true;
1435     if (ThemeMac::drawCellOrFocusRingWithViewIntoContext(cell, paintInfo.context(), rect, documentViewFor(renderer), shouldDrawCell, shouldDrawFocusRing, shouldUseImageBuffer, renderer.page().deviceScaleFactor()))
1436         renderer.page().focusController().setFocusedElementNeedsRepaint();
1437 }
1438
1439 const IntSize* RenderThemeMac::menuListSizes() const
1440 {
1441     static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1442     return sizes;
1443 }
1444
1445 int RenderThemeMac::minimumMenuListSize(const RenderStyle& style) const
1446 {
1447     return sizeForSystemFont(style, menuListSizes()).width();
1448 }
1449
1450 const int trackWidth = 5;
1451 const int trackRadius = 2;
1452
1453 void RenderThemeMac::adjustSliderTrackStyle(StyleResolver&, RenderStyle& style, const Element*) const
1454 {
1455     style.setBoxShadow(nullptr);
1456 }
1457
1458 bool RenderThemeMac::paintSliderTrack(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1459 {
1460     IntRect bounds = r;
1461     float zoomLevel = o.style().effectiveZoom();
1462     float zoomedTrackWidth = trackWidth * zoomLevel;
1463
1464     if (o.style().appearance() ==  SliderHorizontalPart || o.style().appearance() ==  MediaSliderPart) {
1465         bounds.setHeight(zoomedTrackWidth);
1466         bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1467     } else if (o.style().appearance() == SliderVerticalPart) {
1468         bounds.setWidth(zoomedTrackWidth);
1469         bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1470     }
1471
1472     LocalCurrentGraphicsContext localContext(paintInfo.context());
1473     CGContextRef context = localContext.cgContext();
1474     CGColorSpaceRef cspace = sRGBColorSpaceRef();
1475
1476 #if ENABLE(DATALIST_ELEMENT)
1477     paintSliderTicks(o, paintInfo, r);
1478 #endif
1479
1480     GraphicsContextStateSaver stateSaver(paintInfo.context());
1481     CGContextClipToRect(context, bounds);
1482
1483     struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1484     RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1485     RetainPtr<CGShadingRef> mainShading;
1486     if (o.style().appearance() == SliderVerticalPart)
1487         mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(),  bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
1488     else
1489         mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(),  bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
1490
1491     IntSize radius(trackRadius, trackRadius);
1492     paintInfo.context().clipRoundedRect(FloatRoundedRect(bounds, radius, radius, radius, radius));
1493     context = localContext.cgContext();
1494     CGContextDrawShading(context, mainShading.get());
1495
1496     return false;
1497 }
1498
1499 void RenderThemeMac::adjustSliderThumbStyle(StyleResolver& styleResolver, RenderStyle& style, const Element* element) const
1500 {
1501     RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
1502     style.setBoxShadow(nullptr);
1503 }
1504
1505 const float verticalSliderHeightPadding = 0.1f;
1506
1507 bool RenderThemeMac::paintSliderThumb(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1508 {
1509     NSSliderCell* sliderThumbCell = o.style().appearance() == SliderThumbVerticalPart
1510         ? sliderThumbVertical()
1511         : sliderThumbHorizontal();
1512
1513     LocalCurrentGraphicsContext localContext(paintInfo.context());
1514
1515     // Update the various states we respond to.
1516     updateEnabledState(sliderThumbCell, o);
1517     auto focusDelegate = is<Element>(o.node()) ? downcast<Element>(*o.node()).focusDelegate() : nullptr;
1518     if (focusDelegate)
1519         updateFocusedState(sliderThumbCell, *focusDelegate->renderer());
1520
1521     // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1522     bool oldPressed;
1523     if (o.style().appearance() == SliderThumbVerticalPart)
1524         oldPressed = m_isSliderThumbVerticalPressed;
1525     else
1526         oldPressed = m_isSliderThumbHorizontalPressed;
1527
1528     bool pressed = isPressed(o);
1529
1530     if (o.style().appearance() == SliderThumbVerticalPart)
1531         m_isSliderThumbVerticalPressed = pressed;
1532     else
1533         m_isSliderThumbHorizontalPressed = pressed;
1534
1535     NSView *view = documentViewFor(o);
1536
1537     if (pressed != oldPressed) {
1538         if (pressed)
1539             [sliderThumbCell startTrackingAt:NSPoint() inView:view];
1540         else
1541             [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:view mouseIsUp:YES];
1542     }
1543
1544     FloatRect bounds = r;
1545     // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1546     if (o.style().appearance() == SliderThumbVerticalPart)
1547         bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o.style().effectiveZoom());
1548
1549     GraphicsContextStateSaver stateSaver(paintInfo.context());
1550     float zoomLevel = o.style().effectiveZoom();
1551
1552     FloatRect unzoomedRect = bounds;
1553     if (zoomLevel != 1.0f) {
1554         unzoomedRect.setSize(unzoomedRect.size() / zoomLevel);
1555         paintInfo.context().translate(unzoomedRect.location());
1556         paintInfo.context().scale(zoomLevel);
1557         paintInfo.context().translate(-unzoomedRect.location());
1558     }
1559
1560     bool shouldDrawCell = true;
1561     bool shouldDrawFocusRing = false;
1562     float deviceScaleFactor = o.page().deviceScaleFactor();
1563     bool shouldUseImageBuffer = deviceScaleFactor != 1 || zoomLevel != 1;
1564     ThemeMac::drawCellOrFocusRingWithViewIntoContext(sliderThumbCell, paintInfo.context(), unzoomedRect, view, shouldDrawCell, shouldDrawFocusRing, shouldUseImageBuffer, deviceScaleFactor);
1565     [sliderThumbCell setControlView:nil];
1566
1567     return false;
1568 }
1569
1570 bool RenderThemeMac::paintSearchField(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1571 {
1572     LocalCurrentGraphicsContext localContext(paintInfo.context());
1573     NSSearchFieldCell* search = this->search();
1574
1575     setSearchCellState(o, r);
1576
1577     GraphicsContextStateSaver stateSaver(paintInfo.context());
1578
1579     float zoomLevel = o.style().effectiveZoom();
1580
1581     FloatRect unzoomedRect = r;
1582     if (zoomLevel != 1.0f) {
1583         unzoomedRect.setSize(unzoomedRect.size() / zoomLevel);
1584         paintInfo.context().translate(unzoomedRect.location());
1585         paintInfo.context().scale(zoomLevel);
1586         paintInfo.context().translate(-unzoomedRect.location());
1587     }
1588
1589     // Set the search button to nil before drawing.  Then reset it so we can draw it later.
1590     [search setSearchButtonCell:nil];
1591
1592     paintCellAndSetFocusedElementNeedsRepaintIfNecessary(search, o, paintInfo, unzoomedRect);
1593     [search setControlView:nil];
1594     [search resetSearchButtonCell];
1595
1596     return false;
1597 }
1598
1599 void RenderThemeMac::setSearchCellState(const RenderObject& o, const IntRect&)
1600 {
1601     NSSearchFieldCell* search = this->search();
1602
1603     [search setPlaceholderString:@""];
1604     [search setControlSize:controlSizeForFont(o.style())];
1605
1606     // Update the various states we respond to.
1607     updateEnabledState(search, o);
1608     updateFocusedState(search, o);
1609 }
1610
1611 const IntSize* RenderThemeMac::searchFieldSizes() const
1612 {
1613     static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1614     return sizes;
1615 }
1616
1617 void RenderThemeMac::setSearchFieldSize(RenderStyle& style) const
1618 {
1619     // If the width and height are both specified, then we have nothing to do.
1620     if (!style.width().isIntrinsicOrAuto() && !style.height().isAuto())
1621         return;
1622
1623     // Use the font size to determine the intrinsic width of the control.
1624     setSizeFromFont(style, searchFieldSizes());
1625 }
1626
1627 void RenderThemeMac::adjustSearchFieldStyle(StyleResolver& styleResolver, RenderStyle& style, const Element*) const
1628 {
1629     // Override border.
1630     style.resetBorder();
1631     const short borderWidth = 2 * style.effectiveZoom();
1632     style.setBorderLeftWidth(borderWidth);
1633     style.setBorderLeftStyle(INSET);
1634     style.setBorderRightWidth(borderWidth);
1635     style.setBorderRightStyle(INSET);
1636     style.setBorderBottomWidth(borderWidth);
1637     style.setBorderBottomStyle(INSET);
1638     style.setBorderTopWidth(borderWidth);
1639     style.setBorderTopStyle(INSET);
1640
1641     // Override height.
1642     style.setHeight(Length(Auto));
1643     setSearchFieldSize(style);
1644
1645     // Override padding size to match AppKit text positioning.
1646     const int padding = 1 * style.effectiveZoom();
1647     style.setPaddingLeft(Length(padding, Fixed));
1648     style.setPaddingRight(Length(padding, Fixed));
1649     style.setPaddingTop(Length(padding, Fixed));
1650     style.setPaddingBottom(Length(padding, Fixed));
1651
1652     NSControlSize controlSize = controlSizeForFont(style);
1653     setFontFromControlSize(styleResolver, style, controlSize);
1654
1655     style.setBoxShadow(nullptr);
1656 }
1657
1658 bool RenderThemeMac::paintSearchFieldCancelButton(const RenderBox& box, const PaintInfo& paintInfo, const IntRect& r)
1659 {
1660     auto adjustedCancelButtonRect = [this, &box] (const FloatRect& localBoundsForCancelButton) -> FloatRect
1661     {
1662         IntSize cancelButtonSizeBasedOnFontSize = sizeForSystemFont(box.style(), cancelButtonSizes());
1663         FloatSize diff = localBoundsForCancelButton.size() - FloatSize(cancelButtonSizeBasedOnFontSize);
1664         if (!diff.width() && !diff.height())
1665             return localBoundsForCancelButton;
1666         // Vertically centered and right aligned.
1667         FloatRect adjustedLocalBoundsForCancelButton = localBoundsForCancelButton;
1668         adjustedLocalBoundsForCancelButton.move(diff.width(), floorToDevicePixel(diff.height() / 2, box.document().deviceScaleFactor()));
1669         adjustedLocalBoundsForCancelButton.setSize(cancelButtonSizeBasedOnFontSize);
1670         return adjustedLocalBoundsForCancelButton;
1671     };
1672
1673     if (!box.element())
1674         return false;
1675     Element* input = box.element()->shadowHost();
1676     if (!input)
1677         input = box.element();
1678
1679     if (!is<RenderBox>(input->renderer()))
1680         return false;
1681
1682     const RenderBox& inputBox = downcast<RenderBox>(*input->renderer());
1683     LocalCurrentGraphicsContext localContext(paintInfo.context());
1684     setSearchCellState(inputBox, r);
1685
1686     NSSearchFieldCell* search = this->search();
1687
1688     if (!input->isDisabledFormControl() && (is<HTMLTextFormControlElement>(*input) && !downcast<HTMLTextFormControlElement>(*input).isReadOnly()))
1689         updatePressedState([search cancelButtonCell], box);
1690     else if ([[search cancelButtonCell] isHighlighted])
1691         [[search cancelButtonCell] setHighlighted:NO];
1692
1693     GraphicsContextStateSaver stateSaver(paintInfo.context());
1694
1695     float zoomLevel = box.style().effectiveZoom();
1696
1697     FloatRect localBounds = adjustedCancelButtonRect([search cancelButtonRectForBounds:NSRect(snappedIntRect(inputBox.contentBoxRect()))]);
1698     // Adjust position based on the content direction.
1699     float adjustedXPosition;
1700     if (box.style().direction() == RTL)
1701         adjustedXPosition = inputBox.contentBoxRect().x();
1702     else
1703         adjustedXPosition = inputBox.contentBoxRect().maxX() - localBounds.size().width();
1704     
1705     localBounds.setX(adjustedXPosition);
1706     FloatPoint paintingPos = convertToPaintingPosition(inputBox, box, localBounds.location(), r.location());
1707
1708     FloatRect unzoomedRect(paintingPos, localBounds.size());
1709     if (zoomLevel != 1.0f) {
1710         unzoomedRect.setSize(unzoomedRect.size() / zoomLevel);
1711         paintInfo.context().translate(unzoomedRect.location());
1712         paintInfo.context().scale(zoomLevel);
1713         paintInfo.context().translate(-unzoomedRect.location());
1714     }
1715     [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(box)];
1716     [[search cancelButtonCell] setControlView:nil];
1717     return false;
1718 }
1719
1720 const IntSize* RenderThemeMac::cancelButtonSizes() const
1721 {
1722     static const IntSize sizes[3] = { IntSize(22, 22), IntSize(19, 19), IntSize(15, 15) };
1723     return sizes;
1724 }
1725
1726 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
1727 {
1728     IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1729     style.setWidth(Length(size.width(), Fixed));
1730     style.setHeight(Length(size.height(), Fixed));
1731     style.setBoxShadow(nullptr);
1732 }
1733
1734 const int resultsArrowWidth = 5;
1735 const IntSize* RenderThemeMac::resultsButtonSizes() const
1736 {
1737     static const IntSize sizes[3] = { IntSize(19, 22), IntSize(17, 19), IntSize(17, 15) };
1738     return sizes;
1739 }
1740
1741 const int emptyResultsOffset = 9;
1742 void RenderThemeMac::adjustSearchFieldDecorationPartStyle(StyleResolver&, RenderStyle& style, const Element*) const
1743 {
1744     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1745     style.setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1746     style.setHeight(Length(size.height(), Fixed));
1747     style.setBoxShadow(nullptr);
1748 }
1749
1750 bool RenderThemeMac::paintSearchFieldDecorationPart(const RenderObject&, const PaintInfo&, const IntRect&)
1751 {
1752     return false;
1753 }
1754
1755 void RenderThemeMac::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle& style, const Element*) const
1756 {
1757     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1758     style.setWidth(Length(size.width(), Fixed));
1759     style.setHeight(Length(size.height(), Fixed));
1760     style.setBoxShadow(nullptr);
1761 }
1762
1763 bool RenderThemeMac::paintSearchFieldResultsDecorationPart(const RenderBox& box, const PaintInfo& paintInfo, const IntRect& r)
1764 {
1765     if (!box.element())
1766         return false;
1767     Element* input = box.element()->shadowHost();
1768     if (!input)
1769         input = box.element();
1770     if (!is<RenderBox>(input->renderer()))
1771         return false;
1772     
1773     const RenderBox& inputBox = downcast<RenderBox>(*input->renderer());
1774     LocalCurrentGraphicsContext localContext(paintInfo.context());
1775     setSearchCellState(inputBox, r);
1776
1777     NSSearchFieldCell* search = this->search();
1778
1779     if ([search searchMenuTemplate] != nil)
1780         [search setSearchMenuTemplate:nil];
1781
1782     FloatRect localBounds = [search searchButtonRectForBounds:NSRect(snappedIntRect(inputBox.borderBoxRect()))];
1783     FloatPoint paintingPos = convertToPaintingPosition(inputBox, box, localBounds.location(), r.location());
1784     localBounds.setLocation(paintingPos);
1785
1786     [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(box)];
1787     [[search searchButtonCell] setControlView:nil];
1788     return false;
1789 }
1790
1791 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
1792 {
1793     IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1794     style.setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1795     style.setHeight(Length(size.height(), Fixed));
1796     style.setBoxShadow(nullptr);
1797 }
1798
1799 bool RenderThemeMac::paintSearchFieldResultsButton(const RenderBox& box, const PaintInfo& paintInfo, const IntRect& r)
1800 {
1801     auto adjustedResultButtonRect = [this, &box] (const FloatRect& localBounds) -> FloatRect
1802     {
1803         IntSize buttonSize = sizeForSystemFont(box.style(), resultsButtonSizes());
1804         buttonSize.expand(resultsArrowWidth, 0);
1805         FloatSize diff = localBounds.size() - FloatSize(buttonSize);
1806         if (!diff.isZero())
1807             return localBounds;
1808         // Vertically centered and left aligned.
1809         FloatRect adjustedLocalBounds = localBounds;
1810         adjustedLocalBounds.move(0, floorToDevicePixel(diff.height() / 2, box.document().deviceScaleFactor()));
1811         adjustedLocalBounds.setSize(buttonSize);
1812         return adjustedLocalBounds;
1813     };
1814
1815     Element* input = box.element()->shadowHost();
1816     if (!input)
1817         input = box.element();
1818     if (!is<RenderBox>(input->renderer()))
1819         return false;
1820     
1821     const RenderBox& inputBox = downcast<RenderBox>(*input->renderer());
1822     LocalCurrentGraphicsContext localContext(paintInfo.context());
1823     setSearchCellState(inputBox, r);
1824
1825     NSSearchFieldCell* search = this->search();
1826
1827     if (![search searchMenuTemplate])
1828         [search setSearchMenuTemplate:searchMenuTemplate()];
1829
1830     GraphicsContextStateSaver stateSaver(paintInfo.context());
1831     float zoomLevel = box.style().effectiveZoom();
1832
1833     FloatRect localBounds = adjustedResultButtonRect([search searchButtonRectForBounds:NSRect(snappedIntRect(inputBox.contentBoxRect()))]);
1834     // Adjust position based on the content direction.
1835     float adjustedXPosition;
1836     if (box.style().direction() == RTL)
1837         adjustedXPosition = inputBox.contentBoxRect().maxX() - localBounds.size().width();
1838     else
1839         adjustedXPosition = inputBox.contentBoxRect().x();
1840     localBounds.setX(adjustedXPosition);
1841     FloatPoint paintingPos = convertToPaintingPosition(inputBox, box, localBounds.location(), r.location());
1842     
1843     FloatRect unzoomedRect(paintingPos, localBounds.size());
1844     if (zoomLevel != 1.0f) {
1845         unzoomedRect.setSize(unzoomedRect.size() / zoomLevel);
1846         paintInfo.context().translate(unzoomedRect.location());
1847         paintInfo.context().scale(zoomLevel);
1848         paintInfo.context().translate(-unzoomedRect.location());
1849     }
1850
1851     [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(box)];
1852     [[search searchButtonCell] setControlView:nil];
1853
1854     return false;
1855 }
1856
1857 bool RenderThemeMac::paintSnapshottedPluginOverlay(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect&)
1858 {
1859     if (paintInfo.phase != PaintPhaseBlockBackground)
1860         return true;
1861
1862     if (!is<RenderBlock>(renderer))
1863         return true;
1864
1865     const RenderBlock& renderBlock = downcast<RenderBlock>(renderer);
1866
1867     LayoutUnit contentWidth = renderBlock.contentWidth();
1868     LayoutUnit contentHeight = renderBlock.contentHeight();
1869     if (!contentWidth || !contentHeight)
1870         return true;
1871
1872     GraphicsContext& context = paintInfo.context();
1873
1874     LayoutSize contentSize(contentWidth, contentHeight);
1875     LayoutPoint contentLocation = renderBlock.location();
1876     contentLocation.move(renderBlock.borderLeft() + renderBlock.paddingLeft(), renderBlock.borderTop() + renderBlock.paddingTop());
1877
1878     LayoutRect rect(contentLocation, contentSize);
1879     IntRect alignedRect = snappedIntRect(rect);
1880     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
1881         return true;
1882
1883     // We need to get the snapshot image from the plugin element, which should be available
1884     // from our node. Assuming this node is the plugin overlay element, we should get to the
1885     // plugin itself by asking for the shadow root parent, and then its parent.
1886
1887     if (!is<HTMLElement>(*renderBlock.element()))
1888         return true;
1889
1890     HTMLElement& plugInOverlay = downcast<HTMLElement>(*renderBlock.element());
1891     Element* parent = plugInOverlay.parentOrShadowHostElement();
1892     while (parent && !is<HTMLPlugInElement>(*parent))
1893         parent = parent->parentOrShadowHostElement();
1894
1895     if (!parent)
1896         return true;
1897
1898     HTMLPlugInElement& plugInElement = downcast<HTMLPlugInElement>(*parent);
1899     if (!is<HTMLPlugInImageElement>(plugInElement))
1900         return true;
1901
1902     HTMLPlugInImageElement& plugInImageElement = downcast<HTMLPlugInImageElement>(plugInElement);
1903
1904     Image* snapshot = plugInImageElement.snapshotImage();
1905     if (!snapshot)
1906         return true;
1907
1908     RenderSnapshottedPlugIn& plugInRenderer = downcast<RenderSnapshottedPlugIn>(*plugInImageElement.renderer());
1909     FloatPoint snapshotAbsPos = plugInRenderer.localToAbsolute();
1910     snapshotAbsPos.move(plugInRenderer.borderLeft() + plugInRenderer.paddingLeft(), plugInRenderer.borderTop() + plugInRenderer.paddingTop());
1911
1912     // We could draw the snapshot with that coordinates, but we need to make sure there
1913     // isn't a composited layer between us and the plugInRenderer.
1914     for (auto* renderBox = &downcast<RenderBox>(renderer); renderBox != &plugInRenderer; renderBox = renderBox->parentBox()) {
1915         if (renderBox->isComposited()) {
1916             snapshotAbsPos = -renderBox->location();
1917             break;
1918         }
1919     }
1920
1921     LayoutSize pluginSize(plugInRenderer.contentWidth(), plugInRenderer.contentHeight());
1922     LayoutRect pluginRect(snapshotAbsPos, pluginSize);
1923     IntRect alignedPluginRect = snappedIntRect(pluginRect);
1924
1925     if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
1926         return true;
1927
1928     context.drawImage(*snapshot, alignedPluginRect, CompositeSourceOver);
1929     return false;
1930 }
1931
1932 #if ENABLE(DATALIST_ELEMENT)
1933 IntSize RenderThemeMac::sliderTickSize() const
1934 {
1935     return IntSize(1, 3);
1936 }
1937
1938 int RenderThemeMac::sliderTickOffsetFromTrackCenter() const
1939 {
1940     return -9;
1941 }
1942 #endif
1943
1944 const int sliderThumbWidth = 15;
1945 const int sliderThumbHeight = 15;
1946
1947 void RenderThemeMac::adjustSliderThumbSize(RenderStyle& style, const Element*) const
1948 {
1949     float zoomLevel = style.effectiveZoom();
1950     if (style.appearance() == SliderThumbHorizontalPart || style.appearance() == SliderThumbVerticalPart) {
1951         style.setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1952         style.setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1953     }
1954 }
1955
1956 bool RenderThemeMac::shouldHaveCapsLockIndicator(const HTMLInputElement& element) const
1957 {
1958     return element.isPasswordField();
1959 }
1960
1961 NSPopUpButtonCell* RenderThemeMac::popupButton() const
1962 {
1963     if (!m_popupButton) {
1964         m_popupButton = adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
1965         [m_popupButton.get() setUsesItemFromMenu:NO];
1966         [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
1967         [m_popupButton setUserInterfaceLayoutDirection:NSUserInterfaceLayoutDirectionLeftToRight];
1968     }
1969
1970     return m_popupButton.get();
1971 }
1972
1973 NSSearchFieldCell* RenderThemeMac::search() const
1974 {
1975     if (!m_search) {
1976         m_search = adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
1977         [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
1978         [m_search.get() setBezeled:YES];
1979         [m_search.get() setEditable:YES];
1980         [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
1981         [m_search.get() setCenteredLook:NO];
1982     }
1983
1984     return m_search.get();
1985 }
1986
1987 NSMenu* RenderThemeMac::searchMenuTemplate() const
1988 {
1989     if (!m_searchMenuTemplate)
1990         m_searchMenuTemplate = adoptNS([[NSMenu alloc] initWithTitle:@""]);
1991
1992     return m_searchMenuTemplate.get();
1993 }
1994
1995 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
1996 {
1997     if (!m_sliderThumbHorizontal) {
1998         m_sliderThumbHorizontal = adoptNS([[NSSliderCell alloc] init]);
1999         [m_sliderThumbHorizontal.get() setSliderType:NSSliderTypeLinear];
2000         [m_sliderThumbHorizontal.get() setControlSize:NSControlSizeSmall];
2001         [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
2002     }
2003
2004     return m_sliderThumbHorizontal.get();
2005 }
2006
2007 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
2008 {
2009     if (!m_sliderThumbVertical) {
2010         m_sliderThumbVertical = adoptNS([[NSSliderCell alloc] init]);
2011         [m_sliderThumbVertical.get() setSliderType:NSSliderTypeLinear];
2012         [m_sliderThumbVertical.get() setControlSize:NSControlSizeSmall];
2013         [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
2014     }
2015
2016     return m_sliderThumbVertical.get();
2017 }
2018
2019 NSTextFieldCell* RenderThemeMac::textField() const
2020 {
2021     if (!m_textField) {
2022         m_textField = adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
2023         [m_textField.get() setBezeled:YES];
2024         [m_textField.get() setEditable:YES];
2025         [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
2026         // Post-Lion, WebCore can be in charge of paintinng the background thanks to
2027         // the workaround in place for <rdar://problem/11385461>, which is implemented
2028         // above as _coreUIDrawOptionsWithFrame.
2029         [m_textField.get() setDrawsBackground:NO];
2030     }
2031
2032     return m_textField.get();
2033 }
2034
2035 String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const FontCascade& font, int width, bool multipleFilesAllowed) const
2036 {
2037     if (width <= 0)
2038         return String();
2039
2040     String strToTruncate;
2041     if (fileList->isEmpty())
2042         strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
2043     else if (fileList->length() == 1)
2044         strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
2045     else
2046         return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font);
2047
2048     return StringTruncator::centerTruncate(strToTruncate, width, font);
2049 }
2050
2051 #if ENABLE(SERVICE_CONTROLS)
2052 NSServicesRolloverButtonCell* RenderThemeMac::servicesRolloverButtonCell() const
2053 {
2054 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2055     if (!m_servicesRolloverButton) {
2056         m_servicesRolloverButton = [NSServicesRolloverButtonCell serviceRolloverButtonCellForStyle:NSSharingServicePickerStyleRollover];
2057         [m_servicesRolloverButton setBezelStyle:NSBezelStyleRoundedDisclosure];
2058         [m_servicesRolloverButton setButtonType:NSButtonTypePushOnPushOff];
2059         [m_servicesRolloverButton setImagePosition:NSImageOnly];
2060         [m_servicesRolloverButton setState:NO];
2061     }
2062
2063     return m_servicesRolloverButton.get();
2064 #else
2065     return nil;
2066 #endif
2067 }
2068
2069 bool RenderThemeMac::paintImageControlsButton(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect& rect)
2070 {
2071     if (paintInfo.phase != PaintPhaseBlockBackground)
2072         return true;
2073
2074 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2075     NSServicesRolloverButtonCell *cell = servicesRolloverButtonCell();
2076
2077     LocalCurrentGraphicsContext localContext(paintInfo.context());
2078     GraphicsContextStateSaver stateSaver(paintInfo.context());
2079
2080     paintInfo.context().translate(rect.location());
2081
2082     IntRect innerFrame(IntPoint(), rect.size());
2083     [cell drawWithFrame:innerFrame inView:documentViewFor(renderer)];
2084     [cell setControlView:nil];
2085 #else
2086     UNUSED_PARAM(renderer);
2087     UNUSED_PARAM(rect);
2088 #endif
2089
2090     return true;
2091 }
2092
2093 IntSize RenderThemeMac::imageControlsButtonSize(const RenderObject&) const
2094 {
2095 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2096     return IntSize(servicesRolloverButtonCell().cellSize);
2097 #else
2098     return IntSize();
2099 #endif
2100 }
2101
2102 IntSize RenderThemeMac::imageControlsButtonPositionOffset() const
2103 {
2104 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2105     // FIXME: Currently the offsets will always be the same no matter what image rect you try with.
2106     // This may not always be true in the future.
2107     static const int dummyDimension = 100;
2108     IntRect dummyImageRect(0, 0, dummyDimension, dummyDimension);
2109     NSRect bounds = [servicesRolloverButtonCell() rectForBounds:dummyImageRect preferredEdge:NSMinYEdge];
2110
2111     return IntSize(dummyDimension - bounds.origin.x, bounds.origin.y);
2112 #else
2113     return IntSize();
2114 #endif
2115 }
2116 #endif
2117
2118 #if ENABLE(ATTACHMENT_ELEMENT)
2119 const CGFloat attachmentIconSize = 48;
2120 const CGFloat attachmentIconBackgroundPadding = 6;
2121 const CGFloat attachmentIconBackgroundSize = attachmentIconSize + attachmentIconBackgroundPadding;
2122 const CGFloat attachmentIconSelectionBorderThickness = 1;
2123 const CGFloat attachmentIconBackgroundRadius = 3;
2124 const CGFloat attachmentIconToTitleMargin = 2;
2125
2126 static Color attachmentIconBackgroundColor() { return Color(0, 0, 0, 30); }
2127 static Color attachmentIconBorderColor() { return Color(255, 255, 255, 125); }
2128
2129 const CGFloat attachmentTitleFontSize = 12;
2130 const CGFloat attachmentTitleBackgroundRadius = 3;
2131 const CGFloat attachmentTitleBackgroundPadding = 3;
2132 const CGFloat attachmentTitleMaximumWidth = 100 - (attachmentTitleBackgroundPadding * 2);
2133 const CFIndex attachmentTitleMaximumLineCount = 2;
2134
2135 static Color attachmentTitleInactiveBackgroundColor() { return Color(204, 204, 204, 255); }
2136 static Color attachmentTitleInactiveTextColor() { return Color(100, 100, 100, 255); }
2137
2138 const CGFloat attachmentSubtitleFontSize = 10;
2139 const int attachmentSubtitleWidthIncrement = 10;
2140 static Color attachmentSubtitleTextColor() { return Color(82, 145, 214, 255); }
2141
2142 const CGFloat attachmentProgressBarWidth = 30;
2143 const CGFloat attachmentProgressBarHeight = 5;
2144 const CGFloat attachmentProgressBarOffset = -9;
2145 const CGFloat attachmentProgressBarBorderWidth = 1;
2146 static Color attachmentProgressBarBackgroundColor() { return Color(0, 0, 0, 89); }
2147 static Color attachmentProgressBarFillColor() { return Color(Color::white); }
2148 static Color attachmentProgressBarBorderColor() { return Color(0, 0, 0, 128); }
2149
2150 const CGFloat attachmentPlaceholderBorderRadius = 5;
2151 static Color attachmentPlaceholderBorderColor() { return Color(0, 0, 0, 56); }
2152 const CGFloat attachmentPlaceholderBorderWidth = 2;
2153 const CGFloat attachmentPlaceholderBorderDashLength = 6;
2154
2155 const CGFloat attachmentMargin = 3;
2156
2157 struct AttachmentLayout {
2158     explicit AttachmentLayout(const RenderAttachment&);
2159
2160     struct LabelLine {
2161         FloatRect backgroundRect;
2162         FloatPoint origin;
2163         RetainPtr<CTLineRef> line;
2164     };
2165
2166     Vector<LabelLine> lines;
2167
2168     FloatRect iconRect;
2169     FloatRect iconBackgroundRect;
2170     FloatRect attachmentRect;
2171
2172     int baseline;
2173
2174     RetainPtr<CTLineRef> subtitleLine;
2175     FloatRect subtitleTextRect;
2176
2177 private:
2178     void layOutTitle(const RenderAttachment&);
2179     void layOutSubtitle(const RenderAttachment&);
2180
2181     void addTitleLine(CTLineRef, CGFloat& yOffset, Vector<CGPoint> origins, CFIndex lineIndex, const RenderAttachment&);
2182 };
2183
2184 static NSColor *titleTextColorForAttachment(const RenderAttachment& attachment)
2185 {
2186     if (attachment.selectionState() != RenderObject::SelectionNone) {
2187         if (attachment.frame().selection().isFocusedAndActive())
2188             return [NSColor alternateSelectedControlTextColor];    
2189         return (NSColor *)cachedCGColor(attachmentTitleInactiveTextColor());
2190     }
2191
2192     return [NSColor blackColor];
2193 }
2194
2195 void AttachmentLayout::addTitleLine(CTLineRef line, CGFloat& yOffset, Vector<CGPoint> origins, CFIndex lineIndex, const RenderAttachment& attachment)
2196 {
2197     CGRect lineBounds = CTLineGetBoundsWithOptions(line, 0);
2198     CGFloat trailingWhitespaceWidth = CTLineGetTrailingWhitespaceWidth(line);
2199     CGFloat lineWidthIgnoringTrailingWhitespace = lineBounds.size.width - trailingWhitespaceWidth;
2200     CGFloat lineHeight = CGCeiling(lineBounds.size.height);
2201
2202     // Center the line relative to the icon.
2203     CGFloat xOffset = (attachmentIconBackgroundSize / 2) - (lineWidthIgnoringTrailingWhitespace / 2);
2204
2205     if (lineIndex)
2206         yOffset += origins[lineIndex - 1].y - origins[lineIndex].y;
2207
2208     LabelLine labelLine;
2209     labelLine.origin = FloatPoint(xOffset, yOffset + lineHeight - origins.last().y);
2210     labelLine.line = line;
2211     labelLine.backgroundRect = FloatRect(xOffset, yOffset, lineWidthIgnoringTrailingWhitespace, lineHeight);
2212     labelLine.backgroundRect.inflateX(attachmentTitleBackgroundPadding);
2213     labelLine.backgroundRect = encloseRectToDevicePixels(labelLine.backgroundRect, attachment.document().deviceScaleFactor());
2214
2215     // If the text rects are close in size, the curved enclosing background won't
2216     // look right, so make them the same exact size.
2217     if (!lines.isEmpty()) {
2218         float previousBackgroundRectWidth = lines.last().backgroundRect.width();
2219         if (fabs(labelLine.backgroundRect.width() - previousBackgroundRectWidth) < attachmentTitleBackgroundRadius * 4) {
2220             float newBackgroundRectWidth = std::max(previousBackgroundRectWidth, labelLine.backgroundRect.width());
2221             labelLine.backgroundRect.inflateX((newBackgroundRectWidth - labelLine.backgroundRect.width()) / 2);
2222             lines.last().backgroundRect.inflateX((newBackgroundRectWidth - previousBackgroundRectWidth) / 2);
2223         }
2224     }
2225
2226     lines.append(labelLine);
2227 }
2228
2229 void AttachmentLayout::layOutTitle(const RenderAttachment& attachment)
2230 {
2231     CFStringRef language = 0; // By not specifying a language we use the system language.
2232     RetainPtr<CTFontRef> font = adoptCF(CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, attachmentTitleFontSize, language));
2233     baseline = CGRound(attachmentIconBackgroundSize + attachmentIconToTitleMargin + CTFontGetAscent(font.get()));
2234
2235     String title = attachment.attachmentElement().attachmentTitle();
2236     if (title.isEmpty())
2237         return;
2238
2239     NSDictionary *textAttributes = @{
2240         (id)kCTFontAttributeName: (id)font.get(),
2241         (id)kCTForegroundColorAttributeName: titleTextColorForAttachment(attachment)
2242     };
2243     RetainPtr<NSAttributedString> attributedTitle = adoptNS([[NSAttributedString alloc] initWithString:title attributes:textAttributes]);
2244     RetainPtr<CTFramesetterRef> titleFramesetter = adoptCF(CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedTitle.get()));
2245
2246     CFRange fitRange;
2247     CGSize titleTextSize = CTFramesetterSuggestFrameSizeWithConstraints(titleFramesetter.get(), CFRangeMake(0, 0), nullptr, CGSizeMake(attachmentTitleMaximumWidth, CGFLOAT_MAX), &fitRange);
2248
2249     RetainPtr<CGPathRef> titlePath = adoptCF(CGPathCreateWithRect(CGRectMake(0, 0, titleTextSize.width, titleTextSize.height), nullptr));
2250     RetainPtr<CTFrameRef> titleFrame = adoptCF(CTFramesetterCreateFrame(titleFramesetter.get(), fitRange, titlePath.get(), nullptr));
2251
2252     CFArrayRef ctLines = CTFrameGetLines(titleFrame.get());
2253     CFIndex lineCount = CFArrayGetCount(ctLines);
2254     if (!lineCount)
2255         return;
2256
2257     Vector<CGPoint> origins(lineCount);
2258     CTFrameGetLineOrigins(titleFrame.get(), CFRangeMake(0, 0), origins.data());
2259
2260     // Lay out and record the first (attachmentTitleMaximumLineCount - 1) lines.
2261     CFIndex lineIndex = 0;
2262     CGFloat yOffset = attachmentIconBackgroundSize + attachmentIconToTitleMargin;
2263     for (; lineIndex < std::min(attachmentTitleMaximumLineCount - 1, lineCount); ++lineIndex) {
2264         CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
2265         addTitleLine(line, yOffset, origins, lineIndex, attachment);
2266     }
2267
2268     if (lineIndex == lineCount)
2269         return;
2270
2271     // We had text that didn't fit in the first (attachmentTitleMaximumLineCount - 1) lines.
2272     // Combine it into one last line, and center-truncate it.
2273     CTLineRef firstRemainingLine = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
2274     CFIndex remainingRangeStart = CTLineGetStringRange(firstRemainingLine).location;
2275     NSRange remainingRange = NSMakeRange(remainingRangeStart, [attributedTitle length] - remainingRangeStart);
2276     NSAttributedString *remainingString = [attributedTitle attributedSubstringFromRange:remainingRange];
2277     RetainPtr<CTLineRef> remainingLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)remainingString));
2278     RetainPtr<NSAttributedString> ellipsisString = adoptNS([[NSAttributedString alloc] initWithString:@"\u2026" attributes:textAttributes]);
2279     RetainPtr<CTLineRef> ellipsisLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)ellipsisString.get()));
2280     RetainPtr<CTLineRef> truncatedLine = adoptCF(CTLineCreateTruncatedLine(remainingLine.get(), attachmentTitleMaximumWidth, kCTLineTruncationMiddle, ellipsisLine.get()));
2281
2282     if (!truncatedLine)
2283         truncatedLine = remainingLine;
2284
2285     addTitleLine(truncatedLine.get(), yOffset, origins, lineIndex, attachment);
2286 }
2287
2288 void AttachmentLayout::layOutSubtitle(const RenderAttachment& attachment)
2289 {
2290     auto& subtitleText = attachment.attachmentElement().attributeWithoutSynchronization(subtitleAttr);
2291     if (subtitleText.isEmpty())
2292         return;
2293
2294     CFStringRef language = 0; // By not specifying a language we use the system language.
2295     RetainPtr<CTFontRef> font = adoptCF(CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, attachmentSubtitleFontSize, language));
2296     NSDictionary *textAttributes = @{
2297         (id)kCTFontAttributeName: (id)font.get(),
2298         (id)kCTForegroundColorAttributeName: (NSColor *)cachedCGColor(attachmentSubtitleTextColor())
2299     };
2300     RetainPtr<NSAttributedString> attributedSubtitleText = adoptNS([[NSAttributedString alloc] initWithString:subtitleText attributes:textAttributes]);
2301     subtitleLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)attributedSubtitleText.get()));
2302
2303     CGRect lineBounds = CTLineGetBoundsWithOptions(subtitleLine.get(), 0);
2304
2305     // Center the line relative to the icon.
2306     CGFloat xOffset = (attachmentIconBackgroundSize / 2) - (lineBounds.size.width / 2);
2307     CGFloat yOffset = 0;
2308
2309     if (!lines.isEmpty())
2310         yOffset = lines.last().backgroundRect.maxY();
2311     else
2312         yOffset = attachmentIconBackgroundSize + attachmentIconToTitleMargin;
2313
2314     LabelLine labelLine;
2315     subtitleTextRect = FloatRect(xOffset, yOffset, lineBounds.size.width, lineBounds.size.height);
2316 }
2317
2318 AttachmentLayout::AttachmentLayout(const RenderAttachment& attachment)
2319 {
2320     layOutTitle(attachment);
2321     layOutSubtitle(attachment);
2322
2323     iconBackgroundRect = FloatRect(0, 0, attachmentIconBackgroundSize, attachmentIconBackgroundSize);
2324
2325     iconRect = iconBackgroundRect;
2326     iconRect.setSize(FloatSize(attachmentIconSize, attachmentIconSize));
2327     iconRect.move(attachmentIconBackgroundPadding / 2, attachmentIconBackgroundPadding / 2);
2328
2329     attachmentRect = iconBackgroundRect;
2330     for (const auto& line : lines)
2331         attachmentRect.unite(line.backgroundRect);
2332     if (!subtitleTextRect.isEmpty()) {
2333         FloatRect roundedSubtitleTextRect = subtitleTextRect;
2334         roundedSubtitleTextRect.inflateX(attachmentSubtitleWidthIncrement - clampToInteger(ceilf(subtitleTextRect.width())) % attachmentSubtitleWidthIncrement);
2335         attachmentRect.unite(roundedSubtitleTextRect);
2336     }
2337     attachmentRect.inflate(attachmentMargin);
2338     attachmentRect = encloseRectToDevicePixels(attachmentRect, attachment.document().deviceScaleFactor());
2339 }
2340
2341 LayoutSize RenderThemeMac::attachmentIntrinsicSize(const RenderAttachment& attachment) const
2342 {
2343     AttachmentLayout layout(attachment);
2344     return LayoutSize(layout.attachmentRect.size());
2345 }
2346
2347 int RenderThemeMac::attachmentBaseline(const RenderAttachment& attachment) const
2348 {
2349     AttachmentLayout layout(attachment);
2350     return layout.baseline;
2351 }
2352
2353 static void paintAttachmentIconBackground(const RenderAttachment&, GraphicsContext& context, AttachmentLayout& layout)
2354 {
2355     // FIXME: Finder has a discontinuous behavior here when you have a background color other than white,
2356     // where it switches into 'bordered mode' and the border pops in on top of the background.
2357     bool paintBorder = true;
2358
2359     FloatRect backgroundRect = layout.iconBackgroundRect;
2360     if (paintBorder)
2361         backgroundRect.inflate(-attachmentIconSelectionBorderThickness);
2362
2363     context.fillRoundedRect(FloatRoundedRect(backgroundRect, FloatRoundedRect::Radii(attachmentIconBackgroundRadius)), attachmentIconBackgroundColor());
2364
2365     if (paintBorder) {
2366         FloatRect borderRect = layout.iconBackgroundRect;
2367         borderRect.inflate(-attachmentIconSelectionBorderThickness / 2);
2368
2369         FloatSize iconBackgroundRadiusSize(attachmentIconBackgroundRadius, attachmentIconBackgroundRadius);
2370         Path borderPath;
2371         borderPath.addRoundedRect(borderRect, iconBackgroundRadiusSize);
2372         context.setStrokeColor(attachmentIconBorderColor());
2373         context.setStrokeThickness(attachmentIconSelectionBorderThickness);
2374         context.strokePath(borderPath);
2375     }
2376 }
2377
2378 static RefPtr<Icon> iconForAttachment(const RenderAttachment& attachment)
2379 {
2380     String attachmentType = attachment.attachmentElement().attachmentType();
2381     
2382     if (!attachmentType.isEmpty()) {
2383         if (equalIgnoringASCIICase(attachmentType, "multipart/x-folder") || equalIgnoringASCIICase(attachmentType, "application/vnd.apple.folder")) {
2384             if (auto icon = Icon::createIconForUTI("public.directory"))
2385                 return icon;
2386         } else {
2387             String UTI;
2388             if (isDeclaredUTI(attachmentType))
2389                 UTI = attachmentType;
2390             else
2391                 UTI = UTIFromMIMEType(attachmentType);
2392
2393             if (auto icon = Icon::createIconForUTI(UTI))
2394                 return icon;
2395         }
2396     }
2397
2398     if (File* file = attachment.attachmentElement().file()) {
2399         if (auto icon = Icon::createIconForFiles({ file->path() }))
2400             return icon;
2401     }
2402
2403     NSString *fileExtension = [static_cast<NSString *>(attachment.attachmentElement().attachmentTitle()) pathExtension];
2404     if (fileExtension.length) {
2405         if (auto icon = Icon::createIconForFileExtension(fileExtension))
2406             return icon;
2407     }
2408
2409     return Icon::createIconForUTI("public.data");
2410 }
2411
2412 static void paintAttachmentIcon(const RenderAttachment& attachment, GraphicsContext& context, AttachmentLayout& layout)
2413 {
2414     auto icon = iconForAttachment(attachment);
2415     if (!icon)
2416         return;
2417     icon->paint(context, layout.iconRect);
2418 }
2419
2420 static void paintAttachmentIconPlaceholder(const RenderAttachment& attachment, GraphicsContext& context, AttachmentLayout& layout)
2421 {
2422     RefPtr<Image> placeholderImage;
2423     float imageScale = 1;
2424     if (attachment.document().deviceScaleFactor() >= 2) {
2425         placeholderImage = Image::loadPlatformResource("AttachmentPlaceholder@2x");
2426         imageScale = 2;
2427     } else
2428         placeholderImage = Image::loadPlatformResource("AttachmentPlaceholder");
2429
2430     // Center the placeholder image where the icon would usually be.
2431     FloatRect placeholderRect(0, 0, placeholderImage->width() / imageScale, placeholderImage->height() / imageScale);
2432     placeholderRect.setX(layout.iconRect.x() + (layout.iconRect.width() - placeholderRect.width()) / 2);
2433     placeholderRect.setY(layout.iconRect.y() + (layout.iconRect.height() - placeholderRect.height()) / 2);
2434
2435     context.drawImage(*placeholderImage, placeholderRect);
2436 }
2437
2438 static void paintAttachmentTitleBackground(const RenderAttachment& attachment, GraphicsContext& context, AttachmentLayout& layout)
2439 {
2440     if (layout.lines.isEmpty())
2441         return;
2442
2443     Vector<FloatRect> backgroundRects;
2444
2445     for (size_t i = 0; i < layout.lines.size(); ++i)
2446         backgroundRects.append(layout.lines[i].backgroundRect);
2447
2448     Color backgroundColor;
2449     if (attachment.frame().selection().isFocusedAndActive())
2450         backgroundColor = convertNSColorToColor([NSColor alternateSelectedControlColor]);
2451     else
2452         backgroundColor = attachmentTitleInactiveBackgroundColor();
2453
2454     context.setFillColor(backgroundColor);
2455
2456     Path backgroundPath = PathUtilities::pathWithShrinkWrappedRects(backgroundRects, attachmentTitleBackgroundRadius);
2457     context.fillPath(backgroundPath);
2458 }
2459
2460 static void paintAttachmentTitle(const RenderAttachment&, GraphicsContext& context, AttachmentLayout& layout)
2461 {
2462     for (const auto& line : layout.lines) {
2463         GraphicsContextStateSaver saver(context);
2464
2465         context.translate(toFloatSize(line.origin));
2466         context.scale(FloatSize(1, -1));
2467
2468         CGContextSetTextPosition(context.platformContext(), 0, 0);
2469         CTLineDraw(line.line.get(), context.platformContext());
2470     }
2471 }
2472
2473 static void paintAttachmentSubtitle(const RenderAttachment&, GraphicsContext& context, AttachmentLayout& layout)
2474 {
2475     GraphicsContextStateSaver saver(context);
2476
2477     context.translate(toFloatSize(layout.subtitleTextRect.minXMaxYCorner()));
2478     context.scale(FloatSize(1, -1));
2479
2480     CGContextSetTextPosition(context.platformContext(), 0, 0);
2481     CTLineDraw(layout.subtitleLine.get(), context.platformContext());
2482 }
2483
2484 static void paintAttachmentProgress(const RenderAttachment& attachment, GraphicsContext& context, AttachmentLayout& layout, float progress)
2485 {
2486     GraphicsContextStateSaver saver(context);
2487
2488     FloatRect progressBounds((attachmentIconBackgroundSize - attachmentProgressBarWidth) / 2, layout.iconBackgroundRect.maxY() + attachmentProgressBarOffset - attachmentProgressBarHeight, attachmentProgressBarWidth, attachmentProgressBarHeight);
2489
2490     FloatRect borderRect = progressBounds;
2491     borderRect.inflate(-0.5);
2492     FloatRect backgroundRect = borderRect;
2493     backgroundRect.inflate(-attachmentProgressBarBorderWidth / 2);
2494
2495     FloatRoundedRect backgroundRoundedRect(backgroundRect, FloatRoundedRect::Radii(backgroundRect.height() / 2));
2496     context.fillRoundedRect(backgroundRoundedRect, attachmentProgressBarBackgroundColor());
2497
2498     {
2499         GraphicsContextStateSaver clipSaver(context);
2500         context.clipRoundedRect(backgroundRoundedRect);
2501
2502         FloatRect progressRect = progressBounds;
2503         progressRect.setWidth(progressRect.width() * progress);
2504         progressRect = encloseRectToDevicePixels(progressRect, attachment.document().deviceScaleFactor());
2505
2506         context.fillRect(progressRect, attachmentProgressBarFillColor());
2507     }
2508
2509     Path borderPath;
2510     float borderRadius = borderRect.height() / 2;
2511     borderPath.addRoundedRect(borderRect, FloatSize(borderRadius, borderRadius));
2512     context.setStrokeColor(attachmentProgressBarBorderColor());
2513     context.setStrokeThickness(attachmentProgressBarBorderWidth);
2514     context.strokePath(borderPath);
2515 }
2516
2517 static void paintAttachmentPlaceholderBorder(const RenderAttachment&, GraphicsContext& context, AttachmentLayout& layout)
2518 {
2519     Path borderPath;
2520     borderPath.addRoundedRect(layout.attachmentRect, FloatSize(attachmentPlaceholderBorderRadius, attachmentPlaceholderBorderRadius));
2521     context.setStrokeColor(attachmentPlaceholderBorderColor());
2522     context.setStrokeThickness(attachmentPlaceholderBorderWidth);
2523     context.setStrokeStyle(DashedStroke);
2524     context.setLineDash({attachmentPlaceholderBorderDashLength}, 0);
2525     context.strokePath(borderPath);
2526 }
2527
2528 bool RenderThemeMac::paintAttachment(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect& paintRect)
2529 {
2530     if (!is<RenderAttachment>(renderer))
2531         return false;
2532
2533     const RenderAttachment& attachment = downcast<RenderAttachment>(renderer);
2534
2535     AttachmentLayout layout(attachment);
2536
2537     auto& progressString = attachment.attachmentElement().attributeWithoutSynchronization(progressAttr);
2538     bool validProgress = false;
2539     float progress = 0;
2540     if (!progressString.isEmpty())
2541         progress = progressString.toFloat(&validProgress);
2542
2543     GraphicsContext& context = paintInfo.context();
2544     LocalCurrentGraphicsContext localContext(context);
2545     GraphicsContextStateSaver saver(context);
2546
2547     context.translate(toFloatSize(paintRect.location()));
2548     context.translate(floorSizeToDevicePixels(LayoutSize((paintRect.width() - attachmentIconBackgroundSize) / 2, 0), renderer.document().deviceScaleFactor()));
2549
2550     bool useSelectedStyle = attachment.selectionState() != RenderObject::SelectionNone;
2551     bool usePlaceholder = validProgress && !progress;
2552
2553     if (useSelectedStyle)
2554         paintAttachmentIconBackground(attachment, context, layout);
2555     if (usePlaceholder)
2556         paintAttachmentIconPlaceholder(attachment, context, layout);
2557     else
2558         paintAttachmentIcon(attachment, context, layout);
2559
2560     if (useSelectedStyle)
2561         paintAttachmentTitleBackground(attachment, context, layout);
2562     paintAttachmentTitle(attachment, context, layout);
2563     paintAttachmentSubtitle(attachment, context, layout);
2564
2565     if (validProgress && progress)
2566         paintAttachmentProgress(attachment, context, layout, progress);
2567
2568     if (usePlaceholder)
2569         paintAttachmentPlaceholderBorder(attachment, context, layout);
2570
2571     return true;
2572 }
2573
2574 #endif // ENABLE(ATTACHMENT_ELEMENT)
2575
2576 } // namespace WebCore
2577
2578 #endif // PLATFORM(MAC)