From 19dbfc315365eeeb110c6b11cc387a018b03f7c2 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 8 Oct 2019 15:33:58 +0200 Subject: [PATCH] LibHTML: Move selector matching into a SelectorEngine namespace --- Libraries/LibHTML/CSS/SelectorEngine.cpp | 64 ++++++++++++++++++++++++ Libraries/LibHTML/CSS/SelectorEngine.h | 11 ++++ Libraries/LibHTML/CSS/StyleResolver.cpp | 61 +--------------------- Libraries/LibHTML/Makefile.shared | 1 + 4 files changed, 78 insertions(+), 59 deletions(-) create mode 100644 Libraries/LibHTML/CSS/SelectorEngine.cpp create mode 100644 Libraries/LibHTML/CSS/SelectorEngine.h 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 \