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:
Martin Robinson 2024-09-18 08:20:28 +02:00 committed by GitHub
parent 632d832704
commit bd632fc814
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 169 additions and 563 deletions

28
Cargo.lock generated
View file

@ -1308,7 +1308,7 @@ dependencies = [
[[package]]
name = "derive_common"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"darling",
"proc-macro2",
@ -1496,7 +1496,7 @@ dependencies = [
[[package]]
name = "dom"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"bitflags 2.6.0",
]
@ -4131,7 +4131,7 @@ dependencies = [
[[package]]
name = "malloc_size_of"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"accountable-refcell",
"app_units",
@ -5915,7 +5915,7 @@ dependencies = [
[[package]]
name = "selectors"
version = "0.24.0"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"bitflags 2.6.0",
"cssparser",
@ -6203,7 +6203,7 @@ dependencies = [
[[package]]
name = "servo_arc"
version = "0.2.0"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"serde",
"stable_deref_trait",
@ -6212,7 +6212,7 @@ dependencies = [
[[package]]
name = "servo_atoms"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"string_cache",
"string_cache_codegen",
@ -6430,7 +6430,7 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "size_of_test"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"static_assertions",
]
@ -6571,7 +6571,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "static_prefs"
version = "0.1.0"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
[[package]]
name = "strck"
@ -6624,7 +6624,7 @@ dependencies = [
[[package]]
name = "style"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"app_units",
"arrayvec",
@ -6682,7 +6682,7 @@ dependencies = [
[[package]]
name = "style_config"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"lazy_static",
]
@ -6690,7 +6690,7 @@ dependencies = [
[[package]]
name = "style_derive"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"darling",
"derive_common",
@ -6721,7 +6721,7 @@ dependencies = [
[[package]]
name = "style_traits"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"app_units",
"bitflags 2.6.0",
@ -7088,7 +7088,7 @@ dependencies = [
[[package]]
name = "to_shmem"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"cssparser",
"servo_arc",
@ -7101,7 +7101,7 @@ dependencies = [
[[package]]
name = "to_shmem_derive"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#25daa6b91d77ced8498f0a729d311e4292328313"
source = "git+https://github.com/servo/stylo?branch=2024-09-02#1d95da7aec9de466cf0a16d832b6993dad4228fe"
dependencies = [
"darling",
"derive_common",

View file

@ -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),
}
},

View file

@ -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,
}
}
}

View file

@ -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");

View file

@ -1772,6 +1772,7 @@ impl FlexItem<'_> {
let cross_size = flex_axis.vec2_to_flex_relative(size).cross;
let fragments = replaced.contents.make_fragments(
&replaced.style,
containing_block,
size.to_physical_size(container_writing_mode),
);

View file

@ -992,6 +992,7 @@ impl FloatBox {
);
children = replaced.contents.make_fragments(
&replaced.style,
containing_block,
content_size.to_physical_size(containing_block.style.writing_mode),
)
},

View file

@ -1917,7 +1917,11 @@ impl IndependentFormattingContext {
.contents
.used_size_as_if_inline_element(layout.containing_block, &replaced.style, &pbm)
.to_physical_size(container_writing_mode);
let fragments = replaced.contents.make_fragments(&replaced.style, size);
let fragments = replaced.contents.make_fragments(
&replaced.style,
layout.containing_block,
size,
);
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), size);
(fragments, content_rect, None, None)

View file

@ -1307,7 +1307,7 @@ fn layout_in_flow_replaced_block_level(
let containing_block_writing_mode = containing_block.style.writing_mode;
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
let fragments = replaced.make_fragments(style, physical_content_size);
let fragments = replaced.make_fragments(style, containing_block, physical_content_size);
let clearance;
if let Some(ref mut sequential_layout_state) = sequential_layout_state {

View file

@ -83,6 +83,7 @@ pub(crate) struct ImageFragment {
#[serde(skip_serializing)]
pub style: ServoArc<ComputedValues>,
pub rect: PhysicalRect<Au>,
pub clip: PhysicalRect<Au>,
#[serde(skip_serializing)]
pub image_key: ImageKey,
}

View file

@ -552,6 +552,7 @@ impl HoistedAbsolutelyPositionedBox {
content_size = computed_size.auto_is(|| unreachable!());
fragments = replaced.contents.make_fragments(
&style,
&containing_block.into(),
content_size.to_physical_size(containing_block_writing_mode),
);
},

View file

@ -14,6 +14,7 @@ use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use pixels::Image;
use serde::Serialize;
use servo_arc::Arc as ServoArc;
use style::computed_values::object_fit::T as ObjectFit;
use style::logical_geometry::Direction;
use style::properties::ComputedValues;
use style::servo::url::ComputedUrl;
@ -35,32 +36,35 @@ use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
#[derive(Debug, Serialize)]
pub(crate) struct ReplacedContent {
pub kind: ReplacedContentKind,
intrinsic: IntrinsicSizes,
natural_size: NaturalSizes,
base_fragment_info: BaseFragmentInfo,
}
/// * Raster images always have an intrinsic width and height, with 1 image pixel = 1px.
/// The intrinsic ratio should be based on dividing those.
/// The natural dimensions of a replaced element, including a height, width, and
/// aspect ratio.
///
/// * Raster images always have an natural width and height, with 1 image pixel = 1px.
/// The natural ratio should be based on dividing those.
/// See <https://github.com/w3c/csswg-drafts/issues/4572> for the case where either is zero.
/// PNG specifically disallows this but I (SimonSapin) am not sure about other formats.
///
/// * Form controls have both intrinsic width and height **but no intrinsic ratio**.
/// * Form controls have both natural width and height **but no natural ratio**.
/// See <https://github.com/w3c/csswg-drafts/issues/1044> and
/// <https://drafts.csswg.org/css-images/#intrinsic-dimensions> “In general, […]”
/// <https://drafts.csswg.org/css-images/#natural-dimensions> “In general, […]”
///
/// * For SVG, see <https://svgwg.org/svg2-draft/coords.html#SizingSVGInCSS>
/// and again <https://github.com/w3c/csswg-drafts/issues/4572>.
///
/// * IFrames do not have intrinsic width and height or intrinsic ratio according
/// * IFrames do not have natural width and height or natural ratio according
/// to <https://drafts.csswg.org/css-images/#intrinsic-dimensions>.
#[derive(Debug, Serialize)]
pub(crate) struct IntrinsicSizes {
pub(crate) struct NaturalSizes {
pub width: Option<Au>,
pub height: Option<Au>,
pub ratio: Option<CSSFloat>,
}
impl IntrinsicSizes {
impl NaturalSizes {
pub(crate) fn from_width_and_height(width: f32, height: f32) -> Self {
// https://drafts.csswg.org/css-images/#natural-aspect-ratio:
// "If an object has a degenerate natural aspect ratio (at least one part being
@ -145,16 +149,16 @@ impl ReplacedContent {
}
}
let (kind, intrinsic_size_in_dots) = {
if let Some((image, intrinsic_size_in_dots)) = element.as_image() {
let (kind, natural_size_in_dots) = {
if let Some((image, natural_size_in_dots)) = element.as_image() {
(
ReplacedContentKind::Image(image),
Some(intrinsic_size_in_dots),
Some(natural_size_in_dots),
)
} else if let Some((canvas_info, intrinsic_size_in_dots)) = element.as_canvas() {
} else if let Some((canvas_info, natural_size_in_dots)) = element.as_canvas() {
(
ReplacedContentKind::Canvas(canvas_info),
Some(intrinsic_size_in_dots),
Some(natural_size_in_dots),
)
} else if let Some((pipeline_id, browsing_context_id)) = element.as_iframe() {
(
@ -164,31 +168,31 @@ impl ReplacedContent {
}),
None,
)
} else if let Some((image_key, intrinsic_size_in_dots)) = element.as_video() {
} else if let Some((image_key, natural_size_in_dots)) = element.as_video() {
(
ReplacedContentKind::Video(VideoInfo { image_key }),
Some(intrinsic_size_in_dots),
Some(natural_size_in_dots),
)
} else {
return None;
}
};
let intrinsic =
intrinsic_size_in_dots.map_or_else(IntrinsicSizes::empty, |intrinsic_size_in_dots| {
let natural_size =
natural_size_in_dots.map_or_else(NaturalSizes::empty, |naturalc_size_in_dots| {
// FIXME: should 'image-resolution' (when implemented) be used *instead* of
// `script::dom::htmlimageelement::ImageRequest::current_pixel_density`?
// https://drafts.csswg.org/css-images-4/#the-image-resolution
let dppx = 1.0;
let width = (intrinsic_size_in_dots.width as CSSFloat) / dppx;
let height = (intrinsic_size_in_dots.height as CSSFloat) / dppx;
IntrinsicSizes::from_width_and_height(width, height)
let width = (naturalc_size_in_dots.width as CSSFloat) / dppx;
let height = (naturalc_size_in_dots.height as CSSFloat) / dppx;
NaturalSizes::from_width_and_height(width, height)
});
let base_fragment_info = BaseFragmentInfo::new_for_node(element.opaque());
Some(Self {
kind,
intrinsic,
natural_size,
base_fragment_info,
})
}
@ -215,7 +219,7 @@ impl ReplacedContent {
return Some(Self {
kind: ReplacedContentKind::Image(image),
intrinsic: IntrinsicSizes::from_width_and_height(width, height),
natural_size: NaturalSizes::from_width_and_height(width, height),
base_fragment_info: BaseFragmentInfo::new_for_node(element.opaque()),
});
}
@ -234,7 +238,7 @@ impl ReplacedContent {
}
fn flow_relative_intrinsic_size(&self, style: &ComputedValues) -> LogicalVec2<Option<Au>> {
let intrinsic_size = PhysicalSize::new(self.intrinsic.width, self.intrinsic.height);
let intrinsic_size = PhysicalSize::new(self.natural_size.width, self.natural_size.height);
LogicalVec2::from_physical_size(&intrinsic_size, style.writing_mode)
}
@ -242,7 +246,7 @@ impl ReplacedContent {
&self,
style: &ComputedValues,
) -> Option<CSSFloat> {
self.intrinsic.ratio.map(|width_over_height| {
self.natural_size.ratio.map(|width_over_height| {
if style.writing_mode.is_vertical() {
1. / width_over_height
} else {
@ -276,9 +280,61 @@ impl ReplacedContent {
pub fn make_fragments(
&self,
style: &ServoArc<ComputedValues>,
containing_block: &ContainingBlock,
size: PhysicalSize<Au>,
) -> Vec<Fragment> {
let rect = PhysicalRect::new(PhysicalPoint::origin(), size);
let aspect_ratio = self.preferred_aspect_ratio(&containing_block.into(), style);
let natural_size = PhysicalSize::new(
self.natural_size.width.unwrap_or(size.width),
self.natural_size.height.unwrap_or(size.height),
);
let object_fit_size = aspect_ratio.map_or(size, |aspect_ratio| {
let preserve_aspect_ratio_with_comparison =
|size: PhysicalSize<Au>, comparison: fn(&Au, &Au) -> bool| {
let (width_axis, height_axis) = if style.writing_mode.is_horizontal() {
(Direction::Inline, Direction::Block)
} else {
(Direction::Block, Direction::Inline)
};
let candidate_width =
aspect_ratio.compute_dependent_size(width_axis, size.height);
if comparison(&candidate_width, &size.width) {
return PhysicalSize::new(candidate_width, size.height);
}
let candidate_height =
aspect_ratio.compute_dependent_size(height_axis, size.width);
debug_assert!(comparison(&candidate_height, &size.height));
PhysicalSize::new(size.width, candidate_height)
};
match style.clone_object_fit() {
ObjectFit::Fill => size,
ObjectFit::Contain => preserve_aspect_ratio_with_comparison(size, PartialOrd::le),
ObjectFit::Cover => preserve_aspect_ratio_with_comparison(size, PartialOrd::ge),
ObjectFit::None => natural_size,
ObjectFit::ScaleDown => {
preserve_aspect_ratio_with_comparison(size.min(natural_size), PartialOrd::le)
},
}
});
let object_position = style.clone_object_position();
let horizontal_position = object_position
.horizontal
.to_used_value(size.width - object_fit_size.width);
let vertical_position = object_position
.vertical
.to_used_value(size.height - object_fit_size.height);
let rect = PhysicalRect::new(
PhysicalPoint::new(horizontal_position, vertical_position),
object_fit_size,
);
let clip = PhysicalRect::new(PhysicalPoint::origin(), size);
match &self.kind {
ReplacedContentKind::Image(image) => image
.as_ref()
@ -288,6 +344,7 @@ impl ReplacedContent {
base: self.base_fragment_info.into(),
style: style.clone(),
rect,
clip,
image_key,
})
})
@ -297,6 +354,7 @@ impl ReplacedContent {
base: self.base_fragment_info.into(),
style: style.clone(),
rect,
clip,
image_key: video.image_key,
})],
ReplacedContentKind::IFrame(iframe) => {
@ -309,8 +367,8 @@ impl ReplacedContent {
})]
},
ReplacedContentKind::Canvas(canvas_info) => {
if self.intrinsic.width == Some(Au::zero()) ||
self.intrinsic.height == Some(Au::zero())
if self.natural_size.width == Some(Au::zero()) ||
self.natural_size.height == Some(Au::zero())
{
return vec![];
}
@ -337,6 +395,7 @@ impl ReplacedContent {
base: self.base_fragment_info.into(),
style: style.clone(),
rect,
clip,
image_key,
})]
},

View file

@ -1,67 +1,4 @@
[object-position-interpolation.html]
[CSS Transitions: property <object-position> from neutral to [left top\] at (-0.25) should be [62.5% 62.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from neutral to [left top\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from neutral to [left top\] at (0.25) should be [37.5% 37.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from neutral to [left top\] at (0.5) should be [25% 25%\]]
expected: FAIL
[CSS Transitions: property <object-position> from neutral to [left top\] at (0.75) should be [12.5% 12.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from neutral to [left top\] at (1) should be [0% 0%\]]
expected: FAIL
[CSS Transitions: property <object-position> from neutral to [left top\] at (1.25) should be [-12.5% -12.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (-0.25) should be [62.5% 62.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (0.25) should be [37.5% 37.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (0.5) should be [25% 25%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (0.75) should be [12.5% 12.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (1) should be [0% 0%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from neutral to [left top\] at (1.25) should be [-12.5% -12.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (-0.25) should be [62.5% 62.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (0.25) should be [37.5% 37.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (0.5) should be [25% 25%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (0.75) should be [12.5% 12.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (1) should be [0% 0%\]]
expected: FAIL
[CSS Animations: property <object-position> from neutral to [left top\] at (1.25) should be [-12.5% -12.5%\]]
expected: FAIL
[Web Animations: property <object-position> from neutral to [left top\] at (-0.25) should be [62.5% 62.5%\]]
expected: FAIL
@ -83,69 +20,6 @@
[Web Animations: property <object-position> from neutral to [left top\] at (1.25) should be [-12.5% -12.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (-0.25) should be [50% 62.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (0.25) should be [50% 37.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (0.5) should be [50% 25%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (0.75) should be [50% 12.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (1) should be [50% 0%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [center top\] at (1.25) should be [50% -12.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (-0.25) should be [50% 62.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (0.25) should be [50% 37.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (0.5) should be [50% 25%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (0.75) should be [50% 12.5%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (1) should be [50% 0%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [center top\] at (1.25) should be [50% -12.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (-0.25) should be [50% 62.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (0.25) should be [50% 37.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (0.5) should be [50% 25%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (0.75) should be [50% 12.5%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (1) should be [50% 0%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [center top\] at (1.25) should be [50% -12.5%\]]
expected: FAIL
[Web Animations: property <object-position> from [initial\] to [center top\] at (-0.25) should be [50% 62.5%\]]
expected: FAIL
@ -167,69 +41,6 @@
[Web Animations: property <object-position> from [initial\] to [center top\] at (1.25) should be [50% -12.5%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (-0.25) should be [62.5% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (0.25) should be [37.5% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (0.5) should be [25% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (0.75) should be [12.5% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (1) should be [0% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [initial\] to [left center\] at (1.25) should be [-12.5% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (-0.25) should be [62.5% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (0.25) should be [37.5% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (0.5) should be [25% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (0.75) should be [12.5% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (1) should be [0% 50%\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [initial\] to [left center\] at (1.25) should be [-12.5% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (-0.25) should be [62.5% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (0) should be [50% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (0.25) should be [37.5% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (0.5) should be [25% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (0.75) should be [12.5% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (1) should be [0% 50%\]]
expected: FAIL
[CSS Animations: property <object-position> from [initial\] to [left center\] at (1.25) should be [-12.5% 50%\]]
expected: FAIL
[Web Animations: property <object-position> from [initial\] to [left center\] at (-0.25) should be [62.5% 50%\]]
expected: FAIL
@ -251,69 +62,6 @@
[Web Animations: property <object-position> from [initial\] to [left center\] at (1.25) should be [-12.5% 50%\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (-0.25) should be [0px 0px\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (0) should be [20px 20px\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (0.25) should be [40px 40px\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (0.5) should be [60px 60px\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (0.75) should be [80px 80px\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (1) should be [100px 100px\]]
expected: FAIL
[CSS Transitions: property <object-position> from [20px 20px\] to [100px 100px\] at (1.25) should be [120px 120px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (-0.25) should be [0px 0px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (0) should be [20px 20px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (0.25) should be [40px 40px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (0.5) should be [60px 60px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (0.75) should be [80px 80px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (1) should be [100px 100px\]]
expected: FAIL
[CSS Transitions with transition: all: property <object-position> from [20px 20px\] to [100px 100px\] at (1.25) should be [120px 120px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (-0.25) should be [0px 0px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (0) should be [20px 20px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (0.25) should be [40px 40px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (0.5) should be [60px 60px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (0.75) should be [80px 80px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (1) should be [100px 100px\]]
expected: FAIL
[CSS Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (1.25) should be [120px 120px\]]
expected: FAIL
[Web Animations: property <object-position> from [20px 20px\] to [100px 100px\] at (-0.25) should be [0px 0px\]]
expected: FAIL

View file

@ -4,15 +4,3 @@
[Property image-orientation inherits]
expected: FAIL
[Property object-fit has initial value fill]
expected: FAIL
[Property object-fit does not inherit]
expected: FAIL
[Property object-position has initial value 50% 50%]
expected: FAIL
[Property object-position does not inherit]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-contain-png-001c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-contain-png-001i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-contain-png-001p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-contain-png-002c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-contain-png-002i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-contain-png-002p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-containsize-png-001c.tentative.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-containsize-png-001i.tentative.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-containsize-png-001p.tentative.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-cover-png-001c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-cover-png-001i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-cover-png-001p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-cover-png-002c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-cover-png-002i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-cover-png-002p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-fill-png-001c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-fill-png-001i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-fill-png-001p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-fill-png-002c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-fill-png-002i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-fill-png-002p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-none-png-001c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-none-png-001i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-none-png-001p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-none-png-002c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-none-png-002i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-none-png-002p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-scale-down-png-001c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-scale-down-png-001i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-scale-down-png-001p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-scale-down-png-002c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-scale-down-png-002i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-fit-scale-down-png-002p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-position-png-001c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-position-png-001i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-position-png-001p.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-position-png-002c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-position-png-002i.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[object-position-png-002p.html]
expected: FAIL

View file

@ -1,18 +1,3 @@
[object-fit-computed.html]
[Property object-fit value 'contain']
expected: FAIL
[Property object-fit value 'cover']
expected: FAIL
[Property object-fit value 'cover scale-down']
expected: FAIL
[Property object-fit value 'fill']
expected: FAIL
[Property object-fit value 'none']
expected: FAIL
[Property object-fit value 'scale-down']
expected: FAIL

View file

@ -1,25 +1,10 @@
[object-fit-valid.html]
[e.style['object-fit'\] = "contain" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "contain scale-down" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "cover" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "cover scale-down" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "fill" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "none" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "scale-down" should set the property value]
expected: FAIL
[e.style['object-fit'\] = "scale-down contain" should set the property value]
expected: FAIL

View file

@ -1,48 +0,0 @@
[object-position-computed.html]
[Property object-position value '10% center']
expected: FAIL
[Property object-position value 'right 30% top 60px']
expected: FAIL
[Property object-position value '-20% -30px']
expected: FAIL
[Property object-position value '30px center']
expected: FAIL
[Property object-position value '40px top']
expected: FAIL
[Property object-position value 'right 20% bottom 10%']
expected: FAIL
[Property object-position value 'right bottom']
expected: FAIL
[Property object-position value 'center 50px']
expected: FAIL
[Property object-position value 'center bottom']
expected: FAIL
[Property object-position value 'left center']
expected: FAIL
[Property object-position value 'left bottom']
expected: FAIL
[Property object-position value 'right 40%']
expected: FAIL
[Property object-position value 'center top']
expected: FAIL
[Property object-position value 'center']
expected: FAIL
[Property object-position value 'center center']
expected: FAIL
[Property object-position value 'right 20px bottom 10px']
expected: FAIL

View file

@ -1,54 +0,0 @@
[object-position-valid.html]
[e.style['object-position'\] = "10%" should set the property value]
expected: FAIL
[e.style['object-position'\] = "right 30% top 60px" should set the property value]
expected: FAIL
[e.style['object-position'\] = "-20% -30px" should set the property value]
expected: FAIL
[e.style['object-position'\] = "30px center" should set the property value]
expected: FAIL
[e.style['object-position'\] = "40px top" should set the property value]
expected: FAIL
[e.style['object-position'\] = "bottom 10% right 20%" should set the property value]
expected: FAIL
[e.style['object-position'\] = "bottom right" should set the property value]
expected: FAIL
[e.style['object-position'\] = "center 50px" should set the property value]
expected: FAIL
[e.style['object-position'\] = "center bottom" should set the property value]
expected: FAIL
[e.style['object-position'\] = "center left" should set the property value]
expected: FAIL
[e.style['object-position'\] = "left" should set the property value]
expected: FAIL
[e.style['object-position'\] = "left bottom" should set the property value]
expected: FAIL
[e.style['object-position'\] = "left center" should set the property value]
expected: FAIL
[e.style['object-position'\] = "right 40%" should set the property value]
expected: FAIL
[e.style['object-position'\] = "top" should set the property value]
expected: FAIL
[e.style['object-position'\] = "top center" should set the property value]
expected: FAIL
[e.style['object-position'\] = "center" should set the property value]
expected: FAIL
[e.style['object-position'\] = "center center" should set the property value]
expected: FAIL

View file

@ -1,2 +0,0 @@
[canvas-update-with-border-object-fit.html]
expected: FAIL

View file

@ -7,6 +7,3 @@
[Property mask does not support quirky length]
expected: FAIL
[Property object-position does not support quirky length]
expected: FAIL