LibWeb: Allow layout nodes to have multiple paintables

CSS fragmentation implies 1:N relationship between layout nodes and
paintables. This change is a preparation for implementation of inline
fragmentation where InlinePaintable will be replaced with
PaintableWithLines corresponding to each line.
This commit is contained in:
Aliaksandr Kalenik 2024-10-14 16:07:56 +02:00 committed by Alexander Kalenik
commit 7d22b1c5c8
Notes: github-actions[bot] 2024-10-16 18:26:52 +00:00
16 changed files with 90 additions and 30 deletions

View file

@ -1924,6 +1924,11 @@ void Node::set_paintable(JS::GCPtr<Painting::Paintable> paintable)
m_paintable = paintable;
}
void Node::clear_paintable()
{
m_paintable = nullptr;
}
Painting::Paintable const* Node::paintable() const
{
return m_paintable;

View file

@ -248,6 +248,7 @@ public:
Painting::Paintable* paintable();
void set_paintable(JS::GCPtr<Painting::Paintable>);
void clear_paintable();
void set_layout_node(Badge<Layout::Node>, JS::NonnullGCPtr<Layout::Node>);
void detach_layout_node(Badge<Layout::TreeBuilder>);

View file

@ -11,6 +11,7 @@
#include <LibWeb/DOM/DocumentLoading.h>
#include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/Range.h>
#include <LibWeb/DOM/Text.h>
#include <LibWeb/Fetch/Fetching/Fetching.h>
#include <LibWeb/Fetch/Infrastructure/FetchAlgorithms.h>
#include <LibWeb/Fetch/Infrastructure/FetchController.h>

View file

@ -14,6 +14,7 @@
#include <LibWeb/Layout/SVGFormattingContext.h>
#include <LibWeb/Layout/SVGSVGBox.h>
#include <LibWeb/Layout/TableFormattingContext.h>
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/Layout/Viewport.h>
namespace Web::Layout {

View file

@ -221,11 +221,11 @@ void LayoutState::commit(Box& root)
// from the layout tree. This is done to ensure that we don't end up with any old-tree pointers
// when text paintables shift around in the tree.
root.for_each_in_inclusive_subtree([&](Layout::Node& node) {
node.set_paintable(nullptr);
node.clear_paintables();
return TraversalDecision::Continue;
});
root.document().for_each_shadow_including_inclusive_descendant([&](DOM::Node& node) {
node.set_paintable(nullptr);
node.clear_paintable();
return TraversalDecision::Continue;
});
@ -248,7 +248,7 @@ void LayoutState::commit(Box& root)
auto paintable = node.create_paintable();
node.set_paintable(paintable);
node.add_paintable(paintable);
// For boxes, transfer all the state needed for painting.
if (paintable && is<Painting::PaintableBox>(*paintable)) {
@ -351,7 +351,7 @@ void LayoutState::commit(Box& root)
}
for (auto* text_node : text_nodes) {
text_node->set_paintable(text_node->create_paintable());
text_node->add_paintable(text_node->create_paintable());
auto* paintable = text_node->paintable();
auto const& font = text_node->first_available_font();
auto const glyph_height = CSSPixels::nearest_value_for(font.pixel_size());

View file

@ -7,6 +7,7 @@
#include <AK/Utf8View.h>
#include <LibWeb/DOM/Range.h>
#include <LibWeb/Layout/LayoutState.h>
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/Layout/Viewport.h>
#include <ctype.h>

View file

@ -48,7 +48,9 @@ void Node::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_dom_node);
visitor.visit(m_paintable);
for (auto const& paintable : m_paintable) {
visitor.visit(JS::GCPtr { &paintable });
}
visitor.visit(m_pseudo_element_generator);
TreeNode::visit_edges(visitor);
}
@ -1015,9 +1017,16 @@ void NodeWithStyle::transfer_table_box_computed_values_to_wrapper_computed_value
reset_table_box_computed_values_used_by_wrapper_to_init_values();
}
void Node::set_paintable(JS::GCPtr<Painting::Paintable> paintable)
void Node::add_paintable(JS::GCPtr<Painting::Paintable> paintable)
{
m_paintable = move(paintable);
if (!paintable)
return;
m_paintable.append(*paintable);
}
void Node::clear_paintables()
{
m_paintable.clear();
}
JS::GCPtr<Painting::Paintable> Node::create_paintable() const

View file

@ -20,6 +20,7 @@
#include <LibWeb/Forward.h>
#include <LibWeb/Layout/BoxModelMetrics.h>
#include <LibWeb/Painting/PaintContext.h>
#include <LibWeb/Painting/Paintable.h>
#include <LibWeb/TreeNode.h>
namespace Web::Layout {
@ -64,9 +65,12 @@ public:
m_pseudo_element_generator = &element;
}
Painting::Paintable* paintable() { return m_paintable; }
Painting::Paintable const* paintable() const { return m_paintable; }
void set_paintable(JS::GCPtr<Painting::Paintable>);
using PaintableList = IntrusiveList<&Painting::Paintable::m_list_node>;
Painting::Paintable* paintable() { return m_paintable.first(); }
Painting::Paintable const* paintable() const { return m_paintable.first(); }
void add_paintable(JS::GCPtr<Painting::Paintable>);
void clear_paintables();
virtual JS::GCPtr<Painting::Paintable> create_paintable() const;
@ -181,7 +185,7 @@ private:
friend class NodeWithStyle;
JS::NonnullGCPtr<DOM::Node> m_dom_node;
JS::GCPtr<Painting::Paintable> m_paintable;
PaintableList m_paintable;
JS::GCPtr<DOM::Element> m_pseudo_element_generator;

View file

@ -309,7 +309,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
if (!layout_node) {
dom_node.for_each_in_inclusive_subtree([&](auto& node) {
node.detach_layout_node({});
node.set_paintable(nullptr);
node.clear_paintable();
if (is<DOM::Element>(node))
static_cast<DOM::Element&>(node).clear_pseudo_element_nodes({});
return TraversalDecision::Continue;

View file

@ -6,6 +6,7 @@
#include <LibWeb/DOM/Range.h>
#include <LibWeb/Dump.h>
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Painting/StackingContext.h>

View file

@ -8,6 +8,7 @@
#include <LibWeb/CSS/Sizing.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/InlinePaintable.h>

View file

@ -51,6 +51,38 @@ bool Paintable::is_visible() const
return computed_values.visibility() == CSS::Visibility::Visible && computed_values.opacity() != 0;
}
DOM::Document const& Paintable::document() const
{
return layout_node().document();
}
DOM::Document& Paintable::document()
{
return layout_node().document();
}
CSS::Display Paintable::display() const
{
return layout_node().display();
}
PaintableBox* Paintable::containing_block() const
{
if (!m_containing_block.has_value()) {
auto containing_layout_box = m_layout_node->containing_block();
if (containing_layout_box)
m_containing_block = const_cast<PaintableBox*>(containing_layout_box->paintable_box());
else
m_containing_block = nullptr;
}
return *m_containing_block;
}
CSS::ImmutableComputedValues const& Paintable::computed_values() const
{
return m_layout_node->computed_values();
}
void Paintable::set_dom_node(JS::GCPtr<DOM::Node> dom_node)
{
m_dom_node = dom_node;

View file

@ -7,10 +7,11 @@
#pragma once
#include <AK/NonnullOwnPtr.h>
#include <LibJS/Heap/Handle.h>
#include <LibWeb/InvalidateDisplayList.h>
#include <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/LineBox.h>
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/TraversalDecision.h>
#include <LibWeb/TreeNode.h>
namespace Web::Painting {
@ -62,7 +63,7 @@ public:
[[nodiscard]] bool is_floating() const { return m_floating; }
[[nodiscard]] bool is_inline() const { return m_inline; }
[[nodiscard]] bool is_selected() const { return m_selected; }
[[nodiscard]] CSS::Display display() const { return layout_node().display(); }
[[nodiscard]] CSS::Display display() const;
template<typename U, typename Callback>
TraversalDecision for_each_in_inclusive_subtree_of_type(Callback callback)
@ -194,7 +195,7 @@ public:
[[nodiscard]] JS::GCPtr<DOM::Node const> dom_node() const;
void set_dom_node(JS::GCPtr<DOM::Node>);
auto const& computed_values() const { return m_layout_node->computed_values(); }
CSS::ImmutableComputedValues const& computed_values() const;
bool visible_for_hit_testing() const { return computed_values().pointer_events() != CSS::PointerEvents::None; }
@ -202,17 +203,7 @@ public:
virtual void set_needs_display(InvalidateDisplayList = InvalidateDisplayList::Yes);
PaintableBox* containing_block() const
{
if (!m_containing_block.has_value()) {
auto containing_layout_box = m_layout_node->containing_block();
if (containing_layout_box)
m_containing_block = const_cast<PaintableBox*>(containing_layout_box->paintable_box());
else
m_containing_block = nullptr;
}
return *m_containing_block;
}
PaintableBox* containing_block() const;
template<typename T>
bool fast_is() const = delete;
@ -223,8 +214,8 @@ public:
[[nodiscard]] virtual bool is_svg_paintable() const { return false; }
[[nodiscard]] virtual bool is_text_paintable() const { return false; }
DOM::Document const& document() const { return layout_node().document(); }
DOM::Document& document() { return layout_node().document(); }
DOM::Document const& document() const;
DOM::Document& document();
CSSPixelPoint box_type_agnostic_position() const;
@ -242,7 +233,15 @@ public:
Gfx::AffineTransform compute_combined_css_transform() const;
virtual void resolve_paint_properties() {};
virtual void resolve_paint_properties() { }
virtual void finalize() override
{
if (m_list_node.is_in_list())
m_list_node.remove();
}
friend class Layout::Node;
protected:
explicit Paintable(Layout::Node const&);
@ -250,6 +249,7 @@ protected:
virtual void visit_edges(Cell::Visitor&) override;
private:
IntrusiveListNode<Paintable> m_list_node;
JS::GCPtr<DOM::Node> m_dom_node;
JS::NonnullGCPtr<Layout::Node const> m_layout_node;
Optional<JS::GCPtr<PaintableBox>> mutable m_containing_block;

View file

@ -7,6 +7,8 @@
#pragma once
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
#include <LibWeb/Forward.h>
#include <LibWeb/Layout/Box.h>
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/BorderPainting.h>
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>

View file

@ -6,6 +6,7 @@
#pragma once
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {

View file

@ -5,6 +5,7 @@
*/
#include <LibWeb/DOM/Range.h>
#include <LibWeb/Layout/TextNode.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Painting/StackingContext.h>
#include <LibWeb/Painting/ViewportPaintable.h>