--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -203,16 +203,45 @@ public:
};
struct TreeHeaderCellParams {
ControlParams controlParams;
TreeSortDirection sortDirection = eTreeSortDirection_Natural;
bool lastTreeHeaderCell = false;
};
+ struct ScaleParams {
+ int32_t value = 0;
+ int32_t min = 0;
+ int32_t max = 0;
+ bool insideActiveWindow = false;
+ bool disabled = false;
+ bool focused = false;
+ bool horizontal = true;
+ bool reverse = false;
+ };
+
+ struct ScrollbarParams {
+ ScrollbarParams()
+ : overlay(false)
+ , rolledOver(false)
+ , small(false)
+ , horizontal(false)
+ , rtl(false)
+ , onDarkBackground(false)
+ {}
+
+ bool overlay : 1;
+ bool rolledOver : 1;
+ bool small : 1;
+ bool horizontal : 1;
+ bool rtl : 1;
+ bool onDarkBackground : 1;
+ };
+
nsNativeThemeCocoa();
NS_DECL_ISUPPORTS_INHERITED
// The nsITheme interface.
NS_IMETHOD DrawWidgetBackground(gfxContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
@@ -284,29 +313,33 @@ protected:
SearchFieldParams ComputeSearchFieldParams(nsIFrame* aFrame,
mozilla::EventStates aEventState);
ProgressParams ComputeProgressParams(nsIFrame* aFrame,
mozilla::EventStates aEventState,
bool aIsHorizontal);
MeterParams ComputeMeterParams(nsIFrame* aFrame);
TreeHeaderCellParams ComputeTreeHeaderCellParams(nsIFrame* aFrame,
mozilla::EventStates aEventState);
+ ScaleParams ComputeXULScaleParams(nsIFrame* aFrame,
+ mozilla::EventStates aEventState,
+ bool aIsHorizontal);
+ mozilla::Maybe<ScaleParams> ComputeHTMLScaleParams(nsIFrame* aFrame,
+ mozilla::EventStates aEventState);
+ ScrollbarParams ComputeScrollbarParams(nsIFrame* aFrame, bool aIsHorizontal);
// HITheme drawing routines
void DrawTextBox(CGContextRef context, const HIRect& inBoxRect,
TextBoxParams aParams);
void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
const MeterParams& aParams);
void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
const SegmentParams& aParams);
void DrawTabPanel(CGContextRef context, const HIRect& inBoxRect, nsIFrame* aFrame);
void DrawScale(CGContextRef context, const HIRect& inBoxRect,
- mozilla::EventStates inState, bool inDirection,
- bool inIsReverse, int32_t inCurrentValue, int32_t inMinValue,
- int32_t inMaxValue, nsIFrame* aFrame);
+ const ScaleParams& aParams);
void DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox,
const HIRect& inBoxRect,
const CheckboxOrRadioParams& aParams);
void DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
const SearchFieldParams& aParams);
void DrawRoundedBezelPushButton(CGContextRef cgContext,
const HIRect& inBoxRect,
ControlParams aControlParams);
@@ -345,16 +378,20 @@ protected:
void DrawSpinButton(CGContextRef context,
const HIRect& inBoxRect, SpinButton aDrawnButton,
const SpinButtonParams& aParams);
void DrawUnifiedToolbar(CGContextRef cgContext, const HIRect& inBoxRect,
const UnifiedToolbarParams& aParams);
void DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect,
nsIFrame *aFrame);
void DrawResizer(CGContextRef cgContext, const HIRect& aRect, nsIFrame *aFrame);
+ void DrawScrollbarThumb(CGContextRef cgContext, const CGRect& inBoxRect,
+ ScrollbarParams aParams);
+ void DrawScrollbarTrack(CGContextRef cgContext, const CGRect& inBoxRect,
+ ScrollbarParams aParams);
// Scrollbars
nsIFrame* GetParentScrollbarFrame(nsIFrame *aFrame);
bool IsParentScrollbarRolledOver(nsIFrame* aFrame);
private:
NSButtonCell* mDisclosureButtonCell;
NSButtonCell* mHelpButtonCell;
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2281,44 +2281,96 @@ nsNativeThemeCocoa::DrawTabPanel(CGConte
tpdi.size = kHIThemeTabSizeNormal;
tpdi.kind = kHIThemeTabKindNormal;
HIThemeDrawTabPane(&inBoxRect, &tpdi, cgContext, HITHEME_ORIENTATION);
NS_OBJC_END_TRY_ABORT_BLOCK;
}
+nsNativeThemeCocoa::ScaleParams
+nsNativeThemeCocoa::ComputeXULScaleParams(nsIFrame* aFrame,
+ EventStates aEventState,
+ bool aIsHorizontal)
+{
+ ScaleParams params;
+ params.value = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
+ params.min = CheckIntAttr(aFrame, nsGkAtoms::minpos, 0);
+ params.max = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
+ if (!params.max) {
+ params.max = 100;
+ }
+
+ params.reverse =
+ aFrame->GetContent()->IsElement() &&
+ aFrame->GetContent()->AsElement()->AttrValueIs(
+ kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("reverse"),
+ eCaseMatters);
+ params.insideActiveWindow = FrameIsInActiveWindow(aFrame);
+ params.focused = aEventState.HasState(NS_EVENT_STATE_FOCUS);
+ params.disabled = IsDisabled(aFrame, aEventState);
+ params.horizontal = aIsHorizontal;
+ return params;
+}
+
+Maybe<nsNativeThemeCocoa::ScaleParams>
+nsNativeThemeCocoa::ComputeHTMLScaleParams(nsIFrame* aFrame,
+ EventStates aEventState)
+{
+ nsRangeFrame *rangeFrame = do_QueryFrame(aFrame);
+ if (!rangeFrame) {
+ return Nothing();
+ }
+
+ bool isHorizontal = IsRangeHorizontal(aFrame);
+
+ // ScaleParams requires integer min, max and value. This is purely for
+ // drawing, so we normalize to a range 0-1000 here.
+ ScaleParams params;
+ params.value = int32_t(rangeFrame->GetValueAsFractionOfRange() * 1000);
+ params.min = 0;
+ params.max = 1000;
+ params.reverse = !isHorizontal || rangeFrame->IsRightToLeft();
+ params.insideActiveWindow = FrameIsInActiveWindow(aFrame);
+ params.focused = aEventState.HasState(NS_EVENT_STATE_FOCUS);
+ params.disabled = IsDisabled(aFrame, aEventState);
+ params.horizontal = isHorizontal;
+ return Some(params);
+}
+
void
nsNativeThemeCocoa::DrawScale(CGContextRef cgContext, const HIRect& inBoxRect,
- EventStates inState, bool inIsVertical,
- bool inIsReverse, int32_t inCurrentValue,
- int32_t inMinValue, int32_t inMaxValue,
- nsIFrame* aFrame)
+ const ScaleParams& aParams)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
HIThemeTrackDrawInfo tdi;
tdi.version = 0;
tdi.kind = kThemeMediumSlider;
tdi.bounds = inBoxRect;
- tdi.min = inMinValue;
- tdi.max = inMaxValue;
- tdi.value = inCurrentValue;
+ tdi.min = aParams.min;
+ tdi.max = aParams.max;
+ tdi.value = aParams.value;
tdi.attributes = kThemeTrackShowThumb;
- if (!inIsVertical)
+ if (aParams.horizontal) {
tdi.attributes |= kThemeTrackHorizontal;
- if (inIsReverse)
+ }
+ if (aParams.reverse) {
tdi.attributes |= kThemeTrackRightToLeft;
- if (inState.HasState(NS_EVENT_STATE_FOCUS))
+ }
+ if (aParams.focused) {
tdi.attributes |= kThemeTrackHasFocus;
- if (IsDisabled(aFrame, inState))
+ }
+ if (aParams.disabled) {
tdi.enableState = kThemeTrackDisabled;
- else
- tdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
+ } else {
+ tdi.enableState =
+ aParams.insideActiveWindow ? kThemeTrackActive : kThemeTrackInactive;
+ }
tdi.trackInfo.slider.thumbDir = kThemeThumbPlain;
tdi.trackInfo.slider.pressState = 0;
HIThemeDrawTrack(&tdi, NULL, cgContext, HITHEME_ORIENTATION);
NS_OBJC_END_TRY_ABORT_BLOCK;
}
@@ -2593,16 +2645,91 @@ nsNativeThemeCocoa::DrawResizer(CGContex
drawInfo.size = kHIThemeGrowBoxSizeNormal;
RenderTransformedHIThemeControl(cgContext, aRect, RenderResizer, &drawInfo,
IsFrameRTL(aFrame));
NS_OBJC_END_TRY_ABORT_BLOCK;
}
+nsNativeThemeCocoa::ScrollbarParams
+nsNativeThemeCocoa::ComputeScrollbarParams(nsIFrame* aFrame, bool aIsHorizontal)
+{
+ ScrollbarParams params;
+ params.overlay = nsLookAndFeel::UseOverlayScrollbars();
+ params.rolledOver = IsParentScrollbarRolledOver(aFrame);
+ nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
+ params.small =
+ (scrollbarFrame &&
+ scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
+ params.rtl = aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+ params.horizontal = aIsHorizontal;
+ params.onDarkBackground = IsDarkBackground(aFrame);
+ return params;
+}
+
+void
+nsNativeThemeCocoa::DrawScrollbarThumb(CGContextRef cgContext,
+ const CGRect& inBoxRect,
+ ScrollbarParams aParams)
+{
+ CGRect drawRect = inBoxRect;
+ if (aParams.overlay && !aParams.rolledOver) {
+ if (aParams.horizontal) {
+ drawRect.origin.y += 4;
+ drawRect.size.height -= 4;
+ } else {
+ if (!aParams.rtl) {
+ drawRect.origin.x += 4;
+ }
+ drawRect.size.width -= 4;
+ }
+ }
+ NSDictionary* options = @{
+ @"widget": (aParams.overlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"),
+ @"size": (aParams.small ? @"small" : @"regular"),
+ @"kCUIOrientationKey":
+ (aParams.horizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"),
+ @"kCUIVariantKey":
+ (aParams.overlay && aParams.onDarkBackground ? @"kCUIVariantWhite" : @""),
+ @"indiconly": [NSNumber numberWithBool:YES],
+ @"kCUIThumbProportionKey": [NSNumber numberWithBool:YES],
+ @"is.flipped": [NSNumber numberWithBool:YES],
+ };
+ if (aParams.rolledOver) {
+ NSMutableDictionary* mutableOptions = [options mutableCopy];
+ [mutableOptions setObject:@"rollover" forKey:@"state"];
+ options = mutableOptions;
+ }
+ RenderWithCoreUI(drawRect, cgContext, options, true);
+}
+
+void
+nsNativeThemeCocoa::DrawScrollbarTrack(CGContextRef cgContext,
+ const CGRect& inBoxRect,
+ ScrollbarParams aParams)
+{
+ if (aParams.overlay && !aParams.rolledOver) {
+ // Non-hovered overlay scrollbars don't have a track. Draw nothing.
+ return;
+ }
+
+ RenderWithCoreUI(inBoxRect, cgContext,
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ (aParams.overlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
+ (aParams.small ? @"small" : @"regular"), @"size",
+ (aParams.horizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
+ (aParams.onDarkBackground ? @"kCUIVariantWhite" : @""), @"kCUIVariantKey",
+ [NSNumber numberWithBool:YES], @"noindicator",
+ [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
+ [NSNumber numberWithBool:YES], @"is.flipped",
+ nil],
+ true);
+}
+
static void
DrawVibrancyBackground(CGContextRef cgContext, CGRect inBoxRect,
nsIFrame* aFrame, nsITheme::ThemeGeometryType aThemeGeometryType)
{
DrawVibrancyBackground(cgContext, inBoxRect,
VibrancyFillColor(aFrame, aThemeGeometryType), 0);
}
@@ -3086,93 +3213,43 @@ nsNativeThemeCocoa::DrawWidgetBackground
// do nothing, taken care of by individual header cells
case NS_THEME_TREEHEADERSORTARROW:
// do nothing, taken care of by treeview header
case NS_THEME_TREELINE:
// do nothing, these lines don't exist on macos
break;
case NS_THEME_SCALE_HORIZONTAL:
- case NS_THEME_SCALE_VERTICAL: {
- int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
- int32_t minpos = CheckIntAttr(aFrame, nsGkAtoms::minpos, 0);
- int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
- if (!maxpos)
- maxpos = 100;
-
- bool reverse =
- aFrame->GetContent()->IsElement() &&
- aFrame->GetContent()->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
- NS_LITERAL_STRING("reverse"), eCaseMatters);
- DrawScale(cgContext, macRect, eventState,
- (aWidgetType == NS_THEME_SCALE_VERTICAL), reverse,
- curpos, minpos, maxpos, aFrame);
- }
+ case NS_THEME_SCALE_VERTICAL:
+ DrawScale(cgContext, macRect,
+ ComputeXULScaleParams(aFrame, eventState,
+ aWidgetType == NS_THEME_SCALE_HORIZONTAL));
break;
case NS_THEME_SCALETHUMB_HORIZONTAL:
case NS_THEME_SCALETHUMB_VERTICAL:
// do nothing, drawn by scale
break;
case NS_THEME_RANGE: {
- nsRangeFrame *rangeFrame = do_QueryFrame(aFrame);
- if (!rangeFrame) {
- break;
+ Maybe<ScaleParams> params = ComputeHTMLScaleParams(aFrame, eventState);
+ if (params) {
+ DrawScale(cgContext, macRect, *params);
}
- // DrawScale requires integer min, max and value. This is purely for
- // drawing, so we normalize to a range 0-1000 here.
- int32_t value = int32_t(rangeFrame->GetValueAsFractionOfRange() * 1000);
- int32_t min = 0;
- int32_t max = 1000;
- bool isVertical = !IsRangeHorizontal(aFrame);
- bool reverseDir = isVertical || rangeFrame->IsRightToLeft();
- DrawScale(cgContext, macRect, eventState, isVertical, reverseDir,
- value, min, max, aFrame);
break;
}
case NS_THEME_SCROLLBAR_SMALL:
case NS_THEME_SCROLLBAR:
break;
case NS_THEME_SCROLLBARTHUMB_VERTICAL:
- case NS_THEME_SCROLLBARTHUMB_HORIZONTAL: {
- BOOL isOverlay = nsLookAndFeel::UseOverlayScrollbars();
- BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL);
- BOOL isRolledOver = IsParentScrollbarRolledOver(aFrame);
- nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
- bool isSmall = (scrollbarFrame && scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
- if (isOverlay && !isRolledOver) {
- if (isHorizontal) {
- macRect.origin.y += 4;
- macRect.size.height -= 4;
- } else {
- if (aFrame->StyleVisibility()->mDirection !=
- NS_STYLE_DIRECTION_RTL) {
- macRect.origin.x += 4;
- }
- macRect.size.width -= 4;
- }
- }
- const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
- NSMutableDictionary* options = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- (isOverlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
- (isSmall ? @"small" : @"regular"), @"size",
- (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
- (isOverlay && isOnTopOfDarkBackground ? @"kCUIVariantWhite" : @""),
- @"kCUIVariantKey",
- [NSNumber numberWithBool:YES], @"indiconly",
- [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
- [NSNumber numberWithBool:YES], @"is.flipped",
- nil];
- if (isRolledOver) {
- [options setObject:@"rollover" forKey:@"state"];
- }
- RenderWithCoreUI(macRect, cgContext, options, true);
- }
+ case NS_THEME_SCROLLBARTHUMB_HORIZONTAL:
+ DrawScrollbarThumb(cgContext, macRect,
+ ComputeScrollbarParams(
+ aFrame, aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL));
break;
case NS_THEME_SCROLLBARBUTTON_UP:
case NS_THEME_SCROLLBARBUTTON_LEFT:
#if SCROLLBARS_VISUAL_DEBUG
CGContextSetRGBFillColor(cgContext, 1.0, 0, 0, 0.6);
CGContextFillRect(cgContext, macRect);
#endif
@@ -3180,36 +3257,20 @@ nsNativeThemeCocoa::DrawWidgetBackground
case NS_THEME_SCROLLBARBUTTON_DOWN:
case NS_THEME_SCROLLBARBUTTON_RIGHT:
#if SCROLLBARS_VISUAL_DEBUG
CGContextSetRGBFillColor(cgContext, 0, 1.0, 0, 0.6);
CGContextFillRect(cgContext, macRect);
#endif
break;
case NS_THEME_SCROLLBARTRACK_HORIZONTAL:
- case NS_THEME_SCROLLBARTRACK_VERTICAL: {
- BOOL isOverlay = nsLookAndFeel::UseOverlayScrollbars();
- if (!isOverlay || IsParentScrollbarRolledOver(aFrame)) {
- BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBARTRACK_HORIZONTAL);
- nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
- bool isSmall = (scrollbarFrame && scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
- const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
- RenderWithCoreUI(macRect, cgContext,
- [NSDictionary dictionaryWithObjectsAndKeys:
- (isOverlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
- (isSmall ? @"small" : @"regular"), @"size",
- (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
- (isOnTopOfDarkBackground ? @"kCUIVariantWhite" : @""), @"kCUIVariantKey",
- [NSNumber numberWithBool:YES], @"noindicator",
- [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
- [NSNumber numberWithBool:YES], @"is.flipped",
- nil],
- true);
- }
- }
+ case NS_THEME_SCROLLBARTRACK_VERTICAL:
+ DrawScrollbarTrack(cgContext, macRect,
+ ComputeScrollbarParams(
+ aFrame, aWidgetType == NS_THEME_SCROLLBARTRACK_HORIZONTAL));
break;
case NS_THEME_TEXTFIELD_MULTILINE: {
// we have to draw this by hand because there is no HITheme value for it
CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(cgContext, macRect);