Bug 997735 - Add nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset. r=roc
authorMarkus Stange <mstange@themasta.com>
Wed, 23 Apr 2014 11:47:42 +0200
changeset 198244 fcd9986a84c58232fdf6a2f8cb6ee994e5be3612
parent 198243 77a55da6682761f7d7284b671f56d9ce2ff7499a
child 198245 f5bd85e791c3f9d61e4da19de4a831f30cbe7c55
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs997735
milestone31.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 997735 - Add nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset. r=roc This function calculates the offset between "bounding box frame space" and "user space" for SVG frames. For non-SVG frames it returns no offset. It's crucial that this is consistent with what nsSVGUtils::GetBBox does. nsFilterInstance has several methods that are called by consumers before the actual painting, e.g. to calculate post filter extents or invalidation regions. Those nsFilterInstance APIs have their input and output values in "bounding box frame space" coordinates, but if the filter units are "objectBoundingBox", then those methods also do calculations involving the result of nsSVGUtils::GetBBox. So a consistent conversion is very important.
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -884,26 +884,57 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, ui
         !static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
       return bbox;
     }
     gfxMatrix matrix;
     if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
       // The spec says getBBox "Returns the tight bounding box in *current user
       // space*". So we should really be doing this for all elements, but that
       // needs investigation to check that we won't break too much content.
+      // NOTE: When changing this to apply to other frame types, make sure to
+      // also update nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset.
       NS_ABORT_IF_FALSE(content->IsSVG(), "bad cast");
       nsSVGElement *element = static_cast<nsSVGElement*>(content);
       matrix = element->PrependLocalTransformsTo(matrix,
                           nsSVGElement::eChildToUserSpace);
     }
     return svg->GetBBoxContribution(ToMatrix(matrix), aFlags).ToThebesRect();
   }
   return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
 }
 
+gfxPoint
+nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame)
+{
+  if (!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
+    // The user space for non-SVG frames is defined as the bounding box of the
+    // frame's border-box rects over all continuations.
+    return gfxPoint();
+  }
+
+  // Leaf frames apply their own offset inside their user space.
+  if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
+      aFrame->IsSVGText()) {
+    return nsLayoutUtils::RectToGfxRect(aFrame->GetRect(),
+                                         nsPresContext::AppUnitsPerCSSPixel()).TopLeft();
+  }
+
+  // For foreignObject frames, nsSVGUtils::GetBBox applies their local
+  // transform, so we need to do the same here.
+  if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
+    gfxMatrix transform = static_cast<nsSVGElement*>(aFrame->GetContent())->
+        PrependLocalTransformsTo(gfxMatrix(),
+                                 nsSVGElement::eChildToUserSpace);
+    NS_ASSERTION(!transform.HasNonTranslation(), "we're relying on this being an offset-only transform");
+    return transform.GetTranslation();
+  }
+
+  return gfxPoint();
+}
+
 gfxRect
 nsSVGUtils::GetRelativeRect(uint16_t aUnits, const nsSVGLength2 *aXYWH,
                             const gfxRect &aBBox, nsIFrame *aFrame)
 {
   float x, y, width, height;
   if (aUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     x = aBBox.X() + ObjectSpace(aBBox, &aXYWH[0]);
     y = aBBox.Y() + ObjectSpace(aBBox, &aXYWH[1]);
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -400,16 +400,26 @@ public:
   };
   /**
    * Get the SVG bbox (the SVG spec's simplified idea of bounds) of aFrame in
    * aFrame's userspace.
    */
   static gfxRect GetBBox(nsIFrame *aFrame,
                          uint32_t aFlags = eBBoxIncludeFillGeometry);
 
+  /*
+   * "User space" is the space that the frame's BBox (as calculated by
+   * nsSVGUtils::GetBBox) is in. "Frame space" is the space that has its origin
+   * at the top left of the union of the frame's border-box rects over all
+   * continuations.
+   * This function returns the offset one needs to add to something in frame
+   * space in order to get its coordinates in user space.
+   */
+  static gfxPoint FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame);
+
   /**
    * Convert a userSpaceOnUse/objectBoundingBoxUnits rectangle that's specified
    * using four nsSVGLength2 values into a user unit rectangle in user space.
    *
    * @param aXYWH pointer to 4 consecutive nsSVGLength2 objects containing
    * the x, y, width and height values in that order
    * @param aBBox the bounding box of the object the rect is relative to;
    * may be null if aUnits is not SVG_UNIT_TYPE_OBJECTBOUNDINGBOX