diff --git a/crates/typst-library/src/visualize/gradient.rs b/crates/typst-library/src/visualize/gradient.rs index 45f388ccd..438ab66e9 100644 --- a/crates/typst-library/src/visualize/gradient.rs +++ b/crates/typst-library/src/visualize/gradient.rs @@ -1290,9 +1290,21 @@ fn sample_stops(stops: &[(Color, Ratio)], mixing_space: ColorSpace, t: f64) -> C if low == 0 { low = 1; } + if t == 1.0 { + while stops[low - 1].1 >= stops[low].1 { + low -= 1; + } + } else { + while stops[low - 1].1 >= stops[low].1 { + low += 1; + } + } let (col_0, pos_0) = stops[low - 1]; let (col_1, pos_1) = stops[low]; + debug_assert!(pos_0 < pos_1); + debug_assert!(pos_0.get() <= t); + debug_assert!(t <= pos_1.get()); let t = (t - pos_0.get()) / (pos_1.get() - pos_0.get()); Color::mix_iter( diff --git a/tests/ref/issue-6162-coincident-gradient-stops-export-png.png b/tests/ref/issue-6162-coincident-gradient-stops-export-png.png new file mode 100644 index 000000000..d269342c7 Binary files /dev/null and b/tests/ref/issue-6162-coincident-gradient-stops-export-png.png differ diff --git a/tests/suite/visualize/gradient.typ b/tests/suite/visualize/gradient.typ index 811b8b605..8446ca030 100644 --- a/tests/suite/visualize/gradient.typ +++ b/tests/suite/visualize/gradient.typ @@ -666,3 +666,29 @@ $ A = mat( #let _ = gradient.linear(..my-gradient.stops()) #let my-gradient2 = gradient.linear(red, blue).repeat(5, mirror: true) #let _ = gradient.linear(..my-gradient2.stops()) + +--- issue-6162-coincident-gradient-stops-export-png --- +// Ensure that multiple gradient stops with the same position +// don't cause a panic. +#rect( + fill: gradient.linear( + (red, 0%), + (green, 0%), + (blue, 100%), + ) +) +#rect( + fill: gradient.linear( + (red, 0%), + (green, 100%), + (blue, 100%), + ) +) +#rect( + fill: gradient.linear( + (white, 0%), + (red, 50%), + (green, 50%), + (blue, 100%), + ) +)