mirror of
https://github.com/servo/servo.git
synced 2025-08-02 04:00:32 +01:00
Add support for background-repeat: space and round
This adds support for more background-repeat modes using the legacy rendering backend.
This commit is contained in:
parent
821797d6f7
commit
68ae97fd0e
14 changed files with 193 additions and 105 deletions
|
@ -547,46 +547,74 @@ 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(position.horizontal,
|
||||
bounds.size.width - image_size.width);
|
||||
bounds.size.width - image_size.width);
|
||||
let vertical_position = model::specified(position.vertical,
|
||||
bounds.size.height - image_size.height);
|
||||
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;
|
||||
// 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
|
||||
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.origin.x = anchor_origin_x;
|
||||
bounds.origin.y = anchor_origin_y;
|
||||
bounds.size.width = image_size.width;
|
||||
bounds.size.height = image_size.height;
|
||||
}
|
||||
background_repeat::single_value::T::repeat_x => {
|
||||
bounds.origin.y = abs_y;
|
||||
bounds.origin.y = anchor_origin_y;
|
||||
bounds.size.height = image_size.height;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
|
||||
&mut bounds.size.width,
|
||||
abs_x,
|
||||
image_size.width.to_nearest_px() as u32);
|
||||
anchor_origin_x,
|
||||
image_size.width);
|
||||
}
|
||||
background_repeat::single_value::T::repeat_y => {
|
||||
bounds.origin.x = abs_x;
|
||||
bounds.origin.x = anchor_origin_x;
|
||||
bounds.size.width = image_size.width;
|
||||
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
|
||||
&mut bounds.size.height,
|
||||
abs_y,
|
||||
image_size.height.to_nearest_px() as u32);
|
||||
anchor_origin_y,
|
||||
image_size.height);
|
||||
}
|
||||
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,
|
||||
anchor_origin_x,
|
||||
image_size.width);
|
||||
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,
|
||||
anchor_origin_y,
|
||||
image_size.height);
|
||||
}
|
||||
background_repeat::single_value::T::space => {
|
||||
ImageFragmentInfo::tile_image_spaced(&mut bounds.origin.x,
|
||||
&mut bounds.size.width,
|
||||
&mut tile_spacing.width,
|
||||
anchor_origin_x,
|
||||
image_size.width);
|
||||
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::T::round => {
|
||||
ImageFragmentInfo::tile_image_round(&mut bounds.origin.x,
|
||||
&mut bounds.size.width,
|
||||
anchor_origin_x,
|
||||
&mut stretch_size.width);
|
||||
ImageFragmentInfo::tile_image_round(&mut bounds.origin.y,
|
||||
&mut bounds.size.height,
|
||||
anchor_origin_y,
|
||||
&mut stretch_size.height);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -600,7 +628,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
base: base,
|
||||
webrender_image: webrender_image,
|
||||
image_data: image_data.map(Arc::new),
|
||||
stretch_size: Size2D::new(image_size.width, image_size.height),
|
||||
stretch_size: stretch_size,
|
||||
tile_spacing: tile_spacing,
|
||||
image_rendering: style.get_inheritedbox().image_rendering.clone(),
|
||||
}));
|
||||
|
||||
|
@ -1257,6 +1286,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
webrender_image: WebRenderImageInfo::from_image(image),
|
||||
image_data: Some(Arc::new(image.bytes.clone())),
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
tile_spacing: Size2D::zero(),
|
||||
image_rendering: self.style.get_inheritedbox().image_rendering.clone(),
|
||||
}));
|
||||
}
|
||||
|
@ -1300,6 +1330,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
key: canvas_data.image_key,
|
||||
},
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
tile_spacing: Size2D::zero(),
|
||||
image_rendering: image_rendering::T::Auto,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -425,18 +425,73 @@ impl ImageFragmentInfo {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tile_image_round(position: &mut Au,
|
||||
size: &mut Au,
|
||||
absolute_anchor_origin: Au,
|
||||
image_size: &mut Au) {
|
||||
if *size == Au(0) || *image_size == Au(0) {
|
||||
*position = Au(0);
|
||||
*size =Au(0);
|
||||
return;
|
||||
}
|
||||
|
||||
let number_of_tiles = (size.to_f32_px() / image_size.to_f32_px()).round().max(1.0);
|
||||
*image_size = *size / (number_of_tiles as i32);
|
||||
ImageFragmentInfo::tile_image(position, size, absolute_anchor_origin, *image_size);
|
||||
}
|
||||
|
||||
pub fn tile_image_spaced(position: &mut Au,
|
||||
size: &mut Au,
|
||||
tile_spacing: &mut Au,
|
||||
absolute_anchor_origin: Au,
|
||||
image_size: Au) {
|
||||
if *size == Au(0) || image_size == Au(0) {
|
||||
*position = Au(0);
|
||||
*size = Au(0);
|
||||
*tile_spacing = Au(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Per the spec, if the space available is not enough for two images, just tile as
|
||||
// normal but only display a single tile.
|
||||
if image_size * 2 >= *size {
|
||||
ImageFragmentInfo::tile_image(position,
|
||||
size,
|
||||
absolute_anchor_origin,
|
||||
image_size);
|
||||
*tile_spacing = Au(0);
|
||||
*size = image_size;;
|
||||
return;
|
||||
}
|
||||
|
||||
// Take the box size, remove room for two tiles on the edges, and then calculate how many
|
||||
// other tiles fit in between them.
|
||||
let size_remaining = *size - (image_size * 2);
|
||||
let num_middle_tiles = (size_remaining.to_f32_px() / image_size.to_f32_px()).floor() as i32;
|
||||
|
||||
// Allocate the remaining space as padding between tiles. background-position is ignored
|
||||
// as per the spec, so the position is just the box origin. We are also ignoring
|
||||
// background-attachment here, which seems unspecced when combined with
|
||||
// background-repeat: space.
|
||||
let space_for_middle_tiles = image_size * num_middle_tiles;
|
||||
*tile_spacing = (size_remaining - space_for_middle_tiles) / (num_middle_tiles + 1);
|
||||
}
|
||||
|
||||
/// Tile an image
|
||||
pub fn tile_image(position: &mut Au, size: &mut Au, virtual_position: Au, image_size: u32) {
|
||||
pub fn tile_image(position: &mut Au,
|
||||
size: &mut Au,
|
||||
absolute_anchor_origin: Au,
|
||||
image_size: Au) {
|
||||
// Avoid division by zero below!
|
||||
let image_size = image_size as i32;
|
||||
if image_size == 0 {
|
||||
if image_size == Au(0) {
|
||||
return
|
||||
}
|
||||
|
||||
let delta_pixels = (virtual_position - *position).to_px();
|
||||
let tile_count = (delta_pixels + image_size - 1) / image_size;
|
||||
let offset = Au::from_px(image_size * tile_count);
|
||||
let new_position = virtual_position - offset;
|
||||
let delta_pixels = absolute_anchor_origin - *position;
|
||||
let image_size_px = image_size.to_f32_px();
|
||||
let tile_count = ((delta_pixels.to_f32_px() + image_size_px - 1.0) / image_size_px).floor();
|
||||
let offset = image_size * (tile_count as i32);
|
||||
let new_position = absolute_anchor_origin - offset;
|
||||
*size = *position - new_position + *size;
|
||||
*position = new_position;
|
||||
}
|
||||
|
|
|
@ -427,12 +427,10 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
if let Some(id) = item.webrender_image.key {
|
||||
if item.stretch_size.width > Au(0) &&
|
||||
item.stretch_size.height > Au(0) {
|
||||
// TODO(gw): Pass through the tile spacing once the other
|
||||
// changes related to this land (parsing etc).
|
||||
builder.push_image(item.base.bounds.to_rectf(),
|
||||
item.base.clip.to_clip_region(frame_builder),
|
||||
item.stretch_size.to_sizef(),
|
||||
Size2D::zero(),
|
||||
item.tile_spacing.to_sizef(),
|
||||
item.image_rendering.to_image_rendering(),
|
||||
id);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue