/* static */ void gfxAlphaBoxBlur::BlurRectangle(gfxContext* aDestinationCtx, const gfxRect& aRect, RectCornerRadii* aCornerRadii, const gfxPoint& aBlurStdDev, const gfxRGBA& aShadowColor, const gfxRect& aDirtyRect, const gfxRect& aSkipRect) { DrawTarget& destDrawTarget = *aDestinationCtx->GetDrawTarget(); IntSize blurRadius = CalculateBlurRadius(aBlurStdDev); IntRect rect = RoundedToInt(ToRect(aRect)); IntMargin extendDestBy; IntMargin slice; RefPtr<SourceSurface> boxShadow = GetBlur(destDrawTarget, rect.Size(), blurRadius, aCornerRadii, aShadowColor, extendDestBy, slice); if (!boxShadow) { return; } destDrawTarget.PushClipRect(ToRect(aDirtyRect)); // Copy the right parts from boxShadow into destDrawTarget. The middle parts // will be stretched, border-image style. Rect srcOuter(Point(), Size(boxShadow->GetSize())); Rect srcInner = srcOuter; srcInner.Deflate(Margin(slice)); rect.Inflate(extendDestBy); Rect dstOuter(rect); Rect dstInner(rect); dstInner.Deflate(Margin(slice)); Rect skipRect = ToRect(aSkipRect); if (srcInner.IsEqualInterior(srcOuter)) { MOZ_ASSERT(dstInner.IsEqualInterior(dstOuter)); // The target rect is smaller than the minimal size so just draw the surface destDrawTarget.DrawSurface(boxShadow, dstInner, srcInner); } else { DrawBoxShadows(destDrawTarget, boxShadow, dstOuter, dstInner, srcOuter, srcInner, skipRect); // Middle part RepeatOrStretchSurface(destDrawTarget, boxShadow, RectWithEdgesTRBL(dstInner.Y(), dstInner.XMost(), dstInner.YMost(), dstInner.X()), RectWithEdgesTRBL(srcInner.Y(), srcInner.XMost(), srcInner.YMost(), srcInner.X()), skipRect); } // A note about anti-aliasing and seems between adjacent parts: // We don't explicitly disable anti-aliasing in the DrawSurface calls above, // so if there's a transform on destDrawTarget that is not pixel-aligned, // there will be seams between adjacent parts of the box-shadow. It's hard to // avoid those without the use of an intermediate surface. // You might think that we could avoid those by just turning of AA, but there // is a problem with that: Box-shadow rendering needs to clip out the // element's border box, and we'd like that clip to have anti-aliasing - // especially if the element has rounded corners! So we can't do that unless // we have a way to say "Please anti-alias the clip, but don't antialias the // destination rect of the DrawSurface call". // On OS X there is an additional problem with turning off AA: CoreGraphics // will not just fill the pixels that have their pixel center inside the // filled shape. Instead, it will fill all the pixels which are partially // covered by the shape. So for pixels on the edge between two adjacent parts, // all those pixels will be painted to by both parts, which looks very bad. destDrawTarget.PopClip(); }