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::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_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()) {

View file

@ -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<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;
if (enclosing_int_rect(fragment.absolute_rect()).contains(position)) {
if (is<BlockContainer>(fragment.layout_node()))

View file

@ -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<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)
{
NodeWithStyleAndBoxModelMetrics::before_children_paint(context, phase);

View file

@ -10,7 +10,6 @@
#include <LibGfx/Rect.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Painting/BorderPainting.h>
#include <LibWeb/Painting/StackingContext.h>
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<Painting::StackingContext> 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<Painting::StackingContext> m_stacking_context;
};
template<>

View file

@ -24,18 +24,18 @@ InitialContainingBlock::~InitialContainingBlock()
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) {
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<Painting::StackingContext>(box, parent_context));
box.m_paint_box->set_stacking_context(make<Painting::StackingContext>(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()

View file

@ -162,7 +162,7 @@ public:
return;
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)
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<Box>(child) && verify_cast<Box>(child).stacking_context())
if (is<Box>(child) && verify_cast<Box>(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<Box>(child) && verify_cast<Box>(child).stacking_context())
if (is<Box>(child) && verify_cast<Box>(child).m_paint_box->stacking_context())
return;
if (child.is_positioned())
callback(child);
@ -195,7 +195,7 @@ public:
return;
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)
callback(child);
});
@ -208,7 +208,7 @@ public:
return;
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)
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;
}
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 <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/LineBox.h>
#include <LibWeb/Painting/StackingContext.h>
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;
// 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) {
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;

View file

@ -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();
}
}