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 37 namespace WebCore { 38 39 enum AddRuleFlags { 40 RuleHasNoSpecialState = 0, 41 RuleHasDocumentSecurityOrigin = 1, 42 RuleCanUseFastCheckSelector = 1 << 1, 43 }; 44 45 enum PropertyWhitelistType { 46 PropertyWhitelistNone = 0, 47 PropertyWhitelistCue, 48 PropertyWhitelistFirstLetter, 49 }; 50 51 class CSSSelector; 52 class MediaQueryEvaluator; 53 class StyleSheetContents; 54 55 class MinimalRuleData { 56 ALLOW_ONLY_INLINE_ALLOCATION(); 57 public: MinimalRuleData(StyleRule * rule,unsigned selectorIndex,AddRuleFlags flags)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 72 class RuleData { 73 ALLOW_ONLY_INLINE_ALLOCATION(); 74 public: 75 RuleData(StyleRule*, unsigned selectorIndex, unsigned position, AddRuleFlags); 76 position()77 unsigned position() const { return m_position; } rule()78 StyleRule* rule() const { return m_rule; } selector()79 const CSSSelector& selector() const { return m_rule->selectorList().selectorAt(m_selectorIndex); } selectorIndex()80 unsigned selectorIndex() const { return m_selectorIndex; } 81 isLastInArray()82 bool isLastInArray() const { return m_isLastInArray; } setLastInArray(bool flag)83 void setLastInArray(bool flag) { m_isLastInArray = flag; } 84 hasMultipartSelector()85 bool hasMultipartSelector() const { return m_hasMultipartSelector; } hasRightmostSelectorMatchingHTMLBasedOnRuleHash()86 bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; } containsUncommonAttributeSelector()87 bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; } specificity()88 unsigned specificity() const { return m_specificity; } linkMatchType()89 unsigned linkMatchType() const { return m_linkMatchType; } hasDocumentSecurityOrigin()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; descendantSelectorIdentifierHashes()94 const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; } 95 96 void trace(Visitor*); 97 98 private: 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 116 struct SameSizeAsRuleData { 117 void* a; 118 unsigned b; 119 unsigned c; 120 unsigned d[4]; 121 }; 122 123 COMPILE_ASSERT(sizeof(RuleData) == sizeof(SameSizeAsRuleData), RuleData_should_stay_small); 124 125 class RuleSet : public NoBaseWillBeGarbageCollectedFinalized<RuleSet> { 126 WTF_MAKE_NONCOPYABLE(RuleSet); 127 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; 128 public: create()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 features()135 const RuleFeatureSet& features() const { return m_features; } 136 idRules(const AtomicString & key)137 const WillBeHeapTerminatedArray<RuleData>* idRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_idRules.get(key); } classRules(const AtomicString & key)138 const WillBeHeapTerminatedArray<RuleData>* classRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_classRules.get(key); } tagRules(const AtomicString & key)139 const WillBeHeapTerminatedArray<RuleData>* tagRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_tagRules.get(key); } shadowPseudoElementRules(const AtomicString & key)140 const WillBeHeapTerminatedArray<RuleData>* shadowPseudoElementRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_shadowPseudoElementRules.get(key); } linkPseudoClassRules()141 const WillBeHeapVector<RuleData>* linkPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_linkPseudoClassRules; } cuePseudoRules()142 const WillBeHeapVector<RuleData>* cuePseudoRules() const { ASSERT(!m_pendingRules); return &m_cuePseudoRules; } focusPseudoClassRules()143 const WillBeHeapVector<RuleData>* focusPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_focusPseudoClassRules; } universalRules()144 const WillBeHeapVector<RuleData>* universalRules() const { ASSERT(!m_pendingRules); return &m_universalRules; } pageRules()145 const WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> >& pageRules() const { ASSERT(!m_pendingRules); return m_pageRules; } viewportRules()146 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport> >& viewportRules() const { ASSERT(!m_pendingRules); return m_viewportRules; } fontFaceRules()147 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> >& fontFaceRules() const { return m_fontFaceRules; } keyframesRules()148 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> >& keyframesRules() const { return m_keyframesRules; } treeBoundaryCrossingRules()149 const WillBeHeapVector<MinimalRuleData>& treeBoundaryCrossingRules() const { return m_treeBoundaryCrossingRules; } shadowDistributedRules()150 const WillBeHeapVector<MinimalRuleData>& shadowDistributedRules() const { return m_shadowDistributedRules; } viewportDependentMediaQueryResults()151 const MediaQueryResultList& viewportDependentMediaQueryResults() const { return m_viewportDependentMediaQueryResults; } 152 ruleCount()153 unsigned ruleCount() const { return m_ruleCount; } 154 compactRulesIfNeeded()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 168 private: 169 typedef WillBeHeapHashMap<AtomicString, OwnPtrWillBeMember<WillBeHeapLinkedStack<RuleData> > > PendingRuleMap; 170 typedef WillBeHeapHashMap<AtomicString, OwnPtrWillBeMember<WillBeHeapTerminatedArray<RuleData> > > CompactRuleMap; 171 RuleSet()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: create()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: PendingRuleMaps()201 PendingRuleMaps() { } 202 }; 203 ensurePendingRules()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 WebCore 238 239 WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(WebCore::RuleData); 240 WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(WebCore::MinimalRuleData); 241 242 #endif // RuleSet_h 243