Home | History | Annotate | Download | only in resolver
      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 StyleResolver_h
     23 #define StyleResolver_h
     24 
     25 #include "core/animation/KeyframeAnimationEffect.h"
     26 #include "core/css/DocumentRuleSets.h"
     27 #include "core/css/InspectorCSSOMWrappers.h"
     28 #include "core/css/PseudoStyleRequest.h"
     29 #include "core/css/RuleFeature.h"
     30 #include "core/css/RuleSet.h"
     31 #include "core/css/SelectorChecker.h"
     32 #include "core/css/SelectorFilter.h"
     33 #include "core/css/SiblingTraversalStrategies.h"
     34 #include "core/css/resolver/MatchedPropertiesCache.h"
     35 #include "core/css/resolver/ScopedStyleResolver.h"
     36 #include "core/css/resolver/StyleBuilder.h"
     37 #include "core/css/resolver/StyleResolverState.h"
     38 #include "core/css/resolver/StyleResourceLoader.h"
     39 #include "wtf/HashMap.h"
     40 #include "wtf/HashSet.h"
     41 #include "wtf/RefPtr.h"
     42 #include "wtf/Vector.h"
     43 
     44 namespace WebCore {
     45 
     46 class CSSAnimationUpdate;
     47 class CSSFontSelector;
     48 class CSSRuleList;
     49 class CSSSelector;
     50 class CSSStyleSheet;
     51 class CSSValue;
     52 class ContainerNode;
     53 class Document;
     54 class DocumentTimeline;
     55 class Element;
     56 class ElementRuleCollector;
     57 class KeyframeList;
     58 class KeyframeValue;
     59 class MediaQueryEvaluator;
     60 class MediaQueryExp;
     61 class MediaQueryResult;
     62 class RenderRegion;
     63 class RuleData;
     64 class Settings;
     65 class StyleKeyframe;
     66 class StylePropertySet;
     67 class StyleRule;
     68 class StyleRuleKeyframes;
     69 class StyleRulePage;
     70 class ViewportStyleResolver;
     71 
     72 struct MatchResult;
     73 
     74 enum StyleSharingBehavior {
     75     AllowStyleSharing,
     76     DisallowStyleSharing,
     77 };
     78 
     79 // MatchOnlyUserAgentRules is used in media queries, where relative units
     80 // are interpreted according to the document root element style, and styled only
     81 // from the User Agent Stylesheet rules.
     82 enum RuleMatchingBehavior {
     83     MatchAllRules,
     84     MatchAllRulesExcludingSMIL,
     85     MatchOnlyUserAgentRules,
     86 };
     87 
     88 #undef STYLE_STATS
     89 
     90 #ifdef STYLE_STATS
     91 struct StyleSharingStats {
     92     void addSearch() { ++m_searches; ++m_totalSearches; }
     93     void addElementEligibleForSharing() { ++m_elementsEligibleForSharing; ++m_totalElementsEligibleForSharing; }
     94     void addStyleShared() { ++m_stylesShared; ++m_totalStylesShared; }
     95     void addSearchFoundSiblingForSharing() { ++m_searchFoundSiblingForSharing; ++m_totalSearchFoundSiblingForSharing; }
     96     void addSearchMissedSharing() { ++m_searchesMissedSharing; ++m_totalSearchesMissedSharing; }
     97     void addMatchedPropertiesSearch() { ++m_matchedPropertiesSearches; ++m_totalMatchedPropertiesSearches; }
     98     void addMatchedPropertiesHit() { ++m_matchedPropertiesHit; ++m_totalMatchedPropertiesHit; }
     99     void addMatchedPropertiesHitSharedInherited() { ++m_matchedPropertiesSharedInheritedHit; ++m_totalMatchedPropertiesSharedInheritedHit; }
    100     void addMatchedPropertiesToCache() { ++m_matchedPropertiesToCache; ++m_totalMatchedPropertiesToCache; }
    101     void addMatchedPropertiesEnteredIntoCache() { ++m_matchedPropertiesEnteredIntoCache; ++m_totalMatchedPropertiesEnteredIntoCache; }
    102 
    103     void clear()
    104     {
    105         m_searches = m_elementsEligibleForSharing = m_stylesShared = m_searchesMissedSharing = m_searchFoundSiblingForSharing =
    106             m_matchedPropertiesSearches = m_matchedPropertiesHit = m_matchedPropertiesSharedInheritedHit = m_matchedPropertiesToCache =
    107             m_matchedPropertiesEnteredIntoCache = 0;
    108     }
    109 
    110     void printStats() const;
    111 
    112     unsigned m_searches;
    113     unsigned m_elementsEligibleForSharing;
    114     unsigned m_stylesShared;
    115     unsigned m_searchFoundSiblingForSharing;
    116     unsigned m_searchesMissedSharing;
    117     unsigned m_matchedPropertiesSearches;
    118     unsigned m_matchedPropertiesHit;
    119     unsigned m_matchedPropertiesSharedInheritedHit;
    120     unsigned m_matchedPropertiesToCache;
    121     unsigned m_matchedPropertiesEnteredIntoCache;
    122 
    123     unsigned m_totalSearches;
    124     unsigned m_totalElementsEligibleForSharing;
    125     unsigned m_totalStylesShared;
    126     unsigned m_totalSearchFoundSiblingForSharing;
    127     unsigned m_totalSearchesMissedSharing;
    128     unsigned m_totalMatchedPropertiesSearches;
    129     unsigned m_totalMatchedPropertiesHit;
    130     unsigned m_totalMatchedPropertiesSharedInheritedHit;
    131     unsigned m_totalMatchedPropertiesToCache;
    132     unsigned m_totalMatchedPropertiesEnteredIntoCache;
    133 };
    134 
    135 #define STYLE_STATS_ADD_SEARCH() StyleResolver::styleSharingStats().addSearch();
    136 #define STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING() StyleResolver::styleSharingStats().addElementEligibleForSharing();
    137 #define STYLE_STATS_ADD_STYLE_SHARED() StyleResolver::styleSharingStats().addStyleShared();
    138 #define STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING() StyleResolver::styleSharingStats().addSearchFoundSiblingForSharing();
    139 #define STYLE_STATS_ADD_SEARCH_MISSED_SHARING() StyleResolver::styleSharingStats().addSearchMissedSharing();
    140 #define STYLE_STATS_PRINT() StyleResolver::styleSharingStats().printStats();
    141 #define STYLE_STATS_CLEAR() StyleResolver::styleSharingStats().clear();
    142 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_SEARCH() StyleResolver::styleSharingStats().addMatchedPropertiesSearch();
    143 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_HIT() StyleResolver::styleSharingStats().addMatchedPropertiesHit();
    144 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_HIT_SHARED_INHERITED() StyleResolver::styleSharingStats().addMatchedPropertiesHitSharedInherited();
    145 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_TO_CACHE() StyleResolver::styleSharingStats().addMatchedPropertiesToCache();
    146 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_ENTERED_INTO_CACHE() StyleResolver::styleSharingStats().addMatchedPropertiesEnteredIntoCache();
    147 #else
    148 #define STYLE_STATS_ADD_SEARCH() (void(0));
    149 #define STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING() (void(0));
    150 #define STYLE_STATS_ADD_STYLE_SHARED() (void(0));
    151 #define STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING() (void(0));
    152 #define STYLE_STATS_ADD_SEARCH_MISSED_SHARING() (void(0));
    153 #define STYLE_STATS_PRINT() (void(0));
    154 #define STYLE_STATS_CLEAR() (void(0));
    155 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_SEARCH() (void(0));
    156 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_HIT() (void(0));
    157 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_HIT_SHARED_INHERITED() (void(0));
    158 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_TO_CACHE() (void(0));
    159 #define STYLE_STATS_ADD_MATCHED_PROPERTIES_ENTERED_INTO_CACHE() (void(0));
    160 #endif
    161 
    162 struct CSSPropertyValue {
    163     CSSPropertyValue(CSSPropertyID property, CSSValue* value)
    164         : property(property), value(value) { }
    165     // Stores value=propertySet.getPropertyCSSValue(id).get().
    166     CSSPropertyValue(CSSPropertyID, const StylePropertySet&);
    167     CSSPropertyID property;
    168     CSSValue* value;
    169 };
    170 
    171 // This class selects a RenderStyle for a given element based on a collection of stylesheets.
    172 class StyleResolver {
    173     WTF_MAKE_NONCOPYABLE(StyleResolver); WTF_MAKE_FAST_ALLOCATED;
    174 public:
    175     StyleResolver(Document*, bool matchAuthorAndUserStyles);
    176     ~StyleResolver();
    177 
    178     // FIXME: StyleResolver should not be keeping tree-walk state.
    179     // These should move to some global tree-walk state, or should be contained in a
    180     // TreeWalkContext or similar which is passed in to StyleResolver methods when available.
    181     // Using these during tree walk will allow style selector to optimize child and descendant selector lookups.
    182     void pushParentElement(Element*);
    183     void popParentElement(Element*);
    184     void pushParentShadowRoot(const ShadowRoot*);
    185     void popParentShadowRoot(const ShadowRoot*);
    186 
    187     PassRefPtr<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle = 0, StyleSharingBehavior = AllowStyleSharing,
    188         RuleMatchingBehavior = MatchAllRules, RenderRegion* regionForStyling = 0);
    189 
    190     // FIXME: The following logic related to animations and keyframes should be factored out of StyleResolver
    191     // The body of calculateCSSAnimationUpdate can move to CSSAnimations.cpp and take just const element, const style,
    192     // and const ScopedStyleTree
    193     PassOwnPtr<CSSAnimationUpdate> calculateCSSAnimationUpdate(StyleResolverState&);
    194     void resolveKeyframes(Element*, const RenderStyle*, const StringImpl* animationName, KeyframeAnimationEffect::KeyframeVector&);
    195     const StylePropertySet* firstKeyframeStyles(const Element*, const StringImpl* animationName);
    196     void keyframeStylesForAnimation(Element*, const RenderStyle*, KeyframeList&);
    197     const StyleRuleKeyframes* matchScopedKeyframesRule(const Element*, const StringImpl* animationName);
    198     PassRefPtr<RenderStyle> styleForKeyframe(Element*, const RenderStyle*, const StyleKeyframe*);
    199 
    200     PassRefPtr<RenderStyle> pseudoStyleForElement(Element*, const PseudoStyleRequest&, RenderStyle* parentStyle);
    201 
    202     PassRefPtr<RenderStyle> styleForPage(int pageIndex);
    203     PassRefPtr<RenderStyle> defaultStyleForElement();
    204     PassRefPtr<RenderStyle> styleForText(Text*);
    205 
    206     static PassRefPtr<RenderStyle> styleForDocument(const Document*, CSSFontSelector* = 0);
    207 
    208     // FIXME: This only has 5 callers and should be removed. Callers should be explicit about
    209     // their dependency on Document* instead of grabbing one through StyleResolver.
    210     Document* document() { return m_document; }
    211 
    212     // FIXME: It could be better to call m_ruleSets.appendAuthorStyleSheets() directly after we factor StyleRsolver further.
    213     // https://bugs.webkit.org/show_bug.cgi?id=108890
    214     void appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >&);
    215     // FIXME: resetAuthorStyle() will be removed when rulesets are reset in a per-scoping node manner.
    216     void resetAuthorStyle();
    217     void resetAuthorStyle(const ContainerNode*);
    218     void resetAtHostRules(const ContainerNode*);
    219 
    220     DocumentRuleSets& ruleSets() { return m_ruleSets; }
    221     const DocumentRuleSets& ruleSets() const { return m_ruleSets; }
    222     SelectorFilter& selectorFilter() { return m_selectorFilter; }
    223 
    224     void setBuildScopedStyleTreeInDocumentOrder(bool enabled) { m_styleTree.setBuildInDocumentOrder(enabled); }
    225     bool buildScopedStyleTreeInDocumentOrder() const { return m_styleTree.buildInDocumentOrder(); }
    226 
    227     ScopedStyleResolver* ensureScopedStyleResolver(const ContainerNode* scope)
    228     {
    229         return m_styleTree.ensureScopedStyleResolver(scope ? scope : document());
    230     }
    231 
    232     // FIXME: Used by SharingStyleFinder, but should be removed.
    233     bool styleSharingCandidateMatchesRuleSet(const ElementResolveContext&, RenderStyle*, RuleSet*);
    234 
    235     // These methods will give back the set of rules that matched for a given element (or a pseudo-element).
    236     enum CSSRuleFilter {
    237         UAAndUserCSSRules   = 1 << 1,
    238         AuthorCSSRules      = 1 << 2,
    239         EmptyCSSRules       = 1 << 3,
    240         CrossOriginCSSRules = 1 << 4,
    241         AllButEmptyCSSRules = UAAndUserCSSRules | AuthorCSSRules | CrossOriginCSSRules,
    242         AllCSSRules         = AllButEmptyCSSRules | EmptyCSSRules,
    243     };
    244     PassRefPtr<CSSRuleList> styleRulesForElement(Element*, unsigned rulesToInclude = AllButEmptyCSSRules);
    245     PassRefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, PseudoId, unsigned rulesToInclude = AllButEmptyCSSRules);
    246 
    247     // |properties| is an array with |count| elements.
    248     void applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle*);
    249 
    250     CSSFontSelector* fontSelector() const { return m_fontSelector.get(); }
    251     ViewportStyleResolver* viewportStyleResolver() { return m_viewportStyleResolver.get(); }
    252 
    253     // FIXME: This logic belongs in MediaQueryEvaluator.
    254     void addViewportDependentMediaQueryResult(const MediaQueryExp*, bool result);
    255     bool hasViewportDependentMediaQueries() const { return !m_viewportDependentMediaQueryResults.isEmpty(); }
    256     bool affectedByViewportChange() const;
    257 
    258     // FIXME: This likely belongs on RuleSet.
    259     void addKeyframeStyle(PassRefPtr<StyleRuleKeyframes>);
    260 
    261     // FIXME: Regions should not require special logic in StyleResolver.
    262     bool checkRegionStyle(Element* regionElement);
    263 
    264     // FIXME: Rename to reflect the purpose, like didChangeFontSize or something.
    265     void invalidateMatchedPropertiesCache();
    266 
    267     // Exposed for RenderStyle::isStyleAvilable().
    268     static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; }
    269 
    270     // FIXME: StyleResolver should not have this member or method.
    271     InspectorCSSOMWrappers& inspectorCSSOMWrappers() { return m_inspectorCSSOMWrappers; }
    272 
    273     // Exposed for ScopedStyleResolver.
    274     // FIXME: Likely belongs on viewportStyleResolver.
    275     void collectViewportRules(RuleSet*);
    276 
    277     const RuleFeatureSet& ruleFeatureSet() const { return m_features; }
    278 
    279 #ifdef STYLE_STATS
    280     ALWAYS_INLINE static StyleSharingStats& styleSharingStats() { return m_styleSharingStats; }
    281 #endif
    282 private:
    283     // FIXME: This should probably go away, folded into FontBuilder.
    284     void updateFont(StyleResolverState&);
    285 
    286     void matchUARules(ElementRuleCollector&, RuleSet*);
    287     void matchAuthorRules(Element*, ElementRuleCollector&, bool includeEmptyRules);
    288     void matchShadowDistributedRules(ElementRuleCollector&, bool includeEmptyRules);
    289     void matchScopedAuthorRulesForShadowHost(Element*, ElementRuleCollector&, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree);
    290     void matchHostRules(Element*, ScopedStyleResolver*, ElementRuleCollector&, bool includeEmptyRules);
    291     void matchScopedAuthorRules(Element*, ElementRuleCollector&, bool includeEmptyRules);
    292     void matchAllRules(StyleResolverState&, ElementRuleCollector&, bool matchAuthorAndUserStyles, bool includeSMILProperties);
    293     void matchUARules(ElementRuleCollector&);
    294     void matchUserRules(ElementRuleCollector&, bool includeEmptyRules);
    295     void collectFeatures();
    296 
    297     bool fastRejectSelector(const RuleData&) const;
    298 
    299     void applyMatchedProperties(StyleResolverState&, const MatchResult&);
    300 
    301     enum StyleApplicationPass {
    302         VariableDefinitions,
    303         AnimationProperties,
    304         HighPriorityProperties,
    305         LowPriorityProperties
    306     };
    307     template <StyleResolver::StyleApplicationPass pass>
    308     static inline bool isPropertyForPass(CSSPropertyID);
    309     template <StyleApplicationPass pass>
    310     void applyMatchedProperties(StyleResolverState&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
    311     template <StyleApplicationPass pass>
    312     void applyProperties(StyleResolverState&, const StylePropertySet* properties, StyleRule*, bool isImportant, bool inheritedOnly, PropertyWhitelistType = PropertyWhitelistNone);
    313     template <StyleApplicationPass pass>
    314     void applyAnimatedProperties(StyleResolverState&, const Element*, const DocumentTimeline*, const CSSAnimationUpdate*);
    315     void matchPageRules(MatchResult&, RuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName);
    316     void matchPageRulesForList(Vector<StyleRulePage*>& matchedRules, const Vector<StyleRulePage*>&, bool isLeftPage, bool isFirstPage, const String& pageName);
    317     void collectViewportRules();
    318     Settings* documentSettings() { return m_document->settings(); }
    319 
    320     bool isLeftPage(int pageIndex) const;
    321     bool isRightPage(int pageIndex) const { return !isLeftPage(pageIndex); }
    322     bool isFirstPage(int pageIndex) const;
    323     String pageName(int pageIndex) const;
    324 
    325     DocumentRuleSets m_ruleSets;
    326 
    327     // FIXME: This likely belongs on RuleSet.
    328     typedef HashMap<StringImpl*, RefPtr<StyleRuleKeyframes> > KeyframesRuleMap;
    329     KeyframesRuleMap m_keyframesRuleMap;
    330 
    331     static RenderStyle* s_styleNotYetAvailable;
    332 
    333     void cacheBorderAndBackground();
    334 
    335     MatchedPropertiesCache m_matchedPropertiesCache;
    336 
    337     OwnPtr<MediaQueryEvaluator> m_medium;
    338     RefPtr<RenderStyle> m_rootDefaultStyle;
    339 
    340     Document* m_document;
    341     SelectorFilter m_selectorFilter;
    342 
    343     bool m_matchAuthorAndUserStyles;
    344 
    345     RefPtr<CSSFontSelector> m_fontSelector;
    346     Vector<OwnPtr<MediaQueryResult> > m_viewportDependentMediaQueryResults;
    347 
    348     RefPtr<ViewportStyleResolver> m_viewportStyleResolver;
    349 
    350     ScopedStyleTree m_styleTree;
    351 
    352     // FIXME: The entire logic of collecting features on StyleResolver, as well astransferring them
    353     // between various parts of machinery smells wrong. This needs to be better somehow.
    354     RuleFeatureSet m_features;
    355     OwnPtr<RuleSet> m_siblingRuleSet;
    356     OwnPtr<RuleSet> m_uncommonAttributeRuleSet;
    357 
    358     InspectorCSSOMWrappers m_inspectorCSSOMWrappers;
    359 
    360     StyleResourceLoader m_styleResourceLoader;
    361 
    362 #ifdef STYLE_STATS
    363     static StyleSharingStats m_styleSharingStats;
    364 #endif
    365 };
    366 
    367 inline bool checkRegionSelector(const CSSSelector* regionSelector, Element* regionElement)
    368 {
    369     if (!regionSelector || !regionElement)
    370         return false;
    371 
    372     SelectorChecker selectorChecker(regionElement->document(), SelectorChecker::QueryingRules);
    373     for (const CSSSelector* s = regionSelector; s; s = CSSSelectorList::next(s)) {
    374         SelectorChecker::SelectorCheckingContext selectorCheckingContext(s, regionElement, SelectorChecker::VisitedMatchDisabled);
    375         PseudoId ignoreDynamicPseudo = NOPSEUDO;
    376         if (selectorChecker.match(selectorCheckingContext, ignoreDynamicPseudo, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches)
    377             return true;
    378     }
    379     return false;
    380 }
    381 
    382 } // namespace WebCore
    383 
    384 #endif // StyleResolver_h
    385