diff --git a/dom/svg/SVGCircleElement.cpp b/dom/svg/SVGCircleElement.cpp index 028322297c90..9bc447dfdd1d 100644 --- a/dom/svg/SVGCircleElement.cpp +++ b/dom/svg/SVGCircleElement.cpp @@ -81,6 +81,34 @@ SVGCircleElement::GetLengthInfo() //---------------------------------------------------------------------- // nsSVGPathGeometryElement methods +bool +SVGCircleElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) +{ + float x, y, r; + GetAnimatedLengthValues(&x, &y, &r, nullptr); + + if (r <= 0.f) { + // Rendering of the element is disabled + aBounds->MoveTo(x, y); + aBounds->SetEmpty(); + return true; + } + + if (aTransform.IsRectilinear()) { + // Optimize the case where we can treat the circle as a rectangle and + // still get tight bounds. + if (aStrokeWidth > 0.f) { + r += aStrokeWidth / 2.f; + } + Rect rect(x - r, y - r, 2 * r, 2 * r); + *aBounds = aTransform.TransformBounds(rect); + return true; + } + + return false; +} + TemporaryRef SVGCircleElement::BuildPath(PathBuilder* aBuilder) { diff --git a/dom/svg/SVGCircleElement.h b/dom/svg/SVGCircleElement.h index 5768c4a3a45a..417af2ddcc77 100644 --- a/dom/svg/SVGCircleElement.h +++ b/dom/svg/SVGCircleElement.h @@ -30,6 +30,8 @@ public: virtual bool HasValidDimensions() const MOZ_OVERRIDE; // nsSVGPathGeometryElement methods: + virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) MOZ_OVERRIDE; virtual TemporaryRef BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/dom/svg/SVGEllipseElement.cpp b/dom/svg/SVGEllipseElement.cpp index bb7931245d10..47dc8eb3f91d 100644 --- a/dom/svg/SVGEllipseElement.cpp +++ b/dom/svg/SVGEllipseElement.cpp @@ -92,6 +92,35 @@ SVGEllipseElement::GetLengthInfo() //---------------------------------------------------------------------- // nsSVGPathGeometryElement methods +bool +SVGEllipseElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) +{ + float x, y, rx, ry; + GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); + + if (rx <= 0.f || ry <= 0.f) { + // Rendering of the element is disabled + aBounds->MoveTo(x, y); + aBounds->SetEmpty(); + return true; + } + + if (aTransform.IsRectilinear()) { + // Optimize the case where we can treat the ellipse as a rectangle and + // still get tight bounds. + if (aStrokeWidth > 0.f) { + rx += aStrokeWidth / 2.f; + ry += aStrokeWidth / 2.f; + } + Rect rect(x - rx, y - ry, 2 * rx, 2 * ry); + *aBounds = aTransform.TransformBounds(rect); + return true; + } + + return false; +} + TemporaryRef SVGEllipseElement::BuildPath(PathBuilder* aBuilder) { diff --git a/dom/svg/SVGEllipseElement.h b/dom/svg/SVGEllipseElement.h index 84f239d64970..8cd40f9a0dc3 100644 --- a/dom/svg/SVGEllipseElement.h +++ b/dom/svg/SVGEllipseElement.h @@ -30,6 +30,8 @@ public: virtual bool HasValidDimensions() const MOZ_OVERRIDE; // nsSVGPathGeometryElement methods: + virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) MOZ_OVERRIDE; virtual TemporaryRef BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/dom/svg/nsSVGPathGeometryElement.h b/dom/svg/nsSVGPathGeometryElement.h index c55021b48f3a..5f3b6306bec9 100644 --- a/dom/svg/nsSVGPathGeometryElement.h +++ b/dom/svg/nsSVGPathGeometryElement.h @@ -70,6 +70,12 @@ public: virtual bool IsMarkable(); virtual void GetMarkPoints(nsTArray *aMarks); + /** + * A method that can be faster than using a Moz2D Path and calling GetBounds/ + * GetStrokedBounds on it. It also helps us avoid rounding error for simple + * shapes and simple transforms where the Moz2D Path backends can fail to + * produce the clean integer bounds that content authors expect in some cases. + */ virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, const Matrix& aTransform) { return false;