mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 10:22:05 -05:00
LibHTML: Add is<ElementType> and to<ElementType> helper functions
These will help us write node-type-aware template functions.
This commit is contained in:
parent
bedb00603c
commit
f52f2736e1
12 changed files with 93 additions and 22 deletions
|
@ -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<Element>(*ancestor))
|
||||
continue;
|
||||
if (matches(selector, component_index - 1, static_cast<const Element&>(*ancestor)))
|
||||
if (matches(selector, component_index - 1, to<Element>(*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>(*element.parent()))
|
||||
return false;
|
||||
return matches(selector, component_index - 1, static_cast<const Element&>(*element.parent()));
|
||||
return matches(selector, component_index - 1, to<Element>(*element.parent()));
|
||||
case Selector::Component::Relation::AdjacentSibling:
|
||||
ASSERT(component_index != 0);
|
||||
if (auto* sibling = element.previous_element_sibling())
|
||||
|
|
|
@ -29,11 +29,8 @@ StyleResolver& Document::style_resolver()
|
|||
|
||||
void Document::normalize()
|
||||
{
|
||||
if (first_child() != nullptr && first_child()->is_element()) {
|
||||
const Element& el = static_cast<const Element&>(*first_child());
|
||||
if (el.tag_name() == "html")
|
||||
return;
|
||||
}
|
||||
if (is<HTMLHtmlElement>(first_child()))
|
||||
return;
|
||||
|
||||
NonnullRefPtr<Element> body = adopt(*new Element(*this, "body"));
|
||||
NonnullRefPtr<Element> html = adopt(*new Element(*this, "html"));
|
||||
|
|
|
@ -80,3 +80,9 @@ private:
|
|||
Color m_active_link_color { Color::Red };
|
||||
Color m_visited_link_color { Color::Magenta };
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<Document>(const Node& node)
|
||||
{
|
||||
return node.is_document();
|
||||
}
|
||||
|
|
|
@ -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<Attribute> m_attributes;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<Element>(const Node& node)
|
||||
{
|
||||
return node.is_element();
|
||||
}
|
||||
|
|
|
@ -9,3 +9,9 @@ public:
|
|||
|
||||
String href() const { return attribute("href"); }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<HTMLAnchorElement>(const Node& node)
|
||||
{
|
||||
return is<Element>(node) && to<Element>(node).tag_name().to_lowercase() == "a";
|
||||
}
|
||||
|
|
|
@ -12,3 +12,9 @@ public:
|
|||
private:
|
||||
virtual bool is_html_element() const final { return true; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<HTMLElement>(const Node& node)
|
||||
{
|
||||
return node.is_html_element();
|
||||
}
|
||||
|
|
|
@ -7,3 +7,9 @@ public:
|
|||
HTMLHtmlElement(Document&, const String& tag_name);
|
||||
virtual ~HTMLHtmlElement() override;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<HTMLHtmlElement>(const Node& node)
|
||||
{
|
||||
return is<Element>(node) && to<Element>(node).tag_name().to_lowercase() == "html";
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ RefPtr<LayoutNode> 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<HTMLAnchorElement>(*this))
|
||||
return static_cast<const HTMLAnchorElement*>(this);
|
||||
return parent() ? parent()->enclosing_link_element() : nullptr;
|
||||
}
|
||||
|
|
|
@ -74,3 +74,41 @@ protected:
|
|||
mutable LayoutNode* m_layout_node { nullptr };
|
||||
NodeType m_type { NodeType::INVALID };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool is(const Node&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool is(const Node* node)
|
||||
{
|
||||
return node && is<T>(*node);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool is<Node>(const Node&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool is<ParentNode>(const Node& node)
|
||||
{
|
||||
return node.is_parent_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);
|
||||
}
|
||||
|
|
|
@ -19,3 +19,9 @@ private:
|
|||
|
||||
String m_data;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<Text>(const Node& node)
|
||||
{
|
||||
return node.is_text();
|
||||
}
|
||||
|
|
|
@ -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<Document>(node)) {
|
||||
dbgprintf("*Document*\n");
|
||||
} else if (node.is_element()) {
|
||||
dbgprintf("<%s", static_cast<const Element&>(node).tag_name().characters());
|
||||
static_cast<const Element&>(node).for_each_attribute([](auto& name, auto& value) {
|
||||
} else if (is<Element>(node)) {
|
||||
dbgprintf("<%s", to<Element>(node).tag_name().characters());
|
||||
to<Element>(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<Text>(node)) {
|
||||
dbgprintf("\"%s\"\n", static_cast<const Text&>(node).data().characters());
|
||||
}
|
||||
++indent;
|
||||
if (node.is_parent_node()) {
|
||||
if (is<ParentNode>(node)) {
|
||||
static_cast<const ParentNode&>(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<Text>(layout_node.node()))
|
||||
tag_name = "#text";
|
||||
else if (layout_node.node()->is_document())
|
||||
else if (is<Document>(layout_node.node()))
|
||||
tag_name = "#document";
|
||||
else if (layout_node.node()->is_element())
|
||||
tag_name = static_cast<const Element&>(*layout_node.node()).tag_name();
|
||||
else if (is<Element>(layout_node.node()))
|
||||
tag_name = to<Element>(*layout_node.node()).tag_name();
|
||||
else
|
||||
tag_name = "???";
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ public:
|
|||
LayoutReplaced(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutReplaced() override;
|
||||
|
||||
const Element& node() const { return static_cast<const Element&>(*LayoutNode::node()); }
|
||||
const Element& node() const { return to<Element>(*LayoutNode::node()); }
|
||||
|
||||
virtual bool is_replaced() const final { return true; }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue