Browse Source

LibHTML: Templatize Node::first_child_of_type<T>()

This is a lot nicer than first_child_with_tag_name(...).

The is<T>(Node) functions are obviously unoptimized at the moment,
and this is about establishing pleasant patterns right now. :^)
Andreas Kling 5 years ago
parent
commit
3bee9d3d3c

+ 4 - 4
Libraries/LibHTML/DOM/Document.cpp

@@ -41,7 +41,7 @@ void Document::normalize()
 
 const HTMLHtmlElement* Document::document_element() const
 {
-    return static_cast<const HTMLHtmlElement*>(first_child_with_tag_name("html"));
+    return first_child_of_type<HTMLHtmlElement>();
 }
 
 const HTMLHeadElement* Document::head() const
@@ -49,7 +49,7 @@ const HTMLHeadElement* Document::head() const
     auto* html = document_element();
     if (!html)
         return nullptr;
-    return static_cast<const HTMLHeadElement*>(html->first_child_with_tag_name("head"));
+    return html->first_child_of_type<HTMLHeadElement>();
 }
 
 const HTMLBodyElement* Document::body() const
@@ -57,7 +57,7 @@ const HTMLBodyElement* Document::body() const
     auto* html = document_element();
     if (!html)
         return nullptr;
-    return static_cast<const HTMLBodyElement*>(html->first_child_with_tag_name("body"));
+    return html->first_child_of_type<HTMLBodyElement>();
 }
 
 String Document::title() const
@@ -66,7 +66,7 @@ String Document::title() const
     if (!head_element)
         return {};
 
-    auto* title_element = static_cast<const HTMLTitleElement*>(head_element->first_child_with_tag_name("title"));
+    auto* title_element = head_element->first_child_of_type<HTMLTitleElement>();
     if (!title_element)
         return {};
 

+ 6 - 0
Libraries/LibHTML/DOM/HTMLBodyElement.h

@@ -10,3 +10,9 @@ public:
     virtual void parse_attribute(const String&, const String&) override;
     virtual void apply_presentational_hints(StyleProperties&) const override;
 };
+
+template<>
+inline bool is<HTMLBodyElement>(const Node& node)
+{
+    return is<Element>(node) && to<Element>(node).tag_name().to_lowercase() == "body";
+}

+ 6 - 0
Libraries/LibHTML/DOM/HTMLHeadElement.h

@@ -7,3 +7,9 @@ public:
     HTMLHeadElement(Document&, const String& tag_name);
     virtual ~HTMLHeadElement() override;
 };
+
+template<>
+inline bool is<HTMLHeadElement>(const Node& node)
+{
+    return is<Element>(node) && to<Element>(node).tag_name().to_lowercase() == "head";
+}

+ 6 - 0
Libraries/LibHTML/DOM/HTMLTitleElement.h

@@ -7,3 +7,9 @@ public:
     HTMLTitleElement(Document&, const String& tag_name);
     virtual ~HTMLTitleElement() override;
 };
+
+template<>
+inline bool is<HTMLTitleElement>(const Node& node)
+{
+    return is<Element>(node) && to<Element>(node).tag_name().to_lowercase() == "title";
+}

+ 26 - 8
Libraries/LibHTML/DOM/Node.h

@@ -47,14 +47,8 @@ public:
 
     virtual bool is_html_element() const { return false; }
 
-    const Node* first_child_with_tag_name(const StringView& tag_name) const
-    {
-        for (auto* child = first_child(); child; child = child->next_sibling()) {
-            if (child->tag_name() == tag_name)
-                return child;
-        }
-        return nullptr;
-    }
+    template<typename T>
+    const T* first_child_of_type() const;
 
     virtual void inserted_into(Node&) {}
     virtual void removed_from(Node&) {}
@@ -106,9 +100,33 @@ inline const T& to(const Node& node)
     return static_cast<const T&>(node);
 }
 
+template<typename T>
+inline T* to(Node* node)
+{
+    ASSERT(is<T>(node));
+    return static_cast<T*>(node);
+}
+
+template<typename T>
+inline const T* to(const Node* node)
+{
+    ASSERT(is<T>(node));
+    return static_cast<const T*>(node);
+}
+
 template<typename T>
 inline T& to(Node& node)
 {
     ASSERT(is<T>(node));
     return static_cast<T&>(node);
 }
+
+template<typename T>
+inline const T* Node::first_child_of_type() const
+{
+    for (auto* child = first_child(); child; child = child->next_sibling()) {
+        if (is<T>(*child))
+            return to<T>(child);
+    }
+    return nullptr;
+}