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