commit 8bc0bdaaa050082b5f64d705901ae9bd9fc8d0bd
parent c2a7a56a1775e6c9cfd4267cda8870a1fafa5808
Author: Timothy Nikkel <tnikkel@gmail.com>
Date: Fri, 17 Oct 2025 07:21:10 +0000
Bug 1994934. Allow rects to be transformed to the full nscoord range. r=longsonr
We limit the result to the range (nscoord_min/2,nscoord_max/2) to ensure that the size of the rect does not exceed nscoord_max. However we can do better, just limit to (nscoord_min,nscoord_max), and then if the resulting rect has a size that exceeds nscoord_max then RoundGfxRectToAppRect will intelligently handle it by shrinking the rect to nscoord_max and shifting it to its midpoint. The naive approach of just limiting the x, y, width, and height to the nscoord bounds would yield a rect positioned at nscoord_min with size nscoord_max, and thus would not touch the positive axis at all which is where what is visible is almost always.
Differential Revision: https://phabricator.services.mozilla.com/D269003
Diffstat:
3 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
@@ -1861,9 +1861,14 @@ nsRect nsLayoutUtils::MatrixTransformRect(const nsRect& aBounds,
NSAppUnitsToDoublePixels(aBounds.width, aFactor),
NSAppUnitsToDoublePixels(aBounds.height, aFactor));
+ // We clip from nscoord_MIN to nscoord_MAX which allows the resulting rect to
+ // have a size that goes up to 2*nscoord_MAX. We then rely on
+ // RoundGfxRectToAppRect to handle this situation intelligently to give us a
+ // size representable as an nscoord by shifting the rect to its mid point and
+ // shrinking the size to nscoord_MAX.
RectDouble maxBounds = RectDouble(
- double(nscoord_MIN) / aFactor * 0.5, double(nscoord_MIN) / aFactor * 0.5,
- double(nscoord_MAX) / aFactor, double(nscoord_MAX) / aFactor);
+ double(nscoord_MIN) / aFactor, double(nscoord_MIN) / aFactor,
+ double(nscoord_MAX) / aFactor * 2.0, double(nscoord_MAX) / aFactor * 2.0);
image = aMatrix.TransformAndClipBounds(image, maxBounds);
@@ -1879,9 +1884,10 @@ nsRect nsLayoutUtils::MatrixTransformRect(const nsRect& aBounds,
NSAppUnitsToDoublePixels(aBounds.width, aFactor),
NSAppUnitsToDoublePixels(aBounds.height, aFactor));
+ // See comment above about these maxBounds.
RectDouble maxBounds = RectDouble(
- double(nscoord_MIN) / aFactor * 0.5, double(nscoord_MIN) / aFactor * 0.5,
- double(nscoord_MAX) / aFactor, double(nscoord_MAX) / aFactor);
+ double(nscoord_MIN) / aFactor, double(nscoord_MIN) / aFactor,
+ double(nscoord_MAX) / aFactor * 2.0, double(nscoord_MAX) / aFactor * 2.0);
image = aMatrix.TransformAndClipBounds(image, maxBounds);
diff --git a/testing/web-platform/tests/svg/painting/reftests/large-transform-001.html b/testing/web-platform/tests/svg/painting/reftests/large-transform-001.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+
+<head>
+ <meta charset="UTF-8">
+ <title>Large intermediate transforms that are scaled down</title>
+ <link rel="match" href="large-transform-ref.html">
+</head>
+
+<svg width="600" height="500" style="background: gray">
+ <g transform="scale(0.00004)">
+ <g transform="scale(25000)">
+ <rect style="stroke-width: 50px; stroke: blue; fill: cyan;"
+ x="25" y="25" width="500" height="200"></rect>
+ </g>
+ </g>
+</svg>
diff --git a/testing/web-platform/tests/svg/painting/reftests/large-transform-ref.html b/testing/web-platform/tests/svg/painting/reftests/large-transform-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<svg width="600" height="500" style="background: gray">
+ <g>
+ <g>
+ <rect style="stroke-width: 50px; stroke: blue; fill: cyan;"
+ x="25" y="25" width="500" height="200"></rect>
+ </g>
+ </g>
+</svg>