diff --git a/dom/svg/SVGContentUtils.h b/dom/svg/SVGContentUtils.h index 2a613d4899c2..26f96a7a5c52 100644 --- a/dom/svg/SVGContentUtils.h +++ b/dom/svg/SVGContentUtils.h @@ -39,6 +39,8 @@ class Matrix; } // namespace gfx } // namespace mozilla +#define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512 + inline bool IsSVGWhitespace(char aChar) { diff --git a/dom/svg/SVGLineElement.cpp b/dom/svg/SVGLineElement.cpp index 7fc6a879ee47..8e481567f8f6 100644 --- a/dom/svg/SVGLineElement.cpp +++ b/dom/svg/SVGLineElement.cpp @@ -37,6 +37,23 @@ SVGLineElement::SVGLineElement(already_AddRefed& aNodeIn { } +void +SVGLineElement::MaybeAdjustForZeroLength(float aX1, float aY1, + float& aX2, float aY2) +{ + if (aX1 == aX2 && aY1 == aY2) { + SVGContentUtils::AutoStrokeOptions strokeOptions; + SVGContentUtils::GetStrokeOptions(&strokeOptions, this, nullptr, nullptr, + SVGContentUtils::eIgnoreStrokeDashing); + + if (strokeOptions.mLineCap != CapStyle::BUTT) { + float tinyLength = + strokeOptions.mLineWidth / SVG_ZERO_LENGTH_PATH_FIX_FACTOR; + aX2 += tinyLength; + } + } +} + //---------------------------------------------------------------------- // nsIDOMNode methods @@ -112,6 +129,8 @@ SVGLineElement::GetAsSimplePath(SimplePath* aSimplePath) { float x1, y1, x2, y2; GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr); + + MaybeAdjustForZeroLength(x1, y1, x2, y2); aSimplePath->SetLine(x1, y1, x2, y2); } @@ -121,6 +140,7 @@ SVGLineElement::BuildPath(PathBuilder* aBuilder) float x1, y1, x2, y2; GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr); + MaybeAdjustForZeroLength(x1, y1, x2, y2); aBuilder->MoveTo(Point(x1, y1)); aBuilder->LineTo(Point(x2, y2)); diff --git a/dom/svg/SVGLineElement.h b/dom/svg/SVGLineElement.h index f80cd5cb57fe..93ae940130bf 100644 --- a/dom/svg/SVGLineElement.h +++ b/dom/svg/SVGLineElement.h @@ -25,6 +25,10 @@ protected: virtual JSObject* WrapNode(JSContext *cx, JS::Handle aGivenProto) override; friend nsresult (::NS_NewSVGLineElement(nsIContent **aResult, already_AddRefed&& aNodeInfo)); + // If the input line has length zero and linecaps aren't butt, adjust |aX2| by + // a tiny amount to a barely-nonzero-length line that all of our draw targets + // will render + void MaybeAdjustForZeroLength(float aX1, float aY1, float& aX2, float aY2); public: // nsIContent interface diff --git a/dom/svg/SVGPathData.cpp b/dom/svg/SVGPathData.cpp index 2294eb450968..2020798b4f5e 100644 --- a/dom/svg/SVGPathData.cpp +++ b/dom/svg/SVGPathData.cpp @@ -255,7 +255,7 @@ ApproximateZeroLengthSubpathSquareCaps(PathBuilder* aPB, // line is rather arbitrary, other than being chosen to meet the requirements // described in the comment above. - Float tinyLength = aStrokeWidth / 512; + Float tinyLength = aStrokeWidth / SVG_ZERO_LENGTH_PATH_FIX_FACTOR; aPB->LineTo(aPoint + Point(tinyLength, 0)); aPB->MoveTo(aPoint); diff --git a/layout/reftests/svg/stroke-linecap-round-w-zero-length-segs-01.svg b/layout/reftests/svg/stroke-linecap-round-w-zero-length-segs-01.svg index 0f8e174d99b0..5a6c6ad2c21c 100644 --- a/layout/reftests/svg/stroke-linecap-round-w-zero-length-segs-01.svg +++ b/layout/reftests/svg/stroke-linecap-round-w-zero-length-segs-01.svg @@ -6,11 +6,12 @@ Test 'stroke-linecap: round' with zero length path segments - +