1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsNativeThemeCocoa.h"
7 #include "nsObjCExceptions.h"
8 #include "nsNumberControlFrame.h"
9 #include "nsRangeFrame.h"
10 #include "nsRenderingContext.h"
13 #include "nsThemeConstants.h"
14 #include "nsIPresShell.h"
15 #include "nsPresContext.h"
16 #include "nsIContent.h"
17 #include "nsIDocument.h"
20 #include "nsNameSpaceManager.h"
21 #include "nsPresContext.h"
22 #include "nsGkAtoms.h"
23 #include "nsCocoaFeatures.h"
24 #include "nsCocoaWindow.h"
25 #include "nsNativeThemeColors.h"
26 #include "nsIScrollableFrame.h"
27 #include "mozilla/EventStates.h"
28 #include "mozilla/dom/Element.h"
29 #include "mozilla/dom/HTMLMeterElement.h"
30 #include "nsLookAndFeel.h"
31 #include "VibrancyManager.h"
33 #include "gfxContext.h"
34 #include "gfxQuartzSurface.h"
35 #include "gfxQuartzNativeDrawing.h"
38 using namespace mozilla;
39 using namespace mozilla::gfx;
40 using mozilla::dom::HTMLMeterElement;
42 #define DRAW_IN_FRAME_DEBUG 0
43 #define SCROLLBARS_VISUAL_DEBUG 0
45 // private Quartz routines needed here
47 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
48 typedef CFTypeRef CUIRendererRef;
49 void CUIDraw(CUIRendererRef r, CGRect rect, CGContextRef ctx, CFDictionaryRef options, CFDictionaryRef* result);
52 // Workaround for NSCell control tint drawing
53 // Without this workaround, NSCells are always drawn with the clear control tint
54 // as long as they're not attached to an NSControl which is a subview of an active window.
55 // XXXmstange Why doesn't Webkit need this?
56 @implementation NSCell (ControlTintWorkaround)
57 - (int)_realControlTint { return [self controlTint]; }
60 // The purpose of this class is to provide objects that can be used when drawing
61 // NSCells using drawWithFrame:inView: without causing any harm. The only
62 // messages that will be sent to such an object are "isFlipped" and
63 // "currentEditor": isFlipped needs to return YES in order to avoid drawing bugs
64 // on 10.4 (see bug 465069); currentEditor (which isn't even a method of
65 // NSView) will be called when drawing search fields, and we only provide it in
66 // order to prevent "unrecognized selector" exceptions.
67 // There's no need to pass the actual NSView that we're drawing into to
68 // drawWithFrame:inView:. What's more, doing so even causes unnecessary
69 // invalidations as soon as we draw a focusring!
70 @interface CellDrawView : NSView
74 @implementation CellDrawView
81 - (NSText*)currentEditor
89 DrawFocusRingForCellIfNeeded(NSCell* aCell, NSRect aWithFrame, NSView* aInView)
91 if ([aCell showsFirstResponder]) {
92 CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
93 CGContextSaveGState(cgContext);
95 // It's important to set the focus ring style before we enter the
96 // transparency layer so that the transparency layer only contains
97 // the normal button mask without the focus ring, and the conversion
98 // to the focus ring shape happens only when the transparency layer is
100 NSSetFocusRingStyle(NSFocusRingOnly);
102 // We need to draw the whole button into a transparency layer because
103 // many button types are composed of multiple parts, and if these parts
104 // were drawn while the focus ring style was active, each individual part
105 // would produce a focus ring for itself. But we only want one focus ring
106 // for the whole button. The transparency layer is a way to merge the
107 // individual button parts together before the focus ring shape is
109 CGContextBeginTransparencyLayerWithRect(cgContext, NSRectToCGRect(aWithFrame), 0);
110 [aCell drawFocusRingMaskWithFrame:aWithFrame inView:aInView];
111 CGContextEndTransparencyLayer(cgContext);
113 CGContextRestoreGState(cgContext);
118 FocusIsDrawnByDrawWithFrame()
120 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
121 // When building with the 10.8 SDK or higher, focus rings don't draw as part
122 // of -[NSCell drawWithFrame:inView:] and must be drawn by a separate call
123 // to -[NSCell drawFocusRingMaskWithFrame:inView:]; .
124 // See the NSButtonCell section under
125 // https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKitOlderNotes/#X10_8Notes
128 // On 10.10 and up, this is the case even when building against the 10.7 SDK
130 return !nsCocoaFeatures::OnYosemiteOrLater();
135 DrawCellIncludingFocusRing(NSCell* aCell, NSRect aWithFrame, NSView* aInView)
137 [aCell drawWithFrame:aWithFrame inView:aInView];
139 if (!FocusIsDrawnByDrawWithFrame()) {
140 DrawFocusRingForCellIfNeeded(aCell, aWithFrame, aInView);
145 * NSProgressBarCell is used to draw progress bars of any size.
147 @interface NSProgressBarCell : NSCell
149 /*All instance variables are private*/
152 bool mIsIndeterminate;
156 - (void)setValue:(double)value;
158 - (void)setMax:(double)max;
160 - (void)setIndeterminate:(bool)aIndeterminate;
161 - (bool)isIndeterminate;
162 - (void)setHorizontal:(bool)aIsHorizontal;
163 - (bool)isHorizontal;
164 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;
167 @implementation NSProgressBarCell
169 - (void)setMax:(double)aMax
179 - (void)setValue:(double)aValue
189 - (void)setIndeterminate:(bool)aIndeterminate
191 mIsIndeterminate = aIndeterminate;
194 - (bool)isIndeterminate
196 return mIsIndeterminate;
199 - (void)setHorizontal:(bool)aIsHorizontal
201 mIsHorizontal = aIsHorizontal;
206 return mIsHorizontal;
209 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
211 CGContext* cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
213 HIThemeTrackDrawInfo tdi;
218 tdi.value = INT32_MAX * (mValue / mMax);
220 tdi.bounds = NSRectToCGRect(cellFrame);
221 tdi.attributes = mIsHorizontal ? kThemeTrackHorizontal : 0;
222 tdi.enableState = [self controlTint] == NSClearControlTint ? kThemeTrackInactive
225 NSControlSize size = [self controlSize];
226 if (size == NSRegularControlSize) {
227 tdi.kind = mIsIndeterminate ? kThemeLargeIndeterminateBar
228 : kThemeLargeProgressBar;
230 NS_ASSERTION(size == NSSmallControlSize,
231 "We shouldn't have another size than small and regular for the moment");
232 tdi.kind = mIsIndeterminate ? kThemeMediumIndeterminateBar
233 : kThemeMediumProgressBar;
236 int32_t stepsPerSecond = mIsIndeterminate ? 60 : 30;
237 int32_t milliSecondsPerStep = 1000 / stepsPerSecond;
238 tdi.trackInfo.progress.phase = uint8_t(PR_IntervalToMilliseconds(PR_IntervalNow()) /
239 milliSecondsPerStep);
241 HIThemeDrawTrack(&tdi, NULL, cgContext, kHIThemeOrientationNormal);
246 @interface ContextAwareSearchFieldCell : NSSearchFieldCell
251 // setContext: stores the searchfield nsIFrame so that it can be consulted
252 // during painting. Please reset this by calling setContext:nullptr as soon as
253 // you're done with painting because we don't want to keep a dangling pointer.
254 - (void)setContext:(nsIFrame*)aContext;
257 @implementation ContextAwareSearchFieldCell
259 - (id)initTextCell:(NSString*)aString
261 if ((self = [super initTextCell:aString])) {
267 - (void)setContext:(nsIFrame*)aContext
272 static BOOL IsToolbarStyleContainer(nsIFrame* aFrame)
274 nsIContent* content = aFrame->GetContent();
278 if (content->Tag() == nsGkAtoms::toolbar ||
279 content->Tag() == nsGkAtoms::toolbox ||
280 content->Tag() == nsGkAtoms::statusbar)
283 switch (aFrame->StyleDisplay()->mAppearance) {
284 case NS_THEME_TOOLBAR:
285 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
286 case NS_THEME_STATUSBAR:
293 - (BOOL)_isToolbarMode
295 // On 10.7, searchfields have two different styles, depending on whether
296 // the searchfield is on top of of window chrome. This function is called on
297 // 10.7 during drawing in order to determine which style to use.
298 for (nsIFrame* frame = mContext; frame; frame = frame->GetParent()) {
299 if (IsToolbarStyleContainer(frame)) {
308 // Workaround for Bug 542048
309 // On 64-bit, NSSearchFieldCells don't draw focus rings.
310 #if defined(__x86_64__)
312 @interface SearchFieldCellWithFocusRing : ContextAwareSearchFieldCell {} @end
314 @implementation SearchFieldCellWithFocusRing
316 - (void)drawWithFrame:(NSRect)rect inView:(NSView*)controlView
318 [super drawWithFrame:rect inView:controlView];
320 if (FocusIsDrawnByDrawWithFrame()) {
321 DrawFocusRingForCellIfNeeded(self, rect, controlView);
325 - (void)drawFocusRingMaskWithFrame:(NSRect)rect inView:(NSView*)controlView
327 // By default this draws nothing. I don't know why.
328 // We just draw the search field again. It's a great mask shape for its own
330 [super drawWithFrame:rect inView:controlView];
337 #define HITHEME_ORIENTATION kHIThemeOrientationNormal
338 #define MAX_FOCUS_RING_WIDTH 4
340 // These enums are for indexing into the margin array.
358 static int EnumSizeForCocoaSize(NSControlSize cocoaControlSize) {
359 if (cocoaControlSize == NSMiniControlSize)
360 return miniControlSize;
361 else if (cocoaControlSize == NSSmallControlSize)
362 return smallControlSize;
364 return regularControlSize;
367 static NSControlSize CocoaSizeForEnum(int32_t enumControlSize) {
368 if (enumControlSize == miniControlSize)
369 return NSMiniControlSize;
370 else if (enumControlSize == smallControlSize)
371 return NSSmallControlSize;
373 return NSRegularControlSize;
376 static NSString* CUIControlSizeForCocoaSize(NSControlSize aControlSize)
378 if (aControlSize == NSRegularControlSize)
380 else if (aControlSize == NSSmallControlSize)
386 static void InflateControlRect(NSRect* rect, NSControlSize cocoaControlSize, const float marginSet[][3][4])
391 static int osIndex = leopardOS;
392 int controlSize = EnumSizeForCocoaSize(cocoaControlSize);
393 const float* buttonMargins = marginSet[osIndex][controlSize];
394 rect->origin.x -= buttonMargins[leftMargin];
395 rect->origin.y -= buttonMargins[bottomMargin];
396 rect->size.width += buttonMargins[leftMargin] + buttonMargins[rightMargin];
397 rect->size.height += buttonMargins[bottomMargin] + buttonMargins[topMargin];
400 static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
401 nsIWidget** aTopLevelWidget = NULL)
406 nsIWidget* widget = aFrame->GetNearestWidget();
410 nsIWidget* topLevelWidget = widget->GetTopLevelWidget();
412 *aTopLevelWidget = topLevelWidget;
414 return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
418 WindowButtonsSize(nsIFrame* aFrame)
420 NSWindow* window = NativeWindowForFrame(aFrame);
422 // Return fallback values.
423 if (!nsCocoaFeatures::OnLionOrLater())
424 return NSMakeSize(57, 16);
425 return NSMakeSize(54, 16);
428 NSRect buttonBox = NSZeroRect;
429 NSButton* closeButton = [window standardWindowButton:NSWindowCloseButton];
431 buttonBox = NSUnionRect(buttonBox, [closeButton frame]);
433 NSButton* minimizeButton = [window standardWindowButton:NSWindowMiniaturizeButton];
434 if (minimizeButton) {
435 buttonBox = NSUnionRect(buttonBox, [minimizeButton frame]);
437 NSButton* zoomButton = [window standardWindowButton:NSWindowZoomButton];
439 buttonBox = NSUnionRect(buttonBox, [zoomButton frame]);
441 return buttonBox.size;
444 static BOOL FrameIsInActiveWindow(nsIFrame* aFrame)
446 nsIWidget* topLevelWidget = NULL;
447 NSWindow* win = NativeWindowForFrame(aFrame, &topLevelWidget);
448 if (!topLevelWidget || !win)
451 // XUL popups, e.g. the toolbar customization popup, can't become key windows,
452 // but controls in these windows should still get the active look.
453 if (topLevelWidget->WindowType() == eWindowType_popup)
456 return [win isKeyWindow];
457 return [win isMainWindow] && ![win attachedSheet];
460 // Toolbar controls and content controls respond to different window
461 // activeness states.
462 static BOOL IsActive(nsIFrame* aFrame, BOOL aIsToolbarControl)
464 if (aIsToolbarControl)
465 return [NativeWindowForFrame(aFrame) isMainWindow];
466 return FrameIsInActiveWindow(aFrame);
469 NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeCocoa, nsNativeTheme, nsITheme)
472 nsNativeThemeCocoa::nsNativeThemeCocoa()
474 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
476 // provide a local autorelease pool, as this is called during startup
477 // before the main event-loop pool is in place
478 nsAutoreleasePool pool;
480 mHelpButtonCell = [[NSButtonCell alloc] initTextCell:nil];
481 [mHelpButtonCell setBezelStyle:NSHelpButtonBezelStyle];
482 [mHelpButtonCell setButtonType:NSMomentaryPushInButton];
483 [mHelpButtonCell setHighlightsBy:NSPushInCellMask];
485 mPushButtonCell = [[NSButtonCell alloc] initTextCell:nil];
486 [mPushButtonCell setButtonType:NSMomentaryPushInButton];
487 [mPushButtonCell setHighlightsBy:NSPushInCellMask];
489 mRadioButtonCell = [[NSButtonCell alloc] initTextCell:nil];
490 [mRadioButtonCell setButtonType:NSRadioButton];
492 mCheckboxCell = [[NSButtonCell alloc] initTextCell:nil];
493 [mCheckboxCell setButtonType:NSSwitchButton];
494 [mCheckboxCell setAllowsMixedState:YES];
496 #if defined(__x86_64__)
497 mSearchFieldCell = [[SearchFieldCellWithFocusRing alloc] initTextCell:@""];
499 mSearchFieldCell = [[ContextAwareSearchFieldCell alloc] initTextCell:@""];
501 [mSearchFieldCell setBezelStyle:NSTextFieldRoundedBezel];
502 [mSearchFieldCell setBezeled:YES];
503 [mSearchFieldCell setEditable:YES];
504 [mSearchFieldCell setFocusRingType:NSFocusRingTypeExterior];
506 mDropdownCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
508 mComboBoxCell = [[NSComboBoxCell alloc] initTextCell:@""];
509 [mComboBoxCell setBezeled:YES];
510 [mComboBoxCell setEditable:YES];
511 [mComboBoxCell setFocusRingType:NSFocusRingTypeExterior];
513 mProgressBarCell = [[NSProgressBarCell alloc] init];
515 mMeterBarCell = [[NSLevelIndicatorCell alloc]
516 initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle];
518 mCellDrawView = [[CellDrawView alloc] init];
520 NS_OBJC_END_TRY_ABORT_BLOCK;
523 nsNativeThemeCocoa::~nsNativeThemeCocoa()
525 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
527 [mMeterBarCell release];
528 [mProgressBarCell release];
529 [mHelpButtonCell release];
530 [mPushButtonCell release];
531 [mRadioButtonCell release];
532 [mCheckboxCell release];
533 [mSearchFieldCell release];
534 [mDropdownCell release];
535 [mComboBoxCell release];
536 [mCellDrawView release];
538 NS_OBJC_END_TRY_ABORT_BLOCK;
541 // Limit on the area of the target rect (in pixels^2) in
542 // DrawCellWithScaling(), DrawButton() and DrawScrollbar(), above which we
543 // don't draw the object into a bitmap buffer. This is to avoid crashes in
544 // [NSGraphicsContext graphicsContextWithGraphicsPort:flipped:] and
545 // CGContextDrawImage(), and also to avoid very poor drawing performance in
546 // CGContextDrawImage() when it scales the bitmap (particularly if xscale or
547 // yscale is less than but near 1 -- e.g. 0.9). This value was determined
548 // by trial and error, on OS X 10.4.11 and 10.5.4, and on systems with
549 // different amounts of RAM.
550 #define BITMAP_MAX_AREA 500000
553 GetBackingScaleFactorForRendering(CGContextRef cgContext)
555 CGAffineTransform ctm = CGContextGetUserSpaceToDeviceSpaceTransform(cgContext);
556 CGRect transformedUserSpacePixel = CGRectApplyAffineTransform(CGRectMake(0, 0, 1, 1), ctm);
557 float maxScale = std::max(fabs(transformedUserSpacePixel.size.width),
558 fabs(transformedUserSpacePixel.size.height));
559 return maxScale > 1.0 ? 2 : 1;
563 * Draw the given NSCell into the given cgContext.
565 * destRect - the size and position of the resulting control rectangle
566 * controlSize - the NSControlSize which will be given to the NSCell before
567 * asking it to render
568 * naturalSize - The natural dimensions of this control.
569 * If the control rect size is not equal to either of these, a scale
570 * will be applied to the context so that rendering the control at the
571 * natural size will result in it filling the destRect space.
572 * If a control has no natural dimensions in either/both axes, pass 0.0f.
573 * minimumSize - The minimum dimensions of this control.
574 * If the control rect size is less than the minimum for a given axis,
575 * a scale will be applied to the context so that the minimum is used
576 * for drawing. If a control has no minimum dimensions in either/both
578 * marginSet - an array of margins; a multidimensional array of [2][3][4],
579 * with the first dimension being the OS version (Tiger or Leopard),
580 * the second being the control size (mini, small, regular), and the third
581 * being the 4 margin values (left, top, right, bottom).
582 * view - The NSView that we're drawing into. As far as I can tell, it doesn't
583 * matter if this is really the right view; it just has to return YES when
584 * asked for isFlipped. Otherwise we'll get drawing bugs on 10.4.
585 * mirrorHorizontal - whether to mirror the cell horizontally
587 static void DrawCellWithScaling(NSCell *cell,
588 CGContextRef cgContext,
589 const HIRect& destRect,
590 NSControlSize controlSize,
593 const float marginSet[][3][4],
595 BOOL mirrorHorizontal)
597 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
599 NSRect drawRect = NSMakeRect(destRect.origin.x, destRect.origin.y, destRect.size.width, destRect.size.height);
601 if (naturalSize.width != 0.0f)
602 drawRect.size.width = naturalSize.width;
603 if (naturalSize.height != 0.0f)
604 drawRect.size.height = naturalSize.height;
606 // Keep aspect ratio when scaling if one dimension is free.
607 if (naturalSize.width == 0.0f && naturalSize.height != 0.0f)
608 drawRect.size.width = destRect.size.width * naturalSize.height / destRect.size.height;
609 if (naturalSize.height == 0.0f && naturalSize.width != 0.0f)
610 drawRect.size.height = destRect.size.height * naturalSize.width / destRect.size.width;
612 // Honor minimum sizes.
613 if (drawRect.size.width < minimumSize.width)
614 drawRect.size.width = minimumSize.width;
615 if (drawRect.size.height < minimumSize.height)
616 drawRect.size.height = minimumSize.height;
618 [NSGraphicsContext saveGraphicsState];
620 // Only skip the buffer if the area of our cell (in pixels^2) is too large.
621 if (drawRect.size.width * drawRect.size.height > BITMAP_MAX_AREA) {
622 // Inflate the rect Gecko gave us by the margin for the control.
623 InflateControlRect(&drawRect, controlSize, marginSet);
625 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
626 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]];
628 DrawCellIncludingFocusRing(cell, drawRect, view);
630 [NSGraphicsContext setCurrentContext:savedContext];
633 float w = ceil(drawRect.size.width);
634 float h = ceil(drawRect.size.height);
635 NSRect tmpRect = NSMakeRect(MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH, w, h);
637 // inflate to figure out the frame we need to tell NSCell to draw in, to get something that's 0,0,w,h
638 InflateControlRect(&tmpRect, controlSize, marginSet);
640 // and then, expand by MAX_FOCUS_RING_WIDTH size to make sure we can capture any focus ring
641 w += MAX_FOCUS_RING_WIDTH * 2.0;
642 h += MAX_FOCUS_RING_WIDTH * 2.0;
644 int backingScaleFactor = GetBackingScaleFactorForRendering(cgContext);
645 CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
646 CGContextRef ctx = CGBitmapContextCreate(NULL,
647 (int) w * backingScaleFactor, (int) h * backingScaleFactor,
648 8, (int) w * backingScaleFactor * 4,
649 rgb, kCGImageAlphaPremultipliedFirst);
650 CGColorSpaceRelease(rgb);
652 // We need to flip the image twice in order to avoid drawing bugs on 10.4, see bug 465069.
653 // This is the first flip transform, applied to cgContext.
654 CGContextScaleCTM(cgContext, 1.0f, -1.0f);
655 CGContextTranslateCTM(cgContext, 0.0f, -(2.0 * destRect.origin.y + destRect.size.height));
656 if (mirrorHorizontal) {
657 CGContextScaleCTM(cgContext, -1.0f, 1.0f);
658 CGContextTranslateCTM(cgContext, -(2.0 * destRect.origin.x + destRect.size.width), 0.0f);
661 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
662 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];
664 CGContextScaleCTM(ctx, backingScaleFactor, backingScaleFactor);
666 // This is the second flip transform, applied to ctx.
667 CGContextScaleCTM(ctx, 1.0f, -1.0f);
668 CGContextTranslateCTM(ctx, 0.0f, -(2.0 * tmpRect.origin.y + tmpRect.size.height));
670 DrawCellIncludingFocusRing(cell, tmpRect, view);
672 [NSGraphicsContext setCurrentContext:savedContext];
674 CGImageRef img = CGBitmapContextCreateImage(ctx);
676 // Drop the image into the original destination rectangle, scaling to fit
677 // Only scale MAX_FOCUS_RING_WIDTH by xscale/yscale when the resulting rect
678 // doesn't extend beyond the overflow rect
679 float xscale = destRect.size.width / drawRect.size.width;
680 float yscale = destRect.size.height / drawRect.size.height;
681 float scaledFocusRingX = xscale < 1.0f ? MAX_FOCUS_RING_WIDTH * xscale : MAX_FOCUS_RING_WIDTH;
682 float scaledFocusRingY = yscale < 1.0f ? MAX_FOCUS_RING_WIDTH * yscale : MAX_FOCUS_RING_WIDTH;
683 CGContextDrawImage(cgContext, CGRectMake(destRect.origin.x - scaledFocusRingX,
684 destRect.origin.y - scaledFocusRingY,
685 destRect.size.width + scaledFocusRingX * 2,
686 destRect.size.height + scaledFocusRingY * 2),
690 CGContextRelease(ctx);
693 [NSGraphicsContext restoreGraphicsState];
695 #if DRAW_IN_FRAME_DEBUG
696 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
697 CGContextFillRect(cgContext, destRect);
700 NS_OBJC_END_TRY_ABORT_BLOCK;
703 struct CellRenderSettings {
704 // The natural dimensions of the control.
705 // If a control has no natural dimensions in either/both axes, set to 0.0f.
706 NSSize naturalSizes[3];
708 // The minimum dimensions of the control.
709 // If a control has no minimum dimensions in either/both axes, set to 0.0f.
710 NSSize minimumSizes[3];
712 // A three-dimensional array,
713 // with the first dimension being the OS version (only Leopard for the moment),
714 // the second being the control size (mini, small, regular), and the third
715 // being the 4 margin values (left, top, right, bottom).
716 float margins[1][3][4];
720 * This is a helper method that returns the required NSControlSize given a size
721 * and the size of the three controls plus a tolerance.
722 * size - The width or the height of the element to draw.
723 * sizes - An array with the all the width/height of the element for its
725 * tolerance - The tolerance as passed to DrawCellWithSnapping.
726 * NOTE: returns NSRegularControlSize if all values in 'sizes' are zero.
728 static NSControlSize FindControlSize(CGFloat size, const CGFloat* sizes, CGFloat tolerance)
730 for (uint32_t i = miniControlSize; i <= regularControlSize; ++i) {
737 for (uint32_t j = i+1; j <= regularControlSize; ++j) {
744 // If it's the latest value, we pick it.
746 return CocoaSizeForEnum(i);
749 if (size <= sizes[i] + tolerance && size < next) {
750 return CocoaSizeForEnum(i);
754 // If we are here, that means sizes[] was an array with only empty values
755 // or the algorithm above is wrong.
756 // The former can happen but the later would be wrong.
757 NS_ASSERTION(sizes[0] == 0 && sizes[1] == 0 && sizes[2] == 0,
758 "We found no control! We shouldn't be there!");
759 return CocoaSizeForEnum(regularControlSize);
763 * Draw the given NSCell into the given cgContext with a nice control size.
765 * This function is similar to DrawCellWithScaling, but it decides what
766 * control size to use based on the destRect's size.
767 * Scaling is only applied when the difference between the destRect's size
768 * and the next smaller natural size is greater than snapTolerance. Otherwise
769 * it snaps to the next smaller control size without scaling because unscaled
770 * controls look nicer.
772 static void DrawCellWithSnapping(NSCell *cell,
773 CGContextRef cgContext,
774 const HIRect& destRect,
775 const CellRenderSettings settings,
776 float verticalAlignFactor,
778 BOOL mirrorHorizontal,
779 float snapTolerance = 2.0f)
781 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
783 const float rectWidth = destRect.size.width, rectHeight = destRect.size.height;
784 const NSSize *sizes = settings.naturalSizes;
785 const NSSize miniSize = sizes[EnumSizeForCocoaSize(NSMiniControlSize)];
786 const NSSize smallSize = sizes[EnumSizeForCocoaSize(NSSmallControlSize)];
787 const NSSize regularSize = sizes[EnumSizeForCocoaSize(NSRegularControlSize)];
789 HIRect drawRect = destRect;
791 CGFloat controlWidths[3] = { miniSize.width, smallSize.width, regularSize.width };
792 NSControlSize controlSizeX = FindControlSize(rectWidth, controlWidths, snapTolerance);
793 CGFloat controlHeights[3] = { miniSize.height, smallSize.height, regularSize.height };
794 NSControlSize controlSizeY = FindControlSize(rectHeight, controlHeights, snapTolerance);
796 NSControlSize controlSize = NSRegularControlSize;
799 // At some sizes, don't scale but snap.
800 const NSControlSize smallerControlSize =
801 EnumSizeForCocoaSize(controlSizeX) < EnumSizeForCocoaSize(controlSizeY) ?
802 controlSizeX : controlSizeY;
803 const int smallerControlSizeIndex = EnumSizeForCocoaSize(smallerControlSize);
804 const NSSize size = sizes[smallerControlSizeIndex];
805 float diffWidth = size.width ? rectWidth - size.width : 0.0f;
806 float diffHeight = size.height ? rectHeight - size.height : 0.0f;
807 if (diffWidth >= 0.0f && diffHeight >= 0.0f &&
808 diffWidth <= snapTolerance && diffHeight <= snapTolerance) {
809 // Snap to the smaller control size.
810 controlSize = smallerControlSize;
811 sizeIndex = smallerControlSizeIndex;
812 // Resize and center the drawRect.
813 if (sizes[sizeIndex].width) {
814 drawRect.origin.x += ceil((destRect.size.width - sizes[sizeIndex].width) / 2);
815 drawRect.size.width = sizes[sizeIndex].width;
817 if (sizes[sizeIndex].height) {
818 drawRect.origin.y += floor((destRect.size.height - sizes[sizeIndex].height) * verticalAlignFactor);
819 drawRect.size.height = sizes[sizeIndex].height;
822 // Use the larger control size.
823 controlSize = EnumSizeForCocoaSize(controlSizeX) > EnumSizeForCocoaSize(controlSizeY) ?
824 controlSizeX : controlSizeY;
825 sizeIndex = EnumSizeForCocoaSize(controlSize);
828 [cell setControlSize:controlSize];
830 NSSize minimumSize = settings.minimumSizes ? settings.minimumSizes[sizeIndex] : NSZeroSize;
831 DrawCellWithScaling(cell, cgContext, drawRect, controlSize, sizes[sizeIndex],
832 minimumSize, settings.margins, view, mirrorHorizontal);
834 NS_OBJC_END_TRY_ABORT_BLOCK;
837 @interface NSWindow(CoreUIRendererPrivate)
838 + (CUIRendererRef)coreUIRenderer;
842 RenderWithCoreUILegacy(CGRect aRect, CGContextRef cgContext, NSDictionary* aOptions)
844 if (aRect.size.width * aRect.size.height <= BITMAP_MAX_AREA) {
845 CUIRendererRef renderer = [NSWindow respondsToSelector:@selector(coreUIRenderer)]
846 ? [NSWindow coreUIRenderer] : nil;
847 CUIDraw(renderer, aRect, cgContext, (CFDictionaryRef)aOptions, NULL);
854 // We only need NSAppearance on 10.10 and up.
855 if (nsCocoaFeatures::OnYosemiteOrLater()) {
856 Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
857 if (NSAppearanceClass &&
858 [NSAppearanceClass respondsToSelector:@selector(appearanceNamed:)]) {
859 return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
860 withObject:@"NSAppearanceNameAqua"];
866 @interface NSObject(NSAppearanceCoreUIRendering)
867 - (void)_drawInRect:(CGRect)rect context:(CGContextRef)cgContext options:(id)options;
871 RenderWithCoreUI(CGRect aRect, CGContextRef cgContext, NSDictionary* aOptions)
873 id appearance = GetAquaAppearance();
875 if (aRect.size.width * aRect.size.height > BITMAP_MAX_AREA) {
879 if (appearance && [appearance respondsToSelector:@selector(_drawInRect:context:options:)]) {
880 // Render through NSAppearance on Mac OS 10.10 and up. This will call
881 // CUIDraw with a CoreUI renderer that will give us the correct 10.10
882 // style. Calling CUIDraw directly with [NSWindow coreUIRenderer] still
883 // renders 10.9-style widgets on 10.10.
884 [appearance _drawInRect:aRect context:cgContext options:aOptions];
887 RenderWithCoreUILegacy(aRect, cgContext, aOptions);
891 static float VerticalAlignFactor(nsIFrame *aFrame)
894 return 0.5f; // default: center
896 const nsStyleCoord& va = aFrame->StyleTextReset()->mVerticalAlign;
897 uint8_t intval = (va.GetUnit() == eStyleUnit_Enumerated)
899 : NS_STYLE_VERTICAL_ALIGN_MIDDLE;
901 case NS_STYLE_VERTICAL_ALIGN_TOP:
902 case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
905 case NS_STYLE_VERTICAL_ALIGN_SUB:
906 case NS_STYLE_VERTICAL_ALIGN_SUPER:
907 case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
908 case NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE:
911 case NS_STYLE_VERTICAL_ALIGN_BASELINE:
912 case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
913 case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
917 NS_NOTREACHED("invalid vertical-align");
922 // These are the sizes that Gecko needs to request to draw if it wants
923 // to get a standard-sized Aqua radio button drawn. Note that the rects
924 // that draw these are actually a little bigger.
925 static const CellRenderSettings radioSettings = {
927 NSMakeSize(11, 11), // mini
928 NSMakeSize(13, 13), // small
929 NSMakeSize(16, 16) // regular
932 NSZeroSize, NSZeroSize, NSZeroSize
936 {0, 0, 0, 0}, // mini
937 {0, 1, 1, 1}, // small
938 {0, 0, 0, 0} // regular
943 static const CellRenderSettings checkboxSettings = {
945 NSMakeSize(11, 11), // mini
946 NSMakeSize(13, 13), // small
947 NSMakeSize(16, 16) // regular
950 NSZeroSize, NSZeroSize, NSZeroSize
954 {0, 1, 0, 0}, // mini
955 {0, 1, 0, 1}, // small
956 {0, 1, 0, 1} // regular
962 nsNativeThemeCocoa::DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox,
963 const HIRect& inBoxRect, bool inSelected,
964 EventStates inState, nsIFrame* aFrame)
966 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
968 NSButtonCell *cell = inCheckbox ? mCheckboxCell : mRadioButtonCell;
969 NSCellStateValue state = inSelected ? NSOnState : NSOffState;
971 // Check if we have an indeterminate checkbox
972 if (inCheckbox && GetIndeterminate(aFrame))
973 state = NSMixedState;
975 [cell setEnabled:!IsDisabled(aFrame, inState)];
976 [cell setShowsFirstResponder:inState.HasState(NS_EVENT_STATE_FOCUS)];
977 [cell setState:state];
978 [cell setHighlighted:inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)];
979 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
981 // Ensure that the control is square.
982 float length = std::min(inBoxRect.size.width, inBoxRect.size.height);
983 HIRect drawRect = CGRectMake(inBoxRect.origin.x + (int)((inBoxRect.size.width - length) / 2.0f),
984 inBoxRect.origin.y + (int)((inBoxRect.size.height - length) / 2.0f),
987 DrawCellWithSnapping(cell, cgContext, drawRect,
988 inCheckbox ? checkboxSettings : radioSettings,
989 VerticalAlignFactor(aFrame), mCellDrawView, NO);
991 NS_OBJC_END_TRY_ABORT_BLOCK;
994 static const CellRenderSettings searchFieldSettings = {
996 NSMakeSize(0, 16), // mini
997 NSMakeSize(0, 19), // small
998 NSMakeSize(0, 22) // regular
1001 NSMakeSize(32, 0), // mini
1002 NSMakeSize(38, 0), // small
1003 NSMakeSize(44, 0) // regular
1007 {0, 0, 0, 0}, // mini
1008 {0, 0, 0, 0}, // small
1009 {0, 0, 0, 0} // regular
1015 nsNativeThemeCocoa::DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
1016 nsIFrame* aFrame, EventStates inState)
1018 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1020 ContextAwareSearchFieldCell* cell = mSearchFieldCell;
1021 [cell setContext:aFrame];
1022 [cell setEnabled:!IsDisabled(aFrame, inState)];
1023 // NOTE: this could probably use inState
1024 [cell setShowsFirstResponder:IsFocused(aFrame)];
1026 DrawCellWithSnapping(cell, cgContext, inBoxRect, searchFieldSettings,
1027 VerticalAlignFactor(aFrame), mCellDrawView,
1028 IsFrameRTL(aFrame));
1030 [cell setContext:nullptr];
1032 NS_OBJC_END_TRY_ABORT_BLOCK;
1035 static const NSSize kCheckmarkSize = NSMakeSize(11, 11);
1036 static const NSString* kCheckmarkImage = @"image.MenuOnState";
1037 static const CGFloat kMenuIconIndent = 6.0f;
1040 nsNativeThemeCocoa::DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
1041 EventStates inState, nsIFrame* aFrame,
1042 const NSSize& aIconSize, const NSString* aImageName)
1044 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1046 // Adjust size and position of our drawRect.
1047 CGFloat paddingX = std::max(CGFloat(0.0), aRect.size.width - aIconSize.width);
1048 CGFloat paddingY = std::max(CGFloat(0.0), aRect.size.height - aIconSize.height);
1049 CGFloat paddingStartX = std::min(paddingX, kMenuIconIndent);
1050 CGFloat paddingEndX = std::max(CGFloat(0.0), paddingX - kMenuIconIndent);
1051 CGRect drawRect = CGRectMake(
1052 aRect.origin.x + (IsFrameRTL(aFrame) ? paddingEndX : paddingStartX),
1053 aRect.origin.y + ceil(paddingY / 2),
1054 aIconSize.width, aIconSize.height);
1056 BOOL isDisabled = IsDisabled(aFrame, inState);
1057 BOOL isActive = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
1059 // On 10.6 and at least on 10.7.0, Apple doesn’t seem to have implemented all
1060 // keys and values used on 10.7.5 and later. We can however draw menu icons
1061 // on earlier OS versions by using different keys/values.
1062 BOOL otherKeysAndValues = !nsCocoaFeatures::OnLionOrLater() ||
1063 (nsCocoaFeatures::OSXVersionMajor() == 10 &&
1064 nsCocoaFeatures::OSXVersionMinor() == 7 &&
1065 nsCocoaFeatures::OSXVersionBugFix() < 5);
1067 // 2 states combined with 2 different backgroundTypeKeys on earlier versions.
1068 NSString* state = isDisabled ? @"disabled" :
1069 (isActive && !otherKeysAndValues) ? @"pressed" : @"normal";
1070 NSString* backgroundTypeKey = !otherKeysAndValues ? @"kCUIBackgroundTypeMenu" :
1071 !isDisabled && isActive ? @"backgroundTypeDark" : @"backgroundTypeLight";
1073 NSMutableArray* keys = [NSMutableArray arrayWithObjects:@"backgroundTypeKey",
1074 @"imageNameKey", @"state", @"widget", @"is.flipped", nil];
1075 NSMutableArray* values = [NSMutableArray arrayWithObjects: backgroundTypeKey,
1076 aImageName, state, @"image", [NSNumber numberWithBool:YES], nil];
1078 if (otherKeysAndValues) { // Earlier versions used one more key-value pair.
1079 [keys insertObject:@"imageIsGrayscaleKey" atIndex:1];
1080 [values insertObject:[NSNumber numberWithBool:YES] atIndex:1];
1083 RenderWithCoreUI(drawRect, cgContext,
1084 [NSDictionary dictionaryWithObjects:values
1087 #if DRAW_IN_FRAME_DEBUG
1088 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
1089 CGContextFillRect(cgContext, drawRect);
1092 NS_OBJC_END_TRY_ABORT_BLOCK;
1095 static const NSSize kHelpButtonSize = NSMakeSize(20, 20);
1097 static const CellRenderSettings pushButtonSettings = {
1099 NSMakeSize(0, 16), // mini
1100 NSMakeSize(0, 19), // small
1101 NSMakeSize(0, 22) // regular
1104 NSMakeSize(18, 0), // mini
1105 NSMakeSize(26, 0), // small
1106 NSMakeSize(30, 0) // regular
1110 {0, 0, 0, 0}, // mini
1111 {4, 0, 4, 1}, // small
1112 {5, 0, 5, 2} // regular
1117 // The height at which we start doing square buttons instead of rounded buttons
1118 // Rounded buttons look bad if drawn at a height greater than 26, so at that point
1119 // we switch over to doing square buttons which looks fine at any size.
1120 #define DO_SQUARE_BUTTON_HEIGHT 26
1123 nsNativeThemeCocoa::DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
1124 EventStates inState, uint8_t aWidgetType,
1127 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1129 BOOL isActive = FrameIsInActiveWindow(aFrame);
1130 BOOL isDisabled = IsDisabled(aFrame, inState);
1132 NSButtonCell* cell = (aWidgetType == NS_THEME_MOZ_MAC_HELP_BUTTON) ? mHelpButtonCell : mPushButtonCell;
1133 [cell setEnabled:!isDisabled];
1134 [cell setHighlighted:isActive &&
1135 inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)];
1136 [cell setShowsFirstResponder:inState.HasState(NS_EVENT_STATE_FOCUS) && !isDisabled && isActive];
1138 if (aWidgetType == NS_THEME_MOZ_MAC_HELP_BUTTON) {
1139 DrawCellWithScaling(cell, cgContext, inBoxRect, NSRegularControlSize,
1140 NSZeroSize, kHelpButtonSize, NULL, mCellDrawView,
1141 false); // Don't mirror icon in RTL.
1143 // If the button is tall enough, draw the square button style so that
1144 // buttons with non-standard content look good. Otherwise draw normal
1145 // rounded aqua buttons.
1146 if (inBoxRect.size.height > DO_SQUARE_BUTTON_HEIGHT) {
1147 [cell setBezelStyle:NSShadowlessSquareBezelStyle];
1148 DrawCellWithScaling(cell, cgContext, inBoxRect, NSRegularControlSize,
1149 NSZeroSize, NSMakeSize(14, 0), NULL, mCellDrawView,
1150 IsFrameRTL(aFrame));
1152 [cell setBezelStyle:NSRoundedBezelStyle];
1153 DrawCellWithSnapping(cell, cgContext, inBoxRect, pushButtonSettings, 0.5f,
1154 mCellDrawView, IsFrameRTL(aFrame), 1.0f);
1158 #if DRAW_IN_FRAME_DEBUG
1159 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
1160 CGContextFillRect(cgContext, inBoxRect);
1163 NS_OBJC_END_TRY_ABORT_BLOCK;
1167 nsNativeThemeCocoa::DrawFocusOutline(CGContextRef cgContext, const HIRect& inBoxRect,
1168 EventStates inState, uint8_t aWidgetType,
1171 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1173 HIThemeFrameDrawInfo fdi;
1175 fdi.kind = kHIThemeFrameTextFieldSquare;
1176 fdi.state = kThemeStateActive;
1177 fdi.isFocused = TRUE;
1179 #if DRAW_IN_FRAME_DEBUG
1180 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
1181 CGContextFillRect(cgContext, inBoxRect);
1184 HIThemeDrawFrame(&inBoxRect, &fdi, cgContext, HITHEME_ORIENTATION);
1186 NS_OBJC_END_TRY_ABORT_BLOCK;
1189 typedef void (*RenderHIThemeControlFunction)(CGContextRef cgContext, const HIRect& aRenderRect, void* aData);
1192 RenderTransformedHIThemeControl(CGContextRef aCGContext, const HIRect& aRect,
1193 RenderHIThemeControlFunction aFunc, void* aData,
1194 BOOL mirrorHorizontally = NO)
1196 CGAffineTransform savedCTM = CGContextGetCTM(aCGContext);
1197 CGContextTranslateCTM(aCGContext, aRect.origin.x, aRect.origin.y);
1200 HIRect drawRect = aRect;
1201 drawRect.origin = CGPointZero;
1203 if (!mirrorHorizontally && savedCTM.a == 1.0f && savedCTM.b == 0.0f &&
1204 savedCTM.c == 0.0f && (savedCTM.d == 1.0f || savedCTM.d == -1.0f)) {
1210 // Fall back to no bitmap buffer if the area of our control (in pixels^2)
1212 if (drawDirect || (aRect.size.width * aRect.size.height > BITMAP_MAX_AREA)) {
1213 aFunc(aCGContext, drawRect, aData);
1215 // Inflate the buffer to capture focus rings.
1216 int w = ceil(drawRect.size.width) + 2 * MAX_FOCUS_RING_WIDTH;
1217 int h = ceil(drawRect.size.height) + 2 * MAX_FOCUS_RING_WIDTH;
1219 int backingScaleFactor = GetBackingScaleFactorForRendering(aCGContext);
1220 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
1221 CGContextRef bitmapctx = CGBitmapContextCreate(NULL,
1222 w * backingScaleFactor,
1223 h * backingScaleFactor,
1225 w * backingScaleFactor * 4,
1227 kCGImageAlphaPremultipliedFirst);
1228 CGColorSpaceRelease(colorSpace);
1230 CGContextScaleCTM(bitmapctx, backingScaleFactor, backingScaleFactor);
1231 CGContextTranslateCTM(bitmapctx, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH);
1233 // HITheme always wants to draw into a flipped context, or things
1235 CGContextTranslateCTM(bitmapctx, 0.0f, aRect.size.height);
1236 CGContextScaleCTM(bitmapctx, 1.0f, -1.0f);
1238 aFunc(bitmapctx, drawRect, aData);
1240 CGImageRef bitmap = CGBitmapContextCreateImage(bitmapctx);
1242 CGAffineTransform ctm = CGContextGetCTM(aCGContext);
1244 // We need to unflip, so that we can do a DrawImage without getting a flipped image.
1245 CGContextTranslateCTM(aCGContext, 0.0f, aRect.size.height);
1246 CGContextScaleCTM(aCGContext, 1.0f, -1.0f);
1248 if (mirrorHorizontally) {
1249 CGContextTranslateCTM(aCGContext, aRect.size.width, 0);
1250 CGContextScaleCTM(aCGContext, -1.0f, 1.0f);
1253 HIRect inflatedDrawRect = CGRectMake(-MAX_FOCUS_RING_WIDTH, -MAX_FOCUS_RING_WIDTH, w, h);
1254 CGContextDrawImage(aCGContext, inflatedDrawRect, bitmap);
1256 CGContextSetCTM(aCGContext, ctm);
1258 CGImageRelease(bitmap);
1259 CGContextRelease(bitmapctx);
1262 CGContextSetCTM(aCGContext, savedCTM);
1266 RenderButton(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
1268 HIThemeButtonDrawInfo* bdi = (HIThemeButtonDrawInfo*)aData;
1269 HIThemeDrawButton(&aRenderRect, bdi, cgContext, kHIThemeOrientationNormal, NULL);
1273 nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
1274 const HIRect& inBoxRect, bool inIsDefault,
1275 ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
1276 EventStates inState, nsIFrame* aFrame)
1278 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1280 BOOL isActive = FrameIsInActiveWindow(aFrame);
1281 BOOL isDisabled = IsDisabled(aFrame, inState);
1283 HIThemeButtonDrawInfo bdi;
1286 bdi.value = inValue;
1287 bdi.adornment = inAdornment;
1290 bdi.state = kThemeStateUnavailable;
1292 else if (inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) {
1293 bdi.state = kThemeStatePressed;
1296 if (inKind == kThemeArrowButton)
1297 bdi.state = kThemeStateUnavailable; // these are always drawn as unavailable
1298 else if (!isActive && inKind == kThemeListHeaderButton)
1299 bdi.state = kThemeStateInactive;
1301 bdi.state = kThemeStateActive;
1304 if (inState.HasState(NS_EVENT_STATE_FOCUS) && isActive)
1305 bdi.adornment |= kThemeAdornmentFocus;
1307 if (inIsDefault && !isDisabled && isActive &&
1308 !inState.HasState(NS_EVENT_STATE_ACTIVE)) {
1309 bdi.adornment |= kThemeAdornmentDefault;
1310 bdi.animation.time.start = 0;
1311 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
1314 HIRect drawFrame = inBoxRect;
1316 if (inKind == kThemePushButton) {
1317 drawFrame.size.height -= 2;
1318 if (inBoxRect.size.height < pushButtonSettings.naturalSizes[smallControlSize].height) {
1319 bdi.kind = kThemePushButtonMini;
1321 else if (inBoxRect.size.height < pushButtonSettings.naturalSizes[regularControlSize].height) {
1322 bdi.kind = kThemePushButtonSmall;
1323 drawFrame.origin.y -= 1;
1324 drawFrame.origin.x += 1;
1325 drawFrame.size.width -= 2;
1328 else if (inKind == kThemeListHeaderButton) {
1329 CGContextClipToRect(cgContext, inBoxRect);
1330 // Always remove the top border.
1331 drawFrame.origin.y -= 1;
1332 drawFrame.size.height += 1;
1333 // Remove the left border in LTR mode and the right border in RTL mode.
1334 drawFrame.size.width += 1;
1335 bool isLast = IsLastTreeHeaderCell(aFrame);
1337 drawFrame.size.width += 1; // Also remove the other border.
1338 if (!IsFrameRTL(aFrame) || isLast)
1339 drawFrame.origin.x -= 1;
1342 RenderTransformedHIThemeControl(cgContext, drawFrame, RenderButton, &bdi,
1343 IsFrameRTL(aFrame));
1345 #if DRAW_IN_FRAME_DEBUG
1346 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
1347 CGContextFillRect(cgContext, inBoxRect);
1350 NS_OBJC_END_TRY_ABORT_BLOCK;
1353 static const CellRenderSettings dropdownSettings = {
1355 NSMakeSize(0, 16), // mini
1356 NSMakeSize(0, 19), // small
1357 NSMakeSize(0, 22) // regular
1360 NSMakeSize(18, 0), // mini
1361 NSMakeSize(38, 0), // small
1362 NSMakeSize(44, 0) // regular
1366 {1, 1, 2, 1}, // mini
1367 {3, 0, 3, 1}, // small
1368 {3, 0, 3, 0} // regular
1373 static const CellRenderSettings editableMenulistSettings = {
1375 NSMakeSize(0, 15), // mini
1376 NSMakeSize(0, 18), // small
1377 NSMakeSize(0, 21) // regular
1380 NSMakeSize(18, 0), // mini
1381 NSMakeSize(38, 0), // small
1382 NSMakeSize(44, 0) // regular
1386 {0, 0, 2, 2}, // mini
1387 {0, 0, 3, 2}, // small
1388 {0, 1, 3, 3} // regular
1394 nsNativeThemeCocoa::DrawDropdown(CGContextRef cgContext, const HIRect& inBoxRect,
1395 EventStates inState, uint8_t aWidgetType,
1398 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1400 [mDropdownCell setPullsDown:(aWidgetType == NS_THEME_BUTTON)];
1402 BOOL isEditable = (aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD);
1403 NSCell* cell = isEditable ? (NSCell*)mComboBoxCell : (NSCell*)mDropdownCell;
1405 [cell setEnabled:!IsDisabled(aFrame, inState)];
1406 [cell setShowsFirstResponder:(IsFocused(aFrame) || inState.HasState(NS_EVENT_STATE_FOCUS))];
1407 [cell setHighlighted:IsOpenButton(aFrame)];
1408 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
1410 const CellRenderSettings& settings = isEditable ? editableMenulistSettings : dropdownSettings;
1411 DrawCellWithSnapping(cell, cgContext, inBoxRect, settings,
1412 0.5f, mCellDrawView, IsFrameRTL(aFrame));
1414 NS_OBJC_END_TRY_ABORT_BLOCK;
1417 static const CellRenderSettings spinnerSettings = {
1419 NSMakeSize(11, 16), // mini (width trimmed by 2px to reduce blank border)
1420 NSMakeSize(15, 22), // small
1421 NSMakeSize(19, 27) // regular
1424 NSMakeSize(11, 16), // mini (width trimmed by 2px to reduce blank border)
1425 NSMakeSize(15, 22), // small
1426 NSMakeSize(19, 27) // regular
1430 {0, 0, 0, 0}, // mini
1431 {0, 0, 0, 0}, // small
1432 {0, 0, 0, 0} // regular
1438 nsNativeThemeCocoa::DrawSpinButtons(CGContextRef cgContext, ThemeButtonKind inKind,
1439 const HIRect& inBoxRect, ThemeDrawState inDrawState,
1440 ThemeButtonAdornment inAdornment,
1441 EventStates inState, nsIFrame* aFrame)
1443 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1445 HIThemeButtonDrawInfo bdi;
1448 bdi.value = kThemeButtonOff;
1449 bdi.adornment = inAdornment;
1451 if (IsDisabled(aFrame, inState))
1452 bdi.state = kThemeStateUnavailable;
1454 bdi.state = FrameIsInActiveWindow(aFrame) ? inDrawState : kThemeStateActive;
1456 HIThemeDrawButton(&inBoxRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
1458 NS_OBJC_END_TRY_ABORT_BLOCK;
1462 nsNativeThemeCocoa::DrawSpinButton(CGContextRef cgContext,
1463 ThemeButtonKind inKind,
1464 const HIRect& inBoxRect,
1465 ThemeDrawState inDrawState,
1466 ThemeButtonAdornment inAdornment,
1467 EventStates inState,
1469 uint8_t aWidgetType)
1471 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1473 MOZ_ASSERT(aWidgetType == NS_THEME_SPINNER_UP_BUTTON ||
1474 aWidgetType == NS_THEME_SPINNER_DOWN_BUTTON);
1476 HIThemeButtonDrawInfo bdi;
1479 bdi.value = kThemeButtonOff;
1480 bdi.adornment = inAdornment;
1482 if (IsDisabled(aFrame, inState))
1483 bdi.state = kThemeStateUnavailable;
1485 bdi.state = FrameIsInActiveWindow(aFrame) ? inDrawState : kThemeStateActive;
1487 // Cocoa only allows kThemeIncDecButton to paint the up and down spin buttons
1488 // together as a single unit (presumably because when one button is active,
1489 // the appearance of both changes (in different ways)). Here we have to paint
1490 // both buttons, using clip to hide the one we don't want to paint.
1491 HIRect drawRect = inBoxRect;
1492 drawRect.size.height *= 2;
1493 if (aWidgetType == NS_THEME_SPINNER_DOWN_BUTTON) {
1494 drawRect.origin.y -= inBoxRect.size.height;
1497 // Shift the drawing a little to the left, since cocoa paints with more
1498 // blank space around the visual buttons than we'd like:
1499 drawRect.origin.x -= 1;
1501 CGContextSaveGState(cgContext);
1502 CGContextClipToRect(cgContext, inBoxRect);
1504 HIThemeDrawButton(&drawRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
1506 CGContextRestoreGState(cgContext);
1508 NS_OBJC_END_TRY_ABORT_BLOCK;
1512 nsNativeThemeCocoa::DrawFrame(CGContextRef cgContext, HIThemeFrameKind inKind,
1513 const HIRect& inBoxRect, bool inDisabled,
1514 EventStates inState)
1516 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1518 HIThemeFrameDrawInfo fdi;
1522 // We don't ever set an inactive state for this because it doesn't
1523 // look right (see other apps).
1524 fdi.state = inDisabled ? kThemeStateUnavailable : kThemeStateActive;
1526 // for some reason focus rings on listboxes draw incorrectly
1527 if (inKind == kHIThemeFrameListBox)
1530 fdi.isFocused = inState.HasState(NS_EVENT_STATE_FOCUS);
1532 // HIThemeDrawFrame takes the rect for the content area of the frame, not
1533 // the bounding rect for the frame. Here we reduce the size of the rect we
1534 // will pass to make it the size of the content.
1535 HIRect drawRect = inBoxRect;
1536 if (inKind == kHIThemeFrameTextFieldSquare) {
1537 SInt32 frameOutset = 0;
1538 ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
1539 drawRect.origin.x += frameOutset;
1540 drawRect.origin.y += frameOutset;
1541 drawRect.size.width -= frameOutset * 2;
1542 drawRect.size.height -= frameOutset * 2;
1544 else if (inKind == kHIThemeFrameListBox) {
1545 SInt32 frameOutset = 0;
1546 ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
1547 drawRect.origin.x += frameOutset;
1548 drawRect.origin.y += frameOutset;
1549 drawRect.size.width -= frameOutset * 2;
1550 drawRect.size.height -= frameOutset * 2;
1553 #if DRAW_IN_FRAME_DEBUG
1554 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
1555 CGContextFillRect(cgContext, inBoxRect);
1558 HIThemeDrawFrame(&drawRect, &fdi, cgContext, HITHEME_ORIENTATION);
1560 NS_OBJC_END_TRY_ABORT_BLOCK;
1563 static const CellRenderSettings progressSettings[2][2] = {
1564 // Vertical progress bar.
1566 // Determined settings.
1570 NSMakeSize(10, 0), // small
1571 NSMakeSize(16, 0) // regular
1574 NSZeroSize, NSZeroSize, NSZeroSize
1578 {0, 0, 0, 0}, // mini
1579 {1, 1, 1, 1}, // small
1580 {1, 1, 1, 1} // regular
1584 // There is no horizontal margin in regular undetermined size.
1588 NSMakeSize(10, 0), // small
1589 NSMakeSize(16, 0) // regular
1592 NSZeroSize, NSZeroSize, NSZeroSize
1596 {0, 0, 0, 0}, // mini
1597 {1, 1, 1, 1}, // small
1598 {1, 0, 1, 0} // regular
1603 // Horizontal progress bar.
1605 // Determined settings.
1609 NSMakeSize(0, 10), // small
1610 NSMakeSize(0, 16) // regular
1613 NSZeroSize, NSZeroSize, NSZeroSize
1617 {0, 0, 0, 0}, // mini
1618 {1, 1, 1, 1}, // small
1619 {1, 1, 1, 1} // regular
1623 // There is no horizontal margin in regular undetermined size.
1627 NSMakeSize(0, 10), // small
1628 NSMakeSize(0, 16) // regular
1631 NSZeroSize, NSZeroSize, NSZeroSize
1635 {0, 0, 0, 0}, // mini
1636 {1, 1, 1, 1}, // small
1637 {0, 1, 0, 1} // regular
1645 nsNativeThemeCocoa::DrawProgress(CGContextRef cgContext, const HIRect& inBoxRect,
1646 bool inIsIndeterminate, bool inIsHorizontal,
1647 double inValue, double inMaxValue,
1650 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1652 NSProgressBarCell* cell = mProgressBarCell;
1654 [cell setValue:inValue];
1655 [cell setMax:inMaxValue];
1656 [cell setIndeterminate:inIsIndeterminate];
1657 [cell setHorizontal:inIsHorizontal];
1658 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint]
1659 : NSClearControlTint)];
1661 DrawCellWithSnapping(cell, cgContext, inBoxRect,
1662 progressSettings[inIsHorizontal][inIsIndeterminate],
1663 VerticalAlignFactor(aFrame), mCellDrawView,
1664 IsFrameRTL(aFrame));
1666 NS_OBJC_END_TRY_ABORT_BLOCK;
1669 static const CellRenderSettings meterSetting = {
1671 NSMakeSize(0, 16), // mini
1672 NSMakeSize(0, 16), // small
1673 NSMakeSize(0, 16) // regular
1676 NSZeroSize, NSZeroSize, NSZeroSize
1680 {1, 1, 1, 1}, // mini
1681 {1, 1, 1, 1}, // small
1682 {1, 1, 1, 1} // regular
1688 nsNativeThemeCocoa::DrawMeter(CGContextRef cgContext, const HIRect& inBoxRect,
1691 NS_OBJC_BEGIN_TRY_ABORT_BLOCK
1693 NS_PRECONDITION(aFrame, "aFrame should not be null here!");
1695 // When using -moz-meterbar on an non meter element, we will not be able to
1696 // get all the needed information so we just draw an empty meter.
1697 nsIContent* content = aFrame->GetContent();
1698 if (!(content && content->IsHTML(nsGkAtoms::meter))) {
1699 DrawCellWithSnapping(mMeterBarCell, cgContext, inBoxRect,
1700 meterSetting, VerticalAlignFactor(aFrame),
1701 mCellDrawView, IsFrameRTL(aFrame));
1705 HTMLMeterElement* meterElement = static_cast<HTMLMeterElement*>(content);
1706 double value = meterElement->Value();
1707 double min = meterElement->Min();
1708 double max = meterElement->Max();
1710 NSLevelIndicatorCell* cell = mMeterBarCell;
1712 [cell setMinValue:min];
1713 [cell setMaxValue:max];
1714 [cell setDoubleValue:value];
1717 * The way HTML and Cocoa defines the meter/indicator widget are different.
1718 * So, we are going to use a trick to get the Cocoa widget showing what we
1719 * are expecting: we set the warningValue or criticalValue to the current
1720 * value when we want to have the widget to be in the warning or critical
1723 EventStates states = aFrame->GetContent()->AsElement()->State();
1725 // Reset previously set warning and critical values.
1726 [cell setWarningValue:max+1];
1727 [cell setCriticalValue:max+1];
1729 if (states.HasState(NS_EVENT_STATE_SUB_OPTIMUM)) {
1730 [cell setWarningValue:value];
1731 } else if (states.HasState(NS_EVENT_STATE_SUB_SUB_OPTIMUM)) {
1732 [cell setCriticalValue:value];
1735 HIRect rect = CGRectStandardize(inBoxRect);
1736 BOOL vertical = IsVerticalMeter(aFrame);
1738 CGContextSaveGState(cgContext);
1742 * Cocoa doesn't provide a vertical meter bar so to show one, we have to
1743 * show a rotated horizontal meter bar.
1744 * Given that we want to show a vertical meter bar, we assume that the rect
1745 * has vertical dimensions but we can't correctly draw a meter widget inside
1746 * such a rectangle so we need to inverse width and height (and re-position)
1747 * to get a rectangle with horizontal dimensions.
1748 * Finally, we want to show a vertical meter so we want to rotate the result
1749 * so it is vertical. We do that by changing the context.
1751 CGFloat tmp = rect.size.width;
1752 rect.size.width = rect.size.height;
1753 rect.size.height = tmp;
1754 rect.origin.x += rect.size.height / 2.f - rect.size.width / 2.f;
1755 rect.origin.y += rect.size.width / 2.f - rect.size.height / 2.f;
1757 CGContextTranslateCTM(cgContext, CGRectGetMidX(rect), CGRectGetMidY(rect));
1758 CGContextRotateCTM(cgContext, -M_PI / 2.f);
1759 CGContextTranslateCTM(cgContext, -CGRectGetMidX(rect), -CGRectGetMidY(rect));
1762 DrawCellWithSnapping(cell, cgContext, rect,
1763 meterSetting, VerticalAlignFactor(aFrame),
1764 mCellDrawView, !vertical && IsFrameRTL(aFrame));
1766 CGContextRestoreGState(cgContext);
1768 NS_OBJC_END_TRY_ABORT_BLOCK
1772 nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect,
1775 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1777 HIThemeTabPaneDrawInfo tpdi;
1780 tpdi.state = FrameIsInActiveWindow(aFrame) ? kThemeStateActive : kThemeStateInactive;
1781 tpdi.direction = kThemeTabNorth;
1782 tpdi.size = kHIThemeTabSizeNormal;
1783 tpdi.kind = kHIThemeTabKindNormal;
1785 HIThemeDrawTabPane(&inBoxRect, &tpdi, cgContext, HITHEME_ORIENTATION);
1787 NS_OBJC_END_TRY_ABORT_BLOCK;
1791 nsNativeThemeCocoa::DrawScale(CGContextRef cgContext, const HIRect& inBoxRect,
1792 EventStates inState, bool inIsVertical,
1793 bool inIsReverse, int32_t inCurrentValue,
1794 int32_t inMinValue, int32_t inMaxValue,
1797 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1799 HIThemeTrackDrawInfo tdi;
1802 tdi.kind = kThemeMediumSlider;
1803 tdi.bounds = inBoxRect;
1804 tdi.min = inMinValue;
1805 tdi.max = inMaxValue;
1806 tdi.value = inCurrentValue;
1807 tdi.attributes = kThemeTrackShowThumb;
1809 tdi.attributes |= kThemeTrackHorizontal;
1811 tdi.attributes |= kThemeTrackRightToLeft;
1812 if (inState.HasState(NS_EVENT_STATE_FOCUS))
1813 tdi.attributes |= kThemeTrackHasFocus;
1814 if (IsDisabled(aFrame, inState))
1815 tdi.enableState = kThemeTrackDisabled;
1817 tdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
1818 tdi.trackInfo.slider.thumbDir = kThemeThumbPlain;
1819 tdi.trackInfo.slider.pressState = 0;
1821 HIThemeDrawTrack(&tdi, NULL, cgContext, HITHEME_ORIENTATION);
1823 NS_OBJC_END_TRY_ABORT_BLOCK;
1827 nsNativeThemeCocoa::SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter)
1829 // Usually a separator is drawn by the segment to the right of the
1830 // separator, but pressed and selected segments have higher priority.
1831 if (!aBefore || !aAfter)
1833 if (IsSelectedButton(aAfter))
1835 if (IsSelectedButton(aBefore) || IsPressedButton(aBefore))
1841 nsNativeThemeCocoa::SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
1842 nsIFrame* aCurrent, nsIFrame* aRight)
1844 // A separator between two segments should always be located in the leftmost
1845 // pixel column of the segment to the right of the separator, regardless of
1846 // who ends up drawing it.
1847 // CoreUI draws the separators inside the drawing rect.
1848 if (aLeft && SeparatorResponsibility(aLeft, aCurrent) == aLeft) {
1849 // The left button draws the separator, so we need to make room for it.
1850 aRect.origin.x += 1;
1851 aRect.size.width -= 1;
1853 if (SeparatorResponsibility(aCurrent, aRight) == aCurrent) {
1854 // We draw the right separator, so we need to extend the draw rect into the
1855 // segment to our right.
1856 aRect.size.width += 1;
1861 static NSString* ToolbarButtonPosition(BOOL aIsFirst, BOOL aIsLast)
1865 return @"kCUISegmentPositionOnly";
1866 return @"kCUISegmentPositionFirst";
1869 return @"kCUISegmentPositionLast";
1870 return @"kCUISegmentPositionMiddle";
1873 struct SegmentedControlRenderSettings {
1874 const CGFloat* heights;
1875 const NSString* widgetName;
1876 const BOOL ignoresPressedWhenSelected;
1877 const BOOL isToolbarControl;
1880 static const CGFloat tabHeights[3] = { 17, 20, 23 };
1882 static const SegmentedControlRenderSettings tabRenderSettings = {
1883 tabHeights, @"tab", YES, NO
1886 static const CGFloat toolbarButtonHeights[3] = { 15, 18, 22 };
1888 static const SegmentedControlRenderSettings toolbarButtonRenderSettings = {
1889 toolbarButtonHeights, @"kCUIWidgetButtonSegmentedSCurve", NO, YES
1893 nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
1894 EventStates inState, nsIFrame* aFrame,
1895 const SegmentedControlRenderSettings& aSettings)
1897 BOOL isActive = IsActive(aFrame, aSettings.isToolbarControl);
1898 BOOL isFocused = inState.HasState(NS_EVENT_STATE_FOCUS);
1899 BOOL isSelected = IsSelectedButton(aFrame);
1900 BOOL isPressed = IsPressedButton(aFrame);
1901 if (isSelected && aSettings.ignoresPressedWhenSelected) {
1905 BOOL isRTL = IsFrameRTL(aFrame);
1906 nsIFrame* left = GetAdjacentSiblingFrameWithSameAppearance(aFrame, isRTL);
1907 nsIFrame* right = GetAdjacentSiblingFrameWithSameAppearance(aFrame, !isRTL);
1908 CGRect drawRect = SeparatorAdjustedRect(inBoxRect, left, aFrame, right);
1909 BOOL drawLeftSeparator = SeparatorResponsibility(left, aFrame) == aFrame;
1910 BOOL drawRightSeparator = SeparatorResponsibility(aFrame, right) == aFrame;
1911 NSControlSize controlSize = FindControlSize(drawRect.size.height, aSettings.heights, 4.0f);
1913 RenderWithCoreUI(drawRect, cgContext, [NSDictionary dictionaryWithObjectsAndKeys:
1914 aSettings.widgetName, @"widget",
1915 (isActive ? @"kCUIPresentationStateActiveKey" : @"kCUIPresentationStateInactive"), @"kCUIPresentationStateKey",
1916 ToolbarButtonPosition(!left, !right), @"kCUIPositionKey",
1917 [NSNumber numberWithBool:drawLeftSeparator], @"kCUISegmentLeadingSeparatorKey",
1918 [NSNumber numberWithBool:drawRightSeparator], @"kCUISegmentTrailingSeparatorKey",
1919 [NSNumber numberWithBool:isSelected], @"value",
1920 (isPressed ? @"pressed" : (isActive ? @"normal" : @"inactive")), @"state",
1921 [NSNumber numberWithBool:isFocused], @"focus",
1922 CUIControlSizeForCocoaSize(controlSize), @"size",
1923 [NSNumber numberWithBool:YES], @"is.flipped",
1924 @"up", @"direction",
1929 ConvertToPressState(EventStates aButtonState, UInt8 aPressState)
1931 // If the button is pressed, return the press state passed in. Otherwise, return 0.
1932 return aButtonState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER) ? aPressState : 0;
1936 nsNativeThemeCocoa::GetScrollbarPressStates(nsIFrame* aFrame,
1937 EventStates aButtonStates[])
1939 static nsIContent::AttrValuesArray attributeValues[] = {
1940 &nsGkAtoms::scrollbarUpTop,
1941 &nsGkAtoms::scrollbarDownTop,
1942 &nsGkAtoms::scrollbarUpBottom,
1943 &nsGkAtoms::scrollbarDownBottom,
1947 // Get the state of any scrollbar buttons in our child frames
1948 for (nsIFrame *childFrame = aFrame->GetFirstPrincipalChild();
1950 childFrame = childFrame->GetNextSibling()) {
1952 nsIContent *childContent = childFrame->GetContent();
1953 if (!childContent) continue;
1954 int32_t attrIndex = childContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::sbattr,
1955 attributeValues, eCaseMatters);
1956 if (attrIndex < 0) continue;
1958 aButtonStates[attrIndex] = GetContentState(childFrame, NS_THEME_BUTTON);
1962 // Both of the following sets of numbers were derived by loading the testcase in
1963 // bmo bug 380185 in Safari and observing its behavior for various heights of scrollbar.
1964 // These magic numbers are the minimum sizes we can draw a scrollbar and still
1965 // have room for everything to display, including the thumb
1966 #define MIN_SCROLLBAR_SIZE_WITH_THUMB 61
1967 #define MIN_SMALL_SCROLLBAR_SIZE_WITH_THUMB 49
1968 // And these are the minimum sizes if we don't draw the thumb
1969 #define MIN_SCROLLBAR_SIZE 56
1970 #define MIN_SMALL_SCROLLBAR_SIZE 46
1973 nsNativeThemeCocoa::GetScrollbarDrawInfo(HIThemeTrackDrawInfo& aTdi, nsIFrame *aFrame,
1974 const CGSize& aSize, bool aShouldGetButtonStates)
1976 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1978 int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
1979 int32_t minpos = CheckIntAttr(aFrame, nsGkAtoms::minpos, 0);
1980 int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
1981 int32_t thumbSize = CheckIntAttr(aFrame, nsGkAtoms::pageincrement, 10);
1983 bool isHorizontal = aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
1984 nsGkAtoms::horizontal, eCaseMatters);
1985 bool isSmall = aFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL;
1988 aTdi.kind = isSmall ? kThemeSmallScrollBar : kThemeMediumScrollBar;
1989 aTdi.bounds.origin = CGPointZero;
1990 aTdi.bounds.size = aSize;
1993 aTdi.value = curpos;
1994 aTdi.attributes = 0;
1995 aTdi.enableState = kThemeTrackActive;
1997 aTdi.attributes |= kThemeTrackHorizontal;
1999 aTdi.trackInfo.scrollbar.viewsize = (SInt32)thumbSize;
2001 // This should be done early on so things like "kThemeTrackNothingToScroll" can
2002 // override the active enable state.
2003 aTdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
2005 /* Only display features if we have enough room for them.
2006 * Gecko still maintains the scrollbar info; this is just a visual issue (bug 380185).
2008 int32_t longSideLength = (int32_t)(isHorizontal ? (aSize.width) : (aSize.height));
2009 if (longSideLength >= (isSmall ? MIN_SMALL_SCROLLBAR_SIZE_WITH_THUMB : MIN_SCROLLBAR_SIZE_WITH_THUMB)) {
2010 aTdi.attributes |= kThemeTrackShowThumb;
2012 else if (longSideLength < (isSmall ? MIN_SMALL_SCROLLBAR_SIZE : MIN_SCROLLBAR_SIZE)) {
2013 aTdi.enableState = kThemeTrackNothingToScroll;
2017 aTdi.trackInfo.scrollbar.pressState = 0;
2019 // Only go get these scrollbar button states if we need it. For example,
2020 // there's no reason to look up scrollbar button states when we're only
2021 // creating a TrackDrawInfo to determine the size of the thumb. There's
2022 // also no reason to do this on Lion or later, whose scrollbars have no
2024 if (aShouldGetButtonStates && !nsCocoaFeatures::OnLionOrLater()) {
2025 EventStates buttonStates[4];
2026 GetScrollbarPressStates(aFrame, buttonStates);
2027 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
2028 // It seems that unless all four buttons are showing, kThemeTopOutsideArrowPressed is the correct constant for
2029 // the up scrollbar button.
2030 if ([buttonPlacement isEqualToString:@"DoubleBoth"]) {
2031 aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
2032 ConvertToPressState(buttonStates[1], kThemeTopInsideArrowPressed) |
2033 ConvertToPressState(buttonStates[2], kThemeBottomInsideArrowPressed) |
2034 ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
2036 aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
2037 ConvertToPressState(buttonStates[1], kThemeBottomOutsideArrowPressed) |
2038 ConvertToPressState(buttonStates[2], kThemeTopOutsideArrowPressed) |
2039 ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
2043 NS_OBJC_END_TRY_ABORT_BLOCK;
2047 RenderScrollbar(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
2049 HIThemeTrackDrawInfo* tdi = (HIThemeTrackDrawInfo*)aData;
2050 HIThemeDrawTrack(tdi, NULL, cgContext, HITHEME_ORIENTATION);
2054 nsNativeThemeCocoa::DrawScrollbar(CGContextRef aCGContext, const HIRect& aBoxRect, nsIFrame *aFrame)
2056 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
2058 HIThemeTrackDrawInfo tdi;
2059 GetScrollbarDrawInfo(tdi, aFrame, aBoxRect.size, true); // True means we want the press states
2060 RenderTransformedHIThemeControl(aCGContext, aBoxRect, RenderScrollbar, &tdi);
2062 NS_OBJC_END_TRY_ABORT_BLOCK;
2066 nsNativeThemeCocoa::GetParentScrollbarFrame(nsIFrame *aFrame)
2068 // Walk our parents to find a scrollbar frame
2069 nsIFrame *scrollbarFrame = aFrame;
2071 if (scrollbarFrame->GetType() == nsGkAtoms::scrollbarFrame) break;
2072 } while ((scrollbarFrame = scrollbarFrame->GetParent()));
2074 // We return null if we can't find a parent scrollbar frame
2075 return scrollbarFrame;
2079 ToolbarCanBeUnified(CGContextRef cgContext, const HIRect& inBoxRect, NSWindow* aWindow)
2081 if (![aWindow isKindOfClass:[ToolbarWindow class]])
2084 ToolbarWindow* win = (ToolbarWindow*)aWindow;
2085 float unifiedToolbarHeight = [win unifiedToolbarHeight];
2086 return inBoxRect.origin.x == 0 &&
2087 inBoxRect.size.width >= [win frame].size.width &&
2088 CGRectGetMaxY(inBoxRect) <= unifiedToolbarHeight;
2091 // By default, kCUIWidgetWindowFrame drawing draws rounded corners in the
2092 // upper corners. Depending on the context type, it fills the background in
2093 // the corners with black or leaves it transparent. Unfortunately, this corner
2094 // rounding interacts poorly with the window corner masking we apply during
2095 // titlebar drawing and results in small remnants of the corner background
2096 // appearing at the rounded edge.
2097 // So we draw square corners.
2099 DrawNativeTitlebarToolbarWithSquareCorners(CGContextRef aContext, const CGRect& aRect,
2100 CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped)
2102 // We extend the draw rect horizontally and clip away the rounded corners.
2103 const CGFloat extendHorizontal = 10;
2104 CGRect drawRect = CGRectInset(aRect, -extendHorizontal, 0);
2105 CGContextSaveGState(aContext);
2106 CGContextClipToRect(aContext, aRect);
2108 RenderWithCoreUI(drawRect, aContext,
2109 [NSDictionary dictionaryWithObjectsAndKeys:
2110 @"kCUIWidgetWindowFrame", @"widget",
2111 @"regularwin", @"windowtype",
2112 (aIsMain ? @"normal" : @"inactive"), @"state",
2113 [NSNumber numberWithDouble:aUnifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
2114 [NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawTitleSeparatorKey",
2115 [NSNumber numberWithBool:aIsFlipped], @"is.flipped",
2118 CGContextRestoreGState(aContext);
2122 nsNativeThemeCocoa::DrawUnifiedToolbar(CGContextRef cgContext, const HIRect& inBoxRect,
2125 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
2127 CGContextSaveGState(cgContext);
2128 CGContextClipToRect(cgContext, inBoxRect);
2130 CGFloat unifiedHeight = std::max([(ToolbarWindow*)aWindow unifiedToolbarHeight],
2131 inBoxRect.size.height);
2132 BOOL isMain = [aWindow isMainWindow];
2133 CGFloat titlebarHeight = unifiedHeight - inBoxRect.size.height;
2134 CGRect drawRect = CGRectMake(inBoxRect.origin.x, inBoxRect.origin.y - titlebarHeight,
2135 inBoxRect.size.width, inBoxRect.size.height + titlebarHeight);
2136 DrawNativeTitlebarToolbarWithSquareCorners(cgContext, drawRect, unifiedHeight, isMain, YES);
2138 CGContextRestoreGState(cgContext);
2140 NS_OBJC_END_TRY_ABORT_BLOCK;
2144 nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect,
2147 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
2149 if (inBoxRect.size.height < 2.0f)
2152 CGContextSaveGState(cgContext);
2153 CGContextClipToRect(cgContext, inBoxRect);
2155 // kCUIWidgetWindowFrame draws a complete window frame with both title bar
2156 // and bottom bar. We only want the bottom bar, so we extend the draw rect
2157 // upwards to make space for the title bar, and then we clip it away.
2158 CGRect drawRect = inBoxRect;
2159 const int extendUpwards = 40;
2160 drawRect.origin.y -= extendUpwards;
2161 drawRect.size.height += extendUpwards;
2162 RenderWithCoreUI(drawRect, cgContext,
2163 [NSDictionary dictionaryWithObjectsAndKeys:
2164 @"kCUIWidgetWindowFrame", @"widget",
2165 @"regularwin", @"windowtype",
2166 (IsActive(aFrame, YES) ? @"normal" : @"inactive"), @"state",
2167 [NSNumber numberWithInt:inBoxRect.size.height], @"kCUIWindowFrameBottomBarHeightKey",
2168 [NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawBottomBarSeparatorKey",
2169 [NSNumber numberWithBool:YES], @"is.flipped",
2172 CGContextRestoreGState(cgContext);
2174 NS_OBJC_END_TRY_ABORT_BLOCK;
2178 nsNativeThemeCocoa::DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
2179 CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped)
2181 CGFloat unifiedHeight = std::max(aUnifiedHeight, aTitlebarRect.size.height);
2182 DrawNativeTitlebarToolbarWithSquareCorners(aContext, aTitlebarRect, unifiedHeight, aIsMain, aIsFlipped);
2186 RenderResizer(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
2188 HIThemeGrowBoxDrawInfo* drawInfo = (HIThemeGrowBoxDrawInfo*)aData;
2189 HIThemeDrawGrowBox(&CGPointZero, drawInfo, cgContext, kHIThemeOrientationNormal);
2193 nsNativeThemeCocoa::DrawResizer(CGContextRef cgContext, const HIRect& aRect,
2196 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
2198 HIThemeGrowBoxDrawInfo drawInfo;
2199 drawInfo.version = 0;
2200 drawInfo.state = kThemeStateActive;
2201 drawInfo.kind = kHIThemeGrowBoxKindNormal;
2202 drawInfo.direction = kThemeGrowRight | kThemeGrowDown;
2203 drawInfo.size = kHIThemeGrowBoxSizeNormal;
2205 RenderTransformedHIThemeControl(cgContext, aRect, RenderResizer, &drawInfo,
2206 IsFrameRTL(aFrame));
2208 NS_OBJC_END_TRY_ABORT_BLOCK;
2212 ScrollbarTrackAndThumbDrawSeparately()
2214 return nsLookAndFeel::UseOverlayScrollbars() || nsCocoaFeatures::OnLionOrLater();
2218 nsNativeThemeCocoa::IsParentScrollbarRolledOver(nsIFrame* aFrame)
2220 nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
2221 return nsLookAndFeel::UseOverlayScrollbars()
2222 ? CheckBooleanAttr(scrollbarFrame, nsGkAtoms::hover)
2223 : GetContentState(scrollbarFrame, NS_THEME_NONE).HasState(NS_EVENT_STATE_HOVER);
2227 IsHiDPIContext(nsPresContext* aContext)
2229 return nsPresContext::AppUnitsPerCSSPixel() >=
2230 2 * aContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
2234 nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
2236 uint8_t aWidgetType,
2237 const nsRect& aRect,
2238 const nsRect& aDirtyRect)
2240 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2242 // setup to draw into the correct port
2243 int32_t p2a = aFrame->PresContext()->AppUnitsPerDevPixel();
2245 gfxRect nativeDirtyRect(aDirtyRect.x, aDirtyRect.y,
2246 aDirtyRect.width, aDirtyRect.height);
2247 gfxRect nativeWidgetRect(aRect.x, aRect.y, aRect.width, aRect.height);
2248 nativeWidgetRect.ScaleInverse(gfxFloat(p2a));
2249 nativeDirtyRect.ScaleInverse(gfxFloat(p2a));
2250 nativeWidgetRect.Round();
2251 if (nativeWidgetRect.IsEmpty())
2252 return NS_OK; // Don't attempt to draw invisible widgets.
2254 gfxContext* thebesCtx = aContext->ThebesContext();
2256 return NS_ERROR_FAILURE;
2258 gfxContextMatrixAutoSaveRestore save(thebesCtx);
2260 bool hidpi = IsHiDPIContext(aFrame->PresContext());
2262 // Use high-resolution drawing.
2263 nativeWidgetRect.ScaleInverse(2.0f);
2264 nativeDirtyRect.ScaleInverse(2.0f);
2265 thebesCtx->Scale(2.0f, 2.0f);
2268 gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect);
2270 CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
2271 if (cgContext == nullptr) {
2272 // The Quartz surface handles 0x0 surfaces by internally
2273 // making all operations no-ops; there's no cgcontext created for them.
2274 // Unfortunately, this means that callers that want to render
2275 // directly to the CGContext need to be aware of this quirk.
2280 if (1 /*aWidgetType == NS_THEME_TEXTFIELD*/) {
2281 fprintf(stderr, "Native theme drawing widget %d [%p] dis:%d in rect [%d %d %d %d]\n",
2282 aWidgetType, aFrame, IsDisabled(aFrame), aRect.x, aRect.y, aRect.width, aRect.height);
2283 fprintf(stderr, "Cairo matrix: [%f %f %f %f %f %f]\n",
2284 mat._11, mat._12, mat._21, mat._22, mat._31, mat._32);
2285 fprintf(stderr, "Native theme xform[0]: [%f %f %f %f %f %f]\n",
2286 mm0.a, mm0.b, mm0.c, mm0.d, mm0.tx, mm0.ty);
2287 CGAffineTransform mm = CGContextGetCTM(cgContext);
2288 fprintf(stderr, "Native theme xform[1]: [%f %f %f %f %f %f]\n",
2289 mm.a, mm.b, mm.c, mm.d, mm.tx, mm.ty);
2293 CGRect macRect = CGRectMake(nativeWidgetRect.X(), nativeWidgetRect.Y(),
2294 nativeWidgetRect.Width(), nativeWidgetRect.Height());
2297 fprintf(stderr, " --> macRect %f %f %f %f\n",
2298 macRect.origin.x, macRect.origin.y, macRect.size.width, macRect.size.height);
2299 CGRect bounds = CGContextGetClipBoundingBox(cgContext);
2300 fprintf(stderr, " --> clip bounds: %f %f %f %f\n",
2301 bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
2303 //CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 1.0, 0.1);
2304 //CGContextFillRect(cgContext, bounds);
2307 EventStates eventState = GetContentState(aFrame, aWidgetType);
2309 switch (aWidgetType) {
2310 case NS_THEME_DIALOG: {
2311 HIThemeSetFill(kThemeBrushDialogBackgroundActive, NULL, cgContext, HITHEME_ORIENTATION);
2312 CGContextFillRect(cgContext, macRect);
2316 case NS_THEME_MENUPOPUP: {
2317 HIThemeMenuDrawInfo mdi;
2318 memset(&mdi, 0, sizeof(mdi));
2320 mdi.menuType = IsDisabled(aFrame, eventState) ?
2321 static_cast<ThemeMenuType>(kThemeMenuTypeInactive) :
2322 static_cast<ThemeMenuType>(kThemeMenuTypePopUp);
2324 bool isLeftOfParent = false;
2325 if (IsSubmenu(aFrame, &isLeftOfParent) && !isLeftOfParent) {
2326 mdi.menuType = kThemeMenuTypeHierarchical;
2329 // The rounded corners draw outside the frame.
2330 CGRect deflatedRect = CGRectMake(macRect.origin.x, macRect.origin.y + 4,
2331 macRect.size.width, macRect.size.height - 8);
2332 HIThemeDrawMenuBackground(&deflatedRect, &mdi, cgContext, HITHEME_ORIENTATION);
2336 case NS_THEME_MENUITEM:
2337 case NS_THEME_CHECKMENUITEM: {
2338 SurfaceFormat format = thebesCtx->GetDrawTarget()->GetFormat();
2339 bool isTransparent = (format == SurfaceFormat::R8G8B8A8) ||
2340 (format == SurfaceFormat::B8G8R8A8);
2341 if (isTransparent) {
2342 // Clear the background to get correct transparency.
2343 CGContextClearRect(cgContext, macRect);
2346 // maybe use kThemeMenuItemHierBackground or PopUpBackground instead of just Plain?
2347 HIThemeMenuItemDrawInfo drawInfo;
2348 memset(&drawInfo, 0, sizeof(drawInfo));
2349 drawInfo.version = 0;
2350 drawInfo.itemType = kThemeMenuItemPlain;
2351 drawInfo.state = (IsDisabled(aFrame, eventState) ?
2352 static_cast<ThemeMenuState>(kThemeMenuDisabled) :
2353 CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ?
2354 static_cast<ThemeMenuState>(kThemeMenuSelected) :
2355 static_cast<ThemeMenuState>(kThemeMenuActive));
2357 // XXX pass in the menu rect instead of always using the item rect
2359 HIThemeDrawMenuItem(&macRect, &macRect, &drawInfo, cgContext, HITHEME_ORIENTATION, &ignored);
2361 if (aWidgetType == NS_THEME_CHECKMENUITEM) {
2362 DrawMenuIcon(cgContext, macRect, eventState, aFrame, kCheckmarkSize, kCheckmarkImage);
2367 case NS_THEME_MENUSEPARATOR: {
2368 ThemeMenuState menuState;
2369 if (IsDisabled(aFrame, eventState)) {
2370 menuState = kThemeMenuDisabled;
2373 menuState = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ?
2374 kThemeMenuSelected : kThemeMenuActive;
2377 HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
2378 HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
2382 case NS_THEME_TOOLTIP:
2383 if (nsCocoaFeatures::OnYosemiteOrLater()) {
2384 CGContextSetRGBFillColor(cgContext, 0.945, 0.942, 0.945, 0.950);
2386 CGContextSetRGBFillColor(cgContext, 0.996, 1.000, 0.792, 0.950);
2388 CGContextFillRect(cgContext, macRect);
2391 case NS_THEME_CHECKBOX:
2392 case NS_THEME_RADIO: {
2393 bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX);
2394 DrawCheckboxOrRadio(cgContext, isCheckbox, macRect, GetCheckedOrSelected(aFrame, !isCheckbox),
2395 eventState, aFrame);
2399 case NS_THEME_BUTTON:
2400 if (IsDefaultButton(aFrame)) {
2401 if (!IsDisabled(aFrame, eventState) && FrameIsInActiveWindow(aFrame) &&
2402 !QueueAnimatedContentForRefresh(aFrame->GetContent(), 10)) {
2403 NS_WARNING("Unable to animate button!");
2405 DrawButton(cgContext, kThemePushButton, macRect, true,
2406 kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
2407 } else if (IsButtonTypeMenu(aFrame)) {
2408 DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
2410 DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame);
2414 case NS_THEME_FOCUS_OUTLINE:
2415 DrawFocusOutline(cgContext, macRect, eventState, aWidgetType, aFrame);
2418 case NS_THEME_MOZ_MAC_HELP_BUTTON:
2419 DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame);
2422 case NS_THEME_BUTTON_BEVEL:
2423 DrawButton(cgContext, kThemeMediumBevelButton, macRect,
2424 IsDefaultButton(aFrame), kThemeButtonOff, kThemeAdornmentNone,
2425 eventState, aFrame);
2428 case NS_THEME_SPINNER: {
2429 nsIContent* content = aFrame->GetContent();
2430 if (content->IsHTML()) {
2431 // In HTML the theming for the spin buttons is drawn individually into
2432 // their own backgrounds instead of being drawn into the background of
2433 // their spinner parent as it is for XUL.
2436 ThemeDrawState state = kThemeStateActive;
2437 if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::state,
2438 NS_LITERAL_STRING("up"), eCaseMatters)) {
2439 state = kThemeStatePressedUp;
2441 else if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::state,
2442 NS_LITERAL_STRING("down"), eCaseMatters)) {
2443 state = kThemeStatePressedDown;
2446 DrawSpinButtons(cgContext, kThemeIncDecButton, macRect, state,
2447 kThemeAdornmentNone, eventState, aFrame);
2451 case NS_THEME_SPINNER_UP_BUTTON:
2452 case NS_THEME_SPINNER_DOWN_BUTTON: {
2453 nsNumberControlFrame* numberControlFrame =
2454 nsNumberControlFrame::GetNumberControlFrameForSpinButton(aFrame);
2455 if (numberControlFrame) {
2456 ThemeDrawState state = kThemeStateActive;
2457 if (numberControlFrame->SpinnerUpButtonIsDepressed()) {
2458 state = kThemeStatePressedUp;
2459 } else if (numberControlFrame->SpinnerDownButtonIsDepressed()) {
2460 state = kThemeStatePressedDown;
2462 DrawSpinButton(cgContext, kThemeIncDecButtonMini, macRect, state,
2463 kThemeAdornmentNone, eventState, aFrame, aWidgetType);
2468 case NS_THEME_TOOLBAR_BUTTON:
2469 DrawSegment(cgContext, macRect, eventState, aFrame, toolbarButtonRenderSettings);
2472 case NS_THEME_TOOLBAR_SEPARATOR: {
2473 HIThemeSeparatorDrawInfo sdi = { 0, kThemeStateActive };
2474 HIThemeDrawSeparator(&macRect, &sdi, cgContext, HITHEME_ORIENTATION);
2478 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
2479 case NS_THEME_TOOLBAR: {
2480 NSWindow* win = NativeWindowForFrame(aFrame);
2481 if (ToolbarCanBeUnified(cgContext, macRect, win)) {
2482 DrawUnifiedToolbar(cgContext, macRect, win);
2485 BOOL isMain = [win isMainWindow];
2486 CGRect drawRect = macRect;
2489 drawRect.size.height = 1.0f;
2490 DrawNativeGreyColorInRect(cgContext, toolbarTopBorderGrey, drawRect, isMain);
2493 drawRect.origin.y += drawRect.size.height;
2494 drawRect.size.height = macRect.size.height - 2.0f;
2495 DrawNativeGreyColorInRect(cgContext, toolbarFillGrey, drawRect, isMain);
2498 drawRect.origin.y += drawRect.size.height;
2499 drawRect.size.height = 1.0f;
2500 DrawNativeGreyColorInRect(cgContext, toolbarBottomBorderGrey, drawRect, isMain);
2504 case NS_THEME_WINDOW_TITLEBAR: {
2505 NSWindow* win = NativeWindowForFrame(aFrame);
2506 BOOL isMain = [win isMainWindow];
2507 float unifiedToolbarHeight = [win isKindOfClass:[ToolbarWindow class]] ?
2508 [(ToolbarWindow*)win unifiedToolbarHeight] : macRect.size.height;
2509 DrawNativeTitlebar(cgContext, macRect, unifiedToolbarHeight, isMain, YES);
2513 case NS_THEME_TOOLBOX: {
2514 HIThemeHeaderDrawInfo hdi = { 0, kThemeStateActive, kHIThemeHeaderKindWindow };
2515 HIThemeDrawHeader(&macRect, &hdi, cgContext, HITHEME_ORIENTATION);
2519 case NS_THEME_STATUSBAR:
2520 DrawStatusBar(cgContext, macRect, aFrame);
2523 case NS_THEME_DROPDOWN:
2524 case NS_THEME_DROPDOWN_TEXTFIELD:
2525 DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
2528 case NS_THEME_DROPDOWN_BUTTON:
2529 DrawButton(cgContext, kThemeArrowButton, macRect, false, kThemeButtonOn,
2530 kThemeAdornmentArrowDownArrow, eventState, aFrame);
2533 case NS_THEME_GROUPBOX: {
2534 HIThemeGroupBoxDrawInfo gdi = { 0, kThemeStateActive, kHIThemeGroupBoxKindPrimary };
2535 HIThemeDrawGroupBox(&macRect, &gdi, cgContext, HITHEME_ORIENTATION);
2539 case NS_THEME_TEXTFIELD:
2540 case NS_THEME_NUMBER_INPUT:
2541 // HIThemeSetFill is not available on 10.3
2542 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
2543 CGContextFillRect(cgContext, macRect);
2545 // XUL textboxes set the native appearance on the containing box, while
2546 // concrete focus is set on the html:input element within it. We can
2547 // though, check the focused attribute of xul textboxes in this case.
2548 // On Mac, focus rings are always shown for textboxes, so we do not need
2549 // to check the window's focus ring state here
2550 if (aFrame->GetContent()->IsXUL() && IsFocused(aFrame)) {
2551 eventState |= NS_EVENT_STATE_FOCUS;
2554 DrawFrame(cgContext, kHIThemeFrameTextFieldSquare, macRect,
2555 IsDisabled(aFrame, eventState) || IsReadOnly(aFrame), eventState);
2558 case NS_THEME_SEARCHFIELD:
2559 DrawSearchField(cgContext, macRect, aFrame, eventState);
2562 case NS_THEME_PROGRESSBAR:
2564 double value = GetProgressValue(aFrame);
2565 double maxValue = GetProgressMaxValue(aFrame);
2566 // Don't request repaints for scrollbars at 100% because those don't animate.
2567 if (value < maxValue) {
2568 if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) {
2569 NS_WARNING("Unable to animate progressbar!");
2572 DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame, eventState),
2573 aFrame->StyleDisplay()->mOrient != NS_STYLE_ORIENT_VERTICAL,
2574 value, maxValue, aFrame);
2578 case NS_THEME_PROGRESSBAR_VERTICAL:
2579 DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame, eventState),
2580 false, GetProgressValue(aFrame),
2581 GetProgressMaxValue(aFrame), aFrame);
2584 case NS_THEME_METERBAR:
2585 DrawMeter(cgContext, macRect, aFrame);
2588 case NS_THEME_PROGRESSBAR_CHUNK:
2589 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
2590 case NS_THEME_METERBAR_CHUNK:
2591 // Do nothing: progress and meter bars cases will draw chunks.
2594 case NS_THEME_TREEVIEW_TWISTY:
2595 DrawButton(cgContext, kThemeDisclosureButton, macRect, false,
2596 kThemeDisclosureRight, kThemeAdornmentNone, eventState, aFrame);
2599 case NS_THEME_TREEVIEW_TWISTY_OPEN:
2600 DrawButton(cgContext, kThemeDisclosureButton, macRect, false,
2601 kThemeDisclosureDown, kThemeAdornmentNone, eventState, aFrame);
2604 case NS_THEME_TREEVIEW_HEADER_CELL: {
2605 TreeSortDirection sortDirection = GetTreeSortDirection(aFrame);
2606 DrawButton(cgContext, kThemeListHeaderButton, macRect, false,
2607 sortDirection == eTreeSortDirection_Natural ? kThemeButtonOff : kThemeButtonOn,
2608 sortDirection == eTreeSortDirection_Ascending ?
2609 kThemeAdornmentHeaderButtonSortUp : kThemeAdornmentNone, eventState, aFrame);
2613 case NS_THEME_TREEVIEW_TREEITEM:
2614 case NS_THEME_TREEVIEW:
2615 // HIThemeSetFill is not available on 10.3
2616 // HIThemeSetFill(kThemeBrushWhite, NULL, cgContext, HITHEME_ORIENTATION);
2617 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
2618 CGContextFillRect(cgContext, macRect);
2621 case NS_THEME_TREEVIEW_HEADER:
2622 // do nothing, taken care of by individual header cells
2623 case NS_THEME_TREEVIEW_HEADER_SORTARROW:
2624 // do nothing, taken care of by treeview header
2625 case NS_THEME_TREEVIEW_LINE:
2626 // do nothing, these lines don't exist on macos
2629 case NS_THEME_SCALE_HORIZONTAL:
2630 case NS_THEME_SCALE_VERTICAL: {
2631 int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
2632 int32_t minpos = CheckIntAttr(aFrame, nsGkAtoms::minpos, 0);
2633 int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
2637 bool reverse = aFrame->GetContent()->
2638 AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
2639 NS_LITERAL_STRING("reverse"), eCaseMatters);
2640 DrawScale(cgContext, macRect, eventState,
2641 (aWidgetType == NS_THEME_SCALE_VERTICAL), reverse,
2642 curpos, minpos, maxpos, aFrame);
2646 case NS_THEME_SCALE_THUMB_HORIZONTAL:
2647 case NS_THEME_SCALE_THUMB_VERTICAL:
2648 // do nothing, drawn by scale
2651 case NS_THEME_RANGE: {
2652 nsRangeFrame *rangeFrame = do_QueryFrame(aFrame);
2656 // DrawScale requires integer min, max and value. This is purely for
2657 // drawing, so we normalize to a range 0-1000 here.
2658 int32_t value = int32_t(rangeFrame->GetValueAsFractionOfRange() * 1000);
2661 bool isVertical = !IsRangeHorizontal(aFrame);
2664 rangeFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
2665 DrawScale(cgContext, macRect, eventState, isVertical, reverseDir,
2666 value, min, max, aFrame);
2670 case NS_THEME_SCROLLBAR_SMALL:
2671 case NS_THEME_SCROLLBAR:
2672 if (!ScrollbarTrackAndThumbDrawSeparately()) {
2673 DrawScrollbar(cgContext, macRect, aFrame);
2676 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
2677 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
2678 if (ScrollbarTrackAndThumbDrawSeparately()) {
2679 BOOL isOverlay = nsLookAndFeel::UseOverlayScrollbars();
2680 BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
2681 BOOL isRolledOver = IsParentScrollbarRolledOver(aFrame);
2682 if (isOverlay && (!nsCocoaFeatures::OnMountainLionOrLater() || !isRolledOver)) {
2684 macRect.origin.y += 4;
2685 macRect.size.height -= 4;
2687 if (aFrame->StyleVisibility()->mDirection !=
2688 NS_STYLE_DIRECTION_RTL) {
2689 macRect.origin.x += 4;
2691 macRect.size.width -= 4;
2694 const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
2695 // Scrollbar thumbs have a too high minimum width when rendered through
2696 // NSAppearance on 10.10, so we call RenderWithCoreUILegacy here.
2697 RenderWithCoreUILegacy(macRect, cgContext,
2698 [NSDictionary dictionaryWithObjectsAndKeys:
2699 (isOverlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
2700 @"regular", @"size",
2701 (isRolledOver ? @"rollover" : @"normal"), @"state",
2702 (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
2703 (isOnTopOfDarkBackground ? @"kCUIVariantWhite" : @""), @"kCUIVariantKey",
2704 [NSNumber numberWithBool:YES], @"indiconly",
2705 [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
2706 [NSNumber numberWithBool:YES], @"is.flipped",
2710 case NS_THEME_SCROLLBAR_BUTTON_UP:
2711 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
2712 #if SCROLLBARS_VISUAL_DEBUG
2713 CGContextSetRGBFillColor(cgContext, 1.0, 0, 0, 0.6);
2714 CGContextFillRect(cgContext, macRect);
2717 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
2718 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
2719 #if SCROLLBARS_VISUAL_DEBUG
2720 CGContextSetRGBFillColor(cgContext, 0, 1.0, 0, 0.6);
2721 CGContextFillRect(cgContext, macRect);
2724 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
2725 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
2726 if (ScrollbarTrackAndThumbDrawSeparately()) {
2727 BOOL isOverlay = nsLookAndFeel::UseOverlayScrollbars();
2728 if (!isOverlay || IsParentScrollbarRolledOver(aFrame)) {
2729 BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
2730 if (isOverlay && !nsCocoaFeatures::OnMountainLionOrLater()) {
2731 // On OSX 10.7, scrollbars don't grow when hovered.
2732 // The adjustments below were obtained by trial and error.
2734 macRect.origin.y += 2.0;
2736 if (aFrame->StyleVisibility()->mDirection !=
2737 NS_STYLE_DIRECTION_RTL) {
2738 macRect.origin.x += 3.0;
2740 macRect.origin.x -= 1.0;
2744 const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
2745 RenderWithCoreUILegacy(macRect, cgContext,
2746 [NSDictionary dictionaryWithObjectsAndKeys:
2747 (isOverlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
2748 @"regular", @"size",
2749 (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
2750 (isOnTopOfDarkBackground ? @"kCUIVariantWhite" : @""), @"kCUIVariantKey",
2751 [NSNumber numberWithBool:YES], @"noindicator",
2752 [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
2753 [NSNumber numberWithBool:YES], @"is.flipped",
2759 case NS_THEME_TEXTFIELD_MULTILINE: {
2760 // we have to draw this by hand because there is no HITheme value for it
2761 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
2763 CGContextFillRect(cgContext, macRect);
2765 CGContextSetLineWidth(cgContext, 1.0);
2766 CGContextSetShouldAntialias(cgContext, false);
2768 // stroke everything but the top line of the text area
2769 CGContextSetRGBStrokeColor(cgContext, 0.6, 0.6, 0.6, 1.0);
2770 CGContextBeginPath(cgContext);
2771 CGContextMoveToPoint(cgContext, macRect.origin.x, macRect.origin.y + 1);
2772 CGContextAddLineToPoint(cgContext, macRect.origin.x, macRect.origin.y + macRect.size.height);
2773 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + macRect.size.height);
2774 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + 1);
2775 CGContextStrokePath(cgContext);
2777 // stroke the line across the top of the text area
2778 CGContextSetRGBStrokeColor(cgContext, 0.4510, 0.4510, 0.4510, 1.0);
2779 CGContextBeginPath(cgContext);
2780 CGContextMoveToPoint(cgContext, macRect.origin.x, macRect.origin.y + 1);
2781 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + 1);
2782 CGContextStrokePath(cgContext);
2784 // draw a focus ring
2785 if (eventState.HasState(NS_EVENT_STATE_FOCUS)) {
2786 // We need to bring the rectangle in by 1 pixel on each side.
2787 CGRect cgr = CGRectMake(macRect.origin.x + 1,
2788 macRect.origin.y + 1,
2789 macRect.size.width - 2,
2790 macRect.size.height - 2);
2791 HIThemeDrawFocusRect(&cgr, true, cgContext, kHIThemeOrientationNormal);
2796 case NS_THEME_LISTBOX: {
2797 // We have to draw this by hand because kHIThemeFrameListBox drawing
2798 // is buggy on 10.5, see bug 579259.
2799 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
2800 CGContextFillRect(cgContext, macRect);
2802 // #8E8E8E for the top border, #BEBEBE for the rest.
2803 float x = macRect.origin.x, y = macRect.origin.y;
2804 float w = macRect.size.width, h = macRect.size.height;
2805 CGContextSetRGBFillColor(cgContext, 0.557, 0.557, 0.557, 1.0);
2806 CGContextFillRect(cgContext, CGRectMake(x, y, w, 1));
2807 CGContextSetRGBFillColor(cgContext, 0.745, 0.745, 0.745, 1.0);
2808 CGContextFillRect(cgContext, CGRectMake(x, y + 1, 1, h - 1));
2809 CGContextFillRect(cgContext, CGRectMake(x + w - 1, y + 1, 1, h - 1));
2810 CGContextFillRect(cgContext, CGRectMake(x + 1, y + h - 1, w - 2, 1));
2815 DrawSegment(cgContext, macRect, eventState, aFrame, tabRenderSettings);
2818 case NS_THEME_TAB_PANELS:
2819 DrawTabPanel(cgContext, macRect, aFrame);
2822 case NS_THEME_RESIZER:
2823 DrawResizer(cgContext, macRect, aFrame);
2826 case NS_THEME_MAC_VIBRANCY_LIGHT:
2827 case NS_THEME_MAC_VIBRANCY_DARK:
2829 NSWindow* win = NativeWindowForFrame(aFrame);
2830 if ([win isKindOfClass:[ToolbarWindow class]]) {
2831 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
2832 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]];
2834 ChildView* childView = [(ToolbarWindow*)win mainChildView];
2835 [[childView vibrancyFillColorForWidgetType:aWidgetType] set];
2836 NSRectFill(NSRectFromCGRect(macRect));
2838 [NSGraphicsContext setCurrentContext:savedContext];
2844 nativeDrawing.EndNativeDrawing();
2848 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2852 nsNativeThemeCocoa::RTLAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame)
2854 if (IsFrameRTL(aFrame)) {
2855 // Return a copy of aMargin w/ right & left reversed:
2856 return nsIntMargin(aMargin.top, aMargin.left,
2857 aMargin.bottom, aMargin.right);
2863 static const nsIntMargin kAquaDropdownBorder(1, 22, 2, 5);
2864 static const nsIntMargin kAquaComboboxBorder(3, 20, 3, 4);
2865 static const nsIntMargin kAquaSearchfieldBorder(3, 5, 2, 19);
2868 nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext,
2870 uint8_t aWidgetType,
2871 nsIntMargin* aResult)
2873 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2875 aResult->SizeTo(0, 0, 0, 0);
2877 switch (aWidgetType) {
2878 case NS_THEME_BUTTON:
2880 if (IsButtonTypeMenu(aFrame)) {
2881 *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
2883 aResult->SizeTo(1, 7, 3, 7);
2888 case NS_THEME_TOOLBAR_BUTTON:
2890 aResult->SizeTo(1, 4, 1, 4);
2894 case NS_THEME_CHECKBOX:
2895 case NS_THEME_RADIO:
2897 // nsFormControlFrame::GetIntrinsicWidth and nsFormControlFrame::GetIntrinsicHeight
2898 // assume a border width of 2px.
2899 aResult->SizeTo(2, 2, 2, 2);
2903 case NS_THEME_DROPDOWN:
2904 case NS_THEME_DROPDOWN_BUTTON:
2905 *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
2908 case NS_THEME_DROPDOWN_TEXTFIELD:
2909 *aResult = RTLAwareMargin(kAquaComboboxBorder, aFrame);
2912 case NS_THEME_NUMBER_INPUT:
2913 case NS_THEME_TEXTFIELD:
2915 SInt32 frameOutset = 0;
2916 ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
2918 SInt32 textPadding = 0;
2919 ::GetThemeMetric(kThemeMetricEditTextWhitespace, &textPadding);
2921 frameOutset += textPadding;
2923 aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
2927 case NS_THEME_TEXTFIELD_MULTILINE:
2928 aResult->SizeTo(1, 1, 1, 1);
2931 case NS_THEME_SEARCHFIELD:
2932 *aResult = RTLAwareMargin(kAquaSearchfieldBorder, aFrame);
2935 case NS_THEME_LISTBOX:
2937 SInt32 frameOutset = 0;
2938 ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
2939 aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
2943 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
2944 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
2946 bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
2948 // On Lion and later, scrollbars have no arrows.
2949 if (!nsCocoaFeatures::OnLionOrLater()) {
2950 // There's only an endcap to worry about when both arrows are on the bottom
2951 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
2952 if (!buttonPlacement || [buttonPlacement isEqualToString:@"DoubleMax"]) {
2953 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
2954 if (!scrollbarFrame) return NS_ERROR_FAILURE;
2955 bool isSmall = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
2957 // There isn't a metric for this, so just hardcode a best guess at the value.
2958 // This value is even less exact due to the fact that the endcap is partially concave.
2959 int32_t endcapSize = isSmall ? 5 : 6;
2962 aResult->SizeTo(0, 0, 0, endcapSize);
2964 aResult->SizeTo(endcapSize, 0, 0, 0);
2968 if (nsLookAndFeel::UseOverlayScrollbars()) {
2970 aResult->SizeTo(2, 1, 1, 1);
2972 aResult->SizeTo(1, 1, 1, 2);
2979 case NS_THEME_STATUSBAR:
2980 aResult->SizeTo(1, 0, 0, 0);
2984 if (IsHiDPIContext(aFrame->PresContext())) {
2985 *aResult = *aResult + *aResult; // doubled
2990 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2993 // Return false here to indicate that CSS padding values should be used. There is
2994 // no reason to make a distinction between padding and border values, just specify
2995 // whatever values you want in GetWidgetBorder and only use this to return true
2996 // if you want to override CSS padding values.
2998 nsNativeThemeCocoa::GetWidgetPadding(nsDeviceContext* aContext,
3000 uint8_t aWidgetType,
3001 nsIntMargin* aResult)
3003 // We don't want CSS padding being used for certain widgets.
3004 // See bug 381639 for an example of why.
3005 switch (aWidgetType) {
3006 case NS_THEME_BUTTON:
3007 // Radios and checkboxes return a fixed size in GetMinimumWidgetSize
3008 // and have a meaningful baseline, so they can't have
3009 // author-specified padding.
3010 case NS_THEME_CHECKBOX:
3011 case NS_THEME_RADIO:
3012 aResult->SizeTo(0, 0, 0, 0);
3019 nsNativeThemeCocoa::GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
3020 uint8_t aWidgetType, nsRect* aOverflowRect)
3022 int32_t p2a = aFrame->PresContext()->AppUnitsPerDevPixel();
3023 switch (aWidgetType) {
3024 case NS_THEME_BUTTON:
3025 case NS_THEME_MOZ_MAC_HELP_BUTTON:
3026 case NS_THEME_TOOLBAR_BUTTON:
3027 case NS_THEME_NUMBER_INPUT:
3028 case NS_THEME_TEXTFIELD:
3029 case NS_THEME_TEXTFIELD_MULTILINE:
3030 case NS_THEME_SEARCHFIELD:
3031 case NS_THEME_LISTBOX:
3032 case NS_THEME_DROPDOWN:
3033 case NS_THEME_DROPDOWN_BUTTON:
3034 case NS_THEME_DROPDOWN_TEXTFIELD:
3035 case NS_THEME_CHECKBOX:
3036 case NS_THEME_RADIO:
3039 // We assume that the above widgets can draw a focus ring that will be less than
3040 // or equal to 4 pixels thick.
3041 nsIntMargin extraSize = nsIntMargin(MAX_FOCUS_RING_WIDTH,
3042 MAX_FOCUS_RING_WIDTH,
3043 MAX_FOCUS_RING_WIDTH,
3044 MAX_FOCUS_RING_WIDTH);
3045 nsMargin m(NSIntPixelsToAppUnits(extraSize.top, p2a),
3046 NSIntPixelsToAppUnits(extraSize.right, p2a),
3047 NSIntPixelsToAppUnits(extraSize.bottom, p2a),
3048 NSIntPixelsToAppUnits(extraSize.left, p2a));
3049 aOverflowRect->Inflate(m);
3052 case NS_THEME_PROGRESSBAR:
3054 // Progress bars draw a 2 pixel white shadow under their progress indicators
3055 nsMargin m(0, 0, NSIntPixelsToAppUnits(2, p2a), 0);
3056 aOverflowRect->Inflate(m);
3059 case NS_THEME_FOCUS_OUTLINE:
3061 aOverflowRect->Inflate(NSIntPixelsToAppUnits(2, p2a));
3069 static const int32_t kRegularScrollbarThumbMinSize = 26;
3070 static const int32_t kSmallScrollbarThumbMinSize = 26;
3073 nsNativeThemeCocoa::GetMinimumWidgetSize(nsPresContext* aPresContext,
3075 uint8_t aWidgetType,
3077 bool* aIsOverridable)
3079 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
3081 aResult->SizeTo(0,0);
3082 *aIsOverridable = true;
3084 switch (aWidgetType) {
3085 case NS_THEME_BUTTON:
3087 aResult->SizeTo(pushButtonSettings.minimumSizes[miniControlSize].width,
3088 pushButtonSettings.naturalSizes[miniControlSize].height);
3092 case NS_THEME_MOZ_MAC_HELP_BUTTON:
3094 aResult->SizeTo(kHelpButtonSize.width, kHelpButtonSize.height);
3095 *aIsOverridable = false;
3099 case NS_THEME_TOOLBAR_BUTTON:
3101 aResult->SizeTo(0, toolbarButtonHeights[miniControlSize]);
3105 case NS_THEME_SPINNER:
3106 case NS_THEME_SPINNER_UP_BUTTON:
3107 case NS_THEME_SPINNER_DOWN_BUTTON:
3109 SInt32 buttonHeight = 0, buttonWidth = 0;
3110 if (aFrame->GetContent()->IsXUL()) {
3111 ::GetThemeMetric(kThemeMetricLittleArrowsWidth, &buttonWidth);
3112 ::GetThemeMetric(kThemeMetricLittleArrowsHeight, &buttonHeight);
3115 spinnerSettings.minimumSizes[EnumSizeForCocoaSize(NSMiniControlSize)];
3116 buttonWidth = size.width;
3117 buttonHeight = size.height;
3118 if (aWidgetType != NS_THEME_SPINNER) {
3119 // the buttons are half the height of the spinner
3123 aResult->SizeTo(buttonWidth, buttonHeight);
3124 *aIsOverridable = true;
3128 case NS_THEME_DROPDOWN:
3129 case NS_THEME_DROPDOWN_BUTTON:
3131 SInt32 popupHeight = 0;
3132 ::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
3133 aResult->SizeTo(0, popupHeight);
3137 case NS_THEME_NUMBER_INPUT:
3138 case NS_THEME_TEXTFIELD:
3139 case NS_THEME_TEXTFIELD_MULTILINE:
3140 case NS_THEME_SEARCHFIELD:
3142 // at minimum, we should be tall enough for 9pt text.
3143 // I'm using hardcoded values here because the appearance manager
3144 // values for the frame size are incorrect.
3145 aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */);
3149 case NS_THEME_WINDOW_BUTTON_BOX: {
3150 NSSize size = WindowButtonsSize(aFrame);
3151 aResult->SizeTo(size.width, size.height);
3152 *aIsOverridable = false;
3156 case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: {
3157 if ([NativeWindowForFrame(aFrame) respondsToSelector:@selector(toggleFullScreen:)] &&
3158 !nsCocoaFeatures::OnYosemiteOrLater()) {
3159 // This value is hardcoded because it's needed before we can measure the
3160 // position and size of the fullscreen button.
3161 aResult->SizeTo(16, 17);
3163 *aIsOverridable = false;
3167 case NS_THEME_PROGRESSBAR:
3169 SInt32 barHeight = 0;
3170 ::GetThemeMetric(kThemeMetricNormalProgressBarThickness, &barHeight);
3171 aResult->SizeTo(0, barHeight);
3175 case NS_THEME_TREEVIEW_TWISTY:
3176 case NS_THEME_TREEVIEW_TWISTY_OPEN:
3178 SInt32 twistyHeight = 0, twistyWidth = 0;
3179 ::GetThemeMetric(kThemeMetricDisclosureButtonWidth, &twistyWidth);
3180 ::GetThemeMetric(kThemeMetricDisclosureButtonHeight, &twistyHeight);
3181 aResult->SizeTo(twistyWidth, twistyHeight);
3182 *aIsOverridable = false;
3186 case NS_THEME_TREEVIEW_HEADER:
3187 case NS_THEME_TREEVIEW_HEADER_CELL:
3189 SInt32 headerHeight = 0;
3190 ::GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
3191 aResult->SizeTo(0, headerHeight - 1); // We don't need the top border.
3197 aResult->SizeTo(0, tabHeights[miniControlSize]);
3201 case NS_THEME_RANGE:
3203 // The Mac Appearance Manager API (the old API we're currently using)
3204 // doesn't define constants to obtain a minimum size for sliders. We use
3205 // the "thickness" of a slider that has default dimensions for both the
3206 // minimum width and height to get something sane and so that paint
3207 // invalidation works.
3209 if (IsRangeHorizontal(aFrame)) {
3210 ::GetThemeMetric(kThemeMetricHSliderHeight, &size);
3212 ::GetThemeMetric(kThemeMetricVSliderWidth, &size);
3214 aResult->SizeTo(size, size);
3215 *aIsOverridable = true;
3219 case NS_THEME_RANGE_THUMB:
3223 ::GetThemeMetric(kThemeMetricSliderMinThumbWidth, &width);
3224 ::GetThemeMetric(kThemeMetricSliderMinThumbHeight, &height);
3225 aResult->SizeTo(width, height);
3226 *aIsOverridable = false;
3230 case NS_THEME_SCALE_HORIZONTAL:
3232 SInt32 scaleHeight = 0;
3233 ::GetThemeMetric(kThemeMetricHSliderHeight, &scaleHeight);
3234 aResult->SizeTo(scaleHeight, scaleHeight);
3235 *aIsOverridable = false;
3239 case NS_THEME_SCALE_VERTICAL:
3241 SInt32 scaleWidth = 0;
3242 ::GetThemeMetric(kThemeMetricVSliderWidth, &scaleWidth);
3243 aResult->SizeTo(scaleWidth, scaleWidth);
3244 *aIsOverridable = false;
3248 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
3249 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
3251 // Find our parent scrollbar frame in order to find out whether we're in
3252 // a small or a large scrollbar.
3253 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
3254 if (!scrollbarFrame)
3255 return NS_ERROR_FAILURE;
3257 bool isSmall = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
3258 bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
3259 int32_t& minSize = isHorizontal ? aResult->width : aResult->height;
3260 minSize = isSmall ? kSmallScrollbarThumbMinSize : kRegularScrollbarThumbMinSize;
3264 case NS_THEME_SCROLLBAR:
3265 case NS_THEME_SCROLLBAR_SMALL:
3266 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
3267 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
3269 *aIsOverridable = false;
3271 if (nsLookAndFeel::UseOverlayScrollbars()) {
3272 nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
3273 if (scrollbarFrame &&
3274 scrollbarFrame->StyleDisplay()->mAppearance ==
3275 NS_THEME_SCROLLBAR_SMALL) {
3276 aResult->SizeTo(14, 14);
3279 aResult->SizeTo(16, 16);
3284 // yeah, i know i'm cheating a little here, but i figure that it
3285 // really doesn't matter if the scrollbar is vertical or horizontal
3286 // and the width metric is a really good metric for every piece
3287 // of the scrollbar.
3289 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
3290 if (!scrollbarFrame) return NS_ERROR_FAILURE;
3292 int32_t themeMetric = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
3293 kThemeMetricSmallScrollBarWidth :
3294 kThemeMetricScrollBarWidth;
3295 SInt32 scrollbarWidth = 0;
3296 ::GetThemeMetric(themeMetric, &scrollbarWidth);
3297 aResult->SizeTo(scrollbarWidth, scrollbarWidth);
3301 case NS_THEME_SCROLLBAR_NON_DISAPPEARING:
3303 int32_t themeMetric = kThemeMetricScrollBarWidth;
3306 nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
3307 if (scrollbarFrame &&
3308 scrollbarFrame->StyleDisplay()->mAppearance ==
3309 NS_THEME_SCROLLBAR_SMALL) {
3310 // XXX We're interested in the width of non-disappearing scrollbars
3311 // to leave enough space for a dropmarker in non-native styled
3312 // comboboxes (bug 869314). It isn't clear to me if comboboxes can
3313 // ever have small scrollbars.
3314 themeMetric = kThemeMetricSmallScrollBarWidth;
3318 SInt32 scrollbarWidth = 0;
3319 ::GetThemeMetric(themeMetric, &scrollbarWidth);
3320 aResult->SizeTo(scrollbarWidth, scrollbarWidth);
3324 case NS_THEME_SCROLLBAR_BUTTON_UP:
3325 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
3326 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
3327 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
3329 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
3330 if (!scrollbarFrame) return NS_ERROR_FAILURE;
3332 // Since there is no NS_THEME_SCROLLBAR_BUTTON_UP_SMALL we need to ask the parent what appearance style it has.
3333 int32_t themeMetric = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
3334 kThemeMetricSmallScrollBarWidth :
3335 kThemeMetricScrollBarWidth;
3336 SInt32 scrollbarWidth = 0;
3337 ::GetThemeMetric(themeMetric, &scrollbarWidth);
3339 // It seems that for both sizes of scrollbar, the buttons are one pixel "longer".
3340 if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT)
3341 aResult->SizeTo(scrollbarWidth+1, scrollbarWidth);
3343 aResult->SizeTo(scrollbarWidth, scrollbarWidth+1);
3345 *aIsOverridable = false;
3348 case NS_THEME_RESIZER:
3350 HIThemeGrowBoxDrawInfo drawInfo;
3351 drawInfo.version = 0;
3352 drawInfo.state = kThemeStateActive;
3353 drawInfo.kind = kHIThemeGrowBoxKindNormal;
3354 drawInfo.direction = kThemeGrowRight | kThemeGrowDown;
3355 drawInfo.size = kHIThemeGrowBoxSizeNormal;
3356 HIPoint pnt = { 0, 0 };
3358 HIThemeGetGrowBoxBounds(&pnt, &drawInfo, &bounds);
3359 aResult->SizeTo(bounds.size.width, bounds.size.height);
3360 *aIsOverridable = false;
3364 if (IsHiDPIContext(aPresContext)) {
3365 *aResult = *aResult * 2;
3370 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
3374 nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
3375 nsIAtom* aAttribute, bool* aShouldRepaint)
3377 // Some widget types just never change state.
3378 switch (aWidgetType) {
3379 case NS_THEME_WINDOW_TITLEBAR:
3380 case NS_THEME_TOOLBOX:
3381 case NS_THEME_TOOLBAR:
3382 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
3383 case NS_THEME_STATUSBAR:
3384 case NS_THEME_STATUSBAR_PANEL:
3385 case NS_THEME_STATUSBAR_RESIZER_PANEL:
3386 case NS_THEME_TOOLTIP:
3387 case NS_THEME_TAB_PANELS:
3388 case NS_THEME_TAB_PANEL:
3389 case NS_THEME_DIALOG:
3390 case NS_THEME_MENUPOPUP:
3391 case NS_THEME_GROUPBOX:
3392 case NS_THEME_PROGRESSBAR_CHUNK:
3393 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
3394 case NS_THEME_PROGRESSBAR:
3395 case NS_THEME_PROGRESSBAR_VERTICAL:
3396 case NS_THEME_METERBAR:
3397 case NS_THEME_METERBAR_CHUNK:
3398 *aShouldRepaint = false;
3402 // XXXdwh Not sure what can really be done here. Can at least guess for
3403 // specific widgets that they're highly unlikely to have certain states.
3404 // For example, a toolbar doesn't care about any states.
3406 // Hover/focus/active changed. Always repaint.
3407 *aShouldRepaint = true;
3409 // Check the attribute to see if it's relevant.
3410 // disabled, checked, dlgtype, default, etc.
3411 *aShouldRepaint = false;
3412 if (aAttribute == nsGkAtoms::disabled ||
3413 aAttribute == nsGkAtoms::checked ||
3414 aAttribute == nsGkAtoms::selected ||
3415 aAttribute == nsGkAtoms::menuactive ||
3416 aAttribute == nsGkAtoms::sortDirection ||
3417 aAttribute == nsGkAtoms::focused ||
3418 aAttribute == nsGkAtoms::_default ||
3419 aAttribute == nsGkAtoms::open ||
3420 aAttribute == nsGkAtoms::hover)
3421 *aShouldRepaint = true;
3423 if ((aWidgetType == NS_THEME_SCROLLBAR ||
3424 aWidgetType == NS_THEME_SCROLLBAR_SMALL) &&
3425 !ScrollbarTrackAndThumbDrawSeparately() &&
3426 (aAttribute == nsGkAtoms::curpos ||
3427 aAttribute == nsGkAtoms::minpos ||
3428 aAttribute == nsGkAtoms::maxpos ||
3429 aAttribute == nsGkAtoms::pageincrement)) {
3430 // 10.6-style scrollbars paint the thumb as part of the scrollbar,
3431 // so we need to invalidate the scrollbar when the thumb moves.
3432 *aShouldRepaint = true;
3440 nsNativeThemeCocoa::ThemeChanged()
3442 // This is unimplemented because we don't care if gecko changes its theme
3443 // and Mac OS X doesn't have themes.
3448 nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
3449 uint8_t aWidgetType)
3451 // We don't have CSS set up to render non-native scrollbars on Mac OS X so we
3452 // render natively even if native theme support is disabled.
3453 if (aWidgetType != NS_THEME_SCROLLBAR &&
3454 aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled())
3457 // if this is a dropdown button in a combobox the answer is always no
3458 if (aWidgetType == NS_THEME_DROPDOWN_BUTTON) {
3459 nsIFrame* parentFrame = aFrame->GetParent();
3460 if (parentFrame && (parentFrame->GetType() == nsGkAtoms::comboboxControlFrame))
3464 switch (aWidgetType) {
3465 case NS_THEME_LISTBOX:
3467 case NS_THEME_DIALOG:
3468 case NS_THEME_WINDOW:
3469 case NS_THEME_WINDOW_BUTTON_BOX:
3470 case NS_THEME_WINDOW_TITLEBAR:
3471 case NS_THEME_CHECKMENUITEM:
3472 case NS_THEME_MENUPOPUP:
3473 case NS_THEME_MENUITEM:
3474 case NS_THEME_MENUSEPARATOR:
3475 case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
3476 case NS_THEME_TOOLTIP:
3478 case NS_THEME_CHECKBOX:
3479 case NS_THEME_CHECKBOX_CONTAINER:
3480 case NS_THEME_RADIO:
3481 case NS_THEME_RADIO_CONTAINER:
3482 case NS_THEME_GROUPBOX:
3483 case NS_THEME_MOZ_MAC_HELP_BUTTON:
3484 case NS_THEME_BUTTON:
3485 case NS_THEME_BUTTON_BEVEL:
3486 case NS_THEME_TOOLBAR_BUTTON:
3487 case NS_THEME_SPINNER:
3488 case NS_THEME_SPINNER_UP_BUTTON:
3489 case NS_THEME_SPINNER_DOWN_BUTTON:
3490 case NS_THEME_TOOLBAR:
3491 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
3492 case NS_THEME_STATUSBAR:
3493 case NS_THEME_NUMBER_INPUT:
3494 case NS_THEME_TEXTFIELD:
3495 case NS_THEME_TEXTFIELD_MULTILINE:
3496 case NS_THEME_SEARCHFIELD:
3497 //case NS_THEME_TOOLBOX:
3498 //case NS_THEME_TOOLBAR_BUTTON:
3499 case NS_THEME_PROGRESSBAR:
3500 case NS_THEME_PROGRESSBAR_VERTICAL:
3501 case NS_THEME_PROGRESSBAR_CHUNK:
3502 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
3503 case NS_THEME_METERBAR:
3504 case NS_THEME_METERBAR_CHUNK:
3505 case NS_THEME_TOOLBAR_SEPARATOR:
3507 case NS_THEME_TAB_PANELS:
3510 case NS_THEME_TREEVIEW_TWISTY:
3511 case NS_THEME_TREEVIEW_TWISTY_OPEN:
3512 case NS_THEME_TREEVIEW:
3513 case NS_THEME_TREEVIEW_HEADER:
3514 case NS_THEME_TREEVIEW_HEADER_CELL:
3515 case NS_THEME_TREEVIEW_HEADER_SORTARROW:
3516 case NS_THEME_TREEVIEW_TREEITEM:
3517 case NS_THEME_TREEVIEW_LINE:
3519 case NS_THEME_RANGE:
3521 case NS_THEME_SCALE_HORIZONTAL:
3522 case NS_THEME_SCALE_THUMB_HORIZONTAL:
3523 case NS_THEME_SCALE_VERTICAL:
3524 case NS_THEME_SCALE_THUMB_VERTICAL:
3526 case NS_THEME_SCROLLBAR:
3527 case NS_THEME_SCROLLBAR_SMALL:
3528 case NS_THEME_SCROLLBAR_BUTTON_UP:
3529 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
3530 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
3531 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
3532 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
3533 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
3534 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
3535 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
3536 case NS_THEME_SCROLLBAR_NON_DISAPPEARING:
3538 case NS_THEME_DROPDOWN:
3539 case NS_THEME_DROPDOWN_BUTTON:
3540 case NS_THEME_DROPDOWN_TEXT:
3541 case NS_THEME_DROPDOWN_TEXTFIELD:
3542 return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
3545 case NS_THEME_RESIZER:
3547 nsIFrame* parentFrame = aFrame->GetParent();
3548 if (!parentFrame || parentFrame->GetType() != nsGkAtoms::scrollFrame)
3551 // Note that IsWidgetStyled is not called for resizers on Mac. This is
3552 // because for scrollable containers, the native resizer looks better
3553 // when (non-overlay) scrollbars are present even when the style is
3554 // overriden, and the custom transparent resizer looks better when
3555 // scrollbars are not present.
3556 nsIScrollableFrame* scrollFrame = do_QueryFrame(parentFrame);
3557 return (!nsLookAndFeel::UseOverlayScrollbars() &&
3558 scrollFrame && scrollFrame->GetScrollbarVisibility());
3561 case NS_THEME_FOCUS_OUTLINE:
3564 case NS_THEME_MAC_VIBRANCY_LIGHT:
3565 case NS_THEME_MAC_VIBRANCY_DARK:
3566 return VibrancyManager::SystemSupportsVibrancy();
3573 nsNativeThemeCocoa::WidgetIsContainer(uint8_t aWidgetType)
3575 // flesh this out at some point
3576 switch (aWidgetType) {
3577 case NS_THEME_DROPDOWN_BUTTON:
3578 case NS_THEME_RADIO:
3579 case NS_THEME_CHECKBOX:
3580 case NS_THEME_PROGRESSBAR:
3581 case NS_THEME_METERBAR:
3582 case NS_THEME_RANGE:
3583 case NS_THEME_MOZ_MAC_HELP_BUTTON:
3591 nsNativeThemeCocoa::ThemeDrawsFocusForWidget(uint8_t aWidgetType)
3593 if (aWidgetType == NS_THEME_DROPDOWN ||
3594 aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
3595 aWidgetType == NS_THEME_BUTTON ||
3596 aWidgetType == NS_THEME_MOZ_MAC_HELP_BUTTON ||
3597 aWidgetType == NS_THEME_RADIO ||
3598 aWidgetType == NS_THEME_RANGE ||
3599 aWidgetType == NS_THEME_CHECKBOX)
3606 nsNativeThemeCocoa::ThemeNeedsComboboxDropmarker()
3612 nsNativeThemeCocoa::WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType)
3614 switch (aWidgetType) {
3615 case NS_THEME_DIALOG:
3616 case NS_THEME_GROUPBOX:
3617 case NS_THEME_TAB_PANELS:
3618 case NS_THEME_CHECKMENUITEM:
3619 case NS_THEME_MENUPOPUP:
3620 case NS_THEME_MENUITEM:
3621 case NS_THEME_MENUSEPARATOR:
3622 case NS_THEME_TOOLTIP:
3623 case NS_THEME_SPINNER:
3624 case NS_THEME_SPINNER_UP_BUTTON:
3625 case NS_THEME_SPINNER_DOWN_BUTTON:
3626 case NS_THEME_TOOLBAR_SEPARATOR:
3627 case NS_THEME_TOOLBOX:
3628 case NS_THEME_NUMBER_INPUT:
3629 case NS_THEME_TEXTFIELD:
3630 case NS_THEME_TREEVIEW:
3631 case NS_THEME_TREEVIEW_LINE:
3632 case NS_THEME_TEXTFIELD_MULTILINE:
3633 case NS_THEME_LISTBOX:
3634 case NS_THEME_RESIZER:
3642 nsNativeThemeCocoa::NeedToClearBackgroundBehindWidget(uint8_t aWidgetType)
3644 switch (aWidgetType) {
3645 case NS_THEME_MAC_VIBRANCY_LIGHT:
3646 case NS_THEME_MAC_VIBRANCY_DARK:
3653 nsITheme::Transparency
3654 nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
3656 switch (aWidgetType) {
3657 case NS_THEME_MENUPOPUP:
3658 case NS_THEME_TOOLTIP:
3659 return eTransparent;
3661 case NS_THEME_SCROLLBAR_SMALL:
3662 case NS_THEME_SCROLLBAR:
3663 return nsLookAndFeel::UseOverlayScrollbars() ? eTransparent : eOpaque;
3665 case NS_THEME_STATUSBAR:
3666 // Knowing that scrollbars and statusbars are opaque improves
3667 // performance, because we create layers for them.
3670 case NS_THEME_TOOLBAR:
3671 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
3675 return eUnknownTransparency;