aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/display_list_builder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/display_list_builder.rs')
-rw-r--r--components/layout/display_list_builder.rs347
1 files changed, 221 insertions, 126 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index c4a20d1ee11..6794d144a47 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -64,6 +64,7 @@ use style::values::generics::background::BackgroundSize;
use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape};
use style::values::generics::image::{GradientItem as GenericGradientItem, GradientKind};
use style::values::generics::image::{Image, ShapeExtent};
+use style::values::generics::image::PaintWorklet;
use style::values::specified::position::{X, Y};
use style_traits::CSSPixel;
use style_traits::cursor::Cursor;
@@ -395,6 +396,28 @@ pub trait FragmentDisplayListBuilding {
image_url: &ServoUrl,
background_index: usize);
+ /// Adds the display items necessary to paint a webrender image of this fragment to the
+ /// appropriate section of the display list.
+ fn build_display_list_for_webrender_image(&self,
+ state: &mut DisplayListBuildState,
+ style: &ServoComputedValues,
+ display_list_section: DisplayListSection,
+ absolute_bounds: &Rect<Au>,
+ clip: &ClippingRegion,
+ webrender_image: WebRenderImageInfo,
+ index: usize);
+
+ /// Adds the display items necessary to paint the background image created by this fragment's
+ /// worklet to the appropriate section of the display list.
+ fn build_display_list_for_background_paint_worklet(&self,
+ state: &mut DisplayListBuildState,
+ style: &ServoComputedValues,
+ display_list_section: DisplayListSection,
+ absolute_bounds: &Rect<Au>,
+ clip: &ClippingRegion,
+ paint_worklet: &PaintWorklet,
+ index: usize);
+
fn convert_linear_gradient(&self,
bounds: &Rect<Au>,
stops: &[GradientItem],
@@ -893,6 +916,15 @@ impl FragmentDisplayListBuilding for Fragment {
i);
}
}
+ Either::Second(Image::PaintWorklet(ref paint_worklet)) => {
+ self.build_display_list_for_background_paint_worklet(state,
+ style,
+ display_list_section,
+ &bounds,
+ &clip,
+ paint_worklet,
+ i);
+ }
Either::Second(Image::Rect(_)) => {
// TODO: Implement `-moz-image-rect`
}
@@ -956,144 +988,204 @@ impl FragmentDisplayListBuilding for Fragment {
clip: &ClippingRegion,
image_url: &ServoUrl,
index: usize) {
- let background = style.get_background();
let webrender_image = state.layout_context
.get_webrender_image_for_url(self.node,
image_url.clone(),
UsePlaceholder::No);
if let Some(webrender_image) = webrender_image {
- debug!("(building display list) building background image");
-
- // Use `background-size` to get the size.
- let mut bounds = *absolute_bounds;
- let image_size = self.compute_background_image_size(style, &bounds,
- &webrender_image, index);
-
- // Clip.
- //
- // TODO: Check the bounds to see if a clip item is actually required.
- let mut clip = clip.clone();
- clip.intersect_rect(&bounds);
-
- // Background image should be positioned on the padding box basis.
- let border = style.logical_border_width().to_physical(style.writing_mode);
-
- // Use 'background-origin' to get the origin value.
- let origin = get_cyclic(&background.background_origin.0, index);
- let (mut origin_x, mut origin_y) = match *origin {
- background_origin::single_value::T::padding_box => {
- (Au(0), Au(0))
- }
- background_origin::single_value::T::border_box => {
- (-border.left, -border.top)
- }
- background_origin::single_value::T::content_box => {
- let border_padding = self.border_padding.to_physical(self.style.writing_mode);
- (border_padding.left - border.left, border_padding.top - border.top)
- }
- };
+ self.build_display_list_for_webrender_image(state,
+ style,
+ display_list_section,
+ absolute_bounds,
+ clip,
+ webrender_image,
+ index);
+ }
+ }
- // Use `background-attachment` to get the initial virtual origin
- let attachment = get_cyclic(&background.background_attachment.0, index);
- let (virtual_origin_x, virtual_origin_y) = match *attachment {
- background_attachment::single_value::T::scroll => {
- (absolute_bounds.origin.x, absolute_bounds.origin.y)
- }
- background_attachment::single_value::T::fixed => {
- // If the ‘background-attachment’ value for this image is ‘fixed’, then
- // 'background-origin' has no effect.
- origin_x = Au(0);
- origin_y = Au(0);
- (Au(0), Au(0))
- }
- };
+ fn build_display_list_for_webrender_image(&self,
+ state: &mut DisplayListBuildState,
+ style: &ServoComputedValues,
+ display_list_section: DisplayListSection,
+ absolute_bounds: &Rect<Au>,
+ clip: &ClippingRegion,
+ webrender_image: WebRenderImageInfo,
+ index: usize) {
+ debug!("(building display list) building background image");
+ let background = style.get_background();
- let horiz_position = *get_cyclic(&background.background_position_x.0, index);
- let vert_position = *get_cyclic(&background.background_position_y.0, index);
- // Use `background-position` to get the offset.
- let horizontal_position = horiz_position.to_used_value(bounds.size.width - image_size.width);
- let vertical_position = vert_position.to_used_value(bounds.size.height - image_size.height);
-
- // The anchor position for this background, based on both the background-attachment
- // and background-position properties.
- let anchor_origin_x = border.left + virtual_origin_x + origin_x + horizontal_position;
- let anchor_origin_y = border.top + virtual_origin_y + origin_y + vertical_position;
-
- let mut tile_spacing = Size2D::zero();
- let mut stretch_size = image_size;
-
- // Adjust origin and size based on background-repeat
- let background_repeat = get_cyclic(&background.background_repeat.0, index);
- match background_repeat.0 {
- background_repeat::single_value::RepeatKeyword::NoRepeat => {
- bounds.origin.x = anchor_origin_x;
- bounds.size.width = image_size.width;
- }
- background_repeat::single_value::RepeatKeyword::Repeat => {
- ImageFragmentInfo::tile_image(&mut bounds.origin.x,
- &mut bounds.size.width,
- anchor_origin_x,
- image_size.width);
- }
- background_repeat::single_value::RepeatKeyword::Space => {
- ImageFragmentInfo::tile_image_spaced(&mut bounds.origin.x,
- &mut bounds.size.width,
- &mut tile_spacing.width,
- anchor_origin_x,
- image_size.width);
+ // Use `background-size` to get the size.
+ let mut bounds = *absolute_bounds;
+ let image_size = self.compute_background_image_size(style, &bounds,
+ &webrender_image, index);
- }
- background_repeat::single_value::RepeatKeyword::Round => {
- ImageFragmentInfo::tile_image_round(&mut bounds.origin.x,
- &mut bounds.size.width,
- anchor_origin_x,
- &mut stretch_size.width);
- }
- };
- match background_repeat.1 {
- background_repeat::single_value::RepeatKeyword::NoRepeat => {
- bounds.origin.y = anchor_origin_y;
- bounds.size.height = image_size.height;
- }
- background_repeat::single_value::RepeatKeyword::Repeat => {
- ImageFragmentInfo::tile_image(&mut bounds.origin.y,
- &mut bounds.size.height,
- anchor_origin_y,
- image_size.height);
- }
- background_repeat::single_value::RepeatKeyword::Space => {
- ImageFragmentInfo::tile_image_spaced(&mut bounds.origin.y,
- &mut bounds.size.height,
- &mut tile_spacing.height,
- anchor_origin_y,
- image_size.height);
+ // Clip.
+ //
+ // TODO: Check the bounds to see if a clip item is actually required.
+ let mut clip = clip.clone();
+ clip.intersect_rect(&bounds);
- }
- background_repeat::single_value::RepeatKeyword::Round => {
- ImageFragmentInfo::tile_image_round(&mut bounds.origin.y,
- &mut bounds.size.height,
- anchor_origin_y,
- &mut stretch_size.height);
- }
- };
+ // Background image should be positioned on the padding box basis.
+ let border = style.logical_border_width().to_physical(style.writing_mode);
- // Create the image display item.
- let base = state.create_base_display_item(&bounds,
- &clip,
- self.node,
- style.get_cursor(Cursor::Default),
- display_list_section);
- state.add_display_item(DisplayItem::Image(box ImageDisplayItem {
- base: base,
- webrender_image: webrender_image,
- image_data: None,
- stretch_size: stretch_size,
- tile_spacing: tile_spacing,
- image_rendering: style.get_inheritedbox().image_rendering.clone(),
- }));
+ // Use 'background-origin' to get the origin value.
+ let origin = get_cyclic(&background.background_origin.0, index);
+ let (mut origin_x, mut origin_y) = match *origin {
+ background_origin::single_value::T::padding_box => {
+ (Au(0), Au(0))
+ }
+ background_origin::single_value::T::border_box => {
+ (-border.left, -border.top)
+ }
+ background_origin::single_value::T::content_box => {
+ let border_padding = self.border_padding.to_physical(self.style.writing_mode);
+ (border_padding.left - border.left, border_padding.top - border.top)
+ }
+ };
+
+ // Use `background-attachment` to get the initial virtual origin
+ let attachment = get_cyclic(&background.background_attachment.0, index);
+ let (virtual_origin_x, virtual_origin_y) = match *attachment {
+ background_attachment::single_value::T::scroll => {
+ (absolute_bounds.origin.x, absolute_bounds.origin.y)
+ }
+ background_attachment::single_value::T::fixed => {
+ // If the ‘background-attachment’ value for this image is ‘fixed’, then
+ // 'background-origin' has no effect.
+ origin_x = Au(0);
+ origin_y = Au(0);
+ (Au(0), Au(0))
+ }
+ };
+
+ let horiz_position = *get_cyclic(&background.background_position_x.0, index);
+ let vert_position = *get_cyclic(&background.background_position_y.0, index);
+ // Use `background-position` to get the offset.
+ let horizontal_position = horiz_position.to_used_value(bounds.size.width - image_size.width);
+ let vertical_position = vert_position.to_used_value(bounds.size.height - image_size.height);
+
+ // The anchor position for this background, based on both the background-attachment
+ // and background-position properties.
+ let anchor_origin_x = border.left + virtual_origin_x + origin_x + horizontal_position;
+ let anchor_origin_y = border.top + virtual_origin_y + origin_y + vertical_position;
+
+ let mut tile_spacing = Size2D::zero();
+ let mut stretch_size = image_size;
+
+ // Adjust origin and size based on background-repeat
+ let background_repeat = get_cyclic(&background.background_repeat.0, index);
+ match background_repeat.0 {
+ background_repeat::single_value::RepeatKeyword::NoRepeat => {
+ bounds.origin.x = anchor_origin_x;
+ bounds.size.width = image_size.width;
+ }
+ background_repeat::single_value::RepeatKeyword::Repeat => {
+ ImageFragmentInfo::tile_image(&mut bounds.origin.x,
+ &mut bounds.size.width,
+ anchor_origin_x,
+ image_size.width);
+ }
+ background_repeat::single_value::RepeatKeyword::Space => {
+ ImageFragmentInfo::tile_image_spaced(&mut bounds.origin.x,
+ &mut bounds.size.width,
+ &mut tile_spacing.width,
+ anchor_origin_x,
+ image_size.width);
+
+ }
+ background_repeat::single_value::RepeatKeyword::Round => {
+ ImageFragmentInfo::tile_image_round(&mut bounds.origin.x,
+ &mut bounds.size.width,
+ anchor_origin_x,
+ &mut stretch_size.width);
+ }
+ };
+ match background_repeat.1 {
+ background_repeat::single_value::RepeatKeyword::NoRepeat => {
+ bounds.origin.y = anchor_origin_y;
+ bounds.size.height = image_size.height;
+ }
+ background_repeat::single_value::RepeatKeyword::Repeat => {
+ ImageFragmentInfo::tile_image(&mut bounds.origin.y,
+ &mut bounds.size.height,
+ anchor_origin_y,
+ image_size.height);
+ }
+ background_repeat::single_value::RepeatKeyword::Space => {
+ ImageFragmentInfo::tile_image_spaced(&mut bounds.origin.y,
+ &mut bounds.size.height,
+ &mut tile_spacing.height,
+ anchor_origin_y,
+ image_size.height);
+
+ }
+ background_repeat::single_value::RepeatKeyword::Round => {
+ ImageFragmentInfo::tile_image_round(&mut bounds.origin.y,
+ &mut bounds.size.height,
+ anchor_origin_y,
+ &mut stretch_size.height);
+ }
+ };
+
+ // Create the image display item.
+ let base = state.create_base_display_item(&bounds,
+ &clip,
+ self.node,
+ style.get_cursor(Cursor::Default),
+ display_list_section);
+
+ debug!("(building display list) adding background image.");
+ state.add_display_item(DisplayItem::Image(box ImageDisplayItem {
+ base: base,
+ webrender_image: webrender_image,
+ image_data: None,
+ stretch_size: stretch_size,
+ tile_spacing: tile_spacing,
+ image_rendering: style.get_inheritedbox().image_rendering.clone(),
+ }));
- }
+ }
+
+ fn build_display_list_for_background_paint_worklet(&self,
+ state: &mut DisplayListBuildState,
+ style: &ServoComputedValues,
+ display_list_section: DisplayListSection,
+ absolute_bounds: &Rect<Au>,
+ clip: &ClippingRegion,
+ paint_worklet: &PaintWorklet,
+ index: usize)
+ {
+ // TODO: check that this is the servo equivalent of "concrete object size".
+ // https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image
+ // https://drafts.csswg.org/css-images-3/#concrete-object-size
+ let size = self.content_box().size.to_physical(style.writing_mode);
+ let name = paint_worklet.name.clone();
+
+ // If the script thread has not added any paint worklet modules, there is nothing to do!
+ let executor = match state.layout_context.paint_worklet_executor {
+ Some(ref executor) => executor,
+ None => return debug!("Worklet {} called before any paint modules are added.", name),
+ };
+
+ // TODO: add a one-place cache to avoid drawing the paint image every time.
+ debug!("Drawing a paint image {}({},{}).", name, size.width.to_px(), size.height.to_px());
+ let mut image = match executor.draw_a_paint_image(name, size) {
+ Ok(image) => image,
+ Err(err) => return warn!("Error running paint worklet ({:?}).", err),
+ };
+
+ // Make sure the image has a webrender key.
+ state.layout_context.image_cache.set_webrender_image_key(&mut image);
+
+ debug!("Drew a paint image ({},{}).", image.width, image.height);
+ self.build_display_list_for_webrender_image(state,
+ style,
+ display_list_section,
+ absolute_bounds,
+ clip,
+ WebRenderImageInfo::from_image(&image),
+ index);
}
fn convert_linear_gradient(&self,
@@ -1402,6 +1494,9 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
}
+ Either::Second(Image::PaintWorklet(..)) => {
+ // TODO: Handle border-image with `paint()`.
+ }
Either::Second(Image::Rect(..)) => {
// TODO: Handle border-image with `-moz-image-rect`.
}