1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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 "core/css/CSSKeyframesRule.h"
26#include "core/css/MediaQueryEvaluator.h"
27#include "core/css/RuleFeature.h"
28#include "core/css/StyleRule.h"
29#include "core/css/resolver/MediaQueryResult.h"
30#include "platform/heap/HeapLinkedStack.h"
31#include "platform/heap/HeapTerminatedArray.h"
32#include "wtf/Forward.h"
33#include "wtf/HashMap.h"
34#include "wtf/LinkedStack.h"
35#include "wtf/TerminatedArray.h"
36
37namespace blink {
38
39enum AddRuleFlags {
40    RuleHasNoSpecialState         = 0,
41    RuleHasDocumentSecurityOrigin = 1,
42    RuleCanUseFastCheckSelector   = 1 << 1,
43};
44
45enum PropertyWhitelistType {
46    PropertyWhitelistNone   = 0,
47    PropertyWhitelistCue,
48    PropertyWhitelistFirstLetter,
49};
50
51class CSSSelector;
52class MediaQueryEvaluator;
53class StyleSheetContents;
54
55class MinimalRuleData {
56    ALLOW_ONLY_INLINE_ALLOCATION();
57public:
58    MinimalRuleData(StyleRule* rule, unsigned selectorIndex, AddRuleFlags flags)
59    : m_rule(rule)
60    , m_selectorIndex(selectorIndex)
61    , m_flags(flags)
62    {
63    }
64
65    void trace(Visitor*);
66
67    RawPtrWillBeMember<StyleRule> m_rule;
68    unsigned m_selectorIndex;
69    AddRuleFlags m_flags;
70};
71
72class RuleData {
73    ALLOW_ONLY_INLINE_ALLOCATION();
74public:
75    RuleData(StyleRule*, unsigned selectorIndex, unsigned position, AddRuleFlags);
76
77    unsigned position() const { return m_position; }
78    StyleRule* rule() const { return m_rule; }
79    const CSSSelector& selector() const { return m_rule->selectorList().selectorAt(m_selectorIndex); }
80    unsigned selectorIndex() const { return m_selectorIndex; }
81
82    bool isLastInArray() const { return m_isLastInArray; }
83    void setLastInArray(bool flag) { m_isLastInArray = flag; }
84
85    bool hasMultipartSelector() const { return m_hasMultipartSelector; }
86    bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; }
87    bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
88    unsigned specificity() const { return m_specificity; }
89    unsigned linkMatchType() const { return m_linkMatchType; }
90    bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
91    PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
92    // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance.
93    static const unsigned maximumIdentifierCount = 4;
94    const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }
95
96    void trace(Visitor*);
97
98private:
99    RawPtrWillBeMember<StyleRule> m_rule;
100    unsigned m_selectorIndex : 12;
101    unsigned m_isLastInArray : 1; // We store an array of RuleData objects in a primitive array.
102    // This number was picked fairly arbitrarily. We can probably lower it if we need to.
103    // Some simple testing showed <100,000 RuleData's on large sites.
104    unsigned m_position : 18;
105    unsigned m_specificity : 24;
106    unsigned m_hasMultipartSelector : 1;
107    unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1;
108    unsigned m_containsUncommonAttributeSelector : 1;
109    unsigned m_linkMatchType : 2; //  SelectorChecker::LinkMatchMask
110    unsigned m_hasDocumentSecurityOrigin : 1;
111    unsigned m_propertyWhitelistType : 2;
112    // Use plain array instead of a Vector to minimize memory overhead.
113    unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount];
114};
115
116struct SameSizeAsRuleData {
117    void* a;
118    unsigned b;
119    unsigned c;
120    unsigned d[4];
121};
122
123COMPILE_ASSERT(sizeof(RuleData) == sizeof(SameSizeAsRuleData), RuleData_should_stay_small);
124
125class RuleSet : public NoBaseWillBeGarbageCollectedFinalized<RuleSet> {
126    WTF_MAKE_NONCOPYABLE(RuleSet);
127    WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
128public:
129    static PassOwnPtrWillBeRawPtr<RuleSet> create() { return adoptPtrWillBeNoop(new RuleSet); }
130
131    void addRulesFromSheet(StyleSheetContents*, const MediaQueryEvaluator&, AddRuleFlags = RuleHasNoSpecialState);
132    void addStyleRule(StyleRule*, AddRuleFlags);
133    void addRule(StyleRule*, unsigned selectorIndex, AddRuleFlags);
134
135    const RuleFeatureSet& features() const { return m_features; }
136
137    const WillBeHeapTerminatedArray<RuleData>* idRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_idRules.get(key); }
138    const WillBeHeapTerminatedArray<RuleData>* classRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_classRules.get(key); }
139    const WillBeHeapTerminatedArray<RuleData>* tagRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_tagRules.get(key); }
140    const WillBeHeapTerminatedArray<RuleData>* shadowPseudoElementRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_shadowPseudoElementRules.get(key); }
141    const WillBeHeapVector<RuleData>* linkPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_linkPseudoClassRules; }
142    const WillBeHeapVector<RuleData>* cuePseudoRules() const { ASSERT(!m_pendingRules); return &m_cuePseudoRules; }
143    const WillBeHeapVector<RuleData>* focusPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_focusPseudoClassRules; }
144    const WillBeHeapVector<RuleData>* universalRules() const { ASSERT(!m_pendingRules); return &m_universalRules; }
145    const WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> >& pageRules() const { ASSERT(!m_pendingRules); return m_pageRules; }
146    const WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport> >& viewportRules() const { ASSERT(!m_pendingRules); return m_viewportRules; }
147    const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> >& fontFaceRules() const { return m_fontFaceRules; }
148    const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> >& keyframesRules() const { return m_keyframesRules; }
149    const WillBeHeapVector<MinimalRuleData>& treeBoundaryCrossingRules() const { return m_treeBoundaryCrossingRules; }
150    const WillBeHeapVector<MinimalRuleData>& shadowDistributedRules() const { return m_shadowDistributedRules; }
151    const MediaQueryResultList& viewportDependentMediaQueryResults() const { return m_viewportDependentMediaQueryResults; }
152
153    unsigned ruleCount() const { return m_ruleCount; }
154
155    void compactRulesIfNeeded()
156    {
157        if (!m_pendingRules)
158            return;
159        compactRules();
160    }
161
162#ifndef NDEBUG
163    void show();
164#endif
165
166    void trace(Visitor*);
167
168private:
169    typedef WillBeHeapHashMap<AtomicString, OwnPtrWillBeMember<WillBeHeapLinkedStack<RuleData> > > PendingRuleMap;
170    typedef WillBeHeapHashMap<AtomicString, OwnPtrWillBeMember<WillBeHeapTerminatedArray<RuleData> > > CompactRuleMap;
171
172    RuleSet()
173        : m_ruleCount(0)
174    {
175    }
176
177    void addToRuleSet(const AtomicString& key, PendingRuleMap&, const RuleData&);
178    void addPageRule(StyleRulePage*);
179    void addViewportRule(StyleRuleViewport*);
180    void addFontFaceRule(StyleRuleFontFace*);
181    void addKeyframesRule(StyleRuleKeyframes*);
182
183    void addChildRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >&, const MediaQueryEvaluator& medium, AddRuleFlags);
184    bool findBestRuleSetAndAdd(const CSSSelector&, RuleData&);
185
186    void compactRules();
187    static void compactPendingRules(PendingRuleMap&, CompactRuleMap&);
188
189    class PendingRuleMaps : public NoBaseWillBeGarbageCollected<PendingRuleMaps> {
190    public:
191        static PassOwnPtrWillBeRawPtr<PendingRuleMaps> create() { return adoptPtrWillBeNoop(new PendingRuleMaps); }
192
193        PendingRuleMap idRules;
194        PendingRuleMap classRules;
195        PendingRuleMap tagRules;
196        PendingRuleMap shadowPseudoElementRules;
197
198        void trace(Visitor*);
199
200    private:
201        PendingRuleMaps() { }
202    };
203
204    PendingRuleMaps* ensurePendingRules()
205    {
206        if (!m_pendingRules)
207            m_pendingRules = PendingRuleMaps::create();
208        return m_pendingRules.get();
209    }
210
211    CompactRuleMap m_idRules;
212    CompactRuleMap m_classRules;
213    CompactRuleMap m_tagRules;
214    CompactRuleMap m_shadowPseudoElementRules;
215    WillBeHeapVector<RuleData> m_linkPseudoClassRules;
216    WillBeHeapVector<RuleData> m_cuePseudoRules;
217    WillBeHeapVector<RuleData> m_focusPseudoClassRules;
218    WillBeHeapVector<RuleData> m_universalRules;
219    RuleFeatureSet m_features;
220    WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> > m_pageRules;
221    WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport> > m_viewportRules;
222    WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> > m_fontFaceRules;
223    WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> > m_keyframesRules;
224    WillBeHeapVector<MinimalRuleData> m_treeBoundaryCrossingRules;
225    WillBeHeapVector<MinimalRuleData> m_shadowDistributedRules;
226
227    MediaQueryResultList m_viewportDependentMediaQueryResults;
228
229    unsigned m_ruleCount;
230    OwnPtrWillBeMember<PendingRuleMaps> m_pendingRules;
231
232#ifndef NDEBUG
233    WillBeHeapVector<RuleData> m_allRules;
234#endif
235};
236
237} // namespace blink
238
239WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::RuleData);
240WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::MinimalRuleData);
241
242#endif // RuleSet_h
243