Bug 1459890 - Do not clip mask for clip path to bbox of clipped content. r=mstange
MozReview-Commit-ID: 9yZ1ziiDAKa
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2705,17 +2705,18 @@ ComputeClipForMaskItem(nsDisplayListBuil
Rect result = nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(
aMaskedFrame, svgReset->mClipPath);
combinedClip = Some(ThebesRect(result));
} else if (maskUsage.shouldApplyClipPath) {
gfxRect result = nsSVGUtils::GetBBox(aMaskedFrame,
nsSVGUtils::eBBoxIncludeClipped |
nsSVGUtils::eBBoxIncludeFill |
nsSVGUtils::eBBoxIncludeMarkers |
- nsSVGUtils::eBBoxIncludeStroke);
+ nsSVGUtils::eBBoxIncludeStroke |
+ nsSVGUtils::eDoNotClipToBBoxOfContentInsideClipPath);
combinedClip = Some(cssToDevMatrix.TransformBounds(result));
} else {
// The code for this case is adapted from ComputeMaskGeometry().
nsRect borderArea(toReferenceFrame, aMaskedFrame->GetSize());
borderArea -= offsetToUserSpace;
// Use an infinite dirty rect to pass into nsCSSRendering::
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/blur-inside-clipPath-ref.svg
@@ -0,0 +1,12 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="786" viewBox="0,0,512,512">
+ <defs>
+ <filter id="filter-wVmTgUOU" filterUnits="objectBoundingBox" x="-30%" y="-30%" width="160%" height="170%" color-interpolation-filters="sRGB">
+ <feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0" in="SourceGraphic"/>
+ <feOffset dy="28"/>
+ <feGaussianBlur stdDeviation="18.67" result="blur1"/>
+ </filter>
+ </defs>
+ <g filter="url(#filter-wVmTgUOU)">
+ <rect x="58.88" y="58.88" width="394.24" height="394.24" color="#07773e" fill="red"/>
+ </g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/blur-inside-clipPath.svg
@@ -0,0 +1,17 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="786" viewBox="0,0,512,512">
+ <defs>
+ <clipPath id="clip-vXP8Ybe5">
+ <path d="M0,512v-512h512v512z"/>
+ </clipPath>
+ <filter id="filter-wVmTgUOU" filterUnits="objectBoundingBox" x="-30%" y="-30%" width="160%" height="170%" color-interpolation-filters="sRGB">
+ <feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0" in="SourceGraphic"/>
+ <feOffset dy="28"/>
+ <feGaussianBlur stdDeviation="18.67" result="blur1"/>
+ </filter>
+ </defs>
+ <g clip-path="url(#clip-vXP8Ybe5)">
+ <g filter="url(#filter-wVmTgUOU)">
+ <rect x="58.88" y="58.88" width="394.24" height="394.24" color="#07773e" fill="red"/>
+ </g>
+ </g>
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -50,16 +50,18 @@ skip-if(Android) pref(layout.css.mix-ble
skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-multiply.svg blend-multiply-ref.svg
pref(layout.css.mix-blend-mode.enabled,true) == blend-normal.svg blend-normal-ref.svg
#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-overlay.svg blend-overlay-ref.svg
#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-saturation.svg blend-saturation-ref.svg
#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-screen.svg blend-screen-ref.svg
#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-soft-light.svg blend-soft-light-ref.svg
skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) fails-if(webrender) == blend-difference-stacking.html blend-difference-stacking-ref.html
+fuzzy(11,7155) == blur-inside-clipPath.svg blur-inside-clipPath-ref.svg
+
== border-radius-01.html pass.svg
== clip-01.svg pass.svg
== clip-02a.svg clip-02-ref.svg
== clip-02b.svg clip-02-ref.svg
== clip-surface-clone-01.svg clip-surface-clone-01-ref.svg
== clip-use-element-01.svg pass.svg
== clip-use-element-02.svg pass.svg
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -470,17 +470,18 @@ nsSVGClipPathFrame::GetClipPathTransform
: 0);
return nsSVGUtils::AdjustMatrixForUnits(tm, clipPathUnits,
aClippedFrame, flags);
}
SVGBBox
nsSVGClipPathFrame::GetBBoxForClipPathFrame(const SVGBBox &aBBox,
- const gfxMatrix &aMatrix)
+ const gfxMatrix &aMatrix,
+ uint32_t aFlags)
{
nsIContent* node = GetContent()->GetFirstChild();
SVGBBox unionBBox, tmpBBox;
for (; node; node = node->GetNextSibling()) {
nsSVGElement* svgNode = static_cast<nsSVGElement*>(node);
nsIFrame* frame = svgNode->GetPrimaryFrame();
if (frame) {
nsSVGDisplayableFrame* svg = do_QueryFrame(frame);
@@ -489,32 +490,34 @@ nsSVGClipPathFrame::GetBBoxForClipPathFr
tmpBBox = svg->GetBBoxContribution(mozilla::gfx::ToMatrix(matrix),
nsSVGUtils::eBBoxIncludeFill);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(frame);
if (effectProperties.HasNoOrValidClipPath()) {
nsSVGClipPathFrame *clipPathFrame =
effectProperties.GetClipPathFrame();
if (clipPathFrame) {
- tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(tmpBBox, aMatrix);
+ tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(tmpBBox, aMatrix, aFlags);
}
}
- tmpBBox.Intersect(aBBox);
+ if (!(aFlags & nsSVGUtils::eDoNotClipToBBoxOfContentInsideClipPath)) {
+ tmpBBox.Intersect(aBBox);
+ }
unionBBox.UnionEdges(tmpBBox);
}
}
}
SVGObserverUtils::EffectProperties props =
SVGObserverUtils::GetEffectProperties(this);
if (props.mClipPath) {
if (props.HasInvalidClipPath()) {
unionBBox = SVGBBox();
} else {
nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame();
if (clipPathFrame) {
- tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(aBBox, aMatrix);
+ tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(aBBox, aMatrix, aFlags);
unionBBox.Intersect(tmpBBox);
}
}
}
return unionBBox;
}
--- a/layout/svg/nsSVGClipPathFrame.h
+++ b/layout/svg/nsSVGClipPathFrame.h
@@ -127,17 +127,18 @@ public:
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override
{
return MakeFrameName(NS_LITERAL_STRING("SVGClipPath"), aResult);
}
#endif
SVGBBox GetBBoxForClipPathFrame(const SVGBBox& aBBox,
- const gfxMatrix& aMatrix);
+ const gfxMatrix& aMatrix,
+ uint32_t aFlags);
/**
* If the clipPath element transforms its children due to
* clipPathUnits="objectBoundingBox" being set on it and/or due to the
* 'transform' attribute being set on it, this function returns the resulting
* transform.
*/
gfxMatrix GetClipPathTransform(nsIFrame* aClippedFrame);
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1176,17 +1176,17 @@ nsSVGUtils::GetBBox(nsIFrame* aFrame, ui
if (clipContent->IsUnitsObjectBoundingBox()) {
matrix.PreTranslate(gfxPoint(x, y));
matrix.PreScale(width, height);
} else if (aFrame->IsSVGForeignObjectFrame()) {
matrix = gfxMatrix();
}
matrix = clipContent->PrependLocalTransformsTo(matrix, eUserSpaceToParent);
bbox =
- clipPathFrame->GetBBoxForClipPathFrame(bbox, matrix).ToThebesRect();
+ clipPathFrame->GetBBoxForClipPathFrame(bbox, matrix, aFlags).ToThebesRect();
}
if (hasClip) {
bbox = bbox.Intersect(clipRect);
}
if (bbox.IsEmpty()) {
bbox = gfxRect(0, 0, 0, 0);
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -407,16 +407,19 @@ public:
// given frame, instead of all continuations of it, while computing bbox if
// this flag is set.
eIncludeOnlyCurrentFrameForNonSVGElement = 1 << 8,
// This flag is only has an effect when the target is a <use> element.
// getBBox returns the bounds of the elements children in user space if
// this flag is set; Otherwise, getBBox returns the union bounds in
// the coordinate system formed by the <use> element.
eUseUserSpaceOfUseElement = 1 << 9,
+ // For a frame with a clip-path, if this flag is set then the result
+ // will not be clipped to the bbox of the content inside the clip-path.
+ eDoNotClipToBBoxOfContentInsideClipPath = 1 << 10,
};
/**
* This function in primarily for implementing the SVG DOM function getBBox()
* and the SVG attribute value 'objectBoundingBox'. However, it has been
* extended with various extra parameters in order to become more of a
* general purpose getter of all sorts of bounds that we might need to obtain
* for SVG elements, or even for other elements that have SVG effects applied
* to them.