Home | History | Annotate | Download | only in css
      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