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