diff --git a/content/src/gradient.rs b/content/src/gradient.rs index 74e0a5ba..3deb8ba9 100644 --- a/content/src/gradient.rs +++ b/content/src/gradient.rs @@ -15,7 +15,7 @@ use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::vector::Vector2F; use pathfinder_geometry::util as geometry_util; use pathfinder_simd::default::F32x2; -use std::cmp::{Ordering, PartialOrd}; +use std::cmp::Ordering; use std::convert; use std::hash::{Hash, Hasher}; use std::mem; @@ -110,7 +110,7 @@ impl Gradient { #[inline] pub fn add(&mut self, stop: ColorStop) { let index = self.stops.binary_search_by(|other| { - other.offset.partial_cmp(&stop.offset).unwrap() + if other.offset <= stop.offset { Ordering::Less } else { Ordering::Greater } }).unwrap_or_else(convert::identity); self.stops.insert(index, stop); } @@ -138,8 +138,9 @@ impl Gradient { t = geometry_util::clamp(t, 0.0, 1.0); let last_index = self.stops.len() - 1; + let upper_index = self.stops.binary_search_by(|stop| { - stop.offset.partial_cmp(&t).unwrap_or(Ordering::Less) + if stop.offset < t || stop.offset == 0.0 { Ordering::Less } else { Ordering::Greater } }).unwrap_or_else(convert::identity).min(last_index); let lower_index = if upper_index > 0 { upper_index - 1 } else { upper_index }; @@ -205,3 +206,37 @@ impl RadialGradientLine for Vector2F { LineSegment2F::new(self, self) } } + +#[cfg(test)] +mod test { + use crate::gradient::Gradient; + use pathfinder_color::ColorU; + use pathfinder_geometry::vector::Vector2F; + + #[test] + fn stable_order() { + let mut grad = Gradient::linear_from_points(Vector2F::default(), Vector2F::default()); + for i in 0..110 { + grad.add_color_stop(ColorU::new(i, 0, 0, 1), (i % 11) as f32 / 10.0); + } + + // Check that it sorted stably + assert!(grad.stops.windows(2).all(|w| { + w[0].offset < w[1].offset || w[0].color.r < w[1].color.r + })); + } + + #[test] + fn never_sample_zero_width() { + let mut grad = Gradient::linear_from_points(Vector2F::default(), Vector2F::default()); + for i in 0..110 { + let zero_width = (i == 0) || (11 <= i && i < 99) || (i == 109); + grad.add_color_stop(ColorU::new(if zero_width { 255 } else { 0 }, 0, 0, 1), (i % 11) as f32 / 10.0); + } + + for i in 0..11 { + let sample = grad.sample(i as f32 / 10.0); + assert!(sample.r == 0, "{} {}", i, sample.r); + } + } +}