From 156b35742a947c7179bd4f6cbad363eb8918a261 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 6 Oct 2019 15:34:42 +0200 Subject: [PATCH] LibHTML: Implement matching for descendant selectors The CSS engine now correctly matches selectors like "#foo #bar #baz". --- Base/home/anon/www/selectors.html | 32 +++++++++++++++++++++++++ Base/home/anon/www/welcome.html | 1 + Libraries/LibHTML/CSS/StyleResolver.cpp | 32 +++++++++++++++++++++---- 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 Base/home/anon/www/selectors.html diff --git a/Base/home/anon/www/selectors.html b/Base/home/anon/www/selectors.html new file mode 100644 index 0000000000..2ad965f2c1 --- /dev/null +++ b/Base/home/anon/www/selectors.html @@ -0,0 +1,32 @@ + + +Selector test + + + +
+
+
+ I should have a green background. +
+
+
+
+
+
hello
+
hello
+
hello
+
+
+ + diff --git a/Base/home/anon/www/welcome.html b/Base/home/anon/www/welcome.html index 39932c9a10..4a0c583ff7 100644 --- a/Base/home/anon/www/welcome.html +++ b/Base/home/anon/www/welcome.html @@ -21,6 +21,7 @@ h1 {
  • lorem ipsum
  • presentational hints
  • images
  • +
  • selectors
  • diff --git a/Libraries/LibHTML/CSS/StyleResolver.cpp b/Libraries/LibHTML/CSS/StyleResolver.cpp index 6f7697ba65..95b7ab8cc2 100644 --- a/Libraries/LibHTML/CSS/StyleResolver.cpp +++ b/Libraries/LibHTML/CSS/StyleResolver.cpp @@ -15,12 +15,8 @@ StyleResolver::~StyleResolver() { } -static bool matches(const Selector& selector, const Element& element) +static bool matches(const Selector::Component& component, const Element& element) { - // FIXME: Support compound selectors. - ASSERT(selector.components().size() == 1); - - auto& component = selector.components().first(); switch (component.type) { case Selector::Component::Type::Id: return component.value == element.attribute("id"); @@ -33,6 +29,32 @@ static bool matches(const Selector& selector, const Element& element) } } +static bool matches(const Selector& selector, int component_index, const Element& element) +{ + auto& component = selector.components()[component_index]; + if (!matches(component, element)) + return false; + if (component.relation == Selector::Component::Relation::None) + return true; + if (component.relation == Selector::Component::Relation::Descendant) { + ASSERT(component_index != 0); + for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) { + if (!ancestor->is_element()) + continue; + if (matches(selector, component_index - 1, static_cast(*ancestor))) + 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;