summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/CSS/Selector.h
blob: b7c0f18e16f1565c66915f832d8c70510566b76d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * 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/RefCounted.h>
#include <AK/String.h>
#include <AK/Vector.h>

namespace Web::CSS {

class Selector : public RefCounted<Selector> {
public:
    struct SimpleSelector {
        enum class Type {
            Invalid,
            Universal,
            TagName,
            Id,
            Class,
            Attribute,
            PseudoClass,
            PseudoElement,
        };
        Type type { Type::Invalid };

        struct NthChildPattern {
            int step_size = 0;
            int offset = 0;

            static NthChildPattern parse(StringView const& args);
        };

        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".
            NthChildPattern nth_child_pattern;

            // FIXME: This wants to be a Selector, rather than parsing it each time it is used.
            String 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;
    };

    struct ComplexSelector {
        enum class Relation {
            None,
            ImmediateChild,
            Descendant,
            AdjacentSibling,
            GeneralSibling,
            Column,
        };
        Relation relation { Relation::None };

        using CompoundSelector = Vector<SimpleSelector>;
        CompoundSelector compound_selector;
    };

    static NonnullRefPtr<Selector> create(Vector<ComplexSelector>&& complex_selectors)
    {
        return adopt_ref(*new Selector(move(complex_selectors)));
    }

    ~Selector();

    Vector<ComplexSelector> const& complex_selectors() const { return m_complex_selectors; }

    u32 specificity() const;

private:
    explicit Selector(Vector<ComplexSelector>&&);

    Vector<ComplexSelector> m_complex_selectors;
};

}