diff --git a/LibHTML/Document.cpp b/LibHTML/Document.cpp
index a7ba17c2b3..721000e38f 100644
--- a/LibHTML/Document.cpp
+++ b/LibHTML/Document.cpp
@@ -1,4 +1,7 @@
#include
+#include
+#include
+#include
Document::Document()
: 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(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(node).for_each_child([&](auto& child) {
+ create_layout_tree_for_node(child);
+ });
+ }
+}
+
+void Document::build_layout_tree()
+{
+ create_layout_tree_for_node(*this);
+}
+
+RetainPtr Document::create_layout_node()
+{
+ return adopt(*new LayoutDocument(*this));
+}
diff --git a/LibHTML/Document.h b/LibHTML/Document.h
index cf31d766b9..b06e5cdc9c 100644
--- a/LibHTML/Document.h
+++ b/LibHTML/Document.h
@@ -3,11 +3,16 @@
#include
#include
+class LayoutNode;
+
class Document : public ParentNode {
public:
Document();
virtual ~Document() override;
+ virtual RetainPtr create_layout_node() override;
+
+ void build_layout_tree();
+
private:
};
-
diff --git a/LibHTML/Dump.cpp b/LibHTML/Dump.cpp
index 595769fa8f..db50e4ecc2 100644
--- a/LibHTML/Dump.cpp
+++ b/LibHTML/Dump.cpp
@@ -1,10 +1,12 @@
#include
#include
#include
+#include
+#include
#include
#include
-void dump_tree(Node& node)
+void dump_tree(const Node& node)
{
static int indent = 0;
for (int i = 0; i < indent; ++i)
@@ -12,19 +14,35 @@ void dump_tree(Node& node)
if (node.is_document()) {
printf("*Document*\n");
} else if (node.is_element()) {
- printf("<%s", static_cast(node).tag_name().characters());
- static_cast(node).for_each_attribute([](auto& name, auto& value) {
+ printf("<%s", static_cast(node).tag_name().characters());
+ static_cast(node).for_each_attribute([](auto& name, auto& value) {
printf(" %s=%s", name.characters(), value.characters());
});
printf(">\n");
} else if (node.is_text()) {
- printf("\"%s\"\n", static_cast(node).data().characters());
+ printf("\"%s\"\n", static_cast(node).data().characters());
}
++indent;
if (node.is_parent_node()) {
- static_cast(node).for_each_child([](Node& child) {
+ static_cast(node).for_each_child([](auto& child) {
dump_tree(child);
});
}
--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(node).node().data().characters());
+ printf("\n");
+ ++indent;
+ node.for_each_child([](auto& child) {
+ dump_tree(child);
+ });
+ --indent;
+}
diff --git a/LibHTML/Dump.h b/LibHTML/Dump.h
index 09b7de697e..cb5bfe64fb 100644
--- a/LibHTML/Dump.h
+++ b/LibHTML/Dump.h
@@ -1,5 +1,7 @@
#pragma once
class Node;
+class LayoutNode;
-void dump_tree(Node&);
+void dump_tree(const Node&);
+void dump_tree(const LayoutNode&);
diff --git a/LibHTML/Element.cpp b/LibHTML/Element.cpp
index 263774409d..66473fe0c4 100644
--- a/LibHTML/Element.cpp
+++ b/LibHTML/Element.cpp
@@ -1,4 +1,6 @@
#include
+#include
+#include
Element::Element(const String& tag_name)
: ParentNode(NodeType::ELEMENT_NODE)
@@ -47,3 +49,18 @@ void Element::set_attributes(Vector&& attributes)
{
m_attributes = move(attributes);
}
+
+RetainPtr 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;
+}
diff --git a/LibHTML/Element.h b/LibHTML/Element.h
index c21c0f085b..08a87e7233 100644
--- a/LibHTML/Element.h
+++ b/LibHTML/Element.h
@@ -34,12 +34,14 @@ public:
void set_attributes(Vector&&);
template
- void for_each_attribute(Callback callback)
+ void for_each_attribute(Callback callback) const
{
for (auto& attribute : m_attributes)
callback(attribute.name(), attribute.value());
}
+ virtual RetainPtr create_layout_node() override;
+
private:
Attribute* find_attribute(const String& name);
const Attribute* find_attribute(const String& name) const;
diff --git a/LibHTML/LayoutBlock.cpp b/LibHTML/LayoutBlock.cpp
new file mode 100644
index 0000000000..65a94f7d9b
--- /dev/null
+++ b/LibHTML/LayoutBlock.cpp
@@ -0,0 +1,11 @@
+#include
+#include
+
+LayoutBlock::LayoutBlock(Element& element)
+ : LayoutNode(&element)
+{
+}
+
+LayoutBlock::~LayoutBlock()
+{
+}
diff --git a/LibHTML/LayoutBlock.h b/LibHTML/LayoutBlock.h
new file mode 100644
index 0000000000..e953642d67
--- /dev/null
+++ b/LibHTML/LayoutBlock.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include
+
+class Element;
+
+class LayoutBlock : public LayoutNode {
+public:
+ explicit LayoutBlock(Element&);
+ virtual ~LayoutBlock() override;
+
+ virtual const char* class_name() const override { return "LayoutBlock"; }
+
+private:
+};
diff --git a/LibHTML/LayoutDocument.cpp b/LibHTML/LayoutDocument.cpp
new file mode 100644
index 0000000000..738227c604
--- /dev/null
+++ b/LibHTML/LayoutDocument.cpp
@@ -0,0 +1,10 @@
+#include
+
+LayoutDocument::LayoutDocument(const Document& document)
+ : LayoutNode(&document)
+{
+}
+
+LayoutDocument::~LayoutDocument()
+{
+}
diff --git a/LibHTML/LayoutDocument.h b/LibHTML/LayoutDocument.h
new file mode 100644
index 0000000000..3cee3b341e
--- /dev/null
+++ b/LibHTML/LayoutDocument.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+#include
+
+class LayoutDocument : public LayoutNode {
+public:
+ explicit LayoutDocument(const Document&);
+ virtual ~LayoutDocument() override;
+
+ const Document& node() const { return static_cast(*LayoutNode::node()); }
+
+ virtual const char* class_name() const override { return "LayoutDocument"; }
+
+private:
+};
diff --git a/LibHTML/LayoutInline.cpp b/LibHTML/LayoutInline.cpp
new file mode 100644
index 0000000000..bd9c88acde
--- /dev/null
+++ b/LibHTML/LayoutInline.cpp
@@ -0,0 +1,11 @@
+#include
+#include
+
+LayoutInline::LayoutInline(Element& element)
+ : LayoutNode(&element)
+{
+}
+
+LayoutInline::~LayoutInline()
+{
+}
diff --git a/LibHTML/LayoutInline.h b/LibHTML/LayoutInline.h
new file mode 100644
index 0000000000..bb8637aecd
--- /dev/null
+++ b/LibHTML/LayoutInline.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include
+
+class Element;
+
+class LayoutInline : public LayoutNode {
+public:
+ explicit LayoutInline(Element&);
+ virtual ~LayoutInline() override;
+
+ virtual const char* class_name() const override { return "LayoutInline"; }
+
+private:
+};
diff --git a/LibHTML/LayoutNode.cpp b/LibHTML/LayoutNode.cpp
new file mode 100644
index 0000000000..ececf68096
--- /dev/null
+++ b/LibHTML/LayoutNode.cpp
@@ -0,0 +1,33 @@
+#include
+
+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 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;
+}
diff --git a/LibHTML/LayoutNode.h b/LibHTML/LayoutNode.h
new file mode 100644
index 0000000000..cc83db6fd9
--- /dev/null
+++ b/LibHTML/LayoutNode.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include
+#include
+
+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);
+
+ void set_next_sibling(LayoutNode* node) { m_next_sibling = node; }
+ void set_previous_sibling(LayoutNode* node) { m_previous_sibling = node; }
+
+ template
+ 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 };
+};
+
diff --git a/LibHTML/LayoutText.cpp b/LibHTML/LayoutText.cpp
new file mode 100644
index 0000000000..e71c0cd8b4
--- /dev/null
+++ b/LibHTML/LayoutText.cpp
@@ -0,0 +1,10 @@
+#include
+
+LayoutText::LayoutText(const Text& text)
+ : LayoutNode(&text)
+{
+}
+
+LayoutText::~LayoutText()
+{
+}
diff --git a/LibHTML/LayoutText.h b/LibHTML/LayoutText.h
new file mode 100644
index 0000000000..42127c0778
--- /dev/null
+++ b/LibHTML/LayoutText.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+#include
+
+class LayoutText : public LayoutNode {
+public:
+ explicit LayoutText(const Text&);
+ virtual ~LayoutText() override;
+
+ const Text& node() const { return static_cast(*LayoutNode::node()); }
+
+ virtual const char* class_name() const override { return "LayoutText"; }
+ virtual bool is_text() const final { return true; }
+
+private:
+};
diff --git a/LibHTML/Makefile b/LibHTML/Makefile
index ca947be04f..66b48fd839 100644
--- a/LibHTML/Makefile
+++ b/LibHTML/Makefile
@@ -7,6 +7,11 @@ LIBHTML_OBJS = \
Document.o \
Text.o \
Parser.o \
+ LayoutNode.o \
+ LayoutText.o \
+ LayoutBlock.o \
+ LayoutInline.o \
+ LayoutDocument.o \
Dump.o
TEST_OBJS = test.o
diff --git a/LibHTML/Node.cpp b/LibHTML/Node.cpp
index 961699d554..b7c4e3747d 100644
--- a/LibHTML/Node.cpp
+++ b/LibHTML/Node.cpp
@@ -1,5 +1,5 @@
-#include
#include
+#include
Node::Node(NodeType type)
: m_type(type)
@@ -22,3 +22,13 @@ void Node::release()
if (!--m_retain_count)
delete this;
}
+
+RetainPtr Node::create_layout_node()
+{
+ return nullptr;
+}
+
+void Node::set_layout_node(Retained layout_node)
+{
+ m_layout_node = move(layout_node);
+}
diff --git a/LibHTML/Node.h b/LibHTML/Node.h
index 3650782929..3867bddbac 100644
--- a/LibHTML/Node.h
+++ b/LibHTML/Node.h
@@ -1,6 +1,7 @@
#pragma once
-#include
+#include
+#include
#include
enum class NodeType : unsigned {
@@ -10,6 +11,9 @@ enum class NodeType : unsigned {
DOCUMENT_NODE = 9,
};
+class LayoutNode;
+class ParentNode;
+
class Node {
public:
virtual ~Node();
@@ -18,6 +22,11 @@ public:
void release();
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* parent_node) { m_parent_node = parent_node; }
+
NodeType type() const { return m_type; }
bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
bool is_text() const { return type() == NodeType::TEXT_NODE; }
@@ -26,16 +35,26 @@ public:
Node* next_sibling() { return m_next_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_previous_sibling(Node* node) { m_previous_sibling = node; }
+ virtual RetainPtr create_layout_node();
+
+ const LayoutNode* layout_node() const { return m_layout_node; }
+ LayoutNode* layout_node() { return m_layout_node; }
+
+ void set_layout_node(Retained);
+
protected:
explicit Node(NodeType);
int m_retain_count { 1 };
NodeType m_type { NodeType::INVALID };
- Vector m_children;
+ ParentNode* m_parent_node { nullptr };
Node* m_next_sibling { nullptr };
Node* m_previous_sibling { nullptr };
+ RetainPtr m_layout_node;
};
-
diff --git a/LibHTML/ParentNode.cpp b/LibHTML/ParentNode.cpp
index d241032375..23c46692e7 100644
--- a/LibHTML/ParentNode.cpp
+++ b/LibHTML/ParentNode.cpp
@@ -4,6 +4,7 @@ void ParentNode::append_child(Retained node)
{
if (m_last_child)
m_last_child->set_next_sibling(node.ptr());
+ node->set_parent_node({}, this);
m_last_child = &node.leak_ref();
if (!m_first_child)
m_first_child = m_last_child;
diff --git a/LibHTML/ParentNode.h b/LibHTML/ParentNode.h
index 357315e3d7..a28ef494ba 100644
--- a/LibHTML/ParentNode.h
+++ b/LibHTML/ParentNode.h
@@ -8,7 +8,10 @@ public:
Node* first_child() { return m_first_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 void for_each_child(F) const;
template void for_each_child(F);
protected:
@@ -22,11 +25,16 @@ private:
Node* m_last_child { nullptr };
};
-template
-inline void ParentNode::for_each_child(F func)
+template
+inline void ParentNode::for_each_child(Callback callback) const
{
- for (auto* node = first_child(); node; node = node->next_sibling()) {
- func(*node);
- }
+ for (auto* node = first_child(); node; node = node->next_sibling())
+ callback(*node);
}
+template
+inline void ParentNode::for_each_child(Callback callback)
+{
+ for (auto* node = first_child(); node; node = node->next_sibling())
+ callback(*node);
+}
diff --git a/LibHTML/Text.cpp b/LibHTML/Text.cpp
index 67ec381f73..c21a0f54b0 100644
--- a/LibHTML/Text.cpp
+++ b/LibHTML/Text.cpp
@@ -1,4 +1,5 @@
#include
+#include
Text::Text(const String& data)
: Node(NodeType::TEXT_NODE)
@@ -10,4 +11,7 @@ Text::~Text()
{
}
-
+RetainPtr Text::create_layout_node()
+{
+ return adopt(*new LayoutText(*this));
+}
diff --git a/LibHTML/Text.h b/LibHTML/Text.h
index bdc9f86ec2..76e7d7bca4 100644
--- a/LibHTML/Text.h
+++ b/LibHTML/Text.h
@@ -10,6 +10,8 @@ public:
const String& data() const { return m_data; }
+ virtual RetainPtr create_layout_node() override;
+
private:
String m_data;
};
diff --git a/LibHTML/test.cpp b/LibHTML/test.cpp
index ebeda969e6..7e55b5a869 100644
--- a/LibHTML/test.cpp
+++ b/LibHTML/test.cpp
@@ -14,5 +14,9 @@ int main(int argc, char** argv)
String html = String::copy(f.read_all());
auto doc = parse(html);
dump_tree(doc);
+
+ doc->build_layout_tree();
+ ASSERT(doc->layout_node());
+ dump_tree(*doc->layout_node());
return 0;
}