1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:47:44 +00:00

LibWeb: Rename the LayoutMode enum values and explain them

The old mode names, while mechanically accurate, didn't really reflect
their relationship to the CSS specifications.

This patch renames them as follows:

    Default => Normal
    AllPossibleLineBreaks => MinContent
    OnlyRequiredLineBreaks => MaxContent

There's also now an explainer comment with the LayoutMode enum about the
specific implications of layout in each mode.
This commit is contained in:
Andreas Kling 2022-03-19 15:44:02 +01:00
parent ceb055a75e
commit c1f0d21bbe
10 changed files with 43 additions and 32 deletions

View file

@ -577,7 +577,7 @@ void Document::update_layout()
icb.set_has_definite_width(true); icb.set_has_definite_width(true);
icb.set_has_definite_height(true); icb.set_has_definite_height(true);
root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Default); root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Normal);
formatting_state.commit(); formatting_state.commit();
m_layout_root->build_stacking_context_tree(); m_layout_root->build_stacking_context_tree();

View file

@ -224,13 +224,13 @@ void BlockFormattingContext::compute_width_for_floating_box(Box const& box, Layo
float width_of_containing_block = 0; float width_of_containing_block = 0;
switch (layout_mode) { switch (layout_mode) {
case LayoutMode::Default: case LayoutMode::Normal:
width_of_containing_block = m_state.get(containing_block).content_width; width_of_containing_block = m_state.get(containing_block).content_width;
break; break;
case LayoutMode::AllPossibleLineBreaks: case LayoutMode::MinContent:
width_of_containing_block = 0; width_of_containing_block = 0;
break; break;
case LayoutMode::OnlyRequiredLineBreaks: case LayoutMode::MaxContent:
width_of_containing_block = INFINITY; width_of_containing_block = INFINITY;
break; break;
} }
@ -408,7 +408,7 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer const& b
return IterationDecision::Continue; return IterationDecision::Continue;
}); });
if (layout_mode != LayoutMode::Default) { if (layout_mode != LayoutMode::Normal) {
auto& width = block_container.computed_values().width(); auto& width = block_container.computed_values().width();
if (!width.has_value() || (width->is_length() && width->length().is_auto())) { if (!width.has_value() || (width->is_length() && width->length().is_auto())) {
auto& block_container_state = m_state.get_mutable(block_container); auto& block_container_state = m_state.get_mutable(block_container);
@ -559,13 +559,13 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
float width_of_containing_block = 0; float width_of_containing_block = 0;
switch (layout_mode) { switch (layout_mode) {
case LayoutMode::Default: case LayoutMode::Normal:
width_of_containing_block = m_state.get(containing_block).content_width; width_of_containing_block = m_state.get(containing_block).content_width;
break; break;
case LayoutMode::AllPossibleLineBreaks: case LayoutMode::MinContent:
width_of_containing_block = 0; width_of_containing_block = 0;
break; break;
case LayoutMode::OnlyRequiredLineBreaks: case LayoutMode::MaxContent:
width_of_containing_block = INFINITY; width_of_containing_block = INFINITY;
break; break;
} }

View file

@ -27,7 +27,7 @@ public:
auto const& right_side_floats() const { return m_right_floats; } auto const& right_side_floats() const { return m_right_floats; }
static float compute_theoretical_height(FormattingState const&, Box const&); static float compute_theoretical_height(FormattingState const&, Box const&);
void compute_width(Box const&, LayoutMode = LayoutMode::Default); void compute_width(Box const&, LayoutMode = LayoutMode::Normal);
// https://www.w3.org/TR/css-display/#block-formatting-context-root // https://www.w3.org/TR/css-display/#block-formatting-context-root
BlockContainer const& root() const { return static_cast<BlockContainer const&>(context_box()); } BlockContainer const& root() const { return static_cast<BlockContainer const&>(context_box()); }

View file

@ -112,7 +112,7 @@ void FlexFormattingContext::run(Box const& run_box, LayoutMode)
// AD-HOC: Layout the inside of all flex items. // AD-HOC: Layout the inside of all flex items.
copy_dimensions_from_flex_items_to_boxes(); copy_dimensions_from_flex_items_to_boxes();
for (auto& flex_item : m_flex_items) { for (auto& flex_item : m_flex_items) {
auto independent_formatting_context = layout_inside(flex_item.box, LayoutMode::Default); auto independent_formatting_context = layout_inside(flex_item.box, LayoutMode::Normal);
independent_formatting_context->parent_context_did_dimension_child_root_box(); independent_formatting_context->parent_context_did_dimension_child_root_box();
} }
@ -451,7 +451,7 @@ float FlexFormattingContext::calculate_indefinite_main_size(FlexItem const& item
} else { } else {
box_state.content_width = resolved_definite_cross_size(item.box); box_state.content_width = resolved_definite_cross_size(item.box);
} }
independent_formatting_context->run(item.box, LayoutMode::Default); independent_formatting_context->run(item.box, LayoutMode::Normal);
if (is_row_layout()) if (is_row_layout())
return box_state.content_width; return box_state.content_width;
@ -477,7 +477,7 @@ float FlexFormattingContext::calculate_indefinite_main_size(FlexItem const& item
VERIFY(independent_formatting_context); VERIFY(independent_formatting_context);
box_state.content_width = fit_content_cross_size; box_state.content_width = fit_content_cross_size;
independent_formatting_context->run(item.box, LayoutMode::Default); independent_formatting_context->run(item.box, LayoutMode::Normal);
return BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box); return BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box);
} }
@ -825,7 +825,7 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
} else { } else {
box_state.content_height = resolved_definite_main_size(item.box); box_state.content_height = resolved_definite_main_size(item.box);
} }
independent_formatting_context->run(item.box, LayoutMode::Default); independent_formatting_context->run(item.box, LayoutMode::Normal);
if (is_row_layout()) if (is_row_layout())
item.hypothetical_cross_size = BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box); item.hypothetical_cross_size = BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box);
@ -854,7 +854,7 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
VERIFY(independent_formatting_context); VERIFY(independent_formatting_context);
box_state.content_width = fit_content_main_size; box_state.content_width = fit_content_main_size;
independent_formatting_context->run(item.box, LayoutMode::Default); independent_formatting_context->run(item.box, LayoutMode::Normal);
item.hypothetical_cross_size = BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box); item.hypothetical_cross_size = BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box);
} }

View file

@ -692,7 +692,7 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box)
auto specified_width = box.computed_values().width().has_value() ? box.computed_values().width()->resolved(box, width_of_containing_block).resolved(box) : CSS::Length::make_auto(); auto specified_width = box.computed_values().width().has_value() ? box.computed_values().width()->resolved(box, width_of_containing_block).resolved(box) : CSS::Length::make_auto();
compute_width_for_absolutely_positioned_element(box); compute_width_for_absolutely_positioned_element(box);
auto independent_formatting_context = layout_inside(box, LayoutMode::Default); auto independent_formatting_context = layout_inside(box, LayoutMode::Normal);
compute_height_for_absolutely_positioned_element(box); compute_height_for_absolutely_positioned_element(box);
box_state.margin_left = box.computed_values().margin().left.resolved(box, width_of_containing_block).to_px(box); box_state.margin_left = box.computed_values().margin().left.resolved(box, width_of_containing_block).to_px(box);
@ -824,7 +824,7 @@ FormattingState::IntrinsicSizes FormattingContext::calculate_intrinsic_sizes(Lay
auto independent_formatting_context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box); auto independent_formatting_context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
VERIFY(independent_formatting_context); VERIFY(independent_formatting_context);
independent_formatting_context->run(box, LayoutMode::OnlyRequiredLineBreaks); independent_formatting_context->run(box, LayoutMode::MaxContent);
cached_box_sizes.max_content_size.set_width(independent_formatting_context->greatest_child_width(box)); cached_box_sizes.max_content_size.set_width(independent_formatting_context->greatest_child_width(box));
cached_box_sizes.max_content_size.set_height(BlockFormattingContext::compute_theoretical_height(throwaway_state, box)); cached_box_sizes.max_content_size.set_height(BlockFormattingContext::compute_theoretical_height(throwaway_state, box));
} }
@ -836,7 +836,7 @@ FormattingState::IntrinsicSizes FormattingContext::calculate_intrinsic_sizes(Lay
containing_block_state.content_height = 0; containing_block_state.content_height = 0;
auto independent_formatting_context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box); auto independent_formatting_context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
VERIFY(independent_formatting_context); VERIFY(independent_formatting_context);
independent_formatting_context->run(box, LayoutMode::AllPossibleLineBreaks); independent_formatting_context->run(box, LayoutMode::MinContent);
cached_box_sizes.min_content_size.set_width(independent_formatting_context->greatest_child_width(box)); cached_box_sizes.min_content_size.set_width(independent_formatting_context->greatest_child_width(box));
cached_box_sizes.min_content_size.set_height(BlockFormattingContext::compute_theoretical_height(throwaway_state, box)); cached_box_sizes.min_content_size.set_height(BlockFormattingContext::compute_theoretical_height(throwaway_state, box));
} }

View file

@ -84,7 +84,7 @@ void InlineFormattingContext::run(Box const&, LayoutMode layout_mode)
auto& containing_block_state = m_state.get_mutable(containing_block()); auto& containing_block_state = m_state.get_mutable(containing_block());
if (layout_mode != LayoutMode::Default) { if (layout_mode != LayoutMode::Normal) {
containing_block_state.content_width = max_line_width; containing_block_state.content_width = max_line_width;
} }

View file

@ -37,13 +37,13 @@ void LineBuilder::begin_new_line(bool increment_y)
m_current_y += max(m_max_height_on_current_line, m_context.containing_block().line_height()); m_current_y += max(m_max_height_on_current_line, m_context.containing_block().line_height());
switch (m_layout_mode) { switch (m_layout_mode) {
case LayoutMode::Default: case LayoutMode::Normal:
m_available_width_for_current_line = m_context.available_space_for_line(m_current_y); m_available_width_for_current_line = m_context.available_space_for_line(m_current_y);
break; break;
case LayoutMode::AllPossibleLineBreaks: case LayoutMode::MinContent:
m_available_width_for_current_line = 0; m_available_width_for_current_line = 0;
break; break;
case LayoutMode::OnlyRequiredLineBreaks: case LayoutMode::MaxContent:
m_available_width_for_current_line = INFINITY; m_available_width_for_current_line = INFINITY;
break; break;
} }
@ -81,11 +81,11 @@ void LineBuilder::append_text_chunk(TextNode const& text_node, size_t offset_in_
bool LineBuilder::should_break(LayoutMode layout_mode, float next_item_width, bool should_force_break) bool LineBuilder::should_break(LayoutMode layout_mode, float next_item_width, bool should_force_break)
{ {
if (layout_mode == LayoutMode::AllPossibleLineBreaks) if (layout_mode == LayoutMode::MinContent)
return true; return true;
if (should_force_break) if (should_force_break)
return true; return true;
if (layout_mode == LayoutMode::OnlyRequiredLineBreaks) if (layout_mode == LayoutMode::MaxContent)
return false; return false;
auto const& line_boxes = m_containing_block_state.line_boxes; auto const& line_boxes = m_containing_block_state.line_boxes;
if (line_boxes.is_empty() || line_boxes.last().is_empty()) if (line_boxes.is_empty() || line_boxes.last().is_empty())

View file

@ -21,9 +21,20 @@
namespace Web::Layout { namespace Web::Layout {
enum class LayoutMode { enum class LayoutMode {
Default, // Normal layout.
AllPossibleLineBreaks, // - We use the containing block's used width.
OnlyRequiredLineBreaks, // - Content flows into the available space, line breaks inserted where necessary.
Normal,
// MinContent layout is used for discovering the min-content intrinsic size of a box.
// - We act as if the containing block has 0 used width.
// - Every line-breaking opportunity is taken.
MinContent,
// MaxContent layout is used for discovering the max-content intrinsic size of a box.
// - We act as if the containing block has infinite used width.
// - Only forced line-breaking opportunities are taken.
MaxContent,
}; };
class Node : public TreeNode<Node> { class Node : public TreeNode<Node> {

View file

@ -81,9 +81,9 @@ void TableFormattingContext::calculate_column_widths(Box const& row, Vector<floa
auto& cell_state = m_state.get_mutable(cell); auto& cell_state = m_state.get_mutable(cell);
compute_width(cell); compute_width(cell);
if (use_auto_layout) { if (use_auto_layout) {
(void)layout_inside(cell, LayoutMode::OnlyRequiredLineBreaks); (void)layout_inside(cell, LayoutMode::MaxContent);
} else { } else {
(void)layout_inside(cell, LayoutMode::Default); (void)layout_inside(cell, LayoutMode::Normal);
} }
column_widths[column_index] = max(column_widths[column_index], cell_state.content_width); column_widths[column_index] = max(column_widths[column_index], cell_state.content_width);
column_index += cell.colspan(); column_index += cell.colspan();
@ -105,9 +105,9 @@ void TableFormattingContext::layout_row(Box const& row, Vector<float>& column_wi
// Layout the cell contents a second time, now that we know its final width. // Layout the cell contents a second time, now that we know its final width.
if (use_auto_layout) { if (use_auto_layout) {
(void)layout_inside(cell, LayoutMode::OnlyRequiredLineBreaks); (void)layout_inside(cell, LayoutMode::MaxContent);
} else { } else {
(void)layout_inside(cell, LayoutMode::Default); (void)layout_inside(cell, LayoutMode::Normal);
} }
BlockFormattingContext::compute_height(cell, m_state); BlockFormattingContext::compute_height(cell, m_state);

View file

@ -141,7 +141,7 @@ Optional<TextNode::Chunk> TextNode::ChunkIterator::next()
} }
} }
if (m_wrap_lines || m_layout_mode == LayoutMode::AllPossibleLineBreaks) { if (m_wrap_lines || m_layout_mode == LayoutMode::MinContent) {
bool is_space = is_ascii_space(*m_iterator); bool is_space = is_ascii_space(*m_iterator);
if (is_space != m_last_was_space) { if (is_space != m_last_was_space) {
m_last_was_space = is_space; m_last_was_space = is_space;
@ -163,7 +163,7 @@ Optional<TextNode::Chunk> TextNode::ChunkIterator::next()
Optional<TextNode::Chunk> TextNode::ChunkIterator::try_commit_chunk(Utf8View::Iterator const& start, Utf8View::Iterator const& end, bool has_breaking_newline, bool must_commit) const Optional<TextNode::Chunk> TextNode::ChunkIterator::try_commit_chunk(Utf8View::Iterator const& start, Utf8View::Iterator const& end, bool has_breaking_newline, bool must_commit) const
{ {
if (m_layout_mode == LayoutMode::OnlyRequiredLineBreaks && !must_commit) if (m_layout_mode == LayoutMode::MaxContent && !must_commit)
return {}; return {};
auto byte_offset = m_utf8_view.byte_offset_of(start); auto byte_offset = m_utf8_view.byte_offset_of(start);