diff --git a/Libraries/LibHTML/CSS/StyleResolver.cpp b/Libraries/LibHTML/CSS/StyleResolver.cpp
index e9cc8356a2..28dd0f2534 100644
--- a/Libraries/LibHTML/CSS/StyleResolver.cpp
+++ b/Libraries/LibHTML/CSS/StyleResolver.cpp
@@ -40,17 +40,17 @@ static bool matches(const Selector& selector, int component_index, const Element
case Selector::Component::Relation::Descendant:
ASSERT(component_index != 0);
for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) {
- if (!ancestor->is_element())
+ if (!is(*ancestor))
continue;
- if (matches(selector, component_index - 1, static_cast(*ancestor)))
+ if (matches(selector, component_index - 1, to(*ancestor)))
return true;
}
return false;
case Selector::Component::Relation::ImmediateChild:
ASSERT(component_index != 0);
- if (!element.parent() || !element.parent()->is_element())
+ if (!element.parent() || !is(*element.parent()))
return false;
- return matches(selector, component_index - 1, static_cast(*element.parent()));
+ return matches(selector, component_index - 1, to(*element.parent()));
case Selector::Component::Relation::AdjacentSibling:
ASSERT(component_index != 0);
if (auto* sibling = element.previous_element_sibling())
diff --git a/Libraries/LibHTML/DOM/Document.cpp b/Libraries/LibHTML/DOM/Document.cpp
index 5ba2665d65..0f8b1053ab 100644
--- a/Libraries/LibHTML/DOM/Document.cpp
+++ b/Libraries/LibHTML/DOM/Document.cpp
@@ -29,11 +29,8 @@ StyleResolver& Document::style_resolver()
void Document::normalize()
{
- if (first_child() != nullptr && first_child()->is_element()) {
- const Element& el = static_cast(*first_child());
- if (el.tag_name() == "html")
- return;
- }
+ if (is(first_child()))
+ return;
NonnullRefPtr body = adopt(*new Element(*this, "body"));
NonnullRefPtr html = adopt(*new Element(*this, "html"));
diff --git a/Libraries/LibHTML/DOM/Document.h b/Libraries/LibHTML/DOM/Document.h
index 00a3024b6f..1c54caae77 100644
--- a/Libraries/LibHTML/DOM/Document.h
+++ b/Libraries/LibHTML/DOM/Document.h
@@ -80,3 +80,9 @@ private:
Color m_active_link_color { Color::Red };
Color m_visited_link_color { Color::Magenta };
};
+
+template<>
+inline bool is(const Node& node)
+{
+ return node.is_document();
+}
diff --git a/Libraries/LibHTML/DOM/Element.h b/Libraries/LibHTML/DOM/Element.h
index d6641e5496..2b0027d2e3 100644
--- a/Libraries/LibHTML/DOM/Element.h
+++ b/Libraries/LibHTML/DOM/Element.h
@@ -26,7 +26,7 @@ public:
Element(Document&, const String& tag_name);
virtual ~Element() override;
- virtual String tag_name() const override { return m_tag_name; }
+ virtual String tag_name() const final { return m_tag_name; }
String attribute(const String& name) const;
void set_attribute(const String& name, const String& value);
@@ -54,3 +54,9 @@ private:
String m_tag_name;
Vector m_attributes;
};
+
+template<>
+inline bool is(const Node& node)
+{
+ return node.is_element();
+}
diff --git a/Libraries/LibHTML/DOM/HTMLAnchorElement.h b/Libraries/LibHTML/DOM/HTMLAnchorElement.h
index 588e89ca28..f5b3104a09 100644
--- a/Libraries/LibHTML/DOM/HTMLAnchorElement.h
+++ b/Libraries/LibHTML/DOM/HTMLAnchorElement.h
@@ -9,3 +9,9 @@ public:
String href() const { return attribute("href"); }
};
+
+template<>
+inline bool is(const Node& node)
+{
+ return is(node) && to(node).tag_name().to_lowercase() == "a";
+}
diff --git a/Libraries/LibHTML/DOM/HTMLElement.h b/Libraries/LibHTML/DOM/HTMLElement.h
index a366eb9ea0..0c8a324895 100644
--- a/Libraries/LibHTML/DOM/HTMLElement.h
+++ b/Libraries/LibHTML/DOM/HTMLElement.h
@@ -12,3 +12,9 @@ public:
private:
virtual bool is_html_element() const final { return true; }
};
+
+template<>
+inline bool is(const Node& node)
+{
+ return node.is_html_element();
+}
diff --git a/Libraries/LibHTML/DOM/HTMLHtmlElement.h b/Libraries/LibHTML/DOM/HTMLHtmlElement.h
index 4ab5b78af6..d750717635 100644
--- a/Libraries/LibHTML/DOM/HTMLHtmlElement.h
+++ b/Libraries/LibHTML/DOM/HTMLHtmlElement.h
@@ -7,3 +7,9 @@ public:
HTMLHtmlElement(Document&, const String& tag_name);
virtual ~HTMLHtmlElement() override;
};
+
+template<>
+inline bool is(const Node& node)
+{
+ return is(node) && to(node).tag_name().to_lowercase() == "html";
+}
diff --git a/Libraries/LibHTML/DOM/Node.cpp b/Libraries/LibHTML/DOM/Node.cpp
index ca9f874780..d1b70fe1cd 100644
--- a/Libraries/LibHTML/DOM/Node.cpp
+++ b/Libraries/LibHTML/DOM/Node.cpp
@@ -56,7 +56,7 @@ RefPtr Node::create_layout_tree(const StyleResolver& resolver, const
const HTMLAnchorElement* Node::enclosing_link_element() const
{
- if (is_element() && tag_name().to_lowercase() == "a")
+ if (is(*this))
return static_cast(this);
return parent() ? parent()->enclosing_link_element() : nullptr;
}
diff --git a/Libraries/LibHTML/DOM/Node.h b/Libraries/LibHTML/DOM/Node.h
index e9771eeb99..6a9208dd68 100644
--- a/Libraries/LibHTML/DOM/Node.h
+++ b/Libraries/LibHTML/DOM/Node.h
@@ -74,3 +74,41 @@ protected:
mutable LayoutNode* m_layout_node { nullptr };
NodeType m_type { NodeType::INVALID };
};
+
+template
+inline bool is(const Node&)
+{
+ return false;
+}
+
+template
+inline bool is(const Node* node)
+{
+ return node && is(*node);
+}
+
+template<>
+inline bool is(const Node&)
+{
+ return true;
+}
+
+template<>
+inline bool is(const Node& node)
+{
+ return node.is_parent_node();
+}
+
+template
+inline const T& to(const Node& node)
+{
+ ASSERT(is(node));
+ return static_cast(node);
+}
+
+template
+inline T& to(Node& node)
+{
+ ASSERT(is(node));
+ return static_cast(node);
+}
diff --git a/Libraries/LibHTML/DOM/Text.h b/Libraries/LibHTML/DOM/Text.h
index 46e29ba0c6..b7b55f1f70 100644
--- a/Libraries/LibHTML/DOM/Text.h
+++ b/Libraries/LibHTML/DOM/Text.h
@@ -19,3 +19,9 @@ private:
String m_data;
};
+
+template<>
+inline bool is(const Node& node)
+{
+ return node.is_text();
+}
diff --git a/Libraries/LibHTML/Dump.cpp b/Libraries/LibHTML/Dump.cpp
index 0919263ae7..62619de074 100644
--- a/Libraries/LibHTML/Dump.cpp
+++ b/Libraries/LibHTML/Dump.cpp
@@ -14,19 +14,19 @@ void dump_tree(const Node& node)
static int indent = 0;
for (int i = 0; i < indent; ++i)
dbgprintf(" ");
- if (node.is_document()) {
+ if (is(node)) {
dbgprintf("*Document*\n");
- } else if (node.is_element()) {
- dbgprintf("<%s", static_cast(node).tag_name().characters());
- static_cast(node).for_each_attribute([](auto& name, auto& value) {
+ } else if (is(node)) {
+ dbgprintf("<%s", to(node).tag_name().characters());
+ to(node).for_each_attribute([](auto& name, auto& value) {
dbgprintf(" %s=%s", name.characters(), value.characters());
});
dbgprintf(">\n");
- } else if (node.is_text()) {
+ } else if (is(node)) {
dbgprintf("\"%s\"\n", static_cast(node).data().characters());
}
++indent;
- if (node.is_parent_node()) {
+ if (is(node)) {
static_cast(node).for_each_child([](auto& child) {
dump_tree(child);
});
@@ -43,12 +43,12 @@ void dump_tree(const LayoutNode& layout_node)
String tag_name;
if (layout_node.is_anonymous())
tag_name = "(anonymous)";
- else if (layout_node.node()->is_text())
+ else if (is(layout_node.node()))
tag_name = "#text";
- else if (layout_node.node()->is_document())
+ else if (is(layout_node.node()))
tag_name = "#document";
- else if (layout_node.node()->is_element())
- tag_name = static_cast(*layout_node.node()).tag_name();
+ else if (is(layout_node.node()))
+ tag_name = to(*layout_node.node()).tag_name();
else
tag_name = "???";
diff --git a/Libraries/LibHTML/Layout/LayoutReplaced.h b/Libraries/LibHTML/Layout/LayoutReplaced.h
index 0d76b7352b..c76fc3b930 100644
--- a/Libraries/LibHTML/Layout/LayoutReplaced.h
+++ b/Libraries/LibHTML/Layout/LayoutReplaced.h
@@ -6,7 +6,7 @@ public:
LayoutReplaced(const Element&, NonnullRefPtr);
virtual ~LayoutReplaced() override;
- const Element& node() const { return static_cast(*LayoutNode::node()); }
+ const Element& node() const { return to(*LayoutNode::node()); }
virtual bool is_replaced() const final { return true; }