diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-10-09 20:17:01 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-10-09 20:17:01 +0200 |
commit | fc5386793708b7d5d1694f2914b1f62326f74ebd (patch) | |
tree | 3985c9c2ef5f8e5976131e76a98894bd3f82f306 /Libraries/LibHTML | |
parent | 850955053f55a97f932976783db8e7b2f19ee5f1 (diff) | |
download | serenity-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.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibHTML/DOM/DocumentType.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibHTML/DOM/DocumentType.h | 17 | ||||
-rw-r--r-- | Libraries/LibHTML/DOM/Node.cpp | 5 | ||||
-rw-r--r-- | Libraries/LibHTML/DOM/Node.h | 4 | ||||
-rw-r--r-- | Libraries/LibHTML/Dump.cpp | 3 | ||||
-rw-r--r-- | Libraries/LibHTML/Makefile.shared | 1 | ||||
-rw-r--r-- | Libraries/LibHTML/Parser/HTMLParser.cpp | 23 | ||||
-rw-r--r-- | Libraries/LibHTML/TreeNode.h | 17 |
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;) { |