Changeset 286180 in webkit
- Timestamp:
- Nov 26, 2021 7:13:03 AM (8 months ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
-
ChangeLog (modified) (1 diff)
-
css/SelectorChecker.cpp (modified) (3 diffs)
-
css/SelectorChecker.h (modified) (1 diff)
-
style/RuleFeature.cpp (modified) (3 diffs)
-
style/RuleFeature.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r286179 r286180 1 2021-11-26 Antti Koivisto <antti@apple.com> 2 3 [:has() pseudo-class] Don't traverse descendants during selector matching unless needed 4 https://bugs.webkit.org/show_bug.cgi?id=233520 5 6 Reviewed by Alan Bujtas. 7 8 It is sufficient to traverse direct children to match something like :has(> foo). 9 10 * css/SelectorChecker.cpp: 11 (WebCore::SelectorChecker::checkOne const): 12 (WebCore::SelectorChecker::matchHasPseudoClass const): 13 14 Factor into a function. 15 Compute the match element for the :has() argument and use it to choose what to traverse. 16 17 * css/SelectorChecker.h: 18 * style/RuleFeature.cpp: 19 (WebCore::Style::computeNextMatchElement): 20 (WebCore::Style::computeHasPseudoClassMatchElement): 21 (WebCore::Style::computeSubSelectorMatchElement): 22 23 Make these free-standing functions and expose computeHasPseudoClassMatchElement. 24 25 (WebCore::Style::RuleFeatureSet::computeNextMatchElement): Deleted. 26 (WebCore::Style::RuleFeatureSet::computeSubSelectorMatchElement): Deleted. 27 * style/RuleFeature.h: 28 1 29 2021-11-26 Antti Koivisto <antti@apple.com> 2 30 -
trunk/Source/WebCore/css/SelectorChecker.cpp
r285610 r286180 44 44 #include "Page.h" 45 45 #include "RenderElement.h" 46 #include "RuleFeature.h" 46 47 #include "SelectorCheckerTestFunctions.h" 47 48 #include "ShadowRoot.h" … … 862 863 } 863 864 case CSSSelector::PseudoClassHas: { 864 // FIXME: This is the worst possible implementation in terms of performance. 865 auto checkRelative = [&](auto& elementToCheck) { 866 for (auto* subselector = selector.selectorList()->first(); subselector; subselector = CSSSelectorList::next(subselector)) { 867 SelectorChecker selectorChecker(element.document()); 868 CheckingContext selectorCheckingContext(SelectorChecker::Mode::ResolvingStyle); 869 selectorCheckingContext.scope = &element; 870 if (selectorChecker.match(*subselector, elementToCheck, selectorCheckingContext)) 871 return true; 872 } 873 return false; 874 }; 875 for (auto& descendant : descendantsOfType<Element>(element)) { 876 if (checkRelative(descendant)) 865 for (auto* hasSelector = selector.selectorList()->first(); hasSelector; hasSelector = CSSSelectorList::next(hasSelector)) { 866 if (matchHasPseudoClass(checkingContext, element, *hasSelector)) 877 867 return true; 878 }879 for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {880 if (checkRelative(*sibling))881 return true;882 for (auto& descendant : descendantsOfType<Element>(*sibling)) {883 if (checkRelative(descendant))884 return true;885 }886 868 } 887 869 return false; … … 1259 1241 } 1260 1242 1243 bool SelectorChecker::matchHasPseudoClass(CheckingContext&, const Element& element, const CSSSelector& hasSelector) const 1244 { 1245 // FIXME: This is almost the worst possible implementation in terms of performance. 1246 1247 SelectorChecker hasChecker(element.document()); 1248 1249 auto checkRelative = [&](auto& elementToCheck) { 1250 CheckingContext hasCheckingContext(SelectorChecker::Mode::ResolvingStyle); 1251 hasCheckingContext.scope = &element; 1252 return hasChecker.match(hasSelector, elementToCheck, hasCheckingContext); 1253 }; 1254 1255 auto matchElement = Style::computeHasPseudoClassMatchElement(hasSelector); 1256 1257 switch (matchElement) { 1258 case Style::MatchElement::HasChild: 1259 for (auto& child : childrenOfType<Element>(element)) { 1260 if (checkRelative(child)) 1261 return true; 1262 } 1263 break; 1264 case Style::MatchElement::HasDescendant: 1265 for (auto& descendant : descendantsOfType<Element>(element)) { 1266 if (checkRelative(descendant)) 1267 return true; 1268 } 1269 break; 1270 case Style::MatchElement::HasSibling: 1271 for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) { 1272 if (checkRelative(*sibling)) 1273 return true; 1274 for (auto& descendant : descendantsOfType<Element>(*sibling)) { 1275 if (checkRelative(descendant)) 1276 return true; 1277 } 1278 } 1279 break; 1280 default: 1281 ASSERT_NOT_REACHED(); 1282 break; 1283 } 1284 1285 return false; 1286 } 1287 1261 1288 bool SelectorChecker::checkScrollbarPseudoClass(const CheckingContext& checkingContext, const Element& element, const CSSSelector& selector) const 1262 1289 { -
trunk/Source/WebCore/css/SelectorChecker.h
r285316 r286180 118 118 bool checkOne(CheckingContext&, const LocalContext&, MatchType&) const; 119 119 bool matchSelectorList(CheckingContext&, const LocalContext&, const Element&, const CSSSelectorList&) const; 120 bool matchHasPseudoClass(CheckingContext&, const Element&, const CSSSelector&) const; 120 121 121 122 bool checkScrollbarPseudoClass(const CheckingContext&, const Element&, const CSSSelector&) const; -
trunk/Source/WebCore/style/RuleFeature.cpp
r286169 r286180 81 81 } 82 82 83 MatchElement RuleFeatureSet::computeNextMatchElement(MatchElement matchElement, CSSSelector::RelationType relation)83 static MatchElement computeNextMatchElement(MatchElement matchElement, CSSSelector::RelationType relation) 84 84 { 85 85 if (isHasPseudoClassMatchElement(matchElement)) … … 130 130 }; 131 131 132 MatchElement RuleFeatureSet::computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector, const CSSSelector& childSelector) 132 MatchElement computeHasPseudoClassMatchElement(const CSSSelector& hasSelector) 133 { 134 auto hasMatchElement = MatchElement::Subject; 135 for (auto* simpleSelector = &hasSelector; simpleSelector->tagHistory(); simpleSelector = simpleSelector->tagHistory()) 136 hasMatchElement = computeNextMatchElement(hasMatchElement, simpleSelector->relation()); 137 138 if (hasMatchElement == MatchElement::Parent) 139 return MatchElement::HasChild; 140 141 switch (hasMatchElement) { 142 case MatchElement::Parent: 143 case MatchElement::Subject: 144 return MatchElement::HasChild; 145 case MatchElement::Ancestor: 146 return MatchElement::HasDescendant; 147 case MatchElement::IndirectSibling: 148 case MatchElement::DirectSibling: 149 case MatchElement::ParentSibling: 150 case MatchElement::AncestorSibling: 151 case MatchElement::AnySibling: 152 return MatchElement::HasSibling; 153 case MatchElement::HasChild: 154 case MatchElement::HasDescendant: 155 case MatchElement::HasSibling: 156 case MatchElement::Host: 157 ASSERT_NOT_REACHED(); 158 break; 159 } 160 return MatchElement::HasChild; 161 } 162 163 static MatchElement computeSubSelectorMatchElement(MatchElement matchElement, const CSSSelector& selector, const CSSSelector& childSelector) 133 164 { 134 165 if (selector.match() == CSSSelector::PseudoClass) { … … 142 173 return MatchElement::Host; 143 174 144 if (type == CSSSelector::PseudoClassHas) { 145 auto hasMatchElement = MatchElement::Subject; 146 for (auto* simpleSelector = &childSelector; simpleSelector->tagHistory(); simpleSelector = simpleSelector->tagHistory()) 147 hasMatchElement = computeNextMatchElement(hasMatchElement, simpleSelector->relation()); 148 149 if (hasMatchElement == MatchElement::Parent) 150 return MatchElement::HasChild; 151 if (isSiblingOrSubject(hasMatchElement)) 152 return MatchElement::HasSibling; 153 return MatchElement::HasDescendant; 154 } 175 if (type == CSSSelector::PseudoClassHas) 176 return computeHasPseudoClassMatchElement(childSelector); 155 177 } 156 178 if (selector.match() == CSSSelector::PseudoElement) { -
trunk/Source/WebCore/style/RuleFeature.h
r286169 r286180 93 93 94 94 private: 95 static MatchElement computeNextMatchElement(MatchElement, CSSSelector::RelationType);96 static MatchElement computeSubSelectorMatchElement(MatchElement, const CSSSelector&, const CSSSelector& childSelector);97 98 95 struct SelectorFeatures { 99 96 bool hasSiblingSelector { false }; … … 108 105 109 106 bool isHasPseudoClassMatchElement(MatchElement); 107 MatchElement computeHasPseudoClassMatchElement(const CSSSelector&); 110 108 111 109 } // namespace Style
Note: See TracChangeset
for help on using the changeset viewer.