mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 21:37:35 +00:00
LibWeb: Make the layout tree GC-allocated
This removes a set of complex reference cycles between DOM, layout tree and browsing context. It also makes lifetimes much easier to reason about, as the DOM and layout trees are now free to keep each other alive.
This commit is contained in:
parent
83c5ff57d8
commit
268b9c5d90
72 changed files with 258 additions and 207 deletions
|
@ -13,6 +13,8 @@ namespace Web::Layout {
|
|||
|
||||
// https://www.w3.org/TR/css-display/#block-container
|
||||
class BlockContainer : public Box {
|
||||
JS_CELL(BlockContainer, Box);
|
||||
|
||||
public:
|
||||
BlockContainer(DOM::Document&, DOM::Node*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
BlockContainer(DOM::Document&, DOM::Node*, CSS::ComputedValues);
|
||||
|
|
|
@ -18,6 +18,8 @@ struct LineBoxFragmentCoordinate {
|
|||
};
|
||||
|
||||
class Box : public NodeWithStyleAndBoxModelMetrics {
|
||||
JS_CELL(Box, NodeWithStyleAndBoxModelMetrics);
|
||||
|
||||
public:
|
||||
Painting::PaintableBox const* paint_box() const;
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class BreakNode final : public NodeWithStyleAndBoxModelMetrics {
|
||||
JS_CELL(BreakNode, NodeWithStyleAndBoxModelMetrics);
|
||||
|
||||
public:
|
||||
BreakNode(DOM::Document&, HTML::HTMLBRElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~BreakNode() override;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class ButtonBox : public FormAssociatedLabelableNode {
|
||||
JS_CELL(ButtonBox, FormAssociatedLabelableNode);
|
||||
|
||||
public:
|
||||
ButtonBox(DOM::Document&, HTML::HTMLInputElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~ButtonBox() override;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class CanvasBox : public ReplacedBox {
|
||||
JS_CELL(CanvasBox, ReplacedBox);
|
||||
|
||||
public:
|
||||
CanvasBox(DOM::Document&, HTML::HTMLCanvasElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~CanvasBox() override;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class CheckBox : public FormAssociatedLabelableNode {
|
||||
JS_CELL(CheckBox, FormAssociatedLabelableNode);
|
||||
|
||||
public:
|
||||
CheckBox(DOM::Document&, HTML::HTMLInputElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~CheckBox() override;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class FormAssociatedLabelableNode : public LabelableNode {
|
||||
JS_CELL(FormAssociatedLabelableNode, LabelableNode);
|
||||
|
||||
public:
|
||||
const HTML::FormAssociatedElement& dom_node() const { return dynamic_cast<const HTML::FormAssociatedElement&>(LabelableNode::dom_node()); }
|
||||
HTML::FormAssociatedElement& dom_node() { return dynamic_cast<HTML::FormAssociatedElement&>(LabelableNode::dom_node()); }
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class FrameBox final : public ReplacedBox {
|
||||
JS_CELL(FrameBox, ReplacedBox);
|
||||
|
||||
public:
|
||||
FrameBox(DOM::Document&, DOM::Element&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~FrameBox() override;
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Web::Layout {
|
|||
class ImageBox
|
||||
: public ReplacedBox
|
||||
, public HTML::BrowsingContext::ViewportClient {
|
||||
JS_CELL(ImageBox, ReplacedBox);
|
||||
|
||||
public:
|
||||
ImageBox(DOM::Document&, DOM::Element&, NonnullRefPtr<CSS::StyleProperties>, ImageLoader const&);
|
||||
virtual ~ImageBox() override;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class InitialContainingBlock final : public BlockContainer {
|
||||
JS_CELL(InitialContainingBlock, BlockContainer);
|
||||
|
||||
public:
|
||||
explicit InitialContainingBlock(DOM::Document&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~InitialContainingBlock() override;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class InlineNode : public NodeWithStyleAndBoxModelMetrics {
|
||||
JS_CELL(InlineNode, NodeWithStyleAndBoxModelMetrics);
|
||||
|
||||
public:
|
||||
InlineNode(DOM::Document&, DOM::Element*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~InlineNode() override;
|
||||
|
|
|
@ -38,9 +38,6 @@ void Label::handle_mouseup_on_label(Badge<Painting::TextPaintable>, Gfx::IntPoin
|
|||
if (!m_tracking_mouse || button != GUI::MouseButton::Primary)
|
||||
return;
|
||||
|
||||
// NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protect = *this;
|
||||
|
||||
if (auto* control = labeled_control(); control) {
|
||||
bool is_inside_control = enclosing_int_rect(control->paint_box()->absolute_rect()).contains(position);
|
||||
bool is_inside_label = enclosing_int_rect(paint_box()->absolute_rect()).contains(position);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class Label final : public BlockContainer {
|
||||
JS_CELL(Label, BlockContainer);
|
||||
|
||||
public:
|
||||
Label(DOM::Document&, HTML::HTMLLabelElement*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~Label() override;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class LabelableNode : public ReplacedBox {
|
||||
JS_CELL(LabelableNode, ReplacedBox);
|
||||
|
||||
public:
|
||||
Painting::LabelablePaintable* paintable();
|
||||
Painting::LabelablePaintable const* paintable() const;
|
||||
|
|
|
@ -23,7 +23,7 @@ LayoutRange LayoutRange::normalized() const
|
|||
{
|
||||
if (!is_valid())
|
||||
return {};
|
||||
if (m_start.layout_node == m_end.layout_node) {
|
||||
if (m_start.layout_node.ptr() == m_end.layout_node.ptr()) {
|
||||
if (m_start.index_in_node < m_end.index_in_node)
|
||||
return *this;
|
||||
return { m_end, m_start };
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Web::Layout {
|
|||
class Node;
|
||||
|
||||
struct LayoutPosition {
|
||||
RefPtr<Node> layout_node;
|
||||
JS::Handle<Layout::Node> layout_node;
|
||||
int index_in_node { 0 };
|
||||
|
||||
DOM::Position to_dom_position() const;
|
||||
|
|
|
@ -17,7 +17,13 @@ ListItemBox::ListItemBox(DOM::Document& document, DOM::Element* element, Nonnull
|
|||
|
||||
ListItemBox::~ListItemBox() = default;
|
||||
|
||||
void ListItemBox::set_marker(RefPtr<ListItemMarkerBox> marker)
|
||||
void ListItemBox::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_marker);
|
||||
}
|
||||
|
||||
void ListItemBox::set_marker(JS::GCPtr<ListItemMarkerBox> marker)
|
||||
{
|
||||
m_marker = move(marker);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class ListItemBox final : public BlockContainer {
|
||||
JS_CELL(ListItemBox, BlockContainer);
|
||||
|
||||
public:
|
||||
ListItemBox(DOM::Document&, DOM::Element*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~ListItemBox() override;
|
||||
|
@ -20,10 +22,12 @@ public:
|
|||
DOM::Element const& dom_node() const { return static_cast<DOM::Element const&>(*BlockContainer::dom_node()); }
|
||||
|
||||
ListItemMarkerBox const* marker() const { return m_marker; }
|
||||
void set_marker(RefPtr<ListItemMarkerBox>);
|
||||
void set_marker(JS::GCPtr<ListItemMarkerBox>);
|
||||
|
||||
private:
|
||||
RefPtr<ListItemMarkerBox> m_marker;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
JS::GCPtr<ListItemMarkerBox> m_marker;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class ListItemMarkerBox final : public Box {
|
||||
JS_CELL(ListItemMarkerBox, Box);
|
||||
|
||||
public:
|
||||
explicit ListItemMarkerBox(DOM::Document&, CSS::ListStyleType, size_t index, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~ListItemMarkerBox() override;
|
||||
|
|
|
@ -15,24 +15,26 @@
|
|||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
#include <LibWeb/Platform/FontPlugin.h>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace Web::Layout {
|
||||
|
||||
Node::Node(DOM::Document& document, DOM::Node* node)
|
||||
: m_dom_node(node ? node : &document)
|
||||
: m_dom_node(node ? *node : document)
|
||||
, m_anonymous(node == nullptr)
|
||||
{
|
||||
m_serial_id = document.next_layout_node_serial_id({});
|
||||
|
||||
if (node)
|
||||
node->set_layout_node({}, this);
|
||||
node->set_layout_node({}, *this);
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
Node::~Node() = default;
|
||||
|
||||
void Node::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
if (!is_anonymous() && m_dom_node->layout_node() == this)
|
||||
m_dom_node->set_layout_node({}, nullptr);
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_dom_node);
|
||||
TreeNode::visit_edges(visitor);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-display-3/#out-of-flow
|
||||
|
@ -558,16 +560,10 @@ bool Node::is_root_element() const
|
|||
return is<HTML::HTMLHtmlElement>(*dom_node());
|
||||
}
|
||||
|
||||
String Node::class_name() const
|
||||
{
|
||||
auto const* mangled_name = typeid(*this).name();
|
||||
return demangle({ mangled_name, strlen(mangled_name) });
|
||||
}
|
||||
|
||||
String Node::debug_description() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.append(class_name().substring_view(13));
|
||||
builder.append(class_name());
|
||||
if (dom_node()) {
|
||||
builder.appendff("<{}>", dom_node()->node_name());
|
||||
if (dom_node()->is_element()) {
|
||||
|
@ -604,13 +600,13 @@ bool Node::is_inline_block() const
|
|||
return display.is_inline_outside() && display.is_flow_root_inside();
|
||||
}
|
||||
|
||||
NonnullRefPtr<NodeWithStyle> NodeWithStyle::create_anonymous_wrapper() const
|
||||
JS::NonnullGCPtr<NodeWithStyle> NodeWithStyle::create_anonymous_wrapper() const
|
||||
{
|
||||
auto wrapper = adopt_ref(*new BlockContainer(const_cast<DOM::Document&>(document()), nullptr, m_computed_values.clone_inherited_values()));
|
||||
auto wrapper = heap().allocate_without_realm<BlockContainer>(const_cast<DOM::Document&>(document()), nullptr, m_computed_values.clone_inherited_values());
|
||||
static_cast<CSS::MutableComputedValues&>(wrapper->m_computed_values).set_display(CSS::Display(CSS::Display::Outside::Block, CSS::Display::Inside::Flow));
|
||||
wrapper->m_font = m_font;
|
||||
wrapper->m_line_height = m_line_height;
|
||||
return wrapper;
|
||||
return *wrapper;
|
||||
}
|
||||
|
||||
void Node::set_paintable(RefPtr<Painting::Paintable> paintable)
|
||||
|
|
|
@ -31,7 +31,12 @@ enum class LayoutMode {
|
|||
IntrinsicSizing,
|
||||
};
|
||||
|
||||
class Node : public TreeNode<Node> {
|
||||
class Node
|
||||
: public JS::Cell
|
||||
, public TreeNode<Node>
|
||||
, public Weakable<Node> {
|
||||
JS_CELL(Node, JS::Cell);
|
||||
|
||||
public:
|
||||
virtual ~Node();
|
||||
|
||||
|
@ -61,7 +66,6 @@ public:
|
|||
|
||||
bool is_root_element() const;
|
||||
|
||||
String class_name() const;
|
||||
String debug_description() const;
|
||||
|
||||
bool has_style() const { return m_has_style; }
|
||||
|
@ -140,10 +144,12 @@ public:
|
|||
protected:
|
||||
Node(DOM::Document&, DOM::Node*);
|
||||
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
friend class NodeWithStyle;
|
||||
|
||||
JS::Handle<DOM::Node> m_dom_node;
|
||||
JS::NonnullGCPtr<DOM::Node> m_dom_node;
|
||||
RefPtr<Painting::Paintable> m_paintable;
|
||||
|
||||
size_t m_serial_id { 0 };
|
||||
|
@ -159,6 +165,8 @@ private:
|
|||
};
|
||||
|
||||
class NodeWithStyle : public Node {
|
||||
JS_CELL(NodeWithStyle, Node);
|
||||
|
||||
public:
|
||||
virtual ~NodeWithStyle() override = default;
|
||||
|
||||
|
@ -171,7 +179,7 @@ public:
|
|||
Vector<CSS::BackgroundLayerData> const& background_layers() const { return computed_values().background_layers(); }
|
||||
const CSS::AbstractImageStyleValue* list_style_image() const { return m_list_style_image; }
|
||||
|
||||
NonnullRefPtr<NodeWithStyle> create_anonymous_wrapper() const;
|
||||
JS::NonnullGCPtr<NodeWithStyle> create_anonymous_wrapper() const;
|
||||
|
||||
protected:
|
||||
NodeWithStyle(DOM::Document&, DOM::Node*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
|
@ -185,6 +193,8 @@ private:
|
|||
};
|
||||
|
||||
class NodeWithStyleAndBoxModelMetrics : public NodeWithStyle {
|
||||
JS_CELL(NodeWithStyleAndBoxModelMetrics, NodeWithStyle);
|
||||
|
||||
public:
|
||||
BoxModelMetrics& box_model() { return m_box_model; }
|
||||
BoxModelMetrics const& box_model() const { return m_box_model; }
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class Progress : public LabelableNode {
|
||||
JS_CELL(Progress, LabelableNode);
|
||||
|
||||
public:
|
||||
Progress(DOM::Document&, HTML::HTMLProgressElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~Progress() override;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class RadioButton final : public FormAssociatedLabelableNode {
|
||||
JS_CELL(RadioButton, FormAssociatedLabelableNode);
|
||||
|
||||
public:
|
||||
RadioButton(DOM::Document&, HTML::HTMLInputElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~RadioButton() override;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class ReplacedBox : public Box {
|
||||
JS_CELL(ReplacedBox, Box);
|
||||
|
||||
public:
|
||||
ReplacedBox(DOM::Document&, DOM::Element&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~ReplacedBox() override;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class SVGBox : public Box {
|
||||
JS_CELL(SVGBox, Box);
|
||||
|
||||
public:
|
||||
SVGBox(DOM::Document&, SVG::SVGElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~SVGBox() override = default;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class SVGGeometryBox final : public SVGGraphicsBox {
|
||||
JS_CELL(SVGGeometryBox, SVGGraphicsBox);
|
||||
|
||||
public:
|
||||
SVGGeometryBox(DOM::Document&, SVG::SVGGeometryElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~SVGGeometryBox() override = default;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class SVGGraphicsBox : public SVGBox {
|
||||
JS_CELL(SVGGraphicsBox, SVGBox);
|
||||
|
||||
public:
|
||||
SVGGraphicsBox(DOM::Document&, SVG::SVGGraphicsElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~SVGGraphicsBox() override = default;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class SVGSVGBox final : public ReplacedBox {
|
||||
JS_CELL(SVGSVGBox, ReplacedBox);
|
||||
|
||||
public:
|
||||
SVGSVGBox(DOM::Document&, SVG::SVGSVGElement&, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~SVGSVGBox() override = default;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class TableBox final : public Layout::BlockContainer {
|
||||
JS_CELL(TableBox, BlockContainer);
|
||||
|
||||
public:
|
||||
TableBox(DOM::Document&, DOM::Element*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
TableBox(DOM::Document&, DOM::Element*, CSS::ComputedValues);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class TableCellBox final : public BlockContainer {
|
||||
JS_CELL(TableCellBox, BlockContainer);
|
||||
|
||||
public:
|
||||
TableCellBox(DOM::Document&, DOM::Element*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
TableCellBox(DOM::Document&, DOM::Element*, CSS::ComputedValues);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class TableRowBox final : public Box {
|
||||
JS_CELL(TableRowBox, Box);
|
||||
|
||||
public:
|
||||
TableRowBox(DOM::Document&, DOM::Element*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
TableRowBox(DOM::Document&, DOM::Element*, CSS::ComputedValues);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
namespace Web::Layout {
|
||||
|
||||
class TableRowGroupBox final : public BlockContainer {
|
||||
JS_CELL(TableRowGroupBox, BlockContainer);
|
||||
|
||||
public:
|
||||
TableRowGroupBox(DOM::Document&, DOM::Element*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
virtual ~TableRowGroupBox() override;
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Web::Layout {
|
|||
class LineBoxFragment;
|
||||
|
||||
class TextNode : public Node {
|
||||
JS_CELL(TextNode, Node);
|
||||
|
||||
public:
|
||||
TextNode(DOM::Document&, DOM::Text&);
|
||||
virtual ~TextNode() override;
|
||||
|
|
|
@ -31,7 +31,7 @@ TreeBuilder::TreeBuilder() = default;
|
|||
|
||||
static bool has_inline_or_in_flow_block_children(Layout::Node const& layout_node)
|
||||
{
|
||||
for (auto const* child = layout_node.first_child(); child; child = child->next_sibling()) {
|
||||
for (auto child = layout_node.first_child(); child; child = child->next_sibling()) {
|
||||
if (child->is_inline())
|
||||
return true;
|
||||
if (!child->is_floating() && !child->is_absolutely_positioned())
|
||||
|
@ -44,7 +44,7 @@ static bool has_in_flow_block_children(Layout::Node const& layout_node)
|
|||
{
|
||||
if (layout_node.children_are_inline())
|
||||
return false;
|
||||
for (auto const* child = layout_node.first_child(); child; child = child->next_sibling()) {
|
||||
for (auto child = layout_node.first_child(); child; child = child->next_sibling()) {
|
||||
if (child->is_inline())
|
||||
continue;
|
||||
if (!child->is_floating() && !child->is_absolutely_positioned())
|
||||
|
@ -95,15 +95,15 @@ static Layout::Node& insertion_parent_for_block_node(Layout::NodeWithStyle& layo
|
|||
|
||||
// Parent block has inline-level children (our siblings).
|
||||
// First move these siblings into an anonymous wrapper block.
|
||||
NonnullRefPtrVector<Layout::Node> children;
|
||||
while (RefPtr<Layout::Node> child = layout_parent.first_child()) {
|
||||
Vector<JS::Handle<Layout::Node>> children;
|
||||
while (JS::GCPtr<Layout::Node> child = layout_parent.first_child()) {
|
||||
layout_parent.remove_child(*child);
|
||||
children.append(child.release_nonnull());
|
||||
children.append(*child);
|
||||
}
|
||||
layout_parent.append_child(layout_parent.create_anonymous_wrapper());
|
||||
layout_parent.set_children_are_inline(false);
|
||||
for (auto& child : children) {
|
||||
layout_parent.last_child()->append_child(child);
|
||||
layout_parent.last_child()->append_child(*child);
|
||||
}
|
||||
layout_parent.last_child()->set_children_are_inline(true);
|
||||
// Then it's safe to insert this block into parent.
|
||||
|
@ -166,10 +166,10 @@ void TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Se
|
|||
// FIXME: Handle images, and multiple values
|
||||
if (pseudo_element_content.type == CSS::ContentData::Type::String) {
|
||||
auto* text = document.heap().allocate<DOM::Text>(document.realm(), document, pseudo_element_content.data);
|
||||
auto text_node = adopt_ref(*new TextNode(document, *text));
|
||||
auto text_node = document.heap().allocate_without_realm<Layout::TextNode>(document, *text);
|
||||
text_node->set_generated(true);
|
||||
push_parent(verify_cast<NodeWithStyle>(*pseudo_element_node));
|
||||
insert_node_into_inline_or_block_ancestor(text_node, text_node->display(), AppendOrPrepend::Append);
|
||||
insert_node_into_inline_or_block_ancestor(*text_node, text_node->display(), AppendOrPrepend::Append);
|
||||
pop_parent();
|
||||
} else {
|
||||
TODO();
|
||||
|
@ -195,7 +195,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
|
||||
auto& document = dom_node.document();
|
||||
auto& style_computer = document.style_computer();
|
||||
RefPtr<Layout::Node> layout_node;
|
||||
JS::GCPtr<Layout::Node> layout_node;
|
||||
RefPtr<CSS::StyleProperties> style;
|
||||
CSS::Display display;
|
||||
|
||||
|
@ -211,12 +211,12 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
} else if (is<DOM::Document>(dom_node)) {
|
||||
style = style_computer.create_document_style();
|
||||
display = style->display();
|
||||
layout_node = adopt_ref(*new Layout::InitialContainingBlock(static_cast<DOM::Document&>(dom_node), *style));
|
||||
layout_node = document.heap().allocate_without_realm<Layout::InitialContainingBlock>(static_cast<DOM::Document&>(dom_node), *style);
|
||||
} else if (is<DOM::Text>(dom_node)) {
|
||||
layout_node = adopt_ref(*new Layout::TextNode(document, static_cast<DOM::Text&>(dom_node)));
|
||||
layout_node = document.heap().allocate_without_realm<Layout::TextNode>(document, static_cast<DOM::Text&>(dom_node));
|
||||
display = CSS::Display(CSS::Display::Outside::Inline, CSS::Display::Inside::Flow);
|
||||
} else if (is<DOM::ShadowRoot>(dom_node)) {
|
||||
layout_node = adopt_ref(*new Layout::BlockContainer(document, &static_cast<DOM::ShadowRoot&>(dom_node), CSS::ComputedValues {}));
|
||||
layout_node = document.heap().allocate_without_realm<Layout::BlockContainer>(document, &static_cast<DOM::ShadowRoot&>(dom_node), CSS::ComputedValues {});
|
||||
display = CSS::Display(CSS::Display::Outside::Block, CSS::Display::Inside::FlowRoot);
|
||||
}
|
||||
|
||||
|
@ -256,10 +256,10 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
auto& element = static_cast<DOM::Element&>(dom_node);
|
||||
int child_index = layout_node->parent()->index_of_child<ListItemBox>(*layout_node).value();
|
||||
auto marker_style = style_computer.compute_style(element, CSS::Selector::PseudoElement::Marker);
|
||||
auto list_item_marker = adopt_ref(*new ListItemMarkerBox(document, layout_node->computed_values().list_style_type(), child_index + 1, *marker_style));
|
||||
auto list_item_marker = document.heap().allocate_without_realm<ListItemMarkerBox>(document, layout_node->computed_values().list_style_type(), child_index + 1, *marker_style);
|
||||
static_cast<ListItemBox&>(*layout_node).set_marker(list_item_marker);
|
||||
element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::Marker, list_item_marker);
|
||||
layout_node->append_child(move(list_item_marker));
|
||||
layout_node->append_child(*list_item_marker);
|
||||
}
|
||||
|
||||
if (is<HTML::HTMLProgressElement>(dom_node)) {
|
||||
|
@ -287,7 +287,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<Node> TreeBuilder::build(DOM::Node& dom_node)
|
||||
JS::GCPtr<Layout::Node> TreeBuilder::build(DOM::Node& dom_node)
|
||||
{
|
||||
VERIFY(dom_node.is_document());
|
||||
|
||||
|
@ -333,7 +333,7 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
|
|||
{
|
||||
// The following boxes are discarded as if they were display:none:
|
||||
|
||||
NonnullRefPtrVector<Node> to_remove;
|
||||
Vector<JS::Handle<Node>> to_remove;
|
||||
|
||||
// Children of a table-column.
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableColumn>(root, [&](Box& table_column) {
|
||||
|
@ -358,7 +358,7 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
|
|||
// - whose immediate sibling, if any, is a table-non-root box
|
||||
|
||||
for (auto& box : to_remove)
|
||||
box.parent()->remove_child(box);
|
||||
box->parent()->remove_child(*box);
|
||||
}
|
||||
|
||||
static bool is_table_track(CSS::Display display)
|
||||
|
@ -424,18 +424,18 @@ static bool is_ignorable_whitespace(Layout::Node const& node)
|
|||
template<typename Matcher, typename Callback>
|
||||
static void for_each_sequence_of_consecutive_children_matching(NodeWithStyle& parent, Matcher matcher, Callback callback)
|
||||
{
|
||||
NonnullRefPtrVector<Node> sequence;
|
||||
Vector<JS::Handle<Node>> sequence;
|
||||
|
||||
auto sequence_is_all_ignorable_whitespace = [&]() -> bool {
|
||||
for (auto& node : sequence) {
|
||||
if (!is_ignorable_whitespace(node))
|
||||
if (!is_ignorable_whitespace(*node))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Node* next_sibling = nullptr;
|
||||
for (auto* child = parent.first_child(); child; child = next_sibling) {
|
||||
for (auto child = parent.first_child(); child; child = next_sibling) {
|
||||
next_sibling = child->next_sibling();
|
||||
if (matcher(*child)) {
|
||||
sequence.append(*child);
|
||||
|
@ -452,21 +452,21 @@ static void for_each_sequence_of_consecutive_children_matching(NodeWithStyle& pa
|
|||
}
|
||||
|
||||
template<typename WrapperBoxType>
|
||||
static void wrap_in_anonymous(NonnullRefPtrVector<Node>& sequence, Node* nearest_sibling)
|
||||
static void wrap_in_anonymous(Vector<JS::Handle<Node>>& sequence, Node* nearest_sibling)
|
||||
{
|
||||
VERIFY(!sequence.is_empty());
|
||||
auto& parent = *sequence.first().parent();
|
||||
auto& parent = *sequence.first()->parent();
|
||||
auto computed_values = parent.computed_values().clone_inherited_values();
|
||||
static_cast<CSS::MutableComputedValues&>(computed_values).set_display(WrapperBoxType::static_display());
|
||||
auto wrapper = adopt_ref(*new WrapperBoxType(parent.document(), nullptr, move(computed_values)));
|
||||
auto wrapper = parent.heap().template allocate_without_realm<WrapperBoxType>(parent.document(), nullptr, move(computed_values));
|
||||
for (auto& child : sequence) {
|
||||
parent.remove_child(child);
|
||||
wrapper->append_child(child);
|
||||
parent.remove_child(*child);
|
||||
wrapper->append_child(*child);
|
||||
}
|
||||
if (nearest_sibling)
|
||||
parent.insert_before(move(wrapper), *nearest_sibling);
|
||||
parent.insert_before(*wrapper, *nearest_sibling);
|
||||
else
|
||||
parent.append_child(move(wrapper));
|
||||
parent.append_child(*wrapper);
|
||||
}
|
||||
|
||||
void TreeBuilder::generate_missing_child_wrappers(NodeWithStyle& root)
|
||||
|
|
|
@ -17,7 +17,7 @@ class TreeBuilder {
|
|||
public:
|
||||
TreeBuilder();
|
||||
|
||||
RefPtr<Layout::Node> build(DOM::Node&);
|
||||
JS::GCPtr<Layout::Node> build(DOM::Node&);
|
||||
|
||||
private:
|
||||
struct Context {
|
||||
|
@ -47,7 +47,7 @@ private:
|
|||
void insert_node_into_inline_or_block_ancestor(Layout::Node&, CSS::Display, AppendOrPrepend);
|
||||
void create_pseudo_element_if_needed(DOM::Element&, CSS::Selector::PseudoElement, AppendOrPrepend);
|
||||
|
||||
RefPtr<Layout::Node> m_layout_root;
|
||||
JS::GCPtr<Layout::Node> m_layout_root;
|
||||
Vector<Layout::NodeWithStyle&> m_ancestor_stack;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue