mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 05:09:12 +00:00
LibWeb: Generate pseudo-element code from JSON
Initially, this generates the enum and to/from-string functions. The JSON itself contains more data than that, but it's unused for now.
This commit is contained in:
parent
0ed2e71801
commit
ffa1dba96a
Notes:
github-actions[bot]
2025-03-24 09:51:30 +00:00
Author: https://github.com/AtkinsSJ
Commit: ffa1dba96a
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4021
14 changed files with 244 additions and 106 deletions
|
@ -418,15 +418,15 @@ Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_pseudo_simple_selec
|
|||
|
||||
auto pseudo_name = name_token.token().ident();
|
||||
|
||||
if (auto pseudo_element = Selector::PseudoElementSelector::from_string(pseudo_name); pseudo_element.has_value()) {
|
||||
if (auto pseudo_element = pseudo_element_from_string(pseudo_name); pseudo_element.has_value()) {
|
||||
// :has() is fussy about pseudo-elements inside it
|
||||
if (m_pseudo_class_context.contains_slow(PseudoClass::Has) && !is_has_allowed_pseudo_element(pseudo_element->type())) {
|
||||
if (m_pseudo_class_context.contains_slow(PseudoClass::Has) && !is_has_allowed_pseudo_element(*pseudo_element)) {
|
||||
return ParseError::SyntaxError;
|
||||
}
|
||||
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::PseudoElement,
|
||||
.value = pseudo_element.release_value()
|
||||
.value = Selector::PseudoElementSelector { pseudo_element.release_value() }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -481,20 +481,20 @@ Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_pseudo_simple_selec
|
|||
|
||||
// Single-colon syntax allowed for ::after, ::before, ::first-letter and ::first-line for compatibility.
|
||||
// https://www.w3.org/TR/selectors/#pseudo-element-syntax
|
||||
if (auto pseudo_element = Selector::PseudoElementSelector::from_string(pseudo_name); pseudo_element.has_value()) {
|
||||
switch (pseudo_element.value().type()) {
|
||||
if (auto pseudo_element = pseudo_element_from_string(pseudo_name); pseudo_element.has_value()) {
|
||||
switch (pseudo_element.value()) {
|
||||
case PseudoElement::After:
|
||||
case PseudoElement::Before:
|
||||
case PseudoElement::FirstLetter:
|
||||
case PseudoElement::FirstLine:
|
||||
// :has() is fussy about pseudo-elements inside it
|
||||
if (m_pseudo_class_context.contains_slow(PseudoClass::Has) && !is_has_allowed_pseudo_element(pseudo_element->type())) {
|
||||
if (m_pseudo_class_context.contains_slow(PseudoClass::Has) && !is_has_allowed_pseudo_element(pseudo_element.value())) {
|
||||
return ParseError::SyntaxError;
|
||||
}
|
||||
|
||||
return Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::PseudoElement,
|
||||
.value = pseudo_element.value()
|
||||
.value = Selector::PseudoElementSelector { pseudo_element.value() }
|
||||
};
|
||||
default:
|
||||
break;
|
||||
|
|
43
Libraries/LibWeb/CSS/PseudoElements.json
Normal file
43
Libraries/LibWeb/CSS/PseudoElements.json
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"after": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-after",
|
||||
"is-generated": true
|
||||
},
|
||||
"backdrop": {
|
||||
"spec": "https://drafts.csswg.org/css-position-4/#selectordef-backdrop"
|
||||
},
|
||||
"before": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-before",
|
||||
"is-generated": true
|
||||
},
|
||||
"details-content": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-details-content"
|
||||
},
|
||||
"file-selector-button": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-file-selector-button"
|
||||
},
|
||||
"fill": {
|
||||
"spec": "https://drafts.csswg.org/css-forms-1/#selectordef-fill"
|
||||
},
|
||||
"first-letter": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-letter"
|
||||
},
|
||||
"first-line": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-line"
|
||||
},
|
||||
"marker": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-marker"
|
||||
},
|
||||
"placeholder": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-placeholder"
|
||||
},
|
||||
"selection": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-selection"
|
||||
},
|
||||
"thumb": {
|
||||
"spec": "https://drafts.csswg.org/css-forms-1/#selectordef-thumb"
|
||||
},
|
||||
"track": {
|
||||
"spec": "https://drafts.csswg.org/css-forms-1/#selectordef-track"
|
||||
}
|
||||
}
|
|
@ -535,74 +535,6 @@ String serialize_a_group_of_selectors(SelectorList const& selectors)
|
|||
return MUST(String::join(", "sv, selectors));
|
||||
}
|
||||
|
||||
StringView Selector::PseudoElementSelector::name(PseudoElement pseudo_element)
|
||||
{
|
||||
switch (pseudo_element) {
|
||||
case PseudoElement::Before:
|
||||
return "before"sv;
|
||||
case PseudoElement::After:
|
||||
return "after"sv;
|
||||
case PseudoElement::FirstLine:
|
||||
return "first-line"sv;
|
||||
case PseudoElement::FirstLetter:
|
||||
return "first-letter"sv;
|
||||
case PseudoElement::Marker:
|
||||
return "marker"sv;
|
||||
case PseudoElement::Track:
|
||||
return "track"sv;
|
||||
case PseudoElement::Fill:
|
||||
return "fill"sv;
|
||||
case PseudoElement::Thumb:
|
||||
return "thumb"sv;
|
||||
case PseudoElement::Placeholder:
|
||||
return "placeholder"sv;
|
||||
case PseudoElement::Selection:
|
||||
return "selection"sv;
|
||||
case PseudoElement::Backdrop:
|
||||
return "backdrop"sv;
|
||||
case PseudoElement::FileSelectorButton:
|
||||
return "file-selector-button"sv;
|
||||
case PseudoElement::DetailsContent:
|
||||
return "details-content"sv;
|
||||
case PseudoElement::KnownPseudoElementCount:
|
||||
case PseudoElement::UnknownWebKit:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
Optional<Selector::PseudoElementSelector> Selector::PseudoElementSelector::from_string(FlyString const& name)
|
||||
{
|
||||
if (name.equals_ignoring_ascii_case("after"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::After };
|
||||
} else if (name.equals_ignoring_ascii_case("before"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Before };
|
||||
} else if (name.equals_ignoring_ascii_case("first-letter"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::FirstLetter };
|
||||
} else if (name.equals_ignoring_ascii_case("first-line"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::FirstLine };
|
||||
} else if (name.equals_ignoring_ascii_case("marker"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Marker };
|
||||
} else if (name.equals_ignoring_ascii_case("track"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Track };
|
||||
} else if (name.equals_ignoring_ascii_case("fill"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Fill };
|
||||
} else if (name.equals_ignoring_ascii_case("thumb"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Thumb };
|
||||
} else if (name.equals_ignoring_ascii_case("placeholder"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Placeholder };
|
||||
} else if (name.equals_ignoring_ascii_case("selection"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Selection };
|
||||
} else if (name.equals_ignoring_ascii_case("backdrop"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::Backdrop };
|
||||
} else if (name.equals_ignoring_ascii_case("file-selector-button"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::FileSelectorButton };
|
||||
} else if (name.equals_ignoring_ascii_case("details-content"sv)) {
|
||||
return Selector::PseudoElementSelector { PseudoElement::DetailsContent };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
NonnullRefPtr<Selector> Selector::relative_to(SimpleSelector const& parent) const
|
||||
{
|
||||
// To make us relative to the parent, prepend it to the list of compound selectors,
|
||||
|
|
|
@ -14,34 +14,12 @@
|
|||
#include <LibWeb/CSS/Keyword.h>
|
||||
#include <LibWeb/CSS/Parser/ComponentValue.h>
|
||||
#include <LibWeb/CSS/PseudoClass.h>
|
||||
#include <LibWeb/CSS/PseudoElement.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
using SelectorList = Vector<NonnullRefPtr<class Selector>>;
|
||||
|
||||
enum class PseudoElement : u8 {
|
||||
Before,
|
||||
After,
|
||||
FirstLine,
|
||||
FirstLetter,
|
||||
Marker,
|
||||
Track,
|
||||
Fill,
|
||||
Thumb,
|
||||
Placeholder,
|
||||
Selection,
|
||||
Backdrop,
|
||||
FileSelectorButton,
|
||||
DetailsContent,
|
||||
|
||||
// Keep this last.
|
||||
KnownPseudoElementCount,
|
||||
|
||||
// https://www.w3.org/TR/selectors-4/#compat
|
||||
// NOTE: This is not last as the 'unknown -webkit- pseudo-elements' are not stored as part of any Element.
|
||||
UnknownWebKit,
|
||||
};
|
||||
|
||||
// This is a <complex-selector> in the spec. https://www.w3.org/TR/selectors-4/#complex
|
||||
class Selector : public RefCounted<Selector> {
|
||||
public:
|
||||
|
@ -61,21 +39,17 @@ public:
|
|||
|
||||
bool operator==(PseudoElementSelector const&) const = default;
|
||||
|
||||
static Optional<PseudoElementSelector> from_string(FlyString const&);
|
||||
|
||||
[[nodiscard]] static bool is_known_pseudo_element_type(PseudoElement type)
|
||||
{
|
||||
return to_underlying(type) < to_underlying(PseudoElement::KnownPseudoElementCount);
|
||||
}
|
||||
|
||||
static StringView name(PseudoElement pseudo_element);
|
||||
|
||||
StringView name() const
|
||||
{
|
||||
if (!m_name.is_empty())
|
||||
return m_name;
|
||||
|
||||
return name(m_type);
|
||||
return pseudo_element_name(m_type);
|
||||
}
|
||||
|
||||
PseudoElement type() const { return m_type; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue