sw_engine: clamp focal point to the edge
Some checks are pending
Android / build_x86_64 (push) Waiting to run
Android / build_aarch64 (push) Waiting to run
iOS / build_x86_64 (push) Waiting to run
iOS / build_arm64 (push) Waiting to run
macOS / build (push) Waiting to run
macOS / compact_test (push) Waiting to run
macOS / unit_test (push) Waiting to run
Ubuntu / build (push) Waiting to run
Ubuntu / compact_test (push) Waiting to run
Ubuntu / unit_test (push) Waiting to run
Windows / build (push) Waiting to run
Windows / compact_test (push) Waiting to run
Windows / unit_test (push) Waiting to run

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.
This commit is contained in:
Mira Grudzinska 2025-06-18 11:44:49 +09:00 committed by Hermet Park
parent b8ef2d44d9
commit d8ebd8b4f5

View file

@ -262,10 +262,11 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix& pT
//This condition fulfills the SVG 1.1 std: //This condition fulfills the SVG 1.1 std:
//the focal point, if outside the end circle, is moved to be on the end circle //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 //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); auto dist = sqrtf(fill->radial.dx * fill->radial.dx + fill->radial.dy * fill->radial.dy);
fill->radial.fx = cx + r * (fx - cx) / dist; constexpr const float precision = 0.99f; //retract focal point slightly from edge to avoid numerical errors
fill->radial.fy = cy + r * (fy - cy) / dist; 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.dx = cx - fill->radial.fx;
fill->radial.dy = cy - fill->radial.fy; fill->radial.dy = cy - fill->radial.fy;
// Prevent loss of precision on Apple Silicon when dr=dy and dx=0 due to FMA // Prevent loss of precision on Apple Silicon when dr=dy and dx=0 due to FMA