Changeset 287772 in webkit
- Timestamp:
- Jan 7, 2022, 11:38:44 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
-
ChangeLog (modified) (1 diff)
-
style/ClassChangeInvalidation.cpp (modified) (7 diffs)
-
style/ClassChangeInvalidation.h (modified) (3 diffs)
-
style/RuleFeature.cpp (modified) (9 diffs)
-
style/RuleFeature.h (modified) (3 diffs)
-
style/StyleScopeRuleSets.cpp (modified) (1 diff)
-
style/StyleScopeRuleSets.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r287771 r287772 1 2022-01-07 Antti Koivisto <antti@apple.com> 2 3 Make separate invalidation rulesets for negated selectors (inside :not()) 4 https://bugs.webkit.org/show_bug.cgi?id=234959 5 6 Reviewed by Darin Adler. 7 8 Use this information to reduce traversal on class changes. Other mutations will follow. 9 10 * style/ClassChangeInvalidation.cpp: 11 (WebCore::Style::collectClasses): 12 (WebCore::Style::computeClassChanges): 13 (WebCore::Style::ClassChangeInvalidation::computeInvalidation): 14 15 Adding a class can only make a regular selector (not inside :not()) start matching. 16 Adding a class can only make a negated selector (inside :not()) stop matching. 17 We only need to invalidate for the first case after the mutation has happened and for the second 18 case before it happens. 19 20 These are reversed when removing a class. 21 22 (WebCore::Style::ClassChangeInvalidation::invalidateBeforeChange): 23 (WebCore::Style::ClassChangeInvalidation::invalidateAfterChange): 24 (WebCore::Style::computeClassChange): Deleted. 25 (WebCore::Style::ClassChangeInvalidation::invalidateStyleWithRuleSets): Deleted. 26 * style/ClassChangeInvalidation.h: 27 (WebCore::Style::ClassChangeInvalidation::ClassChangeInvalidation): 28 (WebCore::Style::ClassChangeInvalidation::~ClassChangeInvalidation): 29 * style/RuleFeature.cpp: 30 (WebCore::Style::RuleFeature::RuleFeature): 31 (WebCore::Style::RuleFeatureWithInvalidationSelector::RuleFeatureWithInvalidationSelector): 32 (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector): 33 34 Compute the negation state. :not(foo) is negated, :not(:not(foo)) isn't. 35 36 (WebCore::Style::RuleFeatureSet::collectFeatures): 37 * style/RuleFeature.h: 38 (WebCore::Style::RuleFeatureWithInvalidationSelector::RuleFeatureWithInvalidationSelector): Deleted. 39 * style/StyleScopeRuleSets.cpp: 40 (WebCore::Style::ensureInvalidationRuleSets): 41 42 Make separate ruleset. 43 44 * style/StyleScopeRuleSets.h: 45 1 46 2022-01-07 Gabriel Nava Marino <gnavamarino@apple.com> 2 47 -
trunk/Source/WebCore/style/ClassChangeInvalidation.cpp
r253690 r287772 35 35 namespace Style { 36 36 37 using ClassChangeVector = Vector<AtomStringImpl*, 4>;37 enum class ClassChangeType : bool { Add, Remove }; 38 38 39 static ClassChangeVector collectClasses(const SpaceSplitString& classes) 39 struct ClassChange { 40 AtomStringImpl* className { }; 41 ClassChangeType type; 42 }; 43 44 using ClassChangeVector = Vector<ClassChange, 4>; 45 46 static ClassChangeVector collectClasses(const SpaceSplitString& classes, ClassChangeType changeType) 40 47 { 41 48 ClassChangeVector result; 42 49 result.reserveCapacity(classes.size()); 43 50 for (unsigned i = 0; i < classes.size(); ++i) 44 result.uncheckedAppend( classes[i].impl());51 result.uncheckedAppend({ classes[i].impl(), changeType }); 45 52 return result; 46 53 } 47 54 48 static ClassChangeVector computeClassChange (const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)55 static ClassChangeVector computeClassChanges(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses) 49 56 { 50 57 unsigned oldSize = oldClasses.size(); … … 52 59 53 60 if (!oldSize) 54 return collectClasses(newClasses );61 return collectClasses(newClasses, ClassChangeType::Add); 55 62 if (!newSize) 56 return collectClasses(oldClasses );63 return collectClasses(oldClasses, ClassChangeType::Remove); 57 64 58 65 ClassChangeVector changedClasses; … … 71 78 if (foundFromBoth) 72 79 continue; 73 changedClasses.append( newClasses[i].impl());80 changedClasses.append({ newClasses[i].impl(), ClassChangeType::Add }); 74 81 } 75 82 for (unsigned i = 0; i < oldSize; ++i) { … … 77 84 if (remainingClassBits.quickGet(i)) 78 85 continue; 79 changedClasses.append( oldClasses[i].impl());86 changedClasses.append({ oldClasses[i].impl(), ClassChangeType::Remove }); 80 87 } 81 88 … … 85 92 void ClassChangeInvalidation::computeInvalidation(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses) 86 93 { 87 auto c hangedClasses = computeClassChange(oldClasses, newClasses);94 auto classChanges = computeClassChanges(oldClasses, newClasses); 88 95 89 96 bool shouldInvalidateCurrent = false; … … 91 98 92 99 traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) { 93 for (auto * changedClass : changedClasses) {94 if (mayAffectShadowTree && features.classRules.contains(c hangedClass))100 for (auto& classChange : classChanges) { 101 if (mayAffectShadowTree && features.classRules.contains(classChange.className)) 95 102 mayAffectStyleInShadowTree = true; 96 if (features.classesAffectingHost.contains(c hangedClass))103 if (features.classesAffectingHost.contains(classChange.className)) 97 104 shouldInvalidateCurrent = true; 98 105 } … … 109 116 auto& ruleSets = m_element.styleResolver().ruleSets(); 110 117 111 for (auto* changedClass : changedClasses) { 112 if (auto* invalidationRuleSets = ruleSets.classInvalidationRuleSets(changedClass)) { 113 for (auto& invalidationRuleSet : *invalidationRuleSets) 114 Invalidator::addToMatchElementRuleSets(m_matchElementRuleSets, invalidationRuleSet); 118 auto invalidateBeforeChange = [](ClassChangeType type, IsNegation isNegation) { 119 if (type == ClassChangeType::Remove) 120 return isNegation == IsNegation::No; 121 return isNegation == IsNegation::Yes; 122 }; 123 124 for (auto& classChange : classChanges) { 125 if (auto* invalidationRuleSets = ruleSets.classInvalidationRuleSets(classChange.className)) { 126 for (auto& invalidationRuleSet : *invalidationRuleSets) { 127 if (invalidateBeforeChange(classChange.type, invalidationRuleSet.isNegation)) 128 Invalidator::addToMatchElementRuleSets(m_beforeChangeRuleSets, invalidationRuleSet); 129 else 130 Invalidator::addToMatchElementRuleSets(m_afterChangeRuleSets, invalidationRuleSet); 131 } 115 132 } 116 133 } 117 134 } 118 135 119 void ClassChangeInvalidation::invalidate StyleWithRuleSets()136 void ClassChangeInvalidation::invalidateBeforeChange() 120 137 { 121 Invalidator::invalidateWithMatchElementRuleSets(m_element, m_matchElementRuleSets); 138 Invalidator::invalidateWithMatchElementRuleSets(m_element, m_beforeChangeRuleSets); 139 } 140 141 void ClassChangeInvalidation::invalidateAfterChange() 142 { 143 Invalidator::invalidateWithMatchElementRuleSets(m_element, m_afterChangeRuleSets); 122 144 } 123 145 -
trunk/Source/WebCore/style/ClassChangeInvalidation.h
r253690 r287772 43 43 private: 44 44 void computeInvalidation(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses); 45 void invalidateStyleWithRuleSets(); 45 void invalidateBeforeChange(); 46 void invalidateAfterChange(); 46 47 47 48 const bool m_isEnabled; 48 49 Element& m_element; 49 50 50 Invalidator::MatchElementRuleSets m_matchElementRuleSets; 51 Invalidator::MatchElementRuleSets m_beforeChangeRuleSets; 52 Invalidator::MatchElementRuleSets m_afterChangeRuleSets; 51 53 }; 52 54 … … 59 61 return; 60 62 computeInvalidation(oldClasses, newClasses); 61 invalidate StyleWithRuleSets();63 invalidateBeforeChange(); 62 64 } 63 65 … … 66 68 if (!m_isEnabled) 67 69 return; 68 invalidate StyleWithRuleSets();70 invalidateAfterChange(); 69 71 } 70 72 -
trunk/Source/WebCore/style/RuleFeature.cpp
r287479 r287772 85 85 86 86 87 RuleFeature::RuleFeature(const RuleData& ruleData, MatchElement matchElement )87 RuleFeature::RuleFeature(const RuleData& ruleData, MatchElement matchElement, IsNegation isNegation) 88 88 : RuleAndSelector(ruleData) 89 89 , matchElement(matchElement) 90 , isNegation(isNegation) 91 { 92 } 93 94 RuleFeatureWithInvalidationSelector::RuleFeatureWithInvalidationSelector(const RuleData& data, MatchElement matchElement, IsNegation isNegation, const CSSSelector* invalidationSelector) 95 : RuleFeature(data, matchElement, isNegation) 96 , invalidationSelector(invalidationSelector) 90 97 { 91 98 } … … 201 208 }; 202 209 203 void RuleFeatureSet::recursivelyCollectFeaturesFromSelector(SelectorFeatures& selectorFeatures, const CSSSelector& firstSelector, MatchElement matchElement )210 void RuleFeatureSet::recursivelyCollectFeaturesFromSelector(SelectorFeatures& selectorFeatures, const CSSSelector& firstSelector, MatchElement matchElement, IsNegation isNegation) 204 211 { 205 212 const CSSSelector* selector = &firstSelector; … … 210 217 idsMatchingAncestorsInRules.add(selector->value()); 211 218 else if (isHasPseudoClassMatchElement(matchElement)) 212 selectorFeatures.ids.append( std::make_pair(selector->value(), matchElement));219 selectorFeatures.ids.append({ selector->value(), matchElement, isNegation }); 213 220 } else if (selector->match() == CSSSelector::Class) 214 selectorFeatures.classes.append( std::make_pair(selector->value(), matchElement));221 selectorFeatures.classes.append({ selector->value(), matchElement, isNegation }); 215 222 else if (selector->match() == CSSSelector::Tag) { 216 223 if (isHasPseudoClassMatchElement(matchElement)) 217 selectorFeatures.tags.append( std::make_pair(selector->tagLowercaseLocalName(), matchElement));224 selectorFeatures.tags.append({ selector->tagLowercaseLocalName(), matchElement, isNegation }); 218 225 } else if (selector->isAttributeSelector()) { 219 226 auto& canonicalLocalName = selector->attributeCanonicalLocalName(); … … 221 228 attributeCanonicalLocalNamesInRules.add(canonicalLocalName); 222 229 attributeLocalNamesInRules.add(localName); 223 selectorFeatures.attributes.append( std::make_pair(selector, matchElement));230 selectorFeatures.attributes.append({ selector, matchElement, isNegation }); 224 231 } else if (selector->match() == CSSSelector::PseudoElement) { 225 232 switch (selector->pseudoElementType()) { … … 235 242 } else if (selector->match() == CSSSelector::PseudoClass) { 236 243 if (!isLogicalCombinationPseudoClass(selector->pseudoClassType())) 237 selectorFeatures.pseudoClasses.append( std::make_pair(selector, matchElement));244 selectorFeatures.pseudoClasses.append({ selector, matchElement, isNegation }); 238 245 } 239 246 … … 242 249 243 250 if (const CSSSelectorList* selectorList = selector->selectorList()) { 251 auto subSelectorIsNegation = isNegation; 252 if (selector->match() == CSSSelector::PseudoClass && selector->pseudoClassType() == CSSSelector::PseudoClassNot) 253 subSelectorIsNegation = isNegation == IsNegation::No ? IsNegation::Yes : IsNegation::No; 254 244 255 for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { 245 256 auto subSelectorMatchElement = computeSubSelectorMatchElement(matchElement, *selector, *subSelector); 246 257 if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector()) 247 258 selectorFeatures.hasSiblingSelector = true; 248 recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, subSelectorMatchElement );259 recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, subSelectorMatchElement, subSelectorIsNegation); 249 260 } 250 261 } … … 307 318 auto addToMap = [&](auto& map, auto& entries, auto hostAffectingNames) { 308 319 for (auto& entry : entries) { 309 auto& [name, matchElement ] = entry;320 auto& [name, matchElement, isNegation] = entry; 310 321 map.ensure(name, [] { 311 322 return makeUnique<RuleFeatureVector>(); 312 }).iterator->value->append({ ruleData, matchElement });323 }).iterator->value->append({ ruleData, matchElement, isNegation }); 313 324 314 325 setUsesMatchElement(matchElement); … … 325 336 addToMap(classRules, selectorFeatures.classes, &classesAffectingHost); 326 337 327 for (auto& selectorAndMatch : selectorFeatures.attributes) { 328 auto* selector = selectorAndMatch.first; 329 auto matchElement = selectorAndMatch.second; 338 for (auto& entry : selectorFeatures.attributes) { 339 auto [selector, matchElement, isNegation] = entry; 330 340 attributeRules.ensure(selector->attribute().localName().convertToASCIILowercase(), [] { 331 341 return makeUnique<Vector<RuleFeatureWithInvalidationSelector>>(); 332 }).iterator->value->append({ ruleData, matchElement, selector });342 }).iterator->value->append({ ruleData, matchElement, isNegation, selector }); 333 343 if (matchElement == MatchElement::Host) 334 344 attributesAffectingHost.add(selector->attribute().localName().convertToASCIILowercase()); … … 336 346 } 337 347 338 for (auto& selectorAndMatch : selectorFeatures.pseudoClasses) { 339 auto* selector = selectorAndMatch.first; 340 auto matchElement = selectorAndMatch.second; 348 for (auto& entry : selectorFeatures.pseudoClasses) { 349 auto [selector, matchElement, isNegation] = entry; 341 350 pseudoClassRules.ensure(makePseudoClassInvalidationKey(*selector), [] { 342 351 return makeUnique<Vector<RuleFeature>>(); 343 }).iterator->value->append({ ruleData, matchElement });352 }).iterator->value->append({ ruleData, matchElement, isNegation }); 344 353 345 354 if (matchElement == MatchElement::Host) -
trunk/Source/WebCore/style/RuleFeature.h
r287479 r287772 56 56 constexpr unsigned matchElementCount = static_cast<unsigned>(MatchElement::Host) + 1; 57 57 58 enum class IsNegation : bool { No, Yes }; 59 58 60 // For MSVC. 59 61 #pragma pack(push, 4) … … 67 69 68 70 struct RuleFeature : public RuleAndSelector { 69 RuleFeature(const RuleData&, MatchElement );71 RuleFeature(const RuleData&, MatchElement, IsNegation); 70 72 71 73 MatchElement matchElement; 74 IsNegation isNegation; // Whether the selector is in a (non-paired) :not() context. 72 75 }; 73 76 static_assert(sizeof(RuleFeature) <= 16, "RuleFeature is a frquently alocated object. Keep it small."); 74 77 75 78 struct RuleFeatureWithInvalidationSelector : public RuleFeature { 76 RuleFeatureWithInvalidationSelector(const RuleData& data, MatchElement matchElement, const CSSSelector* invalidationSelector = nullptr) 77 : RuleFeature(data, matchElement) 78 , invalidationSelector(invalidationSelector) 79 { } 79 RuleFeatureWithInvalidationSelector(const RuleData&, MatchElement, IsNegation, const CSSSelector* invalidationSelector); 80 80 81 81 const CSSSelector* invalidationSelector { nullptr }; … … 125 125 bool hasSiblingSelector { false }; 126 126 127 Vector<std:: pair<AtomString, MatchElement>, 32> tags;128 Vector<std:: pair<AtomString, MatchElement>, 32> ids;129 Vector<std:: pair<AtomString, MatchElement>, 32> classes;130 Vector<std:: pair<const CSSSelector*, MatchElement>, 32> attributes;131 Vector<std:: pair<const CSSSelector*, MatchElement>, 32> pseudoClasses;127 Vector<std::tuple<AtomString, MatchElement, IsNegation>, 32> tags; 128 Vector<std::tuple<AtomString, MatchElement, IsNegation>, 32> ids; 129 Vector<std::tuple<AtomString, MatchElement, IsNegation>, 32> classes; 130 Vector<std::tuple<const CSSSelector*, MatchElement, IsNegation>, 32> attributes; 131 Vector<std::tuple<const CSSSelector*, MatchElement, IsNegation>, 32> pseudoClasses; 132 132 }; 133 void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject );133 void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject, IsNegation = IsNegation::No); 134 134 }; 135 135 -
trunk/Source/WebCore/style/StyleScopeRuleSets.cpp
r287479 r287772 241 241 return nullptr; 242 242 243 std::array<RefPtr<RuleSet>, matchElementCount> matchElementArray;244 std::array<Vector<const CSSSelector*>, matchElementCount> invalidationSelectorArray; 243 HashMap<std::tuple<uint8_t, bool, bool>, InvalidationRuleSet> invalidationRuleSetMap; 244 245 245 for (auto& feature : *features) { 246 auto arrayIndex = static_cast<unsigned>(feature.matchElement); 247 RELEASE_ASSERT(arrayIndex < matchElementArray.size()); 248 249 auto& ruleSet = matchElementArray[arrayIndex]; 250 if (!ruleSet) 251 ruleSet = RuleSet::create(); 252 ruleSet->addRule(*feature.styleRule, feature.selectorIndex, feature.selectorListIndex); 246 auto key = std::tuple { static_cast<uint8_t>(feature.matchElement), static_cast<bool>(feature.isNegation), true }; 247 248 auto& invalidationRuleSet = invalidationRuleSetMap.ensure(key, [&] { 249 return InvalidationRuleSet { 250 RuleSet::create(), 251 { }, 252 feature.matchElement, 253 feature.isNegation, 254 }; 255 }).iterator->value; 256 257 invalidationRuleSet.ruleSet->addRule(*feature.styleRule, feature.selectorIndex, feature.selectorListIndex); 258 253 259 if constexpr (std::is_same<typename RuleFeatureVectorType::ValueType, RuleFeatureWithInvalidationSelector>::value) { 254 260 if (feature.invalidationSelector) 255 invalidation SelectorArray[arrayIndex].append(feature.invalidationSelector);261 invalidationRuleSet.invalidationSelectors.append(feature.invalidationSelector); 256 262 } 257 263 } 258 264 259 unsigned ruleSetCount = 0;260 for (const auto& item : matchElementArray) {261 if (item)262 ++ruleSetCount;263 }264 265 265 auto invalidationRuleSets = makeUnique<Vector<InvalidationRuleSet>>(); 266 invalidationRuleSets->reserveInitialCapacity(ruleSetCount); 267 268 for (unsigned i = 0; i < matchElementArray.size(); ++i) { 269 if (matchElementArray[i]) { 270 matchElementArray[i]->shrinkToFit(); 271 invalidationRuleSets->uncheckedAppend({ static_cast<MatchElement>(i), matchElementArray[i].releaseNonNull(), WTFMove(invalidationSelectorArray[i]) }); 272 } 273 } 266 invalidationRuleSets->reserveInitialCapacity(invalidationRuleSetMap.size()); 267 268 for (auto& invalidationRuleSet : invalidationRuleSetMap.values()) 269 invalidationRuleSets->uncheckedAppend(WTFMove(invalidationRuleSet)); 270 274 271 return invalidationRuleSets; 275 272 }).iterator->value.get(); -
trunk/Source/WebCore/style/StyleScopeRuleSets.h
r286598 r287772 44 44 45 45 struct InvalidationRuleSet { 46 RefPtr<RuleSet> ruleSet; 47 Vector<const CSSSelector*> invalidationSelectors; 46 48 MatchElement matchElement; 47 Ref<RuleSet> ruleSet; 48 Vector<const CSSSelector*> invalidationSelectors; 49 50 WTF_MAKE_FAST_ALLOCATED; 49 IsNegation isNegation; 51 50 }; 52 51
Note:
See TracChangeset
for help on using the changeset viewer.