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/NSSharingService_Private.h>)
93 #import <AppKit/NSSharingService_Private.h>
96 NSSharingServicePickerStyleRollover = 1
97 } NSSharingServicePickerStyle;
100 #if __has_include(<AppKit/NSServicesRolloverButtonCell.h>)
101 #import <AppKit/NSServicesRolloverButtonCell.h>
103 @interface NSServicesRolloverButtonCell : NSButtonCell
107 @interface NSServicesRolloverButtonCell (Details)
108 + (NSServicesRolloverButtonCell *)serviceRolloverButtonCellForStyle:(NSSharingServicePickerStyle)style;
109 - (NSRect)rectForBounds:(NSRect)bounds preferredEdge:(NSRectEdge)preferredEdge;
112 #endif // ENABLE(SERVICE_CONTROLS)
114 // The methods in this file are specific to the Mac OS X platform.
116 // FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
118 // We estimate the animation rate of a Mac OS X progress bar is 33 fps.
119 // Hard code the value here because we haven't found API for it.
120 const double progressAnimationFrameRate = 0.033;
122 // Mac OS X progress bar animation seems to have 256 frames.
123 const double progressAnimationNumFrames = 256;
125 @interface WebCoreRenderThemeNotificationObserver : NSObject
127 WebCore::RenderTheme *_theme;
130 - (id)initWithTheme:(WebCore::RenderTheme *)theme;
131 - (void)systemColorsDidChange:(NSNotification *)notification;
135 @implementation WebCoreRenderThemeNotificationObserver
137 - (id)initWithTheme:(WebCore::RenderTheme *)theme
139 if (!(self = [super init]))
146 - (void)systemColorsDidChange:(NSNotification *)unusedNotification
148 ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
149 _theme->platformColorsDidChange();
154 @interface NSTextFieldCell (WKDetails)
155 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
159 @interface WebCoreTextFieldCell : NSTextFieldCell
160 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
163 @implementation WebCoreTextFieldCell
164 - (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
166 // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
167 CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
168 CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
169 return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
173 @interface WebCoreRenderThemeBundle : NSObject
176 @implementation WebCoreRenderThemeBundle
179 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
180 @interface NSSearchFieldCell(Details)
181 @property (getter=isCenteredLook) BOOL centeredLook;
187 using namespace HTMLNames;
203 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
205 static RenderTheme* rt = RenderThemeMac::create().leakRef();
209 PassRefPtr<RenderTheme> RenderThemeMac::create()
211 return adoptRef(new RenderThemeMac);
214 RenderThemeMac::RenderThemeMac()
215 : m_isSliderThumbHorizontalPressed(false)
216 , m_isSliderThumbVerticalPressed(false)
217 , m_notificationObserver(adoptNS([[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]))
219 [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
220 selector:@selector(systemColorsDidChange:)
221 name:NSSystemColorsDidChangeNotification
225 RenderThemeMac::~RenderThemeMac()
227 [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
230 NSView* RenderThemeMac::documentViewFor(const RenderObject& o) const
232 ControlStates states(extractControlStatesForRenderer(o));
233 return ThemeMac::ensuredView(&o.view().frameView(), &states);
237 String RenderThemeMac::mediaControlsStyleSheet()
239 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
240 if (m_mediaControlsStyleSheet.isEmpty())
241 m_mediaControlsStyleSheet = [NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"css"] encoding:NSUTF8StringEncoding error:nil];
242 return m_mediaControlsStyleSheet;
244 return emptyString();
248 String RenderThemeMac::mediaControlsScript()
250 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
251 if (m_mediaControlsScript.isEmpty()) {
252 StringBuilder scriptBuilder;
253 scriptBuilder.append([NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsLocalizedStrings" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]);
254 scriptBuilder.append([NSString stringWithContentsOfFile:[[NSBundle bundleForClass:[WebCoreRenderThemeBundle class]] pathForResource:@"mediaControlsApple" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]);
255 m_mediaControlsScript = scriptBuilder.toString();
257 return m_mediaControlsScript;
259 return emptyString();
263 #endif // ENABLE(VIDEO)
266 #if ENABLE(SERVICE_CONTROLS)
267 String RenderThemeMac::imageControlsStyleSheet() const
269 return String(imageControlsMacUserAgentStyleSheet, sizeof(imageControlsMacUserAgentStyleSheet));
273 Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
275 NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
276 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
279 Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
281 NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
282 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
285 Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const
287 NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
288 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
291 Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const
296 Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const
301 Color RenderThemeMac::platformFocusRingColor() const
303 if (usesTestModeFocusRingColor())
304 return oldAquaFocusRingColor();
306 return systemColor(CSSValueWebkitFocusRingColor);
309 int RenderThemeMac::platformFocusRingMaxWidth() const
311 // FIXME: Shouldn't this function be named platformFocusRingMinWidth? But also, I'm not sure if this function is needed - looks like
312 // all platforms just used 0 for this before <http://trac.webkit.org/changeset/168397>.
316 Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const
318 return platformInactiveSelectionBackgroundColor();
321 static FontWeight toFontWeight(NSInteger appKitFontWeight)
323 ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
324 if (appKitFontWeight > 14)
325 appKitFontWeight = 14;
326 else if (appKitFontWeight < 1)
327 appKitFontWeight = 1;
329 static FontWeight fontWeights[] = {
345 return fontWeights[appKitFontWeight - 1];
348 void RenderThemeMac::systemFont(CSSValueID cssValueId, FontDescription& fontDescription) const
350 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
351 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
352 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
353 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
354 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
355 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
356 DEPRECATED_DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
358 FontDescription* cachedDesc;
360 switch (cssValueId) {
361 case CSSValueSmallCaption:
362 cachedDesc = &smallSystemFont;
363 if (!smallSystemFont.isAbsoluteSize())
364 font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
367 cachedDesc = &menuFont;
368 if (!menuFont.isAbsoluteSize())
369 font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
371 case CSSValueStatusBar:
372 cachedDesc = &labelFont;
373 if (!labelFont.isAbsoluteSize())
374 font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
376 case CSSValueWebkitMiniControl:
377 cachedDesc = &miniControlFont;
378 if (!miniControlFont.isAbsoluteSize())
379 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
381 case CSSValueWebkitSmallControl:
382 cachedDesc = &smallControlFont;
383 if (!smallControlFont.isAbsoluteSize())
384 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
386 case CSSValueWebkitControl:
387 cachedDesc = &controlFont;
388 if (!controlFont.isAbsoluteSize())
389 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
392 cachedDesc = &systemFont;
393 if (!systemFont.isAbsoluteSize())
394 font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
398 NSFontManager *fontManager = [NSFontManager sharedFontManager];
399 cachedDesc->setIsAbsoluteSize(true);
400 cachedDesc->setGenericFamily(FontDescription::NoFamily);
401 cachedDesc->setOneFamily([font webCoreFamilyName]);
402 cachedDesc->setSpecifiedSize([font pointSize]);
403 cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font]));
404 cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
406 fontDescription = *cachedDesc;
409 static RGBA32 convertNSColorToColor(NSColor *color)
411 NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
412 if (colorInColorSpace) {
413 static const double scaleFactor = nextafter(256.0, 0.0);
414 return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
415 static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
416 static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
419 // This conversion above can fail if the NSColor in question is an NSPatternColor
420 // (as many system colors are). These colors are actually a repeating pattern
421 // not just a solid color. To work around this we simply draw a 1x1 image of
422 // the color and use that pixel's color. It might be better to use an average of
423 // the colors in the pattern instead.
424 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
431 colorSpaceName:NSDeviceRGBColorSpace
435 [NSGraphicsContext saveGraphicsState];
436 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
437 NSEraseRect(NSMakeRect(0, 0, 1, 1));
438 [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
439 [NSGraphicsContext restoreGraphicsState];
442 [offscreenRep getPixel:pixel atX:0 y:0];
444 [offscreenRep release];
446 return makeRGB(pixel[0], pixel[1], pixel[2]);
449 static RGBA32 menuBackgroundColor()
451 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
458 colorSpaceName:NSDeviceRGBColorSpace
462 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
463 CGRect rect = CGRectMake(0, 0, 1, 1);
464 HIThemeMenuDrawInfo drawInfo;
465 drawInfo.version = 0;
466 drawInfo.menuType = kThemeMenuTypePopUp;
467 HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
470 [offscreenRep getPixel:pixel atX:0 y:0];
472 [offscreenRep release];
474 return makeRGB(pixel[0], pixel[1], pixel[2]);
477 void RenderThemeMac::platformColorsDidChange()
479 m_systemColorCache.clear();
480 RenderTheme::platformColorsDidChange();
483 Color RenderThemeMac::systemColor(CSSValueID cssValueId) const
486 HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
487 if (it != m_systemColorCache.end())
492 switch (cssValueId) {
493 case CSSValueActiveborder:
494 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
496 case CSSValueActivecaption:
497 color = convertNSColorToColor([NSColor windowFrameTextColor]);
499 case CSSValueAppworkspace:
500 color = convertNSColorToColor([NSColor headerColor]);
502 case CSSValueBackground:
503 // Use theme independent default
505 case CSSValueButtonface:
506 // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
507 // We may want to change this to use the NSColor in future.
510 case CSSValueButtonhighlight:
511 color = convertNSColorToColor([NSColor controlHighlightColor]);
513 case CSSValueButtonshadow:
514 color = convertNSColorToColor([NSColor controlShadowColor]);
516 case CSSValueButtontext:
517 color = convertNSColorToColor([NSColor controlTextColor]);
519 case CSSValueActivebuttontext:
520 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
524 case CSSValueCaptiontext:
525 color = convertNSColorToColor([NSColor textColor]);
527 case CSSValueGraytext:
528 color = convertNSColorToColor([NSColor disabledControlTextColor]);
530 case CSSValueHighlight:
531 color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
533 case CSSValueHighlighttext:
534 color = convertNSColorToColor([NSColor selectedTextColor]);
536 case CSSValueInactiveborder:
537 color = convertNSColorToColor([NSColor controlBackgroundColor]);
539 case CSSValueInactivecaption:
540 color = convertNSColorToColor([NSColor controlBackgroundColor]);
542 case CSSValueInactivecaptiontext:
543 color = convertNSColorToColor([NSColor textColor]);
545 case CSSValueInfobackground:
546 // There is no corresponding NSColor for this so we use a hard coded value.
549 case CSSValueInfotext:
550 color = convertNSColorToColor([NSColor textColor]);
553 color = menuBackgroundColor();
555 case CSSValueMenutext:
556 color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
558 case CSSValueScrollbar:
559 color = convertNSColorToColor([NSColor scrollBarColor]);
562 color = convertNSColorToColor([NSColor textColor]);
564 case CSSValueThreeddarkshadow:
565 color = convertNSColorToColor([NSColor controlDarkShadowColor]);
567 case CSSValueThreedshadow:
568 color = convertNSColorToColor([NSColor shadowColor]);
570 case CSSValueThreedface:
571 // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
572 // We may want to change this to use the NSColor in future.
575 case CSSValueThreedhighlight:
576 color = convertNSColorToColor([NSColor highlightColor]);
578 case CSSValueThreedlightshadow:
579 color = convertNSColorToColor([NSColor controlLightHighlightColor]);
581 case CSSValueWebkitFocusRingColor:
582 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
585 color = convertNSColorToColor([NSColor windowBackgroundColor]);
587 case CSSValueWindowframe:
588 color = convertNSColorToColor([NSColor windowFrameColor]);
590 case CSSValueWindowtext:
591 color = convertNSColorToColor([NSColor windowFrameTextColor]);
597 if (!color.isValid())
598 color = RenderTheme::systemColor(cssValueId);
601 m_systemColorCache.set(cssValueId, color.rgb());
606 bool RenderThemeMac::usesTestModeFocusRingColor() const
608 return WebCore::usesTestModeFocusRingColor();
611 bool RenderThemeMac::isControlStyled(const RenderStyle& style, const BorderData& border,
612 const FillLayer& background, const Color& backgroundColor) const
614 if (style.appearance() == TextFieldPart || style.appearance() == TextAreaPart || style.appearance() == ListboxPart)
615 return style.border() != border;
617 // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when
618 // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style
619 // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming
620 // is in effect we treat it like the control is styled.
621 if (style.appearance() == MenulistPart && style.effectiveZoom() != 1.0f)
624 return RenderTheme::isControlStyled(style, border, background, backgroundColor);
627 static FloatRect inflateRect(const FloatRect& rect, const IntSize& size, const int* margins, float zoomLevel)
629 // Only do the inflation if the available width/height are too small. Otherwise try to
630 // fit the glow/check space into the available box's width/height.
631 int widthDelta = rect.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
632 int heightDelta = rect.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
633 FloatRect result(rect);
634 if (widthDelta < 0) {
635 result.setX(result.x() - margins[leftMargin] * zoomLevel);
636 result.setWidth(result.width() - widthDelta);
638 if (heightDelta < 0) {
639 result.setY(result.y() - margins[topMargin] * zoomLevel);
640 result.setHeight(result.height() - heightDelta);
645 void RenderThemeMac::adjustRepaintRect(const RenderObject& renderer, FloatRect& rect)
647 ControlPart part = renderer.style().appearance();
654 case SquareButtonPart:
655 case DefaultButtonPart:
657 case InnerSpinButtonPart:
658 return RenderTheme::adjustRepaintRect(renderer, rect);
664 float zoomLevel = renderer.style().effectiveZoom();
666 if (part == MenulistPart) {
667 setPopupButtonCellState(renderer, IntSize(rect.size()));
668 IntSize size = popupButtonSizes()[[popupButton() controlSize]];
669 size.setHeight(size.height() * zoomLevel);
670 size.setWidth(rect.width());
671 rect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
675 FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject& inputRenderer, const RenderObject& partRenderer, const FloatRect& inputRect, const IntRect& r) const
677 FloatRect partRect(inputRect);
679 // Compute an offset between the part renderer and the input renderer
680 FloatSize offsetFromInputRenderer;
681 const RenderObject* renderer = &partRenderer;
682 while (renderer && renderer != &inputRenderer) {
683 RenderElement* containingRenderer = renderer->container();
684 offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint()));
685 renderer = containingRenderer;
687 // If the input renderer was not a container, something went wrong
688 ASSERT(renderer == &inputRenderer);
689 // Move the rect into partRenderer's coords
690 partRect.move(offsetFromInputRenderer);
691 // Account for the local drawing offset (tx, ty)
692 partRect.move(r.x(), r.y());
697 void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject& o)
699 bool oldIndeterminate = [cell state] == NSMixedState;
700 bool indeterminate = isIndeterminate(o);
701 bool checked = isChecked(o);
703 if (oldIndeterminate != indeterminate) {
704 [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
708 bool oldChecked = [cell state] == NSOnState;
709 if (checked != oldChecked)
710 [cell setState:checked ? NSOnState : NSOffState];
713 void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject& o)
715 bool oldEnabled = [cell isEnabled];
716 bool enabled = isEnabled(o);
717 if (enabled != oldEnabled)
718 [cell setEnabled:enabled];
721 void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject& o)
723 bool oldFocused = [cell showsFirstResponder];
724 bool focused = isFocused(o) && o.style().outlineStyleIsAuto();
725 if (focused != oldFocused)
726 [cell setShowsFirstResponder:focused];
729 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject& o)
731 bool oldPressed = [cell isHighlighted];
732 bool pressed = o.node() && o.node()->isElementNode() && toElement(o.node())->active();
733 if (pressed != oldPressed)
734 [cell setHighlighted:pressed];
737 bool RenderThemeMac::controlSupportsTints(const RenderObject& o) const
739 // An alternate way to implement this would be to get the appropriate cell object
740 // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
741 // that would be that we would match AppKit behavior more closely, but a disadvantage
742 // would be that we would rely on an AppKit SPI method.
747 // Checkboxes only have tint when checked.
748 if (o.style().appearance() == CheckboxPart)
751 // For now assume other controls have tint if enabled.
755 NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle& style) const
757 int fontSize = style.fontSize();
759 return NSRegularControlSize;
761 return NSSmallControlSize;
762 return NSMiniControlSize;
765 NSControlSize RenderThemeMac::controlSizeForCell(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel) const
767 if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel)
768 && minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
769 return NSRegularControlSize;
771 if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel)
772 && minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
773 return NSSmallControlSize;
775 return NSMiniControlSize;
778 void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
780 NSControlSize size = controlSizeForCell(cell, sizes, minSize, zoomLevel);
781 if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
782 [cell setControlSize:size];
785 IntSize RenderThemeMac::sizeForFont(RenderStyle& style, const IntSize* sizes) const
787 if (style.effectiveZoom() != 1.0f) {
788 IntSize result = sizes[controlSizeForFont(style)];
789 return IntSize(result.width() * style.effectiveZoom(), result.height() * style.effectiveZoom());
791 return sizes[controlSizeForFont(style)];
794 IntSize RenderThemeMac::sizeForSystemFont(RenderStyle& style, const IntSize* sizes) const
796 if (style.effectiveZoom() != 1.0f) {
797 IntSize result = sizes[controlSizeForSystemFont(style)];
798 return IntSize(result.width() * style.effectiveZoom(), result.height() * style.effectiveZoom());
800 return sizes[controlSizeForSystemFont(style)];
803 void RenderThemeMac::setSizeFromFont(RenderStyle& style, const IntSize* sizes) const
805 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
806 IntSize size = sizeForFont(style, sizes);
807 if (style.width().isIntrinsicOrAuto() && size.width() > 0)
808 style.setWidth(Length(size.width(), Fixed));
809 if (style.height().isAuto() && size.height() > 0)
810 style.setHeight(Length(size.height(), Fixed));
813 void RenderThemeMac::setFontFromControlSize(StyleResolver&, RenderStyle& style, NSControlSize controlSize) const
815 FontDescription fontDescription;
816 fontDescription.setIsAbsoluteSize(true);
817 fontDescription.setGenericFamily(FontDescription::SerifFamily);
819 NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
820 fontDescription.setOneFamily([font webCoreFamilyName]);
821 fontDescription.setComputedSize([font pointSize] * style.effectiveZoom());
822 fontDescription.setSpecifiedSize([font pointSize] * style.effectiveZoom());
825 style.setLineHeight(RenderStyle::initialLineHeight());
827 if (style.setFontDescription(fontDescription))
828 style.font().update(0);
831 NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle& style) const
833 int fontSize = style.fontSize();
834 if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
835 return NSRegularControlSize;
836 if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
837 return NSSmallControlSize;
838 return NSMiniControlSize;
841 bool RenderThemeMac::paintTextField(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
843 LocalCurrentGraphicsContext localContext(paintInfo.context);
845 NSTextFieldCell *textField = this->textField();
847 GraphicsContextStateSaver stateSaver(*paintInfo.context);
849 [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
850 [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
852 [textField setControlView:nil];
857 void RenderThemeMac::adjustTextFieldStyle(StyleResolver&, RenderStyle&, Element*) const
861 bool RenderThemeMac::paintCapsLockIndicator(const RenderObject&, const PaintInfo& paintInfo, const IntRect& r)
863 if (paintInfo.context->paintingDisabled())
866 LocalCurrentGraphicsContext localContext(paintInfo.context);
867 wkDrawCapsLockIndicator(localContext.cgContext(), r);
872 bool RenderThemeMac::paintTextArea(const RenderObject& o, const PaintInfo& paintInfo, const FloatRect& r)
874 LocalCurrentGraphicsContext localContext(paintInfo.context);
875 wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
879 void RenderThemeMac::adjustTextAreaStyle(StyleResolver&, RenderStyle&, Element*) const
883 const int* RenderThemeMac::popupButtonMargins() const
885 static const int margins[3][4] =
891 return margins[[popupButton() controlSize]];
894 const IntSize* RenderThemeMac::popupButtonSizes() const
896 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
900 const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
902 static const int padding[3][4] =
908 return padding[size];
911 bool RenderThemeMac::paintMenuList(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
913 LocalCurrentGraphicsContext localContext(paintInfo.context);
914 setPopupButtonCellState(renderer, IntSize(rect.size()));
916 NSPopUpButtonCell* popupButton = this->popupButton();
918 float zoomLevel = renderer.style().effectiveZoom();
919 IntSize size = popupButtonSizes()[[popupButton controlSize]];
920 size.setHeight(size.height() * zoomLevel);
921 size.setWidth(rect.width());
923 // Now inflate it to account for the shadow.
924 FloatRect inflatedRect = rect;
925 if (rect.width() >= minimumMenuListSize(renderer.style()))
926 inflatedRect = inflateRect(rect, size, popupButtonMargins(), zoomLevel);
928 GraphicsContextStateSaver stateSaver(*paintInfo.context);
930 // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
931 paintInfo.context->clip(inflatedRect);
933 if (zoomLevel != 1.0f) {
934 inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
935 inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
936 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
937 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
938 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
941 NSView *view = documentViewFor(renderer);
942 [popupButton drawWithFrame:inflatedRect inView:view];
943 if (isFocused(renderer) && renderer.style().outlineStyleIsAuto()) {
944 if (wkDrawCellFocusRingWithFrameAtTime(popupButton, inflatedRect, view, std::numeric_limits<double>::max()))
945 renderer.document().page()->focusController().setFocusedElementNeedsRepaint();
948 [popupButton setControlView:nil];
953 #if ENABLE(METER_ELEMENT)
955 IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter& renderMeter, const IntRect& bounds) const
957 if (NoControlPart == renderMeter.style().appearance())
958 return bounds.size();
960 NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
961 // Makes enough room for cell's intrinsic size.
962 NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
963 return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
964 bounds.height() < cellSize.height ? cellSize.height : bounds.height());
967 bool RenderThemeMac::paintMeter(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
969 if (!renderObject.isMeter())
972 LocalCurrentGraphicsContext localContext(paintInfo.context);
974 NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
975 GraphicsContextStateSaver stateSaver(*paintInfo.context);
977 [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
978 [cell setControlView:nil];
982 bool RenderThemeMac::supportsMeter(ControlPart part) const
985 case RelevancyLevelIndicatorPart:
986 case DiscreteCapacityLevelIndicatorPart:
987 case RatingLevelIndicatorPart:
989 case ContinuousCapacityLevelIndicatorPart:
996 NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
999 case RelevancyLevelIndicatorPart:
1000 return NSRelevancyLevelIndicatorStyle;
1001 case DiscreteCapacityLevelIndicatorPart:
1002 return NSDiscreteCapacityLevelIndicatorStyle;
1003 case RatingLevelIndicatorPart:
1004 return NSRatingLevelIndicatorStyle;
1006 case ContinuousCapacityLevelIndicatorPart:
1008 return NSContinuousCapacityLevelIndicatorStyle;
1013 NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter& renderMeter) const
1015 const RenderStyle& style = renderMeter.style();
1016 ASSERT(style.appearance() != NoControlPart);
1018 if (!m_levelIndicator)
1019 m_levelIndicator = adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
1020 NSLevelIndicatorCell* cell = m_levelIndicator.get();
1022 HTMLMeterElement* element = renderMeter.meterElement();
1023 double value = element->value();
1025 // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
1026 // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
1027 switch (element->gaugeRegion()) {
1028 case HTMLMeterElement::GaugeRegionOptimum:
1029 // Make meter the green
1030 [cell setWarningValue:value + 1];
1031 [cell setCriticalValue:value + 2];
1033 case HTMLMeterElement::GaugeRegionSuboptimal:
1034 // Make the meter yellow
1035 [cell setWarningValue:value - 1];
1036 [cell setCriticalValue:value + 1];
1038 case HTMLMeterElement::GaugeRegionEvenLessGood:
1039 // Make the meter red
1040 [cell setWarningValue:value - 2];
1041 [cell setCriticalValue:value - 1];
1045 [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style.appearance())];
1046 [cell setBaseWritingDirection:style.isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
1047 [cell setMinValue:element->min()];
1048 [cell setMaxValue:element->max()];
1049 RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
1050 [cell setObjectValue:valueObject.get()];
1057 const IntSize* RenderThemeMac::progressBarSizes() const
1059 static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
1063 const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const
1065 static const int margins[3][4] =
1071 return margins[controlSize];
1074 IntRect RenderThemeMac::progressBarRectForBounds(const RenderObject& renderObject, const IntRect& bounds) const
1076 // Workaround until <rdar://problem/15855086> is fixed.
1077 int maxDimension = static_cast<int>(std::numeric_limits<ushort>::max());
1078 IntRect progressBarBounds(bounds.x(), bounds.y(), std::min(bounds.width(), maxDimension), std::min(bounds.height(), maxDimension));
1079 if (NoControlPart == renderObject.style().appearance())
1080 return progressBarBounds;
1082 float zoomLevel = renderObject.style().effectiveZoom();
1083 NSControlSize controlSize = controlSizeForFont(renderObject.style());
1084 IntSize size = progressBarSizes()[controlSize];
1085 size.setHeight(size.height() * zoomLevel);
1086 size.setWidth(progressBarBounds.width());
1088 // Now inflate it to account for the shadow.
1089 IntRect inflatedRect = progressBarBounds;
1090 if (progressBarBounds.height() <= minimumProgressBarHeight(renderObject.style()))
1091 inflatedRect = IntRect(inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel));
1093 return inflatedRect;
1096 int RenderThemeMac::minimumProgressBarHeight(RenderStyle& style) const
1098 return sizeForSystemFont(style, progressBarSizes()).height();
1101 double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress&) const
1103 return progressAnimationFrameRate;
1106 double RenderThemeMac::animationDurationForProgressBar(RenderProgress&) const
1108 return progressAnimationNumFrames * progressAnimationFrameRate;
1111 void RenderThemeMac::adjustProgressBarStyle(StyleResolver&, RenderStyle&, Element*) const
1115 bool RenderThemeMac::paintProgressBar(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect)
1117 if (!renderObject.isProgress())
1120 IntRect inflatedRect = progressBarRectForBounds(renderObject, rect);
1121 NSControlSize controlSize = controlSizeForFont(renderObject.style());
1123 const RenderProgress& renderProgress = *toRenderProgress(&renderObject);
1124 HIThemeTrackDrawInfo trackInfo;
1125 trackInfo.version = 0;
1126 if (controlSize == NSRegularControlSize)
1127 trackInfo.kind = renderProgress.position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
1129 trackInfo.kind = renderProgress.position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
1131 float deviceScaleFactor = renderObject.document().deviceScaleFactor();
1132 trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
1134 trackInfo.max = std::numeric_limits<SInt32>::max();
1135 trackInfo.value = lround(renderProgress.position() * nextafter(trackInfo.max, 0));
1136 trackInfo.trackInfo.progress.phase = lround(renderProgress.animationProgress() * nextafter(progressAnimationNumFrames, 0) * deviceScaleFactor);
1137 trackInfo.attributes = kThemeTrackHorizontal;
1138 trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
1139 trackInfo.reserved = 0;
1140 trackInfo.filler1 = 0;
1142 std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::createCompatibleBuffer(inflatedRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB, paintInfo.context, true);
1146 ContextContainer cgContextContainer(imageBuffer->context());
1147 CGContextRef cgContext = cgContextContainer.context();
1148 HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
1150 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1152 if (!renderProgress.style().isLeftToRightDirection()) {
1153 paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
1154 paintInfo.context->scale(FloatSize(-1, 1));
1157 paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location());
1161 const float baseFontSize = 11.0f;
1162 const float baseArrowHeight = 4.0f;
1163 const float baseArrowWidth = 5.0f;
1164 const float baseSpaceBetweenArrows = 2.0f;
1165 const int arrowPaddingLeft = 6;
1166 const int arrowPaddingRight = 6;
1167 const int paddingBeforeSeparator = 4;
1168 const int baseBorderRadius = 5;
1169 const int styledPopupPaddingLeft = 8;
1170 const int styledPopupPaddingTop = 1;
1171 const int styledPopupPaddingBottom = 2;
1173 static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1175 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
1176 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
1177 float a = inData[0];
1179 for (i = 0; i < 4; i++)
1180 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1183 static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1185 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
1186 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
1187 float a = inData[0];
1189 for (i = 0; i < 4; i++)
1190 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1193 static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1195 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
1196 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1197 float a = inData[0];
1199 for (i = 0; i < 4; i++)
1200 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1203 static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
1205 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
1206 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
1207 float a = inData[0];
1209 for (i = 0; i < 4; i++)
1210 outData[i] = (1.0f - a) * dark[i] + a * light[i];
1213 void RenderThemeMac::paintMenuListButtonGradients(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1218 ContextContainer cgContextContainer(paintInfo.context);
1219 CGContextRef context = cgContextContainer.context();
1221 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1223 FloatRoundedRect border = FloatRoundedRect(o.style().getRoundedBorderFor(r));
1224 int radius = border.radii().topLeft().width();
1226 CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1228 FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
1229 struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
1230 RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
1231 RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
1233 FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
1234 struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
1235 RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
1236 RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
1238 struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
1239 RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1240 RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
1242 RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
1244 RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
1247 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1248 CGContextClipToRect(context, r);
1249 paintInfo.context->clipRoundedRect(border);
1250 context = cgContextContainer.context();
1251 CGContextDrawShading(context, mainShading.get());
1255 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1256 CGContextClipToRect(context, topGradient);
1257 paintInfo.context->clipRoundedRect(FloatRoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
1258 context = cgContextContainer.context();
1259 CGContextDrawShading(context, topShading.get());
1262 if (!bottomGradient.isEmpty()) {
1263 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1264 CGContextClipToRect(context, bottomGradient);
1265 paintInfo.context->clipRoundedRect(FloatRoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
1266 context = cgContextContainer.context();
1267 CGContextDrawShading(context, bottomShading.get());
1271 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1272 CGContextClipToRect(context, r);
1273 paintInfo.context->clipRoundedRect(border);
1274 context = cgContextContainer.context();
1275 CGContextDrawShading(context, leftShading.get());
1276 CGContextDrawShading(context, rightShading.get());
1280 bool RenderThemeMac::paintMenuListButtonDecorations(const RenderObject& renderer, const PaintInfo& paintInfo, const FloatRect& rect)
1282 IntRect bounds = IntRect(rect.x() + renderer.style().borderLeftWidth(),
1283 rect.y() + renderer.style().borderTopWidth(),
1284 rect.width() - renderer.style().borderLeftWidth() - renderer.style().borderRightWidth(),
1285 rect.height() - renderer.style().borderTopWidth() - renderer.style().borderBottomWidth());
1286 // Draw the gradients to give the styled popup menu a button appearance
1287 paintMenuListButtonGradients(renderer, paintInfo, bounds);
1289 // 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
1290 float fontScale = std::min(renderer.style().fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
1291 float centerY = bounds.y() + bounds.height() / 2.0f;
1292 float arrowHeight = baseArrowHeight * fontScale;
1293 float arrowWidth = baseArrowWidth * fontScale;
1294 float leftEdge = bounds.maxX() - arrowPaddingRight * renderer.style().effectiveZoom() - arrowWidth;
1295 float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
1297 if (bounds.width() < arrowWidth + arrowPaddingLeft * renderer.style().effectiveZoom())
1300 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1302 paintInfo.context->setFillColor(renderer.style().visitedDependentColor(CSSPropertyColor), renderer.style().colorSpace());
1303 paintInfo.context->setStrokeStyle(NoStroke);
1305 FloatPoint arrow1[3];
1306 arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
1307 arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
1308 arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
1310 // Draw the top arrow
1311 paintInfo.context->drawConvexPolygon(3, arrow1, true);
1313 FloatPoint arrow2[3];
1314 arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
1315 arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
1316 arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
1318 // Draw the bottom arrow
1319 paintInfo.context->drawConvexPolygon(3, arrow2, true);
1321 Color leftSeparatorColor(0, 0, 0, 40);
1322 Color rightSeparatorColor(255, 255, 255, 40);
1324 // FIXME: Should the separator thickness and space be scaled up by fontScale?
1325 int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
1326 int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * renderer.style().effectiveZoom()); // FIXME: Round?
1328 // Draw the separator to the left of the arrows
1329 paintInfo.context->setStrokeThickness(1); // Deliberately ignores zoom since it looks nicer if it stays thin.
1330 paintInfo.context->setStrokeStyle(SolidStroke);
1331 paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
1332 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
1333 IntPoint(leftEdgeOfSeparator, bounds.maxY()));
1335 paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
1336 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
1337 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
1341 static const IntSize* menuListButtonSizes()
1343 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
1347 void RenderThemeMac::adjustMenuListStyle(StyleResolver& styleResolver, RenderStyle& style, Element* e) const
1349 NSControlSize controlSize = controlSizeForFont(style);
1351 style.resetBorder();
1352 style.resetPadding();
1354 // Height is locked to auto.
1355 style.setHeight(Length(Auto));
1357 // White-space is locked to pre
1358 style.setWhiteSpace(PRE);
1360 // Set the foreground color to black or gray when we have the aqua look.
1361 // Cast to RGB32 is to work around a compiler bug.
1362 style.setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
1364 // Set the button's vertical size.
1365 setSizeFromFont(style, menuListButtonSizes());
1367 // 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
1368 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
1369 // system font for the control size instead.
1370 setFontFromControlSize(styleResolver, style, controlSize);
1372 style.setBoxShadow(nullptr);
1375 int RenderThemeMac::popupInternalPaddingLeft(RenderStyle& style) const
1377 if (style.appearance() == MenulistPart)
1378 return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style.effectiveZoom();
1379 if (style.appearance() == MenulistButtonPart)
1380 return styledPopupPaddingLeft * style.effectiveZoom();
1384 int RenderThemeMac::popupInternalPaddingRight(RenderStyle& style) const
1386 if (style.appearance() == MenulistPart)
1387 return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style.effectiveZoom();
1388 if (style.appearance() == MenulistButtonPart) {
1389 float fontScale = style.fontSize() / baseFontSize;
1390 float arrowWidth = baseArrowWidth * fontScale;
1391 return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style.effectiveZoom()));
1396 int RenderThemeMac::popupInternalPaddingTop(RenderStyle& style) const
1398 if (style.appearance() == MenulistPart)
1399 return popupButtonPadding(controlSizeForFont(style))[topPadding] * style.effectiveZoom();
1400 if (style.appearance() == MenulistButtonPart)
1401 return styledPopupPaddingTop * style.effectiveZoom();
1405 int RenderThemeMac::popupInternalPaddingBottom(RenderStyle& style) const
1407 if (style.appearance() == MenulistPart)
1408 return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style.effectiveZoom();
1409 if (style.appearance() == MenulistButtonPart)
1410 return styledPopupPaddingBottom * style.effectiveZoom();
1414 PopupMenuStyle::PopupMenuSize RenderThemeMac::popupMenuSize(const RenderStyle& style, IntRect& rect) const
1416 NSPopUpButtonCell* popupButton = this->popupButton();
1417 NSControlSize size = controlSizeForCell(popupButton, popupButtonSizes(), rect.size(), style.effectiveZoom());
1419 case NSRegularControlSize:
1420 return PopupMenuStyle::PopupMenuSizeNormal;
1421 case NSSmallControlSize:
1422 return PopupMenuStyle::PopupMenuSizeSmall;
1423 case NSMiniControlSize:
1424 return PopupMenuStyle::PopupMenuSizeMini;
1426 return PopupMenuStyle::PopupMenuSizeNormal;
1430 void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1432 float fontScale = style.fontSize() / baseFontSize;
1434 style.resetPadding();
1435 style.setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
1437 const int minHeight = 15;
1438 style.setMinHeight(Length(minHeight, Fixed));
1440 style.setLineHeight(RenderStyle::initialLineHeight());
1443 void RenderThemeMac::setPopupButtonCellState(const RenderObject& o, const IntSize& buttonSize)
1445 NSPopUpButtonCell* popupButton = this->popupButton();
1447 // Set the control size based off the rectangle we're painting into.
1448 setControlSize(popupButton, popupButtonSizes(), buttonSize, o.style().effectiveZoom());
1450 // Update the various states we respond to.
1451 updateCheckedState(popupButton, o);
1452 updateEnabledState(popupButton, o);
1453 updatePressedState(popupButton, o);
1456 const IntSize* RenderThemeMac::menuListSizes() const
1458 static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
1462 int RenderThemeMac::minimumMenuListSize(RenderStyle& style) const
1464 return sizeForSystemFont(style, menuListSizes()).width();
1467 const int trackWidth = 5;
1468 const int trackRadius = 2;
1470 void RenderThemeMac::adjustSliderTrackStyle(StyleResolver&, RenderStyle& style, Element*) const
1472 style.setBoxShadow(nullptr);
1475 bool RenderThemeMac::paintSliderTrack(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1478 float zoomLevel = o.style().effectiveZoom();
1479 float zoomedTrackWidth = trackWidth * zoomLevel;
1481 if (o.style().appearance() == SliderHorizontalPart || o.style().appearance() == MediaSliderPart) {
1482 bounds.setHeight(zoomedTrackWidth);
1483 bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
1484 } else if (o.style().appearance() == SliderVerticalPart) {
1485 bounds.setWidth(zoomedTrackWidth);
1486 bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
1489 LocalCurrentGraphicsContext localContext(paintInfo.context);
1490 CGContextRef context = localContext.cgContext();
1491 CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
1493 #if ENABLE(DATALIST_ELEMENT)
1494 paintSliderTicks(o, paintInfo, r);
1497 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1498 CGContextClipToRect(context, bounds);
1500 struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
1501 RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
1502 RetainPtr<CGShadingRef> mainShading;
1503 if (o.style().appearance() == SliderVerticalPart)
1504 mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
1506 mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
1508 IntSize radius(trackRadius, trackRadius);
1509 paintInfo.context->clipRoundedRect(FloatRoundedRect(bounds, radius, radius, radius, radius));
1510 context = localContext.cgContext();
1511 CGContextDrawShading(context, mainShading.get());
1516 void RenderThemeMac::adjustSliderThumbStyle(StyleResolver& styleResolver, RenderStyle& style, Element* element) const
1518 RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
1519 style.setBoxShadow(nullptr);
1522 const float verticalSliderHeightPadding = 0.1f;
1524 bool RenderThemeMac::paintSliderThumb(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1526 NSSliderCell* sliderThumbCell = o.style().appearance() == SliderThumbVerticalPart
1527 ? sliderThumbVertical()
1528 : sliderThumbHorizontal();
1530 LocalCurrentGraphicsContext localContext(paintInfo.context);
1532 // Update the various states we respond to.
1533 updateEnabledState(sliderThumbCell, o);
1534 Element* focusDelegate = (o.node() && o.node()->isElementNode()) ? toElement(o.node())->focusDelegate() : 0;
1536 updateFocusedState(sliderThumbCell, *focusDelegate->renderer());
1538 // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
1540 if (o.style().appearance() == SliderThumbVerticalPart)
1541 oldPressed = m_isSliderThumbVerticalPressed;
1543 oldPressed = m_isSliderThumbHorizontalPressed;
1545 bool pressed = isPressed(o);
1547 if (o.style().appearance() == SliderThumbVerticalPart)
1548 m_isSliderThumbVerticalPressed = pressed;
1550 m_isSliderThumbHorizontalPressed = pressed;
1552 if (pressed != oldPressed) {
1554 [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
1556 [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
1559 FloatRect bounds = r;
1560 // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
1561 if (o.style().appearance() == SliderThumbVerticalPart)
1562 bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o.style().effectiveZoom());
1564 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1565 float zoomLevel = o.style().effectiveZoom();
1567 FloatRect unzoomedRect = bounds;
1568 if (zoomLevel != 1.0f) {
1569 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1570 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1571 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1572 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1573 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1576 [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
1577 [sliderThumbCell setControlView:nil];
1582 bool RenderThemeMac::paintSearchField(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1584 LocalCurrentGraphicsContext localContext(paintInfo.context);
1585 NSSearchFieldCell* search = this->search();
1587 setSearchCellState(o, r);
1589 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1591 float zoomLevel = o.style().effectiveZoom();
1593 IntRect unzoomedRect = r;
1595 if (zoomLevel != 1.0f) {
1596 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1597 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1598 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1599 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1600 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1603 // Set the search button to nil before drawing. Then reset it so we can draw it later.
1604 [search setSearchButtonCell:nil];
1606 [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
1608 [search setControlView:nil];
1609 [search resetSearchButtonCell];
1614 void RenderThemeMac::setSearchCellState(const RenderObject& o, const IntRect&)
1616 NSSearchFieldCell* search = this->search();
1618 [search setControlSize:controlSizeForFont(o.style())];
1620 // Update the various states we respond to.
1621 updateEnabledState(search, o);
1622 updateFocusedState(search, o);
1625 const IntSize* RenderThemeMac::searchFieldSizes() const
1627 static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
1631 void RenderThemeMac::setSearchFieldSize(RenderStyle& style) const
1633 // If the width and height are both specified, then we have nothing to do.
1634 if (!style.width().isIntrinsicOrAuto() && !style.height().isAuto())
1637 // Use the font size to determine the intrinsic width of the control.
1638 setSizeFromFont(style, searchFieldSizes());
1641 void RenderThemeMac::adjustSearchFieldStyle(StyleResolver& styleResolver, RenderStyle& style, Element*) const
1644 style.resetBorder();
1645 const short borderWidth = 2 * style.effectiveZoom();
1646 style.setBorderLeftWidth(borderWidth);
1647 style.setBorderLeftStyle(INSET);
1648 style.setBorderRightWidth(borderWidth);
1649 style.setBorderRightStyle(INSET);
1650 style.setBorderBottomWidth(borderWidth);
1651 style.setBorderBottomStyle(INSET);
1652 style.setBorderTopWidth(borderWidth);
1653 style.setBorderTopStyle(INSET);
1656 style.setHeight(Length(Auto));
1657 setSearchFieldSize(style);
1659 // Override padding size to match AppKit text positioning.
1660 const int padding = 1 * style.effectiveZoom();
1661 style.setPaddingLeft(Length(padding, Fixed));
1662 style.setPaddingRight(Length(padding, Fixed));
1663 style.setPaddingTop(Length(padding, Fixed));
1664 style.setPaddingBottom(Length(padding, Fixed));
1666 NSControlSize controlSize = controlSizeForFont(style);
1667 setFontFromControlSize(styleResolver, style, controlSize);
1669 style.setBoxShadow(nullptr);
1672 bool RenderThemeMac::paintSearchFieldCancelButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1674 Element* input = o.node()->shadowHost();
1676 input = toElement(o.node());
1678 if (!input->renderer()->isBox())
1681 LocalCurrentGraphicsContext localContext(paintInfo.context);
1682 setSearchCellState(*input->renderer(), r);
1684 NSSearchFieldCell* search = this->search();
1686 if (!input->isDisabledFormControl() && (input->isTextFormControl() && !toHTMLTextFormControlElement(*input).isReadOnly()))
1687 updatePressedState([search cancelButtonCell], o);
1688 else if ([[search cancelButtonCell] isHighlighted])
1689 [[search cancelButtonCell] setHighlighted:NO];
1691 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1693 float zoomLevel = o.style().effectiveZoom();
1695 FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1696 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1698 FloatRect unzoomedRect(localBounds);
1699 if (zoomLevel != 1.0f) {
1700 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1701 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1702 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1703 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1704 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1707 [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1708 [[search cancelButtonCell] setControlView:nil];
1712 const IntSize* RenderThemeMac::cancelButtonSizes() const
1714 static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
1718 void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1720 IntSize size = sizeForSystemFont(style, cancelButtonSizes());
1721 style.setWidth(Length(size.width(), Fixed));
1722 style.setHeight(Length(size.height(), Fixed));
1723 style.setBoxShadow(nullptr);
1726 const IntSize* RenderThemeMac::resultsButtonSizes() const
1728 static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
1732 const int emptyResultsOffset = 9;
1733 void RenderThemeMac::adjustSearchFieldDecorationPartStyle(StyleResolver&, RenderStyle& style, Element*) const
1735 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1736 style.setWidth(Length(size.width() - emptyResultsOffset, Fixed));
1737 style.setHeight(Length(size.height(), Fixed));
1738 style.setBoxShadow(nullptr);
1741 bool RenderThemeMac::paintSearchFieldDecorationPart(const RenderObject&, const PaintInfo&, const IntRect&)
1746 void RenderThemeMac::adjustSearchFieldResultsDecorationPartStyle(StyleResolver&, RenderStyle& style, Element*) const
1748 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1749 style.setWidth(Length(size.width(), Fixed));
1750 style.setHeight(Length(size.height(), Fixed));
1751 style.setBoxShadow(nullptr);
1754 bool RenderThemeMac::paintSearchFieldResultsDecorationPart(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1756 Node* input = o.node()->shadowHost();
1759 if (!input->renderer()->isBox())
1762 LocalCurrentGraphicsContext localContext(paintInfo.context);
1763 setSearchCellState(*input->renderer(), r);
1765 NSSearchFieldCell* search = this->search();
1767 if ([search searchMenuTemplate] != nil)
1768 [search setSearchMenuTemplate:nil];
1770 FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1771 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1773 [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
1774 [[search searchButtonCell] setControlView:nil];
1778 const int resultsArrowWidth = 5;
1779 void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver&, RenderStyle& style, Element*) const
1781 IntSize size = sizeForSystemFont(style, resultsButtonSizes());
1782 style.setWidth(Length(size.width() + resultsArrowWidth, Fixed));
1783 style.setHeight(Length(size.height(), Fixed));
1784 style.setBoxShadow(nullptr);
1787 bool RenderThemeMac::paintSearchFieldResultsButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
1789 Node* input = o.node()->shadowHost();
1792 if (!input->renderer()->isBox())
1795 LocalCurrentGraphicsContext localContext(paintInfo.context);
1796 setSearchCellState(*input->renderer(), r);
1798 NSSearchFieldCell* search = this->search();
1800 if (![search searchMenuTemplate])
1801 [search setSearchMenuTemplate:searchMenuTemplate()];
1803 GraphicsContextStateSaver stateSaver(*paintInfo.context);
1804 float zoomLevel = o.style().effectiveZoom();
1806 FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
1807 localBounds = convertToPaintingRect(*input->renderer(), o, localBounds, r);
1809 IntRect unzoomedRect(localBounds);
1810 if (zoomLevel != 1.0f) {
1811 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
1812 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
1813 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
1814 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
1815 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
1818 [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
1819 [[search searchButtonCell] setControlView:nil];
1824 bool RenderThemeMac::paintSnapshottedPluginOverlay(const RenderObject& o, const PaintInfo& paintInfo, const IntRect&)
1826 if (paintInfo.phase != PaintPhaseBlockBackground)
1829 if (!o.isRenderBlock())
1832 const RenderBlock& renderBlock = *toRenderBlock(&o);
1834 LayoutUnit contentWidth = renderBlock.contentWidth();
1835 LayoutUnit contentHeight = renderBlock.contentHeight();
1836 if (!contentWidth || !contentHeight)
1839 GraphicsContext* context = paintInfo.context;
1841 LayoutSize contentSize(contentWidth, contentHeight);
1842 LayoutPoint contentLocation = renderBlock.location();
1843 contentLocation.move(renderBlock.borderLeft() + renderBlock.paddingLeft(), renderBlock.borderTop() + renderBlock.paddingTop());
1845 LayoutRect rect(contentLocation, contentSize);
1846 IntRect alignedRect = snappedIntRect(rect);
1847 if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
1850 // We need to get the snapshot image from the plugin element, which should be available
1851 // from our node. Assuming this node is the plugin overlay element, we should get to the
1852 // plugin itself by asking for the shadow root parent, and then its parent.
1854 if (!renderBlock.element()->isHTMLElement())
1857 HTMLElement* plugInOverlay = toHTMLElement(renderBlock.element());
1858 Element* parent = plugInOverlay->parentOrShadowHostElement();
1859 while (parent && !parent->isPluginElement())
1860 parent = parent->parentOrShadowHostElement();
1865 HTMLPlugInElement* plugInElement = toHTMLPlugInElement(parent);
1866 if (!plugInElement->isPlugInImageElement())
1869 HTMLPlugInImageElement& plugInImageElement = toHTMLPlugInImageElement(*plugInElement);
1871 Image* snapshot = plugInImageElement.snapshotImage();
1875 RenderSnapshottedPlugIn* plugInRenderer = toRenderSnapshottedPlugIn(plugInImageElement.renderer());
1876 FloatPoint snapshotAbsPos = plugInRenderer->localToAbsolute();
1877 snapshotAbsPos.move(plugInRenderer->borderLeft() + plugInRenderer->paddingLeft(), plugInRenderer->borderTop() + plugInRenderer->paddingTop());
1879 // We could draw the snapshot with that coordinates, but we need to make sure there
1880 // isn't a composited layer between us and the plugInRenderer.
1881 const RenderBox* renderBox = toRenderBox(&o);
1882 while (renderBox != plugInRenderer) {
1883 if (renderBox->hasLayer() && renderBox->layer() && renderBox->layer()->isComposited()) {
1884 snapshotAbsPos = -renderBox->location();
1887 renderBox = renderBox->parentBox();
1890 LayoutSize pluginSize(plugInRenderer->contentWidth(), plugInRenderer->contentHeight());
1891 LayoutRect pluginRect(snapshotAbsPos, pluginSize);
1892 IntRect alignedPluginRect = snappedIntRect(pluginRect);
1894 if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
1897 context->drawImage(snapshot, plugInRenderer->style().colorSpace(), alignedPluginRect, CompositeSourceOver);
1901 #if ENABLE(DATALIST_ELEMENT)
1902 IntSize RenderThemeMac::sliderTickSize() const
1904 return IntSize(1, 3);
1907 int RenderThemeMac::sliderTickOffsetFromTrackCenter() const
1913 const int sliderThumbWidth = 15;
1914 const int sliderThumbHeight = 15;
1916 void RenderThemeMac::adjustSliderThumbSize(RenderStyle& style, Element*) const
1918 float zoomLevel = style.effectiveZoom();
1919 if (style.appearance() == SliderThumbHorizontalPart || style.appearance() == SliderThumbVerticalPart) {
1920 style.setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
1921 style.setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
1925 bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const
1930 NSPopUpButtonCell* RenderThemeMac::popupButton() const
1932 if (!m_popupButton) {
1933 m_popupButton = adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
1934 [m_popupButton.get() setUsesItemFromMenu:NO];
1935 [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
1936 // We don't want the app's UI layout direction to affect the appearance of popup buttons in
1937 // web content, which has its own layout direction.
1938 // FIXME: Make this depend on the directionality of the select element, once the rest of the
1939 // rendering code can account for the popup arrows appearing on the other side.
1940 [m_popupButton setUserInterfaceLayoutDirection:NSUserInterfaceLayoutDirectionLeftToRight];
1943 return m_popupButton.get();
1946 NSSearchFieldCell* RenderThemeMac::search() const
1949 m_search = adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
1950 [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
1951 [m_search.get() setBezeled:YES];
1952 [m_search.get() setEditable:YES];
1953 [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
1954 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
1955 [m_search.get() setCenteredLook:NO];
1959 return m_search.get();
1962 NSMenu* RenderThemeMac::searchMenuTemplate() const
1964 if (!m_searchMenuTemplate)
1965 m_searchMenuTemplate = adoptNS([[NSMenu alloc] initWithTitle:@""]);
1967 return m_searchMenuTemplate.get();
1970 NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
1972 if (!m_sliderThumbHorizontal) {
1973 m_sliderThumbHorizontal = adoptNS([[NSSliderCell alloc] init]);
1974 [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
1975 [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
1976 [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
1979 return m_sliderThumbHorizontal.get();
1982 NSSliderCell* RenderThemeMac::sliderThumbVertical() const
1984 if (!m_sliderThumbVertical) {
1985 m_sliderThumbVertical = adoptNS([[NSSliderCell alloc] init]);
1986 [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
1987 [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
1988 [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
1991 return m_sliderThumbVertical.get();
1994 NSTextFieldCell* RenderThemeMac::textField() const
1997 m_textField = adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
1998 [m_textField.get() setBezeled:YES];
1999 [m_textField.get() setEditable:YES];
2000 [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
2001 // Post-Lion, WebCore can be in charge of paintinng the background thanks to
2002 // the workaround in place for <rdar://problem/11385461>, which is implemented
2003 // above as _coreUIDrawOptionsWithFrame.
2004 [m_textField.get() setDrawsBackground:NO];
2007 return m_textField.get();
2010 String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
2015 String strToTruncate;
2016 if (fileList->isEmpty())
2017 strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
2018 else if (fileList->length() == 1)
2019 strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
2021 return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
2023 return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
2026 bool RenderThemeMac::defaultButtonHasAnimation() const
2028 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
2035 #if ENABLE(SERVICE_CONTROLS)
2036 NSServicesRolloverButtonCell* RenderThemeMac::servicesRolloverButtonCell() const
2038 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2039 if (!m_servicesRolloverButton) {
2040 m_servicesRolloverButton = [NSServicesRolloverButtonCell serviceRolloverButtonCellForStyle:NSSharingServicePickerStyleRollover];
2041 [m_servicesRolloverButton setBezelStyle:NSRoundedDisclosureBezelStyle];
2042 [m_servicesRolloverButton setButtonType:NSPushOnPushOffButton];
2043 [m_servicesRolloverButton setImagePosition:NSImageOnly];
2044 [m_servicesRolloverButton setState:NO];
2047 return m_servicesRolloverButton.get();
2053 bool RenderThemeMac::paintImageControlsButton(const RenderObject& renderer, const PaintInfo& paintInfo, const IntRect& rect)
2055 if (paintInfo.phase != PaintPhaseBlockBackground)
2058 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2059 NSServicesRolloverButtonCell *cell = servicesRolloverButtonCell();
2061 LocalCurrentGraphicsContext localContext(paintInfo.context);
2062 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2064 paintInfo.context->translate(rect.x(), rect.y());
2066 IntRect innerFrame(IntPoint(), rect.size());
2067 [cell drawWithFrame:innerFrame inView:documentViewFor(renderer)];
2068 [cell setControlView:nil];
2070 UNUSED_PARAM(renderer);
2077 IntSize RenderThemeMac::imageControlsButtonSize(const RenderObject&) const
2079 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2080 return IntSize(servicesRolloverButtonCell().cellSize);
2086 IntSize RenderThemeMac::imageControlsButtonPositionOffset() const
2088 #if HAVE(APPKIT_SERVICE_CONTROLS_SUPPORT)
2089 // FIXME: Currently the offsets will always be the same no matter what image rect you try with.
2090 // This may not always be true in the future.
2091 static const int dummyDimension = 100;
2092 IntRect dummyImageRect(0, 0, dummyDimension, dummyDimension);
2093 NSRect bounds = [servicesRolloverButtonCell() rectForBounds:dummyImageRect preferredEdge:NSMinYEdge];
2095 return IntSize(dummyDimension - bounds.origin.x, bounds.origin.y);
2102 } // namespace WebCore
2104 #endif // !PLATFORM(IOS)