diff --git a/Libraries/LibHTML/CSS/SelectorEngine.cpp b/Libraries/LibHTML/CSS/SelectorEngine.cpp
new file mode 100644
index 0000000000..ef8ab33ab0
--- /dev/null
+++ b/Libraries/LibHTML/CSS/SelectorEngine.cpp
@@ -0,0 +1,64 @@
+#include
+#include
+
+namespace SelectorEngine {
+
+bool matches(const Selector::Component& component, const Element& element)
+{
+ switch (component.type) {
+ case Selector::Component::Type::Id:
+ return component.value == element.attribute("id");
+ case Selector::Component::Type::Class:
+ return element.has_class(component.value);
+ case Selector::Component::Type::TagName:
+ return component.value == element.tag_name();
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+bool matches(const Selector& selector, int component_index, const Element& element)
+{
+ auto& component = selector.components()[component_index];
+ if (!matches(component, element))
+ return false;
+ switch (component.relation) {
+ case Selector::Component::Relation::None:
+ return true;
+ case Selector::Component::Relation::Descendant:
+ ASSERT(component_index != 0);
+ for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) {
+ if (!is(*ancestor))
+ continue;
+ if (matches(selector, component_index - 1, to(*ancestor)))
+ return true;
+ }
+ return false;
+ case Selector::Component::Relation::ImmediateChild:
+ ASSERT(component_index != 0);
+ if (!element.parent() || !is(*element.parent()))
+ return false;
+ 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())
+ return matches(selector, component_index - 1, *sibling);
+ return false;
+ case Selector::Component::Relation::GeneralSibling:
+ ASSERT(component_index != 0);
+ for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
+ if (matches(selector, component_index - 1, *sibling))
+ return true;
+ }
+ return false;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+bool matches(const Selector& selector, const Element& element)
+{
+ ASSERT(!selector.components().is_empty());
+ return matches(selector, selector.components().size() - 1, element);
+}
+
+}
diff --git a/Libraries/LibHTML/CSS/SelectorEngine.h b/Libraries/LibHTML/CSS/SelectorEngine.h
new file mode 100644
index 0000000000..4727091b6f
--- /dev/null
+++ b/Libraries/LibHTML/CSS/SelectorEngine.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+
+class Element;
+
+namespace SelectorEngine {
+
+bool matches(const Selector&, const Element&);
+
+}
diff --git a/Libraries/LibHTML/CSS/StyleResolver.cpp b/Libraries/LibHTML/CSS/StyleResolver.cpp
index 58e5a6cee7..1745084414 100644
--- a/Libraries/LibHTML/CSS/StyleResolver.cpp
+++ b/Libraries/LibHTML/CSS/StyleResolver.cpp
@@ -1,3 +1,4 @@
+#include
#include
#include
#include
@@ -15,64 +16,6 @@ StyleResolver::~StyleResolver()
{
}
-static bool matches(const Selector::Component& component, const Element& element)
-{
- switch (component.type) {
- case Selector::Component::Type::Id:
- return component.value == element.attribute("id");
- case Selector::Component::Type::Class:
- return element.has_class(component.value);
- case Selector::Component::Type::TagName:
- return component.value == element.tag_name();
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-static bool matches(const Selector& selector, int component_index, const Element& element)
-{
- auto& component = selector.components()[component_index];
- if (!matches(component, element))
- return false;
- switch (component.relation) {
- case Selector::Component::Relation::None:
- return true;
- case Selector::Component::Relation::Descendant:
- ASSERT(component_index != 0);
- for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) {
- if (!is(*ancestor))
- continue;
- if (matches(selector, component_index - 1, to(*ancestor)))
- return true;
- }
- return false;
- case Selector::Component::Relation::ImmediateChild:
- ASSERT(component_index != 0);
- if (!element.parent() || !is(*element.parent()))
- return false;
- 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())
- return matches(selector, component_index - 1, *sibling);
- return false;
- case Selector::Component::Relation::GeneralSibling:
- ASSERT(component_index != 0);
- for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
- if (matches(selector, component_index - 1, *sibling))
- return true;
- }
- return false;
- }
- ASSERT_NOT_REACHED();
-}
-
-static bool matches(const Selector& selector, const Element& element)
-{
- ASSERT(!selector.components().is_empty());
- return matches(selector, selector.components().size() - 1, element);
-}
-
static StyleSheet& default_stylesheet()
{
static StyleSheet* sheet;
@@ -100,7 +43,7 @@ NonnullRefPtrVector StyleResolver::collect_matching_rules(const Eleme
for_each_stylesheet([&](auto& sheet) {
for (auto& rule : sheet.rules()) {
for (auto& selector : rule.selectors()) {
- if (matches(selector, element)) {
+ if (SelectorEngine::matches(selector, element)) {
matching_rules.append(rule);
break;
}
diff --git a/Libraries/LibHTML/Makefile.shared b/Libraries/LibHTML/Makefile.shared
index 312bff2c7b..202ca6b808 100644
--- a/Libraries/LibHTML/Makefile.shared
+++ b/Libraries/LibHTML/Makefile.shared
@@ -24,6 +24,7 @@ LIBHTML_OBJS = \
CSS/StyleProperties.o \
CSS/StyleResolver.o \
CSS/DefaultStyleSheetSource.o \
+ CSS/SelectorEngine.o \
Parser/HTMLParser.o \
Parser/CSSParser.o \
Layout/LayoutNode.o \