2 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
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.
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.
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.
22 #import "RenderThemeMac.h"
24 #import "BitmapImage.h"
25 #import "CSSValueKeywords.h"
26 #import "CSSValueList.h"
30 #import "ExceptionCodePlaceholder.h"
32 #import "FloatRoundedRect.h"
33 #import "FocusController.h"
36 #import "GraphicsContextCG.h"
37 #import "HTMLAudioElement.h"
38 #import "HTMLInputElement.h"
39 #import "HTMLMediaElement.h"
41 #import "HTMLPlugInImageElement.h"
43 #import "ImageBuffer.h"
44 #import "LocalCurrentGraphicsContext.h"
45 #import "LocalizedStrings.h"
46 #import "MediaControlElements.h"
47 #import "NSSharingServicePickerSPI.h"
50 #import "RenderLayer.h"
51 #import "RenderMedia.h"
52 #import "RenderMediaControlElements.h"
53 #import "RenderMediaControls.h"
54 #import "RenderProgress.h"
55 #import "RenderSlider.h"
56 #import "RenderSnapshottedPlugIn.h"
57 #import "RenderView.h"
58 #import "SharedBuffer.h"
59 #import "StringTruncator.h"
60 #import "StyleResolver.h"
62 #import "TimeRanges.h"
63 #import "UserAgentScripts.h"
64 #import "UserAgentStyleSheets.h"
65 #import "WebCoreSystemInterface.h"
66 #import <wtf/RetainPtr.h>
67 #import <wtf/RetainPtr.h>
68 #import <wtf/StdLibExtras.h>
69 #import <wtf/text/StringBuilder.h>
70 #import <Carbon/Carbon.h>
71 #import <Cocoa/Cocoa.h>
74 #if ENABLE(METER_ELEMENT)
75 #import "RenderMeter.h"
76 #import "HTMLMeterElement.h"
79 #if defined(__LP64__) && __LP64__
80 #define HAVE_APPKIT_SERVICE_CONTROLS_SUPPORT 1
82 #define HAVE_APPKIT_SERVICE_CONTROLS_SUPPORT 0
85 #if ENABLE(SERVICE_CONTROLS) && HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
87 #if __has_include(<AppKit/AppKitDefines_Private.h>)
88 #import <AppKit/AppKitDefines_Private.h>
90 #define APPKIT_PRIVATE_CLASS
93 #if __has_include(<AppKit/NSServicesRolloverButtonCell.h>)
94 #import <AppKit/NSServicesRolloverButtonCell.h>
96 @interface NSServicesRolloverButtonCell : NSButtonCell
100 @interface NSServicesRolloverButtonCell (Details)
101 + (NSServicesRolloverButtonCell *)serviceRolloverButtonCellForStyle:(NSSharingServicePickerStyle)style;
102 - (NSRect)rectForBounds:(NSRect)bounds preferredEdge:(NSRectEdge)preferredEdge;
105 #endif // ENABLE(SERVICE_CONTROLS)
107 // The methods in this file are specific to the Mac OS X platform.
109 // FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
111 // We estimate the animation rate of a Mac OS X progress bar is 33 fps.
112 // Hard code the value here because we haven't found API for it.
113 const double progressAnimationFrameRate = 0.033;
115 // Mac OS X progress bar animation seems to have 256 frames.
116 const double progressAnimationNumFrames = 256;
118 @interface WebCoreRenderThemeNotificationObserver : NSObject
120 WebCore::RenderTheme *_theme;
123 - (id)initWithTheme:(WebCore::RenderTheme *)theme;
124 - (void)systemColorsDidChange:(NSNotification *)notification;
128 @implementation WebCoreRenderThemeNotificationObserver
130 - (id)initWithTheme:(WebCore::RenderTheme *)theme
132 if (!(self = [super init]))
139 - (void)systemColorsDidChange:(NSNotification *)unusedNotification
141 ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
142 _theme->platformColorsDidChange();
147 @interface NSTextFieldCell (WKDetails)
148 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
152 @interface WebCoreTextFieldCell : NSTextFieldCell
153 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
156 @implementation WebCoreTextFieldCell
157 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
159 // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
160 CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
161 CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
162 return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
166 @interface WebCoreRenderThemeBundle : NSObject
169 @implementation WebCoreRenderThemeBundle
172 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
173 @interface NSSearchFieldCell(Details)
174 @property (getter=isCenteredLook) BOOL centeredLook;
180 using namespace HTMLNames;
196 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
198 static RenderTheme* rt = RenderThemeMac::create().leakRef();
202 PassRefPtr<RenderTheme> RenderThemeMac::create()
204 return adoptRef(new RenderThemeMac);
207 RenderThemeMac::RenderThemeMac()
208 : m_isSliderThumbHorizontalPressed(false)
209 , m_isSliderThumbVerticalPressed(false)
210 , m_notificationObserver(adoptNS([[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]))
212 [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
213 selector:@selector(systemColorsDidChange:)
214 name:NSSystemColorsDidChangeNotification
218 RenderThemeMac::~RenderThemeMac()
220 [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
223 NSView* RenderThemeMac::documentViewFor(const RenderObject& o) const
225 ControlStates states(extractControlStatesForRenderer(o));
226 return ThemeMac::ensuredView(&o.view().frameView(), &states);
230 String RenderThemeMac::mediaControlsStyleSheet()
232 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
233 if (m_mediaControlsStyleSheet.isEmpty())
234 m_mediaControlsStyleSheet = [NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"css"] encoding:NSUTF8StringEncoding error:nil];
235 return m_mediaControlsStyleSheet;
237 return emptyString();
241 String RenderThemeMac::mediaControlsScript()
243 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
244 if (m_mediaControlsScript.isEmpty()) {
245 StringBuilder scriptBuilder;
246 scriptBuilder.append([NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsLocalizedStrings" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]);
247 scriptBuilder.append([NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]);
248 m_mediaControlsScript = scriptBuilder.toString();
250 return m_mediaControlsScript;
252 return emptyString();
256 #endif // ENABLE(VIDEO)
259 #if ENABLE(SERVICE_CONTROLS)
260 String RenderThemeMac::imageControlsStyleSheet() const
262 return String(imageControlsMacUserAgentStyleSheet, sizeof(imageControlsMacUserAgentStyleSheet));
266 Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
268 NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
269 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
272 Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
274 NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
275 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
278 Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const
280 NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
281 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
284 Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const
289 Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const
294 Color RenderThemeMac::platformFocusRingColor() const
296 if (usesTestModeFocusRingColor())
297 return oldAquaFocusRingColor();
299 return systemColor(CSSValueWebkitFocusRingColor);
302 int RenderThemeMac::platformFocusRingMaxWidth() const
304 // FIXME: Shouldn't this function be named platformFocusRingMinWidth? But also, I'm not sure if this function is needed - looks like
305 // all platforms just used 0 for this before <http://trac.webkit.org/changeset/168397>.
309 Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const
311 return platformInactiveSelectionBackgroundColor();
314 static FontWeight toFontWeight(NSInteger appKitFontWeight)
316 ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
317 if (appKitFontWeight > 14)
318 appKitFontWeight = 14;
319 else if (appKitFontWeight < 1)
320 appKitFontWeight = 1;
322 static FontWeight fontWeights[] = {
338 return fontWeights[appKitFontWeight - 1];
341 void RenderThemeMac::updateCachedSystemFontDescription(CSSValueID cssValueId, FontDescription& fontDescription) const
344 switch (cssValueId) {
345 case CSSValueSmallCaption:
346 font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
349 font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
351 case CSSValueStatusBar:
352 font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
354 case CSSValueWebkitMiniControl:
355 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
357 case CSSValueWebkitSmallControl:
358 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
360 case CSSValueWebkitControl:
361 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
364 font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
370 NSFontManager *fontManager = [NSFontManager sharedFontManager];
371 fontDescription.setIsAbsoluteSize(true);
372 fontDescription.setOneFamily([font webCoreFamilyName]);
373 fontDescription.setSpecifiedSize([font pointSize]);
374 fontDescription.setWeight(toFontWeight([fontManager weightOfFont:font]));
375 fontDescription.setIsItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
378 static RGBA32 convertNSColorToColor(NSColor *color)
380 NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
381 if (colorInColorSpace) {
382 static const double scaleFactor = nextafter(256.0, 0.0);
383 return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
384 static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
385 static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
388 // This conversion above can fail if the NSColor in question is an NSPatternColor
389 // (as many system colors are). These colors are actually a repeating pattern
390 // not just a solid color. To work around this we simply draw a 1x1 image of
391 // the color and use that pixel's color. It might be better to use an average of
392 // the colors in the pattern instead.
393 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
400 colorSpaceName:NSDeviceRGBColorSpace
404 [NSGraphicsContext saveGraphicsState];
405 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
406 NSEraseRect(NSMakeRect(0, 0, 1, 1));
407 [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
408 [NSGraphicsContext restoreGraphicsState];
411 [offscreenRep getPixel:pixel atX:0 y:0];
413 [offscreenRep release];
415 return makeRGB(pixel[0], pixel[1], pixel[2]);
418 static RGBA32 menuBackgroundColor()
420 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
427 colorSpaceName:NSDeviceRGBColorSpace
431 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
432 CGRect rect = CGRectMake(0, 0, 1, 1);
433 HIThemeMenuDrawInfo drawInfo;
434 drawInfo.version = 0;
435 drawInfo.menuType = kThemeMenuTypePopUp;
436 HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
439 [offscreenRep getPixel:pixel atX:0 y:0];
441 [offscreenRep release];
443 return makeRGB(pixel[0], pixel[1], pixel[2]);
446 void RenderThemeMac::platformColorsDidChange()
448 m_systemColorCache.clear();
449 RenderTheme::platformColorsDidChange();
452 Color RenderThemeMac::systemColor(CSSValueID cssValueId) const
455 HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
456 if (it != m_systemColorCache.end())
461 switch (cssValueId) {
462 case CSSValueActiveborder:
463 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
465 case CSSValueActivecaption:
466 color = convertNSColorToColor([NSColor windowFrameTextColor]);
468 case CSSValueAppworkspace:
469 color = convertNSColorToColor([NSColor headerColor]);
471 case CSSValueBackground:
472 // Use theme independent default
474 case CSSValueButtonface:
475 // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
476 // We may want to change this to use the NSColor in future.
479 case CSSValueButtonhighlight:
480 color = convertNSColorToColor([NSColor controlHighlightColor]);
482 case CSSValueButtonshadow:
483 color = convertNSColorToColor([NSColor controlShadowColor]);
485 case CSSValueButtontext:
486 color = convertNSColorToColor([NSColor controlTextColor]);
488 case CSSValueActivebuttontext:
489 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
493 case CSSValueCaptiontext:
494 color = convertNSColorToColor([NSColor textColor]);
496 case CSSValueGraytext:
497 color = convertNSColorToColor([NSColor disabledControlTextColor]);
499 case CSSValueHighlight:
500 color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
502 case CSSValueHighlighttext:
503 color = convertNSColorToColor([NSColor selectedTextColor]);
505 case CSSValueInactiveborder:
506 color = convertNSColorToColor([NSColor controlBackgroundColor]);
508 case CSSValueInactivecaption:
509 color = convertNSColorToColor([NSColor controlBackgroundColor]);
511 case CSSValueInactivecaptiontext:
512 color = convertNSColorToColor([NSColor textColor]);
514 case CSSValueInfobackground:
515 // There is no corresponding NSColor for this so we use a hard coded value.
518 case CSSValueInfotext:
519 color = convertNSColorToColor([NSColor textColor]);
522 color = menuBackgroundColor();
524 case CSSValueMenutext:
525 color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
527 case CSSValueScrollbar:
528 color = convertNSColorToColor([NSColor scrollBarColor]);
531 color = convertNSColorToColor([NSColor textColor]);
533 case CSSValueThreeddarkshadow:
534 color = convertNSColorToColor([NSColor controlDarkShadowColor]);
536 case CSSValueThreedshadow:
537 color = convertNSColorToColor([NSColor shadowColor]);
539 case CSSValueThreedface:
540 // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
541 // We may want to change this to use the NSColor in future.
544 case CSSValueThreedhighlight:
545 color = convertNSColorToColor([NSColor highlightColor]);
547 case CSSValueThreedlightshadow:
548 color = convertNSColorToColor([NSColor controlLightHighlightColor]);
550 case CSSValueWebkitFocusRingColor:
551 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
554 color = convertNSColorToColor([NSColor windowBackgroundColor]);
556 case CSSValueWindowframe:
557 color = convertNSColorToColor([NSColor windowFrameColor]);
559 case CSSValueWindowtext:
560 color = convertNSColorToColor([NSColor windowFrameTextColor]);
566 if (!color.isValid())
567 color = RenderTheme::systemColor(cssValueId);
570 m_systemColorCache.set(cssValueId, color.rgb());
575 bool RenderThemeMac::usesTestModeFocusRingColor() const
577 return WebCore::usesTestModeFocusRingColor();
580 bool RenderThemeMac::isControlStyled(const RenderStyle& style, const BorderData& border,
581 const FillLayer& background, const Color& backgroundColor) const
583 if (style.appearance() == TextFieldPart || style.appearance() == TextAreaPart || style.appearance() == ListboxPart)
584 return style.border() != border;
586 // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when
587 // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style
588 // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming
589 // is in effect we treat it like the control is styled.
590 if (style.appearance() == MenulistPart && style.effectiveZoom() != 1.0f)
593 return RenderTheme::isControlStyled(style, border, background, backgroundColor);
596 static FloatRect inflateRect(const FloatRect& rect, const IntSize& size, const int* margins, float zoomLevel)
598 // Only do the inflation if the available width/height are too small. Otherwise try to
599 // fit the glow/check space into the available box's width/height.
600 int widthDelta = rect.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
601 int heightDelta = rect.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
602 FloatRect result(rect);
603 if (widthDelta < 0) {
604 result.setX(result.x() - margins[leftMargin] * zoomLevel);
605 result.setWidth(result.width() - widthDelta);
607 if (heightDelta < 0) {
608 result.setY(result.y() - margins[topMargin] * zoomLevel);
609 result.setHeight(result.height() - heightDelta);
614 void RenderThemeMac::adjustRepaintRect(const RenderObject& renderer, FloatRect& rect)
616 ControlPart part = renderer.style().appearance();
623 case SquareButtonPart:
624 case DefaultButtonPart:
626 case InnerSpinButtonPart:
627 return RenderTheme::adjustRepaintRect(renderer, rect);
633 float zoomLevel = renderer.style().effectiveZoom();
635 if (part == MenulistPart) {
636 setPopupButtonCellState(renderer, IntSize(rect.size()));
637 IntSize size = popupButtonSizes()[[popupButton() controlSize]];
638 size.setHeight(size.height() * zoomLevel);
639 size.setWidth(rect.width());
640 rect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
644 FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject& inputRenderer, const RenderObject& partRenderer, const FloatRect& inputRect, const IntRect& r) const
646 FloatRect partRect(inputRect);
648 // Compute an offset between the part renderer and the input renderer
649 FloatSize offsetFromInputRenderer;
650 const RenderObject* renderer = &partRenderer;
651 while (renderer && renderer != &inputRenderer) {
652 RenderElement* containingRenderer = renderer->container();
653 ASSERT(containingRenderer);
654 offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(*containingRenderer, LayoutPoint()));
655 renderer = containingRenderer;
657 // If the input renderer was not a container, something went wrong
658 ASSERT(renderer == &inputRenderer);
659 // Move the rect into partRenderer's coords
660 partRect.move(offsetFromInputRenderer);
661 // Account for the local drawing offset (tx, ty)
662 partRect.move(r.x(), r.y());
667 void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject& o)
669 bool oldIndeterminate = [cell state] == NSMixedState;
670 bool indeterminate = isIndeterminate(o);
671 bool checked = isChecked(o);
673 if (oldIndeterminate != indeterminate) {
674 [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
678 bool oldChecked = [cell state] == NSOnState;
679 if (checked != oldChecked)
680 [cell setState:checked ? NSOnState : NSOffState];
683 void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject& o)
685 bool oldEnabled = [cell isEnabled];
686 bool enabled = isEnabled(o);
687 if (enabled != oldEnabled)
688 [cell setEnabled:enabled];
691 void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject& o)
693 bool oldFocused = [cell showsFirstResponder];
694 bool focused = isFocused(o) && o.style().outlineStyleIsAuto();
695 if (focused != oldFocused)
696 [cell setShowsFirstResponder:focused];
699 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject& o)
701 bool oldPressed = [cell isHighlighted];
702 bool pressed = is<Element>(o.node()) && downcast<Element>(*o.node()).active();
703 if (pressed != oldPressed)
704 [cell setHighlighted:pressed];
707 bool RenderThemeMac::controlSupportsTints(const RenderObject& o) const
709 // An alternate way to implement this would be to get the appropriate cell object
710 // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
711 // that would be that we would match AppKit behavior more closely, but a disadvantage
712 // would be that we would rely on an AppKit SPI method.
717 // Checkboxes only have tint when checked.
718 if (o.style().appearance() == CheckboxPart)
721 // For now assume other controls have tint if enabled.
725 NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle& style) const
727 int fontSize = style.fontSize();
729 return NSRegularControlSize;
731 return NSSmallControlSize;
732 return NSMiniControlSize;
735 NSControlSize RenderThemeMac::controlSizeForCell(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel) const
737 if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel)
738 && minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
739 return NSRegularControlSize;
741 if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel)
742 && minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
743 return NSSmallControlSize;
745 return NSMiniControlSize;
748 void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
750 NSControlSize size = controlSizeForCell(cell, sizes, minSize, zoomLevel);
751 if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
752 [cell setControlSize:size];
755 IntSize RenderThemeMac::sizeForFont(RenderStyle& style, const IntSize* sizes) const
757 if (style.effectiveZoom() != 1.0f) {
758 IntSize result = sizes[controlSizeForFont(style)];
759 return IntSize(result.width() * style.effectiveZoom(), result.height() * style.effectiveZoom());
761 return sizes[controlSizeForFont(style)];
764 IntSize RenderThemeMac::sizeForSystemFont(RenderStyle& style, const IntSize* sizes) const
766 if (style.effectiveZoom() != 1.0f) {
767 IntSize result = sizes[controlSizeForSystemFont(style)];
768 return IntSize(result.width() * style.effectiveZoom(), result.height() * style.effectiveZoom());
770 return sizes[controlSizeForSystemFont(style)];
773 void RenderThemeMac::setSizeFromFont(RenderStyle& style, const IntSize* sizes) const
775 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
776 IntSize size = sizeForFont(style, sizes);
777 if (style.width().isIntrinsicOrAuto() && size.width() > 0)
778 style.setWidth(Length(size.width(), Fixed));
779 if (style.height().isAuto() && size.height() > 0)
780 style.setHeight(Length(size.height(), Fixed));
783 void RenderThemeMac::setFontFromControlSize(StyleResolver&, RenderStyle& style, NSControlSize controlSize) const
785 FontDescription fontDescription;
786 fontDescription.setIsAbsoluteSize(true);
788 NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
789 fontDescription.setOneFamily([font webCoreFamilyName]);
790 fontDescription.setComputedSize([font pointSize] * style.effectiveZoom());
791 fontDescription.setSpecifiedSize([font pointSize] * style.effectiveZoom());
794 style.setLineHeight(RenderStyle::initialLineHeight());
796 if (style.setFontDescription(fontDescription))
797 style.fontCascade().update(0);
800 NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle& style) const
802 int fontSize = style.fontSize();
803 if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
804 return NSRegularControlSize;
805 if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
806 return NSSmallControlSize;
807 return NSMiniControlSize;
810 bool RenderThemeMac::paintTextField(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
812 LocalCurrentGraphicsContext localContext(paintInfo.context);
814 NSTextFieldCell *textField = this->textField();
816 GraphicsContextStateSaver stateSaver(*paintInfo.context);
818 [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
819 [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
821 [textField setControlView:nil];
826 void RenderThemeMac::adjustTextFieldStyle(StyleResolver&, RenderStyle&, Element*) const
830 bool RenderThemeMac::paintCapsLockIndicator(const RenderObject&, const PaintInfo& paintInfo, const IntRect& r)
832 if (paintInfo.context->paintingDisabled())
835 LocalCurrentGraphicsContext localContext(paintInfo.context);
836 wkDrawCapsLockIndicator(localContext.cgContext(), r);
841 bool RenderThemeMac::paintTextArea(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
843 LocalCurrentGraphicsContext localContext(paintInfo.context);
844 wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
848 void RenderThemeMac::adjustTextAreaStyle(StyleResolver&, RenderStyle&, Element*) const
852 const int* RenderThemeMac::popupButtonMargins() const
854 static const int margins[3][4] =
860 return margins[[popupButton() controlSize]];
863 const IntSize* RenderThemeMac::popupButtonSizes() const
865 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
869 const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
871 static const int padding[3][4] =
877 return padding[size];
880 bool RenderThemeMac::paintMenuList(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
882 LocalCurrentGraphicsContext localContext(paintInfo.context);
883 setPopupButtonCellState(renderer, IntSize(rect.size()));
885 NSPopUpButtonCell* popupButton = this->popupButton();
887 float zoomLevel = renderer.style().effectiveZoom();
888 IntSize size = popupButtonSizes()[[popupButton controlSize]];
889 size.setHeight(size.height() * zoomLevel);
890 size.setWidth(rect.width());
892 // Now inflate it to account for the shadow.
893 FloatRect inflatedRect = rect;
894 if (rect.width() >= minimumMenuListSize(renderer.style()))
895 inflatedRect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
897 GraphicsContextStateSaver stateSaver(*paintInfo.context);
899 // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
900 paintInfo.context->clip(inflatedRect);
902 if (zoomLevel != 1.0f) {
903 inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
904 inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
905 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
906 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
907 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
910 NSView *view = documentViewFor(renderer);
911 [popupButton drawWithFrame:inflatedRect inView:view];
912 if (isFocused(renderer) && renderer.style().outlineStyleIsAuto()) {
913 if (wkDrawCellFocusRingWithFrameAtTime(popupButton, inflatedRect, view, std::numeric_limits<double>::max()))
914 renderer.document().page()->focusController().setFocusedElementNeedsRepaint();
917 [popupButton setControlView:nil];
922 #if ENABLE(METER_ELEMENT)
924 IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter& renderMeter, const IntRect& bounds) const
926 if (NoControlPart == renderMeter.style().appearance())
927 return bounds.size();
929 NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
930 // Makes enough room for cell's intrinsic size.
931 NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
932 return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
933 bounds.height() < cellSize.height ? cellSize.height : bounds.height());
936 bool RenderThemeMac::paintMeter(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
938 if (!is<RenderMeter>(renderObject))
941 LocalCurrentGraphicsContext localContext(paintInfo.context);
943 NSLevelIndicatorCell* cell = levelIndicatorFor(downcast<RenderMeter>(renderObject));
944 GraphicsContextStateSaver stateSaver(*paintInfo.context);
946 [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
947 [cell setControlView:nil];
951 bool RenderThemeMac::supportsMeter(ControlPart part) const
954 case RelevancyLevelIndicatorPart:
955 case DiscreteCapacityLevelIndicatorPart:
956 case RatingLevelIndicatorPart:
958 case ContinuousCapacityLevelIndicatorPart:
965 NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
968 case RelevancyLevelIndicatorPart:
969 return NSRelevancyLevelIndicatorStyle;
970 case DiscreteCapacityLevelIndicatorPart:
971 return NSDiscreteCapacityLevelIndicatorStyle;
972 case RatingLevelIndicatorPart:
973 return NSRatingLevelIndicatorStyle;
975 case ContinuousCapacityLevelIndicatorPart:
977 return NSContinuousCapacityLevelIndicatorStyle;
982 NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter& renderMeter) const
984 const RenderStyle& style = renderMeter.style();
985 ASSERT(style.appearance() != NoControlPart);
987 if (!m_levelIndicator)
988 m_levelIndicator = adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
989 NSLevelIndicatorCell* cell = m_levelIndicator.get();
991 HTMLMeterElement* element = renderMeter.meterElement();
992 double value = element->value();
994 // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
995 // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
996 switch (element->gaugeRegion()) {
997 case HTMLMeterElement::GaugeRegionOptimum:
998 // Make meter the green
999 [cell setWarningValue:value + 1];
1000 [cell setCriticalValue:value + 2];
1002 case HTMLMeterElement::GaugeRegionSuboptimal:
1003 // Make the meter yellow
1004 [cell setWarningValue:value - 1];
1005 [cell setCriticalValue:value + 1];
1007 case HTMLMeterElement::GaugeRegionEvenLessGood:
1008 // Make the meter red
1009 [cell setWarningValue:value - 2];
1010 [cell setCriticalValue:value - 1];
1014 [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style.appearance())];
1015 [cell setBaseWritingDirection:style.isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
1016 [cell setMinValue:element->min()];
1017 [cell setMaxValue:element->max()];
1018 RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
1019 [cell setObjectValue:valueObject.get()];
1026 const IntSize* RenderThemeMac::progressBarSizes() const
1028 static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
1032 const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const
1034 static const int margins[3][4] =
1040 return margins[controlSize];
1043 IntRect RenderThemeMac::progressBarRectForBounds(const RenderObject& renderObject, const IntRect& bounds) const
1045 // Workaround until <rdar://problem/15855086> is fixed.
1046 int maxDimension = static_cast<int>(std::numeric_limits<ushort>::max());
1047 IntRect progressBarBounds(bounds.x(), bounds.y(), std::min(bounds.width(), maxDimension), std::min(bounds.height(), maxDimension));
1048 if (NoControlPart == renderObject.style().appearance())
1049 return progressBarBounds;
1051 float zoomLevel = renderObject.style().effectiveZoom();
1052 NSControlSize controlSize = controlSizeForFont(renderObject.style());
1053 IntSize size = progressBarSizes()[controlSize];
1054 size.setHeight(size.height() * zoomLevel);
1055 size.setWidth(progressBarBounds.width());
1057 // Now inflate it to account for the shadow.
1058 IntRect inflatedRect = progressBarBounds;
1059 if (progressBarBounds.height() <= minimumProgressBarHeight(renderObject.style()))
1060 inflatedRect = IntRect(inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel));
1062 return inflatedRect;
1065 int RenderThemeMac::minimumProgressBarHeight(RenderStyle& style) const
1067 return sizeForSystemFont(style, progressBarSizes()).height();
1070 double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress&) const
1072 return progressAnimationFrameRate;
1075 double RenderThemeMac::animationDurationForProgressBar(RenderProgress&) const
1077 return progressAnimationNumFrames * progressAnimationFrameRate;
1080 void RenderThemeMac::adjustProgressBarStyle(StyleResolver&, RenderStyle&, Element*) const
1084 bool RenderThemeMac::paintProgressBar(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1086 if (!is<RenderProgress>(renderObject))
1089 IntRect inflatedRect = progressBarRectForBounds(renderObject, rect);
1090 NSControlSize controlSize = controlSizeForFont(renderObject.style());
1092 const auto& renderProgress = downcast<RenderProgress>(renderObject);
1093 HIThemeTrackDrawInfo trackInfo;
1094 trackInfo.version = 0;
1095 if (controlSize == NSRegularControlSize)
1096 trackInfo.kind = renderProgress.position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
1098 trackInfo.kind = renderProgress.position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
1100 float deviceScaleFactor = renderObject.document().deviceScaleFactor();
1101 trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
1103 trackInfo.max = std::numeric_limits<SInt32>::max();
1104 trackInfo.value = lround(renderProgress.position() * nextafter(trackInfo.max, 0));
1105 trackInfo.trackInfo.progress.phase = lround(renderProgress.animationProgress() * nextafter(progressAnimationNumFrames, 0) * deviceScaleFactor);
1106 trackInfo.attributes = kThemeTrackHorizontal;
1107 trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
1108 trackInfo.reserved = 0;
1109 trackInfo.filler1 = 0;
1111 std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::createCompatibleBuffer(inflatedRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB, paintInfo.context, true);
1115 ContextContainer cgContextContainer(imageBuffer->context());
1116 CGContextRef cgContext = cgContextContainer.context();
1117 HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
1119 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1121 if (!renderProgress.style().isLeftToRightDirection()) {
1122 paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
1123 paintInfo.context->scale(FloatSize(-1, 1));
1126 paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location());
1130 const float baseFontSize = 11.0f;
1131 const float baseArrowHeight = 4.0f;
1132 const float baseArrowWidth = 5.0f;
1133 const float baseSpaceBetweenArrows = 2.0f;
1134 const int arrowPaddingLeft = 6;
1135 const int arrowPaddingRight = 6;
1136 const int paddingBeforeSeparator = 4;
1137 const int baseBorderRadius = 5;
1138 const int styledPopupPaddingLeft = 8;
1139 const int styledPopupPaddingTop = 1;
1140 const int styledPopupPaddingBottom = 2;
1142 static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1144 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
1145 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
1146 float a = inData[0];
1148 for (i = 0; i < 4; i++)
1149 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1152 static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1154 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
1155 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
1156 float a = inData[0];
1158 for (i = 0; i < 4; i++)
1159 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1162 static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1164 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1165 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1166 float a = inData[0];
1168 for (i = 0; i < 4; i++)
1169 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1172 static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1174 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1175 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1176 float a = inData[0];
1178 for (i = 0; i < 4; i++)
1179 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1182 void RenderThemeMac::paintMenuListButtonGradients(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1187 ContextContainer cgContextContainer(paintInfo.context);
1188 CGContextRef context = cgContextContainer.context();
1190 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1192 FloatRoundedRect border = FloatRoundedRect(o.style().getRoundedBorderFor(r));
1193 int radius = border.radii().topLeft().width();
1195 CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1197 FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1198 struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1199 RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1200 RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
1202 FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1203 struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1204 RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1205 RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
1207 struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1208 RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1209 RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
1211 RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1213 RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
1216 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1217 CGContextClipToRect(context, r);
1218 paintInfo.context->clipRoundedRect(border);
1219 context = cgContextContainer.context();
1220 CGContextDrawShading(context, mainShading.get());
1224 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1225 CGContextClipToRect(context, topGradient);
1226 paintInfo.context->clipRoundedRect(FloatRoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
1227 context = cgContextContainer.context();
1228 CGContextDrawShading(context, topShading.get());
1231 if (!bottomGradient.isEmpty()) {
1232 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1233 CGContextClipToRect(context, bottomGradient);
1234 paintInfo.context->clipRoundedRect(FloatRoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
1235 context = cgContextContainer.context();
1236 CGContextDrawShading(context, bottomShading.get());
1240 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1241 CGContextClipToRect(context, r);
1242 paintInfo.context->clipRoundedRect(border);
1243 context = cgContextContainer.context();
1244 CGContextDrawShading(context, leftShading.get());
1245 CGContextDrawShading(context, rightShading.get());
1249 bool RenderThemeMac::paintMenuListButtonDecorations(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
1251 IntRect bounds = IntRect(rect.x() + renderer.style().borderLeftWidth(),
1252 rect.y() + renderer.style().borderTopWidth(),
1253 rect.width() - renderer.style().borderLeftWidth() - renderer.style().borderRightWidth(),
1254 rect.height() - renderer.style().borderTopWidth() - renderer.style().borderBottomWidth());
1255 // Draw the gradients to give the styled popup menu a button appearance
1256 paintMenuListButtonGradients(renderer, paintInfo, bounds);
1258 // 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
1259 float fontScale = std::min(renderer.style().fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1260 float centerY = bounds.y() + bounds.height() / 2.0f;
1261 float arrowHeight = baseArrowHeight * fontScale;
1262 float arrowWidth = baseArrowWidth * fontScale;
1263 float leftEdge = bounds.maxX() - arrowPaddingRight * renderer.style().effectiveZoom() - arrowWidth;
1264 float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1266 if (bounds.width() < arrowWidth + arrowPaddingLeft * renderer.style().effectiveZoom())
1269 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1271 paintInfo.context->setFillColor(renderer.style().visitedDependentColor(CSSPropertyColor), renderer.style().colorSpace());
1272 paintInfo.context->setStrokeStyle(NoStroke);
1274 FloatPoint arrow1[3];
1275 arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1276 arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1277 arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1279 // Draw the top arrow
1280 paintInfo.context->drawConvexPolygon(3, arrow1, true);
1282 FloatPoint arrow2[3];
1283 arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1284 arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1285 arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1287 // Draw the bottom arrow
1288 paintInfo.context->drawConvexPolygon(3, arrow2, true);
1290 Color leftSeparatorColor(0, 0, 0, 40);
1291 Color rightSeparatorColor(255, 255, 255, 40);
1293 // FIXME: Should the separator thickness and space be scaled up by fontScale?
1294 int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1295 int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * renderer.style().effectiveZoom()); // FIXME: Round?
1297 // Draw the separator to the left of the arrows
1298 paintInfo.context->setStrokeThickness(1); // Deliberately ignores zoom since it looks nicer if it stays thin.
1299 paintInfo.context->setStrokeStyle(SolidStroke);
1300 paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
1301 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1302 IntPoint(leftEdgeOfSeparator, bounds.maxY()));
1304 paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
1305 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1306 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
1310 static const IntSize* menuListButtonSizes()
1312 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1316 void RenderThemeMac::adjustMenuListStyle(StyleResolver& styleResolver, RenderStyle& style, Element* e) const
1318 NSControlSize controlSize = controlSizeForFont(style);
1320 style.resetBorder();
1321 style.resetPadding();
1323 // Height is locked to auto.
1324 style.setHeight(Length(Auto));
1326 // White-space is locked to pre
1327 style.setWhiteSpace(PRE);
1329 // Set the foreground color to black or gray when we have the aqua look.
1330 // Cast to RGB32 is to work around a compiler bug.
1331 style.setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1333 // Set the button's vertical size.
1334 setSizeFromFont(style, menuListButtonSizes());
1336 // 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
1337 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1338 // system font for the control size instead.
1339 setFontFromControlSize(styleResolver, style, controlSize);
1341 style.setBoxShadow(nullptr);
1344 int RenderThemeMac::popupInternalPaddingLeft(RenderStyle& style) const
1346 if (style.appearance() == MenulistPart)
1347 return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style.effectiveZoom();
1348 if (style.appearance() == MenulistButtonPart)
1349 return styledPopupPaddingLeft * style.effectiveZoom();
1353 int RenderThemeMac::popupInternalPaddingRight(RenderStyle& style) const
1355 if (style.appearance() == MenulistPart)
1356 return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style.effectiveZoom();
1357 if (style.appearance() == MenulistButtonPart) {
1358 float fontScale = style.fontSize() / baseFontSize;
1359 float arrowWidth = baseArrowWidth * fontScale;
1360 return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style.effectiveZoom()));
1365 int RenderThemeMac::popupInternalPaddingTop(RenderStyle& style) const
1367 if (style.appearance() == MenulistPart)
1368 return popupButtonPadding(controlSizeForFont(style))[topPadding] * style.effectiveZoom();
1369 if (style.appearance() == MenulistButtonPart)
1370 return styledPopupPaddingTop * style.effectiveZoom();
1374 int RenderThemeMac::popupInternalPaddingBottom(RenderStyle& style) const
1376 if (style.appearance() == MenulistPart)
1377 return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style.effectiveZoom();
1378 if (style.appearance() == MenulistButtonPart)
1379 return styledPopupPaddingBottom * style.effectiveZoom();
1383 PopupMenuStyle::PopupMenuSize RenderThemeMac::popupMenuSize(const RenderStyle& style, IntRect& rect) const
1385 NSPopUpButtonCell* popupButton = this->popupButton();
1386 NSControlSize size = controlSizeForCell(popupButton, popupButtonSizes(), rect.size(), style.effectiveZoom());
1388 case NSRegularControlSize:
1389 return PopupMenuStyle::PopupMenuSizeNormal;
1390 case NSSmallControlSize:
1391 return PopupMenuStyle::PopupMenuSizeSmall;
1392 case NSMiniControlSize:
1393 return PopupMenuStyle::PopupMenuSizeMini;
1395 return PopupMenuStyle::PopupMenuSizeNormal;
1399 void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1401 float fontScale = style.fontSize() / baseFontSize;
1403 style.resetPadding();
1404 style.setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1406 const int minHeight = 15;
1407 style.setMinHeight(Length(minHeight, Fixed));
1409 style.setLineHeight(RenderStyle::initialLineHeight());
1412 void RenderThemeMac::setPopupButtonCellState(const RenderObject& o, const IntSize& buttonSize)
1414 NSPopUpButtonCell* popupButton = this->popupButton();
1416 // Set the control size based off the rectangle we're painting into.
1417 setControlSize(popupButton, popupButtonSizes(), buttonSize, o.style().effectiveZoom());
1419 // Update the various states we respond to.
1420 updateCheckedState(popupButton, o);
1421 updateEnabledState(popupButton, o);
1422 updatePressedState(popupButton, o);
1425 const IntSize* RenderThemeMac::menuListSizes() const
1427 static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1431 int RenderThemeMac::minimumMenuListSize(RenderStyle& style) const
1433 return sizeForSystemFont(style, menuListSizes()).width();
1436 const int trackWidth = 5;
1437 const int trackRadius = 2;
1439 void RenderThemeMac::adjustSliderTrackStyle(StyleResolver&, RenderStyle& style, Element*) const
1441 style.setBoxShadow(nullptr);
1444 bool RenderThemeMac::paintSliderTrack(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1447 float zoomLevel = o.style().effectiveZoom();
1448 float zoomedTrackWidth = trackWidth * zoomLevel;
1450 if (o.style().appearance() == SliderHorizontalPart || o.style().appearance() == MediaSliderPart) {
1451 bounds.setHeight(zoomedTrackWidth);
1452 bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1453 } else if (o.style().appearance() == SliderVerticalPart) {
1454 bounds.setWidth(zoomedTrackWidth);
1455 bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1458 LocalCurrentGraphicsContext localContext(paintInfo.context);
1459 CGContextRef context = localContext.cgContext();
1460 CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1462 #if ENABLE(DATALIST_ELEMENT)
1463 paintSliderTicks(o, paintInfo, r);
1466 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1467 CGContextClipToRect(context, bounds);
1469 struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1470 RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1471 RetainPtr<CGShadingRef> mainShading;
1472 if (o.style().appearance() == SliderVerticalPart)
1473 mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
1475 mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
1477 IntSize radius(trackRadius, trackRadius);
1478 paintInfo.context->clipRoundedRect(FloatRoundedRect(bounds, radius, radius, radius, radius));
1479 context = localContext.cgContext();
1480 CGContextDrawShading(context, mainShading.get());
1485 void RenderThemeMac::adjustSliderThumbStyle(StyleResolver& styleResolver, RenderStyle& style, Element* element) const
1487 RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
1488 style.setBoxShadow(nullptr);
1491 const float verticalSliderHeightPadding = 0.1f;
1493 bool RenderThemeMac::paintSliderThumb(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1495 NSSliderCell* sliderThumbCell = o.style().appearance() == SliderThumbVerticalPart
1496 ? sliderThumbVertical()
1497 : sliderThumbHorizontal();
1499 LocalCurrentGraphicsContext localContext(paintInfo.context);
1501 // Update the various states we respond to.
1502 updateEnabledState(sliderThumbCell, o);
1503 Element* focusDelegate = is<Element>(o.node()) ? downcast<Element>(*o.node()).focusDelegate() : nullptr;
1505 updateFocusedState(sliderThumbCell, *focusDelegate->renderer());
1507 // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1509 if (o.style().appearance() == SliderThumbVerticalPart)
1510 oldPressed = m_isSliderThumbVerticalPressed;
1512 oldPressed = m_isSliderThumbHorizontalPressed;
1514 bool pressed = isPressed(o);
1516 if (o.style().appearance() == SliderThumbVerticalPart)
1517 m_isSliderThumbVerticalPressed = pressed;
1519 m_isSliderThumbHorizontalPressed = pressed;
1521 if (pressed != oldPressed) {
1523 [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1525 [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1528 FloatRect bounds = r;
1529 // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1530 if (o.style().appearance() == SliderThumbVerticalPart)
1531 bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o.style().effectiveZoom());
1533 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1534 float zoomLevel = o.style().effectiveZoom();
1536 FloatRect unzoomedRect = bounds;
1537 if (zoomLevel != 1.0f) {
1538 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1539 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1540 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1541 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1542 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1545 [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
1546 [sliderThumbCell setControlView:nil];
1551 bool RenderThemeMac::paintSearchField(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1553 LocalCurrentGraphicsContext localContext(paintInfo.context);
1554 NSSearchFieldCell* search = this->search();
1556 setSearchCellState(o, r);
1558 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1560 float zoomLevel = o.style().effectiveZoom();
1562 IntRect unzoomedRect = r;
1564 if (zoomLevel != 1.0f) {
1565 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1566 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1567 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1568 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1569 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1572 // Set the search button to nil before drawing. Then reset it so we can draw it later.
1573 [search setSearchButtonCell:nil];
1575 [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1577 [search setControlView:nil];
1578 [search resetSearchButtonCell];
1583 void RenderThemeMac::setSearchCellState(const RenderObject& o, const IntRect&)
1585 NSSearchFieldCell* search = this->search();
1587 [search setControlSize:controlSizeForFont(o.style())];
1589 // Update the various states we respond to.
1590 updateEnabledState(search, o);
1591 updateFocusedState(search, o);
1594 const IntSize* RenderThemeMac::searchFieldSizes() const
1596 static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1600 void RenderThemeMac::setSearchFieldSize(RenderStyle& style) const
1602 // If the width and height are both specified, then we have nothing to do.
1603 if (!style.width().isIntrinsicOrAuto() && !style.height().isAuto())
1606 // Use the font size to determine the intrinsic width of the control.
1607 setSizeFromFont(style, searchFieldSizes());
1610 void RenderThemeMac::adjustSearchFieldStyle(StyleResolver& styleResolver, RenderStyle& style, Element*) const
1613 style.resetBorder();
1614 const short borderWidth = 2 * style.effectiveZoom();
1615 style.setBorderLeftWidth(borderWidth);
1616 style.setBorderLeftStyle(INSET);
1617 style.setBorderRightWidth(borderWidth);
1618 style.setBorderRightStyle(INSET);
1619 style.setBorderBottomWidth(borderWidth);
1620 style.setBorderBottomStyle(INSET);
1621 style.setBorderTopWidth(borderWidth);
1622 style.setBorderTopStyle(INSET);
1625 style.setHeight(Length(Auto));
1626 setSearchFieldSize(style);
1628 // Override padding size to match AppKit text positioning.
1629 const int padding = 1 * style.effectiveZoom();
1630 style.setPaddingLeft(Length(padding, Fixed));
1631 style.setPaddingRight(Length(padding, Fixed));
1632 style.setPaddingTop(Length(padding, Fixed));
1633 style.setPaddingBottom(Length(padding, Fixed));
1635 NSControlSize controlSize = controlSizeForFont(style);
1636 setFontFromControlSize(styleResolver, style, controlSize);
1638 style.setBoxShadow(nullptr);
1641 bool RenderThemeMac::paintSearchFieldCancelButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1643 Element* input = o.node()->shadowHost();
1645 input = downcast<Element>(o.node());
1647 if (!input->renderer()->isBox())
1650 LocalCurrentGraphicsContext localContext(paintInfo.context);
1651 setSearchCellState(*input->renderer(), r);
1653 NSSearchFieldCell* search = this->search();
1655 if (!input->isDisabledFormControl() && (is<HTMLTextFormControlElement>(*input) && !downcast<HTMLTextFormControlElement>(*input).isReadOnly()))
1656 updatePressedState([search cancelButtonCell], o);
1657 else if ([[search cancelButtonCell] isHighlighted])
1658 [[search cancelButtonCell] setHighlighted:NO];
1660 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1662 float zoomLevel = o.style().effectiveZoom();
1664 FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1665 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1667 FloatRect unzoomedRect(localBounds);
1668 if (zoomLevel != 1.0f) {
1669 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1670 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1671 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1672 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1673 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1676 [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1677 [[search cancelButtonCell] setControlView:nil];
1681 const IntSize* RenderThemeMac::cancelButtonSizes() const
1683 static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1687 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1689 IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1690 style.setWidth(Length(size.width(), Fixed));
1691 style.setHeight(Length(size.height(), Fixed));
1692 style.setBoxShadow(nullptr);
1695 const IntSize* RenderThemeMac::resultsButtonSizes() const
1697 static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1701 const int emptyResultsOffset = 9;
1702 void RenderThemeMac::adjustSearchFieldDecorationPartStyle(StyleResolver&, RenderStyle& style, Element*) const
1704 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1705 style.setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1706 style.setHeight(Length(size.height(), Fixed));
1707 style.setBoxShadow(nullptr);
1710 bool RenderThemeMac::paintSearchFieldDecorationPart(const RenderObject&, const PaintInfo&, const IntRect&)
1715 void RenderThemeMac::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle& style, Element*) const
1717 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1718 style.setWidth(Length(size.width(), Fixed));
1719 style.setHeight(Length(size.height(), Fixed));
1720 style.setBoxShadow(nullptr);
1723 bool RenderThemeMac::paintSearchFieldResultsDecorationPart(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1725 Node* input = o.node()->shadowHost();
1728 if (!input->renderer()->isBox())
1731 LocalCurrentGraphicsContext localContext(paintInfo.context);
1732 setSearchCellState(*input->renderer(), r);
1734 NSSearchFieldCell* search = this->search();
1736 if ([search searchMenuTemplate] != nil)
1737 [search setSearchMenuTemplate:nil];
1739 FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1740 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1742 [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
1743 [[search searchButtonCell] setControlView:nil];
1747 const int resultsArrowWidth = 5;
1748 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1750 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1751 style.setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1752 style.setHeight(Length(size.height(), Fixed));
1753 style.setBoxShadow(nullptr);
1756 bool RenderThemeMac::paintSearchFieldResultsButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1758 Node* input = o.node()->shadowHost();
1761 if (!input->renderer()->isBox())
1764 LocalCurrentGraphicsContext localContext(paintInfo.context);
1765 setSearchCellState(*input->renderer(), r);
1767 NSSearchFieldCell* search = this->search();
1769 if (![search searchMenuTemplate])
1770 [search setSearchMenuTemplate:searchMenuTemplate()];
1772 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1773 float zoomLevel = o.style().effectiveZoom();
1775 FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1776 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1778 IntRect unzoomedRect(localBounds);
1779 if (zoomLevel != 1.0f) {
1780 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1781 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1782 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1783 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1784 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1787 [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1788 [[search searchButtonCell] setControlView:nil];
1793 bool RenderThemeMac::paintSnapshottedPluginOverlay(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect&)
1795 if (paintInfo.phase != PaintPhaseBlockBackground)
1798 if (!is<RenderBlock>(renderer))
1801 const RenderBlock& renderBlock = downcast<RenderBlock>(renderer);
1803 LayoutUnit contentWidth = renderBlock.contentWidth();
1804 LayoutUnit contentHeight = renderBlock.contentHeight();
1805 if (!contentWidth || !contentHeight)
1808 GraphicsContext* context = paintInfo.context;
1810 LayoutSize contentSize(contentWidth, contentHeight);
1811 LayoutPoint contentLocation = renderBlock.location();
1812 contentLocation.move(renderBlock.borderLeft() + renderBlock.paddingLeft(), renderBlock.borderTop() + renderBlock.paddingTop());
1814 LayoutRect rect(contentLocation, contentSize);
1815 IntRect alignedRect = snappedIntRect(rect);
1816 if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
1819 // We need to get the snapshot image from the plugin element, which should be available
1820 // from our node. Assuming this node is the plugin overlay element, we should get to the
1821 // plugin itself by asking for the shadow root parent, and then its parent.
1823 if (!is<HTMLElement>(*renderBlock.element()))
1826 HTMLElement& plugInOverlay = downcast<HTMLElement>(*renderBlock.element());
1827 Element* parent = plugInOverlay.parentOrShadowHostElement();
1828 while (parent && !is<HTMLPlugInElement>(*parent))
1829 parent = parent->parentOrShadowHostElement();
1834 HTMLPlugInElement& plugInElement = downcast<HTMLPlugInElement>(*parent);
1835 if (!is<HTMLPlugInImageElement>(plugInElement))
1838 HTMLPlugInImageElement& plugInImageElement = downcast<HTMLPlugInImageElement>(plugInElement);
1840 Image* snapshot = plugInImageElement.snapshotImage();
1844 RenderSnapshottedPlugIn& plugInRenderer = downcast<RenderSnapshottedPlugIn>(*plugInImageElement.renderer());
1845 FloatPoint snapshotAbsPos = plugInRenderer.localToAbsolute();
1846 snapshotAbsPos.move(plugInRenderer.borderLeft() + plugInRenderer.paddingLeft(), plugInRenderer.borderTop() + plugInRenderer.paddingTop());
1848 // We could draw the snapshot with that coordinates, but we need to make sure there
1849 // isn't a composited layer between us and the plugInRenderer.
1850 for (auto* renderBox = &downcast<RenderBox>(renderer); renderBox != &plugInRenderer; renderBox = renderBox->parentBox()) {
1851 if (renderBox->hasLayer() && renderBox->layer() && renderBox->layer()->isComposited()) {
1852 snapshotAbsPos = -renderBox->location();
1857 LayoutSize pluginSize(plugInRenderer.contentWidth(), plugInRenderer.contentHeight());
1858 LayoutRect pluginRect(snapshotAbsPos, pluginSize);
1859 IntRect alignedPluginRect = snappedIntRect(pluginRect);
1861 if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
1864 context->drawImage(snapshot, plugInRenderer.style().colorSpace(), alignedPluginRect, CompositeSourceOver);
1868 #if ENABLE(DATALIST_ELEMENT)
1869 IntSize RenderThemeMac::sliderTickSize() const
1871 return IntSize(1, 3);
1874 int RenderThemeMac::sliderTickOffsetFromTrackCenter() const
1880 const int sliderThumbWidth = 15;
1881 const int sliderThumbHeight = 15;
1883 void RenderThemeMac::adjustSliderThumbSize(RenderStyle& style, Element*) const
1885 float zoomLevel = style.effectiveZoom();
1886 if (style.appearance() == SliderThumbHorizontalPart || style.appearance() == SliderThumbVerticalPart) {
1887 style.setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1888 style.setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1892 bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const
1897 NSPopUpButtonCell* RenderThemeMac::popupButton() const
1899 if (!m_popupButton) {
1900 m_popupButton = adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
1901 [m_popupButton.get() setUsesItemFromMenu:NO];
1902 [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
1903 // We don't want the app's UI layout direction to affect the appearance of popup buttons in
1904 // web content, which has its own layout direction.
1905 // FIXME: Make this depend on the directionality of the select element, once the rest of the
1906 // rendering code can account for the popup arrows appearing on the other side.
1907 [m_popupButton setUserInterfaceLayoutDirection:NSUserInterfaceLayoutDirectionLeftToRight];
1910 return m_popupButton.get();
1913 NSSearchFieldCell* RenderThemeMac::search() const
1916 m_search = adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
1917 [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
1918 [m_search.get() setBezeled:YES];
1919 [m_search.get() setEditable:YES];
1920 [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
1921 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
1922 [m_search.get() setCenteredLook:NO];
1926 return m_search.get();
1929 NSMenu* RenderThemeMac::searchMenuTemplate() const
1931 if (!m_searchMenuTemplate)
1932 m_searchMenuTemplate = adoptNS([[NSMenu alloc] initWithTitle:@""]);
1934 return m_searchMenuTemplate.get();
1937 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
1939 if (!m_sliderThumbHorizontal) {
1940 m_sliderThumbHorizontal = adoptNS([[NSSliderCell alloc] init]);
1941 [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
1942 [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
1943 [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
1946 return m_sliderThumbHorizontal.get();
1949 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
1951 if (!m_sliderThumbVertical) {
1952 m_sliderThumbVertical = adoptNS([[NSSliderCell alloc] init]);
1953 [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
1954 [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
1955 [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
1958 return m_sliderThumbVertical.get();
1961 NSTextFieldCell* RenderThemeMac::textField() const
1964 m_textField = adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
1965 [m_textField.get() setBezeled:YES];
1966 [m_textField.get() setEditable:YES];
1967 [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
1968 // Post-Lion, WebCore can be in charge of paintinng the background thanks to
1969 // the workaround in place for <rdar://problem/11385461>, which is implemented
1970 // above as _coreUIDrawOptionsWithFrame.
1971 [m_textField.get() setDrawsBackground:NO];
1974 return m_textField.get();
1977 String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const FontCascade& font, int width, bool multipleFilesAllowed) const
1982 String strToTruncate;
1983 if (fileList->isEmpty())
1984 strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
1985 else if (fileList->length() == 1)
1986 strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
1988 return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
1990 return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
1993 bool RenderThemeMac::defaultButtonHasAnimation() const
1995 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
2002 #if ENABLE(SERVICE_CONTROLS)
2003 NSServicesRolloverButtonCell* RenderThemeMac::servicesRolloverButtonCell() const
2005 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2006 if (!m_servicesRolloverButton) {
2007 m_servicesRolloverButton = [NSServicesRolloverButtonCell serviceRolloverButtonCellForStyle:NSSharingServicePickerStyleRollover];
2008 [m_servicesRolloverButton setBezelStyle:NSRoundedDisclosureBezelStyle];
2009 [m_servicesRolloverButton setButtonType:NSPushOnPushOffButton];
2010 [m_servicesRolloverButton setImagePosition:NSImageOnly];
2011 [m_servicesRolloverButton setState:NO];
2014 return m_servicesRolloverButton.get();
2020 bool RenderThemeMac::paintImageControlsButton(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect& rect)
2022 if (paintInfo.phase != PaintPhaseBlockBackground)
2025 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2026 NSServicesRolloverButtonCell *cell = servicesRolloverButtonCell();
2028 LocalCurrentGraphicsContext localContext(paintInfo.context);
2029 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2031 paintInfo.context->translate(rect.x(), rect.y());
2033 IntRect innerFrame(IntPoint(), rect.size());
2034 [cell drawWithFrame:innerFrame inView:documentViewFor(renderer)];
2035 [cell setControlView:nil];
2037 UNUSED_PARAM(renderer);
2044 IntSize RenderThemeMac::imageControlsButtonSize(const RenderObject&) const
2046 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2047 return IntSize(servicesRolloverButtonCell().cellSize);
2053 IntSize RenderThemeMac::imageControlsButtonPositionOffset() const
2055 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2056 // FIXME: Currently the offsets will always be the same no matter what image rect you try with.
2057 // This may not always be true in the future.
2058 static const int dummyDimension = 100;
2059 IntRect dummyImageRect(0, 0, dummyDimension, dummyDimension);
2060 NSRect bounds = [servicesRolloverButtonCell() rectForBounds:dummyImageRect preferredEdge:NSMinYEdge];
2062 return IntSize(dummyDimension - bounds.origin.x, bounds.origin.y);
2069 } // namespace WebCore
2071 #endif // !PLATFORM(IOS)