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