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