Bug 1281215 - Making the outline of SVG container narrows to its children; r?heycam draft
authorDaosheng Mu <daoshengmu@gmail.com>
Fri, 29 Jul 2016 07:35:58 +0800
changeset 394276 fb8a78735877c64979099bac390d61249ac9b782
parent 391305 e0bc88708ffed39aaab1fbc0ac461d93561195de
child 526774 992d3763536bdfe7729892372414718496cc519a
push id24532
push userbmo:dmu@mozilla.com
push dateFri, 29 Jul 2016 11:03:00 +0000
reviewersheycam
bugs1281215
milestone50.0a1
Bug 1281215 - Making the outline of SVG container narrows to its children; r?heycam MozReview-Commit-ID: Ct1mdwmHMw2
layout/generic/nsFrame.cpp
--- 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();