summaryrefslogtreecommitdiff
path: root/Libraries/LibHTML
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-10-09 20:17:01 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-10-09 20:17:01 +0200
commitfc5386793708b7d5d1694f2914b1f62326f74ebd (patch)
tree3985c9c2ef5f8e5976131e76a98894bd3f82f306 /Libraries/LibHTML
parent850955053f55a97f932976783db8e7b2f19ee5f1 (diff)
downloadserenity-fc5386793708b7d5d1694f2914b1f62326f74ebd.zip
LibHTML: Add basic <!DOCTYPE> parsing and a DocumentType class
Plus, Document::fixup() will now make sure that the document always starts with a doctype node, followed by an <html> element.
Diffstat (limited to 'Libraries/LibHTML')
-rw-r--r--Libraries/LibHTML/DOM/Document.cpp10
-rw-r--r--Libraries/LibHTML/DOM/DocumentType.cpp10
-rw-r--r--Libraries/LibHTML/DOM/DocumentType.h17
-rw-r--r--Libraries/LibHTML/DOM/Node.cpp5
-rw-r--r--Libraries/LibHTML/DOM/Node.h4
-rw-r--r--Libraries/LibHTML/Dump.cpp3
-rw-r--r--Libraries/LibHTML/Makefile.shared1
-rw-r--r--Libraries/LibHTML/Parser/HTMLParser.cpp23
-rw-r--r--Libraries/LibHTML/TreeNode.h17
9 files changed, 84 insertions, 6 deletions
diff --git a/Libraries/LibHTML/DOM/Document.cpp b/Libraries/LibHTML/DOM/Document.cpp
index 5181d2da9b..fd6b5a1cd3 100644
--- a/Libraries/LibHTML/DOM/Document.cpp
+++ b/Libraries/LibHTML/DOM/Document.cpp
@@ -2,6 +2,7 @@
#include <AK/StringBuilder.h>
#include <LibHTML/CSS/StyleResolver.h>
#include <LibHTML/DOM/Document.h>
+#include <LibHTML/DOM/DocumentType.h>
#include <LibHTML/DOM/Element.h>
#include <LibHTML/DOM/HTMLBodyElement.h>
#include <LibHTML/DOM/HTMLHeadElement.h>
@@ -29,11 +30,14 @@ StyleResolver& Document::style_resolver()
void Document::fixup()
{
- if (is<HTMLHtmlElement>(first_child()))
+ if (!is<DocumentType>(first_child()))
+ prepend_child(adopt(*new DocumentType(*this)));
+
+ if (is<HTMLHtmlElement>(first_child()->next_sibling()))
return;
- NonnullRefPtr<Element> body = adopt(*new Element(*this, "body"));
- NonnullRefPtr<Element> html = adopt(*new Element(*this, "html"));
+ auto body = adopt(*new HTMLBodyElement(*this, "body"));
+ auto html = adopt(*new HTMLHtmlElement(*this, "html"));
html->append_child(body);
this->donate_all_children_to(body);
this->append_child(html);
diff --git a/Libraries/LibHTML/DOM/DocumentType.cpp b/Libraries/LibHTML/DOM/DocumentType.cpp
new file mode 100644
index 0000000000..7f7da8e599
--- /dev/null
+++ b/Libraries/LibHTML/DOM/DocumentType.cpp
@@ -0,0 +1,10 @@
+#include <LibHTML/DOM/DocumentType.h>
+
+DocumentType::DocumentType(Document& document)
+ : Node(document, NodeType::DOCUMENT_TYPE_NODE)
+{
+}
+
+DocumentType::~DocumentType()
+{
+}
diff --git a/Libraries/LibHTML/DOM/DocumentType.h b/Libraries/LibHTML/DOM/DocumentType.h
new file mode 100644
index 0000000000..c13bb5cbee
--- /dev/null
+++ b/Libraries/LibHTML/DOM/DocumentType.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <LibHTML/DOM/Node.h>
+
+class DocumentType final : public Node {
+public:
+ explicit DocumentType(Document&);
+ virtual ~DocumentType() override;
+
+ virtual String tag_name() const override { return "!DOCTYPE"; }
+};
+
+template<>
+inline bool is<DocumentType>(const Node& node)
+{
+ return node.type() == NodeType::DOCUMENT_TYPE_NODE;
+}
diff --git a/Libraries/LibHTML/DOM/Node.cpp b/Libraries/LibHTML/DOM/Node.cpp
index af590b39b4..14c7a38a29 100644
--- a/Libraries/LibHTML/DOM/Node.cpp
+++ b/Libraries/LibHTML/DOM/Node.cpp
@@ -97,3 +97,8 @@ const Element* Node::previous_element_sibling() const
}
return nullptr;
}
+
+RefPtr<LayoutNode> Node::create_layout_node(const StyleResolver&, const StyleProperties*) const
+{
+ return nullptr;
+}
diff --git a/Libraries/LibHTML/DOM/Node.h b/Libraries/LibHTML/DOM/Node.h
index 68f24b4c6f..132bbcd63a 100644
--- a/Libraries/LibHTML/DOM/Node.h
+++ b/Libraries/LibHTML/DOM/Node.h
@@ -11,6 +11,7 @@ enum class NodeType : unsigned {
ELEMENT_NODE = 1,
TEXT_NODE = 3,
DOCUMENT_NODE = 9,
+ DOCUMENT_TYPE_NODE = 10,
};
class Document;
@@ -30,9 +31,10 @@ public:
bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
bool is_text() const { return type() == NodeType::TEXT_NODE; }
bool is_document() const { return type() == NodeType::DOCUMENT_NODE; }
+ bool is_document_type() const { return type() == NodeType::DOCUMENT_TYPE_NODE; }
bool is_parent_node() const { return is_element() || is_document(); }
- virtual RefPtr<LayoutNode> create_layout_node(const StyleResolver&, const StyleProperties* parent_style) const = 0;
+ virtual RefPtr<LayoutNode> create_layout_node(const StyleResolver&, const StyleProperties* parent_style) const;
RefPtr<LayoutNode> create_layout_tree(const StyleResolver&, const StyleProperties* parent_style) const;
virtual String tag_name() const = 0;
diff --git a/Libraries/LibHTML/Dump.cpp b/Libraries/LibHTML/Dump.cpp
index 82458f44b0..6533b58774 100644
--- a/Libraries/LibHTML/Dump.cpp
+++ b/Libraries/LibHTML/Dump.cpp
@@ -1,6 +1,7 @@
#include <AK/Utf8View.h>
#include <LibHTML/CSS/StyleSheet.h>
#include <LibHTML/DOM/Document.h>
+#include <LibHTML/DOM/DocumentType.h>
#include <LibHTML/DOM/Element.h>
#include <LibHTML/DOM/Text.h>
#include <LibHTML/Dump.h>
@@ -24,6 +25,8 @@ void dump_tree(const Node& node)
dbgprintf(">\n");
} else if (is<Text>(node)) {
dbgprintf("\"%s\"\n", static_cast<const Text&>(node).data().characters());
+ } else if (is<DocumentType>(node)) {
+ dbgprintf("<!DOCTYPE>\n");
}
++indent;
if (is<ParentNode>(node)) {
diff --git a/Libraries/LibHTML/Makefile.shared b/Libraries/LibHTML/Makefile.shared
index 8b59ee68bf..e4b772c1cf 100644
--- a/Libraries/LibHTML/Makefile.shared
+++ b/Libraries/LibHTML/Makefile.shared
@@ -16,6 +16,7 @@ LIBHTML_OBJS = \
DOM/HTMLLinkElement.o \
DOM/Document.o \
DOM/Text.o \
+ DOM/DocumentType.o \
CSS/Selector.o \
CSS/StyleSheet.o \
CSS/StyleRule.o \
diff --git a/Libraries/LibHTML/Parser/HTMLParser.cpp b/Libraries/LibHTML/Parser/HTMLParser.cpp
index 981f182702..22618796c3 100644
--- a/Libraries/LibHTML/Parser/HTMLParser.cpp
+++ b/Libraries/LibHTML/Parser/HTMLParser.cpp
@@ -1,6 +1,7 @@
#include <AK/Function.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/StringBuilder.h>
+#include <LibHTML/DOM/DocumentType.h>
#include <LibHTML/DOM/Element.h>
#include <LibHTML/DOM/HTMLAnchorElement.h>
#include <LibHTML/DOM/HTMLBodyElement.h>
@@ -10,9 +11,9 @@
#include <LibHTML/DOM/HTMLHeadingElement.h>
#include <LibHTML/DOM/HTMLHtmlElement.h>
#include <LibHTML/DOM/HTMLImageElement.h>
+#include <LibHTML/DOM/HTMLLinkElement.h>
#include <LibHTML/DOM/HTMLStyleElement.h>
#include <LibHTML/DOM/HTMLTitleElement.h>
-#include <LibHTML/DOM/HTMLLinkElement.h>
#include <LibHTML/DOM/Text.h>
#include <LibHTML/Parser/HTMLParser.h>
#include <ctype.h>
@@ -106,10 +107,12 @@ NonnullRefPtr<Document> parse_html(const StringView& html, const URL& url)
Vector<char, 256> attribute_value_buffer;
bool is_slash_tag = false;
+ bool is_exclamation_tag = false;
auto move_to_state = [&](State new_state) {
if (new_state == State::BeforeTagName) {
is_slash_tag = false;
+ is_exclamation_tag = false;
tag_name_buffer.clear();
attributes.clear();
}
@@ -142,8 +145,19 @@ NonnullRefPtr<Document> parse_html(const StringView& html, const URL& url)
close_tag();
};
+ auto handle_exclamation_tag = [&] {
+ auto name = String::copy(tag_name_buffer);
+ tag_name_buffer.clear();
+ ASSERT(name == "DOCTYPE");
+ if (node_stack.size() != 1)
+ node_stack[node_stack.size() - 2].append_child(adopt(*new DocumentType(document)), false);
+ close_tag();
+ };
+
auto commit_tag = [&] {
- if (is_slash_tag)
+ if (is_exclamation_tag)
+ handle_exclamation_tag();
+ else if (is_slash_tag)
close_tag();
else
open_tag();
@@ -159,6 +173,7 @@ NonnullRefPtr<Document> parse_html(const StringView& html, const URL& url)
case State::Free:
if (ch == '<') {
is_slash_tag = false;
+ is_exclamation_tag = false;
move_to_state(State::BeforeTagName);
break;
}
@@ -193,6 +208,10 @@ NonnullRefPtr<Document> parse_html(const StringView& html, const URL& url)
is_slash_tag = true;
break;
}
+ if (ch == '!') {
+ is_exclamation_tag = true;
+ break;
+ }
if (ch == '>') {
move_to_state(State::Free);
break;
diff --git a/Libraries/LibHTML/TreeNode.h b/Libraries/LibHTML/TreeNode.h
index 36459c5c77..467ab83cfb 100644
--- a/Libraries/LibHTML/TreeNode.h
+++ b/Libraries/LibHTML/TreeNode.h
@@ -33,6 +33,7 @@ public:
const T* first_child() const { return m_first_child; }
const T* last_child() const { return m_last_child; }
+ void prepend_child(NonnullRefPtr<T> node, bool call_inserted_into = true);
void append_child(NonnullRefPtr<T> node, bool call_inserted_into = true);
void donate_all_children_to(T& node);
@@ -65,6 +66,22 @@ inline void TreeNode<T>::append_child(NonnullRefPtr<T> node, bool call_inserted_
}
template<typename T>
+inline void TreeNode<T>::prepend_child(NonnullRefPtr<T> node, bool call_inserted_into)
+{
+ ASSERT(!node->m_parent);
+ if (m_first_child)
+ m_first_child->m_previous_sibling = node.ptr();
+ node->m_next_sibling = m_first_child;
+ node->m_parent = static_cast<T*>(this);
+ m_first_child = node.ptr();
+ if (!m_last_child)
+ m_last_child = m_first_child;
+ if (call_inserted_into)
+ node->inserted_into(static_cast<T&>(*this));
+ (void)node.leak_ref();
+}
+
+template<typename T>
inline void TreeNode<T>::donate_all_children_to(T& node)
{
for (T* child = m_first_child; child != nullptr;) {