diff --git a/widget/ScrollbarDrawingMac.cpp b/widget/ScrollbarDrawingMac.cpp index 7a743570274b..294b941644a8 100644 --- a/widget/ScrollbarDrawingMac.cpp +++ b/widget/ScrollbarDrawingMac.cpp @@ -6,7 +6,6 @@ #include "ScrollbarDrawingMac.h" #include "mozilla/gfx/Helpers.h" -#include "mozilla/gfx/PathHelpers.h" #include "mozilla/RelativeLuminanceUtils.h" #include "nsLayoutUtils.h" #include "nsIFrame.h" @@ -127,8 +126,12 @@ ScrollbarParams ScrollbarDrawingMac::ComputeScrollbarParams( return params; } -void ScrollbarDrawingMac::DrawScrollbarThumb(DrawTarget& aDT, const Rect& aRect, - const ScrollbarParams& aParams) { +auto ScrollbarDrawingMac::GetThumbRect(const Rect& aRect, + const ScrollbarParams& aParams, + float aScale) -> ThumbRect { + // This matches the sizing checks in GetMinimumWidgetSize etc. + aScale = aScale >= 2.0f ? 2.0f : 1.0f; + // Compute the thumb thickness. This varies based on aParams.small, // aParams.overlay and aParams.rolledOver. non-overlay: 6 / 8, overlay // non-hovered: 5 / 7, overlay hovered: 9 / 11 @@ -139,11 +142,13 @@ void ScrollbarDrawingMac::DrawScrollbarThumb(DrawTarget& aDT, const Rect& aRect, thickness += 4.0f; } } + thickness *= aScale; // Compute the thumb rect. - float outerSpacing = (aParams.overlay || aParams.small) ? 1.0f : 2.0f; + const float outerSpacing = + ((aParams.overlay || aParams.small) ? 1.0f : 2.0f) * aScale; Rect thumbRect = aRect; - thumbRect.Deflate(1.0f); + thumbRect.Deflate(1.0f * aScale); if (aParams.horizontal) { float bottomEdge = thumbRect.YMost() - outerSpacing; thumbRect.SetBoxY(bottomEdge - thickness, bottomEdge); @@ -171,29 +176,20 @@ void ScrollbarDrawingMac::DrawScrollbarThumb(DrawTarget& aDT, const Rect& aRect, } } - // Fill the thumb shape with the color. - float cornerRadius = - (aParams.horizontal ? thumbRect.Height() : thumbRect.Width()) / 2.0f; - aDT.FillRoundedRect(RoundedRect(thumbRect, RectCornerRadii(cornerRadius)), - ColorPattern(ToDeviceColor(faceColor))); + nscolor strokeColor = 0; + float strokeOutset = 0.0f; + float strokeWidth = 0.0f; // Overlay scrollbars have an additional stroke around the fill. if (aParams.overlay) { - float strokeOutset = aParams.onDarkBackground ? 0.3f : 0.5f; - float strokeWidth = aParams.onDarkBackground ? 0.6f : 0.8f; - nscolor strokeColor = aParams.onDarkBackground ? NS_RGBA(0, 0, 0, 48) - : NS_RGBA(255, 255, 255, 48); - Rect thumbStrokeRect = thumbRect; - thumbStrokeRect.Inflate(strokeOutset); - float strokeRadius = (aParams.horizontal ? thumbStrokeRect.Height() - : thumbStrokeRect.Width()) / - 2.0f; + strokeOutset = (aParams.onDarkBackground ? 0.3f : 0.5f) * aScale; + strokeWidth = (aParams.onDarkBackground ? 0.6f : 0.8f) * aScale; - RefPtr path = MakePathForRoundedRect(aDT, thumbStrokeRect, - RectCornerRadii(strokeRadius)); - aDT.Stroke(path, ColorPattern(ToDeviceColor(strokeColor)), - StrokeOptions(strokeWidth)); + strokeColor = aParams.onDarkBackground ? NS_RGBA(0, 0, 0, 48) + : NS_RGBA(255, 255, 255, 48); } + + return {thumbRect, faceColor, strokeColor, strokeWidth, strokeOutset}; } struct ScrollbarTrackDecorationColors { @@ -224,13 +220,18 @@ static ScrollbarTrackDecorationColors ComputeScrollbarTrackDecorationColors( return result; } -void ScrollbarDrawingMac::DrawScrollbarTrack(DrawTarget& aDT, const Rect& aRect, - const ScrollbarParams& aParams) { +bool ScrollbarDrawingMac::GetScrollbarTrackRects(const Rect& aRect, + const ScrollbarParams& aParams, + float aScale, + ScrollbarTrackRects& aRects) { if (aParams.overlay && !aParams.rolledOver) { // Non-hovered overlay scrollbars don't have a track. Draw nothing. - return; + return false; } + // This matches the sizing checks in GetMinimumWidgetSize etc. + aScale = aScale >= 2.0f ? 2.0f : 1.0f; + nscolor trackColor; if (aParams.custom) { trackColor = aParams.trackColor; @@ -253,16 +254,17 @@ void ScrollbarDrawingMac::DrawScrollbarTrack(DrawTarget& aDT, const Rect& aRect, nscolor color; float thickness; } segments[] = { - {colors.mInnerColor, 1.0f}, - {colors.mShadowColor, 1.0f}, - {trackColor, thickness - 3.0f}, - {colors.mOuterColor, 1.0f}, + {colors.mInnerColor, 1.0f * aScale}, + {colors.mShadowColor, 1.0f * aScale}, + {trackColor, thickness - 3.0f * aScale}, + {colors.mOuterColor, 1.0f * aScale}, }; // Iterate over the segments "from inside to outside" and fill each segment. // For horizontal scrollbars, iterate top to bottom. // For vertical scrollbars, iterate left to right or right to left based on // aParams.rtl. + auto current = aRects.begin(); float accumulatedThickness = 0.0f; for (const auto& segment : segments) { Rect segmentRect = aRect; @@ -279,18 +281,25 @@ void ScrollbarDrawingMac::DrawScrollbarTrack(DrawTarget& aDT, const Rect& aRect, aRect.X() + endThickness); } } - aDT.FillRect(segmentRect, ColorPattern(ToDeviceColor(segment.color))); accumulatedThickness = endThickness; + *current++ = {segmentRect, segment.color}; } + + return true; } -void ScrollbarDrawingMac::DrawScrollCorner(DrawTarget& aDT, const Rect& aRect, - const ScrollbarParams& aParams) { +bool ScrollbarDrawingMac::GetScrollCornerRects(const Rect& aRect, + const ScrollbarParams& aParams, + float aScale, + ScrollCornerRects& aRects) { if (aParams.overlay && !aParams.rolledOver) { // Non-hovered overlay scrollbars don't have a corner. Draw nothing. - return; + return false; } + // This matches the sizing checks in GetMinimumWidgetSize etc. + aScale = aScale >= 2.0f ? 2.0f : 1.0f; + // Draw the following scroll corner. // // Output: Rectangles: @@ -316,22 +325,29 @@ void ScrollbarDrawingMac::DrawScrollCorner(DrawTarget& aDT, const Rect& aRect, nscolor color; Rect relativeRect; } pieces[] = { - {colors.mInnerColor, {0.0f, 0.0f, 1.0f, 1.0f}}, - {colors.mShadowColor, {1.0f, 0.0f, 1.0f, 1.0f}}, - {colors.mShadowColor, {0.0f, 1.0f, 2.0f, 1.0f}}, - {trackColor, {2.0f, 0.0f, width - 3.0f, 2.0f}}, - {trackColor, {0.0f, 2.0f, width - 1.0f, height - 3.0f}}, - {colors.mOuterColor, {width - 1.0f, 0.0f, 1.0f, height - 1.0f}}, - {colors.mOuterColor, {0.0f, height - 1.0f, width, 1.0f}}, + {colors.mInnerColor, {0.0f, 0.0f, 1.0f * aScale, 1.0f * aScale}}, + {colors.mShadowColor, + {1.0f * aScale, 0.0f, 1.0f * aScale, 1.0f * aScale}}, + {colors.mShadowColor, + {0.0f, 1.0f * aScale, 2.0f * aScale, 1.0f * aScale}}, + {trackColor, {2.0f * aScale, 0.0f, width - 3.0f * aScale, 2.0f * aScale}}, + {trackColor, + {0.0f, 2.0f * aScale, width - 1.0f * aScale, height - 3.0f * aScale}}, + {colors.mOuterColor, + {width - 1.0f * aScale, 0.0f, 1.0f * aScale, height - 1.0f * aScale}}, + {colors.mOuterColor, + {0.0f, height - 1.0f * aScale, width, 1.0f * aScale}}, }; + auto current = aRects.begin(); for (const auto& piece : pieces) { Rect pieceRect = piece.relativeRect + aRect.TopLeft(); if (aParams.rtl) { pieceRect.x = aRect.XMost() - piece.relativeRect.XMost(); } - aDT.FillRect(pieceRect, ColorPattern(ToDeviceColor(piece.color))); + *current++ = {pieceRect, piece.color}; } + return true; } } // namespace widget diff --git a/widget/ScrollbarDrawingMac.h b/widget/ScrollbarDrawingMac.h index 60ff200eef5e..e449a738d57f 100644 --- a/widget/ScrollbarDrawingMac.h +++ b/widget/ScrollbarDrawingMac.h @@ -10,6 +10,7 @@ #include "nsColor.h" #include "nsITheme.h" #include "Units.h" +#include "mozilla/Array.h" namespace mozilla { namespace gfx { @@ -33,6 +34,11 @@ struct ScrollbarParams { class ScrollbarDrawingMac final { public: + struct FillRect { + gfx::Rect mRect; + nscolor mColor; + }; + static CSSIntCoord GetScrollbarSize(StyleScrollbarWidth, bool aOverlay); static LayoutDeviceIntCoord GetScrollbarSize(StyleScrollbarWidth, @@ -43,12 +49,28 @@ class ScrollbarDrawingMac final { static ScrollbarParams ComputeScrollbarParams(nsIFrame* aFrame, const ComputedStyle& aStyle, bool aIsHorizontal); - static void DrawScrollbarThumb(gfx::DrawTarget& aDT, const gfx::Rect& aRect, - const ScrollbarParams& aParams); - static void DrawScrollbarTrack(gfx::DrawTarget& aDT, const gfx::Rect& aRect, - const ScrollbarParams& aParams); - static void DrawScrollCorner(gfx::DrawTarget& aDT, const gfx::Rect& aRect, - const ScrollbarParams& aParams); + + // The caller can draw this rectangle with rounded corners as appropriate. + struct ThumbRect { + gfx::Rect mRect; + nscolor mFillColor; + nscolor mStrokeColor; + float mStrokeWidth; + float mStrokeOutset; + }; + + static ThumbRect GetThumbRect(const gfx::Rect& aRect, + const ScrollbarParams& aParams, float aScale); + + using ScrollbarTrackRects = Array; + static bool GetScrollbarTrackRects(const gfx::Rect& aRect, + const ScrollbarParams& aParams, + float aScale, ScrollbarTrackRects&); + + using ScrollCornerRects = Array; + static bool GetScrollCornerRects(const gfx::Rect& aRect, + const ScrollbarParams& aParams, + float aScale, ScrollCornerRects&); }; } // namespace widget diff --git a/widget/cocoa/nsNativeBasicThemeCocoa.cpp b/widget/cocoa/nsNativeBasicThemeCocoa.cpp index 4802992fea49..40d2f906f2b4 100644 --- a/widget/cocoa/nsNativeBasicThemeCocoa.cpp +++ b/widget/cocoa/nsNativeBasicThemeCocoa.cpp @@ -75,15 +75,25 @@ bool nsNativeBasicThemeCocoa::PaintScrollbarThumb( DPIRatio aDpiRatio) { ScrollbarParams params = ScrollbarDrawingMac::ComputeScrollbarParams(aFrame, aStyle, aHorizontal); - auto rect = aRect.ToUnknownRect(); - if (aDpiRatio.scale >= 2.0f) { - mozilla::gfx::AutoRestoreTransform autoRestoreTransform(&aDrawTarget); - aDrawTarget.SetTransform(aDrawTarget.GetTransform().PreScale(2.0f, 2.0f)); - rect.Scale(1.0f / 2.0f); - ScrollbarDrawingMac::DrawScrollbarThumb(aDrawTarget, rect, params); - } else { - ScrollbarDrawingMac::DrawScrollbarThumb(aDrawTarget, rect, params); + auto thumb = ScrollbarDrawingMac::GetThumbRect(aRect.ToUnknownRect(), params, + aDpiRatio.scale); + auto thumbRect = LayoutDeviceRect::FromUnknownRect(thumb.mRect); + LayoutDeviceCoord radius = + (params.horizontal ? thumbRect.Height() : thumbRect.Width()) / 2.0f; + PaintRoundedRectWithRadius( + aDrawTarget, thumbRect, thumbRect, sRGBColor::FromABGR(thumb.mFillColor), + sRGBColor::White(0.0f), 0.0f, radius / aDpiRatio, aDpiRatio); + if (!thumb.mStrokeColor) { + return true; } + + // Paint the stroke if needed. + thumbRect.Inflate(thumb.mStrokeOutset + thumb.mStrokeWidth); + radius = (params.horizontal ? thumbRect.Height() : thumbRect.Width()) / 2.0f; + PaintRoundedRectWithRadius(aDrawTarget, thumbRect, + sRGBColor::White(0.0f), + sRGBColor::FromABGR(thumb.mStrokeColor), + thumb.mStrokeWidth, radius / aDpiRatio, aDpiRatio); return true; } @@ -93,14 +103,13 @@ bool nsNativeBasicThemeCocoa::PaintScrollbarTrack( const EventStates& aDocumentState, DPIRatio aDpiRatio) { ScrollbarParams params = ScrollbarDrawingMac::ComputeScrollbarParams(aFrame, aStyle, aHorizontal); - auto rect = aRect.ToUnknownRect(); - if (aDpiRatio.scale >= 2.0f) { - mozilla::gfx::AutoRestoreTransform autoRestoreTransform(&aDrawTarget); - aDrawTarget.SetTransform(aDrawTarget.GetTransform().PreScale(2.0f, 2.0f)); - rect.Scale(1.0f / 2.0f); - ScrollbarDrawingMac::DrawScrollbarTrack(aDrawTarget, rect, params); - } else { - ScrollbarDrawingMac::DrawScrollbarTrack(aDrawTarget, rect, params); + ScrollbarDrawingMac::ScrollbarTrackRects rects; + if (ScrollbarDrawingMac::GetScrollbarTrackRects(aRect.ToUnknownRect(), params, + aDpiRatio.scale, rects)) { + for (const auto& rect : rects) { + FillRect(aDrawTarget, LayoutDeviceRect::FromUnknownRect(rect.mRect), + sRGBColor::FromABGR(rect.mColor)); + } } return true; } @@ -111,15 +120,13 @@ bool nsNativeBasicThemeCocoa::PaintScrollCorner( DPIRatio aDpiRatio) { ScrollbarParams params = ScrollbarDrawingMac::ComputeScrollbarParams(aFrame, aStyle, false); - if (aDpiRatio.scale >= 2.0f) { - mozilla::gfx::AutoRestoreTransform autoRestoreTransform(&aDrawTarget); - aDrawTarget.SetTransform(aDrawTarget.GetTransform().PreScale(2.0f, 2.0f)); - auto rect = aRect.ToUnknownRect(); - rect.Scale(1 / 2.0f); - ScrollbarDrawingMac::DrawScrollCorner(aDrawTarget, rect, params); - } else { - auto rect = aRect.ToUnknownRect(); - ScrollbarDrawingMac::DrawScrollCorner(aDrawTarget, rect, params); + ScrollbarDrawingMac::ScrollCornerRects rects; + if (ScrollbarDrawingMac::GetScrollCornerRects(aRect.ToUnknownRect(), params, + aDpiRatio.scale, rects)) { + for (const auto& rect : rects) { + FillRect(aDrawTarget, LayoutDeviceRect::FromUnknownRect(rect.mRect), + sRGBColor::FromABGR(rect.mColor)); + } } return true; } diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index f189517bca70..0d52d341aa2b 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -7,6 +7,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Helpers.h" +#include "mozilla/gfx/PathHelpers.h" #include "nsChildView.h" #include "nsDeviceContext.h" #include "nsLayoutUtils.h" @@ -2815,9 +2816,6 @@ void nsNativeThemeCocoa::RenderWidget(const WidgetInfo& aWidgetInfo, DrawTarget& AutoRestoreTransform autoRestoreTransform(&aDrawTarget); gfx::Rect dirtyRect = aDirtyRect; - gfx::Rect widgetRect = aWidgetRect; - dirtyRect.Scale(1.0f / aScale); - widgetRect.Scale(1.0f / aScale); aDrawTarget.SetTransform(aDrawTarget.GetTransform().PreScale(aScale, aScale)); const Widget widget = aWidgetInfo.Widget(); @@ -2826,25 +2824,51 @@ void nsNativeThemeCocoa::RenderWidget(const WidgetInfo& aWidgetInfo, DrawTarget& switch (widget) { case Widget::eColorFill: { sRGBColor color = aWidgetInfo.Params(); - aDrawTarget.FillRect(widgetRect, ColorPattern(ToDeviceColor(color))); + aDrawTarget.FillRect(aWidgetRect, ColorPattern(ToDeviceColor(color))); break; } case Widget::eScrollbarThumb: { ScrollbarParams params = aWidgetInfo.Params(); - ScrollbarDrawingMac::DrawScrollbarThumb(aDrawTarget, widgetRect, params); + auto thumb = ScrollbarDrawingMac::GetThumbRect(aWidgetRect, params, aScale); + float cornerRadius = (params.horizontal ? thumb.mRect.Height() : thumb.mRect.Width()) / 2.0f; + aDrawTarget.FillRoundedRect(RoundedRect(thumb.mRect, RectCornerRadii(cornerRadius)), + ColorPattern(ToDeviceColor(thumb.mFillColor))); + if (thumb.mStrokeColor) { + auto strokeRect = thumb.mRect; + strokeRect.Inflate(thumb.mStrokeOutset); + float strokeRadius = (params.horizontal ? strokeRect.Height() : strokeRect.Width()) / 2.0f; + RefPtr path = + MakePathForRoundedRect(aDrawTarget, strokeRect, RectCornerRadii(strokeRadius)); + aDrawTarget.Stroke(path, ColorPattern(ToDeviceColor(thumb.mStrokeColor)), + StrokeOptions(thumb.mStrokeWidth)); + } break; } case Widget::eScrollbarTrack: { ScrollbarParams params = aWidgetInfo.Params(); - ScrollbarDrawingMac::DrawScrollbarTrack(aDrawTarget, widgetRect, params); + ScrollbarDrawingMac::ScrollbarTrackRects rects; + if (ScrollbarDrawingMac::GetScrollbarTrackRects(aWidgetRect, params, aScale, rects)) { + for (const auto& rect : rects) { + aDrawTarget.FillRect(rect.mRect, ColorPattern(ToDeviceColor(rect.mColor))); + } + } break; } case Widget::eScrollCorner: { ScrollbarParams params = aWidgetInfo.Params(); - ScrollbarDrawingMac::DrawScrollCorner(aDrawTarget, widgetRect, params); + ScrollbarDrawingMac::ScrollCornerRects rects; + if (ScrollbarDrawingMac::GetScrollCornerRects(aWidgetRect, params, aScale, rects)) { + for (const auto& rect : rects) { + aDrawTarget.FillRect(rect.mRect, ColorPattern(ToDeviceColor(rect.mColor))); + } + } break; } default: { + gfx::Rect widgetRect = aWidgetRect; + dirtyRect.Scale(1.0f / aScale); + widgetRect.Scale(1.0f / aScale); + // The remaining widgets require a CGContext. CGRect macRect = CGRectMake(widgetRect.X(), widgetRect.Y(), widgetRect.Width(), widgetRect.Height());