Add fix_gradient_stops function.

Render gradients where the last stop is the same position
as the previous one like Chrome and Firefox do.
This commit is contained in:
Pyfisch 2017-05-01 13:22:39 +02:00
parent b230be8aaf
commit f7f077c334

View file

@ -650,7 +650,8 @@ fn convert_gradient_stops(gradient_items: &[GradientItem],
}
// Step 3: Evenly space stops without position.
let mut stops = Vec::with_capacity(stop_items.len());
// Note: Remove the + 1 if fix_gradient_stops is changed.
let mut stops = Vec::with_capacity(stop_items.len() + 1);
let mut stop_run = None;
for (i, stop) in stop_items.iter().enumerate() {
let offset = match stop.position {
@ -696,6 +697,25 @@ fn convert_gradient_stops(gradient_items: &[GradientItem],
stops
}
#[inline]
/// Duplicate the last stop if its position is smaller 100%.
///
/// Explanation by pyfisch:
/// If the last stop is at the same position as the previous stop the
/// last color is ignored by webrender. This differs from the spec
/// (I think so). The implementations of Chrome and Firefox seem
/// to have the same problem but work fine if the position of the last
/// stop is smaller than 100%. (Otherwise they ignore the last stop.)
fn fix_gradient_stops(stops: &mut Vec<GradientStop>) {
if stops.last().unwrap().offset < 1.0 {
let color = stops.last().unwrap().color;
stops.push(GradientStop {
offset: 1.0,
color: color,
})
}
}
/// Returns the the distance to the nearest or farthest corner depending on the comperator.
fn get_distance_to_corner<F>(size: &Size2D<Au>, center: &Point2D<Au>, cmp: F) -> Au
where F: Fn(Au, Au) -> Au
@ -1110,7 +1130,10 @@ impl FragmentDisplayListBuilding for Fragment {
let length = Au::from_f32_px(
(delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0));
let stops = convert_gradient_stops(stops, length, style);
let mut stops = convert_gradient_stops(stops, length, style);
if !repeating {
fix_gradient_stops(&mut stops);
}
let center = Point2D::new(bounds.size.width / 2, bounds.size.height / 2);
@ -1145,7 +1168,12 @@ impl FragmentDisplayListBuilding for Fragment {
=> convert_ellipse_size_keyword(word, &bounds.size, &center),
};
let length = Au::from_f32_px(radius.width.to_f32_px().hypot(radius.height.to_f32_px()));
let stops = convert_gradient_stops(stops, length, style);
let mut stops = convert_gradient_stops(stops, length, style);
if !repeating {
fix_gradient_stops(&mut stops);
}
display_list::RadialGradient {
center: center,
radius: radius,