From 5d7c27eccbbf7a1888b6e2fddeaf5852c601fb2a Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 18 Jun 2025 11:44:49 +0900 Subject: [PATCH] sw_engine: clamp focal point to the edge If the radial gradient's focal point lies outside the end circle, it's projected onto the edge. A slight inward offset is applied to avoid numerical issues. Note: Focal point support in the sw and wg engines is consistent with the SVG 1.1 standard, whereas the gl engine aligns with the SVG 2.0 standard. --- src/renderer/sw_engine/tvgSwFill.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/renderer/sw_engine/tvgSwFill.cpp b/src/renderer/sw_engine/tvgSwFill.cpp index e012465b..19b80f21 100644 --- a/src/renderer/sw_engine/tvgSwFill.cpp +++ b/src/renderer/sw_engine/tvgSwFill.cpp @@ -277,10 +277,11 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix& tr //This condition fulfills the SVG 1.1 std: //the focal point, if outside the end circle, is moved to be on the end circle //See: the SVG 2 std requirements: https://www.w3.org/TR/SVG2/pservers.html#RadialGradientNotes - if (fill->radial.a < 0) { + if (fill->radial.a <= FLOAT_EPSILON) { auto dist = sqrtf(fill->radial.dx * fill->radial.dx + fill->radial.dy * fill->radial.dy); - fill->radial.fx = cx + r * (fx - cx) / dist; - fill->radial.fy = cy + r * (fy - cy) / dist; + constexpr const float precision = 0.99f; //retract focal point slightly from edge to avoid numerical errors + fill->radial.fx = cx + r * precision * (fx - cx) / dist; + fill->radial.fy = cy + r * precision * (fy - cy) / dist; fill->radial.dx = cx - fill->radial.fx; fill->radial.dy = cy - fill->radial.fy; // Prevent loss of precision on Apple Silicon when dr=dy and dx=0 due to FMA