Changeset 163592 in webkit
- Timestamp:
- Feb 6, 2014 5:58:40 PM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r163591 r163592 1 2014-02-06 Antti Koivisto <antti@apple.com> 2 3 Check selectors exactly when invalidating style 4 https://bugs.webkit.org/show_bug.cgi?id=128321 5 6 Reviewed by Andreas Kling. 7 8 Selectors are now really fast to match with the JIT. Take advantage of this by invalidating 9 the document style exactly when a new stylesheet arrives (instead of using heuristics). 10 11 This reduces need for large style recalculations in some common cases. 12 13 * css/ElementRuleCollector.cpp: 14 (WebCore::ElementRuleCollector::clearMatchedRules): 15 (WebCore::ElementRuleCollector::collectMatchingRulesForList): 16 * css/ElementRuleCollector.h: 17 (WebCore::ElementRuleCollector::hasMatchedRules): 18 * css/RuleSet.h: 19 (WebCore::RuleSet::hasShadowPseudoElementRules): 20 * css/SelectorChecker.cpp: 21 (WebCore::SelectorChecker::matchRecursively): 22 * css/SelectorChecker.h: 23 24 Add new mode where all pseudo elements match so we can invalidate their element. 25 26 * css/StyleInvalidationAnalysis.cpp: 27 (WebCore::shouldDirtyAllStyle): 28 (WebCore::StyleInvalidationAnalysis::StyleInvalidationAnalysis): 29 (WebCore::invalidateStyleRecursively): 30 (WebCore::StyleInvalidationAnalysis::invalidateStyle): 31 32 Switch to real selector checker. 33 34 * css/StyleInvalidationAnalysis.h: 35 * css/StyleResolver.cpp: 36 (WebCore::StyleResolver::MatchedProperties::~MatchedProperties): 37 * css/StyleResolver.h: 38 (WebCore::StyleResolver::mediaQueryEvaluator): 39 * dom/DocumentStyleSheetCollection.cpp: 40 (WebCore::DocumentStyleSheetCollection::analyzeStyleSheetChange): 41 1 42 2014-02-06 Gavin Barraclough <barraclough@apple.com> 2 43 -
trunk/Source/WebCore/css/ElementRuleCollector.cpp
r163559 r163592 95 95 } 96 96 97 inlinevoid ElementRuleCollector::clearMatchedRules()97 void ElementRuleCollector::clearMatchedRules() 98 98 { 99 99 if (!m_matchedRules) … … 360 360 if (ruleMatches(ruleData, dynamicPseudo)) { 361 361 // For SharingRules testing, any match is good enough, we don't care what is matched. 362 if (m_mode == SelectorChecker::SharingRules ) {362 if (m_mode == SelectorChecker::SharingRules || m_mode == SelectorChecker::StyleInvalidation) { 363 363 addMatchedRule(&ruleData); 364 364 break; -
trunk/Source/WebCore/css/ElementRuleCollector.h
r163475 r163592 71 71 const Vector<RefPtr<StyleRuleBase>>& matchedRuleList() const; 72 72 73 bool hasMatchedRules() const { return m_matchedRules && !m_matchedRules->isEmpty(); } 74 void clearMatchedRules(); 75 73 76 private: 74 77 void addElementStyleProperties(const StyleProperties*, bool isCacheable = true); … … 85 88 86 89 void addMatchedRule(const RuleData*); 87 void clearMatchedRules();88 90 89 91 Element& m_element; -
trunk/Source/WebCore/css/RuleSet.h
r163559 r163592 167 167 unsigned ruleCount() const { return m_ruleCount; } 168 168 169 bool hasShadowPseudoElementRules() const { return !m_shadowPseudoElementRules.isEmpty(); } 170 169 171 private: 170 172 void addChildRules(const Vector<RefPtr<StyleRuleBase>>&, const MediaQueryEvaluator& medium, StyleResolver*, bool hasDocumentSecurityOrigin, AddRuleFlags); -
trunk/Source/WebCore/css/SelectorChecker.cpp
r163427 r163592 3 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. 6 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> 7 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> … … 163 163 if (context.selector->pseudoType() == CSSSelector::PseudoWebKitCustomElement && root->type() != ShadowRoot::UserAgentShadowRoot) 164 164 return SelectorFailsLocally; 165 } else 165 } else if (m_mode != StyleInvalidation) 166 166 return SelectorFailsLocally; 167 167 } else { … … 169 169 return SelectorFailsLocally; 170 170 171 PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoType()); 171 // When invalidating style all pseudo elements need to match. 172 PseudoId pseudoId = m_mode == StyleInvalidation ? NOPSEUDO : CSSSelector::pseudoId(context.selector->pseudoType()); 172 173 if (pseudoId == FIRST_LETTER) 173 174 context.element->document().styleSheetCollection().setUsesFirstLetterRules(true); -
trunk/Source/WebCore/css/SelectorChecker.h
r162394 r163592 48 48 public: 49 49 enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled }; 50 enum Mode { ResolvingStyle = 0, CollectingRules, QueryingRules, SharingRules };50 enum Mode { ResolvingStyle = 0, CollectingRules, QueryingRules, SharingRules, StyleInvalidation }; 51 51 52 52 SelectorChecker(Document&, Mode); -
trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp
r161196 r163592 1 1 /* 2 * Copyright (C) 2012 Apple Inc. All rights reserved.2 * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 30 30 #include "Document.h" 31 31 #include "ElementIterator.h" 32 #include "ElementRuleCollector.h" 33 #include "SelectorFilter.h" 32 34 #include "StyleRuleImport.h" 33 35 #include "StyleSheetContents.h" 34 #include "StyledElement.h"35 36 36 37 namespace WebCore { 37 38 38 StyleInvalidationAnalysis::StyleInvalidationAnalysis(const Vector<StyleSheetContents*>& sheets) 39 : m_dirtiesAllStyle(false) 39 static bool shouldDirtyAllStyle(const Vector<RefPtr<StyleRuleBase>> rules) 40 40 { 41 for (unsigned i = 0; i < sheets.size() && !m_dirtiesAllStyle; ++i) 42 analyzeStyleSheet(sheets[i]); 43 } 44 45 static bool determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes) 46 { 47 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { 48 const CSSSelector* scopeSelector = 0; 49 // This picks the widest scope, not the narrowest, to minimize the number of found scopes. 50 for (const CSSSelector* current = selector; current; current = current->tagHistory()) { 51 // Prefer ids over classes. 52 if (current->m_match == CSSSelector::Id) 53 scopeSelector = current; 54 else if (current->m_match == CSSSelector::Class && (!scopeSelector || scopeSelector->m_match != CSSSelector::Id)) 55 scopeSelector = current; 56 CSSSelector::Relation relation = current->relation(); 57 if (relation != CSSSelector::Descendant && relation != CSSSelector::Child && relation != CSSSelector::SubSelector) 58 break; 41 for (auto& rule : rules) { 42 if (rule->isMediaRule()) { 43 if (shouldDirtyAllStyle(static_cast<StyleRuleMedia&>(*rule).childRules())) 44 return true; 45 continue; 59 46 } 60 if (!scopeSelector) 61 return false; 62 ASSERT(scopeSelector->m_match == CSSSelector::Class || scopeSelector->m_match == CSSSelector::Id); 63 if (scopeSelector->m_match == CSSSelector::Id) 64 idScopes.add(scopeSelector->value().impl()); 65 else 66 classScopes.add(scopeSelector->value().impl()); 67 } 68 return true; 69 } 70 71 void StyleInvalidationAnalysis::analyzeStyleSheet(StyleSheetContents* styleSheetContents) 72 { 73 ASSERT(!styleSheetContents->isLoading()); 74 75 // See if all rules on the sheet are scoped to some specific ids or classes. 76 // Then test if we actually have any of those in the tree at the moment. 77 const Vector<RefPtr<StyleRuleImport>>& importRules = styleSheetContents->importRules(); 78 for (unsigned i = 0; i < importRules.size(); ++i) { 79 if (!importRules[i]->styleSheet()) 80 continue; 81 analyzeStyleSheet(importRules[i]->styleSheet()); 82 if (m_dirtiesAllStyle) 83 return; 84 } 85 const Vector<RefPtr<StyleRuleBase>>& rules = styleSheetContents->childRules(); 86 for (unsigned i = 0; i < rules.size(); i++) { 87 StyleRuleBase* rule = rules[i].get(); 88 if (!rule->isStyleRule()) { 89 // FIXME: Media rules and maybe some others could be allowed. 90 m_dirtiesAllStyle = true; 91 return; 92 } 93 StyleRule* styleRule = static_cast<StyleRule*>(rule); 94 if (!determineSelectorScopes(styleRule->selectorList(), m_idScopes, m_classScopes)) { 95 m_dirtiesAllStyle = true; 96 return; 97 } 98 } 99 } 100 101 static bool elementMatchesSelectorScopes(const Element& element, const HashSet<AtomicStringImpl*>& idScopes, const HashSet<AtomicStringImpl*>& classScopes) 102 { 103 if (!idScopes.isEmpty() && element.hasID() && idScopes.contains(element.idForStyleResolution().impl())) 104 return true; 105 if (classScopes.isEmpty() || !element.hasClass()) 106 return false; 107 const SpaceSplitString& classNames = element.classNames(); 108 for (unsigned i = 0; i < classNames.size(); ++i) { 109 if (classScopes.contains(classNames[i].impl())) 47 // FIXME: At least font faces don't need full recalc in all cases. 48 if (!rule->isStyleRule()) 110 49 return true; 111 50 } … … 113 52 } 114 53 54 static bool shouldDirtyAllStyle(const StyleSheetContents& sheet) 55 { 56 for (auto& import : sheet.importRules()) { 57 if (!import->styleSheet()) 58 continue; 59 if (shouldDirtyAllStyle(*import->styleSheet())) 60 return true; 61 } 62 if (shouldDirtyAllStyle(sheet.childRules())) 63 return true; 64 return false; 65 } 66 67 static bool shouldDirtyAllStyle(const Vector<StyleSheetContents*>& sheets) 68 { 69 for (auto& sheet : sheets) { 70 if (shouldDirtyAllStyle(*sheet)) 71 return true; 72 } 73 return false; 74 } 75 76 StyleInvalidationAnalysis::StyleInvalidationAnalysis(const Vector<StyleSheetContents*>& sheets, const MediaQueryEvaluator& mediaQueryEvaluator) 77 : m_dirtiesAllStyle(shouldDirtyAllStyle(sheets)) 78 { 79 if (m_dirtiesAllStyle) 80 return; 81 82 m_ruleSets.resetAuthorStyle(); 83 for (auto& sheet : sheets) 84 m_ruleSets.authorStyle()->addRulesFromSheet(sheet, mediaQueryEvaluator); 85 86 // FIXME: We don't descent into shadow trees or otherwise handle shadow pseudo elements. 87 if (m_ruleSets.authorStyle()->hasShadowPseudoElementRules()) 88 m_dirtiesAllStyle = true; 89 } 90 91 static void invalidateStyleRecursively(Element& element, SelectorFilter& filter, const DocumentRuleSets& ruleSets) 92 { 93 if (element.styleChangeType() > InlineStyleChange) 94 return; 95 if (element.styleChangeType() == NoStyleChange) { 96 ElementRuleCollector ruleCollector(element, nullptr, ruleSets, filter); 97 ruleCollector.setMode(SelectorChecker::StyleInvalidation); 98 ruleCollector.matchAuthorRules(false); 99 100 if (ruleCollector.hasMatchedRules()) 101 element.setNeedsStyleRecalc(InlineStyleChange); 102 } 103 104 auto children = childrenOfType<Element>(element); 105 if (!children.first()) 106 return; 107 filter.pushParent(&element); 108 for (auto& child : children) 109 invalidateStyleRecursively(child, filter, ruleSets); 110 filter.popParent(); 111 } 112 115 113 void StyleInvalidationAnalysis::invalidateStyle(Document& document) 116 114 { 117 115 ASSERT(!m_dirtiesAllStyle); 118 if ( m_idScopes.isEmpty() && m_classScopes.isEmpty())116 if (!m_ruleSets.authorStyle()) 119 117 return; 120 118 121 auto it = descendantsOfType<Element>(document).begin(); 122 auto end = descendantsOfType<Element>(document).end(); 123 while (it != end) { 124 if (elementMatchesSelectorScopes(*it, m_idScopes, m_classScopes)) { 125 it->setNeedsStyleRecalc(); 126 // The whole subtree is now invalidated, we can skip to the next sibling. 127 it.traverseNextSkippingChildren(); 128 continue; 129 } 130 ++it; 131 } 119 Element* documentElement = document.documentElement(); 120 if (!documentElement) 121 return; 122 123 SelectorFilter filter; 124 filter.setupParentStack(documentElement); 125 invalidateStyleRecursively(*documentElement, filter, m_ruleSets); 132 126 } 133 127 -
trunk/Source/WebCore/css/StyleInvalidationAnalysis.h
r162770 r163592 1 1 /* 2 * Copyright (C) 2012 Apple Inc. All rights reserved.2 * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 #define StyleInvalidationAnalysis_h 28 28 29 #include "DocumentRuleSets.h" 29 30 #include <wtf/HashSet.h> 30 31 #include <wtf/text/AtomicStringImpl.h> … … 37 38 class StyleInvalidationAnalysis { 38 39 public: 39 StyleInvalidationAnalysis(const Vector<StyleSheetContents*>& );40 StyleInvalidationAnalysis(const Vector<StyleSheetContents*>&, const MediaQueryEvaluator&); 40 41 41 42 bool dirtiesAllStyle() const { return m_dirtiesAllStyle; } … … 43 44 44 45 private: 45 46 void analyzeStyleSheet(StyleSheetContents*);47 48 46 bool m_dirtiesAllStyle; 49 HashSet<AtomicStringImpl*> m_idScopes; 50 HashSet<AtomicStringImpl*> m_classScopes; 47 DocumentRuleSets m_ruleSets; 51 48 }; 52 49 -
trunk/Source/WebCore/css/StyleResolver.cpp
r163560 r163592 3658 3658 } 3659 3659 3660 inlineStyleResolver::MatchedProperties::~MatchedProperties()3660 StyleResolver::MatchedProperties::~MatchedProperties() 3661 3661 { 3662 3662 } -
trunk/Source/WebCore/css/StyleResolver.h
r163440 r163592 169 169 SelectorFilter& selectorFilter() { return m_selectorFilter; } 170 170 171 const MediaQueryEvaluator& mediaQueryEvaluator() const { return *m_medium; } 172 171 173 private: 172 174 void initElement(Element*); -
trunk/Source/WebCore/dom/DocumentStyleSheetCollection.cpp
r163440 r163592 367 367 if (!m_document.styleResolverIfExists()) 368 368 return; 369 StyleResolver& styleResolver = *m_document.styleResolverIfExists(); 369 370 370 371 // Find out which stylesheets are new. … … 397 398 if (!m_document.body() || m_document.hasNodesWithPlaceholderStyle()) 398 399 return; 399 StyleInvalidationAnalysis invalidationAnalysis(addedSheets );400 StyleInvalidationAnalysis invalidationAnalysis(addedSheets, styleResolver.mediaQueryEvaluator()); 400 401 if (invalidationAnalysis.dirtiesAllStyle()) 401 402 return;
Note: See TracChangeset
for help on using the changeset viewer.