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