diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 78d50530168..ee3494e1b95 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -886,10 +886,7 @@ pub struct IframeDisplayItem { /// Paints a gradient. #[derive(Clone, Deserialize, HeapSizeOf, Serialize)] -pub struct GradientDisplayItem { - /// Fields common to all display items. - pub base: BaseDisplayItem, - +pub struct Gradient { /// The start point of the gradient (computed during display list construction). pub start_point: Point2D, @@ -900,6 +897,15 @@ pub struct GradientDisplayItem { pub stops: Vec, } +#[derive(Clone, Deserialize, HeapSizeOf, Serialize)] +pub struct GradientDisplayItem { + /// Fields common to all display item. + pub base: BaseDisplayItem, + + /// Contains all gradient data. Included start, end point and color stops. + pub gradient: Gradient, +} + /// A normal border, supporting CSS border styles. #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] pub struct NormalBorder { @@ -939,11 +945,22 @@ pub struct ImageBorder { pub repeat_vertical: webrender_traits::RepeatMode, } +/// A border that is made of linear gradient +#[derive(Clone, HeapSizeOf, Deserialize, Serialize)] +pub struct GradientBorder { + /// The gradient info that this border uses, border-image-source. + pub gradient: Gradient, + + /// Outsets for the border, as per border-image-outset. + pub outset: SideOffsets2D, +} + /// Specifies the type of border #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] pub enum BorderDetails { Normal(NormalBorder), Image(ImageBorder), + Gradient(GradientBorder), } /// Paints a border. diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index bf0550b0363..456acf95c86 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -20,6 +20,7 @@ use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; use flow_ref::FlowRef; use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo}; use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo}; +use gfx::display_list; use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails}; use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion}; @@ -350,6 +351,12 @@ pub trait FragmentDisplayListBuilding { image_url: &ServoUrl, background_index: usize); + fn convert_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, @@ -831,20 +838,13 @@ impl FragmentDisplayListBuilding for Fragment { } } - fn build_display_list_for_background_gradient(&self, - state: &mut DisplayListBuildState, - display_list_section: DisplayListSection, - absolute_bounds: &Rect, - clip: &ClippingRegion, - gradient: &Gradient, - style: &ServoComputedValues) { - let mut clip = clip.clone(); - clip.intersect_rect(absolute_bounds); - - + fn convert_gradient(&self, + absolute_bounds: &Rect, + gradient: &Gradient, + style: &ServoComputedValues) -> Option { // FIXME: Repeating gradients aren't implemented yet. if gradient.repeating { - return; + return None; } let angle = if let GradientKind::Linear(angle_or_corner) = gradient.gradient_kind { match angle_or_corner { @@ -869,7 +869,7 @@ impl FragmentDisplayListBuilding for Fragment { } } else { // FIXME: Radial gradients aren't implemented yet. - return; + return None; }; // Get correct gradient line length, based on: @@ -953,19 +953,39 @@ impl FragmentDisplayListBuilding for Fragment { let center = Point2D::new(absolute_bounds.origin.x + absolute_bounds.size.width / 2, absolute_bounds.origin.y + absolute_bounds.size.height / 2); - 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::Gradient(box GradientDisplayItem { - base: base, + Some(display_list::Gradient { start_point: center - delta, end_point: center + delta, stops: stops, - }); + }) + } - state.add_display_item(gradient_display_item); + fn build_display_list_for_background_gradient(&self, + state: &mut DisplayListBuildState, + display_list_section: DisplayListSection, + absolute_bounds: &Rect, + clip: &ClippingRegion, + gradient: &Gradient, + style: &ServoComputedValues) { + let mut clip = clip.clone(); + clip.intersect_rect(absolute_bounds); + + let grad = self.convert_gradient(absolute_bounds, gradient, style); + + if let Some(x) = grad { + 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::Gradient(box GradientDisplayItem { + base: base, + gradient: x, + }); + + state.add_display_item(gradient_display_item); + } } fn build_display_list_for_box_shadow_if_applicable(&self, @@ -1076,8 +1096,28 @@ impl FragmentDisplayListBuilding for Fragment { }), })); } - Some(computed::Image::Gradient(..)) => { - // TODO(gw): Handle border-image with gradient. + Some(computed::Image::Gradient(ref gradient)) => { + match gradient.gradient_kind { + GradientKind::Linear(_) => { + let grad = self.convert_gradient(&bounds, gradient, 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, + + // TODO(gw): Support border-image-outset + outset: SideOffsets2D::zero(), + }), + })); + } + } + GradientKind::Radial(_, _) => { + // TODO(gw): Handle border-image with radial gradient. + } + } } Some(computed::Image::ImageRect(..)) => { // TODO: Handle border-image with `-moz-image-rect`. diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 2e94b79adaa..3d2f434053d 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -351,20 +351,30 @@ impl WebRenderDisplayItemConverter for DisplayItem { } } } + BorderDetails::Gradient(ref gradient) => { + webrender_traits::BorderDetails::Gradient(webrender_traits::GradientBorder { + gradient: builder.create_gradient( + gradient.gradient.start_point.to_pointf(), + gradient.gradient.end_point.to_pointf(), + gradient.gradient.stops.clone(), + ExtendMode::Clamp), + outset: gradient.outset, + }) + } }; builder.push_border(rect, clip, widths, details); } DisplayItem::Gradient(ref item) => { let rect = item.base.bounds.to_rectf(); - let start_point = item.start_point.to_pointf(); - let end_point = item.end_point.to_pointf(); + 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); builder.push_gradient(rect, clip, start_point, end_point, - item.stops.clone(), + item.gradient.stops.clone(), ExtendMode::Clamp); } DisplayItem::Line(..) => { diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 09e903d7a0b..b891057aa26 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -755,6 +755,18 @@ {} ] ], + "css/border-image-linear-gradient.html": [ + [ + "/_mozilla/css/border-image-linear-gradient.html", + [ + [ + "/_mozilla/css/border-image-linear-gradient-ref.html", + "==" + ] + ], + {} + ] + ], "css/border_black_ridge_a.html": [ [ "/_mozilla/css/border_black_ridge_a.html", @@ -6993,6 +7005,11 @@ {} ] ], + "css/border-image-linear-gradient-ref.html": [ + [ + {} + ] + ], "css/border_black_solid.html": [ [ {} @@ -20351,6 +20368,14 @@ "d0bf8fafec5ff2c0cfde8f0d47083ca23b745588", "support" ], + "css/border-image-linear-gradient-ref.html": [ + "3c1b61477c8a3cb7befc3ab81b80a128b142e3f1", + "support" + ], + "css/border-image-linear-gradient.html": [ + "40ea388a8a920eaecb2d0d12f998ed60ac3b56e8", + "reftest" + ], "css/border_black_groove.html": [ "42912352ee8f09ae0ddbac3dce35294dc8608bbe", "reftest_node" diff --git a/tests/wpt/mozilla/tests/css/border-image-linear-gradient-ref.html b/tests/wpt/mozilla/tests/css/border-image-linear-gradient-ref.html new file mode 100644 index 00000000000..0dddcf89d26 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/border-image-linear-gradient-ref.html @@ -0,0 +1,32 @@ + + + +test of border-image-source: linear-gradient + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tests/wpt/mozilla/tests/css/border-image-linear-gradient.html b/tests/wpt/mozilla/tests/css/border-image-linear-gradient.html new file mode 100644 index 00000000000..a0040e7e157 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/border-image-linear-gradient.html @@ -0,0 +1,19 @@ + + + + + +test of border-image-source: linear-gradient + + + +
+ +