Bug 1281215 - Make the outline of SVG container narrows to its children. r=heycam
authorDaosheng Mu <daoshengmu@gmail.com>
Fri, 29 Jul 2016 07:35:58 +0800
changeset 307348 61c513b90c50559092a853e365ed50be7af6addd
parent 307347 5ad44f0d3ea46981d77e10563fe5c868384bfdc4
child 307349 ebdaaac3f55d32e161abdb687b5024c6f1495960
push id30945
push usercbook@mozilla.com
push dateSat, 30 Jul 2016 14:50:21 +0000
treeherderautoland@9e48f74f44c3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1281215
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1281215 - Make 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
@@ -7861,22 +7861,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;
@@ -7929,34 +7937,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,
@@ -7993,21 +8014,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();