servo: Merge #15905 - Add gradient border support (from mephisto41:add-border-gradient); r=emilio
authorMorris Tseng <mtseng@mozilla.com>
Sun, 26 Mar 2017 02:29:16 -0700
changeset 349683 599c1bda9389341d6ae56b8ca8a97635ce9168ff
parent 349682 1c0b16d1747c0964577a8ec21fa2b0a17b44ea4e
child 349684 c3aa67d05ff62e3c865a34a307b3d18b39090d02
push id39540
push userservo-vcs-sync@mozilla.com
push dateSun, 26 Mar 2017 17:17:42 +0000
treeherderautoland@599c1bda9389 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #15905 - Add gradient border support (from mephisto41:add-border-gradient); r=emilio webrender add gradient border support in https://github.com/servo/webrender/pull/953. This pr add support in servo. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors <!-- Either: --> - [X] These changes do not require tests because it should be covered by wpt <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: fd8127b23b177886217eb1f21963e6c02528647a
servo/components/gfx/display_list/mod.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/webrender_helpers.rs
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -881,30 +881,36 @@ pub struct WebGLDisplayItem {
 #[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
 pub struct IframeDisplayItem {
     pub base: BaseDisplayItem,
     pub iframe: PipelineId,
 }
 
 /// 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<Au>,
 
     /// The end point of the gradient (computed during display list construction).
     pub end_point: Point2D<Au>,
 
     /// A list of color stops.
     pub stops: Vec<GradientStop>,
 }
 
+#[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 {
     /// Border colors.
     pub color: SideOffsets2D<ColorF>,
 
     /// Border styles.
     pub style: SideOffsets2D<border_style::T>,
@@ -934,21 +940,32 @@ pub struct ImageBorder {
     #[ignore_heap_size_of = "WebRender traits type, and tiny"]
     pub repeat_horizontal: webrender_traits::RepeatMode,
 
     /// How to repeat or stretch vertical edges (border-image-repeat).
     #[ignore_heap_size_of = "WebRender traits type, and tiny"]
     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<f32>,
+}
+
 /// Specifies the type of border
 #[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
 pub enum BorderDetails {
     Normal(NormalBorder),
     Image(ImageBorder),
+    Gradient(GradientBorder),
 }
 
 /// Paints a border.
 #[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
 pub struct BorderDisplayItem {
     /// Fields common to all display items.
     pub base: BaseDisplayItem,
 
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -15,16 +15,17 @@ use block::{BlockFlow, BlockStackingCont
 use canvas_traits::{CanvasData, CanvasMsg, FromLayoutMsg};
 use context::LayoutContext;
 use euclid::{Point2D, Rect, SideOffsets2D, Size2D, TypedSize2D};
 use flex::FlexFlow;
 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};
 use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
 use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageDisplayItem};
 use gfx::display_list::{LineDisplayItem, OpaqueNode};
 use gfx::display_list::{SolidColorDisplayItem, ScrollRoot, StackingContext, StackingContextType};
 use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo};
@@ -345,16 +346,22 @@ pub trait FragmentDisplayListBuilding {
                                                state: &mut DisplayListBuildState,
                                                style: &ServoComputedValues,
                                                display_list_section: DisplayListSection,
                                                absolute_bounds: &Rect<Au>,
                                                clip: &ClippingRegion,
                                                image_url: &ServoUrl,
                                                background_index: usize);
 
+    fn convert_gradient(&self,
+                        absolute_bounds: &Rect<Au>,
+                        gradient: &Gradient,
+                        style: &ServoComputedValues)
+                        -> Option<display_list::Gradient>;
+
     /// 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,
                                                   state: &mut DisplayListBuildState,
                                                   display_list_section: DisplayListSection,
                                                   absolute_bounds: &Rect<Au>,
                                                   clip: &ClippingRegion,
                                                   gradient: &Gradient,
@@ -826,30 +833,23 @@ impl FragmentDisplayListBuilding for Fra
               stretch_size: stretch_size,
               tile_spacing: tile_spacing,
               image_rendering: style.get_inheritedbox().image_rendering.clone(),
             }));
 
         }
     }
 
-    fn build_display_list_for_background_gradient(&self,
-                                                  state: &mut DisplayListBuildState,
-                                                  display_list_section: DisplayListSection,
-                                                  absolute_bounds: &Rect<Au>,
-                                                  clip: &ClippingRegion,
-                                                  gradient: &Gradient,
-                                                  style: &ServoComputedValues) {
-        let mut clip = clip.clone();
-        clip.intersect_rect(absolute_bounds);
-
-
+    fn convert_gradient(&self,
+                        absolute_bounds: &Rect<Au>,
+                        gradient: &Gradient,
+                        style: &ServoComputedValues) -> Option<display_list::Gradient> {
         // 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 {
                 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.
@@ -864,17 +864,17 @@ impl FragmentDisplayListBuilding for Fra
                             => atan,
                         (HorizontalDirection::Left, VerticalDirection::Top)
                             => -atan,
                     }
                 }
             }
         } else {
             // FIXME: Radial gradients aren't implemented yet.
-            return;
+            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();
@@ -948,29 +948,49 @@ impl FragmentDisplayListBuilding for Fra
                 offset: offset,
                 color: style.resolve_color(stop.color).to_gfx_color()
             })
         }
 
         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,
-        });
+        })
+    }
+
+    fn build_display_list_for_background_gradient(&self,
+                                                  state: &mut DisplayListBuildState,
+                                                  display_list_section: DisplayListSection,
+                                                  absolute_bounds: &Rect<Au>,
+                                                  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);
 
-        state.add_display_item(gradient_display_item);
+        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,
                                                        state: &mut DisplayListBuildState,
                                                        style: &ServoComputedValues,
                                                        display_list_section: DisplayListSection,
                                                        absolute_bounds: &Rect<Au>,
                                                        clip: &ClippingRegion) {
@@ -1071,18 +1091,38 @@ impl FragmentDisplayListBuilding for Fra
                                                   colors.right.to_gfx_color(),
                                                   colors.bottom.to_gfx_color(),
                                                   colors.left.to_gfx_color()),
                         style: border_style,
                         radius: build_border_radius(&bounds, border_style_struct),
                     }),
                 }));
             }
-            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`.
             }
             Some(computed::Image::Url(ref image_url)) => {
                 if let Some(url) = image_url.url() {
                     let webrender_image = state.layout_context
                                                .get_webrender_image_for_url(self.node,
--- a/servo/components/layout/webrender_helpers.rs
+++ b/servo/components/layout/webrender_helpers.rs
@@ -346,30 +346,40 @@ impl WebRenderDisplayItemConverter for D
                                     },
                                     outset: image.outset,
                                     repeat_horizontal: image.repeat_horizontal,
                                     repeat_vertical: image.repeat_vertical,
                                 })
                             }
                         }
                     }
+                    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(..) => {
                 println!("TODO DisplayItem::Line");
             }
             DisplayItem::BoxShadow(ref item) => {
                 let rect = item.base.bounds.to_rectf();
                 let box_bounds = item.box_bounds.to_rectf();