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"
49 #import "RenderLayer.h"
50 #import "RenderMedia.h"
51 #import "RenderMediaControlElements.h"
52 #import "RenderMediaControls.h"
53 #import "RenderProgress.h"
54 #import "RenderSlider.h"
55 #import "RenderSnapshottedPlugIn.h"
56 #import "RenderView.h"
57 #import "SharedBuffer.h"
58 #import "StringTruncator.h"
59 #import "StyleResolver.h"
61 #import "TimeRanges.h"
62 #import "UserAgentScripts.h"
63 #import "UserAgentStyleSheets.h"
64 #import "WebCoreSystemInterface.h"
65 #import <wtf/RetainPtr.h>
66 #import <wtf/RetainPtr.h>
67 #import <wtf/StdLibExtras.h>
68 #import <wtf/text/StringBuilder.h>
69 #import <Carbon/Carbon.h>
70 #import <Cocoa/Cocoa.h>
73 #if ENABLE(METER_ELEMENT)
74 #import "RenderMeter.h"
75 #import "HTMLMeterElement.h"
78 #if defined(__LP64__) && __LP64__
79 #define HAVE_APPKIT_SERVICE_CONTROLS_SUPPORT 1
81 #define HAVE_APPKIT_SERVICE_CONTROLS_SUPPORT 0
84 #if ENABLE(SERVICE_CONTROLS) && HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
86 #if __has_include(<AppKit/AppKitDefines_Private.h>)
87 #import <AppKit/AppKitDefines_Private.h>
89 #define APPKIT_PRIVATE_CLASS
92 #if __has_include(<AppKit/NSServicesRolloverButtonCell.h>)
93 #import <AppKit/NSServicesRolloverButtonCell.h>
96 @interface NSServicesRolloverButtonCell (Details)
97 + (NSServicesRolloverButtonCell *)serviceRolloverButtonCellForStyle:(NSSharingServicePickerStyle)style;
100 #if __has_include(<AppKit/NSSharingService_Private.h>)
101 #import <AppKit/NSSharingService_Private.h>
104 NSSharingServicePickerStyleRollover = 1
105 } NSSharingServicePickerStyle;
108 #endif // ENABLE(SERVICE_CONTROLS)
110 // The methods in this file are specific to the Mac OS X platform.
112 // FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
114 // We estimate the animation rate of a Mac OS X progress bar is 33 fps.
115 // Hard code the value here because we haven't found API for it.
116 const double progressAnimationFrameRate = 0.033;
118 // Mac OS X progress bar animation seems to have 256 frames.
119 const double progressAnimationNumFrames = 256;
121 @interface WebCoreRenderThemeNotificationObserver : NSObject
123 WebCore::RenderTheme *_theme;
126 - (id)initWithTheme:(WebCore::RenderTheme *)theme;
127 - (void)systemColorsDidChange:(NSNotification *)notification;
131 @implementation WebCoreRenderThemeNotificationObserver
133 - (id)initWithTheme:(WebCore::RenderTheme *)theme
135 if (!(self = [super init]))
142 - (void)systemColorsDidChange:(NSNotification *)unusedNotification
144 ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
145 _theme->platformColorsDidChange();
150 @interface NSTextFieldCell (WKDetails)
151 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
155 @interface WebCoreTextFieldCell : NSTextFieldCell
156 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
159 @implementation WebCoreTextFieldCell
160 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
162 // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
163 CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
164 CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
165 return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
169 @interface WebCoreRenderThemeBundle : NSObject
172 @implementation WebCoreRenderThemeBundle
175 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 10100
176 @interface NSSearchFieldCell(Details)
177 @property (getter=isCenteredLook) BOOL centeredLook;
183 using namespace HTMLNames;
199 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
201 static RenderTheme* rt = RenderThemeMac::create().leakRef();
205 PassRefPtr<RenderTheme> RenderThemeMac::create()
207 return adoptRef(new RenderThemeMac);
210 RenderThemeMac::RenderThemeMac()
211 : m_isSliderThumbHorizontalPressed(false)
212 , m_isSliderThumbVerticalPressed(false)
213 , m_notificationObserver(adoptNS([[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]))
215 [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
216 selector:@selector(systemColorsDidChange:)
217 name:NSSystemColorsDidChangeNotification
221 RenderThemeMac::~RenderThemeMac()
223 [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
226 NSView* RenderThemeMac::documentViewFor(const RenderObject& o) const
228 ControlStates states(extractControlStatesForRenderer(o));
229 return ThemeMac::ensuredView(&o.view().frameView(), &states);
233 String RenderThemeMac::mediaControlsStyleSheet()
235 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
236 if (m_mediaControlsStyleSheet.isEmpty())
237 m_mediaControlsStyleSheet = [NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"css"] encoding:NSUTF8StringEncoding error:nil];
238 return m_mediaControlsStyleSheet;
240 return emptyString();
244 String RenderThemeMac::mediaControlsScript()
246 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
247 if (m_mediaControlsScript.isEmpty()) {
248 StringBuilder scriptBuilder;
249 scriptBuilder.append([NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsLocalizedStrings" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]);
250 scriptBuilder.append([NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]);
251 m_mediaControlsScript = scriptBuilder.toString();
253 return m_mediaControlsScript;
255 return emptyString();
259 #endif // ENABLE(VIDEO)
262 #if ENABLE(SERVICE_CONTROLS)
263 String RenderThemeMac::imageControlsStyleSheet() const
265 return String(imageControlsMacUserAgentStyleSheet, sizeof(imageControlsMacUserAgentStyleSheet));
269 Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
271 NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
272 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
275 Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
277 NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
278 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
281 Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const
283 NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
284 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
287 Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const
292 Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const
297 Color RenderThemeMac::platformFocusRingColor() const
299 if (usesTestModeFocusRingColor())
300 return oldAquaFocusRingColor();
302 return systemColor(CSSValueWebkitFocusRingColor);
305 int RenderThemeMac::platformFocusRingMaxWidth() const
307 // FIXME: Shouldn't this function be named platformFocusRingMinWidth? But also, I'm not sure if this function is needed - looks like
308 // all platforms just used 0 for this before <http://trac.webkit.org/changeset/168397>.
312 Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const
314 return platformInactiveSelectionBackgroundColor();
317 static FontWeight toFontWeight(NSInteger appKitFontWeight)
319 ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
320 if (appKitFontWeight > 14)
321 appKitFontWeight = 14;
322 else if (appKitFontWeight < 1)
323 appKitFontWeight = 1;
325 static FontWeight fontWeights[] = {
341 return fontWeights[appKitFontWeight - 1];
344 void RenderThemeMac::systemFont(CSSValueID cssValueId, FontDescription& fontDescription) const
346 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
347 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
348 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
349 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
350 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
351 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
352 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
354 FontDescription* cachedDesc;
356 switch (cssValueId) {
357 case CSSValueSmallCaption:
358 cachedDesc = &smallSystemFont;
359 if (!smallSystemFont.isAbsoluteSize())
360 font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
363 cachedDesc = &menuFont;
364 if (!menuFont.isAbsoluteSize())
365 font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
367 case CSSValueStatusBar:
368 cachedDesc = &labelFont;
369 if (!labelFont.isAbsoluteSize())
370 font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
372 case CSSValueWebkitMiniControl:
373 cachedDesc = &miniControlFont;
374 if (!miniControlFont.isAbsoluteSize())
375 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
377 case CSSValueWebkitSmallControl:
378 cachedDesc = &smallControlFont;
379 if (!smallControlFont.isAbsoluteSize())
380 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
382 case CSSValueWebkitControl:
383 cachedDesc = &controlFont;
384 if (!controlFont.isAbsoluteSize())
385 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
388 cachedDesc = &systemFont;
389 if (!systemFont.isAbsoluteSize())
390 font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
394 NSFontManager *fontManager = [NSFontManager sharedFontManager];
395 cachedDesc->setIsAbsoluteSize(true);
396 cachedDesc->setGenericFamily(FontDescription::NoFamily);
397 cachedDesc->setOneFamily([font webCoreFamilyName]);
398 cachedDesc->setSpecifiedSize([font pointSize]);
399 cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font]));
400 cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
402 fontDescription = *cachedDesc;
405 static RGBA32 convertNSColorToColor(NSColor *color)
407 NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
408 if (colorInColorSpace) {
409 static const double scaleFactor = nextafter(256.0, 0.0);
410 return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
411 static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
412 static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
415 // This conversion above can fail if the NSColor in question is an NSPatternColor
416 // (as many system colors are). These colors are actually a repeating pattern
417 // not just a solid color. To work around this we simply draw a 1x1 image of
418 // the color and use that pixel's color. It might be better to use an average of
419 // the colors in the pattern instead.
420 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
427 colorSpaceName:NSDeviceRGBColorSpace
431 [NSGraphicsContext saveGraphicsState];
432 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
433 NSEraseRect(NSMakeRect(0, 0, 1, 1));
434 [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
435 [NSGraphicsContext restoreGraphicsState];
438 [offscreenRep getPixel:pixel atX:0 y:0];
440 [offscreenRep release];
442 return makeRGB(pixel[0], pixel[1], pixel[2]);
445 static RGBA32 menuBackgroundColor()
447 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
454 colorSpaceName:NSDeviceRGBColorSpace
458 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
459 CGRect rect = CGRectMake(0, 0, 1, 1);
460 HIThemeMenuDrawInfo drawInfo;
461 drawInfo.version = 0;
462 drawInfo.menuType = kThemeMenuTypePopUp;
463 HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
466 [offscreenRep getPixel:pixel atX:0 y:0];
468 [offscreenRep release];
470 return makeRGB(pixel[0], pixel[1], pixel[2]);
473 void RenderThemeMac::platformColorsDidChange()
475 m_systemColorCache.clear();
476 RenderTheme::platformColorsDidChange();
479 Color RenderThemeMac::systemColor(CSSValueID cssValueId) const
482 HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
483 if (it != m_systemColorCache.end())
488 switch (cssValueId) {
489 case CSSValueActiveborder:
490 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
492 case CSSValueActivecaption:
493 color = convertNSColorToColor([NSColor windowFrameTextColor]);
495 case CSSValueAppworkspace:
496 color = convertNSColorToColor([NSColor headerColor]);
498 case CSSValueBackground:
499 // Use theme independent default
501 case CSSValueButtonface:
502 // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
503 // We may want to change this to use the NSColor in future.
506 case CSSValueButtonhighlight:
507 color = convertNSColorToColor([NSColor controlHighlightColor]);
509 case CSSValueButtonshadow:
510 color = convertNSColorToColor([NSColor controlShadowColor]);
512 case CSSValueButtontext:
513 color = convertNSColorToColor([NSColor controlTextColor]);
515 case CSSValueCaptiontext:
516 color = convertNSColorToColor([NSColor textColor]);
518 case CSSValueGraytext:
519 color = convertNSColorToColor([NSColor disabledControlTextColor]);
521 case CSSValueHighlight:
522 color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
524 case CSSValueHighlighttext:
525 color = convertNSColorToColor([NSColor selectedTextColor]);
527 case CSSValueInactiveborder:
528 color = convertNSColorToColor([NSColor controlBackgroundColor]);
530 case CSSValueInactivecaption:
531 color = convertNSColorToColor([NSColor controlBackgroundColor]);
533 case CSSValueInactivecaptiontext:
534 color = convertNSColorToColor([NSColor textColor]);
536 case CSSValueInfobackground:
537 // There is no corresponding NSColor for this so we use a hard coded value.
540 case CSSValueInfotext:
541 color = convertNSColorToColor([NSColor textColor]);
544 color = menuBackgroundColor();
546 case CSSValueMenutext:
547 color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
549 case CSSValueScrollbar:
550 color = convertNSColorToColor([NSColor scrollBarColor]);
553 color = convertNSColorToColor([NSColor textColor]);
555 case CSSValueThreeddarkshadow:
556 color = convertNSColorToColor([NSColor controlDarkShadowColor]);
558 case CSSValueThreedshadow:
559 color = convertNSColorToColor([NSColor shadowColor]);
561 case CSSValueThreedface:
562 // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
563 // We may want to change this to use the NSColor in future.
566 case CSSValueThreedhighlight:
567 color = convertNSColorToColor([NSColor highlightColor]);
569 case CSSValueThreedlightshadow:
570 color = convertNSColorToColor([NSColor controlLightHighlightColor]);
572 case CSSValueWebkitFocusRingColor:
573 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
576 color = convertNSColorToColor([NSColor windowBackgroundColor]);
578 case CSSValueWindowframe:
579 color = convertNSColorToColor([NSColor windowFrameColor]);
581 case CSSValueWindowtext:
582 color = convertNSColorToColor([NSColor windowFrameTextColor]);
588 if (!color.isValid())
589 color = RenderTheme::systemColor(cssValueId);
592 m_systemColorCache.set(cssValueId, color.rgb());
597 bool RenderThemeMac::usesTestModeFocusRingColor() const
599 return WebCore::usesTestModeFocusRingColor();
602 bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border,
603 const FillLayer& background, const Color& backgroundColor) const
605 if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
606 return style->border() != border;
608 // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when
609 // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style
610 // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming
611 // is in effect we treat it like the control is styled.
612 if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f)
615 return RenderTheme::isControlStyled(style, border, background, backgroundColor);
618 static FloatRect inflateRect(const FloatRect& rect, const IntSize& size, const int* margins, float zoomLevel)
620 // Only do the inflation if the available width/height are too small. Otherwise try to
621 // fit the glow/check space into the available box's width/height.
622 int widthDelta = rect.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
623 int heightDelta = rect.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
624 FloatRect result(rect);
625 if (widthDelta < 0) {
626 result.setX(result.x() - margins[leftMargin] * zoomLevel);
627 result.setWidth(result.width() - widthDelta);
629 if (heightDelta < 0) {
630 result.setY(result.y() - margins[topMargin] * zoomLevel);
631 result.setHeight(result.height() - heightDelta);
636 void RenderThemeMac::adjustRepaintRect(const RenderObject& renderer, FloatRect& rect)
638 ControlPart part = renderer.style().appearance();
645 case SquareButtonPart:
646 case DefaultButtonPart:
648 case InnerSpinButtonPart:
649 return RenderTheme::adjustRepaintRect(renderer, rect);
655 float zoomLevel = renderer.style().effectiveZoom();
657 if (part == MenulistPart) {
658 setPopupButtonCellState(renderer, IntSize(rect.size()));
659 IntSize size = popupButtonSizes()[[popupButton() controlSize]];
660 size.setHeight(size.height() * zoomLevel);
661 size.setWidth(rect.width());
662 rect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
666 FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject& inputRenderer, const RenderObject& partRenderer, const FloatRect& inputRect, const IntRect& r) const
668 FloatRect partRect(inputRect);
670 // Compute an offset between the part renderer and the input renderer
671 FloatSize offsetFromInputRenderer;
672 const RenderObject* renderer = &partRenderer;
673 while (renderer && renderer != &inputRenderer) {
674 RenderElement* containingRenderer = renderer->container();
675 offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint()));
676 renderer = containingRenderer;
678 // If the input renderer was not a container, something went wrong
679 ASSERT(renderer == &inputRenderer);
680 // Move the rect into partRenderer's coords
681 partRect.move(offsetFromInputRenderer);
682 // Account for the local drawing offset (tx, ty)
683 partRect.move(r.x(), r.y());
688 void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject& o)
690 bool oldIndeterminate = [cell state] == NSMixedState;
691 bool indeterminate = isIndeterminate(o);
692 bool checked = isChecked(o);
694 if (oldIndeterminate != indeterminate) {
695 [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
699 bool oldChecked = [cell state] == NSOnState;
700 if (checked != oldChecked)
701 [cell setState:checked ? NSOnState : NSOffState];
704 void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject& o)
706 bool oldEnabled = [cell isEnabled];
707 bool enabled = isEnabled(o);
708 if (enabled != oldEnabled)
709 [cell setEnabled:enabled];
712 void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject& o)
714 bool oldFocused = [cell showsFirstResponder];
715 bool focused = isFocused(o) && o.style().outlineStyleIsAuto();
716 if (focused != oldFocused)
717 [cell setShowsFirstResponder:focused];
720 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject& o)
722 bool oldPressed = [cell isHighlighted];
723 bool pressed = o.node() && o.node()->isElementNode() && toElement(o.node())->active();
724 if (pressed != oldPressed)
725 [cell setHighlighted:pressed];
728 bool RenderThemeMac::controlSupportsTints(const RenderObject& o) const
730 // An alternate way to implement this would be to get the appropriate cell object
731 // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
732 // that would be that we would match AppKit behavior more closely, but a disadvantage
733 // would be that we would rely on an AppKit SPI method.
738 // Checkboxes only have tint when checked.
739 if (o.style().appearance() == CheckboxPart)
742 // For now assume other controls have tint if enabled.
746 NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const
748 int fontSize = style->fontSize();
750 return NSRegularControlSize;
752 return NSSmallControlSize;
753 return NSMiniControlSize;
756 NSControlSize RenderThemeMac::controlSizeForCell(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel) const
758 if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel)
759 && minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
760 return NSRegularControlSize;
762 if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel)
763 && minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
764 return NSSmallControlSize;
766 return NSMiniControlSize;
769 void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
771 NSControlSize size = controlSizeForCell(cell, sizes, minSize, zoomLevel);
772 if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
773 [cell setControlSize:size];
776 IntSize RenderThemeMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const
778 if (style->effectiveZoom() != 1.0f) {
779 IntSize result = sizes[controlSizeForFont(style)];
780 return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
782 return sizes[controlSizeForFont(style)];
785 IntSize RenderThemeMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
787 if (style->effectiveZoom() != 1.0f) {
788 IntSize result = sizes[controlSizeForSystemFont(style)];
789 return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
791 return sizes[controlSizeForSystemFont(style)];
794 void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
796 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
797 IntSize size = sizeForFont(style, sizes);
798 if (style->width().isIntrinsicOrAuto() && size.width() > 0)
799 style->setWidth(Length(size.width(), Fixed));
800 if (style->height().isAuto() && size.height() > 0)
801 style->setHeight(Length(size.height(), Fixed));
804 void RenderThemeMac::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const
806 FontDescription fontDescription;
807 fontDescription.setIsAbsoluteSize(true);
808 fontDescription.setGenericFamily(FontDescription::SerifFamily);
810 NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
811 fontDescription.setOneFamily([font webCoreFamilyName]);
812 fontDescription.setComputedSize([font pointSize] * style->effectiveZoom());
813 fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom());
816 style->setLineHeight(RenderStyle::initialLineHeight());
818 if (style->setFontDescription(fontDescription))
819 style->font().update(0);
822 NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle* style) const
824 int fontSize = style->fontSize();
825 if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
826 return NSRegularControlSize;
827 if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
828 return NSSmallControlSize;
829 return NSMiniControlSize;
832 bool RenderThemeMac::paintTextField(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
834 LocalCurrentGraphicsContext localContext(paintInfo.context);
836 NSTextFieldCell *textField = this->textField();
838 GraphicsContextStateSaver stateSaver(*paintInfo.context);
840 [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
841 [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
843 [textField setControlView:nil];
848 void RenderThemeMac::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const
852 bool RenderThemeMac::paintCapsLockIndicator(const RenderObject&, const PaintInfo& paintInfo, const IntRect& r)
854 if (paintInfo.context->paintingDisabled())
857 LocalCurrentGraphicsContext localContext(paintInfo.context);
858 wkDrawCapsLockIndicator(localContext.cgContext(), r);
863 bool RenderThemeMac::paintTextArea(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
865 LocalCurrentGraphicsContext localContext(paintInfo.context);
866 wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
870 void RenderThemeMac::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
874 const int* RenderThemeMac::popupButtonMargins() const
876 static const int margins[3][4] =
882 return margins[[popupButton() controlSize]];
885 const IntSize* RenderThemeMac::popupButtonSizes() const
887 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
891 const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
893 static const int padding[3][4] =
899 return padding[size];
902 bool RenderThemeMac::paintMenuList(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
904 LocalCurrentGraphicsContext localContext(paintInfo.context);
905 setPopupButtonCellState(renderer, IntSize(rect.size()));
907 NSPopUpButtonCell* popupButton = this->popupButton();
909 float zoomLevel = renderer.style().effectiveZoom();
910 IntSize size = popupButtonSizes()[[popupButton controlSize]];
911 size.setHeight(size.height() * zoomLevel);
912 size.setWidth(rect.width());
914 // Now inflate it to account for the shadow.
915 FloatRect inflatedRect = rect;
916 if (rect.width() >= minimumMenuListSize(&renderer.style()))
917 inflatedRect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
919 GraphicsContextStateSaver stateSaver(*paintInfo.context);
921 // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
922 paintInfo.context->clip(inflatedRect);
924 if (zoomLevel != 1.0f) {
925 inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
926 inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
927 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
928 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
929 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
932 NSView *view = documentViewFor(renderer);
933 [popupButton drawWithFrame:inflatedRect inView:view];
934 if (isFocused(renderer) && renderer.style().outlineStyleIsAuto()) {
935 if (wkDrawCellFocusRingWithFrameAtTime(popupButton, inflatedRect, view, std::numeric_limits<double>::max()))
936 renderer.document().page()->focusController().setFocusedElementNeedsRepaint();
939 [popupButton setControlView:nil];
944 #if ENABLE(METER_ELEMENT)
946 IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const
948 if (NoControlPart == renderMeter->style().appearance())
949 return bounds.size();
951 NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
952 // Makes enough room for cell's intrinsic size.
953 NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
954 return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
955 bounds.height() < cellSize.height ? cellSize.height : bounds.height());
958 bool RenderThemeMac::paintMeter(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
960 if (!renderObject.isMeter())
963 LocalCurrentGraphicsContext localContext(paintInfo.context);
965 NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(&renderObject));
966 GraphicsContextStateSaver stateSaver(*paintInfo.context);
968 [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
969 [cell setControlView:nil];
973 bool RenderThemeMac::supportsMeter(ControlPart part) const
976 case RelevancyLevelIndicatorPart:
977 case DiscreteCapacityLevelIndicatorPart:
978 case RatingLevelIndicatorPart:
980 case ContinuousCapacityLevelIndicatorPart:
987 NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
990 case RelevancyLevelIndicatorPart:
991 return NSRelevancyLevelIndicatorStyle;
992 case DiscreteCapacityLevelIndicatorPart:
993 return NSDiscreteCapacityLevelIndicatorStyle;
994 case RatingLevelIndicatorPart:
995 return NSRatingLevelIndicatorStyle;
997 case ContinuousCapacityLevelIndicatorPart:
999 return NSContinuousCapacityLevelIndicatorStyle;
1004 NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* renderMeter) const
1006 const RenderStyle& style = renderMeter->style();
1007 ASSERT(style.appearance() != NoControlPart);
1009 if (!m_levelIndicator)
1010 m_levelIndicator = adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
1011 NSLevelIndicatorCell* cell = m_levelIndicator.get();
1013 HTMLMeterElement* element = renderMeter->meterElement();
1014 double value = element->value();
1016 // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
1017 // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
1018 switch (element->gaugeRegion()) {
1019 case HTMLMeterElement::GaugeRegionOptimum:
1020 // Make meter the green
1021 [cell setWarningValue:value + 1];
1022 [cell setCriticalValue:value + 2];
1024 case HTMLMeterElement::GaugeRegionSuboptimal:
1025 // Make the meter yellow
1026 [cell setWarningValue:value - 1];
1027 [cell setCriticalValue:value + 1];
1029 case HTMLMeterElement::GaugeRegionEvenLessGood:
1030 // Make the meter red
1031 [cell setWarningValue:value - 2];
1032 [cell setCriticalValue:value - 1];
1036 [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style.appearance())];
1037 [cell setBaseWritingDirection:style.isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
1038 [cell setMinValue:element->min()];
1039 [cell setMaxValue:element->max()];
1040 RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
1041 [cell setObjectValue:valueObject.get()];
1048 const IntSize* RenderThemeMac::progressBarSizes() const
1050 static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
1054 const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const
1056 static const int margins[3][4] =
1062 return margins[controlSize];
1065 IntRect RenderThemeMac::progressBarRectForBounds(const RenderObject& renderObject, const IntRect& bounds) const
1067 // Workaround until <rdar://problem/15855086> is fixed.
1068 int maxDimension = static_cast<int>(std::numeric_limits<ushort>::max());
1069 IntRect progressBarBounds(bounds.x(), bounds.y(), std::min(bounds.width(), maxDimension), std::min(bounds.height(), maxDimension));
1070 if (NoControlPart == renderObject.style().appearance())
1071 return progressBarBounds;
1073 float zoomLevel = renderObject.style().effectiveZoom();
1074 NSControlSize controlSize = controlSizeForFont(&renderObject.style());
1075 IntSize size = progressBarSizes()[controlSize];
1076 size.setHeight(size.height() * zoomLevel);
1077 size.setWidth(progressBarBounds.width());
1079 // Now inflate it to account for the shadow.
1080 IntRect inflatedRect = progressBarBounds;
1081 if (progressBarBounds.height() <= minimumProgressBarHeight(&renderObject.style()))
1082 inflatedRect = IntRect(inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel));
1084 return inflatedRect;
1087 int RenderThemeMac::minimumProgressBarHeight(RenderStyle* style) const
1089 return sizeForSystemFont(style, progressBarSizes()).height();
1092 double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
1094 return progressAnimationFrameRate;
1097 double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const
1099 return progressAnimationNumFrames * progressAnimationFrameRate;
1102 void RenderThemeMac::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const
1106 bool RenderThemeMac::paintProgressBar(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1108 if (!renderObject.isProgress())
1111 IntRect inflatedRect = progressBarRectForBounds(renderObject, rect);
1112 NSControlSize controlSize = controlSizeForFont(&renderObject.style());
1114 const RenderProgress& renderProgress = *toRenderProgress(&renderObject);
1115 HIThemeTrackDrawInfo trackInfo;
1116 trackInfo.version = 0;
1117 if (controlSize == NSRegularControlSize)
1118 trackInfo.kind = renderProgress.position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
1120 trackInfo.kind = renderProgress.position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
1122 float deviceScaleFactor = renderObject.document().deviceScaleFactor();
1123 trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
1125 trackInfo.max = std::numeric_limits<SInt32>::max();
1126 trackInfo.value = lround(renderProgress.position() * nextafter(trackInfo.max, 0));
1127 trackInfo.trackInfo.progress.phase = lround(renderProgress.animationProgress() * nextafter(progressAnimationNumFrames, 0) * deviceScaleFactor);
1128 trackInfo.attributes = kThemeTrackHorizontal;
1129 trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
1130 trackInfo.reserved = 0;
1131 trackInfo.filler1 = 0;
1133 std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size(), deviceScaleFactor);
1137 ContextContainer cgContextContainer(imageBuffer->context());
1138 CGContextRef cgContext = cgContextContainer.context();
1139 HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
1141 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1143 if (!renderProgress.style().isLeftToRightDirection()) {
1144 paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
1145 paintInfo.context->scale(FloatSize(-1, 1));
1148 paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location());
1152 const float baseFontSize = 11.0f;
1153 const float baseArrowHeight = 4.0f;
1154 const float baseArrowWidth = 5.0f;
1155 const float baseSpaceBetweenArrows = 2.0f;
1156 const int arrowPaddingLeft = 6;
1157 const int arrowPaddingRight = 6;
1158 const int paddingBeforeSeparator = 4;
1159 const int baseBorderRadius = 5;
1160 const int styledPopupPaddingLeft = 8;
1161 const int styledPopupPaddingTop = 1;
1162 const int styledPopupPaddingBottom = 2;
1164 static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1166 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
1167 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
1168 float a = inData[0];
1170 for (i = 0; i < 4; i++)
1171 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1174 static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1176 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
1177 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
1178 float a = inData[0];
1180 for (i = 0; i < 4; i++)
1181 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1184 static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1186 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1187 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1188 float a = inData[0];
1190 for (i = 0; i < 4; i++)
1191 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1194 static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1196 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1197 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1198 float a = inData[0];
1200 for (i = 0; i < 4; i++)
1201 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1204 void RenderThemeMac::paintMenuListButtonGradients(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1209 ContextContainer cgContextContainer(paintInfo.context);
1210 CGContextRef context = cgContextContainer.context();
1212 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1214 FloatRoundedRect border = FloatRoundedRect(o.style().getRoundedBorderFor(r));
1215 int radius = border.radii().topLeft().width();
1217 CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1219 FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1220 struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1221 RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1222 RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
1224 FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1225 struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1226 RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1227 RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
1229 struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1230 RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1231 RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
1233 RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1235 RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
1238 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1239 CGContextClipToRect(context, r);
1240 paintInfo.context->clipRoundedRect(border);
1241 context = cgContextContainer.context();
1242 CGContextDrawShading(context, mainShading.get());
1246 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1247 CGContextClipToRect(context, topGradient);
1248 paintInfo.context->clipRoundedRect(FloatRoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
1249 context = cgContextContainer.context();
1250 CGContextDrawShading(context, topShading.get());
1253 if (!bottomGradient.isEmpty()) {
1254 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1255 CGContextClipToRect(context, bottomGradient);
1256 paintInfo.context->clipRoundedRect(FloatRoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
1257 context = cgContextContainer.context();
1258 CGContextDrawShading(context, bottomShading.get());
1262 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1263 CGContextClipToRect(context, r);
1264 paintInfo.context->clipRoundedRect(border);
1265 context = cgContextContainer.context();
1266 CGContextDrawShading(context, leftShading.get());
1267 CGContextDrawShading(context, rightShading.get());
1271 bool RenderThemeMac::paintMenuListButtonDecorations(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
1273 IntRect bounds = IntRect(rect.x() + renderer.style().borderLeftWidth(),
1274 rect.y() + renderer.style().borderTopWidth(),
1275 rect.width() - renderer.style().borderLeftWidth() - renderer.style().borderRightWidth(),
1276 rect.height() - renderer.style().borderTopWidth() - renderer.style().borderBottomWidth());
1277 // Draw the gradients to give the styled popup menu a button appearance
1278 paintMenuListButtonGradients(renderer, paintInfo, bounds);
1280 // 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
1281 float fontScale = std::min(renderer.style().fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1282 float centerY = bounds.y() + bounds.height() / 2.0f;
1283 float arrowHeight = baseArrowHeight * fontScale;
1284 float arrowWidth = baseArrowWidth * fontScale;
1285 float leftEdge = bounds.maxX() - arrowPaddingRight * renderer.style().effectiveZoom() - arrowWidth;
1286 float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1288 if (bounds.width() < arrowWidth + arrowPaddingLeft * renderer.style().effectiveZoom())
1291 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1293 paintInfo.context->setFillColor(renderer.style().visitedDependentColor(CSSPropertyColor), renderer.style().colorSpace());
1294 paintInfo.context->setStrokeStyle(NoStroke);
1296 FloatPoint arrow1[3];
1297 arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1298 arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1299 arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1301 // Draw the top arrow
1302 paintInfo.context->drawConvexPolygon(3, arrow1, true);
1304 FloatPoint arrow2[3];
1305 arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1306 arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1307 arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1309 // Draw the bottom arrow
1310 paintInfo.context->drawConvexPolygon(3, arrow2, true);
1312 Color leftSeparatorColor(0, 0, 0, 40);
1313 Color rightSeparatorColor(255, 255, 255, 40);
1315 // FIXME: Should the separator thickness and space be scaled up by fontScale?
1316 int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1317 int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * renderer.style().effectiveZoom()); // FIXME: Round?
1319 // Draw the separator to the left of the arrows
1320 paintInfo.context->setStrokeThickness(1); // Deliberately ignores zoom since it looks nicer if it stays thin.
1321 paintInfo.context->setStrokeStyle(SolidStroke);
1322 paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
1323 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1324 IntPoint(leftEdgeOfSeparator, bounds.maxY()));
1326 paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
1327 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1328 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
1332 static const IntSize* menuListButtonSizes()
1334 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1338 void RenderThemeMac::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
1340 NSControlSize controlSize = controlSizeForFont(style);
1342 style->resetBorder();
1343 style->resetPadding();
1345 // Height is locked to auto.
1346 style->setHeight(Length(Auto));
1348 // White-space is locked to pre
1349 style->setWhiteSpace(PRE);
1351 // Set the foreground color to black or gray when we have the aqua look.
1352 // Cast to RGB32 is to work around a compiler bug.
1353 style->setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1355 // Set the button's vertical size.
1356 setSizeFromFont(style, menuListButtonSizes());
1358 // 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
1359 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1360 // system font for the control size instead.
1361 setFontFromControlSize(styleResolver, style, controlSize);
1363 style->setBoxShadow(nullptr);
1366 int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const
1368 if (style->appearance() == MenulistPart)
1369 return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
1370 if (style->appearance() == MenulistButtonPart)
1371 return styledPopupPaddingLeft * style->effectiveZoom();
1375 int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const
1377 if (style->appearance() == MenulistPart)
1378 return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
1379 if (style->appearance() == MenulistButtonPart) {
1380 float fontScale = style->fontSize() / baseFontSize;
1381 float arrowWidth = baseArrowWidth * fontScale;
1382 return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
1387 int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const
1389 if (style->appearance() == MenulistPart)
1390 return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
1391 if (style->appearance() == MenulistButtonPart)
1392 return styledPopupPaddingTop * style->effectiveZoom();
1396 int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const
1398 if (style->appearance() == MenulistPart)
1399 return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
1400 if (style->appearance() == MenulistButtonPart)
1401 return styledPopupPaddingBottom * style->effectiveZoom();
1405 PopupMenuStyle::PopupMenuSize RenderThemeMac::popupMenuSize(const RenderStyle* style, IntRect& rect) const
1407 NSPopUpButtonCell* popupButton = this->popupButton();
1408 NSControlSize size = controlSizeForCell(popupButton, popupButtonSizes(), rect.size(), style->effectiveZoom());
1410 case NSRegularControlSize:
1411 return PopupMenuStyle::PopupMenuSizeNormal;
1412 case NSSmallControlSize:
1413 return PopupMenuStyle::PopupMenuSizeSmall;
1414 case NSMiniControlSize:
1415 return PopupMenuStyle::PopupMenuSizeMini;
1417 return PopupMenuStyle::PopupMenuSizeNormal;
1421 void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver&, RenderStyle& style, Element&) const
1423 float fontScale = style.fontSize() / baseFontSize;
1425 style.resetPadding();
1426 style.setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1428 const int minHeight = 15;
1429 style.setMinHeight(Length(minHeight, Fixed));
1431 style.setLineHeight(RenderStyle::initialLineHeight());
1434 void RenderThemeMac::setPopupButtonCellState(const RenderObject& o, const IntSize& buttonSize)
1436 NSPopUpButtonCell* popupButton = this->popupButton();
1438 // Set the control size based off the rectangle we're painting into.
1439 setControlSize(popupButton, popupButtonSizes(), buttonSize, o.style().effectiveZoom());
1441 // Update the various states we respond to.
1442 updateCheckedState(popupButton, o);
1443 updateEnabledState(popupButton, o);
1444 updatePressedState(popupButton, o);
1447 const IntSize* RenderThemeMac::menuListSizes() const
1449 static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1453 int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const
1455 return sizeForSystemFont(style, menuListSizes()).width();
1458 const int trackWidth = 5;
1459 const int trackRadius = 2;
1461 void RenderThemeMac::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
1463 style->setBoxShadow(nullptr);
1466 bool RenderThemeMac::paintSliderTrack(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1469 float zoomLevel = o.style().effectiveZoom();
1470 float zoomedTrackWidth = trackWidth * zoomLevel;
1472 if (o.style().appearance() == SliderHorizontalPart || o.style().appearance() == MediaSliderPart) {
1473 bounds.setHeight(zoomedTrackWidth);
1474 bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1475 } else if (o.style().appearance() == SliderVerticalPart) {
1476 bounds.setWidth(zoomedTrackWidth);
1477 bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1480 LocalCurrentGraphicsContext localContext(paintInfo.context);
1481 CGContextRef context = localContext.cgContext();
1482 CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1484 #if ENABLE(DATALIST_ELEMENT)
1485 paintSliderTicks(o, paintInfo, r);
1488 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1489 CGContextClipToRect(context, bounds);
1491 struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1492 RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1493 RetainPtr<CGShadingRef> mainShading;
1494 if (o.style().appearance() == SliderVerticalPart)
1495 mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
1497 mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
1499 IntSize radius(trackRadius, trackRadius);
1500 paintInfo.context->clipRoundedRect(FloatRoundedRect(bounds, radius, radius, radius, radius));
1501 context = localContext.cgContext();
1502 CGContextDrawShading(context, mainShading.get());
1507 void RenderThemeMac::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
1509 RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
1510 style->setBoxShadow(nullptr);
1513 const float verticalSliderHeightPadding = 0.1f;
1515 bool RenderThemeMac::paintSliderThumb(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1517 NSSliderCell* sliderThumbCell = o.style().appearance() == SliderThumbVerticalPart
1518 ? sliderThumbVertical()
1519 : sliderThumbHorizontal();
1521 LocalCurrentGraphicsContext localContext(paintInfo.context);
1523 // Update the various states we respond to.
1524 updateEnabledState(sliderThumbCell, o);
1525 Element* focusDelegate = (o.node() && o.node()->isElementNode()) ? toElement(o.node())->focusDelegate() : 0;
1527 updateFocusedState(sliderThumbCell, *focusDelegate->renderer());
1529 // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1531 if (o.style().appearance() == SliderThumbVerticalPart)
1532 oldPressed = m_isSliderThumbVerticalPressed;
1534 oldPressed = m_isSliderThumbHorizontalPressed;
1536 bool pressed = isPressed(o);
1538 if (o.style().appearance() == SliderThumbVerticalPart)
1539 m_isSliderThumbVerticalPressed = pressed;
1541 m_isSliderThumbHorizontalPressed = pressed;
1543 if (pressed != oldPressed) {
1545 [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1547 [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1550 FloatRect bounds = r;
1551 // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1552 if (o.style().appearance() == SliderThumbVerticalPart)
1553 bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o.style().effectiveZoom());
1555 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1556 float zoomLevel = o.style().effectiveZoom();
1558 FloatRect unzoomedRect = bounds;
1559 if (zoomLevel != 1.0f) {
1560 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1561 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1562 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1563 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1564 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1567 [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
1568 [sliderThumbCell setControlView:nil];
1573 bool RenderThemeMac::paintSearchField(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1575 LocalCurrentGraphicsContext localContext(paintInfo.context);
1576 NSSearchFieldCell* search = this->search();
1578 setSearchCellState(o, r);
1580 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1582 float zoomLevel = o.style().effectiveZoom();
1584 IntRect unzoomedRect = r;
1586 if (zoomLevel != 1.0f) {
1587 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1588 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1589 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1590 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1591 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1594 // Set the search button to nil before drawing. Then reset it so we can draw it later.
1595 [search setSearchButtonCell:nil];
1597 [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1599 [search setControlView:nil];
1600 [search resetSearchButtonCell];
1605 void RenderThemeMac::setSearchCellState(const RenderObject& o, const IntRect&)
1607 NSSearchFieldCell* search = this->search();
1609 [search setControlSize:controlSizeForFont(&o.style())];
1611 // Update the various states we respond to.
1612 updateEnabledState(search, o);
1613 updateFocusedState(search, o);
1616 const IntSize* RenderThemeMac::searchFieldSizes() const
1618 static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1622 void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const
1624 // If the width and height are both specified, then we have nothing to do.
1625 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
1628 // Use the font size to determine the intrinsic width of the control.
1629 setSizeFromFont(style, searchFieldSizes());
1632 void RenderThemeMac::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const
1635 style->resetBorder();
1636 const short borderWidth = 2 * style->effectiveZoom();
1637 style->setBorderLeftWidth(borderWidth);
1638 style->setBorderLeftStyle(INSET);
1639 style->setBorderRightWidth(borderWidth);
1640 style->setBorderRightStyle(INSET);
1641 style->setBorderBottomWidth(borderWidth);
1642 style->setBorderBottomStyle(INSET);
1643 style->setBorderTopWidth(borderWidth);
1644 style->setBorderTopStyle(INSET);
1647 style->setHeight(Length(Auto));
1648 setSearchFieldSize(style);
1650 // Override padding size to match AppKit text positioning.
1651 const int padding = 1 * style->effectiveZoom();
1652 style->setPaddingLeft(Length(padding, Fixed));
1653 style->setPaddingRight(Length(padding, Fixed));
1654 style->setPaddingTop(Length(padding, Fixed));
1655 style->setPaddingBottom(Length(padding, Fixed));
1657 NSControlSize controlSize = controlSizeForFont(style);
1658 setFontFromControlSize(styleResolver, style, controlSize);
1660 style->setBoxShadow(nullptr);
1663 bool RenderThemeMac::paintSearchFieldCancelButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1665 Element* input = o.node()->shadowHost();
1667 input = toElement(o.node());
1669 if (!input->renderer()->isBox())
1672 LocalCurrentGraphicsContext localContext(paintInfo.context);
1673 setSearchCellState(*input->renderer(), r);
1675 NSSearchFieldCell* search = this->search();
1677 if (!input->isDisabledFormControl() && (input->isTextFormControl() && !toHTMLTextFormControlElement(input)->isReadOnly()))
1678 updatePressedState([search cancelButtonCell], o);
1679 else if ([[search cancelButtonCell] isHighlighted])
1680 [[search cancelButtonCell] setHighlighted:NO];
1682 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1684 float zoomLevel = o.style().effectiveZoom();
1686 FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1688 #if ENABLE(INPUT_SPEECH)
1689 // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g.
1690 // when speech input is enabled for the input element.
1691 IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect();
1692 int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight();
1693 int spaceToRightOfCancelButton = absRight - (r.x() + r.width());
1694 localBounds.setX(localBounds.x() - spaceToRightOfCancelButton);
1697 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1699 FloatRect unzoomedRect(localBounds);
1700 if (zoomLevel != 1.0f) {
1701 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1702 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1703 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1704 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1705 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1708 [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1709 [[search cancelButtonCell] setControlView:nil];
1713 const IntSize* RenderThemeMac::cancelButtonSizes() const
1715 static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1719 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1721 IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1722 style->setWidth(Length(size.width(), Fixed));
1723 style->setHeight(Length(size.height(), Fixed));
1724 style->setBoxShadow(nullptr);
1727 const IntSize* RenderThemeMac::resultsButtonSizes() const
1729 static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1733 const int emptyResultsOffset = 9;
1734 void RenderThemeMac::adjustSearchFieldDecorationPartStyle(StyleResolver*, RenderStyle* style, Element*) const
1736 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1737 style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1738 style->setHeight(Length(size.height(), Fixed));
1739 style->setBoxShadow(nullptr);
1742 bool RenderThemeMac::paintSearchFieldDecorationPart(const RenderObject&, const PaintInfo&, const IntRect&)
1747 void RenderThemeMac::adjustSearchFieldResultsDecorationPartStyle(StyleResolver*, RenderStyle* style, Element*) const
1749 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1750 style->setWidth(Length(size.width(), Fixed));
1751 style->setHeight(Length(size.height(), Fixed));
1752 style->setBoxShadow(nullptr);
1755 bool RenderThemeMac::paintSearchFieldResultsDecorationPart(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1757 Node* input = o.node()->shadowHost();
1760 if (!input->renderer()->isBox())
1763 LocalCurrentGraphicsContext localContext(paintInfo.context);
1764 setSearchCellState(*input->renderer(), r);
1766 NSSearchFieldCell* search = this->search();
1768 if ([search searchMenuTemplate] != nil)
1769 [search setSearchMenuTemplate:nil];
1771 FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1772 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1774 [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
1775 [[search searchButtonCell] setControlView:nil];
1779 const int resultsArrowWidth = 5;
1780 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
1782 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1783 style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1784 style->setHeight(Length(size.height(), Fixed));
1785 style->setBoxShadow(nullptr);
1788 bool RenderThemeMac::paintSearchFieldResultsButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1790 Node* input = o.node()->shadowHost();
1793 if (!input->renderer()->isBox())
1796 LocalCurrentGraphicsContext localContext(paintInfo.context);
1797 setSearchCellState(*input->renderer(), r);
1799 NSSearchFieldCell* search = this->search();
1801 if (![search searchMenuTemplate])
1802 [search setSearchMenuTemplate:searchMenuTemplate()];
1804 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1805 float zoomLevel = o.style().effectiveZoom();
1807 FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1808 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1810 IntRect unzoomedRect(localBounds);
1811 if (zoomLevel != 1.0f) {
1812 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1813 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1814 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1815 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1816 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1819 [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1820 [[search searchButtonCell] setControlView:nil];
1825 bool RenderThemeMac::paintSnapshottedPluginOverlay(const RenderObject& o, const PaintInfo& paintInfo, const IntRect&)
1827 if (paintInfo.phase != PaintPhaseBlockBackground)
1830 if (!o.isRenderBlock())
1833 const RenderBlock& renderBlock = *toRenderBlock(&o);
1835 LayoutUnit contentWidth = renderBlock.contentWidth();
1836 LayoutUnit contentHeight = renderBlock.contentHeight();
1837 if (!contentWidth || !contentHeight)
1840 GraphicsContext* context = paintInfo.context;
1842 LayoutSize contentSize(contentWidth, contentHeight);
1843 LayoutPoint contentLocation = renderBlock.location();
1844 contentLocation.move(renderBlock.borderLeft() + renderBlock.paddingLeft(), renderBlock.borderTop() + renderBlock.paddingTop());
1846 LayoutRect rect(contentLocation, contentSize);
1847 IntRect alignedRect = pixelSnappedIntRect(rect);
1848 if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
1851 // We need to get the snapshot image from the plugin element, which should be available
1852 // from our node. Assuming this node is the plugin overlay element, we should get to the
1853 // plugin itself by asking for the shadow root parent, and then its parent.
1855 if (!renderBlock.element()->isHTMLElement())
1858 HTMLElement* plugInOverlay = toHTMLElement(renderBlock.element());
1859 Element* parent = plugInOverlay->parentOrShadowHostElement();
1860 while (parent && !parent->isPluginElement())
1861 parent = parent->parentOrShadowHostElement();
1866 HTMLPlugInElement* plugInElement = toHTMLPlugInElement(parent);
1867 if (!plugInElement->isPlugInImageElement())
1870 HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(plugInElement);
1872 Image* snapshot = plugInImageElement->snapshotImage();
1876 RenderSnapshottedPlugIn* plugInRenderer = toRenderSnapshottedPlugIn(plugInImageElement->renderer());
1877 FloatPoint snapshotAbsPos = plugInRenderer->localToAbsolute();
1878 snapshotAbsPos.move(plugInRenderer->borderLeft() + plugInRenderer->paddingLeft(), plugInRenderer->borderTop() + plugInRenderer->paddingTop());
1880 // We could draw the snapshot with that coordinates, but we need to make sure there
1881 // isn't a composited layer between us and the plugInRenderer.
1882 const RenderBox* renderBox = toRenderBox(&o);
1883 while (renderBox != plugInRenderer) {
1884 if (renderBox->hasLayer() && renderBox->layer() && renderBox->layer()->isComposited()) {
1885 snapshotAbsPos = -renderBox->location();
1888 renderBox = renderBox->parentBox();
1891 LayoutSize pluginSize(plugInRenderer->contentWidth(), plugInRenderer->contentHeight());
1892 LayoutRect pluginRect(snapshotAbsPos, pluginSize);
1893 IntRect alignedPluginRect = pixelSnappedIntRect(pluginRect);
1895 if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
1898 context->drawImage(snapshot, plugInRenderer->style().colorSpace(), alignedPluginRect, CompositeSourceOver);
1902 #if ENABLE(DATALIST_ELEMENT)
1903 IntSize RenderThemeMac::sliderTickSize() const
1905 return IntSize(1, 3);
1908 int RenderThemeMac::sliderTickOffsetFromTrackCenter() const
1914 const int sliderThumbWidth = 15;
1915 const int sliderThumbHeight = 15;
1917 void RenderThemeMac::adjustSliderThumbSize(RenderStyle* style, Element*) const
1919 float zoomLevel = style->effectiveZoom();
1920 if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
1921 style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1922 style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1926 bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const
1931 NSPopUpButtonCell* RenderThemeMac::popupButton() const
1933 if (!m_popupButton) {
1934 m_popupButton = adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
1935 [m_popupButton.get() setUsesItemFromMenu:NO];
1936 [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
1939 return m_popupButton.get();
1942 NSSearchFieldCell* RenderThemeMac::search() const
1945 m_search = adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
1946 [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
1947 [m_search.get() setBezeled:YES];
1948 [m_search.get() setEditable:YES];
1949 [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
1950 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 10100
1951 [m_search.get() setCenteredLook:NO];
1955 return m_search.get();
1958 NSMenu* RenderThemeMac::searchMenuTemplate() const
1960 if (!m_searchMenuTemplate)
1961 m_searchMenuTemplate = adoptNS([[NSMenu alloc] initWithTitle:@""]);
1963 return m_searchMenuTemplate.get();
1966 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
1968 if (!m_sliderThumbHorizontal) {
1969 m_sliderThumbHorizontal = adoptNS([[NSSliderCell alloc] init]);
1970 [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
1971 [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
1972 [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
1975 return m_sliderThumbHorizontal.get();
1978 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
1980 if (!m_sliderThumbVertical) {
1981 m_sliderThumbVertical = adoptNS([[NSSliderCell alloc] init]);
1982 [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
1983 [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
1984 [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
1987 return m_sliderThumbVertical.get();
1990 NSTextFieldCell* RenderThemeMac::textField() const
1993 m_textField = adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
1994 [m_textField.get() setBezeled:YES];
1995 [m_textField.get() setEditable:YES];
1996 [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
1997 // Post-Lion, WebCore can be in charge of paintinng the background thanks to
1998 // the workaround in place for <rdar://problem/11385461>, which is implemented
1999 // above as _coreUIDrawOptionsWithFrame.
2000 [m_textField.get() setDrawsBackground:NO];
2003 return m_textField.get();
2006 String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
2011 String strToTruncate;
2012 if (fileList->isEmpty())
2013 strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
2014 else if (fileList->length() == 1)
2015 strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
2017 return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
2019 return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
2022 #if ENABLE(SERVICE_CONTROLS)
2023 NSServicesRolloverButtonCell* RenderThemeMac::servicesRolloverButtonCell() const
2025 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2026 if (!m_servicesRolloverButton) {
2027 m_servicesRolloverButton = [NSServicesRolloverButtonCell serviceRolloverButtonCellForStyle:NSSharingServicePickerStyleRollover];
2028 [m_servicesRolloverButton setBezelStyle:NSRoundedDisclosureBezelStyle];
2029 [m_servicesRolloverButton setButtonType:NSPushOnPushOffButton];
2030 [m_servicesRolloverButton setImagePosition:NSImageOnly];
2031 [m_servicesRolloverButton setState:NO];
2034 return m_servicesRolloverButton.get();
2040 bool RenderThemeMac::paintImageControlsButton(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect& rect)
2042 if (paintInfo.phase != PaintPhaseBlockBackground)
2045 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2046 NSServicesRolloverButtonCell *cell = servicesRolloverButtonCell();
2048 LocalCurrentGraphicsContext localContext(paintInfo.context);
2049 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2051 paintInfo.context->translate(rect.x(), rect.y());
2053 IntRect innerFrame(IntPoint(), rect.size());
2054 [cell drawWithFrame:innerFrame inView:documentViewFor(renderer)];
2055 [cell setControlView:nil];
2057 UNUSED_PARAM(renderer);
2064 IntSize RenderThemeMac::imageControlsButtonSize(const RenderObject&) const
2066 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2067 return IntSize(servicesRolloverButtonCell().cellSize);
2073 IntSize RenderThemeMac::imageControlsButtonPositionOffset() const
2075 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2076 // FIXME: Currently the offsets will always be the same no matter what image rect you try with.
2077 // This may not always be true in the future.
2078 static const int dummyDimension = 100;
2079 IntRect dummyImageRect(0, 0, dummyDimension, dummyDimension);
2080 NSRect bounds = [servicesRolloverButtonCell() rectForBounds:dummyImageRect preferredEdge:NSMinYEdge];
2082 return IntSize(dummyDimension - bounds.origin.x, bounds.origin.y);
2089 } // namespace WebCore
2091 #endif // !PLATFORM(IOS)