From f73aa8e2bd06155bb18a6dd3a0f67ebbb3690d1f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 6 Oct 2021 21:53:25 +0200 Subject: [PATCH] LibWeb: Move line boxes from Layout::Box to BlockContainer Per the spec, only a BlockContainer" can have line boxes, so let's not clutter up every Layout::Box with line boxes. This also allows us to establish an invariant that BFC and IFC always operate on a Layout::BlockContainer. Note that if BlockContainer has all block-level children, its line boxes are not used for anything. They are only used in the all inline-level children scenario. --- .../LibWeb/Layout/BlockContainer.cpp | 13 ++++++ .../Libraries/LibWeb/Layout/BlockContainer.h | 9 ++++ .../LibWeb/Layout/BlockFormattingContext.cpp | 43 ++++++++++--------- .../LibWeb/Layout/BlockFormattingContext.h | 19 ++++---- Userland/Libraries/LibWeb/Layout/Box.cpp | 13 ------ Userland/Libraries/LibWeb/Layout/Box.h | 9 ---- .../LibWeb/Layout/FlexFormattingContext.cpp | 12 +++--- .../LibWeb/Layout/FormattingContext.cpp | 19 ++++---- .../LibWeb/Layout/InlineFormattingContext.cpp | 2 +- .../LibWeb/Layout/InlineFormattingContext.h | 7 +-- .../Libraries/LibWeb/Layout/InlineNode.cpp | 2 +- .../LibWeb/Layout/TableFormattingContext.cpp | 4 +- .../LibWeb/Layout/TableFormattingContext.h | 2 +- 13 files changed, 80 insertions(+), 74 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp index 3624a94a84..a22981a9fe 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp @@ -147,4 +147,17 @@ bool BlockContainer::handle_mousewheel(Badge, const Gfx::IntPoint& return true; } +LineBox& BlockContainer::ensure_last_line_box() +{ + if (m_line_boxes.is_empty()) + return add_line_box(); + return m_line_boxes.last(); +} + +LineBox& BlockContainer::add_line_box() +{ + m_line_boxes.append(LineBox()); + return m_line_boxes.last(); +} + } diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.h b/Userland/Libraries/LibWeb/Layout/BlockContainer.h index d502b1fa7a..1e5017a671 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockContainer.h +++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.h @@ -38,6 +38,15 @@ public: const Gfx::FloatPoint& scroll_offset() const { return m_scroll_offset; } void set_scroll_offset(const Gfx::FloatPoint&); + Vector& line_boxes() { return m_line_boxes; } + const Vector& line_boxes() const { return m_line_boxes; } + + LineBox& ensure_last_line_box(); + LineBox& add_line_box(); + +protected: + Vector m_line_boxes; + private: virtual bool is_block_container() const final { return true; } virtual bool wants_mouse_events() const override { return false; } diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 1a5c4953cb..6727d9444b 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2020-2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -17,7 +17,7 @@ namespace Web::Layout { -BlockFormattingContext::BlockFormattingContext(Box& root, FormattingContext* parent) +BlockFormattingContext::BlockFormattingContext(BlockContainer& root, FormattingContext* parent) : FormattingContext(root, parent) { } @@ -46,9 +46,9 @@ void BlockFormattingContext::run(Box& box, LayoutMode layout_mode) compute_width(box); if (box.children_are_inline()) { - layout_inline_children(box, layout_mode); + layout_inline_children(verify_cast(box), layout_mode); } else { - layout_block_level_children(box, layout_mode); + layout_block_level_children(verify_cast(box), layout_mode); } if (layout_mode == LayoutMode::Default) { @@ -289,7 +289,7 @@ void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_n box.set_width(compute_width_for_replaced_element(box)); } -static float compute_auto_height_for_block_level_element(const Box& box) +static float compute_auto_height_for_block_level_element(Box const& box) { Optional top; Optional bottom; @@ -297,12 +297,13 @@ static float compute_auto_height_for_block_level_element(const Box& box) if (box.children_are_inline()) { // If it only has inline-level children, the height is the distance between // the top of the topmost line box and the bottom of the bottommost line box. - if (!box.line_boxes().is_empty()) { - for (auto& fragment : box.line_boxes().first().fragments()) { + auto& block_container = verify_cast(box); + if (!block_container.line_boxes().is_empty()) { + for (auto& fragment : block_container.line_boxes().first().fragments()) { if (!top.has_value() || fragment.offset().y() < top.value()) top = fragment.offset().y(); } - for (auto& fragment : box.line_boxes().last().fragments()) { + for (auto& fragment : block_container.line_boxes().last().fragments()) { if (!bottom.has_value() || (fragment.offset().y() + fragment.height()) > bottom.value()) bottom = fragment.offset().y() + fragment.height(); } @@ -415,23 +416,23 @@ void BlockFormattingContext::compute_position(Box& box) } } -void BlockFormattingContext::layout_inline_children(Box& box, LayoutMode layout_mode) +void BlockFormattingContext::layout_inline_children(BlockContainer& block_container, LayoutMode layout_mode) { - InlineFormattingContext context(box, this); - context.run(box, layout_mode); + InlineFormattingContext context(block_container, this); + context.run(block_container, layout_mode); } -void BlockFormattingContext::layout_block_level_children(Box& box, LayoutMode layout_mode) +void BlockFormattingContext::layout_block_level_children(BlockContainer& block_container, LayoutMode layout_mode) { float content_height = 0; float content_width = 0; - box.for_each_child_of_type([&](auto& child_box) { + block_container.for_each_child_of_type([&](Box& child_box) { if (child_box.is_absolutely_positioned()) return IterationDecision::Continue; if (child_box.is_floating()) { - layout_floating_child(child_box, box); + layout_floating_child(child_box, block_container); return IterationDecision::Continue; } @@ -443,9 +444,9 @@ void BlockFormattingContext::layout_block_level_children(Box& box, LayoutMode la compute_position(child_box); if (is(child_box)) - place_block_level_replaced_element_in_normal_flow(child_box, box); + place_block_level_replaced_element_in_normal_flow(child_box, block_container); else if (is(child_box)) - place_block_level_non_replaced_element_in_normal_flow(child_box, box); + place_block_level_non_replaced_element_in_normal_flow(child_box, block_container); // FIXME: This should be factored differently. It's uncool that we mutate the tree *during* layout! // Instead, we should generate the marker box during the tree build. @@ -458,12 +459,12 @@ void BlockFormattingContext::layout_block_level_children(Box& box, LayoutMode la }); if (layout_mode != LayoutMode::Default) { - if (box.computed_values().width().is_undefined() || box.computed_values().width().is_auto()) - box.set_width(content_width); + if (block_container.computed_values().width().is_undefined() || block_container.computed_values().width().is_auto()) + block_container.set_width(content_width); } } -void BlockFormattingContext::place_block_level_replaced_element_in_normal_flow(Box& child_box, Box& containing_block) +void BlockFormattingContext::place_block_level_replaced_element_in_normal_flow(Box& child_box, BlockContainer const& containing_block) { VERIFY(!containing_block.is_absolutely_positioned()); auto& replaced_element_box_model = child_box.box_model(); @@ -485,7 +486,7 @@ void BlockFormattingContext::place_block_level_replaced_element_in_normal_flow(B child_box.set_offset(x, y); } -void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_flow(Box& child_box, Box& containing_block) +void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_flow(Box& child_box, BlockContainer const& containing_block) { auto& box_model = child_box.box_model(); auto& computed_values = child_box.computed_values(); @@ -600,7 +601,7 @@ static Gfx::FloatRect rect_in_coordinate_space(const Box& box, const Box& contex return rect; } -void BlockFormattingContext::layout_floating_child(Box& box, Box& containing_block) +void BlockFormattingContext::layout_floating_child(Box& box, BlockContainer const& containing_block) { VERIFY(box.is_floating()); diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index c47bb716df..c8a324992c 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace Web::Layout { @@ -15,7 +16,7 @@ namespace Web::Layout { // https://drafts.csswg.org/css-display/#block-formatting-context class BlockFormattingContext : public FormattingContext { public: - explicit BlockFormattingContext(Box&, FormattingContext* parent); + explicit BlockFormattingContext(BlockContainer&, FormattingContext* parent); ~BlockFormattingContext(); virtual void run(Box&, LayoutMode) override; @@ -25,12 +26,12 @@ public: const Vector& left_floating_boxes() const { return m_left_floating_boxes; } const Vector& right_floating_boxes() const { return m_right_floating_boxes; } - static float compute_theoretical_height(const Box&); + static float compute_theoretical_height(Box const&); void compute_width(Box&); // https://drafts.csswg.org/css-display/#block-formatting-context-root - Box& root() { return context_box(); } - Box const& root() const { return context_box(); } + BlockContainer& root() { return static_cast(context_box()); } + BlockContainer const& root() const { return static_cast(context_box()); } protected: static void compute_height(Box&); @@ -45,13 +46,13 @@ private: void layout_initial_containing_block(LayoutMode); - void layout_block_level_children(Box&, LayoutMode); - void layout_inline_children(Box&, LayoutMode); + void layout_block_level_children(BlockContainer&, LayoutMode); + void layout_inline_children(BlockContainer&, LayoutMode); - void place_block_level_replaced_element_in_normal_flow(Box& child, Box& container); - void place_block_level_non_replaced_element_in_normal_flow(Box& child, Box& container); + void place_block_level_replaced_element_in_normal_flow(Box& child, BlockContainer const&); + void place_block_level_non_replaced_element_in_normal_flow(Box& child, BlockContainer const&); - void layout_floating_child(Box&, Box& containing_block); + void layout_floating_child(Box& child, BlockContainer const& containing_block); void apply_transformations_to_children(Box&); diff --git a/Userland/Libraries/LibWeb/Layout/Box.cpp b/Userland/Libraries/LibWeb/Layout/Box.cpp index b097024b00..62a205207b 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.cpp +++ b/Userland/Libraries/LibWeb/Layout/Box.cpp @@ -238,19 +238,6 @@ StackingContext* Box::enclosing_stacking_context() VERIFY_NOT_REACHED(); } -LineBox& Box::ensure_last_line_box() -{ - if (m_line_boxes.is_empty()) - return add_line_box(); - return m_line_boxes.last(); -} - -LineBox& Box::add_line_box() -{ - m_line_boxes.append(LineBox()); - return m_line_boxes.last(); -} - float Box::width_of_logical_containing_block() const { auto* containing_block = this->containing_block(); diff --git a/Userland/Libraries/LibWeb/Layout/Box.h b/Userland/Libraries/LibWeb/Layout/Box.h index 43d2728b33..2248d81be3 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.h +++ b/Userland/Libraries/LibWeb/Layout/Box.h @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -118,12 +117,6 @@ public: virtual void paint_box_shadow(PaintContext& context); virtual void paint_background(PaintContext& context); - Vector& line_boxes() { return m_line_boxes; } - const Vector& line_boxes() const { return m_line_boxes; } - - LineBox& ensure_last_line_box(); - LineBox& add_line_box(); - virtual float width_of_logical_containing_block() const; Painting::BorderRadiusData normalized_border_radius_data(); @@ -141,8 +134,6 @@ protected: virtual void did_set_rect() { } - Vector m_line_boxes; - private: virtual bool is_box() const final { return true; } diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index c004519df2..e105e0ab34 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -84,9 +84,10 @@ void FlexFormattingContext::run(Box& box, LayoutMode) } if (!main_constrained && box.children_are_inline()) { - BlockFormattingContext bfc(box, this); + auto& block_container = verify_cast(box); + BlockFormattingContext bfc(block_container, this); bfc.run(box, LayoutMode::Default); - InlineFormattingContext ifc(box, &bfc); + InlineFormattingContext ifc(block_container, &bfc); if (is_row) { ifc.run(box, LayoutMode::OnlyRequiredLineBreaks); @@ -236,9 +237,10 @@ void FlexFormattingContext::run(Box& box, LayoutMode) } if (!cross_constrained && box.children_are_inline()) { - BlockFormattingContext bfc(box, this); + auto& block_container = verify_cast(box); + BlockFormattingContext bfc(block_container, this); bfc.run(box, LayoutMode::Default); - InlineFormattingContext ifc(box, &bfc); + InlineFormattingContext ifc(block_container, &bfc); ifc.run(box, LayoutMode::OnlyRequiredLineBreaks); if (is_row) @@ -248,7 +250,7 @@ void FlexFormattingContext::run(Box& box, LayoutMode) if (is_row) { return BlockFormattingContext::compute_theoretical_height(box); } else { - BlockFormattingContext context(box, this); + BlockFormattingContext context(verify_cast(box), this); context.compute_width(box); return box.width(); } diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index e42fd77ddb..294d153035 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -94,13 +94,13 @@ void FormattingContext::layout_inside(Box& child_box, LayoutMode layout_mode) } if (creates_block_formatting_context(child_box)) { - BlockFormattingContext context(child_box, this); + BlockFormattingContext context(verify_cast(child_box), this); context.run(child_box, layout_mode); return; } if (child_display.is_table_inside()) { - TableFormattingContext context(child_box, this); + TableFormattingContext context(verify_cast(child_box), this); context.run(child_box, layout_mode); return; } @@ -108,7 +108,7 @@ void FormattingContext::layout_inside(Box& child_box, LayoutMode layout_mode) VERIFY(is_block_formatting_context()); if (child_box.children_are_inline()) { - InlineFormattingContext context(child_box, this); + InlineFormattingContext context(verify_cast(child_box), this); context.run(child_box, layout_mode); return; } @@ -117,11 +117,11 @@ void FormattingContext::layout_inside(Box& child_box, LayoutMode layout_mode) run(child_box, layout_mode); } -static float greatest_child_width(const Box& box) +static float greatest_child_width(Box const& box) { float max_width = 0; if (box.children_are_inline()) { - for (auto& child : box.line_boxes()) { + for (auto& child : verify_cast(box).line_boxes()) { max_width = max(max_width, child.width()); } } else { @@ -186,7 +186,7 @@ static Gfx::FloatSize solve_replaced_size_constraint(float w, float h, const Rep return { w, h }; } -static float compute_auto_height_for_block_level_element(const Box& box) +static float compute_auto_height_for_block_level_element(Box const& box) { Optional top; Optional bottom; @@ -194,12 +194,13 @@ static float compute_auto_height_for_block_level_element(const Box& box) if (box.children_are_inline()) { // If it only has inline-level children, the height is the distance between // the top of the topmost line box and the bottom of the bottommost line box. - if (!box.line_boxes().is_empty()) { - for (auto& fragment : box.line_boxes().first().fragments()) { + auto& block_container = verify_cast(box); + if (!block_container.line_boxes().is_empty()) { + for (auto& fragment : block_container.line_boxes().first().fragments()) { if (!top.has_value() || fragment.offset().y() < top.value()) top = fragment.offset().y(); } - for (auto& fragment : box.line_boxes().last().fragments()) { + for (auto& fragment : block_container.line_boxes().last().fragments()) { if (!bottom.has_value() || (fragment.offset().y() + fragment.height()) > bottom.value()) bottom = fragment.offset().y() + fragment.height(); } diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 0377b9610b..09fd2b063c 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -15,7 +15,7 @@ namespace Web::Layout { -InlineFormattingContext::InlineFormattingContext(Box& containing_block, FormattingContext* parent) +InlineFormattingContext::InlineFormattingContext(BlockContainer& containing_block, FormattingContext* parent) : FormattingContext(containing_block, parent) { } diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h index f4573433e7..fbf75b1684 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h @@ -8,17 +8,18 @@ #include #include +#include #include namespace Web::Layout { class InlineFormattingContext final : public FormattingContext { public: - InlineFormattingContext(Box& containing_block, FormattingContext* parent); + InlineFormattingContext(BlockContainer& containing_block, FormattingContext* parent); ~InlineFormattingContext(); - Box& containing_block() { return context_box(); } - const Box& containing_block() const { return context_box(); } + BlockContainer& containing_block() { return static_cast(context_box()); } + BlockContainer const& containing_block() const { return static_cast(context_box()); } virtual void run(Box&, LayoutMode) override; diff --git a/Userland/Libraries/LibWeb/Layout/InlineNode.cpp b/Userland/Libraries/LibWeb/Layout/InlineNode.cpp index 5761d8e5bc..f2b3651f2c 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineNode.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineNode.cpp @@ -29,7 +29,7 @@ InlineNode::~InlineNode() void InlineNode::split_into_lines(InlineFormattingContext& context, LayoutMode layout_mode) { - auto& containing_block = context.context_box(); + auto& containing_block = context.containing_block(); if (!computed_values().padding().left.is_undefined_or_auto()) { float padding_left = computed_values().padding().left.resolved(CSS::Length::make_px(0), *this, containing_block.width()).to_px(*this); diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp index 677a24f1b7..b577eb4459 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp @@ -16,8 +16,8 @@ namespace Web::Layout { -TableFormattingContext::TableFormattingContext(Box& context_box, FormattingContext* parent) - : BlockFormattingContext(context_box, parent) +TableFormattingContext::TableFormattingContext(BlockContainer& block_container, FormattingContext* parent) + : BlockFormattingContext(block_container, parent) { } diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h index f5eae985f4..0567cec5d5 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h @@ -13,7 +13,7 @@ namespace Web::Layout { class TableFormattingContext final : public BlockFormattingContext { public: - explicit TableFormattingContext(Box&, FormattingContext* parent); + explicit TableFormattingContext(BlockContainer&, FormattingContext* parent); ~TableFormattingContext(); virtual void run(Box&, LayoutMode) override;