static already_AddRefed<SourceSurface> GetBlur(gfxContext* aDestinationCtx, const IntSize& aRectSize, const IntSize& aBlurRadius, const RectCornerRadii* aCornerRadii, const Color& aShadowColor, bool aMirrorCorners, IntMargin& aOutBlurMargin, IntMargin& aOutSlice, IntSize& aOutMinSize) { if (!gBlurCache) { gBlurCache = new BlurCache(); } IntSize minSize = ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, aOutSlice, aRectSize); // We can get seams using the min size rect when drawing to the destination rect // if we have a non-pixel aligned destination transformation. In those cases, // fallback to just rendering the destination rect. // During printing, we record all the Moz 2d commands and replay them on the parent side // with Cairo. Cairo printing uses StretchDIBits to stretch the surface. However, // since our source image is only 1px for some parts, we make thousands of calls. // Instead just render the blur ourself here as one image and send it over for printing. // TODO: May need to change this with the blob renderer in WR since it also records. Matrix destMatrix = ToMatrix(aDestinationCtx->CurrentMatrix()); bool useDestRect = !destMatrix.IsRectilinear() || destMatrix.HasNonIntegerTranslation() || aDestinationCtx->GetDrawTarget()->IsRecording(); if (useDestRect) { minSize = aRectSize; } aOutMinSize = minSize; DrawTarget* destDT = aDestinationCtx->GetDrawTarget(); if (!useDestRect) { BlurCacheData* cached = gBlurCache->Lookup(minSize, aBlurRadius, aCornerRadii, aShadowColor, destDT->GetBackendType()); if (cached) { // See CreateBoxShadow() for these values aOutBlurMargin = cached->mBlurMargin; RefPtr<SourceSurface> blur = cached->mBlur; return blur.forget(); } } RefPtr<SourceSurface> boxShadow = CreateBoxShadow(destDT, minSize, aCornerRadii, aBlurRadius, aShadowColor, aMirrorCorners, aOutBlurMargin); if (!boxShadow) { return nullptr; } if (RefPtr<SourceSurface> opt = destDT->OptimizeSourceSurface(boxShadow)) { boxShadow = opt; } if (!useDestRect) { CacheBlur(destDT, minSize, aBlurRadius, aCornerRadii, aShadowColor, aOutBlurMargin, boxShadow); } return boxShadow.forget(); }