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