LibWeb: Obey CSS aspect-ratio property during layout

Calculate a "preferred aspect ratio" based on the value of
`aspect-ratio` and the presence of a natural aspect ratio, and use that
in layout.

This is by no means complete or perfect, but we do now apply the given
aspect-ratio to things.

The spec is a bit vague, just saying to calculate sizes for
aspect-ratio'ed boxes the same as you would for replaced elements. My
naive solution here is to find everywhere we were checking for a
ReplacedBox, and then also accept a regular Box with a preferred aspect
ratio. This gets us pretty far. :^)

https://www.w3.org/TR/css-sizing-4/#aspect-ratio-minimum is not at all
implemented.
This commit is contained in:
Sam Atkins 2023-06-08 16:47:50 +01:00 committed by Andreas Kling
parent 84e7216603
commit 1051624084
Notes: sideshowbarker 2024-07-17 04:10:16 +09:00
14 changed files with 131 additions and 55 deletions

View File

@ -0,0 +1,9 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x320 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x304 children: not-inline
BlockContainer <div> at (9,9) content-size 200x100 children: not-inline
BlockContainer <(anonymous)> at (8,110) content-size 784x202 children: inline
line 0 width: 202, height: 202, bottom: 202, baseline: 202
frag 0 from ImageBox start: 0, length: 0, rect: [9,111 200x200]
ImageBox <img> at (9,111) content-size 200x200 children: not-inline
TextNode <#text>

View File

@ -0,0 +1,9 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x220 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x204 children: not-inline
BlockContainer <div> at (9,9) content-size 200x0 children: not-inline
BlockContainer <(anonymous)> at (8,10) content-size 784x202 children: inline
line 0 width: 202, height: 202, bottom: 202, baseline: 202
frag 0 from ImageBox start: 0, length: 0, rect: [9,11 200x200]
ImageBox <img> at (9,11) content-size 200x200 children: not-inline
TextNode <#text>

View File

@ -0,0 +1,9 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x220 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x204 children: not-inline
BlockContainer <div> at (9,9) content-size 200x100 children: not-inline
BlockContainer <(anonymous)> at (8,110) content-size 784x102 children: inline
line 0 width: 202, height: 102, bottom: 102, baseline: 102
frag 0 from ImageBox start: 0, length: 0, rect: [9,111 200x100]
ImageBox <img> at (9,111) content-size 200x100 children: not-inline
TextNode <#text>

View File

@ -0,0 +1,7 @@
<!doctype html><style>
div, img {
width: 200px;
aspect-ratio: auto 2/1;
border: 1px solid black;
}
</style><div></div><img src="120.png"/>

View File

@ -0,0 +1,7 @@
<!doctype html><style>
div, img {
width: 200px;
aspect-ratio: auto;
border: 1px solid black;
}
</style><div></div><img src="120.png"/>

View File

@ -0,0 +1,7 @@
<!doctype html><style>
div, img {
width: 200px;
aspect-ratio: 2/1;
border: 1px solid black;
}
</style><div></div><img src="120.png"/>

View File

@ -54,6 +54,9 @@ static bool margins_collapse_through(Box const& box, LayoutState& state)
// nor top or bottom padding, and it has a 'height' of either 0 or 'auto', and it does not contain a line box, and
// all of its in-flow children's margins (if any) collapse.
// https://www.w3.org/TR/CSS22/box.html#collapsing-margins
// FIXME: For the purpose of margin collapsing (CSS 2 §8.3.1 Collapsing margins), if the block axis is the
// ratio-dependent axis, it is not considered to have a computed block-size of auto.
// https://www.w3.org/TR/css-sizing-4/#aspect-ratio-margin-collapse
return state.get(box).border_box_height() == 0;
}
@ -130,12 +133,14 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
remaining_available_space.width = AvailableSize::make_definite(remaining_width);
}
if (is<ReplacedBox>(box)) {
if (box_is_sized_as_replaced_element(box)) {
// FIXME: This should not be done *by* ReplacedBox
auto& replaced = verify_cast<ReplacedBox>(box);
// FIXME: This const_cast is gross.
const_cast<ReplacedBox&>(replaced).prepare_for_replaced_layout();
compute_width_for_block_level_replaced_element_in_normal_flow(replaced, remaining_available_space);
if (is<ReplacedBox>(box)) {
auto& replaced = verify_cast<ReplacedBox>(box);
// FIXME: This const_cast is gross.
const_cast<ReplacedBox&>(replaced).prepare_for_replaced_layout();
}
compute_width_for_block_level_replaced_element_in_normal_flow(box, remaining_available_space);
if (box.is_floating()) {
// 10.3.6 Floating, replaced elements:
// https://www.w3.org/TR/CSS22/visudet.html#float-replaced-width
@ -231,7 +236,7 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
};
auto input_width = [&] {
if (is<ReplacedBox>(box)) {
if (box_is_sized_as_replaced_element(box)) {
// NOTE: Replaced elements had their width calculated independently above.
// We use that width as the input here to ensure that margins get resolved.
return CSS::Length::make_px(box_state.content_width());
@ -266,7 +271,7 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
}
}
if (!is<ReplacedBox>(box) && !used_width.is_auto())
if (!box_is_sized_as_replaced_element(box) && !used_width.is_auto())
box_state.set_content_width(used_width.to_px(box));
box_state.margin_left = margin_left.to_px(box);
@ -350,7 +355,7 @@ void BlockFormattingContext::compute_width_for_floating_box(Box const& box, Avai
box_state.padding_right = padding_right;
}
void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox const& box, AvailableSpace const& available_space)
void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_normal_flow(Box const& box, AvailableSpace const& available_space)
{
// 10.3.6 Floating, replaced elements
auto& computed_values = box.computed_values();
@ -436,8 +441,8 @@ void BlockFormattingContext::compute_height(Box const& box, AvailableSpace const
// Then work out what the height is, based on box type and CSS properties.
CSSPixels height = 0;
if (is<ReplacedBox>(box)) {
height = compute_height_for_replaced_element(verify_cast<ReplacedBox>(box), available_space);
if (box_is_sized_as_replaced_element(box)) {
height = compute_height_for_replaced_element(box, available_space);
} else {
if (should_treat_height_as_auto(box, available_space)) {
height = compute_auto_height_for_block_level_element(box, m_state.get(box).available_inner_space_or_constraints_from(available_space));

View File

@ -57,7 +57,7 @@ private:
void compute_width_for_floating_box(Box const&, AvailableSpace const&);
void compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox const&, AvailableSpace const&);
void compute_width_for_block_level_replaced_element_in_normal_flow(Box const&, AvailableSpace const&);
CSSPixels compute_table_box_width_inside_table_wrapper(Box const&, AvailableSpace const&);

View File

@ -91,4 +91,12 @@ Painting::PaintableBox const* Box::paintable_box() const
return static_cast<Painting::PaintableBox const*>(Node::paintable());
}
Optional<float> Box::preferred_aspect_ratio() const
{
auto computed_aspect_ratio = computed_values().aspect_ratio();
if (computed_aspect_ratio.use_natural_aspect_ratio_if_available && natural_aspect_ratio().has_value())
return natural_aspect_ratio();
return computed_aspect_ratio.preferred_ratio.map([](CSS::Ratio const& ratio) { return ratio.value(); });
}
}

View File

@ -41,6 +41,10 @@ public:
void set_natural_height(Optional<CSSPixels> height) { m_natural_height = height; }
void set_natural_aspect_ratio(Optional<float> ratio) { m_natural_aspect_ratio = ratio; }
// https://www.w3.org/TR/css-sizing-4/#preferred-aspect-ratio
Optional<float> preferred_aspect_ratio() const;
bool has_preferred_aspect_ratio() const { return preferred_aspect_ratio().has_value(); }
virtual ~Box() override;
virtual void did_set_content_size() { }

View File

@ -590,12 +590,12 @@ CSSPixels FlexFormattingContext::adjust_main_size_through_aspect_ratio_for_cross
{
if (!max_cross_size.is_none()) {
auto max_cross_size_px = max_cross_size.to_px(box, !is_row_layout() ? m_flex_container_state.content_width() : m_flex_container_state.content_height());
main_size = min(main_size, calculate_main_size_from_cross_size_and_aspect_ratio(max_cross_size_px, box.natural_aspect_ratio().value()));
main_size = min(main_size, calculate_main_size_from_cross_size_and_aspect_ratio(max_cross_size_px, box.preferred_aspect_ratio().value()));
}
if (!min_cross_size.is_auto()) {
auto min_cross_size_px = min_cross_size.to_px(box, !is_row_layout() ? m_flex_container_state.content_width() : m_flex_container_state.content_height());
main_size = max(main_size, calculate_main_size_from_cross_size_and_aspect_ratio(min_cross_size_px, box.natural_aspect_ratio().value()));
main_size = max(main_size, calculate_main_size_from_cross_size_and_aspect_ratio(min_cross_size_px, box.preferred_aspect_ratio().value()));
}
return main_size;
@ -647,13 +647,13 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// - an intrinsic aspect ratio,
// - a used flex basis of content, and
// - a definite cross size,
if (item.box->has_natural_aspect_ratio()
if (item.box->has_preferred_aspect_ratio()
&& item.used_flex_basis.type == CSS::FlexBasis::Content
&& has_definite_cross_size(item.box)) {
// flex_base_size is calculated from definite cross size and intrinsic aspect ratio
return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(
item.box,
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), item.box->natural_aspect_ratio().value()),
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), item.box->preferred_aspect_ratio().value()),
computed_cross_min_size(item.box),
computed_cross_max_size(item.box));
}
@ -713,7 +713,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// AD-HOC: This is not mentioned in the spec, but if the item has an aspect ratio,
// we may need to adjust the main size in response to cross size min/max constraints.
if (item.box->has_natural_aspect_ratio()) {
if (item.box->has_preferred_aspect_ratio()) {
item.flex_base_size = adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(child_box, item.flex_base_size, computed_cross_min_size(child_box), computed_cross_max_size(child_box));
}
@ -762,7 +762,7 @@ CSSPixels FlexFormattingContext::content_size_suggestion(FlexItem const& item) c
{
auto suggestion = calculate_min_content_main_size(item);
if (item.box->has_natural_aspect_ratio()) {
if (item.box->has_preferred_aspect_ratio()) {
suggestion = adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(item.box, suggestion, computed_cross_min_size(item.box), computed_cross_max_size(item.box));
}
@ -775,8 +775,8 @@ Optional<CSSPixels> FlexFormattingContext::transferred_size_suggestion(FlexItem
// If the item has a preferred aspect ratio and its preferred cross size is definite,
// then the transferred size suggestion is that size
// (clamped by its minimum and maximum cross sizes if they are definite), converted through the aspect ratio.
if (item.box->has_natural_aspect_ratio() && has_definite_cross_size(item.box)) {
auto aspect_ratio = item.box->natural_aspect_ratio().value();
if (item.box->has_preferred_aspect_ratio() && has_definite_cross_size(item.box)) {
auto aspect_ratio = item.box->preferred_aspect_ratio().value();
return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(
item.box,
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), aspect_ratio),

View File

@ -256,7 +256,7 @@ FormattingContext::ShrinkToFitResult FormattingContext::calculate_shrink_to_fit_
};
}
CSSPixelSize FormattingContext::solve_replaced_size_constraint(CSSPixels input_width, CSSPixels input_height, ReplacedBox const& box) const
CSSPixelSize FormattingContext::solve_replaced_size_constraint(CSSPixels input_width, CSSPixels input_height, Box const& box) const
{
// 10.4 Minimum and maximum widths: 'min-width' and 'max-width'
@ -365,7 +365,7 @@ CSSPixels FormattingContext::compute_auto_height_for_block_formatting_context_ro
}
// 10.3.2 Inline, replaced elements, https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width
CSSPixels FormattingContext::tentative_width_for_replaced_element(ReplacedBox const& box, CSS::Size const& computed_width, AvailableSpace const& available_space) const
CSSPixels FormattingContext::tentative_width_for_replaced_element(Box const& box, CSS::Size const& computed_width, AvailableSpace const& available_space) const
{
// Treat percentages of indefinite containing block widths as 0 (the initial width).
if (computed_width.is_percentage() && !m_state.get(*box.containing_block()).has_definite_width())
@ -387,16 +387,16 @@ CSSPixels FormattingContext::tentative_width_for_replaced_element(ReplacedBox co
// 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value of 'width' is:
//
// (used height) * (intrinsic ratio)
if ((computed_height.is_auto() && computed_width.is_auto() && !box.has_natural_width() && box.has_natural_height() && box.has_natural_aspect_ratio())
|| (computed_width.is_auto() && !computed_height.is_auto() && box.has_natural_aspect_ratio())) {
return compute_height_for_replaced_element(box, available_space) * static_cast<double>(box.natural_aspect_ratio().value());
if ((computed_height.is_auto() && computed_width.is_auto() && !box.has_natural_width() && box.has_natural_height() && box.has_preferred_aspect_ratio())
|| (computed_width.is_auto() && !computed_height.is_auto() && box.has_preferred_aspect_ratio())) {
return compute_height_for_replaced_element(box, available_space) * static_cast<double>(box.preferred_aspect_ratio().value());
}
// If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width,
// then the used value of 'width' is undefined in CSS 2.2. However, it is suggested that, if the containing block's width does not itself
// depend on the replaced element's width, then the used value of 'width' is calculated from the constraint equation used for block-level,
// non-replaced elements in normal flow.
if (computed_height.is_auto() && computed_width.is_auto() && !box.has_natural_width() && !box.has_natural_height() && box.has_natural_aspect_ratio()) {
if (computed_height.is_auto() && computed_width.is_auto() && !box.has_natural_width() && !box.has_natural_height() && box.has_preferred_aspect_ratio()) {
return calculate_stretch_fit_width(box, available_space.width);
}
@ -414,21 +414,21 @@ CSSPixels FormattingContext::tentative_width_for_replaced_element(ReplacedBox co
void FormattingContext::compute_width_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space)
{
if (is<ReplacedBox>(box))
compute_width_for_absolutely_positioned_replaced_element(verify_cast<ReplacedBox>(box), available_space);
if (box_is_sized_as_replaced_element(box))
compute_width_for_absolutely_positioned_replaced_element(box, available_space);
else
compute_width_for_absolutely_positioned_non_replaced_element(box, available_space);
}
void FormattingContext::compute_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout)
{
if (is<ReplacedBox>(box))
compute_height_for_absolutely_positioned_replaced_element(static_cast<ReplacedBox const&>(box), available_space, before_or_after_inside_layout);
if (box_is_sized_as_replaced_element(box))
compute_height_for_absolutely_positioned_replaced_element(box, available_space, before_or_after_inside_layout);
else
compute_height_for_absolutely_positioned_non_replaced_element(box, available_space, before_or_after_inside_layout);
}
CSSPixels FormattingContext::compute_width_for_replaced_element(ReplacedBox const& box, AvailableSpace const& available_space) const
CSSPixels FormattingContext::compute_width_for_replaced_element(Box const& box, AvailableSpace const& available_space) const
{
// 10.3.4 Block-level, replaced elements in normal flow...
// 10.3.2 Inline, replaced elements
@ -443,7 +443,7 @@ CSSPixels FormattingContext::compute_width_for_replaced_element(ReplacedBox cons
// 1. The tentative used width is calculated (without 'min-width' and 'max-width')
auto used_width = tentative_width_for_replaced_element(box, computed_width, available_space);
if (computed_width.is_auto() && computed_height.is_auto() && box.has_natural_aspect_ratio()) {
if (computed_width.is_auto() && computed_height.is_auto() && box.has_preferred_aspect_ratio()) {
CSSPixels w = used_width;
CSSPixels h = tentative_height_for_replaced_element(box, computed_height, available_space);
used_width = solve_replaced_size_constraint(w, h, box).width();
@ -473,7 +473,7 @@ CSSPixels FormattingContext::compute_width_for_replaced_element(ReplacedBox cons
// 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
// https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-height
CSSPixels FormattingContext::tentative_height_for_replaced_element(ReplacedBox const& box, CSS::Size const& computed_height, AvailableSpace const& available_space) const
CSSPixels FormattingContext::tentative_height_for_replaced_element(Box const& box, CSS::Size const& computed_height, AvailableSpace const& available_space) const
{
// If 'height' and 'width' both have computed values of 'auto' and the element also has
// an intrinsic height, then that intrinsic height is the used value of 'height'.
@ -483,8 +483,8 @@ CSSPixels FormattingContext::tentative_height_for_replaced_element(ReplacedBox c
// Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
//
// (used width) / (intrinsic ratio)
if (computed_height.is_auto() && box.has_natural_aspect_ratio())
return m_state.get(box).content_width() / static_cast<double>(box.natural_aspect_ratio().value());
if (computed_height.is_auto() && box.has_preferred_aspect_ratio())
return m_state.get(box).content_width() / static_cast<double>(box.preferred_aspect_ratio().value());
// Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'.
if (computed_height.is_auto() && box.has_natural_height())
@ -500,7 +500,7 @@ CSSPixels FormattingContext::tentative_height_for_replaced_element(ReplacedBox c
return calculate_inner_height(box, available_space.height, computed_height).to_px(box);
}
CSSPixels FormattingContext::compute_height_for_replaced_element(ReplacedBox const& box, AvailableSpace const& available_space) const
CSSPixels FormattingContext::compute_height_for_replaced_element(Box const& box, AvailableSpace const& available_space) const
{
// 10.6.2 Inline replaced elements
// 10.6.4 Block-level replaced elements in normal flow
@ -518,7 +518,7 @@ CSSPixels FormattingContext::compute_height_for_replaced_element(ReplacedBox con
// use the algorithm under 'Minimum and maximum widths'
// https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
// to find the used width and height.
if (computed_width.is_auto() && computed_height.is_auto() && box.has_natural_aspect_ratio()) {
if (computed_width.is_auto() && computed_height.is_auto() && box.has_preferred_aspect_ratio()) {
CSSPixels w = tentative_width_for_replaced_element(box, computed_width, available_space);
CSSPixels h = used_height;
used_height = solve_replaced_size_constraint(w, h, box).height();
@ -689,12 +689,14 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
box_state.padding_right = padding_right;
}
void FormattingContext::compute_width_for_absolutely_positioned_replaced_element(ReplacedBox const& box, AvailableSpace const& available_space)
void FormattingContext::compute_width_for_absolutely_positioned_replaced_element(Box const& box, AvailableSpace const& available_space)
{
// 10.3.8 Absolutely positioned, replaced elements
// The used value of 'width' is determined as for inline replaced elements.
// FIXME: This const_cast is gross.
const_cast<ReplacedBox&>(box).prepare_for_replaced_layout();
if (is<ReplacedBox>(box)) {
// FIXME: This const_cast is gross.
static_cast<ReplacedBox&>(const_cast<Box&>(box)).prepare_for_replaced_layout();
}
m_state.get_mutable(box).set_content_width(compute_width_for_replaced_element(box, available_space));
}
@ -1061,7 +1063,7 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
independent_formatting_context->parent_context_did_dimension_child_root_box();
}
void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(ReplacedBox const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout)
void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout)
{
// 10.6.5 Absolutely positioned, replaced elements
// The used value of 'height' is determined as for inline replaced elements.
@ -1283,8 +1285,8 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box
CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box, AvailableSize const& available_width) const
{
if (box.has_natural_aspect_ratio() && available_width.is_definite())
return available_width.to_px() / static_cast<double>(*box.natural_aspect_ratio());
if (box.has_preferred_aspect_ratio() && available_width.is_definite())
return available_width.to_px() / static_cast<double>(*box.preferred_aspect_ratio());
if (box.has_natural_height())
return *box.natural_height();
@ -1623,4 +1625,13 @@ CSSPixelRect FormattingContext::margin_box_rect_in_ancestor_coordinate_space(Box
VERIFY_NOT_REACHED();
}
bool box_is_sized_as_replaced_element(Box const& box)
{
// When a box has a preferred aspect ratio, its automatic sizes are calculated the same as for a
// replaced element with a natural aspect ratio and no natural size in that axis, see e.g. CSS2 §10
// and CSS Flexible Box Model Level 1 §9.2.
// https://www.w3.org/TR/css-sizing-4/#aspect-ratio-automatic
return is<ReplacedBox>(box) || box.has_preferred_aspect_ratio();
}
}

View File

@ -50,8 +50,8 @@ public:
static bool creates_block_formatting_context(Box const&);
CSSPixels compute_width_for_replaced_element(ReplacedBox const&, AvailableSpace const&) const;
CSSPixels compute_height_for_replaced_element(ReplacedBox const&, AvailableSpace const&) const;
CSSPixels compute_width_for_replaced_element(Box const&, AvailableSpace const&) const;
CSSPixels compute_height_for_replaced_element(Box const&, AvailableSpace const&) const;
OwnPtr<FormattingContext> create_independent_formatting_context_if_needed(LayoutState&, Box const& child_box);
@ -112,18 +112,18 @@ protected:
CSSPixels preferred_minimum_width { 0 };
};
CSSPixels tentative_width_for_replaced_element(ReplacedBox const&, CSS::Size const& computed_width, AvailableSpace const&) const;
CSSPixels tentative_height_for_replaced_element(ReplacedBox const&, CSS::Size const& computed_height, AvailableSpace const&) const;
CSSPixels tentative_width_for_replaced_element(Box const&, CSS::Size const& computed_width, AvailableSpace const&) const;
CSSPixels tentative_height_for_replaced_element(Box const&, CSS::Size const& computed_height, AvailableSpace const&) const;
CSSPixels compute_auto_height_for_block_formatting_context_root(Box const&) const;
[[nodiscard]] CSSPixelSize solve_replaced_size_constraint(CSSPixels input_width, CSSPixels input_height, ReplacedBox const&) const;
[[nodiscard]] CSSPixelSize solve_replaced_size_constraint(CSSPixels input_width, CSSPixels input_height, Box const&) const;
ShrinkToFitResult calculate_shrink_to_fit_widths(Box const&);
void layout_absolutely_positioned_element(Box const&, AvailableSpace const&);
void compute_width_for_absolutely_positioned_element(Box const&, AvailableSpace const&);
void compute_width_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&);
void compute_width_for_absolutely_positioned_replaced_element(ReplacedBox const&, AvailableSpace const&);
void compute_width_for_absolutely_positioned_replaced_element(Box const&, AvailableSpace const&);
enum class BeforeOrAfterInsideLayout {
Before,
@ -131,7 +131,7 @@ protected:
};
void compute_height_for_absolutely_positioned_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout);
void compute_height_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout);
void compute_height_for_absolutely_positioned_replaced_element(ReplacedBox const&, AvailableSpace const&, BeforeOrAfterInsideLayout);
void compute_height_for_absolutely_positioned_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout);
Type m_type {};
@ -141,4 +141,6 @@ protected:
LayoutState& m_state;
};
bool box_is_sized_as_replaced_element(Box const&);
}

View File

@ -110,14 +110,12 @@ void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode l
box_state.border_bottom = computed_values.border_bottom().width;
box_state.margin_bottom = computed_values.margin().bottom().to_px(box, width_of_containing_block);
if (is<ReplacedBox>(box)) {
auto& replaced = verify_cast<ReplacedBox>(box);
box_state.set_content_width(compute_width_for_replaced_element(replaced, *m_available_space));
box_state.set_content_height(compute_height_for_replaced_element(replaced, *m_available_space));
if (box_is_sized_as_replaced_element(box)) {
box_state.set_content_width(compute_width_for_replaced_element(box, *m_available_space));
box_state.set_content_height(compute_height_for_replaced_element(box, *m_available_space));
if (is<SVGSVGBox>(box))
(void)layout_inside(replaced, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space));
(void)layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space));
return;
}