Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/Badge.h>
30#include <AK/RefPtr.h>
31#include <AK/String.h>
32#include <AK/Vector.h>
33#include <LibHTML/TreeNode.h>
34
35enum class NodeType : unsigned {
36 INVALID = 0,
37 ELEMENT_NODE = 1,
38 TEXT_NODE = 3,
39 COMMENT_NODE = 8,
40 DOCUMENT_NODE = 9,
41 DOCUMENT_TYPE_NODE = 10,
42 DOCUMENT_FRAGMENT_NODE = 11,
43};
44
45class Document;
46class Element;
47class HTMLElement;
48class HTMLAnchorElement;
49class ParentNode;
50class LayoutNode;
51class StyleResolver;
52class StyleProperties;
53
54class Node : public TreeNode<Node> {
55public:
56 virtual ~Node();
57
58 NodeType type() const { return m_type; }
59 bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
60 bool is_text() const { return type() == NodeType::TEXT_NODE; }
61 bool is_document() const { return type() == NodeType::DOCUMENT_NODE; }
62 bool is_document_type() const { return type() == NodeType::DOCUMENT_TYPE_NODE; }
63 bool is_comment() const { return type() == NodeType::COMMENT_NODE; }
64 bool is_character_data() const { return type() == NodeType::TEXT_NODE || type() == NodeType::COMMENT_NODE; }
65 bool is_document_fragment() const { return type() == NodeType::DOCUMENT_FRAGMENT_NODE; }
66 bool is_parent_node() const { return is_element() || is_document(); }
67
68 virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const;
69
70 virtual String tag_name() const = 0;
71
72 virtual String text_content() const;
73
74 Document& document() { return m_document; }
75 const Document& document() const { return m_document; }
76
77 const HTMLAnchorElement* enclosing_link_element() const;
78 const HTMLElement* enclosing_html_element() const;
79
80 virtual bool is_html_element() const { return false; }
81
82 template<typename T>
83 const T* first_child_of_type() const;
84
85 template<typename T>
86 const T* first_ancestor_of_type() const;
87
88 virtual void inserted_into(Node&) {}
89 virtual void removed_from(Node&) {}
90
91 const LayoutNode* layout_node() const { return m_layout_node; }
92 LayoutNode* layout_node() { return m_layout_node; }
93
94 void set_layout_node(Badge<LayoutNode>, LayoutNode* layout_node) const { m_layout_node = layout_node; }
95
96 const Element* previous_element_sibling() const;
97 const Element* next_element_sibling() const;
98
99 virtual bool is_child_allowed(const Node&) const { return true; }
100
101 bool needs_style_update() const { return m_needs_style_update; }
102 void set_needs_style_update(bool value) { m_needs_style_update = value; }
103
104 void invalidate_style();
105
106 bool is_link() const;
107
108protected:
109 Node(Document&, NodeType);
110
111 Document& m_document;
112 mutable LayoutNode* m_layout_node { nullptr };
113 NodeType m_type { NodeType::INVALID };
114 bool m_needs_style_update { false };
115};
116
117template<typename T>
118inline bool is(const Node&)
119{
120 return false;
121}
122
123template<typename T>
124inline bool is(const Node* node)
125{
126 return !node || is<T>(*node);
127}
128
129template<>
130inline bool is<Node>(const Node&)
131{
132 return true;
133}
134
135template<>
136inline bool is<ParentNode>(const Node& node)
137{
138 return node.is_parent_node();
139}
140
141template<typename T>
142inline const T& to(const Node& node)
143{
144 ASSERT(is<T>(node));
145 return static_cast<const T&>(node);
146}
147
148template<typename T>
149inline T* to(Node* node)
150{
151 ASSERT(is<T>(node));
152 return static_cast<T*>(node);
153}
154
155template<typename T>
156inline const T* to(const Node* node)
157{
158 ASSERT(is<T>(node));
159 return static_cast<const T*>(node);
160}
161
162template<typename T>
163inline T& to(Node& node)
164{
165 ASSERT(is<T>(node));
166 return static_cast<T&>(node);
167}
168
169template<typename T>
170inline const T* Node::first_child_of_type() const
171{
172 for (auto* child = first_child(); child; child = child->next_sibling()) {
173 if (is<T>(*child))
174 return to<T>(child);
175 }
176 return nullptr;
177}
178
179template<typename T>
180inline const T* Node::first_ancestor_of_type() const
181{
182 for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
183 if (is<T>(*ancestor))
184 return to<T>(ancestor);
185 }
186 return nullptr;
187}