/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Web::CSS { using SelectorList = NonnullRefPtrVector; // This is a in the spec. https://www.w3.org/TR/selectors-4/#complex class Selector : public RefCounted { public: struct SimpleSelector { enum class Type { Invalid, Universal, TagName, Id, Class, Attribute, PseudoClass, PseudoElement, }; Type type { Type::Invalid }; struct ANPlusBPattern { int step_size { 0 }; // "A" int offset = { 0 }; // "B" String serialize() const { return String::formatted("{}n{:+}", step_size, offset); } }; 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". ANPlusBPattern 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 {}; String serialize() const; }; enum class Combinator { None, ImmediateChild, // > Descendant, // NextSibling, // + SubsequentSibling, // ~ Column, // || }; struct CompoundSelector { // Spec-wise, the is not part of a , // but it is more understandable to put them together. Combinator combinator { Combinator::None }; Vector simple_selectors; }; static NonnullRefPtr create(Vector&& compound_selectors) { return adopt_ref(*new Selector(move(compound_selectors))); } ~Selector(); Vector const& compound_selectors() const { return m_compound_selectors; } u32 specificity() const; String serialize() const; private: explicit Selector(Vector&&); Vector m_compound_selectors; }; constexpr StringView pseudo_element_name(Selector::SimpleSelector::PseudoElement); constexpr StringView pseudo_class_name(Selector::SimpleSelector::PseudoClass::Type); String serialize_a_group_of_selectors(NonnullRefPtrVector const& selectors); } namespace AK { template<> struct Formatter : Formatter { ErrorOr format(FormatBuilder& builder, Web::CSS::Selector const& selector) { return Formatter::format(builder, selector.serialize()); } }; }