mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 05:57:41 +00:00
LibWeb: Bring Selector terminology in line with the CSS spec
- CompoundSelector -> *deleted* - ComplexSelector -> CompoundSelector - Relation -> Combinator Our Selector is really a ComplexSelector, but only the Parser and SelectorEngine need to know that, so keeping it named Selector makes it more understandable for users. Our CompoundSelector is really a CompoundSelectorAndCombinator. Combining the two makes sense in our codebase, but the accurate name is so long that I think it makes the code less readable. Renamed some Combinators to also match the spec terminology: - AdjacentSibling -> NextSibling - GeneralSibling -> SubsequentSibling The previous names are somewhat ambiguous, so hopefully this is clearer.
This commit is contained in:
parent
ca436afeb5
commit
6ea5d03f43
6 changed files with 67 additions and 63 deletions
|
@ -1081,9 +1081,9 @@ public:
|
||||||
return simple_selector;
|
return simple_selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<CSS::Selector::ComplexSelector> parse_complex_selector()
|
Optional<CSS::Selector::CompoundSelector> parse_complex_selector()
|
||||||
{
|
{
|
||||||
auto relation = CSS::Selector::ComplexSelector::Relation::Descendant;
|
auto relation = CSS::Selector::Combinator::Descendant;
|
||||||
|
|
||||||
if (peek() == '{' || peek() == ',')
|
if (peek() == '{' || peek() == ',')
|
||||||
return {};
|
return {};
|
||||||
|
@ -1091,13 +1091,13 @@ public:
|
||||||
if (is_combinator(peek())) {
|
if (is_combinator(peek())) {
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case '>':
|
case '>':
|
||||||
relation = CSS::Selector::ComplexSelector::Relation::ImmediateChild;
|
relation = CSS::Selector::Combinator::ImmediateChild;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
relation = CSS::Selector::ComplexSelector::Relation::AdjacentSibling;
|
relation = CSS::Selector::Combinator::NextSibling;
|
||||||
break;
|
break;
|
||||||
case '~':
|
case '~':
|
||||||
relation = CSS::Selector::ComplexSelector::Relation::GeneralSibling;
|
relation = CSS::Selector::Combinator::SubsequentSibling;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
consume_one();
|
consume_one();
|
||||||
|
@ -1119,12 +1119,12 @@ public:
|
||||||
if (simple_selectors.is_empty())
|
if (simple_selectors.is_empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return CSS::Selector::ComplexSelector { relation, move(simple_selectors) };
|
return CSS::Selector::CompoundSelector { relation, move(simple_selectors) };
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_selector()
|
void parse_selector()
|
||||||
{
|
{
|
||||||
Vector<CSS::Selector::ComplexSelector> complex_selectors;
|
Vector<CSS::Selector::CompoundSelector> complex_selectors;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto index_before = index;
|
auto index_before = index;
|
||||||
|
@ -1141,7 +1141,7 @@ public:
|
||||||
|
|
||||||
if (complex_selectors.is_empty())
|
if (complex_selectors.is_empty())
|
||||||
return;
|
return;
|
||||||
complex_selectors.first().relation = CSS::Selector::ComplexSelector::Relation::None;
|
complex_selectors.first().combinator = CSS::Selector::Combinator::None;
|
||||||
|
|
||||||
current_rule.selectors.append(CSS::Selector::create(move(complex_selectors)));
|
current_rule.selectors.append(CSS::Selector::create(move(complex_selectors)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ RefPtr<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is_r
|
||||||
|
|
||||||
// FIXME: Bring this all in line with the spec. https://www.w3.org/TR/selectors-4/
|
// FIXME: Bring this all in line with the spec. https://www.w3.org/TR/selectors-4/
|
||||||
|
|
||||||
Vector<Selector::ComplexSelector> selectors;
|
Vector<Selector::CompoundSelector> selectors;
|
||||||
|
|
||||||
auto check_for_eof_or_whitespace = [&](T& current_value) -> bool {
|
auto check_for_eof_or_whitespace = [&](T& current_value) -> bool {
|
||||||
if (current_value.is(Token::Type::EndOfFile))
|
if (current_value.is(Token::Type::EndOfFile))
|
||||||
|
@ -491,8 +491,8 @@ RefPtr<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is_r
|
||||||
return simple_selector;
|
return simple_selector;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parse_complex_selector = [&]() -> Optional<Selector::ComplexSelector> {
|
auto parse_complex_selector = [&]() -> Optional<Selector::CompoundSelector> {
|
||||||
auto relation = Selector::ComplexSelector::Relation::Descendant;
|
auto combinator = Selector::Combinator::Descendant;
|
||||||
|
|
||||||
tokens.skip_whitespace();
|
tokens.skip_whitespace();
|
||||||
|
|
||||||
|
@ -500,13 +500,13 @@ RefPtr<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is_r
|
||||||
if (current_value.is(Token::Type::Delim)) {
|
if (current_value.is(Token::Type::Delim)) {
|
||||||
auto delim = ((Token)current_value).delim();
|
auto delim = ((Token)current_value).delim();
|
||||||
if (delim == ">") {
|
if (delim == ">") {
|
||||||
relation = Selector::ComplexSelector::Relation::ImmediateChild;
|
combinator = Selector::Combinator::ImmediateChild;
|
||||||
tokens.next_token();
|
tokens.next_token();
|
||||||
} else if (delim == "+") {
|
} else if (delim == "+") {
|
||||||
relation = Selector::ComplexSelector::Relation::AdjacentSibling;
|
combinator = Selector::Combinator::NextSibling;
|
||||||
tokens.next_token();
|
tokens.next_token();
|
||||||
} else if (delim == "~") {
|
} else if (delim == "~") {
|
||||||
relation = Selector::ComplexSelector::Relation::GeneralSibling;
|
combinator = Selector::Combinator::SubsequentSibling;
|
||||||
tokens.next_token();
|
tokens.next_token();
|
||||||
} else if (delim == "|") {
|
} else if (delim == "|") {
|
||||||
tokens.next_token();
|
tokens.next_token();
|
||||||
|
@ -516,7 +516,7 @@ RefPtr<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is_r
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (next.is(Token::Type::Delim) && next.token().delim() == "|") {
|
if (next.is(Token::Type::Delim) && next.token().delim() == "|") {
|
||||||
relation = Selector::ComplexSelector::Relation::Column;
|
combinator = Selector::Combinator::Column;
|
||||||
tokens.next_token();
|
tokens.next_token();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +541,7 @@ RefPtr<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is_r
|
||||||
if (simple_selectors.is_empty())
|
if (simple_selectors.is_empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return Selector::ComplexSelector { relation, move(simple_selectors) };
|
return Selector::CompoundSelector { combinator, move(simple_selectors) };
|
||||||
};
|
};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -558,7 +558,7 @@ RefPtr<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is_r
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!is_relative)
|
if (!is_relative)
|
||||||
selectors.first().relation = Selector::ComplexSelector::Relation::None;
|
selectors.first().combinator = Selector::Combinator::None;
|
||||||
|
|
||||||
return Selector::create(move(selectors));
|
return Selector::create(move(selectors));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
namespace Web::CSS {
|
namespace Web::CSS {
|
||||||
|
|
||||||
Selector::Selector(Vector<ComplexSelector>&& component_lists)
|
Selector::Selector(Vector<CompoundSelector>&& compound_selectors)
|
||||||
: m_complex_selectors(move(component_lists))
|
: m_compound_selectors(move(compound_selectors))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ u32 Selector::specificity() const
|
||||||
unsigned tag_names = 0;
|
unsigned tag_names = 0;
|
||||||
unsigned classes = 0;
|
unsigned classes = 0;
|
||||||
|
|
||||||
for (auto& list : m_complex_selectors) {
|
for (auto& list : m_compound_selectors) {
|
||||||
for (auto& simple_selector : list.compound_selector) {
|
for (auto& simple_selector : list.simple_selectors) {
|
||||||
switch (simple_selector.type) {
|
switch (simple_selector.type) {
|
||||||
case SimpleSelector::Type::Id:
|
case SimpleSelector::Type::Id:
|
||||||
++ids;
|
++ids;
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
namespace Web::CSS {
|
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> {
|
class Selector : public RefCounted<Selector> {
|
||||||
public:
|
public:
|
||||||
struct SimpleSelector {
|
struct SimpleSelector {
|
||||||
|
@ -65,7 +68,7 @@ public:
|
||||||
// Only used when "pseudo_class" is "NthChild" or "NthLastChild".
|
// Only used when "pseudo_class" is "NthChild" or "NthLastChild".
|
||||||
NthChildPattern nth_child_pattern;
|
NthChildPattern nth_child_pattern;
|
||||||
|
|
||||||
NonnullRefPtrVector<Selector> not_selector {};
|
SelectorList not_selector {};
|
||||||
};
|
};
|
||||||
PseudoClass pseudo_class;
|
PseudoClass pseudo_class;
|
||||||
|
|
||||||
|
@ -98,36 +101,37 @@ public:
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ComplexSelector {
|
enum class Combinator {
|
||||||
enum class Relation {
|
None,
|
||||||
None,
|
ImmediateChild, // >
|
||||||
ImmediateChild,
|
Descendant, // <whitespace>
|
||||||
Descendant,
|
NextSibling, // +
|
||||||
AdjacentSibling,
|
SubsequentSibling, // ~
|
||||||
GeneralSibling,
|
Column, // ||
|
||||||
Column,
|
|
||||||
};
|
|
||||||
Relation relation { Relation::None };
|
|
||||||
|
|
||||||
using CompoundSelector = Vector<SimpleSelector>;
|
|
||||||
CompoundSelector compound_selector;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static NonnullRefPtr<Selector> create(Vector<ComplexSelector>&& complex_selectors)
|
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(complex_selectors)));
|
return adopt_ref(*new Selector(move(compound_selectors)));
|
||||||
}
|
}
|
||||||
|
|
||||||
~Selector();
|
~Selector();
|
||||||
|
|
||||||
Vector<ComplexSelector> const& complex_selectors() const { return m_complex_selectors; }
|
Vector<CompoundSelector> const& compound_selectors() const { return m_compound_selectors; }
|
||||||
|
|
||||||
u32 specificity() const;
|
u32 specificity() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Selector(Vector<ComplexSelector>&&);
|
explicit Selector(Vector<CompoundSelector>&&);
|
||||||
|
|
||||||
Vector<ComplexSelector> m_complex_selectors;
|
Vector<CompoundSelector> m_compound_selectors;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,15 +195,15 @@ static bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element
|
||||||
|
|
||||||
static bool matches(CSS::Selector const& selector, int component_list_index, DOM::Element const& element)
|
static bool matches(CSS::Selector const& selector, int component_list_index, DOM::Element const& element)
|
||||||
{
|
{
|
||||||
auto& component_list = selector.complex_selectors()[component_list_index];
|
auto& relative_selector = selector.compound_selectors()[component_list_index];
|
||||||
for (auto& component : component_list.compound_selector) {
|
for (auto& simple_selector : relative_selector.simple_selectors) {
|
||||||
if (!matches(component, element))
|
if (!matches(simple_selector, element))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (component_list.relation) {
|
switch (relative_selector.combinator) {
|
||||||
case CSS::Selector::ComplexSelector::Relation::None:
|
case CSS::Selector::Combinator::None:
|
||||||
return true;
|
return true;
|
||||||
case CSS::Selector::ComplexSelector::Relation::Descendant:
|
case CSS::Selector::Combinator::Descendant:
|
||||||
VERIFY(component_list_index != 0);
|
VERIFY(component_list_index != 0);
|
||||||
for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) {
|
for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) {
|
||||||
if (!is<DOM::Element>(*ancestor))
|
if (!is<DOM::Element>(*ancestor))
|
||||||
|
@ -212,24 +212,24 @@ static bool matches(CSS::Selector const& selector, int component_list_index, DOM
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case CSS::Selector::ComplexSelector::Relation::ImmediateChild:
|
case CSS::Selector::Combinator::ImmediateChild:
|
||||||
VERIFY(component_list_index != 0);
|
VERIFY(component_list_index != 0);
|
||||||
if (!element.parent() || !is<DOM::Element>(*element.parent()))
|
if (!element.parent() || !is<DOM::Element>(*element.parent()))
|
||||||
return false;
|
return false;
|
||||||
return matches(selector, component_list_index - 1, verify_cast<DOM::Element>(*element.parent()));
|
return matches(selector, component_list_index - 1, verify_cast<DOM::Element>(*element.parent()));
|
||||||
case CSS::Selector::ComplexSelector::Relation::AdjacentSibling:
|
case CSS::Selector::Combinator::NextSibling:
|
||||||
VERIFY(component_list_index != 0);
|
VERIFY(component_list_index != 0);
|
||||||
if (auto* sibling = element.previous_element_sibling())
|
if (auto* sibling = element.previous_element_sibling())
|
||||||
return matches(selector, component_list_index - 1, *sibling);
|
return matches(selector, component_list_index - 1, *sibling);
|
||||||
return false;
|
return false;
|
||||||
case CSS::Selector::ComplexSelector::Relation::GeneralSibling:
|
case CSS::Selector::Combinator::SubsequentSibling:
|
||||||
VERIFY(component_list_index != 0);
|
VERIFY(component_list_index != 0);
|
||||||
for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
|
for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
|
||||||
if (matches(selector, component_list_index - 1, *sibling))
|
if (matches(selector, component_list_index - 1, *sibling))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case CSS::Selector::ComplexSelector::Relation::Column:
|
case CSS::Selector::Combinator::Column:
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
|
@ -237,8 +237,8 @@ static bool matches(CSS::Selector const& selector, int component_list_index, DOM
|
||||||
|
|
||||||
bool matches(CSS::Selector const& selector, DOM::Element const& element)
|
bool matches(CSS::Selector const& selector, DOM::Element const& element)
|
||||||
{
|
{
|
||||||
VERIFY(!selector.complex_selectors().is_empty());
|
VERIFY(!selector.compound_selectors().is_empty());
|
||||||
return matches(selector, selector.complex_selectors().size() - 1, element);
|
return matches(selector, selector.compound_selectors().size() - 1, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,27 +267,27 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
|
||||||
{
|
{
|
||||||
builder.append(" CSS::Selector:\n");
|
builder.append(" CSS::Selector:\n");
|
||||||
|
|
||||||
for (auto& complex_selector : selector.complex_selectors()) {
|
for (auto& relative_selector : selector.compound_selectors()) {
|
||||||
builder.append(" ");
|
builder.append(" ");
|
||||||
|
|
||||||
char const* relation_description = "";
|
char const* relation_description = "";
|
||||||
switch (complex_selector.relation) {
|
switch (relative_selector.combinator) {
|
||||||
case CSS::Selector::ComplexSelector::Relation::None:
|
case CSS::Selector::Combinator::None:
|
||||||
relation_description = "None";
|
relation_description = "None";
|
||||||
break;
|
break;
|
||||||
case CSS::Selector::ComplexSelector::Relation::ImmediateChild:
|
case CSS::Selector::Combinator::ImmediateChild:
|
||||||
relation_description = "ImmediateChild";
|
relation_description = "ImmediateChild";
|
||||||
break;
|
break;
|
||||||
case CSS::Selector::ComplexSelector::Relation::Descendant:
|
case CSS::Selector::Combinator::Descendant:
|
||||||
relation_description = "Descendant";
|
relation_description = "Descendant";
|
||||||
break;
|
break;
|
||||||
case CSS::Selector::ComplexSelector::Relation::AdjacentSibling:
|
case CSS::Selector::Combinator::NextSibling:
|
||||||
relation_description = "AdjacentSibling";
|
relation_description = "AdjacentSibling";
|
||||||
break;
|
break;
|
||||||
case CSS::Selector::ComplexSelector::Relation::GeneralSibling:
|
case CSS::Selector::Combinator::SubsequentSibling:
|
||||||
relation_description = "GeneralSibling";
|
relation_description = "GeneralSibling";
|
||||||
break;
|
break;
|
||||||
case CSS::Selector::ComplexSelector::Relation::Column:
|
case CSS::Selector::Combinator::Column:
|
||||||
relation_description = "Column";
|
relation_description = "Column";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -295,8 +295,8 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
|
||||||
if (*relation_description)
|
if (*relation_description)
|
||||||
builder.appendff("{{{}}} ", relation_description);
|
builder.appendff("{{{}}} ", relation_description);
|
||||||
|
|
||||||
for (size_t i = 0; i < complex_selector.compound_selector.size(); ++i) {
|
for (size_t i = 0; i < relative_selector.simple_selectors.size(); ++i) {
|
||||||
auto& simple_selector = complex_selector.compound_selector[i];
|
auto& simple_selector = relative_selector.simple_selectors[i];
|
||||||
char const* type_description = "Unknown";
|
char const* type_description = "Unknown";
|
||||||
switch (simple_selector.type) {
|
switch (simple_selector.type) {
|
||||||
case CSS::Selector::SimpleSelector::Type::Invalid:
|
case CSS::Selector::SimpleSelector::Type::Invalid:
|
||||||
|
@ -459,7 +459,7 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
|
||||||
builder.appendff(" [{}, name='{}', value='{}']", attribute_match_type_description, simple_selector.attribute.name, simple_selector.attribute.value);
|
builder.appendff(" [{}, name='{}', value='{}']", attribute_match_type_description, simple_selector.attribute.name, simple_selector.attribute.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != complex_selector.compound_selector.size() - 1)
|
if (i != relative_selector.simple_selectors.size() - 1)
|
||||||
builder.append(", ");
|
builder.append(", ");
|
||||||
}
|
}
|
||||||
builder.append("\n");
|
builder.append("\n");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue