LibHTML: Implement matching for descendant selectors

The CSS engine now correctly matches selectors like "#foo #bar #baz".
This commit is contained in:
Andreas Kling 2019-10-06 15:34:42 +02:00
parent b587eb2f4d
commit 156b35742a
3 changed files with 60 additions and 5 deletions

View file

@ -0,0 +1,32 @@
<html>
<head>
<title>Selector test</title>
<style>
#foo #bar #baz {
background-color: #00ff00;
}
.abc .def div {
background-color: #ffffff;
border-style: solid;
border-width: 1;
border-color: #00ff00;
}
</style>
</head>
<body>
<div id="foo">
<div id="bar">
<div id="baz">
I should have a green background.
</div>
</div>
</div>
<div class="abc">
<div class="def">
<div>hello</div>
<div>hello</div>
<div>hello</div>
</div>
</div>
</body>
</html>

View file

@ -21,6 +21,7 @@ h1 {
<li><a href="lorem.html">lorem ipsum</a></li>
<li><a href="phint.html">presentational hints</a></li>
<li><a href="images.html">images</a></li>
<li><a href="selectors.html">selectors</a></li>
</ul>
</body>
</html>

View file

@ -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<const Element&>(*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;