1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) 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/RuleFeature.h" 26 #include "core/css/StyleRule.h" 27 #include "wtf/Forward.h" 28 #include "wtf/HashMap.h" 29 #include "wtf/LinkedStack.h" 30 31 namespace WebCore { 32 33 enum AddRuleFlags { 34 RuleHasNoSpecialState = 0, 35 RuleHasDocumentSecurityOrigin = 1, 36 RuleCanUseFastCheckSelector = 1 << 1, 37 RuleIsInRegionRule = 1 << 2, 38 }; 39 40 enum PropertyWhitelistType { 41 PropertyWhitelistNone = 0, 42 PropertyWhitelistRegion, 43 PropertyWhitelistCue 44 }; 45 46 class CSSSelector; 47 class ContainerNode; 48 class MediaQueryEvaluator; 49 class StyleResolver; 50 class StyleRuleRegion; 51 class StyleSheetContents; 52 53 class RuleData { 54 WTF_MAKE_FAST_ALLOCATED; 55 public: 56 RuleData(StyleRule*, unsigned selectorIndex, unsigned position, AddRuleFlags); 57 58 unsigned position() const { return m_position; } 59 StyleRule* rule() const { return m_rule; } 60 const CSSSelector* selector() const { return m_rule->selectorList().selectorAt(m_selectorIndex); } 61 unsigned selectorIndex() const { return m_selectorIndex; } 62 63 bool isLastInArray() const { return m_isLastInArray; } 64 void setLastInArray(bool flag) { m_isLastInArray = flag; } 65 66 bool hasFastCheckableSelector() const { return m_hasFastCheckableSelector; } 67 bool hasMultipartSelector() const { return m_hasMultipartSelector; } 68 bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; } 69 bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; } 70 unsigned specificity() const { return m_specificity; } 71 unsigned linkMatchType() const { return m_linkMatchType; } 72 bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; } 73 PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelistType); } 74 // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance. 75 static const unsigned maximumIdentifierCount = 4; 76 const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; } 77 78 private: 79 StyleRule* m_rule; 80 unsigned m_selectorIndex : 12; 81 unsigned m_isLastInArray : 1; // We store an array of RuleData objects in a primitive array. 82 // This number was picked fairly arbitrarily. We can probably lower it if we need to. 83 // Some simple testing showed <100,000 RuleData's on large sites. 84 unsigned m_position : 18; 85 unsigned m_hasFastCheckableSelector : 1; 86 unsigned m_specificity : 24; 87 unsigned m_hasMultipartSelector : 1; 88 unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1; 89 unsigned m_containsUncommonAttributeSelector : 1; 90 unsigned m_linkMatchType : 2; // SelectorChecker::LinkMatchMask 91 unsigned m_hasDocumentSecurityOrigin : 1; 92 unsigned m_propertyWhitelistType : 2; 93 // Use plain array instead of a Vector to minimize memory overhead. 94 unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount]; 95 }; 96 97 struct SameSizeAsRuleData { 98 void* a; 99 unsigned b; 100 unsigned c; 101 unsigned d[4]; 102 }; 103 104 COMPILE_ASSERT(sizeof(RuleData) == sizeof(SameSizeAsRuleData), RuleData_should_stay_small); 105 106 class RuleSet { 107 WTF_MAKE_NONCOPYABLE(RuleSet); WTF_MAKE_FAST_ALLOCATED; 108 public: 109 static PassOwnPtr<RuleSet> create() { return adoptPtr(new RuleSet); } 110 111 void addRulesFromSheet(StyleSheetContents*, const MediaQueryEvaluator&, StyleResolver* = 0, const ContainerNode* = 0); 112 void addStyleRule(StyleRule*, AddRuleFlags); 113 void addRule(StyleRule*, unsigned selectorIndex, AddRuleFlags); 114 115 const RuleFeatureSet& features() const { return m_features; } 116 117 const RuleData* idRules(StringImpl* key) const { ASSERT(!m_pendingRules); return m_idRules.get(key); } 118 const RuleData* classRules(StringImpl* key) const { ASSERT(!m_pendingRules); return m_classRules.get(key); } 119 const RuleData* tagRules(StringImpl* key) const { ASSERT(!m_pendingRules); return m_tagRules.get(key); } 120 const RuleData* shadowPseudoElementRules(StringImpl* key) const { ASSERT(!m_pendingRules); return m_shadowPseudoElementRules.get(key); } 121 const Vector<RuleData>* linkPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_linkPseudoClassRules; } 122 const Vector<RuleData>* cuePseudoRules() const { ASSERT(!m_pendingRules); return &m_cuePseudoRules; } 123 const Vector<RuleData>* focusPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_focusPseudoClassRules; } 124 const Vector<RuleData>* universalRules() const { ASSERT(!m_pendingRules); return &m_universalRules; } 125 const Vector<StyleRulePage*>& pageRules() const { ASSERT(!m_pendingRules); return m_pageRules; } 126 const Vector<StyleRuleViewport*>& viewportRules() const { ASSERT(!m_pendingRules); return m_viewportRules; } 127 128 unsigned ruleCount() const { return m_ruleCount; } 129 130 void compactRulesIfNeeded() 131 { 132 if (!m_pendingRules) 133 return; 134 compactRules(); 135 } 136 137 struct RuleSetSelectorPair { 138 RuleSetSelectorPair(const CSSSelector* selector, PassOwnPtr<RuleSet> ruleSet) : selector(selector), ruleSet(ruleSet) { } 139 RuleSetSelectorPair(const RuleSetSelectorPair& rs) : selector(rs.selector), ruleSet(const_cast<RuleSetSelectorPair*>(&rs)->ruleSet.release()) { } 140 141 const CSSSelector* selector; 142 OwnPtr<RuleSet> ruleSet; 143 }; 144 145 Vector<RuleSetSelectorPair> m_regionSelectorsAndRuleSets; 146 147 private: 148 typedef HashMap<StringImpl*, OwnPtr<LinkedStack<RuleData> > > PendingRuleMap; 149 typedef HashMap<StringImpl*, OwnPtr<RuleData> > CompactRuleMap; 150 151 RuleSet() 152 : m_ruleCount(0) 153 { 154 } 155 156 void addToRuleSet(StringImpl* key, PendingRuleMap&, const RuleData&); 157 void addPageRule(StyleRulePage*); 158 void addViewportRule(StyleRuleViewport*); 159 void addRegionRule(StyleRuleRegion*, bool hasDocumentSecurityOrigin); 160 161 void addChildRules(const Vector<RefPtr<StyleRuleBase> >&, const MediaQueryEvaluator& medium, StyleResolver*, const ContainerNode* scope, bool hasDocumentSecurityOrigin, AddRuleFlags); 162 bool findBestRuleSetAndAdd(const CSSSelector*, RuleData&); 163 164 void compactRules(); 165 static void compactPendingRules(PendingRuleMap&, CompactRuleMap&); 166 167 struct PendingRuleMaps { 168 PendingRuleMap idRules; 169 PendingRuleMap classRules; 170 PendingRuleMap tagRules; 171 PendingRuleMap shadowPseudoElementRules; 172 }; 173 174 PendingRuleMaps* ensurePendingRules() 175 { 176 if (!m_pendingRules) 177 m_pendingRules = adoptPtr(new PendingRuleMaps); 178 return m_pendingRules.get(); 179 } 180 181 CompactRuleMap m_idRules; 182 CompactRuleMap m_classRules; 183 CompactRuleMap m_tagRules; 184 CompactRuleMap m_shadowPseudoElementRules; 185 Vector<RuleData> m_linkPseudoClassRules; 186 Vector<RuleData> m_cuePseudoRules; 187 Vector<RuleData> m_focusPseudoClassRules; 188 Vector<RuleData> m_universalRules; 189 RuleFeatureSet m_features; 190 Vector<StyleRulePage*> m_pageRules; 191 Vector<StyleRuleViewport*> m_viewportRules; 192 193 unsigned m_ruleCount; 194 OwnPtr<PendingRuleMaps> m_pendingRules; 195 }; 196 197 } // namespace WebCore 198 199 #endif // RuleSet_h 200