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