Changeset 286598 in webkit
- Timestamp:
- Dec 7, 2021, 9:49:42 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 11 edited
-
ChangeLog (modified) (1 diff)
-
css/CSSSelector.cpp (modified) (2 diffs)
-
css/CSSSelector.h (modified) (6 diffs)
-
css/CSSSelectorList.cpp (modified) (2 diffs)
-
css/parser/CSSSelectorParser.cpp (modified) (1 diff)
-
style/PseudoClassChangeInvalidation.cpp (modified) (3 diffs)
-
style/PseudoClassChangeInvalidation.h (modified) (1 diff)
-
style/RuleFeature.cpp (modified) (5 diffs)
-
style/RuleFeature.h (modified) (4 diffs)
-
style/StyleScopeRuleSets.cpp (modified) (1 diff)
-
style/StyleScopeRuleSets.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r286596 r286598 1 2021-12-07 Antti Koivisto <antti@apple.com> 2 3 Use more specific keys for pseudo-class invalidation 4 https://bugs.webkit.org/show_bug.cgi?id=233883 5 6 Reviewed by Simon Fraser. 7 8 Currently pseudo-class invalidation is keyed with pseudo-class type only. If we have rule like 9 10 .foo:hover { ... } 11 12 we end up considering this rule for every element whenever :hover state changes, whether the element has class 'foo' or not. 13 14 We can improve this by keying pseudo-class invalidation more narrowly with type/class, type/id or type/tag pairs. 15 16 * css/CSSSelector.cpp: 17 (WebCore::CSSSelector::CSSSelector): 18 (WebCore::CSSSelector::firstInCompound const): 19 20 Add a function to find the start of a compound selector. 21 22 * css/CSSSelector.h: 23 (WebCore::CSSSelector::tagHistory const): 24 (WebCore::CSSSelector::isFirstInTagHistory const): 25 (WebCore::CSSSelector::setNotFirstInTagHistory): 26 27 Add isFirstInTagHistory bit, similar to the isLastInTagHistory bit, to enable firstInCompound. 28 29 (WebCore::CSSSelector::CSSSelector): 30 * css/CSSSelectorList.cpp: 31 (WebCore::CSSSelectorList::CSSSelectorList): 32 33 Set the bit. 34 35 * style/PseudoClassChangeInvalidation.cpp: 36 (WebCore::Style::makePseudoClassInvalidationKeys): 37 38 Collect the id, tag and classes from the element and make keys out of them. 39 40 (WebCore::Style::PseudoClassChangeInvalidation::computeInvalidation): 41 (WebCore::Style::PseudoClassChangeInvalidation::collectRuleSets): 42 43 Use the keys to look up for matching invalidation rulesets. 44 45 * style/PseudoClassChangeInvalidation.h: 46 * style/RuleFeature.cpp: 47 (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector): 48 (WebCore::Style::makePseudoClassInvalidationKey): 49 50 Make a key out of a selector. 51 Search the compound for id, classes or tag. 52 53 (WebCore::Style::RuleFeatureSet::collectFeatures): 54 (WebCore::Style::RuleFeatureSet::add): 55 (WebCore::Style::RuleFeatureSet::clear): 56 * style/RuleFeature.h: 57 * style/StyleScopeRuleSets.cpp: 58 (WebCore::Style::ScopeRuleSets::pseudoClassInvalidationRuleSets const): 59 * style/StyleScopeRuleSets.h: 60 1 61 2021-12-07 Kimmo Kinnunen <kkinnunen@apple.com> 2 62 -
trunk/Source/WebCore/css/CSSSelector.cpp
r285610 r286598 57 57 , m_pseudoType(0) 58 58 , m_isLastInSelectorList(false) 59 , m_isFirstInTagHistory(true) 59 60 , m_isLastInTagHistory(true) 60 61 , m_hasRareData(false) … … 289 290 } 290 291 292 const CSSSelector* CSSSelector::firstInCompound() const 293 { 294 auto* selector = this; 295 while (!selector->isFirstInTagHistory()) { 296 auto* previousSelector = selector - 1; 297 if (previousSelector->relation() != Subselector) 298 break; 299 selector = previousSelector; 300 } 301 return selector; 302 } 303 291 304 bool CSSSelector::operator==(const CSSSelector& other) const 292 305 { -
trunk/Source/WebCore/css/CSSSelector.h
r285610 r286598 254 254 // Selectors are kept in an array by CSSSelectorList. The next component of the selector is 255 255 // the next item in the array. 256 const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); } 256 const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? nullptr : this + 1; } 257 const CSSSelector* firstInCompound() const; 257 258 258 259 const QualifiedName& tagQName() const; … … 340 341 bool isLastInSelectorList() const { return m_isLastInSelectorList; } 341 342 void setLastInSelectorList() { m_isLastInSelectorList = true; } 343 bool isFirstInTagHistory() const { return m_isFirstInTagHistory; } 342 344 bool isLastInTagHistory() const { return m_isLastInTagHistory; } 345 void setNotFirstInTagHistory() { m_isFirstInTagHistory = false; } 343 346 void setNotLastInTagHistory() { m_isLastInTagHistory = false; } 344 347 … … 351 354 mutable unsigned m_pseudoType : 8; // PseudoType. 352 355 unsigned m_isLastInSelectorList : 1; 356 unsigned m_isFirstInTagHistory : 1; 353 357 unsigned m_isLastInTagHistory : 1; 354 358 unsigned m_hasRareData : 1; … … 469 473 } 470 474 475 inline bool isLogicalCombinationPseudoClass(CSSSelector::PseudoClassType pseudoClassType) 476 { 477 switch (pseudoClassType) { 478 case CSSSelector::PseudoClassIs: 479 case CSSSelector::PseudoClassWhere: 480 case CSSSelector::PseudoClassNot: 481 case CSSSelector::PseudoClassAny: 482 case CSSSelector::PseudoClassMatches: 483 case CSSSelector::PseudoClassHas: 484 return true; 485 default: 486 return false; 487 } 488 } 489 471 490 inline bool CSSSelector::isSiblingSelector() const 472 491 { … … 512 531 , m_pseudoType(0) 513 532 , m_isLastInSelectorList(false) 533 , m_isFirstInTagHistory(true) 514 534 , m_isLastInTagHistory(true) 515 535 , m_hasRareData(false) … … 529 549 , m_pseudoType(o.m_pseudoType) 530 550 , m_isLastInSelectorList(o.m_isLastInSelectorList) 551 , m_isFirstInTagHistory(o.m_isFirstInTagHistory) 531 552 , m_isLastInTagHistory(o.m_isLastInTagHistory) 532 553 , m_hasRareData(o.m_hasRareData) -
trunk/Source/WebCore/css/CSSSelectorList.cpp
r277967 r286598 56 56 size_t arrayIndex = 0; 57 57 for (size_t i = 0; i < selectorVector.size(); ++i) { 58 CSSParserSelector* current = selectorVector[i].get(); 58 CSSParserSelector* first = selectorVector[i].get(); 59 CSSParserSelector* current = first; 59 60 while (current) { 60 61 { … … 66 67 operator delete (currentSelector); 67 68 } 69 if (current != first) 70 m_selectorArray[arrayIndex].setNotFirstInTagHistory(); 68 71 current = current->tagHistory(); 69 72 ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); -
trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp
r285054 r286598 321 321 } 322 322 323 static bool isLogicalCombinationPseudoClass(CSSSelector::PseudoClassType pseudo)324 {325 switch (pseudo) {326 case CSSSelector::PseudoClassIs:327 case CSSSelector::PseudoClassWhere:328 case CSSSelector::PseudoClassNot:329 case CSSSelector::PseudoClassAny:330 case CSSSelector::PseudoClassMatches:331 case CSSSelector::PseudoClassHas:332 return true;333 default:334 return false;335 }336 }337 338 323 static bool isPseudoClassValidAfterPseudoElement(CSSSelector::PseudoClassType pseudoClass, CSSSelector::PseudoElementType compoundPseudoElement) 339 324 { -
trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp
r271930 r286598 33 33 namespace Style { 34 34 35 static Vector<PseudoClassInvalidationKey, 4> makePseudoClassInvalidationKeys(CSSSelector::PseudoClassType pseudoClass, const Element& element) 36 { 37 Vector<PseudoClassInvalidationKey, 4> keys; 38 39 if (!element.idForStyleResolution().isEmpty()) 40 keys.append(makePseudoClassInvalidationKey(pseudoClass, InvalidationKeyType::Id, element.idForStyleResolution())); 41 42 if (element.hasClass()) { 43 auto classCount = element.classNames().size(); 44 for (size_t i = 0; i < classCount; ++i) 45 keys.append(makePseudoClassInvalidationKey(pseudoClass, InvalidationKeyType::Class, element.classNames()[i])); 46 } 47 48 keys.append(makePseudoClassInvalidationKey(pseudoClass, InvalidationKeyType::Tag, element.localName().convertToASCIILowercase())); 49 keys.append(makePseudoClassInvalidationKey(pseudoClass, InvalidationKeyType::Universal)); 50 51 return keys; 52 }; 53 35 54 void PseudoClassChangeInvalidation::computeInvalidation(CSSSelector::PseudoClassType pseudoClass, InvalidationScope invalidationScope) 36 55 { … … 39 58 40 59 traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) { 41 if (mayAffectShadowTree && features.pseudoClass Rules.contains(pseudoClass))60 if (mayAffectShadowTree && features.pseudoClassTypes.contains(pseudoClass)) 42 61 mayAffectStyleInShadowTree = true; 43 62 if (m_element.shadowRoot() && features.pseudoClassesAffectingHost.contains(pseudoClass)) … … 53 72 m_element.invalidateStyle(); 54 73 74 for (auto& key : makePseudoClassInvalidationKeys(pseudoClass, m_element)) 75 collectRuleSets(key, invalidationScope); 76 } 77 78 void PseudoClassChangeInvalidation::collectRuleSets(const PseudoClassInvalidationKey& key, InvalidationScope invalidationScope) 79 { 55 80 auto& ruleSets = m_element.styleResolver().ruleSets(); 56 if (auto* invalidationRuleSets = ruleSets.pseudoClassInvalidationRuleSets(pseudoClass)) { 57 for (auto& invalidationRuleSet : *invalidationRuleSets) { 58 // For focus/hover we flip the whole ancestor chain. We only need to do deep invalidation traversal in the change root. 59 auto shouldInvalidate = [&] { 60 switch (invalidationScope) { 61 case InvalidationScope::All: 62 return true; 63 case InvalidationScope::SelfChildrenAndSiblings: 64 return invalidationRuleSet.matchElement != MatchElement::Ancestor; 65 case InvalidationScope::Descendants: 66 return invalidationRuleSet.matchElement == MatchElement::Ancestor; 67 } 68 ASSERT_NOT_REACHED(); 81 auto* invalidationRuleSets = ruleSets.pseudoClassInvalidationRuleSets(key); 82 if (!invalidationRuleSets) 83 return; 84 85 for (auto& invalidationRuleSet : *invalidationRuleSets) { 86 // For focus/hover we flip the whole ancestor chain. We only need to do deep invalidation traversal in the change root. 87 auto shouldInvalidate = [&] { 88 bool invalidatesAllDescendants = invalidationRuleSet.matchElement == MatchElement::Ancestor && isUniversalInvalidation(key); 89 switch (invalidationScope) { 90 case InvalidationScope::All: 69 91 return true; 70 }(); 71 if (!shouldInvalidate) 72 continue; 73 Invalidator::addToMatchElementRuleSets(m_matchElementRuleSets, invalidationRuleSet); 74 } 92 case InvalidationScope::SelfChildrenAndSiblings: 93 return !invalidatesAllDescendants; 94 case InvalidationScope::Descendants: 95 return invalidatesAllDescendants; 96 } 97 ASSERT_NOT_REACHED(); 98 return true; 99 }(); 100 if (!shouldInvalidate) 101 continue; 102 103 Invalidator::addToMatchElementRuleSets(m_matchElementRuleSets, invalidationRuleSet); 75 104 } 76 105 } -
trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h
r271930 r286598 41 41 private: 42 42 void computeInvalidation(CSSSelector::PseudoClassType, Style::InvalidationScope); 43 void collectRuleSets(const PseudoClassInvalidationKey&, InvalidationScope); 43 44 void invalidateStyleWithRuleSets(); 44 45 -
trunk/Source/WebCore/style/RuleFeature.cpp
r286433 r286598 227 227 break; 228 228 } 229 } else if (selector->match() == CSSSelector::PseudoClass) 230 selectorFeatures.pseudoClasses.append(std::make_pair(selector->pseudoClassType(), matchElement)); 229 } else if (selector->match() == CSSSelector::PseudoClass) { 230 if (!isLogicalCombinationPseudoClass(selector->pseudoClassType())) 231 selectorFeatures.pseudoClasses.append(std::make_pair(selector, matchElement)); 232 } 231 233 232 234 if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector()) … … 247 249 } while (selector); 248 250 } 251 252 PseudoClassInvalidationKey makePseudoClassInvalidationKey(CSSSelector::PseudoClassType pseudoClass, InvalidationKeyType keyType, const AtomString& keyString) 253 { 254 ASSERT(keyType != InvalidationKeyType::Universal || keyString == starAtom()); 255 return { 256 pseudoClass, 257 static_cast<uint8_t>(keyType), 258 keyString 259 }; 260 }; 261 262 static PseudoClassInvalidationKey makePseudoClassInvalidationKey(const CSSSelector& selector) 263 { 264 ASSERT(selector.match() == CSSSelector::PseudoClass); 265 266 auto pseudoClassType = selector.pseudoClassType(); 267 268 AtomString className; 269 AtomString tagName; 270 for (auto* simpleSelector = selector.firstInCompound(); simpleSelector; simpleSelector = simpleSelector->tagHistory()) { 271 if (simpleSelector->match() == CSSSelector::Id) 272 return makePseudoClassInvalidationKey(pseudoClassType, InvalidationKeyType::Id, simpleSelector->value()); 273 274 if (simpleSelector->match() == CSSSelector::Class && className.isNull()) 275 className = simpleSelector->value(); 276 277 if (simpleSelector->match() == CSSSelector::Tag) 278 tagName = simpleSelector->tagLowercaseLocalName(); 279 280 if (simpleSelector->relation() != CSSSelector::Subselector) 281 break; 282 } 283 if (!className.isEmpty()) 284 return makePseudoClassInvalidationKey(pseudoClassType, InvalidationKeyType::Class, className); 285 286 if (!tagName.isEmpty() && tagName != starAtom()) 287 return makePseudoClassInvalidationKey(pseudoClassType, InvalidationKeyType::Tag, tagName); 288 289 return makePseudoClassInvalidationKey(selector.pseudoClassType(), InvalidationKeyType::Universal); 290 }; 249 291 250 292 void RuleFeatureSet::collectFeatures(const RuleData& ruleData) … … 288 330 } 289 331 290 addToMap(pseudoClassRules, selectorFeatures.pseudoClasses, &pseudoClassesAffectingHost); 332 for (auto& selectorAndMatch : selectorFeatures.pseudoClasses) { 333 auto* selector = selectorAndMatch.first; 334 auto matchElement = selectorAndMatch.second; 335 pseudoClassRules.ensure(makePseudoClassInvalidationKey(*selector), [] { 336 return makeUnique<Vector<RuleFeature>>(); 337 }).iterator->value->append({ ruleData, matchElement }); 338 339 if (matchElement == MatchElement::Host) 340 pseudoClassesAffectingHost.add(selector->pseudoClassType()); 341 pseudoClassTypes.add(selector->pseudoClassType()); 342 343 setUsesMatchElement(matchElement); 344 } 291 345 } 292 346 … … 320 374 addMap(pseudoClassRules, other.pseudoClassRules); 321 375 pseudoClassesAffectingHost.add(other.pseudoClassesAffectingHost.begin(), other.pseudoClassesAffectingHost.end()); 376 pseudoClassTypes.add(other.pseudoClassTypes.begin(), other.pseudoClassTypes.end()); 322 377 323 378 for (size_t i = 0; i < usedMatchElements.size(); ++i) … … 352 407 pseudoClassRules.clear(); 353 408 pseudoClassesAffectingHost.clear(); 409 pseudoClassTypes.clear(); 354 410 usesFirstLineRules = false; 355 411 usesFirstLetterRules = false; -
trunk/Source/WebCore/style/RuleFeature.h
r286433 r286598 75 75 }; 76 76 77 using PseudoClassInvalidationKey = std::tuple<unsigned, uint8_t, AtomString>; 78 77 79 using RuleFeatureVector = Vector<RuleFeature>; 78 80 … … 99 101 HashMap<AtomString, std::unique_ptr<RuleFeatureVector>> classRules; 100 102 HashMap<AtomString, std::unique_ptr<Vector<RuleFeatureWithInvalidationSelector>>> attributeRules; 101 HashMap< CSSSelector::PseudoClassType, std::unique_ptr<RuleFeatureVector>, IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> pseudoClassRules;103 HashMap<PseudoClassInvalidationKey, std::unique_ptr<RuleFeatureVector>> pseudoClassRules; 102 104 HashSet<AtomString> classesAffectingHost; 103 105 HashSet<AtomString> attributesAffectingHost; 104 106 HashSet<CSSSelector::PseudoClassType, IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> pseudoClassesAffectingHost; 107 HashSet<CSSSelector::PseudoClassType, IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> pseudoClassTypes; 105 108 106 109 std::array<bool, matchElementCount> usedMatchElements { }; … … 117 120 Vector<std::pair<AtomString, MatchElement>, 32> classes; 118 121 Vector<std::pair<const CSSSelector*, MatchElement>, 32> attributes; 119 Vector<std::pair< CSSSelector::PseudoClassType, MatchElement>, 32> pseudoClasses;122 Vector<std::pair<const CSSSelector*, MatchElement>, 32> pseudoClasses; 120 123 }; 121 124 void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject); … … 125 128 MatchElement computeHasPseudoClassMatchElement(const CSSSelector&); 126 129 130 enum class InvalidationKeyType : uint8_t { Universal = 1, Class, Id, Tag }; 131 PseudoClassInvalidationKey makePseudoClassInvalidationKey(CSSSelector::PseudoClassType, InvalidationKeyType, const AtomString& = starAtom()); 132 133 inline bool isUniversalInvalidation(const PseudoClassInvalidationKey& key) 134 { 135 return static_cast<InvalidationKeyType>(std::get<1>(key)) == InvalidationKeyType::Universal; 136 } 137 127 138 } // namespace Style 128 139 } // namespace WebCore -
trunk/Source/WebCore/style/StyleScopeRuleSets.cpp
r286226 r286598 296 296 } 297 297 298 const Vector<InvalidationRuleSet>* ScopeRuleSets::pseudoClassInvalidationRuleSets( CSSSelector::PseudoClassType pseudoClass) const299 { 300 return ensureInvalidationRuleSets(pseudoClass , m_pseudoClassInvalidationRuleSets, m_features.pseudoClassRules);298 const Vector<InvalidationRuleSet>* ScopeRuleSets::pseudoClassInvalidationRuleSets(const PseudoClassInvalidationKey& pseudoClassKey) const 299 { 300 return ensureInvalidationRuleSets(pseudoClassKey, m_pseudoClassInvalidationRuleSets, m_features.pseudoClassRules); 301 301 } 302 302 -
trunk/Source/WebCore/style/StyleScopeRuleSets.h
r286226 r286598 68 68 const Vector<InvalidationRuleSet>* classInvalidationRuleSets(const AtomString&) const; 69 69 const Vector<InvalidationRuleSet>* attributeInvalidationRuleSets(const AtomString&) const; 70 const Vector<InvalidationRuleSet>* pseudoClassInvalidationRuleSets( CSSSelector::PseudoClassType) const;70 const Vector<InvalidationRuleSet>* pseudoClassInvalidationRuleSets(const PseudoClassInvalidationKey&) const; 71 71 72 72 const Vector<InvalidationRuleSet>* invalidationRuleSetsForChildChange(const Element&); … … 107 107 mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_classInvalidationRuleSets; 108 108 mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_attributeInvalidationRuleSets; 109 mutable HashMap< CSSSelector::PseudoClassType, std::unique_ptr<Vector<InvalidationRuleSet>>, IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> m_pseudoClassInvalidationRuleSets;109 mutable HashMap<PseudoClassInvalidationKey, std::unique_ptr<Vector<InvalidationRuleSet>>> m_pseudoClassInvalidationRuleSets; 110 110 111 111 mutable std::optional<bool> m_cachedHasComplexSelectorsForStyleAttribute;
Note:
See TracChangeset
for help on using the changeset viewer.