static IntSize ComputeMinSizeForShadowShape(RectCornerRadii* aCornerRadii, gfxIntSize aBlurRadius, IntMargin& aSlice, const IntSize& aRectSize) { float cornerWidth = 0; float cornerHeight = 0; if (aCornerRadii) { RectCornerRadii corners = *aCornerRadii; for (size_t i = 0; i < 4; i++) { cornerWidth = std::max(cornerWidth, corners[i].width); cornerHeight = std::max(cornerHeight, corners[i].height); } } aSlice = IntMargin(ceil(cornerHeight) + aBlurRadius.height, ceil(cornerWidth) + aBlurRadius.width, ceil(cornerHeight) + aBlurRadius.height, ceil(cornerWidth) + aBlurRadius.width); IntSize minSize(aSlice.LeftRight() + 1, aSlice.TopBottom() + 1); // If aRectSize is smaller than minSize, the border-image approach won't // work; there's no way to squeeze parts of the min box-shadow source // image such that the result looks correct. So we need to adjust minSize // in such a way that we can later draw it without stretching in the affected // dimension. We also need to adjust "slice" to ensure that we're not trying // to slice away more than we have. if (aRectSize.width < minSize.width) { minSize.width = aRectSize.width; aSlice.left = 0; aSlice.right = 0; } if (aRectSize.height < minSize.height) { minSize.height = aRectSize.height; aSlice.top = 0; aSlice.bottom = 0; } MOZ_ASSERT(aSlice.LeftRight() <= minSize.width); MOZ_ASSERT(aSlice.TopBottom() <= minSize.height); return minSize; }
static IntSize ComputeMinSizeForShadowShape(const RectCornerRadii* aCornerRadii, const IntSize& aBlurRadius, IntMargin& aOutSlice, const IntSize& aRectSize) { Size cornerSize(0, 0); if (aCornerRadii) { const RectCornerRadii& corners = *aCornerRadii; NS_FOR_CSS_FULL_CORNERS(i) { cornerSize.width = std::max(cornerSize.width, corners[i].width); cornerSize.height = std::max(cornerSize.height, corners[i].height); } } IntSize margin = IntSize::Ceil(cornerSize) + aBlurRadius; aOutSlice = IntMargin(margin.height, margin.width, margin.height, margin.width); IntSize minSize(aOutSlice.LeftRight() + 1, aOutSlice.TopBottom() + 1); // If aRectSize is smaller than minSize, the border-image approach won't // work; there's no way to squeeze parts of the min box-shadow source // image such that the result looks correct. So we need to adjust minSize // in such a way that we can later draw it without stretching in the affected // dimension. We also need to adjust "slice" to ensure that we're not trying // to slice away more than we have. if (aRectSize.width < minSize.width) { minSize.width = aRectSize.width; aOutSlice.left = 0; aOutSlice.right = 0; } if (aRectSize.height < minSize.height) { minSize.height = aRectSize.height; aOutSlice.top = 0; aOutSlice.bottom = 0; } MOZ_ASSERT(aOutSlice.LeftRight() <= minSize.width); MOZ_ASSERT(aOutSlice.TopBottom() <= minSize.height); return minSize; }
// Blurs a small surface and creates the mask. static already_AddRefed<SourceSurface> CreateBlurMask(const IntSize& aRectSize, RectCornerRadii* aCornerRadii, gfxIntSize aBlurRadius, IntMargin& aExtendDestBy, IntMargin& aSliceBorder, DrawTarget& aDestDrawTarget) { IntMargin slice; gfxAlphaBoxBlur blur; IntSize minSize = ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, slice, aRectSize); IntRect minRect(IntPoint(), minSize); gfxContext* blurCtx = blur.Init(ThebesRect(Rect(minRect)), gfxIntSize(), aBlurRadius, nullptr, nullptr); if (!blurCtx) { return nullptr; } DrawTarget* blurDT = blurCtx->GetDrawTarget(); ColorPattern black(Color(0.f, 0.f, 0.f, 1.f)); if (aCornerRadii) { RefPtr<Path> roundedRect = MakePathForRoundedRect(*blurDT, Rect(minRect), *aCornerRadii); blurDT->Fill(roundedRect, black); } else { blurDT->FillRect(Rect(minRect), black); } IntPoint topLeft; RefPtr<SourceSurface> result = blur.DoBlur(&aDestDrawTarget, &topLeft); if (!result) { return nullptr; } IntRect expandedMinRect(topLeft, result->GetSize()); aExtendDestBy = expandedMinRect - minRect; aSliceBorder = slice + aExtendDestBy; MOZ_ASSERT(aSliceBorder.LeftRight() <= expandedMinRect.width); MOZ_ASSERT(aSliceBorder.TopBottom() <= expandedMinRect.height); return result.forget(); }
static void ComputeRectsForInsetBoxShadow(IntSize aBlurRadius, IntSize aSpreadRadius, IntRect& aOutOuterRect, IntRect& aOutInnerRect, IntMargin& aOutPathMargins, const Rect& aDestRect, const Rect& aShadowClipRect, bool aHasBorderRadius, const RectCornerRadii& aInnerClipRectRadii) { IntSize rectBufferSize = aBlurRadius + aSpreadRadius; float cornerWidth = 0; float cornerHeight = 0; if (aHasBorderRadius) { for (size_t i = 0; i < 4; i++) { cornerWidth = std::max(cornerWidth, aInnerClipRectRadii[i].width); cornerHeight = std::max(cornerHeight, aInnerClipRectRadii[i].height); } } // Create the inner rect to be the smallest possible size based on // blur / spread / corner radii IntMargin innerMargin = IntMargin(ceil(cornerHeight) + rectBufferSize.height, ceil(cornerWidth) + rectBufferSize.width, ceil(cornerHeight) + rectBufferSize.height, ceil(cornerWidth) + rectBufferSize.width); aOutPathMargins = innerMargin; // If we have a negative spread radius, we would not have enough // size to actually do the blur. So the min size must be the abs() of the blur // and spread radius. IntSize minBlurSize(std::abs(aSpreadRadius.width) + std::abs(aBlurRadius.width), std::abs(aSpreadRadius.height) + std::abs(aBlurRadius.height)); IntMargin minInnerMargins = IntMargin(ceil(cornerHeight) + minBlurSize.height, ceil(cornerWidth) + minBlurSize.width, ceil(cornerHeight) + minBlurSize.height, ceil(cornerWidth) + minBlurSize.width); IntSize minInnerSize(minInnerMargins.LeftRight() + 1, minInnerMargins.TopBottom() + 1); if (aShadowClipRect.height < minInnerSize.height) { minInnerSize.height = aShadowClipRect.height; } if (aShadowClipRect.width < minInnerSize.width) { minInnerSize.width = aShadowClipRect.width; } // Then expand the outer rect based on the size between the inner/outer rects IntSize minOuterSize(minInnerSize); IntMargin outerRectMargin(rectBufferSize.height, rectBufferSize.width, rectBufferSize.height, rectBufferSize.width); minOuterSize.width += outerRectMargin.LeftRight(); minOuterSize.height += outerRectMargin.TopBottom(); aOutOuterRect = IntRect(IntPoint(), minOuterSize); aOutInnerRect = IntRect(IntPoint(rectBufferSize.width, rectBufferSize.height), minInnerSize); if (aShadowClipRect.IsEmpty()) { aOutInnerRect.width = 0; aOutInnerRect.height = 0; } }