diff options
author | Andreas Kling <kling@serenityos.org> | 2020-12-06 19:48:02 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-12-06 20:05:04 +0100 |
commit | 59de4adb607b3196297dadf1a22d1e56c4e0083b (patch) | |
tree | d40e23a3b405e77a836e05ae4cf96443dc2fe996 | |
parent | b638e74b6898359886a69c7004930a3036282c47 (diff) | |
download | serenity-59de4adb607b3196297dadf1a22d1e56c4e0083b.zip |
LibWeb: Pass current target box to BFC::run()
The BFC "context box" is now the outer box of the block formatting
context. Previously the context box was always the current target box,
which made it hard to reason about who was really the containing block
of whom in various places.
Note that IFC still has the containing block as its context box, this
change only affects BFC. However, to clarify the situation in IFC,
I've added a containing_block() getter than returns the context_box().
-rw-r--r-- | Libraries/LibWeb/DOM/Document.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/BlockBox.cpp | 8 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/BlockFormattingContext.cpp | 165 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/BlockFormattingContext.h | 18 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/BreakNode.cpp | 4 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/FormattingContext.cpp | 11 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/FormattingContext.h | 4 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/InlineFormattingContext.cpp | 50 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/InlineFormattingContext.h | 6 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/Node.h | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/ReplacedBox.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/TableFormattingContext.cpp | 18 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/TableFormattingContext.h | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/TextNode.cpp | 3 |
14 files changed, 138 insertions, 156 deletions
diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index c57d7e06c7..7ef3a418e0 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -353,7 +353,7 @@ void Document::layout() } Layout::BlockFormattingContext root_formatting_context(*m_layout_root, nullptr); - root_formatting_context.run(Layout::LayoutMode::Default); + root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Default); m_layout_root->set_needs_display(); diff --git a/Libraries/LibWeb/Layout/BlockBox.cpp b/Libraries/LibWeb/Layout/BlockBox.cpp index dc4855975d..39b95277b0 100644 --- a/Libraries/LibWeb/Layout/BlockBox.cpp +++ b/Libraries/LibWeb/Layout/BlockBox.cpp @@ -110,13 +110,13 @@ HitTestResult BlockBox::hit_test(const Gfx::IntPoint& position, HitTestType type void BlockBox::split_into_lines(InlineFormattingContext& context, LayoutMode layout_mode) { - auto& container = context.context_box(); - auto* line_box = &container.ensure_last_line_box(); + auto& containing_block = context.containing_block(); + auto* line_box = &containing_block.ensure_last_line_box(); - float available_width = context.available_width_at_line(container.line_boxes().size() - 1); + float available_width = context.available_width_at_line(containing_block.line_boxes().size() - 1); if (layout_mode != LayoutMode::OnlyRequiredLineBreaks && line_box->width() > 0 && line_box->width() + width() > available_width) { - line_box = &container.add_line_box(); + line_box = &containing_block.add_line_box(); } line_box->add_fragment(*this, 0, 0, width(), height()); } diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 0369775c46..858e9d431b 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -51,34 +51,30 @@ bool BlockFormattingContext::is_initial() const return context_box().is_initial_containing_block(); } -void BlockFormattingContext::run(LayoutMode layout_mode) +void BlockFormattingContext::run(Box& box, LayoutMode layout_mode) { if (is_initial()) { layout_initial_containing_block(layout_mode); return; } - // FIXME: BFC currently computes the width+height of the context box. + // FIXME: BFC currently computes the width+height of the target box. // This is necessary to be able to place absolutely positioned descendants. // The same work is also done by the parent BFC for each of its blocks.. if (layout_mode == LayoutMode::Default) - compute_width(context_box()); + compute_width(box); - layout_floating_children(); + layout_floating_children(box); - if (context_box().children_are_inline()) { - layout_inline_children(layout_mode); + if (box.children_are_inline()) { + layout_inline_children(box, layout_mode); } else { - layout_block_level_children(layout_mode); + layout_block_level_children(box, layout_mode); } if (layout_mode == LayoutMode::Default) - compute_height(context_box()); - - // No need to layout absolute positioned boxes during shrink-to-fit layouts. - if (layout_mode == LayoutMode::Default) - layout_absolutely_positioned_descendants(); + compute_height(box); } void BlockFormattingContext::compute_width(Box& box) @@ -411,7 +407,7 @@ void BlockFormattingContext::compute_height(Box& box) } auto& style = box.style(); - auto& containing_block = context_box(); + auto& containing_block = *box.containing_block(); CSS::Length specified_height; @@ -438,80 +434,83 @@ void BlockFormattingContext::compute_height(Box& box) } } -void BlockFormattingContext::layout_inline_children(LayoutMode layout_mode) +void BlockFormattingContext::layout_inline_children(Box& box, LayoutMode layout_mode) { - InlineFormattingContext context(context_box(), this); - context.run(layout_mode); + InlineFormattingContext context(box, this); + context.run(box, layout_mode); } -void BlockFormattingContext::layout_block_level_children(LayoutMode layout_mode) +void BlockFormattingContext::layout_block_level_children(Box& box, LayoutMode layout_mode) { float content_height = 0; float content_width = 0; - context_box().for_each_in_subtree_of_type<Box>([&](auto& box) { - if (box.is_absolutely_positioned() || box.is_floating() || box.containing_block() != &context_box()) + box.for_each_child_of_type<Box>([&](auto& child_box) { + if (child_box.is_absolutely_positioned()) { + layout_absolutely_positioned_child(child_box); + return IterationDecision::Continue; + } + + if (child_box.is_floating()) return IterationDecision::Continue; - compute_width(box); - layout_inside(box, layout_mode); - compute_height(box); + compute_width(child_box); + layout_inside(child_box, layout_mode); + compute_height(child_box); - if (box.is_replaced()) - place_block_level_replaced_element_in_normal_flow(box); - else if (box.is_block()) - place_block_level_non_replaced_element_in_normal_flow(box); + if (child_box.is_replaced()) + place_block_level_replaced_element_in_normal_flow(child_box, box); + else if (child_box.is_block()) + place_block_level_non_replaced_element_in_normal_flow(child_box, box); else - dbgln("FIXME: Layout::BlockBox::layout_contained_boxes doesn't know how to place a {}", box.class_name()); + dbgln("FIXME: BlockFormattingContext::layout_block_level_children() doesn't know how to place a {}", child_box.class_name()); // 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. - if (is<ListItemBox>(box)) - downcast<ListItemBox>(box).layout_marker(); + if (is<ListItemBox>(child_box)) + downcast<ListItemBox>(child_box).layout_marker(); - content_height = max(content_height, box.effective_offset().y() + box.height() + box.box_model().margin_box(box).bottom); - content_width = max(content_width, downcast<Box>(box).width()); + content_height = max(content_height, child_box.effective_offset().y() + child_box.height() + child_box.box_model().margin_box(child_box).bottom); + content_width = max(content_width, downcast<Box>(child_box).width()); return IterationDecision::Continue; }); if (layout_mode != LayoutMode::Default) { - if (context_box().style().width().is_undefined() || context_box().style().width().is_auto()) - context_box().set_width(content_width); + if (box.style().width().is_undefined() || box.style().width().is_auto()) + box.set_width(content_width); } - // FIXME: It's not right to always shrink-wrap the context box to the content here. - context_box().set_height(content_height); + // FIXME: It's not right to always shrink-wrap the box to the content here. + box.set_height(content_height); } -void BlockFormattingContext::place_block_level_replaced_element_in_normal_flow(Box& box) +void BlockFormattingContext::place_block_level_replaced_element_in_normal_flow(Box& child_box, Box& containing_block) { - auto& containing_block = context_box(); ASSERT(!containing_block.is_absolutely_positioned()); - auto& replaced_element_box_model = box.box_model(); + auto& replaced_element_box_model = child_box.box_model(); - replaced_element_box_model.margin.top = box.style().margin().top.resolved_or_zero(context_box(), containing_block.width()); - replaced_element_box_model.margin.bottom = box.style().margin().bottom.resolved_or_zero(context_box(), containing_block.width()); - replaced_element_box_model.border.top = CSS::Length::make_px(box.style().border_top().width); - replaced_element_box_model.border.bottom = CSS::Length::make_px(box.style().border_bottom().width); - replaced_element_box_model.padding.top = box.style().padding().top.resolved_or_zero(context_box(), containing_block.width()); - replaced_element_box_model.padding.bottom = box.style().padding().bottom.resolved_or_zero(context_box(), containing_block.width()); + replaced_element_box_model.margin.top = child_box.style().margin().top.resolved_or_zero(containing_block, containing_block.width()); + replaced_element_box_model.margin.bottom = child_box.style().margin().bottom.resolved_or_zero(containing_block, containing_block.width()); + replaced_element_box_model.border.top = CSS::Length::make_px(child_box.style().border_top().width); + replaced_element_box_model.border.bottom = CSS::Length::make_px(child_box.style().border_bottom().width); + replaced_element_box_model.padding.top = child_box.style().padding().top.resolved_or_zero(containing_block, containing_block.width()); + replaced_element_box_model.padding.bottom = child_box.style().padding().bottom.resolved_or_zero(containing_block, containing_block.width()); - float x = replaced_element_box_model.margin.left.to_px(box) - + replaced_element_box_model.border.left.to_px(box) - + replaced_element_box_model.padding.left.to_px(box) - + replaced_element_box_model.offset.left.to_px(box); + float x = replaced_element_box_model.margin.left.to_px(child_box) + + replaced_element_box_model.border.left.to_px(child_box) + + replaced_element_box_model.padding.left.to_px(child_box) + + replaced_element_box_model.offset.left.to_px(child_box); - float y = replaced_element_box_model.margin_box(box).top + context_box().box_model().offset.top.to_px(box); + float y = replaced_element_box_model.margin_box(child_box).top + containing_block.box_model().offset.top.to_px(child_box); - box.set_offset(x, y); + child_box.set_offset(x, y); } -void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_flow(Box& box) +void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_flow(Box& child_box, Box& containing_block) { auto zero_value = CSS::Length::make_px(0); - auto& containing_block = context_box(); - auto& box_model = box.box_model(); - auto& style = box.style(); + auto& box_model = child_box.box_model(); + auto& style = child_box.style(); box_model.margin.top = style.margin().top.resolved(zero_value, containing_block, containing_block.width()); box_model.margin.bottom = style.margin().bottom.resolved(zero_value, containing_block, containing_block.width()); @@ -520,22 +519,22 @@ void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_fl box_model.padding.top = style.padding().top.resolved(zero_value, containing_block, containing_block.width()); box_model.padding.bottom = style.padding().bottom.resolved(zero_value, containing_block, containing_block.width()); - float x = box_model.margin.left.to_px(box) - + box_model.border.left.to_px(box) - + box_model.padding.left.to_px(box) - + box_model.offset.left.to_px(box); + float x = box_model.margin.left.to_px(child_box) + + box_model.border.left.to_px(child_box) + + box_model.padding.left.to_px(child_box) + + box_model.offset.left.to_px(child_box); if (containing_block.style().text_align() == CSS::TextAlign::VendorSpecificCenter) { - x = (containing_block.width() / 2) - box.width() / 2; + x = (containing_block.width() / 2) - child_box.width() / 2; } - float y = box_model.margin_box(box).top - + box_model.offset.top.to_px(box); + float y = box_model.margin_box(child_box).top + + box_model.offset.top.to_px(child_box); // NOTE: Empty (0-height) preceding siblings have their margins collapsed with *their* preceding sibling, etc. float collapsed_bottom_margin_of_preceding_siblings = 0; - auto* relevant_sibling = box.previous_sibling_of_type<Layout::BlockBox>(); + auto* relevant_sibling = child_box.previous_sibling_of_type<Layout::BlockBox>(); while (relevant_sibling != nullptr) { if (!relevant_sibling->is_absolutely_positioned() && !relevant_sibling->is_floating()) { collapsed_bottom_margin_of_preceding_siblings = max(collapsed_bottom_margin_of_preceding_siblings, relevant_sibling->box_model().margin.bottom.to_px(*relevant_sibling)); @@ -551,7 +550,7 @@ void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_fl + relevant_sibling->box_model().border_box(*relevant_sibling).bottom; // Collapse top margin with bottom margin of preceding siblings if needed - float my_margin_top = box_model.margin.top.to_px(box); + float my_margin_top = box_model.margin.top.to_px(child_box); if (my_margin_top < 0 || collapsed_bottom_margin_of_preceding_siblings < 0) { // Negative margins present. @@ -565,7 +564,7 @@ void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_fl } } - if (box.style().clear() == CSS::Clear::Left || box.style().clear() == CSS::Clear::Both) { + if (child_box.style().clear() == CSS::Clear::Left || child_box.style().clear() == CSS::Clear::Both) { if (!m_left_floating_boxes.is_empty()) { float clearance_y = 0; for (auto* floating_box : m_left_floating_boxes) { @@ -576,7 +575,7 @@ void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_fl } } - if (box.style().clear() == CSS::Clear::Right || box.style().clear() == CSS::Clear::Both) { + if (child_box.style().clear() == CSS::Clear::Right || child_box.style().clear() == CSS::Clear::Both) { if (!m_right_floating_boxes.is_empty()) { float clearance_y = 0; for (auto* floating_box : m_right_floating_boxes) { @@ -587,7 +586,7 @@ void BlockFormattingContext::place_block_level_non_replaced_element_in_normal_fl } } - box.set_offset(x, y); + child_box.set_offset(x, y); } void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_mode) @@ -599,9 +598,9 @@ void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_m icb.set_width(viewport_rect.width()); - layout_floating_children(); + layout_floating_children(context_box()); - layout_block_level_children(layout_mode); + layout_block_level_children(context_box(), layout_mode); ASSERT(!icb.children_are_inline()); @@ -613,10 +612,6 @@ void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_m }); icb.set_height(lowest_bottom); - // No need to layout absolute positioned boxes during shrink-to-fit layouts. - if (layout_mode == LayoutMode::Default) - layout_absolutely_positioned_descendants(); - // FIXME: This is a total hack. Make sure any GUI::Widgets are moved into place after layout. // We should stop embedding GUI::Widgets entirely, since that won't work out-of-process. icb.for_each_in_subtree_of_type<Layout::WidgetBox>([&](auto& widget) { @@ -625,26 +620,16 @@ void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_m }); } -void BlockFormattingContext::layout_absolutely_positioned_descendants() -{ - context_box().for_each_in_subtree_of_type<Box>([&](auto& box) { - if (box.is_absolutely_positioned() && box.containing_block() == &context_box()) { - layout_absolutely_positioned_descendant(box); - } - return IterationDecision::Continue; - }); -} - -void BlockFormattingContext::layout_floating_children() +void BlockFormattingContext::layout_floating_children(Box& box) { - context_box().for_each_child_of_type<Box>([&](auto& box) { - if (box.is_floating()) - layout_floating_child(box); + box.for_each_child_of_type<Box>([&](auto& child_box) { + if (child_box.is_floating()) + layout_floating_child(child_box, box); return IterationDecision::Continue; }); } -void BlockFormattingContext::layout_floating_child(Box& box) +void BlockFormattingContext::layout_floating_child(Box& box, Box& containing_block) { ASSERT(box.is_floating()); @@ -653,7 +638,7 @@ void BlockFormattingContext::layout_floating_child(Box& box) compute_height(box); // First we place the box normally (to get the right y coordinate.) - place_block_level_non_replaced_element_in_normal_flow(box); + place_block_level_non_replaced_element_in_normal_flow(box, containing_block); // Then we float it to the left or right. @@ -671,7 +656,7 @@ void BlockFormattingContext::layout_floating_child(Box& box) auto& previous_floating_box = *m_right_floating_boxes.last(); x = previous_floating_box.effective_offset().x() - box.width(); } else { - x = context_box().width() - box.width(); + x = containing_block.width() - box.width(); } m_right_floating_boxes.append(&box); } @@ -679,7 +664,7 @@ void BlockFormattingContext::layout_floating_child(Box& box) box.set_offset(x, y); } -void BlockFormattingContext::layout_absolutely_positioned_descendant(Box& box) +void BlockFormattingContext::layout_absolutely_positioned_child(Box& box) { auto& containing_block = context_box(); auto& box_model = box.box_model(); diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Libraries/LibWeb/Layout/BlockFormattingContext.h index d20a1c7514..21e4a57794 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -37,7 +37,7 @@ public: explicit BlockFormattingContext(Box&, FormattingContext* parent); ~BlockFormattingContext(); - virtual void run(LayoutMode) override; + virtual void run(Box&, LayoutMode) override; bool is_initial() const; @@ -55,16 +55,16 @@ private: void compute_width_for_floating_box(Box&); void layout_initial_containing_block(LayoutMode); - void layout_block_level_children(LayoutMode); - void layout_inline_children(LayoutMode); - void layout_absolutely_positioned_descendants(); - void layout_floating_children(); - void place_block_level_replaced_element_in_normal_flow(Box&); - void place_block_level_non_replaced_element_in_normal_flow(Box&); + void layout_block_level_children(Box&, LayoutMode); + void layout_inline_children(Box&, LayoutMode); + void layout_floating_children(Box&); - void layout_absolutely_positioned_descendant(Box&); - void layout_floating_child(Box&); + 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 layout_absolutely_positioned_child(Box&); + void layout_floating_child(Box&, Box& containing_block); Vector<Box*> m_left_floating_boxes; Vector<Box*> m_right_floating_boxes; diff --git a/Libraries/LibWeb/Layout/BreakNode.cpp b/Libraries/LibWeb/Layout/BreakNode.cpp index a16633e71a..9951ae4fe0 100644 --- a/Libraries/LibWeb/Layout/BreakNode.cpp +++ b/Libraries/LibWeb/Layout/BreakNode.cpp @@ -40,9 +40,9 @@ BreakNode::~BreakNode() { } -void BreakNode::split_into_lines(InlineFormattingContext& block, LayoutMode) +void BreakNode::split_into_lines(InlineFormattingContext& context, LayoutMode) { - block.context_box().add_line_box(); + context.containing_block().add_line_box(); } } diff --git a/Libraries/LibWeb/Layout/FormattingContext.cpp b/Libraries/LibWeb/Layout/FormattingContext.cpp index 5d81536260..44d1e4bcfb 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -71,22 +71,19 @@ void FormattingContext::layout_inside(Box& box, LayoutMode layout_mode) { if (creates_block_formatting_context(box)) { BlockFormattingContext context(box, this); - context.run(layout_mode); + context.run(box, layout_mode); return; } if (box.is_table()) { TableFormattingContext context(box, this); - context.run(layout_mode); + context.run(box, layout_mode); } else if (box.children_are_inline()) { InlineFormattingContext context(box, this); - context.run(layout_mode); + context.run(box, layout_mode); } else { // FIXME: This needs refactoring! ASSERT(is_block_formatting_context()); - auto& old_box = context_box(); - set_context_box(box); - run(layout_mode); - set_context_box(old_box); + run(box, layout_mode); } } diff --git a/Libraries/LibWeb/Layout/FormattingContext.h b/Libraries/LibWeb/Layout/FormattingContext.h index b505702d67..c1a305ed43 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Libraries/LibWeb/Layout/FormattingContext.h @@ -32,7 +32,7 @@ namespace Web::Layout { class FormattingContext { public: - virtual void run(LayoutMode) = 0; + virtual void run(Box&, LayoutMode) = 0; Box& context_box() { return *m_context_box; } const Box& context_box() const { return *m_context_box; } @@ -48,8 +48,6 @@ protected: FormattingContext(Box&, FormattingContext* parent = nullptr); virtual ~FormattingContext(); - void set_context_box(Box& box) { m_context_box = &box; } - void layout_inside(Box&, LayoutMode); struct ShrinkToFitResult { diff --git a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index ac914a2314..eb3a01240e 100644 --- a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -55,7 +55,7 @@ static AvailableSpaceForLineInfo available_space_for_line(const InlineFormatting AvailableSpaceForLineInfo info; // FIXME: This is a total hack guess since we don't actually know the final y position of lines here! - float line_height = context.context_box().specified_style().line_height(context.context_box()); + float line_height = context.containing_block().specified_style().line_height(context.containing_block()); float y = (line_index * line_height); auto& bfc = static_cast<const BlockFormattingContext&>(*context.parent()); @@ -69,7 +69,7 @@ static AvailableSpaceForLineInfo available_space_for_line(const InlineFormatting } } - info.right = context.context_box().width(); + info.right = context.containing_block().width(); for (ssize_t i = bfc.right_floating_boxes().size() - 1; i >= 0; --i) { auto& floating_box = *bfc.right_floating_boxes().at(i); @@ -89,13 +89,11 @@ float InlineFormattingContext::available_width_at_line(size_t line_index) const return info.right - info.left; } -void InlineFormattingContext::run(LayoutMode layout_mode) +void InlineFormattingContext::run(Box&, LayoutMode layout_mode) { - auto& containing_block = downcast<BlockBox>(context_box()); - - ASSERT(containing_block.children_are_inline()); - containing_block.line_boxes().clear(); - containing_block.for_each_child([&](auto& child) { + ASSERT(containing_block().children_are_inline()); + containing_block().line_boxes().clear(); + containing_block().for_each_child([&](auto& child) { ASSERT(child.is_inline()); if (child.is_absolutely_positioned()) return; @@ -103,21 +101,21 @@ void InlineFormattingContext::run(LayoutMode layout_mode) child.split_into_lines(*this, layout_mode); }); - for (auto& line_box : containing_block.line_boxes()) { + for (auto& line_box : containing_block().line_boxes()) { line_box.trim_trailing_whitespace(); } // If there's an empty line box at the bottom, just remove it instead of giving it height. - if (!containing_block.line_boxes().is_empty() && containing_block.line_boxes().last().fragments().is_empty()) - containing_block.line_boxes().take_last(); + if (!containing_block().line_boxes().is_empty() && containing_block().line_boxes().last().fragments().is_empty()) + containing_block().line_boxes().take_last(); - auto text_align = containing_block.style().text_align(); - float min_line_height = containing_block.specified_style().line_height(containing_block); + auto text_align = containing_block().style().text_align(); + float min_line_height = containing_block().specified_style().line_height(containing_block()); float content_height = 0; float max_linebox_width = 0; - for (size_t line_index = 0; line_index < containing_block.line_boxes().size(); ++line_index) { - auto& line_box = containing_block.line_boxes()[line_index]; + for (size_t line_index = 0; line_index < containing_block().line_boxes().size(); ++line_index) { + auto& line_box = containing_block().line_boxes()[line_index]; float max_height = min_line_height; for (auto& fragment : line_box.fragments()) { max_height = max(max_height, fragment.height()); @@ -125,7 +123,7 @@ void InlineFormattingContext::run(LayoutMode layout_mode) float x_offset = available_space_for_line(*this, line_index).left; - float excess_horizontal_space = (float)containing_block.width() - line_box.width(); + float excess_horizontal_space = (float)containing_block().width() - line_box.width(); switch (text_align) { case CSS::TextAlign::Center: @@ -195,16 +193,14 @@ void InlineFormattingContext::run(LayoutMode layout_mode) } if (layout_mode != LayoutMode::Default) { - containing_block.set_width(max_linebox_width); + containing_block().set_width(max_linebox_width); } - containing_block.set_height(content_height); + containing_block().set_height(content_height); } void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_mode) { - auto& containing_block = downcast<BlockBox>(context_box()); - if (box.is_replaced()) { auto& replaced = const_cast<ReplacedBox&>(downcast<ReplacedBox>(box)); replaced.set_width(replaced.calculate_width()); @@ -218,15 +214,15 @@ void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_ if (inline_block.style().width().is_undefined_or_auto()) { auto result = calculate_shrink_to_fit_widths(inline_block); - auto margin_left = inline_block.style().margin().left.resolved(CSS::Length::make_px(0), containing_block, containing_block.width()).to_px(inline_block); + auto margin_left = inline_block.style().margin().left.resolved(CSS::Length::make_px(0), containing_block(), containing_block().width()).to_px(inline_block); auto border_left_width = inline_block.style().border_left().width; - auto padding_left = inline_block.style().padding().left.resolved(CSS::Length::make_px(0), containing_block, containing_block.width()).to_px(inline_block); + auto padding_left = inline_block.style().padding().left.resolved(CSS::Length::make_px(0), containing_block(), containing_block().width()).to_px(inline_block); - auto margin_right = inline_block.style().margin().right.resolved(CSS::Length::make_px(0), containing_block, containing_block.width()).to_px(inline_block); + auto margin_right = inline_block.style().margin().right.resolved(CSS::Length::make_px(0), containing_block(), containing_block().width()).to_px(inline_block); auto border_right_width = inline_block.style().border_right().width; - auto padding_right = inline_block.style().padding().right.resolved(CSS::Length::make_px(0), containing_block, containing_block.width()).to_px(inline_block); + auto padding_right = inline_block.style().padding().right.resolved(CSS::Length::make_px(0), containing_block(), containing_block().width()).to_px(inline_block); - auto available_width = containing_block.width() + auto available_width = containing_block().width() - margin_left - border_left_width - padding_left @@ -237,7 +233,7 @@ void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_ auto width = min(max(result.preferred_minimum_width, available_width), result.preferred_width); inline_block.set_width(width); } else { - inline_block.set_width(inline_block.style().width().resolved(CSS::Length::make_px(0), containing_block, containing_block.width()).to_px(inline_block)); + inline_block.set_width(inline_block.style().width().resolved(CSS::Length::make_px(0), containing_block(), containing_block().width()).to_px(inline_block)); } layout_inside(inline_block, layout_mode); @@ -245,7 +241,7 @@ void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_ if (inline_block.style().height().is_undefined_or_auto()) { // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. } else { - inline_block.set_height(inline_block.style().height().resolved(CSS::Length::make_px(0), containing_block, containing_block.height()).to_px(inline_block)); + inline_block.set_height(inline_block.style().height().resolved(CSS::Length::make_px(0), containing_block(), containing_block().height()).to_px(inline_block)); } return; } diff --git a/Libraries/LibWeb/Layout/InlineFormattingContext.h b/Libraries/LibWeb/Layout/InlineFormattingContext.h index a96f0c9901..8b7d44d267 100644 --- a/Libraries/LibWeb/Layout/InlineFormattingContext.h +++ b/Libraries/LibWeb/Layout/InlineFormattingContext.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/Types.h> #include <LibWeb/Forward.h> #include <LibWeb/Layout/FormattingContext.h> @@ -36,7 +37,10 @@ public: InlineFormattingContext(Box& containing_block, FormattingContext* parent); ~InlineFormattingContext(); - virtual void run(LayoutMode) override; + Box& containing_block() { return context_box(); } + const Box& containing_block() const { return context_box(); } + + virtual void run(Box&, LayoutMode) override; float available_width_at_line(size_t line_index) const; diff --git a/Libraries/LibWeb/Layout/Node.h b/Libraries/LibWeb/Layout/Node.h index 3a7f702e0b..ce5c7da605 100644 --- a/Libraries/LibWeb/Layout/Node.h +++ b/Libraries/LibWeb/Layout/Node.h @@ -137,6 +137,7 @@ public: bool is_fixed_position() const; const BlockBox* containing_block() const; + BlockBox* containing_block() { return const_cast<BlockBox*>(const_cast<const Node*>(this)->containing_block()); } bool can_contain_boxes_with_position_absolute() const; diff --git a/Libraries/LibWeb/Layout/ReplacedBox.cpp b/Libraries/LibWeb/Layout/ReplacedBox.cpp index a8b40f039f..9373ea5ffd 100644 --- a/Libraries/LibWeb/Layout/ReplacedBox.cpp +++ b/Libraries/LibWeb/Layout/ReplacedBox.cpp @@ -120,7 +120,7 @@ float ReplacedBox::calculate_height() const void ReplacedBox::split_into_lines(InlineFormattingContext& context, LayoutMode) { - auto& containing_block = context.context_box(); + auto& containing_block = context.containing_block(); // FIXME: This feels out of place. It would be nice if someone at a higher level // made sure we had usable geometry by the time we start splitting. diff --git a/Libraries/LibWeb/Layout/TableFormattingContext.cpp b/Libraries/LibWeb/Layout/TableFormattingContext.cpp index 988b859488..665706ab0f 100644 --- a/Libraries/LibWeb/Layout/TableFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/TableFormattingContext.cpp @@ -47,37 +47,37 @@ TableFormattingContext::~TableFormattingContext() { } -void TableFormattingContext::run(LayoutMode) +void TableFormattingContext::run(Box& box, LayoutMode) { - compute_width(context_box()); + compute_width(box); float total_content_height = 0; - context_box().for_each_child_of_type<TableRowGroupBox>([&](auto& box) { - compute_width(box); - auto column_count = box.column_count(); + box.for_each_child_of_type<TableRowGroupBox>([&](auto& row_group_box) { + compute_width(row_group_box); + auto column_count = row_group_box.column_count(); Vector<float> column_widths; column_widths.resize(column_count); - box.template for_each_child_of_type<TableRowBox>([&](auto& row) { + row_group_box.template for_each_child_of_type<TableRowBox>([&](auto& row) { calculate_column_widths(row, column_widths); }); float content_height = 0; - box.template for_each_child_of_type<TableRowBox>([&](auto& row) { + row_group_box.template for_each_child_of_type<TableRowBox>([&](auto& row) { row.set_offset(0, content_height); layout_row(row, column_widths); content_height += row.height(); }); - box.set_height(content_height); + row_group_box.set_height(content_height); total_content_height += content_height; }); // FIXME: This is a total hack, we should respect the 'height' property. - context_box().set_height(total_content_height); + box.set_height(total_content_height); } void TableFormattingContext::calculate_column_widths(Box& row, Vector<float>& column_widths) diff --git a/Libraries/LibWeb/Layout/TableFormattingContext.h b/Libraries/LibWeb/Layout/TableFormattingContext.h index 5419b437a9..7bb973a5d2 100644 --- a/Libraries/LibWeb/Layout/TableFormattingContext.h +++ b/Libraries/LibWeb/Layout/TableFormattingContext.h @@ -36,7 +36,7 @@ public: explicit TableFormattingContext(Box&, FormattingContext* parent); ~TableFormattingContext(); - virtual void run(LayoutMode) override; + virtual void run(Box&, LayoutMode) override; private: void calculate_column_widths(Box& row, Vector<float>& column_widths); diff --git a/Libraries/LibWeb/Layout/TextNode.cpp b/Libraries/LibWeb/Layout/TextNode.cpp index 5438054e9d..a4f59874a4 100644 --- a/Libraries/LibWeb/Layout/TextNode.cpp +++ b/Libraries/LibWeb/Layout/TextNode.cpp @@ -192,7 +192,8 @@ void TextNode::for_each_chunk(Callback callback, LayoutMode layout_mode, bool do void TextNode::split_into_lines_by_rules(InlineFormattingContext& context, LayoutMode layout_mode, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks) { - auto& containing_block = context.context_box(); + auto& containing_block = context.containing_block(); + auto& font = specified_style().font(); float space_width = font.glyph_width(' ') + font.glyph_spacing(); |