diff --git a/layout/svg/SVGGeometryFrame.cpp b/layout/svg/SVGGeometryFrame.cpp index 21b81bcbd406..5711f7c613d2 100644 --- a/layout/svg/SVGGeometryFrame.cpp +++ b/layout/svg/SVGGeometryFrame.cpp @@ -744,29 +744,52 @@ void SVGGeometryFrame::PaintMarkers(gfxContext& aContext, const gfxMatrix& aTransform, imgDrawingParams& aImgParams) { auto* element = static_cast(GetContent()); - - if (element->IsMarkable()) { - SVGMarkerFrame* markerFrames[SVGMark::eTypeCount]; - if (SVGObserverUtils::GetAndObserveMarkers(this, &markerFrames)) { - nsTArray marks; - element->GetMarkPoints(&marks); - if (uint32_t num = marks.Length()) { - SVGContextPaint* contextPaint = - SVGContextPaint::GetContextPaint(GetContent()); - float strokeWidth = SVGUtils::GetStrokeWidth(this, contextPaint); - for (uint32_t i = 0; i < num; i++) { - const SVGMark& mark = marks[i]; - SVGMarkerFrame* frame = markerFrames[mark.type]; - if (frame) { - frame->PaintMark(aContext, aTransform, this, mark, strokeWidth, - aImgParams); - } - } - } + if (!element->IsMarkable()) { + return; + } + SVGMarkerFrame* markerFrames[SVGMark::eTypeCount]; + if (!SVGObserverUtils::GetAndObserveMarkers(this, &markerFrames)) { + return; + } + nsTArray marks; + element->GetMarkPoints(&marks); + if (marks.IsEmpty()) { + return; + } + float strokeWidth = GetStrokeWidthForMarkers(); + for (const SVGMark& mark : marks) { + if (auto* frame = markerFrames[mark.type]) { + frame->PaintMark(aContext, aTransform, this, mark, strokeWidth, + aImgParams); } } } +float SVGGeometryFrame::GetStrokeWidthForMarkers() { + float strokeWidth = SVGUtils::GetStrokeWidth( + this, SVGContextPaint::GetContextPaint(GetContent())); + gfxMatrix userToOuterSVG; + if (SVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) { + // We're not interested in any translation here so we can treat this as + // Singular Value Decomposition (SVD) of a 2 x 2 matrix. That would give us + // sx and sy values as the X and Y scales. The value we want is the XY + // scale i.e. the normalised hypotenuse, which is sqrt(sx^2 + sy^2) / + // sqrt(2). If we use the formulae from + // https://scicomp.stackexchange.com/a/14103, we discover that the + // normalised hypotenuse is simply the square root of the sum of the squares + // of all the 2D matrix elements divided by sqrt(2). + // + // Note that this may need adjusting to support 3D transforms properly. + + strokeWidth /= float(sqrt(userToOuterSVG._11 * userToOuterSVG._11 + + userToOuterSVG._12 * userToOuterSVG._12 + + userToOuterSVG._21 * userToOuterSVG._21 + + userToOuterSVG._22 * userToOuterSVG._22) / + M_SQRT2); + } + return strokeWidth; +} + uint16_t SVGGeometryFrame::GetHitTestFlags() { return SVGUtils::GetGeometryHitTestFlags(this); } diff --git a/layout/svg/SVGGeometryFrame.h b/layout/svg/SVGGeometryFrame.h index 1458d53c2867..a69587cad055 100644 --- a/layout/svg/SVGGeometryFrame.h +++ b/layout/svg/SVGGeometryFrame.h @@ -137,6 +137,12 @@ class SVGGeometryFrame : public nsIFrame, public ISVGDisplayableFrame { */ void PaintMarkers(gfxContext& aContext, const gfxMatrix& aTransform, imgDrawingParams& aImgParams); + + /* + * Get the stroke width that markers should use, accounting for + * non-scaling stroke. + */ + float GetStrokeWidthForMarkers(); }; //---------------------------------------------------------------------- diff --git a/testing/web-platform/meta/svg/painting/reftests/marker-units-strokewidth-non-scaling-stroke.svg.ini b/testing/web-platform/meta/svg/painting/reftests/marker-units-strokewidth-non-scaling-stroke.svg.ini deleted file mode 100644 index cd672e5663e9..000000000000 --- a/testing/web-platform/meta/svg/painting/reftests/marker-units-strokewidth-non-scaling-stroke.svg.ini +++ /dev/null @@ -1,2 +0,0 @@ -[marker-units-strokewidth-non-scaling-stroke.svg] - expected: FAIL