1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:57:34 +00:00

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.
This commit is contained in:
Andreas Kling 2022-03-10 10:38:13 +01:00
parent cc8e429126
commit 9f5cbcaad3
10 changed files with 39 additions and 38 deletions

View file

@ -570,7 +570,6 @@ void Document::update_layout()
Layout::FormattingState formatting_state; Layout::FormattingState formatting_state;
Layout::BlockFormattingContext root_formatting_context(formatting_state, *m_layout_root, nullptr); Layout::BlockFormattingContext root_formatting_context(formatting_state, *m_layout_root, nullptr);
m_layout_root->build_stacking_context_tree();
auto& icb = static_cast<Layout::InitialContainingBlock&>(*m_layout_root); auto& icb = static_cast<Layout::InitialContainingBlock&>(*m_layout_root);
auto& icb_state = formatting_state.get_mutable(icb); 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); root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Default);
formatting_state.commit(); formatting_state.commit();
m_layout_root->build_stacking_context_tree();
browsing_context()->set_needs_display(); browsing_context()->set_needs_display();
if (browsing_context()->is_top_level()) { if (browsing_context()->is_top_level()) {

View file

@ -88,7 +88,7 @@ HitTestResult BlockContainer::hit_test(const Gfx::IntPoint& position, HitTestTyp
HitTestResult last_good_candidate; HitTestResult last_good_candidate;
for (auto& line_box : m_paint_box->m_line_boxes) { for (auto& line_box : m_paint_box->m_line_boxes) {
for (auto& fragment : line_box.fragments()) { for (auto& fragment : line_box.fragments()) {
if (is<Box>(fragment.layout_node()) && verify_cast<Box>(fragment.layout_node()).stacking_context()) if (is<Box>(fragment.layout_node()) && verify_cast<Box>(fragment.layout_node()).m_paint_box->stacking_context())
continue; continue;
if (enclosing_int_rect(fragment.absolute_rect()).contains(position)) { if (enclosing_int_rect(fragment.absolute_rect()).contains(position)) {
if (is<BlockContainer>(fragment.layout_node())) if (is<BlockContainer>(fragment.layout_node()))

View file

@ -217,21 +217,6 @@ bool Box::is_body() const
return dom_node() && dom_node() == document().body(); return dom_node() && dom_node() == document().body();
} }
Painting::StackingContext* Box::enclosing_stacking_context()
{
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
if (!is<Box>(ancestor))
continue;
auto& ancestor_box = verify_cast<Box>(*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) void Box::before_children_paint(PaintContext& context, Painting::PaintPhase phase)
{ {
NodeWithStyleAndBoxModelMetrics::before_children_paint(context, phase); NodeWithStyleAndBoxModelMetrics::before_children_paint(context, phase);

View file

@ -10,7 +10,6 @@
#include <LibGfx/Rect.h> #include <LibGfx/Rect.h>
#include <LibWeb/Layout/Node.h> #include <LibWeb/Layout/Node.h>
#include <LibWeb/Painting/BorderPainting.h> #include <LibWeb/Painting/BorderPainting.h>
#include <LibWeb/Painting/StackingContext.h>
namespace Web::Layout { namespace Web::Layout {
@ -30,11 +29,6 @@ public:
bool is_body() const; 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<Painting::StackingContext> context) { m_stacking_context = move(context); }
Painting::StackingContext* enclosing_stacking_context();
virtual void paint(PaintContext&, Painting::PaintPhase) override; virtual void paint(PaintContext&, Painting::PaintPhase) override;
virtual void paint_border(PaintContext& context); virtual void paint_border(PaintContext& context);
virtual void paint_box_shadow(PaintContext& context); virtual void paint_box_shadow(PaintContext& context);
@ -63,8 +57,6 @@ protected:
private: private:
virtual bool is_box() const final { return true; } virtual bool is_box() const final { return true; }
OwnPtr<Painting::StackingContext> m_stacking_context;
}; };
template<> template<>

View file

@ -24,18 +24,18 @@ InitialContainingBlock::~InitialContainingBlock()
void InitialContainingBlock::build_stacking_context_tree() void InitialContainingBlock::build_stacking_context_tree()
{ {
set_stacking_context(make<Painting::StackingContext>(*this, nullptr)); m_paint_box->set_stacking_context(make<Painting::StackingContext>(*this, nullptr));
for_each_in_inclusive_subtree_of_type<Box>([&](Box& box) { for_each_in_inclusive_subtree_of_type<Box>([&](Box& box) {
if (&box == this) if (&box == this)
return IterationDecision::Continue; return IterationDecision::Continue;
if (!box.establishes_stacking_context()) { if (!box.establishes_stacking_context()) {
VERIFY(!box.stacking_context()); VERIFY(!box.m_paint_box->stacking_context());
return IterationDecision::Continue; return IterationDecision::Continue;
} }
auto* parent_context = box.enclosing_stacking_context(); auto* parent_context = box.m_paint_box->enclosing_stacking_context();
VERIFY(parent_context); VERIFY(parent_context);
box.set_stacking_context(make<Painting::StackingContext>(box, parent_context)); box.m_paint_box->set_stacking_context(make<Painting::StackingContext>(box, parent_context));
return IterationDecision::Continue; 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().fill_rect(enclosing_int_rect(m_paint_box->absolute_rect()), context.palette().base());
context.painter().translate(-context.viewport_rect().location()); 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 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() void InitialContainingBlock::recompute_selection_states()

View file

@ -162,7 +162,7 @@ public:
return; return;
auto& box_child = verify_cast<Box>(child); auto& box_child = verify_cast<Box>(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) if (stacking_context && box_child.computed_values().z_index().has_value() && box_child.computed_values().z_index().value() < 0)
callback(child); 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, // 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: // or other block equivalent:
for_each_child([&](auto& child) { for_each_child([&](auto& child) {
if (is<Box>(child) && verify_cast<Box>(child).stacking_context()) if (is<Box>(child) && verify_cast<Box>(child).m_paint_box->stacking_context())
return; return;
if (!child.is_positioned()) if (!child.is_positioned())
callback(child); callback(child);
@ -180,7 +180,7 @@ public:
// a new stacking context, but any positioned descendants and descendants which actually create a new stacking context // 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. // should be considered part of the parent stacking context, not this new one.
for_each_child([&](auto& child) { for_each_child([&](auto& child) {
if (is<Box>(child) && verify_cast<Box>(child).stacking_context()) if (is<Box>(child) && verify_cast<Box>(child).m_paint_box->stacking_context())
return; return;
if (child.is_positioned()) if (child.is_positioned())
callback(child); callback(child);
@ -195,7 +195,7 @@ public:
return; return;
auto& box_child = verify_cast<Box>(child); auto& box_child = verify_cast<Box>(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) if (stacking_context && box_child.computed_values().z_index().has_value() && box_child.computed_values().z_index().value() == 0)
callback(child); callback(child);
}); });
@ -208,7 +208,7 @@ public:
return; return;
auto& box_child = verify_cast<Box>(child); auto& box_child = verify_cast<Box>(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) if (stacking_context && box_child.computed_values().z_index().has_value() && box_child.computed_values().z_index().value() > 0)
callback(child); callback(child);
}); });

View file

@ -49,4 +49,19 @@ void Box::set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoord
m_containing_line_box_fragment = fragment_coordinate; m_containing_line_box_fragment = fragment_coordinate;
} }
Painting::StackingContext* Box::enclosing_stacking_context()
{
for (auto* ancestor = m_layout_box.parent(); ancestor; ancestor = ancestor->parent()) {
if (!is<Layout::Box>(ancestor))
continue;
auto& ancestor_box = static_cast<Layout::Box&>(const_cast<Layout::NodeWithStyle&>(*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();
}
} }

View file

@ -9,6 +9,7 @@
#include <AK/NonnullOwnPtr.h> #include <AK/NonnullOwnPtr.h>
#include <LibWeb/Layout/Box.h> #include <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/LineBox.h> #include <LibWeb/Layout/LineBox.h>
#include <LibWeb/Painting/StackingContext.h>
namespace Web::Painting { 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<Painting::StackingContext> context) { m_stacking_context = move(context); }
StackingContext* enclosing_stacking_context();
OwnPtr<Painting::StackingContext> m_stacking_context;
}; };
} }

View file

@ -165,7 +165,7 @@ Layout::HitTestResult StackingContext::hit_test(const Gfx::IntPoint& position, L
Layout::HitTestResult result; Layout::HitTestResult result;
// 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0. // 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>([&](Layout::Box const& box) { m_box.for_each_in_subtree_of_type<Layout::Box>([&](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); result = box.hit_test(position, type);
if (result.layout_node) if (result.layout_node)
return IterationDecision::Break; return IterationDecision::Break;

View file

@ -190,7 +190,7 @@ void ConnectionFromClient::debug_request(const String& request, const String& ar
if (request == "dump-stacking-context-tree") { if (request == "dump-stacking-context-tree") {
if (auto* doc = page().top_level_browsing_context().active_document()) { if (auto* doc = page().top_level_browsing_context().active_document()) {
if (auto* icb = doc->layout_node()) { 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(); stacking_context->dump();
} }
} }