mirror of
https://github.com/servo/servo.git
synced 2025-08-13 01:15:34 +01:00
layout: Add support for object-fit
and object-position
(#33479)
This also makes a couple small improvements: - Rename `IntrinsicSizes` to `NaturalSizes` which reflects more modern spec language. - Move the conversion of Stylo's `ImageRendering` to WebRender's version to a `ToWebRender` trait implementation. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
632d832704
commit
bd632fc814
58 changed files with 169 additions and 563 deletions
|
@ -17,7 +17,7 @@ use webrender_api::{self as wr, units};
|
|||
use wr::units::LayoutSize;
|
||||
use wr::ClipChainId;
|
||||
|
||||
use crate::replaced::IntrinsicSizes;
|
||||
use crate::replaced::NaturalSizes;
|
||||
|
||||
pub(super) struct BackgroundLayer {
|
||||
pub common: wr::CommonItemProperties,
|
||||
|
@ -167,7 +167,7 @@ pub(super) fn layout_layer(
|
|||
painter: &BackgroundPainter,
|
||||
builder: &mut super::DisplayListBuilder,
|
||||
layer_index: usize,
|
||||
intrinsic: IntrinsicSizes,
|
||||
natural_sizes: NaturalSizes,
|
||||
) -> Option<BackgroundLayer> {
|
||||
let painting_area = painter.painting_area(fragment_builder, builder, layer_index);
|
||||
let positioning_area = painter.positioning_area(fragment_builder, layer_index);
|
||||
|
@ -180,19 +180,19 @@ pub(super) fn layout_layer(
|
|||
}
|
||||
let size_contain_or_cover = |background_size| {
|
||||
let mut tile_size = positioning_area.size();
|
||||
if let Some(intrinsic_ratio) = intrinsic.ratio {
|
||||
if let Some(natural_ratio) = natural_sizes.ratio {
|
||||
let positioning_ratio = positioning_area.size().width / positioning_area.size().height;
|
||||
// Whether the tile width (as opposed to height)
|
||||
// is scaled to that of the positioning area
|
||||
let fit_width = match background_size {
|
||||
ContainOrCover::Contain => positioning_ratio <= intrinsic_ratio,
|
||||
ContainOrCover::Cover => positioning_ratio > intrinsic_ratio,
|
||||
ContainOrCover::Contain => positioning_ratio <= natural_ratio,
|
||||
ContainOrCover::Cover => positioning_ratio > natural_ratio,
|
||||
};
|
||||
// The other dimension needs to be adjusted
|
||||
if fit_width {
|
||||
tile_size.height = tile_size.width / intrinsic_ratio
|
||||
tile_size.height = tile_size.width / natural_ratio
|
||||
} else {
|
||||
tile_size.width = tile_size.height * intrinsic_ratio
|
||||
tile_size.width = tile_size.height * natural_ratio
|
||||
}
|
||||
}
|
||||
tile_size
|
||||
|
@ -212,18 +212,18 @@ pub(super) fn layout_layer(
|
|||
|
||||
if width.is_none() && height.is_none() {
|
||||
// Both computed values are 'auto':
|
||||
// use intrinsic sizes, treating missing width or height as 'auto'
|
||||
width = intrinsic.width;
|
||||
height = intrinsic.height;
|
||||
// use natural sizes, treating missing width or height as 'auto'
|
||||
width = natural_sizes.width;
|
||||
height = natural_sizes.height;
|
||||
}
|
||||
|
||||
match (width, height) {
|
||||
(Some(w), Some(h)) => units::LayoutSize::new(w.to_f32_px(), h.to_f32_px()),
|
||||
(Some(w), None) => {
|
||||
let h = if let Some(intrinsic_ratio) = intrinsic.ratio {
|
||||
w.scale_by(1.0 / intrinsic_ratio)
|
||||
} else if let Some(intrinsic_height) = intrinsic.height {
|
||||
intrinsic_height
|
||||
let h = if let Some(natural_ratio) = natural_sizes.ratio {
|
||||
w.scale_by(1.0 / natural_ratio)
|
||||
} else if let Some(natural_height) = natural_sizes.height {
|
||||
natural_height
|
||||
} else {
|
||||
// Treated as 100%
|
||||
Au::from_f32_px(positioning_area.size().height)
|
||||
|
@ -231,17 +231,17 @@ pub(super) fn layout_layer(
|
|||
units::LayoutSize::new(w.to_f32_px(), h.to_f32_px())
|
||||
},
|
||||
(None, Some(h)) => {
|
||||
let w = if let Some(intrinsic_ratio) = intrinsic.ratio {
|
||||
h.scale_by(intrinsic_ratio)
|
||||
} else if let Some(intrinsic_width) = intrinsic.width {
|
||||
intrinsic_width
|
||||
let w = if let Some(natural_ratio) = natural_sizes.ratio {
|
||||
h.scale_by(natural_ratio)
|
||||
} else if let Some(natural_width) = natural_sizes.width {
|
||||
natural_width
|
||||
} else {
|
||||
// Treated as 100%
|
||||
Au::from_f32_px(positioning_area.size().width)
|
||||
};
|
||||
units::LayoutSize::new(w.to_f32_px(), h.to_f32_px())
|
||||
},
|
||||
// Both comptued values were 'auto', and neither intrinsic size is present
|
||||
// Both comptued values were 'auto', and neither natural size is present
|
||||
(None, None) => size_contain_or_cover(ContainOrCover::Contain),
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
use app_units::Au;
|
||||
use style::color::AbsoluteColor;
|
||||
use style::computed_values::image_rendering::T as ComputedImageRendering;
|
||||
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
|
||||
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
|
||||
use style::computed_values::transform_style::T as ComputedTransformStyle;
|
||||
use style::values::computed::Filter as ComputedFilter;
|
||||
use style::values::specified::border::BorderImageRepeatKeyword;
|
||||
use webrender_api::{units, FilterOp, LineStyle, MixBlendMode, RepeatMode, Shadow, TransformStyle};
|
||||
use webrender_api::{
|
||||
units, FilterOp, ImageRendering, LineStyle, MixBlendMode, RepeatMode, Shadow, TransformStyle,
|
||||
};
|
||||
|
||||
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
|
||||
|
||||
|
@ -142,3 +145,15 @@ impl ToWebRender for BorderImageRepeatKeyword {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToWebRender for ComputedImageRendering {
|
||||
type Type = ImageRendering;
|
||||
|
||||
fn to_webrender(&self) -> Self::Type {
|
||||
match self {
|
||||
ComputedImageRendering::Auto => ImageRendering::Auto,
|
||||
ComputedImageRendering::CrispEdges => ImageRendering::CrispEdges,
|
||||
ComputedImageRendering::Pixelated => ImageRendering::Pixelated,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ use crate::fragment_tree::{
|
|||
BackgroundMode, BoxFragment, Fragment, FragmentFlags, FragmentTree, Tag, TextFragment,
|
||||
};
|
||||
use crate::geom::{PhysicalPoint, PhysicalRect};
|
||||
use crate::replaced::IntrinsicSizes;
|
||||
use crate::replaced::NaturalSizes;
|
||||
use crate::style_ext::ComputedValuesExt;
|
||||
|
||||
mod background;
|
||||
|
@ -272,18 +272,31 @@ impl Fragment {
|
|||
);
|
||||
}
|
||||
},
|
||||
Fragment::Image(i) => match i.style.get_inherited_box().visibility {
|
||||
Fragment::Image(image) => match image.style.get_inherited_box().visibility {
|
||||
Visibility::Visible => {
|
||||
builder.is_contentful = true;
|
||||
let rect = i.rect.translate(containing_block.origin.to_vector());
|
||||
|
||||
let common = builder.common_properties(rect.to_webrender(), &i.style);
|
||||
let image_rendering = image
|
||||
.style
|
||||
.get_inherited_box()
|
||||
.image_rendering
|
||||
.to_webrender();
|
||||
let rect = image
|
||||
.rect
|
||||
.translate(containing_block.origin.to_vector())
|
||||
.to_webrender();
|
||||
let clip = image
|
||||
.clip
|
||||
.translate(containing_block.origin.to_vector())
|
||||
.to_webrender();
|
||||
let common = builder.common_properties(clip, &image.style);
|
||||
|
||||
builder.wr().push_image(
|
||||
&common,
|
||||
rect.to_webrender(),
|
||||
image_rendering(i.style.get_inherited_box().image_rendering),
|
||||
rect,
|
||||
image_rendering,
|
||||
wr::AlphaType::PremultipliedAlpha,
|
||||
i.image_key,
|
||||
image.image_key,
|
||||
wr::ColorF::WHITE,
|
||||
);
|
||||
},
|
||||
|
@ -736,7 +749,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
match image {
|
||||
Image::None => {},
|
||||
Image::Gradient(ref gradient) => {
|
||||
let intrinsic = IntrinsicSizes::empty();
|
||||
let intrinsic = NaturalSizes::empty();
|
||||
let Some(layer) =
|
||||
&background::layout_layer(self, painter, builder, index, intrinsic)
|
||||
else {
|
||||
|
@ -801,7 +814,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
|
||||
// FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution
|
||||
let dppx = 1.0;
|
||||
let intrinsic = IntrinsicSizes::from_width_and_height(
|
||||
let intrinsic = NaturalSizes::from_width_and_height(
|
||||
width as f32 / dppx,
|
||||
height as f32 / dppx,
|
||||
);
|
||||
|
@ -809,14 +822,13 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
if let Some(layer) =
|
||||
background::layout_layer(self, painter, builder, index, intrinsic)
|
||||
{
|
||||
let image_rendering = image_rendering(style.clone_image_rendering());
|
||||
if layer.repeat {
|
||||
builder.wr().push_repeating_image(
|
||||
&layer.common,
|
||||
layer.bounds,
|
||||
layer.tile_size,
|
||||
layer.tile_spacing,
|
||||
image_rendering,
|
||||
style.clone_image_rendering().to_webrender(),
|
||||
wr::AlphaType::PremultipliedAlpha,
|
||||
key,
|
||||
wr::ColorF::WHITE,
|
||||
|
@ -825,7 +837,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
builder.wr().push_image(
|
||||
&layer.common,
|
||||
layer.bounds,
|
||||
image_rendering,
|
||||
style.clone_image_rendering().to_webrender(),
|
||||
wr::AlphaType::PremultipliedAlpha,
|
||||
key,
|
||||
wr::ColorF::WHITE,
|
||||
|
@ -1142,15 +1154,6 @@ fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
fn image_rendering(ir: style::computed_values::image_rendering::T) -> wr::ImageRendering {
|
||||
use style::computed_values::image_rendering::T as ImageRendering;
|
||||
match ir {
|
||||
ImageRendering::Auto => wr::ImageRendering::Auto,
|
||||
ImageRendering::CrispEdges => wr::ImageRendering::CrispEdges,
|
||||
ImageRendering::Pixelated => wr::ImageRendering::Pixelated,
|
||||
}
|
||||
}
|
||||
|
||||
/// Radii for the padding edge or content edge
|
||||
fn inner_radii(mut radii: wr::BorderRadius, insets: units::LayoutSideOffsets) -> wr::BorderRadius {
|
||||
assert!(insets.left >= 0.0, "left inset must not be negative");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue