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