Bug 1099197 - Determine the bounds of unstroked polylines/polygons directly. r=jwatt, a=lsblakk
☠☠ backed out by 7242a447378b ☠ ☠
authorRobert Longson <longsonr@gmail.com>
Mon, 24 Nov 2014 14:28:58 +0000
changeset 234040 4d72f5451cd0ccd5a8e26b7cc7ab406b33ba58c5
parent 234039 8ff014d18f0fc1f05b0b28445d67e7315b463850
child 234041 a71cc988caf54d301598f8184b444c1cf6185a10
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt, lsblakk
bugs1099197
milestone35.0a2
Bug 1099197 - Determine the bounds of unstroked polylines/polygons directly. r=jwatt, a=lsblakk
content/svg/content/src/nsSVGPolyElement.cpp
content/svg/content/src/nsSVGPolyElement.h
gfx/2d/BaseRect.h
--- a/content/svg/content/src/nsSVGPolyElement.cpp
+++ b/content/svg/content/src/nsSVGPolyElement.cpp
@@ -115,16 +115,51 @@ nsSVGPolyElement::GetMarkPoints(nsTArray
     px = x;
     py = y;
   }
 
   aMarks->LastElement().angle = prevAngle;
   aMarks->LastElement().type = nsSVGMark::eEnd;
 }
 
+bool
+nsSVGPolyElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                    const Matrix& aTransform)
+{
+  const SVGPointList &points = mPoints.GetAnimValue();
+
+  if (!points.Length()) {
+    // Rendering of the element is disabled
+    aBounds->SetEmpty();
+    return true;
+  }
+
+  if (aStrokeWidth > 0) {
+    // We don't handle stroke-miterlimit etc. yet
+    return false;
+  }
+
+  if (aTransform.IsRectilinear()) {
+    // We can avoid transforming each point and just transform the result.
+    // Important for large point lists.
+    Rect bounds(points[0], Size());
+    for (uint32_t i = 1; i < points.Length(); ++i) {
+      bounds.ExpandToEnclose(points[i]);
+    }
+    *aBounds = aTransform.TransformBounds(bounds);
+  } else {
+    *aBounds = Rect(aTransform * points[0], Size());
+    for (uint32_t i = 1; i < points.Length(); ++i) {
+      aBounds->ExpandToEnclose(aTransform * points[i]);
+    }
+  }
+  return true;
+}
+
+
 TemporaryRef<Path>
 nsSVGPolyElement::BuildPath(PathBuilder* aBuilder)
 {
   const SVGPointList &points = mPoints.GetAnimValue();
 
   if (points.IsEmpty()) {
     return nullptr;
   }
--- a/content/svg/content/src/nsSVGPolyElement.h
+++ b/content/svg/content/src/nsSVGPolyElement.h
@@ -41,16 +41,18 @@ public:
   // nsSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE;
+  virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                 const Matrix& aTransform) MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<mozilla::DOMSVGPointList> Points();
   already_AddRefed<mozilla::DOMSVGPointList> AnimatedPoints();
 
 protected:
   SVGAnimatedPointList mPoints;
 };
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -171,16 +171,33 @@ struct BaseRect {
   // Thus, empty input rectangles are allowed to affect the result.
   //
   // 'this' can be the same object as either aRect1 or aRect2
   void UnionRectEdges(const Sub& aRect1, const Sub& aRect2)
   {
     *static_cast<Sub*>(this) = aRect1.UnionEdges(aRect2);
   }
 
+  // Expands the rect to include the point
+  void ExpandToEnclose(const Point& aPoint)
+  {
+    if (aPoint.x < x) {
+      width = XMost() - aPoint.x;
+      x = aPoint.x;
+    } else if (aPoint.x > XMost()) {
+      width = aPoint.x - x;
+    }
+    if (aPoint.y < y) {
+      height = YMost() - aPoint.y;
+      y = aPoint.y;
+    } else if (aPoint.y > YMost()) {
+      height = aPoint.y - y;
+    }
+  }
+
   void SetRect(T aX, T aY, T aWidth, T aHeight)
   {
     x = aX; y = aY; width = aWidth; height = aHeight;
   }
   void SetRect(const Point& aPt, const SizeT& aSize)
   {
     SetRect(aPt.x, aPt.y, aSize.width, aSize.height);
   }