1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003-2014 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#pragma once
23
24#include "RuleFeature.h"
25#include "SelectorCompiler.h"
26#include "SelectorFilter.h"
27#include "StyleRule.h"
28#include <wtf/Forward.h>
29#include <wtf/HashMap.h>
30#include <wtf/text/AtomicString.h>
31#include <wtf/text/AtomicStringHash.h>
32
33namespace WebCore {
34
35enum PropertyWhitelistType {
36 PropertyWhitelistNone = 0,
37 PropertyWhitelistMarker,
38#if ENABLE(VIDEO_TRACK)
39 PropertyWhitelistCue
40#endif
41};
42
43class CSSSelector;
44class ContainerNode;
45class MediaQueryEvaluator;
46class Node;
47class StyleResolver;
48class StyleSheetContents;
49
50enum class MatchBasedOnRuleHash : unsigned {
51 None,
52 Universal,
53 ClassA,
54 ClassB,
55 ClassC
56};
57
58class RuleData {
59public:
60 static const unsigned maximumSelectorComponentCount = 8192;
61
62 RuleData(StyleRule*, unsigned selectorIndex, unsigned selectorListIndex, unsigned position);
63
64 unsigned position() const { return m_position; }
65 StyleRule* rule() const { return m_rule.get(); }
66 const CSSSelector* selector() const { return m_rule->selectorList().selectorAt(m_selectorIndex); }
67 unsigned selectorIndex() const { return m_selectorIndex; }
68 unsigned selectorListIndex() const { return m_selectorListIndex; }
69
70 bool canMatchPseudoElement() const { return m_canMatchPseudoElement; }
71 MatchBasedOnRuleHash matchBasedOnRuleHash() const { return static_cast<MatchBasedOnRuleHash>(m_matchBasedOnRuleHash); }
72 bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
73 unsigned linkMatchType() const { return m_linkMatchType; }
74 PropertyWhitelistType propertyWhitelistType() const { return static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
75 const SelectorFilter::Hashes& descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }
76
77 void disableSelectorFiltering() { m_descendantSelectorIdentifierHashes[0] = 0; }
78
79private:
80 RefPtr<StyleRule> m_rule;
81 unsigned m_selectorIndex : 16;
82 unsigned m_selectorListIndex : 16;
83 // This number was picked fairly arbitrarily. We can probably lower it if we need to.
84 // Some simple testing showed <100,000 RuleData's on large sites.
85 unsigned m_position : 18;
86 unsigned m_matchBasedOnRuleHash : 3;
87 unsigned m_canMatchPseudoElement : 1;
88 unsigned m_containsUncommonAttributeSelector : 1;
89 unsigned m_linkMatchType : 2; // SelectorChecker::LinkMatchMask
90 unsigned m_propertyWhitelistType : 2;
91 SelectorFilter::Hashes m_descendantSelectorIdentifierHashes;
92};
93
94struct SameSizeAsRuleData {
95 void* a;
96 unsigned b;
97 unsigned c;
98 unsigned d[4];
99};
100
101COMPILE_ASSERT(sizeof(RuleData) == sizeof(SameSizeAsRuleData), RuleData_should_stay_small);
102
103class RuleSet {
104 WTF_MAKE_NONCOPYABLE(RuleSet); WTF_MAKE_FAST_ALLOCATED;
105public:
106 struct RuleSetSelectorPair {
107 RuleSetSelectorPair(const CSSSelector* selector, std::unique_ptr<RuleSet> ruleSet) : selector(selector), ruleSet(WTFMove(ruleSet)) { }
108 RuleSetSelectorPair(const RuleSetSelectorPair& pair) : selector(pair.selector), ruleSet(const_cast<RuleSetSelectorPair*>(&pair)->ruleSet.release()) { }
109
110 const CSSSelector* selector;
111 std::unique_ptr<RuleSet> ruleSet;
112 };
113
114 RuleSet();
115 ~RuleSet();
116
117 typedef Vector<RuleData, 1> RuleDataVector;
118 typedef HashMap<AtomicString, std::unique_ptr<RuleDataVector>> AtomRuleMap;
119
120 void addRulesFromSheet(StyleSheetContents&, const MediaQueryEvaluator&, StyleResolver* = 0);
121
122 void addStyleRule(StyleRule*);
123 void addRule(StyleRule*, unsigned selectorIndex, unsigned selectorListIndex);
124 void addPageRule(StyleRulePage*);
125 void addToRuleSet(const AtomicString& key, AtomRuleMap&, const RuleData&);
126 void shrinkToFit();
127 void disableAutoShrinkToFit() { m_autoShrinkToFitEnabled = false; }
128
129 const RuleFeatureSet& features() const { return m_features; }
130
131 const RuleDataVector* idRules(const AtomicString& key) const { return m_idRules.get(key); }
132 const RuleDataVector* classRules(const AtomicString& key) const { return m_classRules.get(key); }
133 const RuleDataVector* tagRules(const AtomicString& key, bool isHTMLName) const;
134 const RuleDataVector* shadowPseudoElementRules(const AtomicString& key) const { return m_shadowPseudoElementRules.get(key); }
135 const RuleDataVector* linkPseudoClassRules() const { return &m_linkPseudoClassRules; }
136#if ENABLE(VIDEO_TRACK)
137 const RuleDataVector* cuePseudoRules() const { return &m_cuePseudoRules; }
138#endif
139 const RuleDataVector& hostPseudoClassRules() const { return m_hostPseudoClassRules; }
140 const RuleDataVector& slottedPseudoElementRules() const { return m_slottedPseudoElementRules; }
141 const RuleDataVector* focusPseudoClassRules() const { return &m_focusPseudoClassRules; }
142 const RuleDataVector* universalRules() const { return &m_universalRules; }
143
144 const Vector<StyleRulePage*>& pageRules() const { return m_pageRules; }
145
146 unsigned ruleCount() const { return m_ruleCount; }
147
148 bool hasShadowPseudoElementRules() const;
149 bool hasHostPseudoClassRulesMatchingInShadowTree() const { return m_hasHostPseudoClassRulesMatchingInShadowTree; }
150
151private:
152 void addChildRules(const Vector<RefPtr<StyleRuleBase>>&, const MediaQueryEvaluator& medium, StyleResolver*, bool isInitiatingElementInUserAgentShadowTree);
153
154 AtomRuleMap m_idRules;
155 AtomRuleMap m_classRules;
156 AtomRuleMap m_tagLocalNameRules;
157 AtomRuleMap m_tagLowercaseLocalNameRules;
158 AtomRuleMap m_shadowPseudoElementRules;
159 RuleDataVector m_linkPseudoClassRules;
160#if ENABLE(VIDEO_TRACK)
161 RuleDataVector m_cuePseudoRules;
162#endif
163 RuleDataVector m_hostPseudoClassRules;
164 RuleDataVector m_slottedPseudoElementRules;
165 RuleDataVector m_focusPseudoClassRules;
166 RuleDataVector m_universalRules;
167 Vector<StyleRulePage*> m_pageRules;
168 unsigned m_ruleCount { 0 };
169 bool m_hasHostPseudoClassRulesMatchingInShadowTree { false };
170 bool m_autoShrinkToFitEnabled { true };
171 RuleFeatureSet m_features;
172};
173
174inline const RuleSet::RuleDataVector* RuleSet::tagRules(const AtomicString& key, bool isHTMLName) const
175{
176 const AtomRuleMap* tagRules;
177 if (isHTMLName)
178 tagRules = &m_tagLowercaseLocalNameRules;
179 else
180 tagRules = &m_tagLocalNameRules;
181 return tagRules->get(key);
182}
183
184} // namespace WebCore
185
186namespace WTF {
187
188// RuleData is simple enough that initializing to 0 and moving with memcpy will totally work.
189template<> struct VectorTraits<WebCore::RuleData> : SimpleClassVectorTraits { };
190
191} // namespace WTF
192