
The spec does not directly tell us how to parse selectors, so there are likely some bugs here, but I've used the spec language where possible. This is very much based on the previous selector parsing code. Any parse error inside a selector makes the entire SelectorList invalid, so nothing is returned.
137 lines
3.6 KiB
C++
137 lines
3.6 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2021, Sam Atkins <atkinssj@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/FlyString.h>
|
|
#include <AK/NonnullRefPtrVector.h>
|
|
#include <AK/RefCounted.h>
|
|
#include <AK/String.h>
|
|
#include <AK/Vector.h>
|
|
|
|
namespace Web::CSS {
|
|
|
|
using SelectorList = NonnullRefPtrVector<class Selector>;
|
|
|
|
// This is a <complex-selector> in the spec. https://www.w3.org/TR/selectors-4/#complex
|
|
class Selector : public RefCounted<Selector> {
|
|
public:
|
|
struct SimpleSelector {
|
|
enum class Type {
|
|
Invalid,
|
|
Universal,
|
|
TagName,
|
|
Id,
|
|
Class,
|
|
Attribute,
|
|
PseudoClass,
|
|
PseudoElement,
|
|
};
|
|
Type type { Type::Invalid };
|
|
|
|
struct NthChildPattern {
|
|
int step_size { 0 };
|
|
int offset = { 0 };
|
|
|
|
static NthChildPattern parse(StringView const& args);
|
|
};
|
|
|
|
struct PseudoClass {
|
|
enum class Type {
|
|
None,
|
|
Link,
|
|
Visited,
|
|
Hover,
|
|
Focus,
|
|
FirstChild,
|
|
LastChild,
|
|
OnlyChild,
|
|
Empty,
|
|
Root,
|
|
FirstOfType,
|
|
LastOfType,
|
|
NthChild,
|
|
NthLastChild,
|
|
Disabled,
|
|
Enabled,
|
|
Checked,
|
|
Not,
|
|
Active,
|
|
};
|
|
Type type { Type::None };
|
|
|
|
// FIXME: We don't need this field on every single SimpleSelector, but it's also annoying to malloc it somewhere.
|
|
// Only used when "pseudo_class" is "NthChild" or "NthLastChild".
|
|
NthChildPattern nth_child_pattern;
|
|
|
|
SelectorList not_selector {};
|
|
};
|
|
PseudoClass pseudo_class {};
|
|
|
|
enum class PseudoElement {
|
|
None,
|
|
Before,
|
|
After,
|
|
FirstLine,
|
|
FirstLetter,
|
|
};
|
|
PseudoElement pseudo_element { PseudoElement::None };
|
|
|
|
FlyString value {};
|
|
|
|
struct Attribute {
|
|
enum class MatchType {
|
|
None,
|
|
HasAttribute,
|
|
ExactValueMatch,
|
|
ContainsWord, // [att~=val]
|
|
ContainsString, // [att*=val]
|
|
StartsWithSegment, // [att|=val]
|
|
StartsWithString, // [att^=val]
|
|
EndsWithString, // [att$=val]
|
|
};
|
|
MatchType match_type { MatchType::None };
|
|
FlyString name {};
|
|
String value {};
|
|
};
|
|
Attribute attribute {};
|
|
};
|
|
|
|
enum class Combinator {
|
|
None,
|
|
ImmediateChild, // >
|
|
Descendant, // <whitespace>
|
|
NextSibling, // +
|
|
SubsequentSibling, // ~
|
|
Column, // ||
|
|
};
|
|
|
|
struct CompoundSelector {
|
|
// Spec-wise, the <combinator> is not part of a <compound-selector>,
|
|
// but it is more understandable to put them together.
|
|
Combinator combinator { Combinator::None };
|
|
Vector<SimpleSelector> simple_selectors;
|
|
};
|
|
|
|
static NonnullRefPtr<Selector> create(Vector<CompoundSelector>&& compound_selectors)
|
|
{
|
|
return adopt_ref(*new Selector(move(compound_selectors)));
|
|
}
|
|
|
|
~Selector();
|
|
|
|
Vector<CompoundSelector> const& compound_selectors() const { return m_compound_selectors; }
|
|
|
|
u32 specificity() const;
|
|
|
|
private:
|
|
explicit Selector(Vector<CompoundSelector>&&);
|
|
|
|
Vector<CompoundSelector> m_compound_selectors;
|
|
};
|
|
|
|
}
|