void DrawBlur(gfxContext* aDestinationCtx, SourceSurface* aBlur, const IntPoint& aTopLeft, const Rect* aDirtyRect) { DrawTarget *dest = aDestinationCtx->GetDrawTarget(); nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern(); Pattern* pat = thebesPat->GetPattern(dest, nullptr); Matrix oldTransform = dest->GetTransform(); Matrix newTransform = oldTransform; newTransform.Translate(aTopLeft.x, aTopLeft.y); // Avoid a semi-expensive clip operation if we can, otherwise // clip to the dirty rect if (aDirtyRect) { dest->PushClipRect(*aDirtyRect); } dest->SetTransform(newTransform); dest->MaskSurface(*pat, aBlur, Point(0, 0)); dest->SetTransform(oldTransform); if (aDirtyRect) { dest->PopClip(); } }
void gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx) { if (!mContext) return; mBlur->Blur(mData); mozilla::gfx::Rect* dirtyRect = mBlur->GetDirtyRect(); DrawTarget *dest = aDestinationCtx->GetDrawTarget(); if (!dest) { NS_ERROR("Blurring not supported for Thebes contexts!"); return; } mozilla::RefPtr<SourceSurface> mask = dest->CreateSourceSurfaceFromData(mData, mBlur->GetSize(), mBlur->GetStride(), FORMAT_A8); if (!mask) { NS_ERROR("Failed to create mask!"); return; } nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern(); Pattern* pat = thebesPat->GetPattern(dest, nullptr); Matrix oldTransform = dest->GetTransform(); Matrix newTransform = oldTransform; newTransform.Translate(mBlur->GetRect().x, mBlur->GetRect().y); // Avoid a semi-expensive clip operation if we can, otherwise // clip to the dirty rect if (dirtyRect) { dest->PushClipRect(*dirtyRect); } dest->SetTransform(newTransform); dest->MaskSurface(*pat, mask, Point(0, 0)); dest->SetTransform(oldTransform); if (dirtyRect) { dest->PopClip(); } }
void gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx) { if (!mAccelerated && !mData) { return; } DrawTarget *dest = aDestinationCtx->GetDrawTarget(); if (!dest) { NS_WARNING("Blurring not supported for Thebes contexts!"); return; } RefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern(); Pattern* pat = thebesPat->GetPattern(dest, nullptr); if (!pat) { NS_WARNING("Failed to get pattern for blur!"); return; } IntPoint topLeft; RefPtr<SourceSurface> mask = DoBlur(nullptr, &topLeft); if (!mask) { NS_ERROR("Failed to create mask!"); return; } // Avoid a semi-expensive clip operation if we can, otherwise // clip to the dirty rect Rect* dirtyRect = mBlur.GetDirtyRect(); if (dirtyRect) { dest->PushClipRect(*dirtyRect); } Matrix oldTransform = dest->GetTransform(); Matrix newTransform = oldTransform; newTransform.PreTranslate(topLeft); dest->SetTransform(newTransform); dest->MaskSurface(*pat, mask, Point(0, 0)); dest->SetTransform(oldTransform); if (dirtyRect) { dest->PopClip(); } }
/* static */ void gfxAlphaBoxBlur::BlurRectangle(gfxContext* aDestinationCtx, const gfxRect& aRect, const RectCornerRadii* aCornerRadii, const gfxPoint& aBlurStdDev, const Color& aShadowColor, const gfxRect& aDirtyRect, const gfxRect& aSkipRect) { IntSize blurRadius = CalculateBlurRadius(aBlurStdDev); bool mirrorCorners = !aCornerRadii || aCornerRadii->AreRadiiSame(); IntRect rect = RoundedToInt(ToRect(aRect)); IntMargin blurMargin; IntMargin slice; IntSize minSize; RefPtr<SourceSurface> boxShadow = GetBlur(aDestinationCtx, rect.Size(), blurRadius, aCornerRadii, aShadowColor, mirrorCorners, blurMargin, slice, minSize); if (!boxShadow) { return; } DrawTarget* destDrawTarget = aDestinationCtx->GetDrawTarget(); destDrawTarget->PushClipRect(ToRect(aDirtyRect)); // Copy the right parts from boxShadow into destDrawTarget. The middle parts // will be stretched, border-image style. Rect srcOuter(Point(blurMargin.left, blurMargin.top), Size(minSize)); Rect srcInner(srcOuter); srcOuter.Inflate(Margin(blurMargin)); srcInner.Deflate(Margin(slice)); Rect dstOuter(rect); Rect dstInner(rect); dstOuter.Inflate(Margin(blurMargin)); dstInner.Deflate(Margin(slice)); Rect skipRect = ToRect(aSkipRect); if (minSize == rect.Size()) { // The target rect is smaller than the minimal size so just draw the surface if (mirrorCorners) { DrawMirroredBoxShadow(destDrawTarget, boxShadow, dstOuter); } else { destDrawTarget->DrawSurface(boxShadow, dstOuter, srcOuter); } } else { if (mirrorCorners) { DrawMirroredMinBoxShadow(destDrawTarget, boxShadow, dstOuter, dstInner, srcOuter, srcInner, skipRect, true); } else { DrawMinBoxShadow(destDrawTarget, boxShadow, dstOuter, dstInner, srcOuter, srcInner, skipRect, true); } } // 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(); }