Bug 1385745 - Part 1: Add BBoxFlags::eIncludeOnlyCurrentFrameForNonSVGElement to determine whether include all continuations while computing bbox of a html frame. r=cjku, r=heycam, a=gchang
authorLouis Chang <lochang@mozilla.com>
Thu, 17 Aug 2017 09:52:17 +0800
changeset 423720 06894e19fc5bfa67b45e4d9d5e7fd10430ea2271
parent 423719 ce166fe03511b29916c6f2cba5234af75fc05266
child 423721 2bd7fc8ce509baf357a1baa0356b1c29d40c4c2e
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjku, heycam, gchang
bugs1385745
milestone56.0
Bug 1385745 - Part 1: Add BBoxFlags::eIncludeOnlyCurrentFrameForNonSVGElement to determine whether include all continuations while computing bbox of a html frame. r=cjku, r=heycam, a=gchang MozReview-Commit-ID: Fx11LjhBcrM
layout/svg/nsSVGClipPathFrame.cpp
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGIntegrationUtils.h
layout/svg/nsSVGMaskFrame.cpp
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -460,17 +460,24 @@ nsSVGClipPathFrame::GetClipPathTransform
 {
   SVGClipPathElement *content = static_cast<SVGClipPathElement*>(mContent);
 
   gfxMatrix tm = content->PrependLocalTransformsTo(gfxMatrix());
 
   nsSVGEnum* clipPathUnits =
     &content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS];
 
-  return nsSVGUtils::AdjustMatrixForUnits(tm, clipPathUnits, aClippedFrame);
+  uint32_t flags =
+    nsSVGUtils::eBBoxIncludeFillGeometry |
+    (aClippedFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone
+      ? nsSVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
+      : 0);
+
+  return nsSVGUtils::AdjustMatrixForUnits(tm, clipPathUnits,
+                                          aClippedFrame, flags);
 }
 
 SVGBBox
 nsSVGClipPathFrame::GetBBoxForClipPathFrame(const SVGBBox &aBBox,
                                             const gfxMatrix &aMatrix)
 {
   nsIContent* node = GetContent()->GetFirstChild();
   SVGBBox unionBBox, tmpBBox;
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -208,38 +208,36 @@ nsSVGIntegrationUtils::GetSVGCoordContex
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aNonSVGFrame);
   nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(firstFrame, firstFrame);
   nsPresContext* presContext = firstFrame->PresContext();
   return gfx::Size(presContext->AppUnitsToFloatCSSPixels(r.width),
                    presContext->AppUnitsToFloatCSSPixels(r.height));
 }
 
 gfxRect
-nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame)
+nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame,
+                                                bool aUnionContinuations)
 {
   // Except for nsSVGOuterSVGFrame, we shouldn't be getting here with SVG
   // frames at all. This function is for elements that are laid out using the
   // CSS box model rules.
   NS_ASSERTION(!(aNonSVGFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT),
                "Frames with SVG layout should not get here");
   MOZ_ASSERT(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG) ||
              aNonSVGFrame->IsSVGOuterSVGFrame());
 
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aNonSVGFrame);
   // 'r' is in "user space":
-  nsRect r;
-  if (aNonSVGFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone) {
-    r = GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame,
-                                    GetOffsetToBoundingBox(firstFrame));
-  } else {
-    r = GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
-                                         GetOffsetToBoundingBox(firstFrame),
-                                         false);
-  }
+  nsRect r = (aUnionContinuations)
+    ? GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
+                                       GetOffsetToBoundingBox(firstFrame),
+                                       false)
+    : GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame,
+                                  GetOffsetToBoundingBox(firstFrame));
 
   return nsLayoutUtils::RectToGfxRect(r,
            aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel());
 }
 
 // XXX Since we're called during reflow, this method is broken for frames with
 // continuations. When we're called for a frame with continuations, we're
 // called for each continuation in turn as it's reflowed. However, it isn't
--- a/layout/svg/nsSVGIntegrationUtils.h
+++ b/layout/svg/nsSVGIntegrationUtils.h
@@ -73,22 +73,23 @@ public:
   static mozilla::gfx::Size
   GetSVGCoordContextForNonSVGFrame(nsIFrame* aNonSVGFrame);
 
   /**
    * SVG effects such as SVG filters, masking and clipPath may require an SVG
    * "bbox" for the element they're being applied to in order to make decisions
    * about positioning, and to resolve various lengths against. This method
    * provides the "bbox" for non-SVG frames. The bbox returned is in CSS px
-   * units, and is the union of all aNonSVGFrame's continuations' overflow
-   * areas, relative to the top-left of the union of all aNonSVGFrame's
+   * units, and aUnionContinuations decide whether bbox contains the area of
+   * current frame only or the union of all aNonSVGFrame's continuations'
+   * overflow areas, relative to the top-left of the union of all aNonSVGFrame's
    * continuations' border box rects.
    */
   static gfxRect
-  GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame);
+  GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame, bool aUnionContinuations);
 
   /**
    * Used to adjust a frame's pre-effects visual overflow rect to take account
    * of SVG effects.
    *
    * XXX This method will not do the right thing for frames with continuations.
    * It really needs all the continuations to have been reflowed before being
    * called, but we currently call it on each continuation as its overflow
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -221,11 +221,17 @@ nsSVGMaskFrame::GetCanvasTM()
 gfxMatrix
 nsSVGMaskFrame::GetMaskTransform(nsIFrame* aMaskedFrame)
 {
   SVGMaskElement *content = static_cast<SVGMaskElement*>(mContent);
 
   nsSVGEnum* maskContentUnits =
     &content->mEnumAttributes[SVGMaskElement::MASKCONTENTUNITS];
 
+  uint32_t flags =
+    nsSVGUtils::eBBoxIncludeFillGeometry |
+    (aMaskedFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone
+      ? nsSVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
+      : 0);
+
   return nsSVGUtils::AdjustMatrixForUnits(gfxMatrix(), maskContentUnits,
-                                          aMaskedFrame);
+                                          aMaskedFrame, flags);
 }
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1094,17 +1094,20 @@ nsSVGUtils::GetBBox(nsIFrame* aFrame, ui
   }
 
   const bool isOuterSVG = svg && !hasSVGLayout;
   MOZ_ASSERT(!isOuterSVG || aFrame->IsSVGOuterSVGFrame());
   if (!svg ||
       (isOuterSVG && (aFlags & eUseFrameBoundsForOuterSVG))) {
     // An HTML element or an SVG outer frame.
     MOZ_ASSERT(!hasSVGLayout);
-    return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
+    bool onlyCurrentFrame = aFlags & eIncludeOnlyCurrentFrameForNonSVGElement;
+    return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(
+      aFrame,
+      /* aUnionContinuations = */ !onlyCurrentFrame);
   }
 
   MOZ_ASSERT(svg);
 
   nsIContent* content = aFrame->GetContent();
   if (content->IsSVGElement() &&
       !static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
     return gfxRect();
@@ -1291,21 +1294,22 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame 
     return true;
   }
   return false;
 }
 
 gfxMatrix
 nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix &aMatrix,
                                  nsSVGEnum *aUnits,
-                                 nsIFrame *aFrame)
+                                 nsIFrame *aFrame,
+                                 uint32_t aFlags)
 {
   if (aFrame &&
       aUnits->GetAnimValue() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
-    gfxRect bbox = GetBBox(aFrame);
+    gfxRect bbox = GetBBox(aFrame, aFlags);
     gfxMatrix tm = aMatrix;
     tm.PreTranslate(gfxPoint(bbox.X(), bbox.Y()));
     tm.PreScale(bbox.Width(), bbox.Height());
     return tm;
   }
   return aMatrix;
 }
 
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -374,48 +374,55 @@ public:
 
   /**
    * Take the CTM to userspace for an element, and adjust it to a CTM to its
    * object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX.
    * (I.e. so that [0,0] is at the top left of its bbox, and [1,1] is at the
    * bottom right of its bbox).
    *
    * If the bbox is empty, this will return a singular matrix.
+   *
+   * @param aFlags One or more of the BBoxFlags values defined below.
    */
   static gfxMatrix AdjustMatrixForUnits(const gfxMatrix &aMatrix,
                                         nsSVGEnum *aUnits,
-                                        nsIFrame *aFrame);
+                                        nsIFrame *aFrame,
+                                        uint32_t aFlags);
 
   enum BBoxFlags {
     eBBoxIncludeFill           = 1 << 0,
     eBBoxIncludeFillGeometry   = 1 << 1,
     eBBoxIncludeStroke         = 1 << 2,
     eBBoxIncludeStrokeGeometry = 1 << 3,
     eBBoxIncludeMarkers        = 1 << 4,
     eBBoxIncludeClipped        = 1 << 5,
     // Normally a getBBox call on outer-<svg> should only return the
-    // bounds of the elements children.  This flag will cause the
+    // bounds of the elements children. This flag will cause the
     // element's bounds to be returned instead.
     eUseFrameBoundsForOuterSVG = 1 << 6,
     // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
     eForGetClientRects         = 1 << 7,
+    // If the given frame is an HTML element, only include the region of the
+    // given frame, instead of all continuations of it, while computing bbox if
+    // this flag is set.
+    eIncludeOnlyCurrentFrameForNonSVGElement = 1 << 8,
   };
   /**
    * 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.
    *
    * @param aFrame The frame of the element for which the bounds are to be
    *   obtained.
    * @param aFlags One or more of the BBoxFlags values defined above.
    * @param aToBoundsSpace If not specified the returned rect is in aFrame's
-   *   element's "user space".  A matrix can optionally be pass to specify a
+   *   element's "user space". A matrix can optionally be pass to specify a
    *   transform from aFrame's user space to the bounds space of interest
    *   (typically this will be the ancestor nsSVGOuterSVGFrame, but it could be
    *   to any other coordinate space).
    */
   static gfxRect GetBBox(nsIFrame *aFrame,
                          // If the default arg changes, update the handling for
                          // ObjectBoundingBoxProperty() in the implementation.
                          uint32_t aFlags = eBBoxIncludeFillGeometry,