From f4bad2d9205691626e6e16233348eb2d2aca902f Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Wed, 12 Apr 2017 14:54:28 +0200 Subject: [PATCH 1/9] Partially implement radial gradients. Missing: repeating radial gradients and keyword sizes. --- components/gfx/display_list/mod.rs | 26 +++ components/layout/display_list_builder.rs | 232 ++++++++++++++-------- components/layout/webrender_helpers.rs | 15 ++ components/style/values/computed/image.rs | 4 +- 4 files changed, 194 insertions(+), 83 deletions(-) diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 205b4071589..9425e742da6 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -528,6 +528,7 @@ pub enum DisplayItem { WebGL(Box), Border(Box), Gradient(Box), + RadialGradient(Box), Line(Box), BoxShadow(Box), Iframe(Box), @@ -900,6 +901,29 @@ pub struct GradientDisplayItem { pub gradient: Gradient, } +/// Paints a radial gradient. +#[derive(Clone, Deserialize, HeapSizeOf, Serialize)] +pub struct RadialGradient { + /// The center point of the gradient. + pub center: Point2D, + + /// The radius of the gradient with an x and an y component. + pub radius: Size2D, + + /// A list of color stops. + pub stops: Vec, +} + +#[derive(Clone, Deserialize, HeapSizeOf, Serialize)] +pub struct RadialGradientDisplayItem { + /// Fields common to all display item. + pub base: BaseDisplayItem, + + /// Contains all gradient data. + pub gradient: RadialGradient, +} + + /// A normal border, supporting CSS border styles. #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] pub struct NormalBorder { @@ -1124,6 +1148,7 @@ impl DisplayItem { DisplayItem::WebGL(ref webgl_item) => &webgl_item.base, DisplayItem::Border(ref border) => &border.base, DisplayItem::Gradient(ref gradient) => &gradient.base, + DisplayItem::RadialGradient(ref gradient) => &gradient.base, DisplayItem::Line(ref line) => &line.base, DisplayItem::BoxShadow(ref box_shadow) => &box_shadow.base, DisplayItem::Iframe(ref iframe) => &iframe.base, @@ -1241,6 +1266,7 @@ impl fmt::Debug for DisplayItem { DisplayItem::WebGL(_) => "WebGL".to_owned(), DisplayItem::Border(_) => "Border".to_owned(), DisplayItem::Gradient(_) => "Gradient".to_owned(), + DisplayItem::RadialGradient(_) => "RadialGradient".to_owned(), DisplayItem::Line(_) => "Line".to_owned(), DisplayItem::BoxShadow(_) => "BoxShadow".to_owned(), DisplayItem::Iframe(_) => "Iframe".to_owned(), diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 2e065572615..9eedbbbe7e6 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -25,7 +25,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails}; use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion}; use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection}; -use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageDisplayItem}; +use gfx::display_list::{GradientDisplayItem, RadialGradientDisplayItem, IframeDisplayItem, ImageDisplayItem}; use gfx::display_list::{LineDisplayItem, OpaqueNode}; use gfx::display_list::{SolidColorDisplayItem, ScrollRoot, StackingContext, StackingContextType}; use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo}; @@ -33,7 +33,7 @@ use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId} use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; use list_item::ListItemFlow; -use model::{self, MaybeAuto}; +use model::{self, MaybeAuto, specified}; use msg::constellation_msg::PipelineId; use net_traits::image::base::PixelFormat; use net_traits::image_cache::UsePlaceholder; @@ -58,8 +58,9 @@ use style::properties::longhands::border_image_repeat::computed_value::RepeatKey use style::properties::style_structs; use style::servo::restyle_damage::REPAINT; use style::values::{Either, RGBA, computed}; -use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind}; -use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, NumberOrPercentage}; +use style::values::computed::{AngleOrCorner, Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto}; +use style::values::computed::{LengthOrKeyword, LengthOrPercentageOrKeyword, NumberOrPercentage}; +use style::values::computed::image::{ColorStop, EndingShape, SizeKeyword}; use style::values::specified::{HorizontalDirection, VerticalDirection}; use style_traits::CSSPixel; use style_traits::cursor::Cursor; @@ -391,6 +392,12 @@ pub trait FragmentDisplayListBuilding { style: &ServoComputedValues) -> Option; + fn convert_radial_gradient(&self, + absolute_bounds: &Rect, + gradient: &Gradient, + style: &ServoComputedValues) + -> Option; + /// Adds the display items necessary to paint the background linear gradient of this fragment /// to the appropriate section of the display list. fn build_display_list_for_background_gradient(&self, @@ -588,6 +595,85 @@ fn build_border_radius_for_inner_rect(outer_rect: &Rect, radii } +fn convert_gradient_stops(gradient_stops: &[ColorStop], + length: Au, + style: &ServoComputedValues) -> Vec { + // Determine the position of each stop per CSS-IMAGES § 3.4. + // + // FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops. + let stop_items = gradient.items.iter().filter_map(|item| { + match *item { + GradientItem::ColorStop(ref stop) => Some(stop), + _ => None, + } + }).collect::>(); + let mut stops = Vec::with_capacity(stop_items.len()); + let mut stop_run = None; + for (i, stop) in stop_items.iter().enumerate() { + let offset = match stop.position { + None => { + if stop_run.is_none() { + // Initialize a new stop run. + let start_offset = if i == 0 { + 0.0 + } else { + // `unwrap()` here should never fail because this is the beginning of + // a stop run, which is always bounded by a length or percentage. + position_to_offset(stop_items[i - 1].position.unwrap(), length) + }; + let (end_index, end_offset) = + match stop_items[i..] + .iter() + .enumerate() + .find(|&(_, ref stop)| stop.position.is_some()) { + None => (stop_items.len() - 1, 1.0), + Some((end_index, end_stop)) => { + // `unwrap()` here should never fail because this is the end of + // a stop run, which is always bounded by a length or + // percentage. + (end_index, + position_to_offset(end_stop.position.unwrap(), length)) + } + }; + stop_run = Some(StopRun { + start_offset: start_offset, + end_offset: end_offset, + start_index: i, + stop_count: end_index - i, + }) + } + + let stop_run = stop_run.unwrap(); + let stop_run_length = stop_run.end_offset - stop_run.start_offset; + if stop_run.stop_count == 0 { + stop_run.end_offset + } else { + stop_run.start_offset + + stop_run_length * (i - stop_run.start_index) as f32 / + (stop_run.stop_count as f32) + } + } + Some(position) => { + stop_run = None; + position_to_offset(position, length) + } + }; + stops.push(GradientStop { + offset: offset, + color: style.resolve_color(stop.color).to_gfx_color() + }) + } + stops +} + +fn convert_size_keyword(_keyword: SizeKeyword, + _circle: bool, + _size: &Size2D, + _center: &Point2D) -> Size2D { + println!("TODO Implement size-keyword for radial gradients."); + return Size2D::zero(); +} + impl FragmentDisplayListBuilding for Fragment { fn build_display_list_for_background_if_applicable(&self, state: &mut DisplayListBuildState, @@ -653,15 +739,12 @@ impl FragmentDisplayListBuilding for Fragment { match background_image.0 { None => {} Some(computed::Image::Gradient(ref gradient)) => { - // FIXME: Radial gradients aren't implemented yet. - if let GradientKind::Linear(_) = gradient.gradient_kind { - self.build_display_list_for_background_gradient(state, - display_list_section, - &bounds, - &clip, - gradient, - style); - } + self.build_display_list_for_background_gradient(state, + display_list_section, + &bounds, + &clip, + gradient, + style); } Some(computed::Image::Url(ref image_url)) => { if let Some(url) = image_url.url() { @@ -923,7 +1006,6 @@ impl FragmentDisplayListBuilding for Fragment { } } } else { - // FIXME: Radial gradients aren't implemented yet. return None; }; @@ -945,71 +1027,9 @@ 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)); - // Determine the position of each stop per CSS-IMAGES § 3.4. - // - // FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops. - let stop_items = gradient.items.iter().filter_map(|item| { - match *item { - GradientItem::ColorStop(ref stop) => Some(stop), - _ => None, - } - }).collect::>(); - let mut stops = Vec::with_capacity(stop_items.len()); - let mut stop_run = None; - for (i, stop) in stop_items.iter().enumerate() { - let offset = match stop.position { - None => { - if stop_run.is_none() { - // Initialize a new stop run. - let start_offset = if i == 0 { - 0.0 - } else { - // `unwrap()` here should never fail because this is the beginning of - // a stop run, which is always bounded by a length or percentage. - position_to_offset(stop_items[i - 1].position.unwrap(), length) - }; - let (end_index, end_offset) = - match stop_items[i..] - .iter() - .enumerate() - .find(|&(_, ref stop)| stop.position.is_some()) { - None => (stop_items.len() - 1, 1.0), - Some((end_index, end_stop)) => { - // `unwrap()` here should never fail because this is the end of - // a stop run, which is always bounded by a length or - // percentage. - (end_index, - position_to_offset(end_stop.position.unwrap(), length)) - } - }; - stop_run = Some(StopRun { - start_offset: start_offset, - end_offset: end_offset, - start_index: i, - stop_count: end_index - i, - }) - } - - let stop_run = stop_run.unwrap(); - let stop_run_length = stop_run.end_offset - stop_run.start_offset; - if stop_run.stop_count == 0 { - stop_run.end_offset - } else { - stop_run.start_offset + - stop_run_length * (i - stop_run.start_index) as f32 / - (stop_run.stop_count as f32) - } - } - Some(position) => { - stop_run = None; - position_to_offset(position, length) - } - }; - stops.push(GradientStop { - offset: offset, - color: style.resolve_color(stop.color).to_gfx_color() - }) - } + let stops = convert_gradient_stops(&gradient.stops[..], + length, + style); let center = Point2D::new(absolute_bounds.size.width / 2, absolute_bounds.size.height / 2); @@ -1021,6 +1041,43 @@ impl FragmentDisplayListBuilding for Fragment { }) } + fn convert_radial_gradient(&self, + absolute_bounds: &Rect, + gradient: &Gradient, + style: &ServoComputedValues) -> Option { + // FIXME: Repeating gradients aren't implemented yet. + if gradient.repeating { + return None; + } + if let GradientKind::Radial(ref shape, ref center) = gradient.gradient_kind { + let center = Point2D::new(specified(center.horizontal, absolute_bounds.size.width), + specified(center.vertical, absolute_bounds.size.height)); + let radius = match *shape { + EndingShape::Circle(LengthOrKeyword::Length(length)) + => Size2D::new(length, length), + EndingShape::Circle(LengthOrKeyword::Keyword(word)) + => convert_size_keyword(word, true, &absolute_bounds.size, ¢er), + EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal, + vertical)) + => Size2D::new(specified(horizontal, absolute_bounds.size.width), + specified(vertical, absolute_bounds.size.height)), + EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word)) + => convert_size_keyword(word, false, &absolute_bounds.size, ¢er), + }; + let length = Au::from_f32_px(radius.width.to_f32_px().hypot(radius.height.to_f32_px())); + let stops = convert_gradient_stops(&gradient.stops[..], + length, + style); + Some(display_list::RadialGradient { + center: absolute_bounds.origin + center, + radius: radius, + stops: stops, + }) + } else { + None + } + } + fn build_display_list_for_background_gradient(&self, state: &mut DisplayListBuildState, display_list_section: DisplayListSection, @@ -1031,9 +1088,7 @@ impl FragmentDisplayListBuilding for Fragment { let mut clip = clip.clone(); clip.intersect_rect(absolute_bounds); - let grad = self.convert_gradient(absolute_bounds, gradient, style); - - if let Some(x) = grad { + if let Some(x) = self.convert_gradient(absolute_bounds, gradient, style) { let base = state.create_base_display_item(absolute_bounds, &clip, self.node, @@ -1045,6 +1100,19 @@ impl FragmentDisplayListBuilding for Fragment { gradient: x, }); + state.add_display_item(gradient_display_item); + } else if let Some(x) = self.convert_radial_gradient(absolute_bounds, gradient, style) { + let base = state.create_base_display_item(absolute_bounds, + &clip, + self.node, + style.get_cursor(Cursor::Default), + display_list_section); + + let gradient_display_item = DisplayItem::RadialGradient(box RadialGradientDisplayItem { + base: base, + gradient: x, + }); + state.add_display_item(gradient_display_item); } } diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 723e3328702..5d77bc1b565 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -380,6 +380,21 @@ impl WebRenderDisplayItemConverter for DisplayItem { rect.size, webrender_traits::LayoutSize::zero()); } + DisplayItem::RadialGradient(ref item) => { + let rect = item.base.bounds.to_rectf(); + let center = item.gradient.center.to_pointf(); + let radius = item.gradient.radius.to_sizef(); + let clip = item.base.clip.to_clip_region(builder); + let gradient = builder.create_radial_gradient(center, + radius, + item.gradient.stops.clone(), + ExtendMode::Clamp); + builder.push_radial_gradient(rect, + clip, + gradient, + rect.size, + webrender_traits::LayoutSize::zero()); + } DisplayItem::Line(..) => { println!("TODO DisplayItem::Line"); } diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index 4ccce1e1f8f..54aaaaa7820 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -14,10 +14,12 @@ use std::fmt; use style_traits::ToCss; use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; use values::computed::position::Position; -use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection}; +use values::specified::{self, HorizontalDirection, VerticalDirection}; use values::specified::image::CompatMode; use values::specified::url::SpecifiedUrl; +pub use values::specified::SizeKeyword; + impl ToComputedValue for specified::Image { type ComputedValue = Image; From 02159477337dec12fbf160cd446262a91f1130fd Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Wed, 12 Apr 2017 17:37:56 +0200 Subject: [PATCH 2/9] Implement radial gradient size keywords. --- components/layout/display_list_builder.rs | 81 +++++++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 9eedbbbe7e6..60586fecc37 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -666,12 +666,81 @@ fn convert_gradient_stops(gradient_stops: &[ColorStop], stops } -fn convert_size_keyword(_keyword: SizeKeyword, - _circle: bool, - _size: &Size2D, - _center: &Point2D) -> Size2D { - println!("TODO Implement size-keyword for radial gradients."); - return Size2D::zero(); +/// Returns the the distance to the nearest or farthest corner depending on the comperator. +fn get_distance_to_corner(size: &Size2D, center: &Point2D, cmp: F) -> Au + where F: Fn(f32, f32) -> f32 { + let top_left = center.x.to_f32_px().hypot(center.y.to_f32_px()); + let top_right = (size.width.to_f32_px() - center.x.to_f32_px()).hypot(center.y.to_f32_px()); + let bottom_right = (size.width.to_f32_px() - center.x.to_f32_px()) + .hypot(size.height.to_f32_px() - center.y.to_f32_px()); + let bottom_left = center.x.to_f32_px().hypot(size.height.to_f32_px() - center.y.to_f32_px()); + Au::from_f32_px(cmp(cmp(top_left, top_right), cmp(bottom_right, bottom_left))) +} + +/// Returns the distance to the nearest or farthest sides depending on the comparator. +/// +/// The first return value is horizontal distance the second vertical distance. +fn get_distance_to_sides(size: &Size2D, center: &Point2D, cmp: F) -> (Au, Au) + where F: Fn(Au, Au) -> Au { + let top_side = center.y; + let right_side = size.width - center.x; + let bottom_side = size.height - center.y; + let left_side = center.x; + (cmp(left_side, right_side), cmp(top_side, bottom_side)) +} + +/// Returns the radius for an ellipse with the same ratio as if it was matched to the sides. +fn get_scaled_radius(radius: Au, size: &Size2D, center: &Point2D, cmp: F) -> Size2D + where F: Fn(Au, Au) -> Au { + let (horizontal, vertical) = get_distance_to_sides(size, center, cmp); + let factor = horizontal.to_f32_px() / vertical.to_f32_px(); + Size2D::new(radius.scale_by(factor), radius.scale_by(factor.recip())) +} + +/// Determines the radius of a radial gradient if it was not explicitly provided. +/// +/// https://drafts.csswg.org/css-images-3/#typedef-size +fn convert_size_keyword(keyword: SizeKeyword, + circle: bool, + size: &Size2D, + center: &Point2D) -> Size2D { + use style::values::computed::image::SizeKeyword::*; + match keyword { + ClosestSide => { + let (horizontal, vertical) = get_distance_to_sides(size, center, ::std::cmp::min); + if circle { + let radius = ::std::cmp::min(vertical, horizontal); + Size2D::new(radius, radius) + } else { + Size2D::new(horizontal, vertical) + } + }, + FarthestSide => { + let (horizontal, vertical) = get_distance_to_sides(size, center, ::std::cmp::max); + if circle { + let radius = ::std::cmp::max(vertical, horizontal); + Size2D::new(radius, radius) + } else { + Size2D::new(horizontal, vertical) + } + }, + ClosestCorner => { + let radius = get_distance_to_corner(size, center, f32::min); + if circle { + Size2D::new(radius, radius) + } else { + get_scaled_radius(radius, size, center, ::std::cmp::min) + } + } + FarthestCorner => { + let radius = get_distance_to_corner(size, center, f32::max); + if circle { + Size2D::new(radius, radius) + } else { + get_scaled_radius(radius, size, center, ::std::cmp::max) + } + } + } } impl FragmentDisplayListBuilding for Fragment { From 6768614fdd9226314a2c208af4bbf2a38a0497be Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Thu, 13 Apr 2017 11:40:05 +0200 Subject: [PATCH 3/9] Use content_box instead of absoulte bounds in radial_gradient. --- components/layout/display_list_builder.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 60586fecc37..042704a70fa 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -393,7 +393,6 @@ pub trait FragmentDisplayListBuilding { -> Option; fn convert_radial_gradient(&self, - absolute_bounds: &Rect, gradient: &Gradient, style: &ServoComputedValues) -> Option; @@ -1111,34 +1110,38 @@ impl FragmentDisplayListBuilding for Fragment { } fn convert_radial_gradient(&self, - absolute_bounds: &Rect, gradient: &Gradient, style: &ServoComputedValues) -> Option { // FIXME: Repeating gradients aren't implemented yet. if gradient.repeating { return None; } + // FIXME(pcwalton, #2795): Get the real container size. + let container_size = Size2D::zero(); + let content_box = self.content_box().to_physical(style.writing_mode, container_size); + let origin = content_box.origin; + let size = content_box.size; if let GradientKind::Radial(ref shape, ref center) = gradient.gradient_kind { - let center = Point2D::new(specified(center.horizontal, absolute_bounds.size.width), - specified(center.vertical, absolute_bounds.size.height)); + let center = Point2D::new(specified(center.horizontal, size.width), + specified(center.vertical, size.height)); let radius = match *shape { EndingShape::Circle(LengthOrKeyword::Length(length)) => Size2D::new(length, length), EndingShape::Circle(LengthOrKeyword::Keyword(word)) - => convert_size_keyword(word, true, &absolute_bounds.size, ¢er), + => convert_size_keyword(word, true, &size, ¢er), EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal, vertical)) - => Size2D::new(specified(horizontal, absolute_bounds.size.width), - specified(vertical, absolute_bounds.size.height)), + => Size2D::new(specified(horizontal, size.width), + specified(vertical, size.height)), EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word)) - => convert_size_keyword(word, false, &absolute_bounds.size, ¢er), + => convert_size_keyword(word, false, &size, ¢er), }; let length = Au::from_f32_px(radius.width.to_f32_px().hypot(radius.height.to_f32_px())); let stops = convert_gradient_stops(&gradient.stops[..], length, style); Some(display_list::RadialGradient { - center: absolute_bounds.origin + center, + center: origin + center, radius: radius, stops: stops, }) @@ -1170,7 +1173,7 @@ impl FragmentDisplayListBuilding for Fragment { }); state.add_display_item(gradient_display_item); - } else if let Some(x) = self.convert_radial_gradient(absolute_bounds, gradient, style) { + } else if let Some(x) = self.convert_radial_gradient(gradient, style) { let base = state.create_base_display_item(absolute_bounds, &clip, self.node, From 803bc0395c2a4f07a0043ddfef1bdad32eb250a6 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Mon, 17 Apr 2017 10:50:14 +0200 Subject: [PATCH 4/9] Fix gradient math and positioning. Formatting. Start adding repeating gradients. --- components/gfx/display_list/mod.rs | 7 +- components/layout/display_list_builder.rs | 346 +++++++++++----------- components/style/values/computed/image.rs | 1 - 3 files changed, 175 insertions(+), 179 deletions(-) diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 9425e742da6..77a64553c29 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -890,6 +890,9 @@ pub struct Gradient { /// A list of color stops. pub stops: Vec, + + /// True if gradient repeats infinitly. + pub repeating: bool, } #[derive(Clone, Deserialize, HeapSizeOf, Serialize)] @@ -912,6 +915,9 @@ pub struct RadialGradient { /// A list of color stops. pub stops: Vec, + + /// True if gradient repeats infinitly. + pub repeating: bool, } #[derive(Clone, Deserialize, HeapSizeOf, Serialize)] @@ -923,7 +929,6 @@ pub struct RadialGradientDisplayItem { pub gradient: RadialGradient, } - /// A normal border, supporting CSS border styles. #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] pub struct NormalBorder { diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 042704a70fa..569cb86e9eb 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -59,7 +59,7 @@ use style::properties::style_structs; use style::servo::restyle_damage::REPAINT; use style::values::{Either, RGBA, computed}; use style::values::computed::{AngleOrCorner, Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto}; -use style::values::computed::{LengthOrKeyword, LengthOrPercentageOrKeyword, NumberOrPercentage}; +use style::values::computed::{LengthOrKeyword, LengthOrPercentageOrKeyword, NumberOrPercentage, Position}; use style::values::computed::image::{ColorStop, EndingShape, SizeKeyword}; use style::values::specified::{HorizontalDirection, VerticalDirection}; use style_traits::CSSPixel; @@ -386,16 +386,22 @@ pub trait FragmentDisplayListBuilding { image_url: &ServoUrl, background_index: usize); - fn convert_gradient(&self, - absolute_bounds: &Rect, - gradient: &Gradient, - style: &ServoComputedValues) - -> Option; + fn convert_linear_gradient(&self, + bounds: &Rect, + stops: &[ColorStop], + angle_or_corner: &AngleOrCorner, + repeating: bool, + style: &ServoComputedValues) + -> display_list::Gradient; fn convert_radial_gradient(&self, - gradient: &Gradient, - style: &ServoComputedValues) - -> Option; + bounds: &Rect, + stops: &[ColorStop], + shape: &EndingShape, + center: &Position, + repeating: bool, + style: &ServoComputedValues) + -> display_list::RadialGradient; /// Adds the display items necessary to paint the background linear gradient of this fragment /// to the appropriate section of the display list. @@ -667,78 +673,66 @@ fn convert_gradient_stops(gradient_stops: &[ColorStop], /// Returns the the distance to the nearest or farthest corner depending on the comperator. fn get_distance_to_corner(size: &Size2D, center: &Point2D, cmp: F) -> Au - where F: Fn(f32, f32) -> f32 { - let top_left = center.x.to_f32_px().hypot(center.y.to_f32_px()); - let top_right = (size.width.to_f32_px() - center.x.to_f32_px()).hypot(center.y.to_f32_px()); - let bottom_right = (size.width.to_f32_px() - center.x.to_f32_px()) - .hypot(size.height.to_f32_px() - center.y.to_f32_px()); - let bottom_left = center.x.to_f32_px().hypot(size.height.to_f32_px() - center.y.to_f32_px()); - Au::from_f32_px(cmp(cmp(top_left, top_right), cmp(bottom_right, bottom_left))) + where F: Fn(Au, Au) -> Au +{ + let dist = get_distance_to_sides(size, center, cmp); + Au::from_f32_px(dist.width.to_f32_px().hypot(dist.height.to_f32_px())) } /// Returns the distance to the nearest or farthest sides depending on the comparator. /// /// The first return value is horizontal distance the second vertical distance. -fn get_distance_to_sides(size: &Size2D, center: &Point2D, cmp: F) -> (Au, Au) - where F: Fn(Au, Au) -> Au { +fn get_distance_to_sides(size: &Size2D, center: &Point2D, cmp: F) -> Size2D + where F: Fn(Au, Au) -> Au +{ let top_side = center.y; let right_side = size.width - center.x; let bottom_side = size.height - center.y; let left_side = center.x; - (cmp(left_side, right_side), cmp(top_side, bottom_side)) + Size2D::new(cmp(left_side, right_side), cmp(top_side, bottom_side)) } /// Returns the radius for an ellipse with the same ratio as if it was matched to the sides. -fn get_scaled_radius(radius: Au, size: &Size2D, center: &Point2D, cmp: F) -> Size2D - where F: Fn(Au, Au) -> Au { - let (horizontal, vertical) = get_distance_to_sides(size, center, cmp); - let factor = horizontal.to_f32_px() / vertical.to_f32_px(); - Size2D::new(radius.scale_by(factor), radius.scale_by(factor.recip())) +fn get_ellipse_radius(size: &Size2D, center: &Point2D, cmp: F) -> Size2D + where F: Fn(Au, Au) -> Au +{ + let dist = get_distance_to_sides(size, center, cmp); + Size2D::new(dist.width.scale_by(::std::f32::consts::FRAC_1_SQRT_2 * 2.0), + dist.height.scale_by(::std::f32::consts::FRAC_1_SQRT_2 * 2.0)) } -/// Determines the radius of a radial gradient if it was not explicitly provided. -/// +/// Determines the radius of a circle if it was not explictly provided. /// https://drafts.csswg.org/css-images-3/#typedef-size -fn convert_size_keyword(keyword: SizeKeyword, - circle: bool, - size: &Size2D, - center: &Point2D) -> Size2D { +fn convert_circle_size_keyword(keyword: SizeKeyword, + size: &Size2D, + center: &Point2D) -> Size2D { + use style::values::computed::image::SizeKeyword::*; + let radius = match keyword { + ClosestSide => { + let dist = get_distance_to_sides(size, center, ::std::cmp::min); + ::std::cmp::min(dist.width, dist.height) + } + FarthestSide => { + let dist = get_distance_to_sides(size, center, ::std::cmp::max); + ::std::cmp::max(dist.width, dist.height) + } + ClosestCorner => get_distance_to_corner(size, center, ::std::cmp::min), + FarthestCorner => get_distance_to_corner(size, center, ::std::cmp::max), + }; + Size2D::new(radius, radius) +} + +/// Determines the radius of an ellipse if it was not explictly provided. +/// https://drafts.csswg.org/css-images-3/#typedef-size +fn convert_ellipse_size_keyword(keyword: SizeKeyword, + size: &Size2D, + center: &Point2D) -> Size2D { use style::values::computed::image::SizeKeyword::*; match keyword { - ClosestSide => { - let (horizontal, vertical) = get_distance_to_sides(size, center, ::std::cmp::min); - if circle { - let radius = ::std::cmp::min(vertical, horizontal); - Size2D::new(radius, radius) - } else { - Size2D::new(horizontal, vertical) - } - }, - FarthestSide => { - let (horizontal, vertical) = get_distance_to_sides(size, center, ::std::cmp::max); - if circle { - let radius = ::std::cmp::max(vertical, horizontal); - Size2D::new(radius, radius) - } else { - Size2D::new(horizontal, vertical) - } - }, - ClosestCorner => { - let radius = get_distance_to_corner(size, center, f32::min); - if circle { - Size2D::new(radius, radius) - } else { - get_scaled_radius(radius, size, center, ::std::cmp::min) - } - } - FarthestCorner => { - let radius = get_distance_to_corner(size, center, f32::max); - if circle { - Size2D::new(radius, radius) - } else { - get_scaled_radius(radius, size, center, ::std::cmp::max) - } - } + ClosestSide => get_distance_to_sides(size, center, ::std::cmp::min), + FarthestSide => get_distance_to_sides(size, center, ::std::cmp::max), + ClosestCorner => get_ellipse_radius(size, center, ::std::cmp::min), + FarthestCorner => get_ellipse_radius(size, center, ::std::cmp::max), } } @@ -1044,45 +1038,40 @@ impl FragmentDisplayListBuilding for Fragment { } } - fn convert_gradient(&self, - absolute_bounds: &Rect, - gradient: &Gradient, - style: &ServoComputedValues) -> Option { - // FIXME: Repeating gradients aren't implemented yet. - if gradient.repeating { - return None; - } - let angle = if let GradientKind::Linear(angle_or_corner) = gradient.gradient_kind { - match angle_or_corner { - AngleOrCorner::Angle(angle) => angle.radians(), - AngleOrCorner::Corner(horizontal, vertical) => { - // This the angle for one of the diagonals of the box. Our angle - // will either be this one, this one + PI, or one of the other - // two perpendicular angles. - let atan = (absolute_bounds.size.height.to_f32_px() / - absolute_bounds.size.width.to_f32_px()).atan(); - match (horizontal, vertical) { - (HorizontalDirection::Right, VerticalDirection::Bottom) - => f32::consts::PI - atan, - (HorizontalDirection::Left, VerticalDirection::Bottom) - => f32::consts::PI + atan, - (HorizontalDirection::Right, VerticalDirection::Top) - => atan, - (HorizontalDirection::Left, VerticalDirection::Top) - => -atan, - } + fn convert_linear_gradient(&self, + bounds: &Rect, + stops: &[ColorStop], + angle_or_corner: &AngleOrCorner, + repeating: bool, + style: &ServoComputedValues) + -> display_list::Gradient { + let angle = match *angle_or_corner { + AngleOrCorner::Angle(angle) => angle.radians(), + AngleOrCorner::Corner(horizontal, vertical) => { + // This the angle for one of the diagonals of the box. Our angle + // will either be this one, this one + PI, or one of the other + // two perpendicular angles. + let atan = (bounds.size.height.to_f32_px() / + bounds.size.width.to_f32_px()).atan(); + match (horizontal, vertical) { + (HorizontalDirection::Right, VerticalDirection::Bottom) + => f32::consts::PI - atan, + (HorizontalDirection::Left, VerticalDirection::Bottom) + => f32::consts::PI + atan, + (HorizontalDirection::Right, VerticalDirection::Top) + => atan, + (HorizontalDirection::Left, VerticalDirection::Top) + => -atan, } } - } else { - return None; }; // Get correct gradient line length, based on: // https://drafts.csswg.org/css-images-3/#linear-gradients let dir = Point2D::new(angle.sin(), -angle.cos()); - let line_length = (dir.x * absolute_bounds.size.width.to_f32_px()).abs() + - (dir.y * absolute_bounds.size.height.to_f32_px()).abs(); + let line_length = (dir.x * bounds.size.width.to_f32_px()).abs() + + (dir.y * bounds.size.height.to_f32_px()).abs(); let inv_dir_length = 1.0 / (dir.x * dir.x + dir.y * dir.y).sqrt(); @@ -1095,58 +1084,47 @@ 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(&gradient.stops[..], - length, - style); + let stops = convert_gradient_stops(stops, length, style); - let center = Point2D::new(absolute_bounds.size.width / 2, - absolute_bounds.size.height / 2); + let center = Point2D::new(bounds.size.width / 2, bounds.size.height / 2); - Some(display_list::Gradient { + display_list::Gradient { start_point: center - delta, end_point: center + delta, stops: stops, - }) + repeating: repeating, + } } fn convert_radial_gradient(&self, - gradient: &Gradient, - style: &ServoComputedValues) -> Option { - // FIXME: Repeating gradients aren't implemented yet. - if gradient.repeating { - return None; - } - // FIXME(pcwalton, #2795): Get the real container size. - let container_size = Size2D::zero(); - let content_box = self.content_box().to_physical(style.writing_mode, container_size); - let origin = content_box.origin; - let size = content_box.size; - if let GradientKind::Radial(ref shape, ref center) = gradient.gradient_kind { - let center = Point2D::new(specified(center.horizontal, size.width), - specified(center.vertical, size.height)); - let radius = match *shape { - EndingShape::Circle(LengthOrKeyword::Length(length)) - => Size2D::new(length, length), - EndingShape::Circle(LengthOrKeyword::Keyword(word)) - => convert_size_keyword(word, true, &size, ¢er), - EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal, - vertical)) - => Size2D::new(specified(horizontal, size.width), - specified(vertical, size.height)), - EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word)) - => convert_size_keyword(word, false, &size, ¢er), - }; - let length = Au::from_f32_px(radius.width.to_f32_px().hypot(radius.height.to_f32_px())); - let stops = convert_gradient_stops(&gradient.stops[..], - length, - style); - Some(display_list::RadialGradient { - center: origin + center, - radius: radius, - stops: stops, - }) - } else { - None + bounds: &Rect, + stops: &[ColorStop], + shape: &EndingShape, + center: &Position, + repeating: bool, + style: &ServoComputedValues) + -> display_list::RadialGradient { + let center = Point2D::new(specified(center.horizontal, bounds.size.width), + specified(center.vertical, bounds.size.height)); + let radius = match *shape { + EndingShape::Circle(LengthOrKeyword::Length(length)) + => Size2D::new(length, length), + EndingShape::Circle(LengthOrKeyword::Keyword(word)) + => convert_circle_size_keyword(word, &bounds.size, ¢er), + EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal, + vertical)) + => Size2D::new(specified(horizontal, bounds.size.width), + specified(vertical, bounds.size.height)), + EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word)) + => convert_ellipse_size_keyword(word, &bounds.size, ¢er), + }; + 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); + display_list::RadialGradient { + center: center, + radius: radius, + stops: stops, + repeating: repeating, } } @@ -1160,33 +1138,45 @@ impl FragmentDisplayListBuilding for Fragment { let mut clip = clip.clone(); clip.intersect_rect(absolute_bounds); - if let Some(x) = self.convert_gradient(absolute_bounds, gradient, style) { - let base = state.create_base_display_item(absolute_bounds, - &clip, - self.node, - style.get_cursor(Cursor::Default), - display_list_section); + let border = style.logical_border_width().to_physical(style.writing_mode); + let mut bounds = *absolute_bounds; + bounds.origin.x += border.left; + bounds.origin.y += border.top; + bounds.size.width -= border.horizontal(); + bounds.size.height -= border.vertical(); - let gradient_display_item = DisplayItem::Gradient(box GradientDisplayItem { - base: base, - gradient: x, - }); + let base = state.create_base_display_item(&bounds, + &clip, + self.node, + style.get_cursor(Cursor::Default), + display_list_section); - state.add_display_item(gradient_display_item); - } else if let Some(x) = self.convert_radial_gradient(gradient, style) { - let base = state.create_base_display_item(absolute_bounds, - &clip, - self.node, - style.get_cursor(Cursor::Default), - display_list_section); - - let gradient_display_item = DisplayItem::RadialGradient(box RadialGradientDisplayItem { - base: base, - gradient: x, - }); - - state.add_display_item(gradient_display_item); - } + let display_item = match gradient.gradient_kind { + GradientKind::Linear(ref angle_or_corner) => { + let gradient = self.convert_linear_gradient(&bounds, + &gradient.stops[..], + angle_or_corner, + gradient.repeating, + style); + DisplayItem::Gradient(box GradientDisplayItem { + base: base, + gradient: gradient, + }) + } + GradientKind::Radial(ref shape, ref center) => { + let gradient = self.convert_radial_gradient(&bounds, + &gradient.stops[..], + shape, + center, + gradient.repeating, + style); + DisplayItem::RadialGradient(box RadialGradientDisplayItem { + base: base, + gradient: gradient, + }) + } + }; + state.add_display_item(display_item); } fn build_display_list_for_box_shadow_if_applicable(&self, @@ -1299,21 +1289,23 @@ impl FragmentDisplayListBuilding for Fragment { } Some(computed::Image::Gradient(ref gradient)) => { match gradient.gradient_kind { - GradientKind::Linear(_) => { - let grad = self.convert_gradient(&bounds, gradient, style); + GradientKind::Linear(angle_or_corner) => { + let grad = self.convert_linear_gradient(&bounds, + &gradient.stops[..], + &angle_or_corner, + gradient.repeating, + style); - if let Some(x) = grad { - state.add_display_item(DisplayItem::Border(box BorderDisplayItem { - base: base, - border_widths: border.to_physical(style.writing_mode), - details: BorderDetails::Gradient(display_list::GradientBorder { - gradient: x, + state.add_display_item(DisplayItem::Border(box BorderDisplayItem { + base: base, + border_widths: border.to_physical(style.writing_mode), + details: BorderDetails::Gradient(display_list::GradientBorder { + gradient: grad, - // TODO(gw): Support border-image-outset - outset: SideOffsets2D::zero(), - }), - })); - } + // TODO(gw): Support border-image-outset + outset: SideOffsets2D::zero(), + }), + })); } GradientKind::Radial(_, _) => { // TODO(gw): Handle border-image with radial gradient. diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index 54aaaaa7820..607cc8f2025 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -20,7 +20,6 @@ use values::specified::url::SpecifiedUrl; pub use values::specified::SizeKeyword; - impl ToComputedValue for specified::Image { type ComputedValue = Image; From 1c4ae53a8866c2e8a1ac600469bc53eb9bd1889c Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Mon, 17 Apr 2017 11:08:37 +0200 Subject: [PATCH 5/9] Pass repeating gradients to webrender. --- components/layout/webrender_helpers.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 5d77bc1b565..70479d43837 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -370,10 +370,15 @@ impl WebRenderDisplayItemConverter for DisplayItem { let start_point = item.gradient.start_point.to_pointf(); let end_point = item.gradient.end_point.to_pointf(); let clip = item.base.clip.to_clip_region(builder); + let extend_mode = if item.gradient.repeating { + ExtendMode::Repeat + } else { + ExtendMode::Clamp + }; let gradient = builder.create_gradient(start_point, end_point, item.gradient.stops.clone(), - ExtendMode::Clamp); + extend_mode); builder.push_gradient(rect, clip, gradient, @@ -385,10 +390,15 @@ impl WebRenderDisplayItemConverter for DisplayItem { let center = item.gradient.center.to_pointf(); let radius = item.gradient.radius.to_sizef(); let clip = item.base.clip.to_clip_region(builder); + let extend_mode = if item.gradient.repeating { + ExtendMode::Repeat + } else { + ExtendMode::Clamp + }; let gradient = builder.create_radial_gradient(center, radius, item.gradient.stops.clone(), - ExtendMode::Clamp); + extend_mode); builder.push_radial_gradient(rect, clip, gradient, From c9461985c17ba4860b2e48953f722580d1ae82be Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Mon, 17 Apr 2017 14:09:05 +0200 Subject: [PATCH 6/9] Fix gradient position if background-clip is present. --- components/layout/display_list_builder.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 569cb86e9eb..941a1387092 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -409,6 +409,7 @@ pub trait FragmentDisplayListBuilding { state: &mut DisplayListBuildState, display_list_section: DisplayListSection, absolute_bounds: &Rect, + clip_bounds: &Rect, clip: &ClippingRegion, gradient: &Gradient, style: &ServoComputedValues); @@ -803,6 +804,7 @@ impl FragmentDisplayListBuilding for Fragment { Some(computed::Image::Gradient(ref gradient)) => { self.build_display_list_for_background_gradient(state, display_list_section, + &absolute_bounds, &bounds, &clip, gradient, @@ -1132,18 +1134,19 @@ impl FragmentDisplayListBuilding for Fragment { state: &mut DisplayListBuildState, display_list_section: DisplayListSection, absolute_bounds: &Rect, + clip_bounds: &Rect, clip: &ClippingRegion, gradient: &Gradient, style: &ServoComputedValues) { let mut clip = clip.clone(); - clip.intersect_rect(absolute_bounds); + clip.intersect_rect(clip_bounds); - let border = style.logical_border_width().to_physical(style.writing_mode); + let border_padding = self.border_padding.to_physical(style.writing_mode); let mut bounds = *absolute_bounds; - bounds.origin.x += border.left; - bounds.origin.y += border.top; - bounds.size.width -= border.horizontal(); - bounds.size.height -= border.vertical(); + bounds.origin.x = bounds.origin.x + border_padding.left; + bounds.origin.y = bounds.origin.y + border_padding.top; + bounds.size.width = bounds.size.width - border_padding.horizontal(); + bounds.size.height = bounds.size.height - border_padding.vertical(); let base = state.create_base_display_item(&bounds, &clip, From 0708d62f165e35a12fe70406b2a137fc7bde5d1d Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Mon, 17 Apr 2017 16:23:57 +0200 Subject: [PATCH 7/9] Set /css-flexbox-1_dev/html/align-content-004.htm.ini to PASS --- .../css-flexbox-1_dev/html/align-content-004.htm.ini | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 tests/wpt/metadata-css/css-flexbox-1_dev/html/align-content-004.htm.ini diff --git a/tests/wpt/metadata-css/css-flexbox-1_dev/html/align-content-004.htm.ini b/tests/wpt/metadata-css/css-flexbox-1_dev/html/align-content-004.htm.ini deleted file mode 100644 index 8a4f207f977..00000000000 --- a/tests/wpt/metadata-css/css-flexbox-1_dev/html/align-content-004.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[align-content-004.htm] - type: reftest - expected: FAIL From ce3e1406ca8976e079dedd0cb54468eb0d4b9368 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sat, 22 Apr 2017 22:06:16 +0200 Subject: [PATCH 8/9] Handle unimplemented size keywords for radial gradients. --- components/layout/display_list_builder.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 941a1387092..912155ee0d4 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -719,6 +719,10 @@ fn convert_circle_size_keyword(keyword: SizeKeyword, } ClosestCorner => get_distance_to_corner(size, center, ::std::cmp::min), FarthestCorner => get_distance_to_corner(size, center, ::std::cmp::max), + _ => { + println!("TODO: implement size keyword {:?} for circles", keyword); + Au::new(0) + } }; Size2D::new(radius, radius) } @@ -734,6 +738,10 @@ fn convert_ellipse_size_keyword(keyword: SizeKeyword, FarthestSide => get_distance_to_sides(size, center, ::std::cmp::max), ClosestCorner => get_ellipse_radius(size, center, ::std::cmp::min), FarthestCorner => get_ellipse_radius(size, center, ::std::cmp::max), + _ => { + println!("TODO: implement size keyword {:?} for ellipses", keyword); + Size2D::new(Au::new(0), Au::new(0)) + } } } From d48c1222ca46ab437fd8934f8d1bdf49367647ca Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sat, 29 Apr 2017 14:38:33 +0200 Subject: [PATCH 9/9] Changes needed for rebase. --- components/layout/display_list_builder.rs | 33 ++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 912155ee0d4..a2453067e1f 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -58,9 +58,10 @@ use style::properties::longhands::border_image_repeat::computed_value::RepeatKey use style::properties::style_structs; use style::servo::restyle_damage::REPAINT; use style::values::{Either, RGBA, computed}; -use style::values::computed::{AngleOrCorner, Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto}; -use style::values::computed::{LengthOrKeyword, LengthOrPercentageOrKeyword, NumberOrPercentage, Position}; -use style::values::computed::image::{ColorStop, EndingShape, SizeKeyword}; +use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind, LengthOrPercentage}; +use style::values::computed::{LengthOrPercentageOrAuto, LengthOrKeyword, LengthOrPercentageOrKeyword}; +use style::values::computed::{NumberOrPercentage, Position}; +use style::values::computed::image::{EndingShape, SizeKeyword}; use style::values::specified::{HorizontalDirection, VerticalDirection}; use style_traits::CSSPixel; use style_traits::cursor::Cursor; @@ -388,7 +389,7 @@ pub trait FragmentDisplayListBuilding { fn convert_linear_gradient(&self, bounds: &Rect, - stops: &[ColorStop], + stops: &[GradientItem], angle_or_corner: &AngleOrCorner, repeating: bool, style: &ServoComputedValues) @@ -396,7 +397,7 @@ pub trait FragmentDisplayListBuilding { fn convert_radial_gradient(&self, bounds: &Rect, - stops: &[ColorStop], + stops: &[GradientItem], shape: &EndingShape, center: &Position, repeating: bool, @@ -601,13 +602,13 @@ fn build_border_radius_for_inner_rect(outer_rect: &Rect, radii } -fn convert_gradient_stops(gradient_stops: &[ColorStop], +fn convert_gradient_stops(gradient_items: &[GradientItem], length: Au, style: &ServoComputedValues) -> Vec { // Determine the position of each stop per CSS-IMAGES § 3.4. // // FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops. - let stop_items = gradient.items.iter().filter_map(|item| { + let stop_items = gradient_items.iter().filter_map(|item| { match *item { GradientItem::ColorStop(ref stop) => Some(stop), _ => None, @@ -720,6 +721,7 @@ fn convert_circle_size_keyword(keyword: SizeKeyword, ClosestCorner => get_distance_to_corner(size, center, ::std::cmp::min), FarthestCorner => get_distance_to_corner(size, center, ::std::cmp::max), _ => { + // TODO(#16542) println!("TODO: implement size keyword {:?} for circles", keyword); Au::new(0) } @@ -739,6 +741,7 @@ fn convert_ellipse_size_keyword(keyword: SizeKeyword, ClosestCorner => get_ellipse_radius(size, center, ::std::cmp::min), FarthestCorner => get_ellipse_radius(size, center, ::std::cmp::max), _ => { + // TODO(#16542) println!("TODO: implement size keyword {:?} for ellipses", keyword); Size2D::new(Au::new(0), Au::new(0)) } @@ -1050,7 +1053,7 @@ impl FragmentDisplayListBuilding for Fragment { fn convert_linear_gradient(&self, bounds: &Rect, - stops: &[ColorStop], + stops: &[GradientItem], angle_or_corner: &AngleOrCorner, repeating: bool, style: &ServoComputedValues) @@ -1108,14 +1111,14 @@ impl FragmentDisplayListBuilding for Fragment { fn convert_radial_gradient(&self, bounds: &Rect, - stops: &[ColorStop], + stops: &[GradientItem], shape: &EndingShape, center: &Position, repeating: bool, style: &ServoComputedValues) -> display_list::RadialGradient { - let center = Point2D::new(specified(center.horizontal, bounds.size.width), - specified(center.vertical, bounds.size.height)); + let center = Point2D::new(specified(center.horizontal.0, bounds.size.width), + specified(center.vertical.0, bounds.size.height)); let radius = match *shape { EndingShape::Circle(LengthOrKeyword::Length(length)) => Size2D::new(length, length), @@ -1165,7 +1168,7 @@ impl FragmentDisplayListBuilding for Fragment { let display_item = match gradient.gradient_kind { GradientKind::Linear(ref angle_or_corner) => { let gradient = self.convert_linear_gradient(&bounds, - &gradient.stops[..], + &gradient.items[..], angle_or_corner, gradient.repeating, style); @@ -1176,7 +1179,7 @@ impl FragmentDisplayListBuilding for Fragment { } GradientKind::Radial(ref shape, ref center) => { let gradient = self.convert_radial_gradient(&bounds, - &gradient.stops[..], + &gradient.items[..], shape, center, gradient.repeating, @@ -1302,7 +1305,7 @@ impl FragmentDisplayListBuilding for Fragment { match gradient.gradient_kind { GradientKind::Linear(angle_or_corner) => { let grad = self.convert_linear_gradient(&bounds, - &gradient.stops[..], + &gradient.items[..], &angle_or_corner, gradient.repeating, style); @@ -1319,7 +1322,7 @@ impl FragmentDisplayListBuilding for Fragment { })); } GradientKind::Radial(_, _) => { - // TODO(gw): Handle border-image with radial gradient. + // TODO(#16638): Handle border-image with radial gradient. } } }