From d76cf3c6258fa0bdb783d7ff3e423c1173f78c44 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Thu, 22 Jan 2015 09:36:08 +0000 Subject: [PATCH] Bug 1090934 - Get bounds of line element using maths. r=jwatt --- dom/svg/SVGCircleElement.cpp | 2 +- dom/svg/SVGCircleElement.h | 2 +- dom/svg/SVGEllipseElement.cpp | 2 +- dom/svg/SVGEllipseElement.h | 2 +- dom/svg/SVGImageElement.cpp | 2 +- dom/svg/SVGImageElement.h | 2 +- dom/svg/SVGLineElement.cpp | 61 +++++++++++++++++++++++++++ dom/svg/SVGLineElement.h | 2 + dom/svg/SVGRectElement.cpp | 2 +- dom/svg/SVGRectElement.h | 2 +- dom/svg/nsSVGPathGeometryElement.h | 3 +- dom/svg/nsSVGPolyElement.cpp | 2 +- dom/svg/nsSVGPolyElement.h | 2 +- layout/svg/nsSVGPathGeometryFrame.cpp | 12 +++++- 14 files changed, 85 insertions(+), 13 deletions(-) diff --git a/dom/svg/SVGCircleElement.cpp b/dom/svg/SVGCircleElement.cpp index deac6112db1..1ba06f2aa33 100644 --- a/dom/svg/SVGCircleElement.cpp +++ b/dom/svg/SVGCircleElement.cpp @@ -83,7 +83,7 @@ SVGCircleElement::GetLengthInfo() bool SVGCircleElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) + CapStyle aCapStyle, const Matrix& aTransform) { float x, y, r; GetAnimatedLengthValues(&x, &y, &r, nullptr); diff --git a/dom/svg/SVGCircleElement.h b/dom/svg/SVGCircleElement.h index 417af2ddcc7..064e5d0b65f 100644 --- a/dom/svg/SVGCircleElement.h +++ b/dom/svg/SVGCircleElement.h @@ -31,7 +31,7 @@ public: // nsSVGPathGeometryElement methods: virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) MOZ_OVERRIDE; + CapStyle aCapStyle, 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 a0ae35bb611..f23ccd943a4 100644 --- a/dom/svg/SVGEllipseElement.cpp +++ b/dom/svg/SVGEllipseElement.cpp @@ -94,7 +94,7 @@ SVGEllipseElement::GetLengthInfo() bool SVGEllipseElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) + CapStyle aCapStyle, const Matrix& aTransform) { float x, y, rx, ry; GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); diff --git a/dom/svg/SVGEllipseElement.h b/dom/svg/SVGEllipseElement.h index 8cd40f9a0dc..5eefc20c9df 100644 --- a/dom/svg/SVGEllipseElement.h +++ b/dom/svg/SVGEllipseElement.h @@ -31,7 +31,7 @@ public: // nsSVGPathGeometryElement methods: virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) MOZ_OVERRIDE; + CapStyle aCapStyle, 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/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp index 31cde149d92..7022dcfd05e 100644 --- a/dom/svg/SVGImageElement.cpp +++ b/dom/svg/SVGImageElement.cpp @@ -228,7 +228,7 @@ SVGImageElement::IsAttributeMapped(const nsIAtom* name) const be a rectangle. */ bool SVGImageElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) + CapStyle aCapStyle, const Matrix& aTransform) { Rect rect; GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width, diff --git a/dom/svg/SVGImageElement.h b/dom/svg/SVGImageElement.h index c083c28d260..548a1662fad 100644 --- a/dom/svg/SVGImageElement.h +++ b/dom/svg/SVGImageElement.h @@ -54,7 +54,7 @@ public: // nsSVGPathGeometryElement methods: virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) MOZ_OVERRIDE; + CapStyle cap, const Matrix& aTransform) MOZ_OVERRIDE; virtual TemporaryRef BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE; // nsSVGSVGElement methods: diff --git a/dom/svg/SVGLineElement.cpp b/dom/svg/SVGLineElement.cpp index 206a74ea2b1..e645f5fd5be 100644 --- a/dom/svg/SVGLineElement.cpp +++ b/dom/svg/SVGLineElement.cpp @@ -126,5 +126,66 @@ SVGLineElement::BuildPath(PathBuilder* aBuilder) return aBuilder->Finish(); } +bool +SVGLineElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + CapStyle aCapStyle, const Matrix& aTransform) +{ + float x1, y1, x2, y2; + GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr); + + if (aStrokeWidth <= 0) { + *aBounds = Rect(aTransform * Point(x1, y1), Size()); + aBounds->ExpandToEnclose(aTransform * Point(x2, y2)); + return true; + } + + if (aCapStyle == CapStyle::ROUND) { + if (!aTransform.IsRectilinear()) { + // TODO: handle this case. + return false; + } + Rect bounds(Point(x1, y1), Size()); + bounds.ExpandToEnclose(Point(x2, y2)); + bounds.Inflate(aStrokeWidth / 2.f); + *aBounds = aTransform.TransformBounds(bounds); + return true; + } + + Float length = Float(NS_hypot(x2 - x1, y2 - y1)); + Float xDelta; + Float yDelta; + + if (aCapStyle == CapStyle::BUTT) { + if (length == 0.f) { + xDelta = yDelta = 0.f; + } else { + Float ratio = aStrokeWidth / 2.f / length; + xDelta = ratio * (y2 - y1); + yDelta = ratio * (x2 - x1); + } + } else { + MOZ_ASSERT(aCapStyle == CapStyle::SQUARE); + if (length == 0.f) { + xDelta = yDelta = aStrokeWidth / 2.f; + } else { + Float ratio = aStrokeWidth / 2.f / length; + xDelta = yDelta = ratio * (fabs(y2 - y1) + fabs(x2 - x1)); + } + } + + Point points[4]; + + points[0] = Point(x1 - xDelta, y1 - yDelta); + points[1] = Point(x1 + xDelta, y1 + yDelta); + points[2] = Point(x2 + xDelta, y2 + yDelta); + points[3] = Point(x2 - xDelta, y2 - yDelta); + + *aBounds = Rect(aTransform * points[0], Size()); + for (uint32_t i = 1; i < 4; ++i) { + aBounds->ExpandToEnclose(aTransform * points[i]); + } + return true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/svg/SVGLineElement.h b/dom/svg/SVGLineElement.h index e8c098d1cfe..ddb63d13b6f 100644 --- a/dom/svg/SVGLineElement.h +++ b/dom/svg/SVGLineElement.h @@ -34,6 +34,8 @@ public: virtual void GetMarkPoints(nsTArray *aMarks) MOZ_OVERRIDE; virtual void GetAsSimplePath(SimplePath* aSimplePath) MOZ_OVERRIDE; virtual TemporaryRef BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE; + virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + CapStyle cap, const Matrix& aTransform) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/dom/svg/SVGRectElement.cpp b/dom/svg/SVGRectElement.cpp index 8bd69f458e3..ef82fe75b04 100644 --- a/dom/svg/SVGRectElement.cpp +++ b/dom/svg/SVGRectElement.cpp @@ -112,7 +112,7 @@ SVGRectElement::GetLengthInfo() bool SVGRectElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) + CapStyle aCapStyle, const Matrix& aTransform) { Rect rect; Float rx, ry; diff --git a/dom/svg/SVGRectElement.h b/dom/svg/SVGRectElement.h index 3340ecf45ce..ec97daae3e5 100644 --- a/dom/svg/SVGRectElement.h +++ b/dom/svg/SVGRectElement.h @@ -31,7 +31,7 @@ public: // nsSVGPathGeometryElement methods: virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) MOZ_OVERRIDE; + CapStyle aCapStyle, const Matrix& aTransform) MOZ_OVERRIDE; virtual void GetAsSimplePath(SimplePath* aSimplePath) MOZ_OVERRIDE; virtual TemporaryRef BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE; diff --git a/dom/svg/nsSVGPathGeometryElement.h b/dom/svg/nsSVGPathGeometryElement.h index 5f3b6306bec..3145f7fc6ef 100644 --- a/dom/svg/nsSVGPathGeometryElement.h +++ b/dom/svg/nsSVGPathGeometryElement.h @@ -31,6 +31,7 @@ typedef mozilla::dom::SVGGraphicsElement nsSVGPathGeometryElementBase; class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase { protected: + typedef mozilla::gfx::CapStyle CapStyle; typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::FillRule FillRule; typedef mozilla::gfx::Float Float; @@ -77,7 +78,7 @@ public: * produce the clean integer bounds that content authors expect in some cases. */ virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) { + CapStyle aCapStyle, const Matrix& aTransform) { return false; } diff --git a/dom/svg/nsSVGPolyElement.cpp b/dom/svg/nsSVGPolyElement.cpp index 211d8015d89..e1914a9d4ef 100644 --- a/dom/svg/nsSVGPolyElement.cpp +++ b/dom/svg/nsSVGPolyElement.cpp @@ -122,7 +122,7 @@ nsSVGPolyElement::GetMarkPoints(nsTArray *aMarks) bool nsSVGPolyElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) + CapStyle aCapStyle, const Matrix& aTransform) { const SVGPointList &points = mPoints.GetAnimValue(); diff --git a/dom/svg/nsSVGPolyElement.h b/dom/svg/nsSVGPolyElement.h index 32f271bb6d9..f8313187ed6 100644 --- a/dom/svg/nsSVGPolyElement.h +++ b/dom/svg/nsSVGPolyElement.h @@ -46,7 +46,7 @@ public: virtual bool IsMarkable() MOZ_OVERRIDE { return true; } virtual void GetMarkPoints(nsTArray *aMarks) MOZ_OVERRIDE; virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, - const Matrix& aTransform) MOZ_OVERRIDE; + CapStyle aCapStyle, const Matrix& aTransform) MOZ_OVERRIDE; // WebIDL already_AddRefed Points(); diff --git a/layout/svg/nsSVGPathGeometryFrame.cpp b/layout/svg/nsSVGPathGeometryFrame.cpp index 9fa123dbce4..2481c8495f2 100644 --- a/layout/svg/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/nsSVGPathGeometryFrame.cpp @@ -471,9 +471,17 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace, bool gotSimpleBounds = false; if (!StyleSVGReset()->HasNonScalingStroke()) { - Float strokeWidth = getStroke ? nsSVGUtils::GetStrokeWidth(this) : 0.f; + SVGContentUtils::AutoStrokeOptions strokeOptions; + strokeOptions.mLineWidth = 0.f; + if (getStroke) { + SVGContentUtils::GetStrokeOptions(&strokeOptions, element, + StyleContext(), nullptr, + SVGContentUtils::eIgnoreStrokeDashing); + } Rect simpleBounds; - gotSimpleBounds = element->GetGeometryBounds(&simpleBounds, strokeWidth, + gotSimpleBounds = element->GetGeometryBounds(&simpleBounds, + strokeOptions.mLineWidth, + strokeOptions.mLineCap, aToBBoxUserspace); if (gotSimpleBounds) { bbox = simpleBounds;