9909173ff9f0fb4597d54903870c397309b29550
[WebKit-https.git] / Source / WebCore / css / RuleSet.h
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 #ifndef RuleSet_h
23 #define RuleSet_h
24
25 #include "RuleFeature.h"
26 #include "SelectorCompiler.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/CString.h>
32
33 namespace WebCore {
34
35 enum AddRuleFlags {
36     RuleHasNoSpecialState         = 0,
37     RuleHasDocumentSecurityOrigin = 1,
38     RuleIsInRegionRule            = 1 << 1,
39 };
40     
41 enum PropertyWhitelistType {
42     PropertyWhitelistNone   = 0,
43     PropertyWhitelistRegion,
44 #if ENABLE(VIDEO_TRACK)
45     PropertyWhitelistCue
46 #endif
47 };
48
49 class CSSSelector;
50 class ContainerNode;
51 class MediaQueryEvaluator;
52 class Node;
53 class StyleResolver;
54 class StyleRuleRegion;
55 class StyleSheetContents;
56
57 enum class MatchBasedOnRuleHash : unsigned {
58     None,
59     Universal,
60     ClassA,
61     ClassB,
62     ClassC
63 };
64
65 class RuleData {
66 public:
67     static const unsigned maximumSelectorComponentCount = 8192;
68
69     RuleData(StyleRule*, unsigned selectorIndex, unsigned position, AddRuleFlags);
70
71     unsigned position() const { return m_position; }
72     StyleRule* rule() const { return m_rule.get(); }
73     const CSSSelector* selector() const { return m_rule->selectorList().selectorAt(m_selectorIndex); }
74     unsigned selectorIndex() const { return m_selectorIndex; }
75
76     bool canMatchPseudoElement() const { return m_canMatchPseudoElement; }
77     MatchBasedOnRuleHash matchBasedOnRuleHash() const { return static_cast<MatchBasedOnRuleHash>(m_matchBasedOnRuleHash); }
78     bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
79     unsigned linkMatchType() const { return m_linkMatchType; }
80     bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
81     PropertyWhitelistType propertyWhitelistType() const { return static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
82     // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance.
83     static const unsigned maximumIdentifierCount = 4;
84     const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }
85
86     void disableSelectorFiltering() { m_descendantSelectorIdentifierHashes[0] = 0; }
87
88 #if ENABLE(CSS_SELECTOR_JIT)
89     SelectorCompilationStatus compilationStatus() const { return m_compilationStatus; }
90     JSC::MacroAssemblerCodeRef compiledSelectorCodeRef() const { return m_compiledSelectorCodeRef; }
91     void setCompiledSelector(SelectorCompilationStatus status, JSC::MacroAssemblerCodeRef codeRef) const
92     {
93         m_compilationStatus = status;
94         m_compiledSelectorCodeRef = codeRef;
95     }
96 #if CSS_SELECTOR_JIT_PROFILING
97     ~RuleData()
98     {
99         if (m_compiledSelectorCodeRef.code().executableAddress())
100             dataLogF("RuleData compiled selector %d \"%s\"\n", m_compiledSelectorUseCount, selector()->selectorText().utf8().data());
101     }
102     void compiledSelectorUsed() const { m_compiledSelectorUseCount++; }
103 #endif
104 #endif // ENABLE(CSS_SELECTOR_JIT)
105
106 private:
107     RefPtr<StyleRule> m_rule;
108     unsigned m_selectorIndex : 13;
109     unsigned m_hasDocumentSecurityOrigin : 1;
110     // This number was picked fairly arbitrarily. We can probably lower it if we need to.
111     // Some simple testing showed <100,000 RuleData's on large sites.
112     unsigned m_position : 18;
113     unsigned m_matchBasedOnRuleHash : 3;
114     unsigned m_canMatchPseudoElement : 1;
115     unsigned m_containsUncommonAttributeSelector : 1;
116     unsigned m_linkMatchType : 2; //  SelectorChecker::LinkMatchMask
117     unsigned m_propertyWhitelistType : 2;
118     // Use plain array instead of a Vector to minimize memory overhead.
119     unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount];
120 #if ENABLE(CSS_SELECTOR_JIT)
121     mutable SelectorCompilationStatus m_compilationStatus;
122     mutable JSC::MacroAssemblerCodeRef m_compiledSelectorCodeRef;
123 #if CSS_SELECTOR_JIT_PROFILING
124     mutable unsigned m_compiledSelectorUseCount;
125 #endif
126 #endif // ENABLE(CSS_SELECTOR_JIT)
127 };
128     
129 struct SameSizeAsRuleData {
130 #if ENABLE(CSS_SELECTOR_JIT)
131     unsigned compilationStatus;
132     void* compiledSelectorPointer;
133     void* codeRefPtr;
134 #if CSS_SELECTOR_JIT_PROFILING
135     unsigned compiledSelectorUseCount;
136 #endif
137 #endif // ENABLE(CSS_SELECTOR_JIT)
138
139     void* a;
140     unsigned b;
141     unsigned c;
142     unsigned d[4];
143 };
144
145 COMPILE_ASSERT(sizeof(RuleData) == sizeof(SameSizeAsRuleData), RuleData_should_stay_small);
146
147 class RuleSet {
148     WTF_MAKE_NONCOPYABLE(RuleSet); WTF_MAKE_FAST_ALLOCATED;
149 public:
150     struct RuleSetSelectorPair {
151         RuleSetSelectorPair(const CSSSelector* selector, std::unique_ptr<RuleSet> ruleSet) : selector(selector), ruleSet(WTFMove(ruleSet)) { }
152         RuleSetSelectorPair(const RuleSetSelectorPair& pair) : selector(pair.selector), ruleSet(const_cast<RuleSetSelectorPair*>(&pair)->ruleSet.release()) { }
153
154         const CSSSelector* selector;
155         std::unique_ptr<RuleSet> ruleSet;
156     };
157
158     RuleSet();
159     ~RuleSet();
160
161     typedef Vector<RuleData, 1> RuleDataVector;
162     typedef HashMap<AtomicStringImpl*, std::unique_ptr<RuleDataVector>> AtomRuleMap;
163
164     void addRulesFromSheet(StyleSheetContents&, const MediaQueryEvaluator&, StyleResolver* = 0);
165
166     void addStyleRule(StyleRule*, AddRuleFlags);
167     void addRule(StyleRule*, unsigned selectorIndex, AddRuleFlags);
168     void addPageRule(StyleRulePage*);
169     void addToRuleSet(AtomicStringImpl* key, AtomRuleMap&, const RuleData&);
170     void addRegionRule(StyleRuleRegion*, bool hasDocumentSecurityOrigin);
171     void shrinkToFit();
172     void disableAutoShrinkToFit() { m_autoShrinkToFitEnabled = false; }
173
174     const RuleFeatureSet& features() const { return m_features; }
175
176     const RuleDataVector* idRules(AtomicStringImpl& key) const { return m_idRules.get(&key); }
177     const RuleDataVector* classRules(AtomicStringImpl* key) const { return m_classRules.get(key); }
178     const RuleDataVector* tagRules(AtomicStringImpl* key, bool isHTMLName) const;
179     const RuleDataVector* shadowPseudoElementRules(AtomicStringImpl* key) const { return m_shadowPseudoElementRules.get(key); }
180     const RuleDataVector* linkPseudoClassRules() const { return &m_linkPseudoClassRules; }
181 #if ENABLE(VIDEO_TRACK)
182     const RuleDataVector* cuePseudoRules() const { return &m_cuePseudoRules; }
183 #endif
184     const RuleDataVector& hostPseudoClassRules() const { return m_hostPseudoClassRules; }
185     const RuleDataVector& slottedPseudoElementRules() const { return m_slottedPseudoElementRules; }
186     const RuleDataVector* focusPseudoClassRules() const { return &m_focusPseudoClassRules; }
187     const RuleDataVector* universalRules() const { return &m_universalRules; }
188
189     const Vector<StyleRulePage*>& pageRules() const { return m_pageRules; }
190     const Vector<RuleSetSelectorPair>& regionSelectorsAndRuleSets() const { return m_regionSelectorsAndRuleSets; }
191
192     unsigned ruleCount() const { return m_ruleCount; }
193
194     bool hasShadowPseudoElementRules() const;
195
196 private:
197     void addChildRules(const Vector<RefPtr<StyleRuleBase>>&, const MediaQueryEvaluator& medium, StyleResolver*, bool hasDocumentSecurityOrigin, bool isInitiatingElementInUserAgentShadowTree, AddRuleFlags);
198
199     AtomRuleMap m_idRules;
200     AtomRuleMap m_classRules;
201     AtomRuleMap m_tagLocalNameRules;
202     AtomRuleMap m_tagLowercaseLocalNameRules;
203     AtomRuleMap m_shadowPseudoElementRules;
204     RuleDataVector m_linkPseudoClassRules;
205 #if ENABLE(VIDEO_TRACK)
206     RuleDataVector m_cuePseudoRules;
207 #endif
208     RuleDataVector m_hostPseudoClassRules;
209     RuleDataVector m_slottedPseudoElementRules;
210     RuleDataVector m_focusPseudoClassRules;
211     RuleDataVector m_universalRules;
212     Vector<StyleRulePage*> m_pageRules;
213     unsigned m_ruleCount { 0 };
214     bool m_autoShrinkToFitEnabled { false };
215     RuleFeatureSet m_features;
216     Vector<RuleSetSelectorPair> m_regionSelectorsAndRuleSets;
217 };
218
219 inline const RuleSet::RuleDataVector* RuleSet::tagRules(AtomicStringImpl* key, bool isHTMLName) const
220 {
221     const AtomRuleMap* tagRules;
222     if (isHTMLName)
223         tagRules = &m_tagLowercaseLocalNameRules;
224     else
225         tagRules = &m_tagLocalNameRules;
226     return tagRules->get(key);
227 }
228
229 } // namespace WebCore
230
231 namespace WTF {
232 // RuleData is simple enough that initializing to 0 and moving with memcpy will totally work.
233 template<> struct VectorTraits<WebCore::RuleData> : SimpleClassVectorTraits { };
234
235 } // namespace WTF
236
237 #endif // RuleSet_h