mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 03:02:45 +00:00 
			
		
		
		
	 6034fc0ee6
			
		
	
	
		6034fc0ee6
		
	
	
	
	
		
			
			Parsing this pattern from CSS tokens turns out to be slightly crazy, but thankfully well documented in the spec. The spec lists the cases in order of simple -> complicated, but this would cause problems in code, since `<n-dimension> <signed-.integer>` would never by reached, as `<n-dimension>` comes before. Instead, I have grouped them by their first token. Also renamed the NthChildPattern class to ANPlusBPattern, to match spec terminology.
		
			
				
	
	
		
			141 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
	
		
			3.7 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 ANPlusBPattern {
 | |
|             int step_size { 0 }; // "A"
 | |
|             int offset = { 0 };  // "B"
 | |
| 
 | |
|             static ANPlusBPattern parse(StringView const& args);
 | |
|             String to_string() 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 {};
 | |
|     };
 | |
| 
 | |
|     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;
 | |
| };
 | |
| 
 | |
| }
 |