diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index c683a19605..54f965e9d2 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -855,8 +855,6 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, const nsRect& aBorderArea, nsStyleContext* aStyleContext) { - nscoord twipsRadii[8]; - // Get our style context's color struct. const nsStyleOutline* ourOutline = aStyleContext->StyleOutline(); MOZ_ASSERT(ourOutline != NS_STYLE_BORDER_STYLE_NONE, @@ -898,24 +896,6 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, if (innerRect.Contains(aDirtyRect)) return; - nsRect outerRect = innerRect; - outerRect.Inflate(width, width); - - // get the radius for our outline - nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(), - outerRect.Size(), Sides(), twipsRadii); - - // Get our conversion values - nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); - - // get the outer rectangles - Rect oRect(NSRectToRect(outerRect, twipsPerPixel)); - - // convert the radii - nsMargin outlineMargin(width, width, width, width); - RectCornerRadii outlineRadii; - ComputePixelRadii(twipsRadii, twipsPerPixel, &outlineRadii); - if (outlineStyle == NS_STYLE_BORDER_STYLE_AUTO) { if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) { nsITheme* theme = aPresContext->GetTheme(); @@ -935,6 +915,36 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, outlineStyle = NS_STYLE_BORDER_STYLE_SOLID; } + RectCornerRadii outlineRadii; + nsRect outerRect = innerRect; + outerRect.Inflate(width, width); + + const nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel(); + Rect oRect(NSRectToRect(outerRect, oneDevPixel)); + + const Float outlineWidths[4] = { + Float(width) / oneDevPixel, Float(width) / oneDevPixel, + Float(width) / oneDevPixel, Float(width) / oneDevPixel}; + + // convert the radii + nscoord twipsRadii[8]; + + // get the radius for our outline + if (nsLayoutUtils::HasNonZeroCorner(ourOutline->mOutlineRadius)) { + nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(), + outerRect.Size(), Sides(), twipsRadii); + ComputePixelRadii(twipsRadii, oneDevPixel, &outlineRadii); + } else if (aForFrame->GetBorderRadii(twipsRadii)) { + RectCornerRadii innerRadii; + ComputePixelRadii(twipsRadii, oneDevPixel, &innerRadii); + + Float devPixelOffset = aPresContext->AppUnitsToFloatDevPixels(offset); + const Float widths[4] = { + outlineWidths[0] + devPixelOffset, outlineWidths[1] + devPixelOffset, + outlineWidths[2] + devPixelOffset, outlineWidths[3] + devPixelOffset}; + nsCSSBorderRenderer::ComputeOuterRadii(innerRadii, widths, &outlineRadii); + } + uint8_t outlineStyles[4] = { outlineStyle, outlineStyle, outlineStyle, outlineStyle }; @@ -947,12 +957,7 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, outlineColor, outlineColor }; - // convert the border widths - Float outlineWidths[4] = { Float(width / twipsPerPixel), - Float(width / twipsPerPixel), - Float(width / twipsPerPixel), - Float(width / twipsPerPixel) }; - Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel); + Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel); nsIDocument* document = nullptr; nsIContent* content = aForFrame->GetContent(); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index fa28ea5f87..825c564211 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3757,18 +3757,23 @@ nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder, mFrame->StyleContext()); } +bool nsDisplayOutline::HasRadius() const { + if (nsLayoutUtils::HasNonZeroCorner(mFrame->StyleOutline()->mOutlineRadius)) { + return true; + } + return nsLayoutUtils::HasNonZeroCorner(mFrame->StyleBorder()->mBorderRadius); +} + bool nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect) { const nsStyleOutline* outline = mFrame->StyleOutline(); nsRect borderBox(ToReferenceFrame(), mFrame->GetSize()); - if (borderBox.Contains(aRect) && - !nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) { - if (outline->mOutlineOffset >= 0) { - // aRect is entirely inside the border-rect, and the outline isn't - // rendered inside the border-rect, so the outline is not visible. - return true; - } + if (borderBox.Contains(aRect) && !HasRadius() && + outline->mOutlineOffset >= 0) { + // aRect is entirely inside the border-rect, and the outline isn't + // rendered inside the border-rect, so the outline is not visible. + return true; } return false; diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 2b4efd86ef..2f3f53b7fc 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3220,6 +3220,9 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE) + +private: + bool HasRadius() const; }; /** diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 4f95ddaeb0..9de0f13c00 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -510,6 +510,8 @@ nsStyleBorder::CalcDifference(const nsStyleBorder& aNewData) const } } + // Note that border radius is used as a fallback for outline radius, if set. + // Any optimizations here should apply to both. if (mBorderRadius != aNewData.mBorderRadius || !mBorderColors != !aNewData.mBorderColors) { return nsChangeHint_RepaintFrame;