--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -7840,22 +7840,30 @@ IsInlineFrame(nsIFrame *aFrame)
/**
* Compute the union of the border boxes of aFrame and its descendants,
* in aFrame's coordinate space (if aApplyTransform is false) or its
* post-transform coordinate space (if aApplyTransform is true).
*/
static nsRect
UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
+ bool& aOutValid,
const nsSize* aSizeOverride = nullptr,
const nsOverflowAreas* aOverflowOverride = nullptr)
{
const nsRect bounds(nsPoint(0, 0),
aSizeOverride ? *aSizeOverride : aFrame->GetSize());
+ // The SVG container frames do not maintain an accurate mRect.
+ // It will make the outline be larger than we expect, we need
+ // to make them narrow to their children's outline.
+ // aOutValid is set to false if the returned nsRect is not valid
+ // and should not be included in the outline rectangle.
+ aOutValid = !aFrame->IsFrameOfType(nsIFrame::eSVGContainer);
+
// Start from our border-box, transformed. See comment below about
// transform of children.
nsRect u;
bool doTransform = aApplyTransform && aFrame->IsTransformed();
if (doTransform) {
u = nsDisplayTransform::TransformRect(bounds, aFrame, &bounds);
} else {
u = bounds;
@@ -7908,34 +7916,47 @@ UnionBorderBoxes(nsIFrame* aFrame, bool
// child->Combines3DTransformWithAncestors() is incorrect if our
// aApplyTransform is false... but the opposite would be as
// well. This is because elements within a preserve-3d scene
// are always transformed up to the top of the scene. This
// means we don't have a mechanism for getting a transform up to
// an intermediate point within the scene. We choose to
// over-transform rather than under-transform because this is
// consistent with other overflow areas.
- nsRect childRect = UnionBorderBoxes(child, true) +
+ bool validRect = true;
+ nsRect childRect = UnionBorderBoxes(child, true, validRect) +
child->GetPosition();
+ if (!validRect) {
+ continue;
+ }
+
if (hasClipPropClip) {
// Intersect with the clip before transforming.
childRect.IntersectRect(childRect, clipPropClipRect);
}
// Note that we transform each child separately according to
// aFrame's transform, and then union, which gives a different
// (smaller) result from unioning and then transforming the
// union. This doesn't match the way we handle overflow areas
// with 2-D transforms, though it does match the way we handle
// overflow areas in preserve-3d 3-D scenes.
if (doTransform && !child->Combines3DTransformWithAncestors()) {
childRect = nsDisplayTransform::TransformRect(childRect, aFrame, &bounds);
}
- u.UnionRectEdges(u, childRect);
+
+ // If a SVGContainer has a non-SVGContainer child, we assign
+ // its child's outline to this SVGContainer directly.
+ if (!aOutValid && validRect) {
+ u = childRect;
+ aOutValid = true;
+ } else {
+ u.UnionRectEdges(u, childRect);
+ }
}
}
return u;
}
static void
ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
@@ -7972,21 +7993,22 @@ ComputeAndIncludeOutlineArea(nsIFrame* a
// Find the union of the border boxes of all descendants, or in
// the block-in-inline case, all descendants we care about.
//
// Note that the interesting perspective-related cases are taken
// care of by the code that handles those issues for overflow
// calling FinishAndStoreOverflow again, which in turn calls this
// function again. We still need to deal with preserve-3d a bit.
nsRect innerRect;
+ bool validRect;
if (frameForArea == aFrame) {
- innerRect = UnionBorderBoxes(aFrame, false, &aNewSize, &aOverflowAreas);
+ innerRect = UnionBorderBoxes(aFrame, false, validRect, &aNewSize, &aOverflowAreas);
} else {
for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
- nsRect r(UnionBorderBoxes(frameForArea, true));
+ nsRect r(UnionBorderBoxes(frameForArea, true, validRect));
// Adjust for offsets transforms up to aFrame's pre-transform
// (i.e., normal) coordinate space; see comments in
// UnionBorderBoxes for some of the subtlety here.
for (nsIFrame *f = frameForArea, *parent = f->GetParent();
/* see middle of loop */;
f = parent, parent = f->GetParent()) {
r += f->GetPosition();