diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index d8cafc58638..6ada27b453a 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -13,6 +13,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Helpers.h" +#include "mozilla/gfx/PathHelpers.h" #include "mozilla/HashFunctions.h" #include "mozilla/MathAlgorithms.h" @@ -577,6 +578,25 @@ nsCSSRendering::ComputePixelRadii(const nscoord *aAppUnitsRadii, radii[NS_CORNER_BOTTOM_LEFT_Y]); } +/* static */ void +nsCSSRendering::ComputePixelRadii(const nscoord *aAppUnitsRadii, + nscoord aAppUnitsPerPixel, + RectCornerRadii *oBorderRadii) +{ + Float radii[8]; + NS_FOR_CSS_HALF_CORNERS(corner) + radii[corner] = Float(aAppUnitsRadii[corner]) / aAppUnitsPerPixel; + + (*oBorderRadii)[C_TL] = Size(radii[NS_CORNER_TOP_LEFT_X], + radii[NS_CORNER_TOP_LEFT_Y]); + (*oBorderRadii)[C_TR] = Size(radii[NS_CORNER_TOP_RIGHT_X], + radii[NS_CORNER_TOP_RIGHT_Y]); + (*oBorderRadii)[C_BR] = Size(radii[NS_CORNER_BOTTOM_RIGHT_X], + radii[NS_CORNER_BOTTOM_RIGHT_Y]); + (*oBorderRadii)[C_BL] = Size(radii[NS_CORNER_BOTTOM_LEFT_X], + radii[NS_CORNER_BOTTOM_LEFT_Y]); +} + void nsCSSRendering::PaintBorder(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, @@ -1194,6 +1214,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, const nsRect& aDirtyRect, float aOpacity) { + DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget(); const nsStyleBorder* styleBorder = aForFrame->StyleBorder(); nsCSSShadowArray* shadows = styleBorder->mBoxShadow; if (!shadows) @@ -1223,7 +1244,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, // Get any border radius, since box-shadow must also have rounded corners if // the frame does. - gfxCornerSizes borderRadii; + RectCornerRadii borderRadii; const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); if (hasBorderRadius) { nscoord twipsRadii[8]; @@ -1236,12 +1257,12 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, } } - gfxRect frameGfxRect(nsLayoutUtils::RectToGfxRect(frameRect, twipsPerPixel)); + Rect frameGfxRect = NSRectToRect(frameRect, twipsPerPixel); frameGfxRect.Round(); // We don't show anything that intersects with the frame we're blurring on. So tell the // blurrer not to do unnecessary work there. - gfxRect skipGfxRect = frameGfxRect; + gfxRect skipGfxRect = ThebesRect(frameGfxRect); bool useSkipGfxRect = true; if (nativeTheme) { // Optimize non-leaf native-themed frames by skipping computing pixels @@ -1259,6 +1280,8 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0)); } + gfxContext* renderContext = aRenderingContext.ThebesContext(); + for (uint32_t i = shadows->Length(); i > 0; --i) { nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1); if (shadowItem->mInset) @@ -1277,9 +1300,10 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, shadowRectPlusBlur.Inflate( nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel)); - gfxRect shadowGfxRectPlusBlur = - nsLayoutUtils::RectToGfxRect(shadowRectPlusBlur, twipsPerPixel); + Rect shadowGfxRectPlusBlur = + NSRectToRect(shadowRectPlusBlur, twipsPerPixel); shadowGfxRectPlusBlur.RoundOut(); + MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true); // Set the shadow color; if not specified, use the foreground color nscolor shadowColor; @@ -1291,7 +1315,6 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, gfxRGBA gfxShadowColor(shadowColor); gfxShadowColor.a *= aOpacity; - gfxContext* renderContext = aRenderingContext.ThebesContext(); if (nativeTheme) { nsContextBoxBlur blurringArea; @@ -1307,7 +1330,6 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, if (!shadowContext) continue; - // shadowContext is owned by either blurringArea or aRenderingContext. MOZ_ASSERT(shadowContext == blurringArea.GetContext()); renderContext->Save(); @@ -1342,18 +1364,21 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, renderContext->Restore(); } else { renderContext->Save(); - // Clip out the area of the actual frame so the shadow is not shown within - // the frame. - renderContext->NewPath(); - renderContext->Rectangle(shadowGfxRectPlusBlur); - if (hasBorderRadius) { - renderContext->RoundedRectangle(frameGfxRect, borderRadii); - } else { - renderContext->Rectangle(frameGfxRect); - } - renderContext->SetFillRule(FillRule::FILL_EVEN_ODD); - renderContext->Clip(); + { + // Clip out the interior of the frame's border edge so that the shadow + // is only painted outside that area. + RefPtr builder = + aDrawTarget.CreatePathBuilder(FillRule::FILL_EVEN_ODD); + AppendRectToPath(builder, shadowGfxRectPlusBlur); + if (hasBorderRadius) { + AppendRoundedRectToPath(builder, frameGfxRect, borderRadii); + } else { + AppendRectToPath(builder, frameGfxRect); + } + RefPtr path = builder->Finish(); + renderContext->Clip(path); + } // Clip the shadow so that we only get the part that applies to aForFrame. nsRect fragmentClip = shadowRectPlusBlur; @@ -1383,16 +1408,16 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, } } } - aRenderingContext.ThebesContext()-> + renderContext-> Clip(NSRectToSnappedRect(fragmentClip, aForFrame->PresContext()->AppUnitsPerDevPixel(), - *aRenderingContext.GetDrawTarget())); + aDrawTarget)); gfxCornerSizes clipRectRadii; if (hasBorderRadius) { - gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel; + Float spreadDistance = shadowItem->mSpread / twipsPerPixel; - gfxFloat borderSizes[4]; + Float borderSizes[4]; borderSizes[NS_SIDE_LEFT] = spreadDistance; borderSizes[NS_SIDE_TOP] = spreadDistance; diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index 9fce2f149d3..bf52373ab7a 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -24,6 +24,7 @@ namespace mozilla { namespace gfx { class DrawTarget; +struct RectCornerRadii; } namespace layers { @@ -319,6 +320,7 @@ struct nsCSSRendering { typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::Float Float; typedef mozilla::gfx::Rect Rect; + typedef mozilla::gfx::RectCornerRadii RectCornerRadii; typedef nsIFrame::Sides Sides; /** @@ -344,6 +346,10 @@ struct nsCSSRendering { const nsRect& aDirtyRect, float aOpacity = 1.0); + static void ComputePixelRadii(const nscoord *aAppUnitsRadii, + nscoord aAppUnitsPerPixel, + RectCornerRadii *oBorderRadii); + static void ComputePixelRadii(const nscoord *aAppUnitsRadii, nscoord aAppUnitsPerPixel, gfxCornerSizes *oBorderRadii); diff --git a/layout/base/nsCSSRenderingBorders.cpp b/layout/base/nsCSSRenderingBorders.cpp index 43e955925e1..976589c0b4d 100644 --- a/layout/base/nsCSSRenderingBorders.cpp +++ b/layout/base/nsCSSRenderingBorders.cpp @@ -7,6 +7,8 @@ #include "nsCSSRenderingBorders.h" #include "gfxUtils.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/PathHelpers.h" #include "nsStyleConsts.h" #include "nsCSSColorUtils.h" #include "GeckoProfiler.h" @@ -173,8 +175,8 @@ nsCSSBorderRenderer::ComputeInnerRadii(const gfxCornerSizes& aRadii, } /* static */ void -nsCSSBorderRenderer::ComputeOuterRadii(const gfxCornerSizes& aRadii, - const gfxFloat *aBorderSizes, +nsCSSBorderRenderer::ComputeOuterRadii(const RectCornerRadii& aRadii, + const Float *aBorderSizes, gfxCornerSizes *aOuterRadiiRet) { gfxCornerSizes& oRadii = *aOuterRadiiRet; @@ -183,24 +185,24 @@ nsCSSBorderRenderer::ComputeOuterRadii(const gfxCornerSizes& aRadii, oRadii = gfxCornerSizes(0.0); // round the edges that have radii > 0.0 to start with - if (aRadii[C_TL].width > 0.0 && aRadii[C_TL].height > 0.0) { - oRadii[C_TL].width = std::max(0.0, aRadii[C_TL].width + aBorderSizes[NS_SIDE_LEFT]); - oRadii[C_TL].height = std::max(0.0, aRadii[C_TL].height + aBorderSizes[NS_SIDE_TOP]); + if (aRadii[C_TL].width > 0.f && aRadii[C_TL].height > 0.f) { + oRadii[C_TL].width = std::max(0.f, aRadii[C_TL].width + aBorderSizes[NS_SIDE_LEFT]); + oRadii[C_TL].height = std::max(0.f, aRadii[C_TL].height + aBorderSizes[NS_SIDE_TOP]); } - if (aRadii[C_TR].width > 0.0 && aRadii[C_TR].height > 0.0) { - oRadii[C_TR].width = std::max(0.0, aRadii[C_TR].width + aBorderSizes[NS_SIDE_RIGHT]); - oRadii[C_TR].height = std::max(0.0, aRadii[C_TR].height + aBorderSizes[NS_SIDE_TOP]); + if (aRadii[C_TR].width > 0.f && aRadii[C_TR].height > 0.f) { + oRadii[C_TR].width = std::max(0.f, aRadii[C_TR].width + aBorderSizes[NS_SIDE_RIGHT]); + oRadii[C_TR].height = std::max(0.f, aRadii[C_TR].height + aBorderSizes[NS_SIDE_TOP]); } - if (aRadii[C_BR].width > 0.0 && aRadii[C_BR].height > 0.0) { - oRadii[C_BR].width = std::max(0.0, aRadii[C_BR].width + aBorderSizes[NS_SIDE_RIGHT]); - oRadii[C_BR].height = std::max(0.0, aRadii[C_BR].height + aBorderSizes[NS_SIDE_BOTTOM]); + if (aRadii[C_BR].width > 0.f && aRadii[C_BR].height > 0.f) { + oRadii[C_BR].width = std::max(0.f, aRadii[C_BR].width + aBorderSizes[NS_SIDE_RIGHT]); + oRadii[C_BR].height = std::max(0.f, aRadii[C_BR].height + aBorderSizes[NS_SIDE_BOTTOM]); } - if (aRadii[C_BL].width > 0.0 && aRadii[C_BL].height > 0.0) { - oRadii[C_BL].width = std::max(0.0, aRadii[C_BL].width + aBorderSizes[NS_SIDE_LEFT]); - oRadii[C_BL].height = std::max(0.0, aRadii[C_BL].height + aBorderSizes[NS_SIDE_BOTTOM]); + if (aRadii[C_BL].width > 0.f && aRadii[C_BL].height > 0.f) { + oRadii[C_BL].width = std::max(0.f, aRadii[C_BL].width + aBorderSizes[NS_SIDE_LEFT]); + oRadii[C_BL].height = std::max(0.f, aRadii[C_BL].height + aBorderSizes[NS_SIDE_BOTTOM]); } } diff --git a/layout/base/nsCSSRenderingBorders.h b/layout/base/nsCSSRenderingBorders.h index 0cea52811e4..2f31a5aa3cc 100644 --- a/layout/base/nsCSSRenderingBorders.h +++ b/layout/base/nsCSSRenderingBorders.h @@ -21,6 +21,7 @@ struct nsBorderColors; namespace mozilla { namespace gfx { class GradientStops; +struct RectCornerRadii; } } @@ -76,6 +77,9 @@ typedef enum { } BorderColorStyle; struct nsCSSBorderRenderer { + typedef mozilla::gfx::Float Float; + typedef mozilla::gfx::RectCornerRadii RectCornerRadii; + nsCSSBorderRenderer(int32_t aAppUnitsPerPixel, gfxContext* aDestContext, gfxRect& aOuterRect, @@ -219,8 +223,8 @@ struct nsCSSBorderRenderer { // appropriate radii for another rectangle *outside* that rectangle // by increasing the radii, except keeping sharp corners sharp. // Used for spread box-shadows - static void ComputeOuterRadii(const gfxCornerSizes& aRadii, - const gfxFloat *aBorderSizes, + static void ComputeOuterRadii(const RectCornerRadii& aRadii, + const Float *aBorderSizes, gfxCornerSizes *aOuterRadiiRet); };