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