From 9f5cbcaad39aa9df43694140613fdd8b3b2fe5b2 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 10 Mar 2022 10:38:13 +0100 Subject: [PATCH] LibWeb: Hang StackingContext off of the paint boxes Stacking contexts have nothing to do with layout and everything with painting, so let's keep them in Painting::Box. --- Userland/Libraries/LibWeb/DOM/Document.cpp | 3 ++- .../Libraries/LibWeb/Layout/BlockContainer.cpp | 2 +- Userland/Libraries/LibWeb/Layout/Box.cpp | 15 --------------- Userland/Libraries/LibWeb/Layout/Box.h | 8 -------- .../LibWeb/Layout/InitialContainingBlock.cpp | 12 ++++++------ Userland/Libraries/LibWeb/Layout/Node.h | 10 +++++----- Userland/Libraries/LibWeb/Painting/Box.cpp | 15 +++++++++++++++ Userland/Libraries/LibWeb/Painting/Box.h | 8 ++++++++ .../Libraries/LibWeb/Painting/StackingContext.cpp | 2 +- .../Services/WebContent/ConnectionFromClient.cpp | 2 +- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 1a5900e831..b71b42c237 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -570,7 +570,6 @@ void Document::update_layout() Layout::FormattingState formatting_state; Layout::BlockFormattingContext root_formatting_context(formatting_state, *m_layout_root, nullptr); - m_layout_root->build_stacking_context_tree(); auto& icb = static_cast(*m_layout_root); auto& icb_state = formatting_state.get_mutable(icb); @@ -583,6 +582,8 @@ void Document::update_layout() root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Default); formatting_state.commit(); + m_layout_root->build_stacking_context_tree(); + browsing_context()->set_needs_display(); if (browsing_context()->is_top_level()) { diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp index 414b82c1b5..a76b3677b0 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp @@ -88,7 +88,7 @@ HitTestResult BlockContainer::hit_test(const Gfx::IntPoint& position, HitTestTyp HitTestResult last_good_candidate; for (auto& line_box : m_paint_box->m_line_boxes) { for (auto& fragment : line_box.fragments()) { - if (is(fragment.layout_node()) && verify_cast(fragment.layout_node()).stacking_context()) + if (is(fragment.layout_node()) && verify_cast(fragment.layout_node()).m_paint_box->stacking_context()) continue; if (enclosing_int_rect(fragment.absolute_rect()).contains(position)) { if (is(fragment.layout_node())) diff --git a/Userland/Libraries/LibWeb/Layout/Box.cpp b/Userland/Libraries/LibWeb/Layout/Box.cpp index 0ef918b209..05d2cdceb8 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.cpp +++ b/Userland/Libraries/LibWeb/Layout/Box.cpp @@ -217,21 +217,6 @@ bool Box::is_body() const return dom_node() && dom_node() == document().body(); } -Painting::StackingContext* Box::enclosing_stacking_context() -{ - for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { - if (!is(ancestor)) - continue; - auto& ancestor_box = verify_cast(*ancestor); - if (!ancestor_box.establishes_stacking_context()) - continue; - VERIFY(ancestor_box.stacking_context()); - return ancestor_box.stacking_context(); - } - // We should always reach the Layout::InitialContainingBlock stacking context. - VERIFY_NOT_REACHED(); -} - void Box::before_children_paint(PaintContext& context, Painting::PaintPhase phase) { NodeWithStyleAndBoxModelMetrics::before_children_paint(context, phase); diff --git a/Userland/Libraries/LibWeb/Layout/Box.h b/Userland/Libraries/LibWeb/Layout/Box.h index b3ede364c7..7c7e0a4481 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.h +++ b/Userland/Libraries/LibWeb/Layout/Box.h @@ -10,7 +10,6 @@ #include #include #include -#include namespace Web::Layout { @@ -30,11 +29,6 @@ public: bool is_body() const; - Painting::StackingContext* stacking_context() { return m_stacking_context; } - Painting::StackingContext const* stacking_context() const { return m_stacking_context; } - void set_stacking_context(NonnullOwnPtr context) { m_stacking_context = move(context); } - Painting::StackingContext* enclosing_stacking_context(); - virtual void paint(PaintContext&, Painting::PaintPhase) override; virtual void paint_border(PaintContext& context); virtual void paint_box_shadow(PaintContext& context); @@ -63,8 +57,6 @@ protected: private: virtual bool is_box() const final { return true; } - - OwnPtr m_stacking_context; }; template<> diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp b/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp index c11f7055aa..5a9937e640 100644 --- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp +++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp @@ -24,18 +24,18 @@ InitialContainingBlock::~InitialContainingBlock() void InitialContainingBlock::build_stacking_context_tree() { - set_stacking_context(make(*this, nullptr)); + m_paint_box->set_stacking_context(make(*this, nullptr)); for_each_in_inclusive_subtree_of_type([&](Box& box) { if (&box == this) return IterationDecision::Continue; if (!box.establishes_stacking_context()) { - VERIFY(!box.stacking_context()); + VERIFY(!box.m_paint_box->stacking_context()); return IterationDecision::Continue; } - auto* parent_context = box.enclosing_stacking_context(); + auto* parent_context = box.m_paint_box->enclosing_stacking_context(); VERIFY(parent_context); - box.set_stacking_context(make(box, parent_context)); + box.m_paint_box->set_stacking_context(make(box, parent_context)); return IterationDecision::Continue; }); } @@ -44,12 +44,12 @@ void InitialContainingBlock::paint_all_phases(PaintContext& context) { context.painter().fill_rect(enclosing_int_rect(m_paint_box->absolute_rect()), context.palette().base()); context.painter().translate(-context.viewport_rect().location()); - stacking_context()->paint(context); + m_paint_box->stacking_context()->paint(context); } HitTestResult InitialContainingBlock::hit_test(const Gfx::IntPoint& position, HitTestType type) const { - return stacking_context()->hit_test(position, type); + return m_paint_box->stacking_context()->hit_test(position, type); } void InitialContainingBlock::recompute_selection_states() diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index 06e8d69d91..3789cd7a38 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -162,7 +162,7 @@ public: return; auto& box_child = verify_cast(child); - auto* stacking_context = box_child.stacking_context(); + auto* stacking_context = box_child.m_paint_box->stacking_context(); if (stacking_context && box_child.computed_values().z_index().has_value() && box_child.computed_values().z_index().value() < 0) callback(child); }); @@ -170,7 +170,7 @@ public: // 4. For all its in-flow, non-positioned, block-level descendants in tree order: If the element is a block, list-item, // or other block equivalent: for_each_child([&](auto& child) { - if (is(child) && verify_cast(child).stacking_context()) + if (is(child) && verify_cast(child).m_paint_box->stacking_context()) return; if (!child.is_positioned()) callback(child); @@ -180,7 +180,7 @@ public: // a new stacking context, but any positioned descendants and descendants which actually create a new stacking context // should be considered part of the parent stacking context, not this new one. for_each_child([&](auto& child) { - if (is(child) && verify_cast(child).stacking_context()) + if (is(child) && verify_cast(child).m_paint_box->stacking_context()) return; if (child.is_positioned()) callback(child); @@ -195,7 +195,7 @@ public: return; auto& box_child = verify_cast(child); - auto* stacking_context = box_child.stacking_context(); + auto* stacking_context = box_child.m_paint_box->stacking_context(); if (stacking_context && box_child.computed_values().z_index().has_value() && box_child.computed_values().z_index().value() == 0) callback(child); }); @@ -208,7 +208,7 @@ public: return; auto& box_child = verify_cast(child); - auto* stacking_context = box_child.stacking_context(); + auto* stacking_context = box_child.m_paint_box->stacking_context(); if (stacking_context && box_child.computed_values().z_index().has_value() && box_child.computed_values().z_index().value() > 0) callback(child); }); diff --git a/Userland/Libraries/LibWeb/Painting/Box.cpp b/Userland/Libraries/LibWeb/Painting/Box.cpp index 888e2a8ce2..cc6e5d8786 100644 --- a/Userland/Libraries/LibWeb/Painting/Box.cpp +++ b/Userland/Libraries/LibWeb/Painting/Box.cpp @@ -49,4 +49,19 @@ void Box::set_containing_line_box_fragment(Optionalparent()) { + if (!is(ancestor)) + continue; + auto& ancestor_box = static_cast(const_cast(*ancestor)); + if (!ancestor_box.establishes_stacking_context()) + continue; + VERIFY(ancestor_box.m_paint_box->stacking_context()); + return ancestor_box.m_paint_box->stacking_context(); + } + // We should always reach the Layout::InitialContainingBlock stacking context. + VERIFY_NOT_REACHED(); +} + } diff --git a/Userland/Libraries/LibWeb/Painting/Box.h b/Userland/Libraries/LibWeb/Painting/Box.h index f5e35be8d1..874bb65f69 100644 --- a/Userland/Libraries/LibWeb/Painting/Box.h +++ b/Userland/Libraries/LibWeb/Painting/Box.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace Web::Painting { @@ -121,6 +122,13 @@ public: } } } + + StackingContext* stacking_context() { return m_stacking_context; } + StackingContext const* stacking_context() const { return m_stacking_context; } + void set_stacking_context(NonnullOwnPtr context) { m_stacking_context = move(context); } + StackingContext* enclosing_stacking_context(); + + OwnPtr m_stacking_context; }; } diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 103b41ee42..a74086508a 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -165,7 +165,7 @@ Layout::HitTestResult StackingContext::hit_test(const Gfx::IntPoint& position, L Layout::HitTestResult result; // 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0. m_box.for_each_in_subtree_of_type([&](Layout::Box const& box) { - if (box.is_positioned() && !box.stacking_context()) { + if (box.is_positioned() && !box.m_paint_box->stacking_context()) { result = box.hit_test(position, type); if (result.layout_node) return IterationDecision::Break; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index ad66641500..fa3386f260 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -190,7 +190,7 @@ void ConnectionFromClient::debug_request(const String& request, const String& ar if (request == "dump-stacking-context-tree") { if (auto* doc = page().top_level_browsing_context().active_document()) { if (auto* icb = doc->layout_node()) { - if (auto* stacking_context = icb->stacking_context()) + if (auto* stacking_context = icb->m_paint_box->stacking_context()) stacking_context->dump(); } }