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.rs156
1 files changed, 91 insertions, 65 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 2c0063b7c39..ce3df3f4c47 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -60,6 +60,10 @@ use table_cell::CollapsedBordersForCell;
use url::Url;
use util::opts;
+fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
+ &arr[index % arr.len()]
+}
+
pub struct DisplayListBuildState<'a> {
pub layout_context: &'a LayoutContext<'a>,
pub items: Vec<DisplayItem>,
@@ -146,7 +150,7 @@ pub trait FragmentDisplayListBuilding {
fn compute_background_image_size(&self,
style: &ServoComputedValues,
bounds: &Rect<Au>,
- image: &WebRenderImageInfo)
+ image: &WebRenderImageInfo, index: usize)
-> Size2D<Au>;
/// Adds the display items necessary to paint the background image of this fragment to the
@@ -157,7 +161,8 @@ pub trait FragmentDisplayListBuilding {
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion,
- image_url: &Url);
+ image_url: &Url,
+ background_index: usize);
/// Adds the display items necessary to paint the background linear gradient of this fragment
/// to the appropriate section of the display list.
@@ -344,27 +349,32 @@ impl FragmentDisplayListBuilding for Fragment {
if !border_radii.is_square() {
clip.intersect_with_rounded_rect(absolute_bounds, &border_radii)
}
+ let background = style.get_background();
// FIXME: This causes a lot of background colors to be displayed when they are clearly not
// needed. We could use display list optimization to clean this up, but it still seems
// inefficient. What we really want is something like "nearest ancestor element that
// doesn't have a fragment".
- let background_color = style.resolve_color(style.get_background().background_color);
+ let background_color = style.resolve_color(background.background_color);
// 'background-clip' determines the area within which the background is painted.
// http://dev.w3.org/csswg/css-backgrounds-3/#the-background-clip
let mut bounds = *absolute_bounds;
- match style.get_background().background_clip {
- background_clip::T::border_box => {}
- background_clip::T::padding_box => {
+ // This is the clip for the color (which is the last element in the bg array)
+ let color_clip = get_cyclic(&background.background_clip.0,
+ background.background_image.0.len() - 1);
+
+ match *color_clip {
+ background_clip::single_value::T::border_box => {}
+ background_clip::single_value::T::padding_box => {
let border = style.logical_border_width().to_physical(style.writing_mode);
bounds.origin.x = bounds.origin.x + border.left;
bounds.origin.y = bounds.origin.y + border.top;
bounds.size.width = bounds.size.width - border.horizontal();
bounds.size.height = bounds.size.height - border.vertical();
}
- background_clip::T::content_box => {
+ background_clip::single_value::T::content_box => {
let border_padding = self.border_padding.to_physical(style.writing_mode);
bounds.origin.x = bounds.origin.x + border_padding.left;
bounds.origin.y = bounds.origin.y + border_padding.top;
@@ -388,23 +398,26 @@ impl FragmentDisplayListBuilding for Fragment {
// Implements background image, per spec:
// http://www.w3.org/TR/CSS21/colors.html#background
let background = style.get_background();
- match background.background_image.0 {
- None => {}
- Some(computed::Image::LinearGradient(ref gradient)) => {
- self.build_display_list_for_background_linear_gradient(state,
- display_list_section,
- &bounds,
- &clip,
- gradient,
- style);
- }
- Some(computed::Image::Url(ref image_url, ref _extra_data)) => {
- self.build_display_list_for_background_image(state,
- style,
- display_list_section,
- &bounds,
- &clip,
- image_url);
+ for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
+ match background_image.0 {
+ None => {}
+ Some(computed::Image::LinearGradient(ref gradient)) => {
+ self.build_display_list_for_background_linear_gradient(state,
+ display_list_section,
+ &bounds,
+ &clip,
+ gradient,
+ style);
+ }
+ Some(computed::Image::Url(ref image_url, ref _extra_data)) => {
+ self.build_display_list_for_background_image(state,
+ style,
+ display_list_section,
+ &bounds,
+ &clip,
+ image_url,
+ i);
+ }
}
}
}
@@ -412,7 +425,8 @@ impl FragmentDisplayListBuilding for Fragment {
fn compute_background_image_size(&self,
style: &ServoComputedValues,
bounds: &Rect<Au>,
- image: &WebRenderImageInfo)
+ image: &WebRenderImageInfo,
+ index: usize)
-> Size2D<Au> {
// If `image_aspect_ratio` < `bounds_aspect_ratio`, the image is tall; otherwise, it is
// wide.
@@ -420,19 +434,22 @@ impl FragmentDisplayListBuilding for Fragment {
let bounds_aspect_ratio = bounds.size.width.to_f64_px() / bounds.size.height.to_f64_px();
let intrinsic_size = Size2D::new(Au::from_px(image.width as i32),
Au::from_px(image.height as i32));
- match (style.get_background().background_size.clone(),
- image_aspect_ratio < bounds_aspect_ratio) {
- (background_size::T::Contain, false) | (background_size::T::Cover, true) => {
+ let background_size = get_cyclic(&style.get_background().background_size.0, index).clone();
+ match (background_size, image_aspect_ratio < bounds_aspect_ratio) {
+ (background_size::single_value::T::Contain, false) |
+ (background_size::single_value::T::Cover, true) => {
Size2D::new(bounds.size.width,
Au::from_f64_px(bounds.size.width.to_f64_px() / image_aspect_ratio))
}
- (background_size::T::Contain, true) | (background_size::T::Cover, false) => {
+ (background_size::single_value::T::Contain, true) |
+ (background_size::single_value::T::Cover, false) => {
Size2D::new(Au::from_f64_px(bounds.size.height.to_f64_px() * image_aspect_ratio),
bounds.size.height)
}
- (background_size::T::Explicit(background_size::ExplicitSize {
+ (background_size::single_value::T::Explicit(background_size::single_value
+ ::ExplicitSize {
width,
height: LengthOrPercentageOrAuto::Auto,
}), _) => {
@@ -441,7 +458,8 @@ impl FragmentDisplayListBuilding for Fragment {
Size2D::new(width, Au::from_f64_px(width.to_f64_px() / image_aspect_ratio))
}
- (background_size::T::Explicit(background_size::ExplicitSize {
+ (background_size::single_value::T::Explicit(background_size::single_value
+ ::ExplicitSize {
width: LengthOrPercentageOrAuto::Auto,
height
}), _) => {
@@ -450,7 +468,8 @@ impl FragmentDisplayListBuilding for Fragment {
Size2D::new(Au::from_f64_px(height.to_f64_px() * image_aspect_ratio), height)
}
- (background_size::T::Explicit(background_size::ExplicitSize {
+ (background_size::single_value::T::Explicit(background_size::single_value
+ ::ExplicitSize {
width,
height
}), _) => {
@@ -468,19 +487,22 @@ impl FragmentDisplayListBuilding for Fragment {
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion,
- image_url: &Url) {
+ image_url: &Url,
+ index: usize) {
let background = style.get_background();
let fetch_image_data_as_well = !opts::get().use_webrender;
let webrender_image =
state.layout_context.get_webrender_image_for_url(image_url,
UsePlaceholder::No,
fetch_image_data_as_well);
+
if let Some((webrender_image, image_data)) = 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);
+ let image_size = self.compute_background_image_size(style, &bounds,
+ &webrender_image, index);
// Clip.
//
@@ -492,25 +514,27 @@ impl FragmentDisplayListBuilding for Fragment {
let border = style.logical_border_width().to_physical(style.writing_mode);
// Use 'background-origin' to get the origin value.
- let (mut origin_x, mut origin_y) = match background.background_origin {
- background_origin::T::padding_box => {
+ 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::T::border_box => {
+ background_origin::single_value::T::border_box => {
(-border.left, -border.top)
}
- background_origin::T::content_box => {
+ 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 (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
- background_attachment::T::scroll => {
+ 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::T::fixed => {
+ 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);
@@ -519,24 +543,25 @@ impl FragmentDisplayListBuilding for Fragment {
}
};
+ let position = *get_cyclic(&background.background_position.0, index);
// Use `background-position` to get the offset.
- let horizontal_position = model::specified(background.background_position.0.horizontal,
- bounds.size.width - image_size.width);
- let vertical_position = model::specified(background.background_position.0.vertical,
- bounds.size.height - image_size.height);
+ let horizontal_position = model::specified(position.horizontal,
+ bounds.size.width - image_size.width);
+ let vertical_position = model::specified(position.vertical,
+ bounds.size.height - image_size.height);
let abs_x = border.left + virtual_origin_x + horizontal_position + origin_x;
let abs_y = border.top + virtual_origin_y + vertical_position + origin_y;
// Adjust origin and size based on background-repeat
- match background.background_repeat {
- background_repeat::T::no_repeat => {
+ match *get_cyclic(&background.background_repeat.0, index) {
+ background_repeat::single_value::T::no_repeat => {
bounds.origin.x = abs_x;
bounds.origin.y = abs_y;
bounds.size.width = image_size.width;
bounds.size.height = image_size.height;
}
- background_repeat::T::repeat_x => {
+ background_repeat::single_value::T::repeat_x => {
bounds.origin.y = abs_y;
bounds.size.height = image_size.height;
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
@@ -544,7 +569,7 @@ impl FragmentDisplayListBuilding for Fragment {
abs_x,
image_size.width.to_nearest_px() as u32);
}
- background_repeat::T::repeat_y => {
+ background_repeat::single_value::T::repeat_y => {
bounds.origin.x = abs_x;
bounds.size.width = image_size.width;
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
@@ -552,31 +577,32 @@ impl FragmentDisplayListBuilding for Fragment {
abs_y,
image_size.height.to_nearest_px() as u32);
}
- background_repeat::T::repeat => {
+ background_repeat::single_value::T::repeat => {
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
- &mut bounds.size.width,
- abs_x,
- image_size.width.to_nearest_px() as u32);
+ &mut bounds.size.width,
+ abs_x,
+ image_size.width.to_nearest_px() as u32);
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
- &mut bounds.size.height,
- abs_y,
- image_size.height.to_nearest_px() as u32);
+ &mut bounds.size.height,
+ abs_y,
+ image_size.height.to_nearest_px() as u32);
}
};
// Create the image display item.
let base = state.create_base_display_item(&bounds,
- &clip,
- self.node,
- style.get_cursor(Cursor::Default),
- display_list_section);
+ &clip,
+ self.node,
+ style.get_cursor(Cursor::Default),
+ display_list_section);
state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem {
- base: base,
- webrender_image: webrender_image,
- image_data: image_data.map(Arc::new),
- stretch_size: Size2D::new(image_size.width, image_size.height),
- image_rendering: style.get_inheritedbox().image_rendering.clone(),
+ base: base,
+ webrender_image: webrender_image,
+ image_data: image_data.map(Arc::new),
+ stretch_size: Size2D::new(image_size.width, image_size.height),
+ image_rendering: style.get_inheritedbox().image_rendering.clone(),
}));
+
}
}