LibWeb: Save layout mode inside formatting context object

FormattingContext::run() does not allow reentrancy, so it's safe to
save and access layout mode from FC object. This avoids need to drill it
through methods of a formatting context and makes it clear that this
value could never be changed after FC construction.
This commit is contained in:
Aliaksandr Kalenik 2024-09-11 01:03:02 +02:00 committed by Andreas Kling
parent 623e358d7a
commit 90b8bfc04c
Notes: github-actions[bot] 2024-09-11 07:30:59 +00:00
15 changed files with 124 additions and 124 deletions

View file

@ -1134,7 +1134,7 @@ void Document::update_layout()
Layout::LayoutState layout_state;
{
Layout::BlockFormattingContext root_formatting_context(layout_state, *m_layout_root, nullptr);
Layout::BlockFormattingContext root_formatting_context(layout_state, Layout::LayoutMode::Normal, *m_layout_root, nullptr);
auto& viewport = static_cast<Layout::Viewport&>(*m_layout_root);
auto& viewport_state = layout_state.get_mutable(viewport);
@ -1147,7 +1147,6 @@ void Document::update_layout()
}
root_formatting_context.run(
Layout::LayoutMode::Normal,
Layout::AvailableSpace(
Layout::AvailableSize::make_definite(viewport_rect.width()),
Layout::AvailableSize::make_definite(viewport_rect.height())));

View file

@ -23,8 +23,8 @@
namespace Web::Layout {
BlockFormattingContext::BlockFormattingContext(LayoutState& state, BlockContainer const& root, FormattingContext* parent)
: FormattingContext(Type::Block, state, root, parent)
BlockFormattingContext::BlockFormattingContext(LayoutState& state, LayoutMode layout_mode, BlockContainer const& root, FormattingContext* parent)
: FormattingContext(Type::Block, layout_mode, state, root, parent)
{
}
@ -66,17 +66,17 @@ static bool margins_collapse_through(Box const& box, LayoutState& state)
return state.get(box).border_box_height() == 0;
}
void BlockFormattingContext::run(LayoutMode layout_mode, AvailableSpace const& available_space)
void BlockFormattingContext::run(AvailableSpace const& available_space)
{
if (is<Viewport>(root())) {
layout_viewport(layout_mode, available_space);
layout_viewport(available_space);
return;
}
if (root().children_are_inline())
layout_inline_children(root(), layout_mode, available_space);
layout_inline_children(root(), available_space);
else
layout_block_level_children(root(), layout_mode, available_space);
layout_block_level_children(root(), available_space);
// Assign collapsed margin left after children layout of formatting context to the last child box
if (m_margin_state.current_collapsed_margin() != 0) {
@ -130,7 +130,7 @@ bool BlockFormattingContext::box_should_avoid_floats_because_it_establishes_fc(B
return false;
}
void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const& available_space, LayoutMode)
void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const& available_space)
{
if (box.is_absolutely_positioned()) {
compute_width_for_absolutely_positioned_element(box, available_space);
@ -466,16 +466,14 @@ void BlockFormattingContext::compute_height(Box const& box, AvailableSpace const
box_used_values.set_content_height(height);
}
void BlockFormattingContext::layout_inline_children(BlockContainer const& block_container, LayoutMode layout_mode, AvailableSpace const& available_space)
void BlockFormattingContext::layout_inline_children(BlockContainer const& block_container, AvailableSpace const& available_space)
{
VERIFY(block_container.children_are_inline());
auto& block_container_state = m_state.get_mutable(block_container);
InlineFormattingContext context(m_state, block_container, block_container_state, *this);
context.run(
layout_mode,
available_space);
InlineFormattingContext context(m_state, m_layout_mode, block_container, block_container_state, *this);
context.run(available_space);
if (!block_container_state.has_definite_width()) {
// NOTE: min-width or max-width for boxes with inline children can only be applied after inside layout
@ -579,7 +577,7 @@ CSSPixels BlockFormattingContext::compute_auto_height_for_block_level_element(Bo
return 0;
}
void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContainer const& block_container, LayoutMode layout_mode, CSSPixels& bottom_of_lowest_margin_box, AvailableSpace const& available_space)
void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContainer const& block_container, CSSPixels& bottom_of_lowest_margin_box, AvailableSpace const& available_space)
{
auto& box_state = m_state.get_mutable(box);
@ -598,7 +596,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
if (box.is_floating()) {
auto const y = m_y_offset_of_current_block_container.value();
auto margin_top = !m_margin_state.has_block_container_waiting_for_final_y_position() ? m_margin_state.current_collapsed_margin() : 0;
layout_floating_box(box, block_container, layout_mode, available_space, margin_top + y);
layout_floating_box(box, block_container, available_space, margin_top + y);
bottom_of_lowest_margin_box = max(bottom_of_lowest_margin_box, box_state.offset.y() + box_state.content_height() + box_state.margin_box_bottom());
return;
}
@ -620,7 +618,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
compute_height(box, available_space);
}
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box);
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, m_layout_mode, box);
// NOTE: It is possible to encounter SVGMaskBox nodes while doing layout of formatting context established by <foreignObject> with a mask.
// We should skip and let SVGFormattingContext take care of them.
@ -647,7 +645,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
place_block_level_element_in_normal_flow_vertically(box, y + margin_top);
compute_width(box, available_space, layout_mode);
compute_width(box, available_space);
place_block_level_element_in_normal_flow_horizontally(box, available_space);
@ -677,11 +675,11 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
if (independent_formatting_context) {
// This box establishes a new formatting context. Pass control to it.
independent_formatting_context->run(layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
independent_formatting_context->run(box_state.available_inner_space_or_constraints_from(available_space));
} else {
// This box participates in the current block container's flow.
if (box.children_are_inline()) {
layout_inline_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
layout_inline_children(verify_cast<BlockContainer>(box), box_state.available_inner_space_or_constraints_from(available_space));
} else {
if (box_state.border_top > 0 || box_state.padding_top > 0) {
// margin-top of block container can't collapse with it's children if it has non zero border or padding
@ -695,7 +693,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
});
}
layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
layout_block_level_children(verify_cast<BlockContainer>(box), box_state.available_inner_space_or_constraints_from(available_space));
}
}
@ -729,7 +727,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
independent_formatting_context->parent_context_did_dimension_child_root_box();
}
void BlockFormattingContext::layout_block_level_children(BlockContainer const& block_container, LayoutMode layout_mode, AvailableSpace const& available_space)
void BlockFormattingContext::layout_block_level_children(BlockContainer const& block_container, AvailableSpace const& available_space)
{
VERIFY(!block_container.children_are_inline());
@ -737,13 +735,13 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer const& b
TemporaryChange<Optional<CSSPixels>> change { m_y_offset_of_current_block_container, CSSPixels(0) };
block_container.for_each_child_of_type<Box>([&](Box& box) {
layout_block_level_box(box, block_container, layout_mode, bottom_of_lowest_margin_box, available_space);
layout_block_level_box(box, block_container, bottom_of_lowest_margin_box, available_space);
return IterationDecision::Continue;
});
m_margin_state.block_container_y_position_update_callback = {};
if (layout_mode == LayoutMode::IntrinsicSizing) {
if (m_layout_mode == LayoutMode::IntrinsicSizing) {
auto& block_container_state = m_state.get_mutable(block_container);
if (!block_container_state.has_definite_width()) {
auto width = greatest_child_width(block_container);
@ -910,7 +908,7 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_horizontal
box_state.set_content_offset({ x, box_state.offset.y() });
}
void BlockFormattingContext::layout_viewport(LayoutMode layout_mode, AvailableSpace const& available_space)
void BlockFormattingContext::layout_viewport(AvailableSpace const& available_space)
{
// NOTE: If we are laying out a standalone SVG document, we give it some special treatment:
// The root <svg> container gets the same size as the viewport,
@ -919,17 +917,17 @@ void BlockFormattingContext::layout_viewport(LayoutMode layout_mode, AvailableSp
auto const& svg_root = verify_cast<SVGSVGBox>(*root().first_child());
auto content_height = m_state.get(*svg_root.containing_block()).content_height();
m_state.get_mutable(svg_root).set_content_height(content_height);
auto svg_formatting_context = create_independent_formatting_context_if_needed(m_state, svg_root);
svg_formatting_context->run(layout_mode, available_space);
auto svg_formatting_context = create_independent_formatting_context_if_needed(m_state, m_layout_mode, svg_root);
svg_formatting_context->run(available_space);
} else {
if (root().children_are_inline())
layout_inline_children(root(), layout_mode, available_space);
layout_inline_children(root(), available_space);
else
layout_block_level_children(root(), layout_mode, available_space);
layout_block_level_children(root(), available_space);
}
}
void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer const&, LayoutMode layout_mode, AvailableSpace const& available_space, CSSPixels y, LineBuilder* line_builder)
void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer const&, AvailableSpace const& available_space, CSSPixels y, LineBuilder* line_builder)
{
VERIFY(box.is_floating());
@ -938,13 +936,13 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
resolve_vertical_box_model_metrics(box);
compute_width(box, available_space, layout_mode);
compute_width(box, available_space);
// NOTE: Flex containers with `auto` height are treated as `max-content`, so we can compute their height early.
if (box.is_replaced_box() || box.display().is_flex_inside())
compute_height(box, available_space);
auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
auto independent_formatting_context = layout_inside(box, m_layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
compute_height(box, available_space);
// First we place the box normally (to get the right y coordinate.)

View file

@ -19,10 +19,10 @@ class LineBuilder;
// https://www.w3.org/TR/css-display/#block-formatting-context
class BlockFormattingContext : public FormattingContext {
public:
explicit BlockFormattingContext(LayoutState&, BlockContainer const&, FormattingContext* parent);
explicit BlockFormattingContext(LayoutState&, LayoutMode layout_mode, BlockContainer const&, FormattingContext* parent);
~BlockFormattingContext();
virtual void run(LayoutMode, AvailableSpace const&) override;
virtual void run(AvailableSpace const&) override;
virtual CSSPixels automatic_content_width() const override;
virtual CSSPixels automatic_content_height() const override;
@ -30,7 +30,7 @@ public:
auto const& right_side_floats() const { return m_right_floats; }
bool box_should_avoid_floats_because_it_establishes_fc(Box const&);
void compute_width(Box const&, AvailableSpace const&, LayoutMode = LayoutMode::Normal);
void compute_width(Box const&, AvailableSpace const&);
// https://www.w3.org/TR/css-display/#block-formatting-context-root
BlockContainer const& root() const { return static_cast<BlockContainer const&>(context_box()); }
@ -47,9 +47,9 @@ public:
virtual CSSPixels greatest_child_width(Box const&) const override;
void layout_floating_box(Box const& child, BlockContainer const& containing_block, LayoutMode, AvailableSpace const&, CSSPixels y, LineBuilder* = nullptr);
void layout_floating_box(Box const& child, BlockContainer const& containing_block, AvailableSpace const&, CSSPixels y, LineBuilder* = nullptr);
void layout_block_level_box(Box const&, BlockContainer const&, LayoutMode, CSSPixels& bottom_of_lowest_margin_box, AvailableSpace const&);
void layout_block_level_box(Box const&, BlockContainer const&, CSSPixels& bottom_of_lowest_margin_box, AvailableSpace const&);
void resolve_vertical_box_model_metrics(Box const&);
@ -69,10 +69,10 @@ private:
void compute_width_for_block_level_replaced_element_in_normal_flow(Box const&, AvailableSpace const&);
void layout_viewport(LayoutMode, AvailableSpace const&);
void layout_viewport(AvailableSpace const&);
void layout_block_level_children(BlockContainer const&, LayoutMode, AvailableSpace const&);
void layout_inline_children(BlockContainer const&, LayoutMode, AvailableSpace const&);
void layout_block_level_children(BlockContainer const&, AvailableSpace const&);
void layout_inline_children(BlockContainer const&, AvailableSpace const&);
void place_block_level_element_in_normal_flow_horizontally(Box const& child_box, AvailableSpace const&);
void place_block_level_element_in_normal_flow_vertically(Box const&, CSSPixels y);

View file

@ -28,8 +28,8 @@ CSSPixels FlexFormattingContext::get_pixel_height(Box const& box, CSS::Size cons
return calculate_inner_height(box, containing_block_height_as_available_size(box), size);
}
FlexFormattingContext::FlexFormattingContext(LayoutState& state, Box const& flex_container, FormattingContext* parent)
: FormattingContext(Type::Flex, state, flex_container, parent)
FlexFormattingContext::FlexFormattingContext(LayoutState& state, LayoutMode layout_mode, Box const& flex_container, FormattingContext* parent)
: FormattingContext(Type::Flex, layout_mode, state, flex_container, parent)
, m_flex_container_state(m_state.get_mutable(flex_container))
, m_flex_direction(flex_container.computed_values().flex_direction())
{
@ -47,7 +47,7 @@ CSSPixels FlexFormattingContext::automatic_content_height() const
return m_flex_container_state.content_height();
}
void FlexFormattingContext::run(LayoutMode, AvailableSpace const& available_space)
void FlexFormattingContext::run(AvailableSpace const& available_space)
{
// This implements https://www.w3.org/TR/css-flexbox-1/#layout-algorithm
@ -1126,14 +1126,14 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
}
// Item has definite main size, layout with that as the used main size.
auto independent_formatting_context = create_independent_formatting_context_if_needed(throwaway_state, item.box);
auto independent_formatting_context = create_independent_formatting_context_if_needed(throwaway_state, LayoutMode::Normal, item.box);
// NOTE: Flex items should always create an independent formatting context!
VERIFY(independent_formatting_context);
auto available_width = is_row_layout() ? AvailableSize::make_definite(item.main_size.value()) : AvailableSize::make_indefinite();
auto available_height = is_row_layout() ? AvailableSize::make_indefinite() : AvailableSize::make_definite(item.main_size.value());
independent_formatting_context->run(LayoutMode::Normal, AvailableSpace(available_width, available_height));
independent_formatting_context->run(AvailableSpace(available_width, available_height));
auto automatic_cross_size = is_row_layout() ? independent_formatting_context->automatic_content_height()
: independent_formatting_context->automatic_content_width();

View file

@ -13,12 +13,12 @@ namespace Web::Layout {
class FlexFormattingContext final : public FormattingContext {
public:
FlexFormattingContext(LayoutState&, Box const& flex_container, FormattingContext* parent);
FlexFormattingContext(LayoutState&, LayoutMode, Box const& flex_container, FormattingContext* parent);
~FlexFormattingContext();
virtual bool inhibits_floating() const override { return true; }
virtual void run(LayoutMode, AvailableSpace const&) override;
virtual void run(AvailableSpace const&) override;
virtual CSSPixels automatic_content_width() const override;
virtual CSSPixels automatic_content_height() const override;

View file

@ -18,8 +18,9 @@
namespace Web::Layout {
FormattingContext::FormattingContext(Type type, LayoutState& state, Box const& context_box, FormattingContext* parent)
FormattingContext::FormattingContext(Type type, LayoutMode layout_mode, LayoutState& state, Box const& context_box, FormattingContext* parent)
: m_type(type)
, m_layout_mode(layout_mode)
, m_parent(parent)
, m_context_box(context_box)
, m_state(state)
@ -154,27 +155,27 @@ Optional<FormattingContext::Type> FormattingContext::formatting_context_type_cre
// FIXME: This is a hack. Get rid of it.
struct ReplacedFormattingContext : public FormattingContext {
ReplacedFormattingContext(LayoutState& state, Box const& box)
: FormattingContext(Type::Block, state, box)
ReplacedFormattingContext(LayoutState& state, LayoutMode layout_mode, Box const& box)
: FormattingContext(Type::Block, layout_mode, state, box)
{
}
virtual CSSPixels automatic_content_width() const override { return 0; }
virtual CSSPixels automatic_content_height() const override { return 0; }
virtual void run(LayoutMode, AvailableSpace const&) override { }
virtual void run(AvailableSpace const&) override { }
};
// FIXME: This is a hack. Get rid of it.
struct DummyFormattingContext : public FormattingContext {
DummyFormattingContext(LayoutState& state, Box const& box)
: FormattingContext(Type::Block, state, box)
DummyFormattingContext(LayoutState& state, LayoutMode layout_mode, Box const& box)
: FormattingContext(Type::Block, layout_mode, state, box)
{
}
virtual CSSPixels automatic_content_width() const override { return 0; }
virtual CSSPixels automatic_content_height() const override { return 0; }
virtual void run(LayoutMode, AvailableSpace const&) override { }
virtual void run(AvailableSpace const&) override { }
};
OwnPtr<FormattingContext> FormattingContext::create_independent_formatting_context_if_needed(LayoutState& state, Box const& child_box)
OwnPtr<FormattingContext> FormattingContext::create_independent_formatting_context_if_needed(LayoutState& state, LayoutMode layout_mode, Box const& child_box)
{
auto type = formatting_context_type_created_by_box(child_box);
if (!type.has_value())
@ -182,19 +183,19 @@ OwnPtr<FormattingContext> FormattingContext::create_independent_formatting_conte
switch (type.value()) {
case Type::Block:
return make<BlockFormattingContext>(state, verify_cast<BlockContainer>(child_box), this);
return make<BlockFormattingContext>(state, layout_mode, verify_cast<BlockContainer>(child_box), this);
case Type::SVG:
return make<SVGFormattingContext>(state, child_box, this);
return make<SVGFormattingContext>(state, layout_mode, child_box, this);
case Type::Flex:
return make<FlexFormattingContext>(state, child_box, this);
return make<FlexFormattingContext>(state, layout_mode, child_box, this);
case Type::Grid:
return make<GridFormattingContext>(state, child_box, this);
return make<GridFormattingContext>(state, layout_mode, child_box, this);
case Type::Table:
return make<TableFormattingContext>(state, child_box, this);
return make<TableFormattingContext>(state, layout_mode, child_box, this);
case Type::InternalReplaced:
return make<ReplacedFormattingContext>(state, child_box);
return make<ReplacedFormattingContext>(state, layout_mode, child_box);
case Type::InternalDummy:
return make<DummyFormattingContext>(state, child_box);
return make<DummyFormattingContext>(state, layout_mode, child_box);
case Type::Inline:
// IFC should always be created by a parent BFC directly.
VERIFY_NOT_REACHED();
@ -223,11 +224,11 @@ OwnPtr<FormattingContext> FormattingContext::layout_inside(Box const& child_box,
if (!child_box.can_have_children())
return {};
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, child_box);
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, layout_mode, child_box);
if (independent_formatting_context)
independent_formatting_context->run(layout_mode, available_space);
independent_formatting_context->run(available_space);
else
run(layout_mode, available_space);
run(available_space);
return independent_formatting_context;
}
@ -423,7 +424,7 @@ CSSPixels FormattingContext::compute_table_box_width_inside_table_wrapper(Box co
table_box_state.border_left = table_box_computed_values.border_left().width;
table_box_state.border_right = table_box_computed_values.border_right().width;
auto context = make<TableFormattingContext>(throwaway_state, *table_box, this);
auto context = make<TableFormattingContext>(throwaway_state, LayoutMode::IntrinsicSizing, *table_box, this);
context->run_until_width_calculation(m_state.get(*table_box).available_inner_space_or_constraints_from(available_space));
auto table_used_width = throwaway_state.get(*table_box).border_box_width();
@ -456,9 +457,9 @@ CSSPixels FormattingContext::compute_table_box_height_inside_table_wrapper(Box c
auto available_height = height_of_containing_block - margin_top.to_px(box) - margin_bottom.to_px(box);
LayoutState throwaway_state(&m_state);
auto context = create_independent_formatting_context_if_needed(throwaway_state, box);
auto context = create_independent_formatting_context_if_needed(throwaway_state, LayoutMode::IntrinsicSizing, box);
VERIFY(context);
context->run(LayoutMode::IntrinsicSizing, m_state.get(box).available_inner_space_or_constraints_from(available_space));
context->run(m_state.get(box).available_inner_space_or_constraints_from(available_space));
Optional<Box const&> table_box;
box.for_each_in_subtree_of_type<Box>([&](Box const& child_box) {
@ -1453,14 +1454,14 @@ CSSPixels FormattingContext::calculate_min_content_width(Layout::Box const& box)
box_state.set_indefinite_content_width();
box_state.set_indefinite_content_height();
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, LayoutMode::IntrinsicSizing, box);
if (!context) {
context = make<BlockFormattingContext>(throwaway_state, verify_cast<BlockContainer>(box), nullptr);
context = make<BlockFormattingContext>(throwaway_state, LayoutMode::IntrinsicSizing, verify_cast<BlockContainer>(box), nullptr);
}
auto available_width = AvailableSize::make_min_content();
auto available_height = AvailableSize::make_indefinite();
context->run(LayoutMode::IntrinsicSizing, AvailableSpace(available_width, available_height));
context->run(AvailableSpace(available_width, available_height));
cache.min_content_width = context->automatic_content_width();
@ -1491,14 +1492,14 @@ CSSPixels FormattingContext::calculate_max_content_width(Layout::Box const& box)
box_state.set_indefinite_content_width();
box_state.set_indefinite_content_height();
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, LayoutMode::IntrinsicSizing, box);
if (!context) {
context = make<BlockFormattingContext>(throwaway_state, verify_cast<BlockContainer>(box), nullptr);
context = make<BlockFormattingContext>(throwaway_state, LayoutMode::IntrinsicSizing, verify_cast<BlockContainer>(box), nullptr);
}
auto available_width = AvailableSize::make_max_content();
auto available_height = AvailableSize::make_indefinite();
context->run(LayoutMode::IntrinsicSizing, AvailableSpace(available_width, available_height));
context->run(AvailableSpace(available_width, available_height));
cache.max_content_width = context->automatic_content_width();
@ -1537,12 +1538,12 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box
box_state.set_indefinite_content_height();
box_state.set_content_width(width);
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, LayoutMode::IntrinsicSizing, box);
if (!context) {
context = make<BlockFormattingContext>(throwaway_state, verify_cast<BlockContainer>(box), nullptr);
context = make<BlockFormattingContext>(throwaway_state, LayoutMode::IntrinsicSizing, verify_cast<BlockContainer>(box), nullptr);
}
context->run(LayoutMode::IntrinsicSizing, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_min_content()));
context->run(AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_min_content()));
auto min_content_height = context->automatic_content_height();
if (min_content_height.might_be_saturated()) {
@ -1581,12 +1582,12 @@ CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box
box_state.set_indefinite_content_height();
box_state.set_content_width(width);
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, LayoutMode::IntrinsicSizing, box);
if (!context) {
context = make<BlockFormattingContext>(throwaway_state, verify_cast<BlockContainer>(box), nullptr);
context = make<BlockFormattingContext>(throwaway_state, LayoutMode::IntrinsicSizing, verify_cast<BlockContainer>(box), nullptr);
}
context->run(LayoutMode::IntrinsicSizing, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_max_content()));
context->run(AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_max_content()));
auto max_content_height = context->automatic_content_height();

View file

@ -36,7 +36,7 @@ public:
InternalDummy, // Internal hack formatting context for unimplemented things. FIXME: Get rid of this.
};
virtual void run(LayoutMode, AvailableSpace const&) = 0;
virtual void run(AvailableSpace const&) = 0;
// This function returns the automatic content height of the context's root box.
virtual CSSPixels automatic_content_width() const = 0;
@ -64,7 +64,7 @@ public:
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);
OwnPtr<FormattingContext> create_independent_formatting_context_if_needed(LayoutState&, LayoutMode, Box const& child_box);
virtual void parent_context_did_dimension_child_root_box() { }
@ -113,7 +113,7 @@ public:
void compute_inset(NodeWithStyleAndBoxModelMetrics const&);
protected:
FormattingContext(Type, LayoutState&, Box const&, FormattingContext* parent = nullptr);
FormattingContext(Type, LayoutMode, LayoutState&, Box const&, FormattingContext* parent = nullptr);
static bool should_treat_width_as_auto(Box const&, AvailableSpace const&);
static bool should_treat_height_as_auto(Box const&, AvailableSpace const&);
@ -170,6 +170,7 @@ protected:
[[nodiscard]] Box const* box_child_to_derive_baseline_from(Box const&) const;
Type m_type {};
LayoutMode m_layout_mode;
FormattingContext* m_parent { nullptr };
JS::NonnullGCPtr<Box const> m_context_box;

View file

@ -65,8 +65,8 @@ GridFormattingContext::GridTrack GridFormattingContext::GridTrack::create_gap(CS
};
}
GridFormattingContext::GridFormattingContext(LayoutState& state, Box const& grid_container, FormattingContext* parent)
: FormattingContext(Type::Grid, state, grid_container, parent)
GridFormattingContext::GridFormattingContext(LayoutState& state, LayoutMode layout_mode, Box const& grid_container, FormattingContext* parent)
: FormattingContext(Type::Grid, layout_mode, state, grid_container, parent)
{
}
@ -1771,7 +1771,7 @@ CSSPixelRect GridFormattingContext::get_grid_area_rect(GridItem const& grid_item
return { x_start, y_start, x_end - x_start, y_end - y_start };
}
void GridFormattingContext::run(LayoutMode, AvailableSpace const& available_space)
void GridFormattingContext::run(AvailableSpace const& available_space)
{
m_available_space = available_space;

View file

@ -101,12 +101,12 @@ private:
class GridFormattingContext final : public FormattingContext {
public:
explicit GridFormattingContext(LayoutState&, Box const& grid_container, FormattingContext* parent);
explicit GridFormattingContext(LayoutState&, LayoutMode, Box const& grid_container, FormattingContext* parent);
~GridFormattingContext();
virtual bool inhibits_floating() const override { return true; }
virtual void run(LayoutMode, AvailableSpace const& available_space) override;
virtual void run(AvailableSpace const& available_space) override;
virtual CSSPixels automatic_content_width() const override;
virtual CSSPixels automatic_content_height() const override;

View file

@ -20,10 +20,11 @@ namespace Web::Layout {
InlineFormattingContext::InlineFormattingContext(
LayoutState& state,
LayoutMode layout_mode,
BlockContainer const& containing_block,
LayoutState::UsedValues& containing_block_used_values,
BlockFormattingContext& parent)
: FormattingContext(Type::Inline, state, containing_block, &parent)
: FormattingContext(Type::Inline, layout_mode, state, containing_block, &parent)
, m_containing_block_used_values(containing_block_used_values)
{
}
@ -77,11 +78,11 @@ CSSPixels InlineFormattingContext::automatic_content_height() const
return m_automatic_content_height;
}
void InlineFormattingContext::run(LayoutMode layout_mode, AvailableSpace const& available_space)
void InlineFormattingContext::run(AvailableSpace const& available_space)
{
VERIFY(containing_block().children_are_inline());
m_available_space = available_space;
generate_line_boxes(layout_mode);
generate_line_boxes();
CSSPixels content_height = 0;
@ -244,14 +245,14 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
}
}
void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
void InlineFormattingContext::generate_line_boxes()
{
auto& line_boxes = m_containing_block_used_values.line_boxes;
line_boxes.clear_with_capacity();
auto direction = m_context_box->computed_values().direction();
InlineLevelIterator iterator(*this, m_state, containing_block(), m_containing_block_used_values, layout_mode);
InlineLevelIterator iterator(*this, m_state, containing_block(), m_containing_block_used_values, m_layout_mode);
LineBuilder line_builder(*this, m_state, m_containing_block_used_values, direction);
// NOTE: When we ignore collapsible whitespace chunks at the start of a line,
@ -313,7 +314,7 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
auto introduce_clearance = parent().clear_floating_boxes(*item.node, *this);
if (introduce_clearance == BlockFormattingContext::DidIntroduceClearance::Yes)
parent().reset_margin_state();
parent().layout_floating_box(static_cast<Layout::Box const&>(*item.node), containing_block(), layout_mode, *m_available_space, 0, &line_builder);
parent().layout_floating_box(static_cast<Layout::Box const&>(*item.node), containing_block(), *m_available_space, 0, &line_builder);
}
break;

View file

@ -15,7 +15,7 @@ namespace Web::Layout {
class InlineFormattingContext final : public FormattingContext {
public:
InlineFormattingContext(LayoutState&, BlockContainer const& containing_block, LayoutState::UsedValues& containing_block_used_values, BlockFormattingContext& parent);
InlineFormattingContext(LayoutState&, LayoutMode, BlockContainer const& containing_block, LayoutState::UsedValues& containing_block_used_values, BlockFormattingContext& parent);
~InlineFormattingContext();
BlockFormattingContext& parent();
@ -23,7 +23,7 @@ public:
BlockContainer const& containing_block() const { return static_cast<BlockContainer const&>(context_box()); }
virtual void run(LayoutMode, AvailableSpace const&) override;
virtual void run(AvailableSpace const&) override;
virtual CSSPixels automatic_content_height() const override;
virtual CSSPixels automatic_content_width() const override;
@ -38,7 +38,7 @@ public:
void set_vertical_float_clearance(CSSPixels);
private:
void generate_line_boxes(LayoutMode);
void generate_line_boxes();
void apply_justification_to_fragments(CSS::TextJustify, LineBox&, bool is_last_line);
LayoutState::UsedValues& m_containing_block_used_values;

View file

@ -30,8 +30,8 @@
namespace Web::Layout {
SVGFormattingContext::SVGFormattingContext(LayoutState& state, Box const& box, FormattingContext* parent, Gfx::AffineTransform parent_viewbox_transform)
: FormattingContext(Type::SVG, state, box, parent)
SVGFormattingContext::SVGFormattingContext(LayoutState& state, LayoutMode layout_mode, Box const& box, FormattingContext* parent, Gfx::AffineTransform parent_viewbox_transform)
: FormattingContext(Type::SVG, layout_mode, state, box, parent)
, m_parent_viewbox_transform(parent_viewbox_transform)
{
}
@ -171,7 +171,7 @@ static bool is_container_element(Node const& node)
return false;
}
void SVGFormattingContext::run(LayoutMode, AvailableSpace const& available_space)
void SVGFormattingContext::run(AvailableSpace const& available_space)
{
// NOTE: SVG doesn't have a "formatting context" in the spec, but this is the most
// obvious way to drive SVG layout in our engine at the moment.
@ -265,8 +265,8 @@ void SVGFormattingContext::layout_svg_element(Box const& child)
if (is<SVG::SVGViewport>(child.dom_node())) {
layout_nested_viewport(child);
} else if (is<SVG::SVGForeignObjectElement>(child.dom_node()) && is<BlockContainer>(child)) {
Layout::BlockFormattingContext bfc(m_state, static_cast<BlockContainer const&>(child), this);
bfc.run(LayoutMode::Normal, *m_available_space);
Layout::BlockFormattingContext bfc(m_state, LayoutMode::Normal, static_cast<BlockContainer const&>(child), this);
bfc.run(*m_available_space);
auto& child_state = m_state.get_mutable(child);
child_state.set_content_offset(child_state.offset.translated(m_svg_offset));
child.for_each_child_of_type<SVGMaskBox>([&](SVGMaskBox const& child) {
@ -282,7 +282,7 @@ void SVGFormattingContext::layout_nested_viewport(Box const& viewport)
{
// Layout for a nested SVG viewport.
// https://svgwg.org/svg2-draft/coords.html#EstablishingANewSVGViewport.
SVGFormattingContext nested_context(m_state, viewport, this, m_current_viewbox_transform);
SVGFormattingContext nested_context(m_state, LayoutMode::Normal, viewport, this, m_current_viewbox_transform);
auto& nested_viewport_state = m_state.get_mutable(viewport);
auto resolve_dimension = [](auto& node, auto size, auto reference_value) {
// The value auto for width and height on the svg element is treated as 100%.
@ -301,7 +301,7 @@ void SVGFormattingContext::layout_nested_viewport(Box const& viewport)
nested_viewport_state.set_content_height(nested_viewport_height);
nested_viewport_state.set_has_definite_width(true);
nested_viewport_state.set_has_definite_height(true);
nested_context.run(LayoutMode::Normal, *m_available_space);
nested_context.run(*m_available_space);
}
Gfx::Path SVGFormattingContext::compute_path_for_text(SVGTextBox const& text_box)
@ -456,10 +456,10 @@ void SVGFormattingContext::layout_mask_or_clip(SVGBox const& mask_or_clip)
layout_state.set_content_height(m_viewport_size.height());
}
// Pretend masks/clips are a viewport so we can scale the contents depending on the `contentUnits`.
SVGFormattingContext nested_context(m_state, mask_or_clip, this, parent_viewbox_transform);
SVGFormattingContext nested_context(m_state, LayoutMode::Normal, mask_or_clip, this, parent_viewbox_transform);
layout_state.set_has_definite_width(true);
layout_state.set_has_definite_height(true);
nested_context.run(LayoutMode::Normal, *m_available_space);
nested_context.run(*m_available_space);
}
void SVGFormattingContext::layout_container_element(SVGBox const& container)

View file

@ -18,10 +18,10 @@ namespace Web::Layout {
class SVGFormattingContext : public FormattingContext {
public:
explicit SVGFormattingContext(LayoutState&, Box const&, FormattingContext* parent, Gfx::AffineTransform parent_viewbox_transform = {});
explicit SVGFormattingContext(LayoutState&, LayoutMode, Box const&, FormattingContext* parent, Gfx::AffineTransform parent_viewbox_transform = {});
~SVGFormattingContext();
virtual void run(LayoutMode, AvailableSpace const&) override;
virtual void run(AvailableSpace const&) override;
virtual CSSPixels automatic_content_width() const override;
virtual CSSPixels automatic_content_height() const override;

View file

@ -14,8 +14,8 @@
namespace Web::Layout {
TableFormattingContext::TableFormattingContext(LayoutState& state, Box const& root, FormattingContext* parent)
: FormattingContext(Type::Table, state, root, parent)
TableFormattingContext::TableFormattingContext(LayoutState& state, LayoutMode layout_mode, Box const& root, FormattingContext* parent)
: FormattingContext(Type::Table, layout_mode, state, root, parent)
{
}
@ -31,7 +31,7 @@ static inline bool is_table_column(Box const& box)
return box.display().is_table_column();
}
CSSPixels TableFormattingContext::run_caption_layout(LayoutMode layout_mode, CSS::CaptionSide phase)
CSSPixels TableFormattingContext::run_caption_layout(CSS::CaptionSide phase)
{
CSSPixels caption_height = 0;
for (auto* child = table_box().first_child(); child; child = child->next_sibling()) {
@ -40,8 +40,8 @@ CSSPixels TableFormattingContext::run_caption_layout(LayoutMode layout_mode, CSS
}
// The caption boxes are principal block-level boxes that retain their own content, padding, margin, and border areas,
// and are rendered as normal block boxes inside the table wrapper box, as described in https://www.w3.org/TR/CSS22/tables.html#model
auto caption_context = make<BlockFormattingContext>(m_state, *verify_cast<BlockContainer>(child), this);
caption_context->run(layout_mode, *m_available_space);
auto caption_context = make<BlockFormattingContext>(m_state, m_layout_mode, *verify_cast<BlockContainer>(child), this);
caption_context->run(*m_available_space);
VERIFY(child->is_box());
auto const& child_box = static_cast<Box const&>(*child);
// FIXME: Since caption only has inline children, BlockFormattingContext doesn't resolve the vertical metrics.
@ -828,7 +828,7 @@ void TableFormattingContext::distribute_excess_width_to_columns_fixed_mode(CSSPi
distribute_excess_width_equally(excess_width, [](auto const& column) { return column.used_width == 0; });
}
void TableFormattingContext::compute_table_height(LayoutMode layout_mode)
void TableFormattingContext::compute_table_height()
{
// First pass of row height calculation:
for (auto& row : m_rows) {
@ -878,7 +878,7 @@ void TableFormattingContext::compute_table_height(LayoutMode layout_mode)
// - the horizontal/vertical border-spacing times the amount of spanned visible columns/rows minus one
// FIXME: Account for visibility.
cell_state.set_content_width(span_width - cell_state.border_box_left() - cell_state.border_box_right() + (cell.column_span - 1) * border_spacing_horizontal());
if (auto independent_formatting_context = layout_inside(cell.box, layout_mode, cell_state.available_inner_space_or_constraints_from(*m_available_space))) {
if (auto independent_formatting_context = layout_inside(cell.box, m_layout_mode, cell_state.available_inner_space_or_constraints_from(*m_available_space))) {
cell_state.set_content_height(independent_formatting_context->automatic_content_height());
independent_formatting_context->parent_context_did_dimension_child_root_box();
}
@ -961,7 +961,7 @@ void TableFormattingContext::compute_table_height(LayoutMode layout_mode)
}
cell_state.set_content_width(span_width - cell_state.border_box_left() - cell_state.border_box_right() + (cell.column_span - 1) * border_spacing_horizontal());
if (auto independent_formatting_context = layout_inside(cell.box, layout_mode, cell_state.available_inner_space_or_constraints_from(*m_available_space))) {
if (auto independent_formatting_context = layout_inside(cell.box, m_layout_mode, cell_state.available_inner_space_or_constraints_from(*m_available_space))) {
independent_formatting_context->parent_context_did_dimension_child_root_box();
}
@ -1607,11 +1607,11 @@ void TableFormattingContext::run_until_width_calculation(AvailableSpace const& a
compute_table_width();
}
void TableFormattingContext::run(LayoutMode layout_mode, AvailableSpace const& available_space)
void TableFormattingContext::run(AvailableSpace const& available_space)
{
m_available_space = available_space;
auto total_captions_height = run_caption_layout(layout_mode, CSS::CaptionSide::Top);
auto total_captions_height = run_caption_layout(CSS::CaptionSide::Top);
run_until_width_calculation(available_space);
@ -1622,7 +1622,7 @@ void TableFormattingContext::run(LayoutMode layout_mode, AvailableSpace const& a
// Distribute the width of the table among columns.
distribute_width_to_columns();
compute_table_height(layout_mode);
compute_table_height();
distribute_height_to_rows();
@ -1631,7 +1631,7 @@ void TableFormattingContext::run(LayoutMode layout_mode, AvailableSpace const& a
m_state.get_mutable(table_box()).set_content_height(m_table_height);
total_captions_height += run_caption_layout(layout_mode, CSS::CaptionSide::Bottom);
total_captions_height += run_caption_layout(CSS::CaptionSide::Bottom);
// Table captions are positioned between the table margins and its borders (outside the grid box borders) as described in
// https://www.w3.org/TR/css-tables-3/#bounding-box-assignment

View file

@ -20,12 +20,12 @@ enum class TableDimension {
class TableFormattingContext final : public FormattingContext {
public:
explicit TableFormattingContext(LayoutState&, Box const&, FormattingContext* parent);
explicit TableFormattingContext(LayoutState&, LayoutMode, Box const&, FormattingContext* parent);
~TableFormattingContext();
void run_until_width_calculation(AvailableSpace const& available_space);
virtual void run(LayoutMode, AvailableSpace const&) override;
virtual void run(AvailableSpace const&) override;
virtual CSSPixels automatic_content_width() const override;
virtual CSSPixels automatic_content_height() const override;
@ -38,7 +38,7 @@ public:
static bool border_is_less_specific(const CSS::BorderData& a, const CSS::BorderData& b);
private:
CSSPixels run_caption_layout(LayoutMode, CSS::CaptionSide);
CSSPixels run_caption_layout(CSS::CaptionSide);
CSSPixels compute_capmin();
void compute_constrainedness();
void compute_cell_measures();
@ -53,7 +53,7 @@ private:
void distribute_width_to_columns();
void distribute_excess_width_to_columns(CSSPixels available_width);
void distribute_excess_width_to_columns_fixed_mode(CSSPixels excess_width);
void compute_table_height(LayoutMode layout_mode);
void compute_table_height();
void distribute_height_to_rows();
void position_row_boxes();
void position_cell_boxes();