Order and sample gradient correctly
Zero-width gradient sections should be ‘ignored’. The visible endpoints should be precisely the first and last colors added at that point. https://html.spec.whatwg.org/multipage/canvas.html#interpolation
This commit is contained in:
parent
6d8a89b8c5
commit
033a150639
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue