1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 15:07:45 +00:00

LibWeb: Use a Variant for SimpleSelector's contents

This reduces SimpleSelector's size from 112 bytes to 80 bytes. :^)
This commit is contained in:
Sam Atkins 2022-03-21 15:43:59 +00:00 committed by Andreas Kling
parent 218a9af6b3
commit c0db19f63c
6 changed files with 96 additions and 77 deletions

View file

@ -327,7 +327,7 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_attribute_
Selector::SimpleSelector simple_selector { Selector::SimpleSelector simple_selector {
.type = Selector::SimpleSelector::Type::Attribute, .type = Selector::SimpleSelector::Type::Attribute,
.attribute = { .value = Selector::SimpleSelector::Attribute {
.match_type = Selector::SimpleSelector::Attribute::MatchType::HasAttribute, .match_type = Selector::SimpleSelector::Attribute::MatchType::HasAttribute,
// FIXME: Case-sensitivity is defined by the document language. // FIXME: Case-sensitivity is defined by the document language.
// HTML is insensitive with attribute names, and our code generally assumes // HTML is insensitive with attribute names, and our code generally assumes
@ -349,7 +349,7 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_attribute_
} }
if (delim_part.token().delim() == '=') { if (delim_part.token().delim() == '=') {
simple_selector.attribute.match_type = Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch; simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch;
} else { } else {
if (!attribute_tokens.has_next_token()) { if (!attribute_tokens.has_next_token()) {
dbgln_if(CSS_PARSER_DEBUG, "Attribute selector ended part way through a match type."); dbgln_if(CSS_PARSER_DEBUG, "Attribute selector ended part way through a match type.");
@ -363,19 +363,19 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_attribute_
} }
switch (delim_part.token().delim()) { switch (delim_part.token().delim()) {
case '~': case '~':
simple_selector.attribute.match_type = Selector::SimpleSelector::Attribute::MatchType::ContainsWord; simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::ContainsWord;
break; break;
case '*': case '*':
simple_selector.attribute.match_type = Selector::SimpleSelector::Attribute::MatchType::ContainsString; simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::ContainsString;
break; break;
case '|': case '|':
simple_selector.attribute.match_type = Selector::SimpleSelector::Attribute::MatchType::StartsWithSegment; simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::StartsWithSegment;
break; break;
case '^': case '^':
simple_selector.attribute.match_type = Selector::SimpleSelector::Attribute::MatchType::StartsWithString; simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::StartsWithString;
break; break;
case '$': case '$':
simple_selector.attribute.match_type = Selector::SimpleSelector::Attribute::MatchType::EndsWithString; simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::EndsWithString;
break; break;
default: default:
attribute_tokens.reconsume_current_input_token(); attribute_tokens.reconsume_current_input_token();
@ -393,7 +393,7 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_attribute_
dbgln_if(CSS_PARSER_DEBUG, "Expected a string or ident for the value to match attribute against, got: '{}'", value_part.to_debug_string()); dbgln_if(CSS_PARSER_DEBUG, "Expected a string or ident for the value to match attribute against, got: '{}'", value_part.to_debug_string());
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} }
simple_selector.attribute.value = value_part.token().is(Token::Type::Ident) ? value_part.token().ident() : value_part.token().string(); simple_selector.attribute().value = value_part.token().is(Token::Type::Ident) ? value_part.token().ident() : value_part.token().string();
attribute_tokens.skip_whitespace(); attribute_tokens.skip_whitespace();
@ -439,7 +439,7 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_pseudo_sim
dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-element: '::{}'", pseudo_name); dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-element: '::{}'", pseudo_name);
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} }
simple_selector.pseudo_element = pseudo_element.value(); simple_selector.value = pseudo_element.value();
return simple_selector; return simple_selector;
} }
@ -449,7 +449,8 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_pseudo_sim
auto const& pseudo_class_token = tokens.next_token(); auto const& pseudo_class_token = tokens.next_token();
Selector::SimpleSelector simple_selector { Selector::SimpleSelector simple_selector {
.type = Selector::SimpleSelector::Type::PseudoClass .type = Selector::SimpleSelector::Type::PseudoClass,
.value = Selector::SimpleSelector::PseudoClass {}
}; };
if (pseudo_class_token.is(Token::Type::Ident)) { if (pseudo_class_token.is(Token::Type::Ident)) {
@ -458,56 +459,56 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_pseudo_sim
return ParsingResult::IncludesIgnoredVendorPrefix; return ParsingResult::IncludesIgnoredVendorPrefix;
if (pseudo_name.equals_ignoring_case("active")) { if (pseudo_name.equals_ignoring_case("active")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Active; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Active;
} else if (pseudo_name.equals_ignoring_case("checked")) { } else if (pseudo_name.equals_ignoring_case("checked")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Checked; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Checked;
} else if (pseudo_name.equals_ignoring_case("disabled")) { } else if (pseudo_name.equals_ignoring_case("disabled")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Disabled; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Disabled;
} else if (pseudo_name.equals_ignoring_case("empty")) { } else if (pseudo_name.equals_ignoring_case("empty")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Empty; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Empty;
} else if (pseudo_name.equals_ignoring_case("enabled")) { } else if (pseudo_name.equals_ignoring_case("enabled")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Enabled; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Enabled;
} else if (pseudo_name.equals_ignoring_case("first-child")) { } else if (pseudo_name.equals_ignoring_case("first-child")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::FirstChild; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::FirstChild;
} else if (pseudo_name.equals_ignoring_case("first-of-type")) { } else if (pseudo_name.equals_ignoring_case("first-of-type")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::FirstOfType; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::FirstOfType;
} else if (pseudo_name.equals_ignoring_case("focus")) { } else if (pseudo_name.equals_ignoring_case("focus")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Focus; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Focus;
} else if (pseudo_name.equals_ignoring_case("focus-within")) { } else if (pseudo_name.equals_ignoring_case("focus-within")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::FocusWithin; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::FocusWithin;
} else if (pseudo_name.equals_ignoring_case("hover")) { } else if (pseudo_name.equals_ignoring_case("hover")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Hover; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Hover;
} else if (pseudo_name.equals_ignoring_case("last-child")) { } else if (pseudo_name.equals_ignoring_case("last-child")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::LastChild; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::LastChild;
} else if (pseudo_name.equals_ignoring_case("last-of-type")) { } else if (pseudo_name.equals_ignoring_case("last-of-type")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::LastOfType; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::LastOfType;
} else if (pseudo_name.equals_ignoring_case("link")) { } else if (pseudo_name.equals_ignoring_case("link")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Link; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Link;
} else if (pseudo_name.equals_ignoring_case("only-child")) { } else if (pseudo_name.equals_ignoring_case("only-child")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::OnlyChild; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::OnlyChild;
} else if (pseudo_name.equals_ignoring_case("only-of-type")) { } else if (pseudo_name.equals_ignoring_case("only-of-type")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::OnlyOfType; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::OnlyOfType;
} else if (pseudo_name.equals_ignoring_case("root")) { } else if (pseudo_name.equals_ignoring_case("root")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Root; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Root;
} else if (pseudo_name.equals_ignoring_case("visited")) { } else if (pseudo_name.equals_ignoring_case("visited")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Visited; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Visited;
} else if (pseudo_name.equals_ignoring_case("after")) { } else if (pseudo_name.equals_ignoring_case("after")) {
// Single-colon syntax allowed for compatibility. https://www.w3.org/TR/selectors/#pseudo-element-syntax // Single-colon syntax allowed for compatibility. https://www.w3.org/TR/selectors/#pseudo-element-syntax
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
simple_selector.pseudo_element = Selector::PseudoElement::After; simple_selector.value = Selector::PseudoElement::After;
} else if (pseudo_name.equals_ignoring_case("before")) { } else if (pseudo_name.equals_ignoring_case("before")) {
// See :after // See :after
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
simple_selector.pseudo_element = Selector::PseudoElement::Before; simple_selector.value = Selector::PseudoElement::Before;
} else if (pseudo_name.equals_ignoring_case("first-letter")) { } else if (pseudo_name.equals_ignoring_case("first-letter")) {
// See :after // See :after
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
simple_selector.pseudo_element = Selector::PseudoElement::FirstLetter; simple_selector.value = Selector::PseudoElement::FirstLetter;
} else if (pseudo_name.equals_ignoring_case("first-line")) { } else if (pseudo_name.equals_ignoring_case("first-line")) {
// See :after // See :after
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
simple_selector.pseudo_element = Selector::PseudoElement::FirstLine; simple_selector.value = Selector::PseudoElement::FirstLine;
} else { } else {
dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-class: ':{}'", pseudo_name); dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-class: ':{}'", pseudo_name);
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
@ -520,7 +521,7 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_pseudo_sim
auto function_values = TokenStream<StyleComponentValueRule>(pseudo_function.values()); auto function_values = TokenStream<StyleComponentValueRule>(pseudo_function.values());
auto nth_child_pattern = parse_a_n_plus_b_pattern(function_values, allow_of ? AllowTrailingTokens::Yes : AllowTrailingTokens::No); auto nth_child_pattern = parse_a_n_plus_b_pattern(function_values, allow_of ? AllowTrailingTokens::Yes : AllowTrailingTokens::No);
if (nth_child_pattern.has_value()) { if (nth_child_pattern.has_value()) {
simple_selector.pseudo_class.nth_child_pattern = nth_child_pattern.value(); simple_selector.pseudo_class().nth_child_pattern = nth_child_pattern.value();
} else { } else {
dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid format for {}", pseudo_function.name()); dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid format for {}", pseudo_function.name());
return false; return false;
@ -546,42 +547,42 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_pseudo_sim
if (function_values.has_next_token()) if (function_values.has_next_token())
return false; return false;
simple_selector.pseudo_class.argument_selector_list = selector_list.value(); simple_selector.pseudo_class().argument_selector_list = selector_list.value();
return true; return true;
}; };
auto const& pseudo_function = pseudo_class_token.function(); auto const& pseudo_function = pseudo_class_token.function();
if (pseudo_function.name().equals_ignoring_case("not")) { if (pseudo_function.name().equals_ignoring_case("not")) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Not; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Not;
auto function_token_stream = TokenStream(pseudo_function.values()); auto function_token_stream = TokenStream(pseudo_function.values());
auto not_selector = parse_a_selector_list(function_token_stream, SelectorType::Standalone); auto not_selector = parse_a_selector_list(function_token_stream, SelectorType::Standalone);
if (not_selector.is_error()) { if (not_selector.is_error()) {
dbgln_if(CSS_PARSER_DEBUG, "Invalid selector in :not() clause"); dbgln_if(CSS_PARSER_DEBUG, "Invalid selector in :not() clause");
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} }
simple_selector.pseudo_class.argument_selector_list = not_selector.release_value(); simple_selector.pseudo_class().argument_selector_list = not_selector.release_value();
} else if (pseudo_function.name().equals_ignoring_case("lang"sv)) { } else if (pseudo_function.name().equals_ignoring_case("lang"sv)) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Lang; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::Lang;
if (pseudo_function.values().is_empty()) { if (pseudo_function.values().is_empty()) {
dbgln_if(CSS_PARSER_DEBUG, "Empty :lang() selector"); dbgln_if(CSS_PARSER_DEBUG, "Empty :lang() selector");
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} }
// FIXME: Support multiple, comma-separated, language ranges. // FIXME: Support multiple, comma-separated, language ranges.
simple_selector.pseudo_class.languages.append(pseudo_function.values().first().token().to_string()); simple_selector.pseudo_class().languages.append(pseudo_function.values().first().token().to_string());
} else if (pseudo_function.name().equals_ignoring_case("nth-child"sv)) { } else if (pseudo_function.name().equals_ignoring_case("nth-child"sv)) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthChild; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::NthChild;
if (!parse_nth_child_pattern(simple_selector, pseudo_function, true)) if (!parse_nth_child_pattern(simple_selector, pseudo_function, true))
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} else if (pseudo_function.name().equals_ignoring_case("nth-last-child"sv)) { } else if (pseudo_function.name().equals_ignoring_case("nth-last-child"sv)) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthLastChild; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::NthLastChild;
if (!parse_nth_child_pattern(simple_selector, pseudo_function, true)) if (!parse_nth_child_pattern(simple_selector, pseudo_function, true))
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} else if (pseudo_function.name().equals_ignoring_case("nth-of-type"sv)) { } else if (pseudo_function.name().equals_ignoring_case("nth-of-type"sv)) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthOfType; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::NthOfType;
if (!parse_nth_child_pattern(simple_selector, pseudo_function)) if (!parse_nth_child_pattern(simple_selector, pseudo_function))
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} else if (pseudo_function.name().equals_ignoring_case("nth-last-of-type"sv)) { } else if (pseudo_function.name().equals_ignoring_case("nth-last-of-type"sv)) {
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthLastOfType; simple_selector.pseudo_class().type = Selector::SimpleSelector::PseudoClass::Type::NthLastOfType;
if (!parse_nth_child_pattern(simple_selector, pseudo_function)) if (!parse_nth_child_pattern(simple_selector, pseudo_function))
return ParsingResult::SyntaxError; return ParsingResult::SyntaxError;
} else { } else {
@ -625,7 +626,7 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
} }
return Selector::SimpleSelector { return Selector::SimpleSelector {
.type = Selector::SimpleSelector::Type::Class, .type = Selector::SimpleSelector::Type::Class,
.value = class_name_value.token().ident() .value = FlyString { class_name_value.token().ident() }
}; };
} }
case '>': case '>':
@ -649,13 +650,13 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
} }
return Selector::SimpleSelector { return Selector::SimpleSelector {
.type = Selector::SimpleSelector::Type::Id, .type = Selector::SimpleSelector::Type::Id,
.value = first_value.token().hash_value() .value = FlyString { first_value.token().hash_value() }
}; };
} }
if (first_value.is(Token::Type::Ident)) { if (first_value.is(Token::Type::Ident)) {
return Selector::SimpleSelector { return Selector::SimpleSelector {
.type = Selector::SimpleSelector::Type::TagName, .type = Selector::SimpleSelector::Type::TagName,
.value = first_value.token().ident() .value = FlyString { first_value.token().ident() }
}; };
} }
if (first_value.is_block() && first_value.block().is_square()) if (first_value.is_block() && first_value.block().is_square())

View file

@ -13,12 +13,12 @@ namespace Web::CSS {
Selector::Selector(Vector<CompoundSelector>&& compound_selectors) Selector::Selector(Vector<CompoundSelector>&& compound_selectors)
: m_compound_selectors(move(compound_selectors)) : m_compound_selectors(move(compound_selectors))
{ {
// Note: This assumes that only one pseudo-element is allowed in a selector, and that it appears at the end. // FIXME: This assumes that only one pseudo-element is allowed in a selector, and that it appears at the end.
// This is true currently, and there are no current proposals to change this, but you never know! // This is not true in Selectors-4!
if (!m_compound_selectors.is_empty()) { if (!m_compound_selectors.is_empty()) {
for (auto const& simple_selector : m_compound_selectors.last().simple_selectors) { for (auto const& simple_selector : m_compound_selectors.last().simple_selectors) {
if (simple_selector.type == SimpleSelector::Type::PseudoElement) { if (simple_selector.type == SimpleSelector::Type::PseudoElement) {
m_pseudo_element = simple_selector.pseudo_element; m_pseudo_element = simple_selector.pseudo_element();
break; break;
} }
} }
@ -69,13 +69,14 @@ u32 Selector::specificity() const
// count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= B) // count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= B)
++classes; ++classes;
break; break;
case SimpleSelector::Type::PseudoClass: case SimpleSelector::Type::PseudoClass: {
switch (simple_selector.pseudo_class.type) { auto& pseudo_class = simple_selector.pseudo_class();
switch (pseudo_class.type) {
case SimpleSelector::PseudoClass::Type::Is: case SimpleSelector::PseudoClass::Type::Is:
case SimpleSelector::PseudoClass::Type::Not: { case SimpleSelector::PseudoClass::Type::Not: {
// The specificity of an :is(), :not(), or :has() pseudo-class is replaced by the // The specificity of an :is(), :not(), or :has() pseudo-class is replaced by the
// specificity of the most specific complex selector in its selector list argument. // specificity of the most specific complex selector in its selector list argument.
count_specificity_of_most_complex_selector(simple_selector.pseudo_class.argument_selector_list); count_specificity_of_most_complex_selector(pseudo_class.argument_selector_list);
break; break;
} }
case SimpleSelector::PseudoClass::Type::NthChild: case SimpleSelector::PseudoClass::Type::NthChild:
@ -84,7 +85,7 @@ u32 Selector::specificity() const
// is the specificity of the pseudo class itself (counting as one pseudo-class selector) // is the specificity of the pseudo class itself (counting as one pseudo-class selector)
// plus the specificity of the most specific complex selector in its selector list argument (if any). // plus the specificity of the most specific complex selector in its selector list argument (if any).
++classes; ++classes;
count_specificity_of_most_complex_selector(simple_selector.pseudo_class.argument_selector_list); count_specificity_of_most_complex_selector(pseudo_class.argument_selector_list);
break; break;
} }
case SimpleSelector::PseudoClass::Type::Where: case SimpleSelector::PseudoClass::Type::Where:
@ -95,6 +96,7 @@ u32 Selector::specificity() const
break; break;
} }
break; break;
}
case SimpleSelector::Type::TagName: case SimpleSelector::Type::TagName:
case SimpleSelector::Type::PseudoElement: case SimpleSelector::Type::PseudoElement:
// count the number of type selectors and pseudo-elements in the selector (= C) // count the number of type selectors and pseudo-elements in the selector (= C)
@ -129,13 +131,15 @@ String Selector::SimpleSelector::serialize() const
// FIXME: 2. If the namespace prefix maps to a namespace that is the null namespace (not in a namespace) append "|" (U+007C) to s. // FIXME: 2. If the namespace prefix maps to a namespace that is the null namespace (not in a namespace) append "|" (U+007C) to s.
// 3. If this is a type selector append the serialization of the element name as an identifier to s. // 3. If this is a type selector append the serialization of the element name as an identifier to s.
if (type == Selector::SimpleSelector::Type::TagName) { if (type == Selector::SimpleSelector::Type::TagName) {
serialize_an_identifier(s, value); serialize_an_identifier(s, name());
} }
// 4. If this is a universal selector append "*" (U+002A) to s. // 4. If this is a universal selector append "*" (U+002A) to s.
if (type == Selector::SimpleSelector::Type::Universal) if (type == Selector::SimpleSelector::Type::Universal)
s.append('*'); s.append('*');
break; break;
case Selector::SimpleSelector::Type::Attribute: case Selector::SimpleSelector::Type::Attribute: {
auto& attribute = this->attribute();
// 1. Append "[" (U+005B) to s. // 1. Append "[" (U+005B) to s.
s.append('['); s.append('[');
@ -177,20 +181,23 @@ String Selector::SimpleSelector::serialize() const
// 6. Append "]" (U+005D) to s. // 6. Append "]" (U+005D) to s.
s.append(']'); s.append(']');
break; break;
}
case Selector::SimpleSelector::Type::Class: case Selector::SimpleSelector::Type::Class:
// Append a "." (U+002E), followed by the serialization of the class name as an identifier to s. // Append a "." (U+002E), followed by the serialization of the class name as an identifier to s.
s.append('.'); s.append('.');
serialize_an_identifier(s, value); serialize_an_identifier(s, name());
break; break;
case Selector::SimpleSelector::Type::Id: case Selector::SimpleSelector::Type::Id:
// Append a "#" (U+0023), followed by the serialization of the ID as an identifier to s. // Append a "#" (U+0023), followed by the serialization of the ID as an identifier to s.
s.append('#'); s.append('#');
serialize_an_identifier(s, value); serialize_an_identifier(s, name());
break; break;
case Selector::SimpleSelector::Type::PseudoClass: case Selector::SimpleSelector::Type::PseudoClass: {
auto& pseudo_class = this->pseudo_class();
switch (pseudo_class.type) { switch (pseudo_class.type) {
case Selector::SimpleSelector::PseudoClass::Type::Link: case Selector::SimpleSelector::PseudoClass::Type::Link:
case Selector::SimpleSelector::PseudoClass::Type::Visited: case Selector::SimpleSelector::PseudoClass::Type::Visited:
@ -239,6 +246,7 @@ String Selector::SimpleSelector::serialize() const
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
break; break;
}
case Selector::SimpleSelector::Type::PseudoElement: case Selector::SimpleSelector::Type::PseudoElement:
// Note: Pseudo-elements are dealt with in Selector::serialize() // Note: Pseudo-elements are dealt with in Selector::serialize()
break; break;
@ -299,7 +307,7 @@ String Selector::serialize() const
// append "::" followed by the name of the pseudo-element, to s. // append "::" followed by the name of the pseudo-element, to s.
if (compound_selector.simple_selectors.last().type == Selector::SimpleSelector::Type::PseudoElement) { if (compound_selector.simple_selectors.last().type == Selector::SimpleSelector::Type::PseudoElement) {
s.append("::"); s.append("::");
s.append(pseudo_element_name(compound_selector.simple_selectors.last().pseudo_element)); s.append(pseudo_element_name(compound_selector.simple_selectors.last().pseudo_element()));
} }
} }
} }

View file

@ -41,7 +41,6 @@ public:
PseudoClass, PseudoClass,
PseudoElement, PseudoElement,
}; };
Type type { Type::Invalid };
struct ANPlusBPattern { struct ANPlusBPattern {
int step_size { 0 }; // "A" int step_size { 0 }; // "A"
@ -93,10 +92,6 @@ public:
// Used for :lang(en-gb,dk) // Used for :lang(en-gb,dk)
Vector<FlyString> languages; Vector<FlyString> languages;
}; };
PseudoClass pseudo_class {};
PseudoElement pseudo_element { PseudoElement::None };
FlyString value {};
struct Attribute { struct Attribute {
enum class MatchType { enum class MatchType {
@ -113,7 +108,18 @@ public:
FlyString name {}; FlyString name {};
String value {}; String value {};
}; };
Attribute attribute {};
Type type { Type::Invalid };
Variant<Empty, Attribute, PseudoClass, PseudoElement, FlyString> value {};
Attribute const& attribute() const { return value.get<Attribute>(); }
Attribute& attribute() { return value.get<Attribute>(); }
PseudoClass const& pseudo_class() const { return value.get<PseudoClass>(); }
PseudoClass& pseudo_class() { return value.get<PseudoClass>(); }
PseudoElement const& pseudo_element() const { return value.get<PseudoElement>(); }
PseudoElement& pseudo_element() { return value.get<PseudoElement>(); }
FlyString const& name() const { return value.get<FlyString>(); }
FlyString& name() { return value.get<FlyString>(); }
String serialize() const; String serialize() const;
}; };

View file

@ -301,15 +301,15 @@ static inline bool matches(CSS::Selector::SimpleSelector const& component, DOM::
case CSS::Selector::SimpleSelector::Type::Universal: case CSS::Selector::SimpleSelector::Type::Universal:
return true; return true;
case CSS::Selector::SimpleSelector::Type::Id: case CSS::Selector::SimpleSelector::Type::Id:
return component.value == element.attribute(HTML::AttributeNames::id); return component.name() == element.attribute(HTML::AttributeNames::id);
case CSS::Selector::SimpleSelector::Type::Class: case CSS::Selector::SimpleSelector::Type::Class:
return element.has_class(component.value); return element.has_class(component.name());
case CSS::Selector::SimpleSelector::Type::TagName: case CSS::Selector::SimpleSelector::Type::TagName:
return component.value == element.local_name(); return component.name() == element.local_name();
case CSS::Selector::SimpleSelector::Type::Attribute: case CSS::Selector::SimpleSelector::Type::Attribute:
return matches_attribute(component.attribute, element); return matches_attribute(component.attribute(), element);
case CSS::Selector::SimpleSelector::Type::PseudoClass: case CSS::Selector::SimpleSelector::Type::PseudoClass:
return matches_pseudo_class(component.pseudo_class, element); return matches_pseudo_class(component.pseudo_class(), element);
case CSS::Selector::SimpleSelector::Type::PseudoElement: case CSS::Selector::SimpleSelector::Type::PseudoElement:
// Pseudo-element matching/not-matching is handled in the top level matches(). // Pseudo-element matching/not-matching is handled in the top level matches().
return true; return true;

View file

@ -1109,7 +1109,7 @@ void StyleComputer::build_rule_cache()
bool added_to_bucket = false; bool added_to_bucket = false;
for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) { for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) {
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) {
m_rule_cache->rules_by_pseudo_element.ensure(simple_selector.pseudo_element).append(move(matching_rule)); m_rule_cache->rules_by_pseudo_element.ensure(simple_selector.pseudo_element()).append(move(matching_rule));
++num_pseudo_element_rules; ++num_pseudo_element_rules;
added_to_bucket = true; added_to_bucket = true;
break; break;
@ -1118,19 +1118,19 @@ void StyleComputer::build_rule_cache()
if (!added_to_bucket) { if (!added_to_bucket) {
for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) { for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) {
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Id) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Id) {
m_rule_cache->rules_by_id.ensure(simple_selector.value).append(move(matching_rule)); m_rule_cache->rules_by_id.ensure(simple_selector.name()).append(move(matching_rule));
++num_id_rules; ++num_id_rules;
added_to_bucket = true; added_to_bucket = true;
break; break;
} }
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Class) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Class) {
m_rule_cache->rules_by_class.ensure(simple_selector.value).append(move(matching_rule)); m_rule_cache->rules_by_class.ensure(simple_selector.name()).append(move(matching_rule));
++num_class_rules; ++num_class_rules;
added_to_bucket = true; added_to_bucket = true;
break; break;
} }
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::TagName) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::TagName) {
m_rule_cache->rules_by_tag_name.ensure(simple_selector.value).append(move(matching_rule)); m_rule_cache->rules_by_tag_name.ensure(simple_selector.name()).append(move(matching_rule));
++num_tag_name_rules; ++num_tag_name_rules;
added_to_bucket = true; added_to_bucket = true;
break; break;

View file

@ -359,10 +359,13 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
break; break;
} }
builder.appendff("{}:{}", type_description, simple_selector.value); builder.appendff("{}:", type_description);
// FIXME: This is goofy
if (simple_selector.value.has<FlyString>())
builder.append(simple_selector.name());
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass) {
auto const& pseudo_class = simple_selector.pseudo_class; auto const& pseudo_class = simple_selector.pseudo_class();
char const* pseudo_class_description = ""; char const* pseudo_class_description = "";
switch (pseudo_class.type) { switch (pseudo_class.type) {
@ -475,7 +478,7 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) {
char const* pseudo_element_description = ""; char const* pseudo_element_description = "";
switch (simple_selector.pseudo_element) { switch (simple_selector.pseudo_element()) {
case CSS::Selector::PseudoElement::None: case CSS::Selector::PseudoElement::None:
pseudo_element_description = "NONE"; pseudo_element_description = "NONE";
break; break;
@ -500,9 +503,10 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
} }
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Attribute) { if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Attribute) {
auto const& attribute = simple_selector.attribute();
char const* attribute_match_type_description = ""; char const* attribute_match_type_description = "";
switch (simple_selector.attribute.match_type) { switch (attribute.match_type) {
case CSS::Selector::SimpleSelector::Attribute::MatchType::None: case CSS::Selector::SimpleSelector::Attribute::MatchType::None:
attribute_match_type_description = "NONE"; attribute_match_type_description = "NONE";
break; break;
@ -529,7 +533,7 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
break; break;
} }
builder.appendff(" [{}, name='{}', value='{}']", attribute_match_type_description, simple_selector.attribute.name, simple_selector.attribute.value); builder.appendff(" [{}, name='{}', value='{}']", attribute_match_type_description, attribute.name, attribute.value);
} }
if (i != relative_selector.simple_selectors.size() - 1) if (i != relative_selector.simple_selectors.size() - 1)