mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:57:44 +00:00
LibHTML: Start fleshing out a basic layout tree.
This commit is contained in:
parent
f8a86b5164
commit
8a0e21b22b
24 changed files with 338 additions and 18 deletions
|
@ -1,4 +1,7 @@
|
||||||
#include <LibHTML/Document.h>
|
#include <LibHTML/Document.h>
|
||||||
|
#include <LibHTML/Element.h>
|
||||||
|
#include <LibHTML/LayoutDocument.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
Document::Document()
|
Document::Document()
|
||||||
: ParentNode(NodeType::DOCUMENT_NODE)
|
: ParentNode(NodeType::DOCUMENT_NODE)
|
||||||
|
@ -9,3 +12,31 @@ Document::~Document()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_layout_tree_for_node(Node& node)
|
||||||
|
{
|
||||||
|
if (auto layout_node = node.create_layout_node()) {
|
||||||
|
node.set_layout_node(*layout_node);
|
||||||
|
#ifdef DEBUG_LAYOUT_TREE_BUILD
|
||||||
|
if (node.is_element()) {
|
||||||
|
printf("created layout node for <%s>, parent is %p, parent ln is %p\n", static_cast<const Element&>(node).tag_name().characters(), node.parent_node(), node.parent_node()->layout_node());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (node.parent_node() && node.parent_node()->layout_node())
|
||||||
|
node.parent_node()->layout_node()->append_child(*layout_node);
|
||||||
|
}
|
||||||
|
if (node.is_parent_node()) {
|
||||||
|
static_cast<ParentNode&>(node).for_each_child([&](auto& child) {
|
||||||
|
create_layout_tree_for_node(child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::build_layout_tree()
|
||||||
|
{
|
||||||
|
create_layout_tree_for_node(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RetainPtr<LayoutNode> Document::create_layout_node()
|
||||||
|
{
|
||||||
|
return adopt(*new LayoutDocument(*this));
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,16 @@
|
||||||
#include <AK/AKString.h>
|
#include <AK/AKString.h>
|
||||||
#include <LibHTML/ParentNode.h>
|
#include <LibHTML/ParentNode.h>
|
||||||
|
|
||||||
|
class LayoutNode;
|
||||||
|
|
||||||
class Document : public ParentNode {
|
class Document : public ParentNode {
|
||||||
public:
|
public:
|
||||||
Document();
|
Document();
|
||||||
virtual ~Document() override;
|
virtual ~Document() override;
|
||||||
|
|
||||||
|
virtual RetainPtr<LayoutNode> create_layout_node() override;
|
||||||
|
|
||||||
|
void build_layout_tree();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include <LibHTML/Document.h>
|
#include <LibHTML/Document.h>
|
||||||
#include <LibHTML/Dump.h>
|
#include <LibHTML/Dump.h>
|
||||||
#include <LibHTML/Element.h>
|
#include <LibHTML/Element.h>
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
#include <LibHTML/LayoutText.h>
|
||||||
#include <LibHTML/Text.h>
|
#include <LibHTML/Text.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void dump_tree(Node& node)
|
void dump_tree(const Node& node)
|
||||||
{
|
{
|
||||||
static int indent = 0;
|
static int indent = 0;
|
||||||
for (int i = 0; i < indent; ++i)
|
for (int i = 0; i < indent; ++i)
|
||||||
|
@ -12,19 +14,35 @@ void dump_tree(Node& node)
|
||||||
if (node.is_document()) {
|
if (node.is_document()) {
|
||||||
printf("*Document*\n");
|
printf("*Document*\n");
|
||||||
} else if (node.is_element()) {
|
} else if (node.is_element()) {
|
||||||
printf("<%s", static_cast<Element&>(node).tag_name().characters());
|
printf("<%s", static_cast<const Element&>(node).tag_name().characters());
|
||||||
static_cast<Element&>(node).for_each_attribute([](auto& name, auto& value) {
|
static_cast<const Element&>(node).for_each_attribute([](auto& name, auto& value) {
|
||||||
printf(" %s=%s", name.characters(), value.characters());
|
printf(" %s=%s", name.characters(), value.characters());
|
||||||
});
|
});
|
||||||
printf(">\n");
|
printf(">\n");
|
||||||
} else if (node.is_text()) {
|
} else if (node.is_text()) {
|
||||||
printf("\"%s\"\n", static_cast<Text&>(node).data().characters());
|
printf("\"%s\"\n", static_cast<const Text&>(node).data().characters());
|
||||||
}
|
}
|
||||||
++indent;
|
++indent;
|
||||||
if (node.is_parent_node()) {
|
if (node.is_parent_node()) {
|
||||||
static_cast<ParentNode&>(node).for_each_child([](Node& child) {
|
static_cast<const ParentNode&>(node).for_each_child([](auto& child) {
|
||||||
dump_tree(child);
|
dump_tree(child);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
--indent;
|
--indent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_tree(const LayoutNode& node)
|
||||||
|
{
|
||||||
|
static int indent = 0;
|
||||||
|
for (int i = 0; i < indent; ++i)
|
||||||
|
printf(" ");
|
||||||
|
printf("%s{%p}", node.class_name(), &node);
|
||||||
|
if (node.is_text())
|
||||||
|
printf(" \"%s\"", static_cast<const LayoutText&>(node).node().data().characters());
|
||||||
|
printf("\n");
|
||||||
|
++indent;
|
||||||
|
node.for_each_child([](auto& child) {
|
||||||
|
dump_tree(child);
|
||||||
|
});
|
||||||
|
--indent;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class Node;
|
class Node;
|
||||||
|
class LayoutNode;
|
||||||
|
|
||||||
void dump_tree(Node&);
|
void dump_tree(const Node&);
|
||||||
|
void dump_tree(const LayoutNode&);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include <LibHTML/Element.h>
|
#include <LibHTML/Element.h>
|
||||||
|
#include <LibHTML/LayoutBlock.h>
|
||||||
|
#include <LibHTML/LayoutInline.h>
|
||||||
|
|
||||||
Element::Element(const String& tag_name)
|
Element::Element(const String& tag_name)
|
||||||
: ParentNode(NodeType::ELEMENT_NODE)
|
: ParentNode(NodeType::ELEMENT_NODE)
|
||||||
|
@ -47,3 +49,18 @@ void Element::set_attributes(Vector<Attribute>&& attributes)
|
||||||
{
|
{
|
||||||
m_attributes = move(attributes);
|
m_attributes = move(attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RetainPtr<LayoutNode> Element::create_layout_node()
|
||||||
|
{
|
||||||
|
if (m_tag_name == "html")
|
||||||
|
return adopt(*new LayoutBlock(*this));
|
||||||
|
if (m_tag_name == "body")
|
||||||
|
return adopt(*new LayoutBlock(*this));
|
||||||
|
if (m_tag_name == "h1")
|
||||||
|
return adopt(*new LayoutBlock(*this));
|
||||||
|
if (m_tag_name == "p")
|
||||||
|
return adopt(*new LayoutBlock(*this));
|
||||||
|
if (m_tag_name == "b")
|
||||||
|
return adopt(*new LayoutInline(*this));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -34,12 +34,14 @@ public:
|
||||||
void set_attributes(Vector<Attribute>&&);
|
void set_attributes(Vector<Attribute>&&);
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_attribute(Callback callback)
|
void for_each_attribute(Callback callback) const
|
||||||
{
|
{
|
||||||
for (auto& attribute : m_attributes)
|
for (auto& attribute : m_attributes)
|
||||||
callback(attribute.name(), attribute.value());
|
callback(attribute.name(), attribute.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual RetainPtr<LayoutNode> create_layout_node() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Attribute* find_attribute(const String& name);
|
Attribute* find_attribute(const String& name);
|
||||||
const Attribute* find_attribute(const String& name) const;
|
const Attribute* find_attribute(const String& name) const;
|
||||||
|
|
11
LibHTML/LayoutBlock.cpp
Normal file
11
LibHTML/LayoutBlock.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <LibHTML/Element.h>
|
||||||
|
#include <LibHTML/LayoutBlock.h>
|
||||||
|
|
||||||
|
LayoutBlock::LayoutBlock(Element& element)
|
||||||
|
: LayoutNode(&element)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutBlock::~LayoutBlock()
|
||||||
|
{
|
||||||
|
}
|
15
LibHTML/LayoutBlock.h
Normal file
15
LibHTML/LayoutBlock.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
|
||||||
|
class Element;
|
||||||
|
|
||||||
|
class LayoutBlock : public LayoutNode {
|
||||||
|
public:
|
||||||
|
explicit LayoutBlock(Element&);
|
||||||
|
virtual ~LayoutBlock() override;
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "LayoutBlock"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
10
LibHTML/LayoutDocument.cpp
Normal file
10
LibHTML/LayoutDocument.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include <LibHTML/LayoutDocument.h>
|
||||||
|
|
||||||
|
LayoutDocument::LayoutDocument(const Document& document)
|
||||||
|
: LayoutNode(&document)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutDocument::~LayoutDocument()
|
||||||
|
{
|
||||||
|
}
|
16
LibHTML/LayoutDocument.h
Normal file
16
LibHTML/LayoutDocument.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
#include <LibHTML/Document.h>
|
||||||
|
|
||||||
|
class LayoutDocument : public LayoutNode {
|
||||||
|
public:
|
||||||
|
explicit LayoutDocument(const Document&);
|
||||||
|
virtual ~LayoutDocument() override;
|
||||||
|
|
||||||
|
const Document& node() const { return static_cast<const Document&>(*LayoutNode::node()); }
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "LayoutDocument"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
11
LibHTML/LayoutInline.cpp
Normal file
11
LibHTML/LayoutInline.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <LibHTML/Element.h>
|
||||||
|
#include <LibHTML/LayoutInline.h>
|
||||||
|
|
||||||
|
LayoutInline::LayoutInline(Element& element)
|
||||||
|
: LayoutNode(&element)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutInline::~LayoutInline()
|
||||||
|
{
|
||||||
|
}
|
15
LibHTML/LayoutInline.h
Normal file
15
LibHTML/LayoutInline.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
|
||||||
|
class Element;
|
||||||
|
|
||||||
|
class LayoutInline : public LayoutNode {
|
||||||
|
public:
|
||||||
|
explicit LayoutInline(Element&);
|
||||||
|
virtual ~LayoutInline() override;
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "LayoutInline"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
33
LibHTML/LayoutNode.cpp
Normal file
33
LibHTML/LayoutNode.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
|
||||||
|
LayoutNode::LayoutNode(const Node* node)
|
||||||
|
: m_node(node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutNode::~LayoutNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutNode::retain()
|
||||||
|
{
|
||||||
|
ASSERT(m_retain_count);
|
||||||
|
++m_retain_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutNode::release()
|
||||||
|
{
|
||||||
|
ASSERT(m_retain_count);
|
||||||
|
if (!--m_retain_count)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutNode::append_child(Retained<LayoutNode> node)
|
||||||
|
{
|
||||||
|
if (m_last_child)
|
||||||
|
m_last_child->set_next_sibling(node.ptr());
|
||||||
|
node->m_parent_node = this;
|
||||||
|
m_last_child = &node.leak_ref();
|
||||||
|
if (!m_first_child)
|
||||||
|
m_first_child = m_last_child;
|
||||||
|
}
|
54
LibHTML/LayoutNode.h
Normal file
54
LibHTML/LayoutNode.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Retained.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
|
||||||
|
class Node;
|
||||||
|
|
||||||
|
class LayoutNode {
|
||||||
|
public:
|
||||||
|
virtual ~LayoutNode();
|
||||||
|
|
||||||
|
void retain();
|
||||||
|
void release();
|
||||||
|
int retain_count() const { return m_retain_count; }
|
||||||
|
|
||||||
|
const Node* node() const { return m_node; }
|
||||||
|
|
||||||
|
LayoutNode* next_sibling() { return m_next_sibling; }
|
||||||
|
LayoutNode* previous_sibling() { return m_previous_sibling; }
|
||||||
|
LayoutNode* first_child() { return m_first_child; }
|
||||||
|
LayoutNode* last_child() { return m_last_child; }
|
||||||
|
const LayoutNode* next_sibling() const { return m_next_sibling; }
|
||||||
|
const LayoutNode* previous_sibling() const { return m_previous_sibling; }
|
||||||
|
const LayoutNode* first_child() const { return m_first_child; }
|
||||||
|
const LayoutNode* last_child() const { return m_last_child; }
|
||||||
|
|
||||||
|
void append_child(Retained<LayoutNode>);
|
||||||
|
|
||||||
|
void set_next_sibling(LayoutNode* node) { m_next_sibling = node; }
|
||||||
|
void set_previous_sibling(LayoutNode* node) { m_previous_sibling = node; }
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
inline void for_each_child(Callback callback) const
|
||||||
|
{
|
||||||
|
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||||
|
callback(*node);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* class_name() const { return "LayoutNode"; }
|
||||||
|
virtual bool is_text() const { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit LayoutNode(const Node*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_retain_count { 1 };
|
||||||
|
const Node* m_node { nullptr };
|
||||||
|
LayoutNode* m_parent_node { nullptr };
|
||||||
|
LayoutNode* m_first_child { nullptr };
|
||||||
|
LayoutNode* m_last_child { nullptr };
|
||||||
|
LayoutNode* m_next_sibling { nullptr };
|
||||||
|
LayoutNode* m_previous_sibling { nullptr };
|
||||||
|
};
|
||||||
|
|
10
LibHTML/LayoutText.cpp
Normal file
10
LibHTML/LayoutText.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include <LibHTML/LayoutText.h>
|
||||||
|
|
||||||
|
LayoutText::LayoutText(const Text& text)
|
||||||
|
: LayoutNode(&text)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutText::~LayoutText()
|
||||||
|
{
|
||||||
|
}
|
17
LibHTML/LayoutText.h
Normal file
17
LibHTML/LayoutText.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
#include <LibHTML/Text.h>
|
||||||
|
|
||||||
|
class LayoutText : public LayoutNode {
|
||||||
|
public:
|
||||||
|
explicit LayoutText(const Text&);
|
||||||
|
virtual ~LayoutText() override;
|
||||||
|
|
||||||
|
const Text& node() const { return static_cast<const Text&>(*LayoutNode::node()); }
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "LayoutText"; }
|
||||||
|
virtual bool is_text() const final { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
|
@ -7,6 +7,11 @@ LIBHTML_OBJS = \
|
||||||
Document.o \
|
Document.o \
|
||||||
Text.o \
|
Text.o \
|
||||||
Parser.o \
|
Parser.o \
|
||||||
|
LayoutNode.o \
|
||||||
|
LayoutText.o \
|
||||||
|
LayoutBlock.o \
|
||||||
|
LayoutInline.o \
|
||||||
|
LayoutDocument.o \
|
||||||
Dump.o
|
Dump.o
|
||||||
|
|
||||||
TEST_OBJS = test.o
|
TEST_OBJS = test.o
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <AK/Retained.h>
|
|
||||||
#include <LibHTML/Node.h>
|
#include <LibHTML/Node.h>
|
||||||
|
#include <LibHTML/LayoutNode.h>
|
||||||
|
|
||||||
Node::Node(NodeType type)
|
Node::Node(NodeType type)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
|
@ -22,3 +22,13 @@ void Node::release()
|
||||||
if (!--m_retain_count)
|
if (!--m_retain_count)
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RetainPtr<LayoutNode> Node::create_layout_node()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::set_layout_node(Retained<LayoutNode> layout_node)
|
||||||
|
{
|
||||||
|
m_layout_node = move(layout_node);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Retained.h>
|
#include <AK/Badge.h>
|
||||||
|
#include <AK/RetainPtr.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
|
|
||||||
enum class NodeType : unsigned {
|
enum class NodeType : unsigned {
|
||||||
|
@ -10,6 +11,9 @@ enum class NodeType : unsigned {
|
||||||
DOCUMENT_NODE = 9,
|
DOCUMENT_NODE = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LayoutNode;
|
||||||
|
class ParentNode;
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
public:
|
public:
|
||||||
virtual ~Node();
|
virtual ~Node();
|
||||||
|
@ -18,6 +22,11 @@ public:
|
||||||
void release();
|
void release();
|
||||||
int retain_count() const { return m_retain_count; }
|
int retain_count() const { return m_retain_count; }
|
||||||
|
|
||||||
|
ParentNode* parent_node() { return m_parent_node; }
|
||||||
|
const ParentNode* parent_node() const { return m_parent_node; }
|
||||||
|
|
||||||
|
void set_parent_node(Badge<ParentNode>, ParentNode* parent_node) { m_parent_node = parent_node; }
|
||||||
|
|
||||||
NodeType type() const { return m_type; }
|
NodeType type() const { return m_type; }
|
||||||
bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
|
bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
|
||||||
bool is_text() const { return type() == NodeType::TEXT_NODE; }
|
bool is_text() const { return type() == NodeType::TEXT_NODE; }
|
||||||
|
@ -26,16 +35,26 @@ public:
|
||||||
|
|
||||||
Node* next_sibling() { return m_next_sibling; }
|
Node* next_sibling() { return m_next_sibling; }
|
||||||
Node* previous_sibling() { return m_previous_sibling; }
|
Node* previous_sibling() { return m_previous_sibling; }
|
||||||
|
const Node* next_sibling() const { return m_next_sibling; }
|
||||||
|
const Node* previous_sibling() const { return m_previous_sibling; }
|
||||||
|
|
||||||
void set_next_sibling(Node* node) { m_next_sibling = node; }
|
void set_next_sibling(Node* node) { m_next_sibling = node; }
|
||||||
void set_previous_sibling(Node* node) { m_previous_sibling = node; }
|
void set_previous_sibling(Node* node) { m_previous_sibling = node; }
|
||||||
|
|
||||||
|
virtual RetainPtr<LayoutNode> create_layout_node();
|
||||||
|
|
||||||
|
const LayoutNode* layout_node() const { return m_layout_node; }
|
||||||
|
LayoutNode* layout_node() { return m_layout_node; }
|
||||||
|
|
||||||
|
void set_layout_node(Retained<LayoutNode>);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Node(NodeType);
|
explicit Node(NodeType);
|
||||||
|
|
||||||
int m_retain_count { 1 };
|
int m_retain_count { 1 };
|
||||||
NodeType m_type { NodeType::INVALID };
|
NodeType m_type { NodeType::INVALID };
|
||||||
Vector<Node*> m_children;
|
ParentNode* m_parent_node { nullptr };
|
||||||
Node* m_next_sibling { nullptr };
|
Node* m_next_sibling { nullptr };
|
||||||
Node* m_previous_sibling { nullptr };
|
Node* m_previous_sibling { nullptr };
|
||||||
|
RetainPtr<LayoutNode> m_layout_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ void ParentNode::append_child(Retained<Node> node)
|
||||||
{
|
{
|
||||||
if (m_last_child)
|
if (m_last_child)
|
||||||
m_last_child->set_next_sibling(node.ptr());
|
m_last_child->set_next_sibling(node.ptr());
|
||||||
|
node->set_parent_node({}, this);
|
||||||
m_last_child = &node.leak_ref();
|
m_last_child = &node.leak_ref();
|
||||||
if (!m_first_child)
|
if (!m_first_child)
|
||||||
m_first_child = m_last_child;
|
m_first_child = m_last_child;
|
||||||
|
|
|
@ -8,7 +8,10 @@ public:
|
||||||
|
|
||||||
Node* first_child() { return m_first_child; }
|
Node* first_child() { return m_first_child; }
|
||||||
Node* last_child() { return m_last_child; }
|
Node* last_child() { return m_last_child; }
|
||||||
|
const Node* first_child() const { return m_first_child; }
|
||||||
|
const Node* last_child() const { return m_last_child; }
|
||||||
|
|
||||||
|
template<typename F> void for_each_child(F) const;
|
||||||
template<typename F> void for_each_child(F);
|
template<typename F> void for_each_child(F);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -22,11 +25,16 @@ private:
|
||||||
Node* m_last_child { nullptr };
|
Node* m_last_child { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename Callback>
|
||||||
inline void ParentNode::for_each_child(F func)
|
inline void ParentNode::for_each_child(Callback callback) const
|
||||||
{
|
{
|
||||||
for (auto* node = first_child(); node; node = node->next_sibling()) {
|
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||||
func(*node);
|
callback(*node);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
inline void ParentNode::for_each_child(Callback callback)
|
||||||
|
{
|
||||||
|
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||||
|
callback(*node);
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <LibHTML/Text.h>
|
#include <LibHTML/Text.h>
|
||||||
|
#include <LibHTML/LayoutText.h>
|
||||||
|
|
||||||
Text::Text(const String& data)
|
Text::Text(const String& data)
|
||||||
: Node(NodeType::TEXT_NODE)
|
: Node(NodeType::TEXT_NODE)
|
||||||
|
@ -10,4 +11,7 @@ Text::~Text()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RetainPtr<LayoutNode> Text::create_layout_node()
|
||||||
|
{
|
||||||
|
return adopt(*new LayoutText(*this));
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ public:
|
||||||
|
|
||||||
const String& data() const { return m_data; }
|
const String& data() const { return m_data; }
|
||||||
|
|
||||||
|
virtual RetainPtr<LayoutNode> create_layout_node() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
String m_data;
|
String m_data;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,5 +14,9 @@ int main(int argc, char** argv)
|
||||||
String html = String::copy(f.read_all());
|
String html = String::copy(f.read_all());
|
||||||
auto doc = parse(html);
|
auto doc = parse(html);
|
||||||
dump_tree(doc);
|
dump_tree(doc);
|
||||||
|
|
||||||
|
doc->build_layout_tree();
|
||||||
|
ASSERT(doc->layout_node());
|
||||||
|
dump_tree(*doc->layout_node());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue