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/InspectorCSSOMWrappers.h" 27 #include "core/css/PseudoStyleRequest.h" 28 #include "core/css/RuleFeature.h" 29 #include "core/css/RuleSet.h" 30 #include "core/css/SelectorChecker.h" 31 #include "core/css/SelectorFilter.h" 32 #include "core/css/SiblingTraversalStrategies.h" 33 #include "core/css/TreeBoundaryCrossingRules.h" 34 #include "core/css/resolver/MatchedPropertiesCache.h" 35 #include "core/css/resolver/ScopedStyleResolver.h" 36 #include "core/css/resolver/ScopedStyleTree.h" 37 #include "core/css/resolver/StyleBuilder.h" 38 #include "core/css/resolver/StyleResolverIncludes.h" 39 #include "core/css/resolver/StyleResolverState.h" 40 #include "core/css/resolver/StyleResourceLoader.h" 41 #include "wtf/Deque.h" 42 #include "wtf/HashMap.h" 43 #include "wtf/HashSet.h" 44 #include "wtf/ListHashSet.h" 45 #include "wtf/RefPtr.h" 46 #include "wtf/Vector.h" 47 48 namespace WebCore { 49 50 class CSSAnimationUpdate; 51 class CSSFontSelector; 52 class CSSRuleList; 53 class CSSSelector; 54 class CSSStyleSheet; 55 class CSSValue; 56 class ContainerNode; 57 class Document; 58 class DocumentTimeline; 59 class Element; 60 class ElementRuleCollector; 61 class KeyframeList; 62 class KeyframeValue; 63 class MediaQueryEvaluator; 64 class MediaQueryResult; 65 class RenderRegion; 66 class RuleData; 67 class Settings; 68 class StyleKeyframe; 69 class StylePropertySet; 70 class StyleResolverStats; 71 class StyleRule; 72 class StyleRuleKeyframes; 73 class StyleRulePage; 74 class ViewportStyleResolver; 75 76 struct MatchResult; 77 78 enum StyleSharingBehavior { 79 AllowStyleSharing, 80 DisallowStyleSharing, 81 }; 82 83 // MatchOnlyUserAgentRules is used in media queries, where relative units 84 // are interpreted according to the document root element style, and styled only 85 // from the User Agent Stylesheet rules. 86 enum RuleMatchingBehavior { 87 MatchAllRules, 88 MatchAllRulesExcludingSMIL, 89 MatchOnlyUserAgentRules, 90 }; 91 92 const unsigned styleSharingListSize = 40; 93 typedef WTF::Deque<Element*, styleSharingListSize> StyleSharingList; 94 95 struct CSSPropertyValue { 96 CSSPropertyValue(CSSPropertyID property, CSSValue* value) 97 : property(property), value(value) { } 98 // Stores value=propertySet.getPropertyCSSValue(id).get(). 99 CSSPropertyValue(CSSPropertyID, const StylePropertySet&); 100 CSSPropertyID property; 101 CSSValue* value; 102 }; 103 104 // This class selects a RenderStyle for a given element based on a collection of stylesheets. 105 class StyleResolver : public FontSelectorClient { 106 WTF_MAKE_NONCOPYABLE(StyleResolver); WTF_MAKE_FAST_ALLOCATED; 107 public: 108 explicit StyleResolver(Document&); 109 ~StyleResolver(); 110 111 // FIXME: StyleResolver should not be keeping tree-walk state. 112 // These should move to some global tree-walk state, or should be contained in a 113 // TreeWalkContext or similar which is passed in to StyleResolver methods when available. 114 // Using these during tree walk will allow style selector to optimize child and descendant selector lookups. 115 void pushParentElement(Element&); 116 void popParentElement(Element&); 117 void pushParentShadowRoot(const ShadowRoot&); 118 void popParentShadowRoot(const ShadowRoot&); 119 120 PassRefPtr<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle = 0, StyleSharingBehavior = AllowStyleSharing, 121 RuleMatchingBehavior = MatchAllRules, RenderRegion* regionForStyling = 0); 122 123 // FIXME: keyframeStylesForAnimation is only used in the legacy animations implementation 124 // and should be removed when that is replaced by Web Animations. 125 void keyframeStylesForAnimation(Element*, const RenderStyle&, KeyframeList&); 126 PassRefPtr<RenderStyle> styleForKeyframe(Element*, const RenderStyle&, RenderStyle* parentStyle, const StyleKeyframe*, const AtomicString& animationName); 127 static PassRefPtr<KeyframeAnimationEffect> createKeyframeAnimationEffect(Element&, const Vector<RefPtr<MutableStylePropertySet> >&, KeyframeAnimationEffect::KeyframeVector&); 128 129 PassRefPtr<RenderStyle> pseudoStyleForElement(Element*, const PseudoStyleRequest&, RenderStyle* parentStyle); 130 131 PassRefPtr<RenderStyle> styleForPage(int pageIndex); 132 PassRefPtr<RenderStyle> defaultStyleForElement(); 133 PassRefPtr<RenderStyle> styleForText(Text*); 134 135 static PassRefPtr<RenderStyle> styleForDocument(Document&, CSSFontSelector* = 0); 136 137 // FIXME: This only has 5 callers and should be removed. Callers should be explicit about 138 // their dependency on Document* instead of grabbing one through StyleResolver. 139 Document& document() { return m_document; } 140 141 // FIXME: It could be better to call appendAuthorStyleSheets() directly after we factor StyleResolver further. 142 // https://bugs.webkit.org/show_bug.cgi?id=108890 143 void appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >&); 144 void resetAuthorStyle(const ContainerNode*); 145 void finishAppendAuthorStyleSheets(); 146 147 TreeBoundaryCrossingRules& treeBoundaryCrossingRules() { return m_treeBoundaryCrossingRules; } 148 void processScopedRules(const RuleSet& authorRules, const KURL&, ContainerNode* scope = 0); 149 150 void lazyAppendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >&); 151 void removePendingAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet> >&); 152 void appendPendingAuthorStyleSheets(); 153 bool hasPendingAuthorStyleSheets() const { return m_pendingStyleSheets.size() > 0 || m_needCollectFeatures; } 154 155 SelectorFilter& selectorFilter() { return m_selectorFilter; } 156 157 void setBuildScopedStyleTreeInDocumentOrder(bool enabled) { m_styleTree.setBuildInDocumentOrder(enabled); } 158 bool buildScopedStyleTreeInDocumentOrder() const { return m_styleTree.buildInDocumentOrder(); } 159 bool styleTreeHasOnlyScopedResolverForDocument() const { return m_styleTree.hasOnlyScopedResolverForDocument(); } 160 ScopedStyleResolver* styleTreeScopedStyleResolverForDocument() const { return m_styleTree.scopedStyleResolverForDocument(); } 161 162 ScopedStyleResolver* ensureScopedStyleResolver(ContainerNode* scope) 163 { 164 ASSERT(scope); 165 return m_styleTree.ensureScopedStyleResolver(*scope); 166 } 167 168 void styleTreeResolveScopedKeyframesRules(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers) 169 { 170 m_styleTree.resolveScopedKeyframesRules(element, resolvers); 171 } 172 173 // These methods will give back the set of rules that matched for a given element (or a pseudo-element). 174 enum CSSRuleFilter { 175 UAAndUserCSSRules = 1 << 1, 176 AuthorCSSRules = 1 << 2, 177 EmptyCSSRules = 1 << 3, 178 CrossOriginCSSRules = 1 << 4, 179 AllButEmptyCSSRules = UAAndUserCSSRules | AuthorCSSRules | CrossOriginCSSRules, 180 AllCSSRules = AllButEmptyCSSRules | EmptyCSSRules, 181 }; 182 PassRefPtr<CSSRuleList> cssRulesForElement(Element*, unsigned rulesToInclude = AllButEmptyCSSRules, ShouldIncludeStyleSheetInCSSOMWrapper = IncludeStyleSheetInCSSOMWrapper); 183 PassRefPtr<CSSRuleList> pseudoCSSRulesForElement(Element*, PseudoId, unsigned rulesToInclude = AllButEmptyCSSRules, ShouldIncludeStyleSheetInCSSOMWrapper = IncludeStyleSheetInCSSOMWrapper); 184 PassRefPtr<StyleRuleList> styleRulesForElement(Element*, unsigned rulesToInclude); 185 186 // |properties| is an array with |count| elements. 187 void applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle*); 188 189 ViewportStyleResolver* viewportStyleResolver() { return m_viewportStyleResolver.get(); } 190 191 void addMediaQueryResults(const MediaQueryResultList&); 192 MediaQueryResultList* viewportDependentMediaQueryResults() { return &m_viewportDependentMediaQueryResults; } 193 bool hasViewportDependentMediaQueries() const { return !m_viewportDependentMediaQueryResults.isEmpty(); } 194 bool affectedByViewportChange() const; 195 196 // FIXME: Regions should not require special logic in StyleResolver. 197 bool checkRegionStyle(Element* regionElement); 198 199 // FIXME: Rename to reflect the purpose, like didChangeFontSize or something. 200 void invalidateMatchedPropertiesCache(); 201 202 // Exposed for RenderStyle::isStyleAvilable(). 203 static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; } 204 205 // FIXME: StyleResolver should not have this member or method. 206 InspectorCSSOMWrappers& inspectorCSSOMWrappers() { return m_inspectorCSSOMWrappers; } 207 208 const RuleFeatureSet& ensureRuleFeatureSet() 209 { 210 if (hasPendingAuthorStyleSheets()) 211 appendPendingAuthorStyleSheets(); 212 return m_features; 213 } 214 215 StyleSharingList& styleSharingList() { return m_styleSharingList; } 216 217 bool hasRulesForId(const AtomicString&) const; 218 219 void addToStyleSharingList(Element&); 220 void clearStyleSharingList(); 221 222 StyleResolverStats* stats() { return m_styleResolverStats.get(); } 223 StyleResolverStats* statsTotals() { return m_styleResolverStatsTotals.get(); } 224 enum StatsReportType { ReportDefaultStats, ReportSlowStats }; 225 void enableStats(StatsReportType = ReportDefaultStats); 226 void disableStats(); 227 void printStats(); 228 229 unsigned accessCount() const { return m_accessCount; } 230 void didAccess() { ++m_accessCount; } 231 232 PassRefPtr<PseudoElement> createPseudoElementIfNeeded(Element&, PseudoId); 233 234 private: 235 // FontSelectorClient implementation. 236 virtual void fontsNeedUpdate(FontSelector*); 237 238 private: 239 void initWatchedSelectorRules(const Vector<RefPtr<StyleRule> >& watchedSelectors); 240 241 void addTreeBoundaryCrossingRules(const Vector<MinimalRuleData>&, ContainerNode* scope); 242 243 // FIXME: This should probably go away, folded into FontBuilder. 244 void updateFont(StyleResolverState&); 245 246 void appendCSSStyleSheet(CSSStyleSheet*); 247 248 void collectPseudoRulesForElement(Element*, ElementRuleCollector&, PseudoId, unsigned rulesToInclude); 249 void matchUARules(ElementRuleCollector&, RuleSet*); 250 void matchAuthorRules(Element*, ElementRuleCollector&, bool includeEmptyRules); 251 void matchAuthorRulesForShadowHost(Element*, ElementRuleCollector&, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree); 252 void matchAllRules(StyleResolverState&, ElementRuleCollector&, bool includeSMILProperties); 253 void matchUARules(ElementRuleCollector&); 254 // FIXME: watched selectors should be implemented using injected author stylesheets: http://crbug.com/316960 255 void matchWatchSelectorRules(ElementRuleCollector&); 256 void collectFeatures(); 257 void collectTreeBoundaryCrossingRules(Element*, ElementRuleCollector&, bool includeEmptyRules); 258 void resetRuleFeatures(); 259 260 bool fastRejectSelector(const RuleData&) const; 261 262 void applyMatchedProperties(StyleResolverState&, const MatchResult&); 263 void applyAnimatedProperties(StyleResolverState&, Element* animatingElement); 264 265 enum StyleApplicationPass { 266 VariableDefinitions, 267 AnimationProperties, 268 HighPriorityProperties, 269 LowPriorityProperties 270 }; 271 template <StyleResolver::StyleApplicationPass pass> 272 static inline bool isPropertyForPass(CSSPropertyID); 273 template <StyleApplicationPass pass> 274 void applyMatchedProperties(StyleResolverState&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly); 275 template <StyleApplicationPass pass> 276 void applyProperties(StyleResolverState&, const StylePropertySet* properties, StyleRule*, bool isImportant, bool inheritedOnly, PropertyWhitelistType = PropertyWhitelistNone); 277 template <StyleApplicationPass pass> 278 void applyAnimatedProperties(StyleResolverState&, const AnimationEffect::CompositableValueMap&); 279 void matchPageRules(MatchResult&, RuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName); 280 void matchPageRulesForList(Vector<StyleRulePage*>& matchedRules, const Vector<StyleRulePage*>&, bool isLeftPage, bool isFirstPage, const String& pageName); 281 void collectViewportRules(); 282 Settings* documentSettings() { return m_document.settings(); } 283 284 bool isLeftPage(int pageIndex) const; 285 bool isRightPage(int pageIndex) const { return !isLeftPage(pageIndex); } 286 bool isFirstPage(int pageIndex) const; 287 String pageName(int pageIndex) const; 288 289 bool pseudoStyleForElementInternal(Element&, const PseudoStyleRequest&, RenderStyle* parentStyle, StyleResolverState&); 290 291 // FIXME: This likely belongs on RuleSet. 292 typedef HashMap<StringImpl*, RefPtr<StyleRuleKeyframes> > KeyframesRuleMap; 293 KeyframesRuleMap m_keyframesRuleMap; 294 295 static RenderStyle* s_styleNotYetAvailable; 296 297 void cacheBorderAndBackground(); 298 299 MatchedPropertiesCache m_matchedPropertiesCache; 300 301 OwnPtr<MediaQueryEvaluator> m_medium; 302 MediaQueryResultList m_viewportDependentMediaQueryResults; 303 304 RefPtr<RenderStyle> m_rootDefaultStyle; 305 306 Document& m_document; 307 SelectorFilter m_selectorFilter; 308 309 RefPtr<ViewportStyleResolver> m_viewportStyleResolver; 310 311 ListHashSet<CSSStyleSheet*, 16> m_pendingStyleSheets; 312 313 ScopedStyleTree m_styleTree; 314 315 // FIXME: The entire logic of collecting features on StyleResolver, as well astransferring them 316 // between various parts of machinery smells wrong. This needs to be better somehow. 317 RuleFeatureSet m_features; 318 OwnPtr<RuleSet> m_siblingRuleSet; 319 OwnPtr<RuleSet> m_uncommonAttributeRuleSet; 320 321 // FIXME: watched selectors should be implemented using injected author stylesheets: http://crbug.com/316960 322 OwnPtr<RuleSet> m_watchedSelectorsRules; 323 TreeBoundaryCrossingRules m_treeBoundaryCrossingRules; 324 325 bool m_needCollectFeatures; 326 327 InspectorCSSOMWrappers m_inspectorCSSOMWrappers; 328 329 StyleResourceLoader m_styleResourceLoader; 330 331 StyleSharingList m_styleSharingList; 332 333 OwnPtr<StyleResolverStats> m_styleResolverStats; 334 OwnPtr<StyleResolverStats> m_styleResolverStatsTotals; 335 unsigned m_styleResolverStatsSequence; 336 337 unsigned m_accessCount; 338 }; 339 340 inline bool checkRegionSelector(const CSSSelector* regionSelector, Element* regionElement) 341 { 342 if (!regionSelector || !regionElement) 343 return false; 344 345 SelectorChecker selectorChecker(regionElement->document(), SelectorChecker::QueryingRules); 346 for (const CSSSelector* s = regionSelector; s; s = CSSSelectorList::next(s)) { 347 SelectorChecker::SelectorCheckingContext selectorCheckingContext(s, regionElement, SelectorChecker::VisitedMatchDisabled); 348 if (selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches) 349 return true; 350 } 351 return false; 352 } 353 354 } // namespace WebCore 355 356 #endif // StyleResolver_h 357