Changeset 176307 in webkit
- Timestamp:
- Nov 18, 2014, 9:12:53 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 20 added
- 7 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/css/matches-specificity-1-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-1.html (added)
-
LayoutTests/fast/css/matches-specificity-10-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-10.html (added)
-
LayoutTests/fast/css/matches-specificity-2-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-2.html (added)
-
LayoutTests/fast/css/matches-specificity-3-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-3.html (added)
-
LayoutTests/fast/css/matches-specificity-4-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-4.html (added)
-
LayoutTests/fast/css/matches-specificity-5-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-5.html (added)
-
LayoutTests/fast/css/matches-specificity-6-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-6.html (added)
-
LayoutTests/fast/css/matches-specificity-7-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-7.html (added)
-
LayoutTests/fast/css/matches-specificity-8-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-8.html (added)
-
LayoutTests/fast/css/matches-specificity-9-expected.html (added)
-
LayoutTests/fast/css/matches-specificity-9.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/css/CSSSelector.cpp (modified) (3 diffs)
-
Source/WebCore/css/CSSSelector.h (modified) (2 diffs)
-
Source/WebCore/css/PageRuleCollector.cpp (modified) (1 diff)
-
Source/WebCore/css/SelectorChecker.cpp (modified) (3 diffs)
-
Source/WebCore/cssjit/SelectorCompiler.cpp (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r176301 r176307 1 2014-11-18 Benjamin Poulain <benjamin@webkit.org> 2 3 Add the initial implementation of dynamic specificity for :matches() 4 https://bugs.webkit.org/show_bug.cgi?id=138822 5 6 Reviewed by Andreas Kling. 7 8 * fast/css/matches-specificity-1-expected.html: Added. 9 * fast/css/matches-specificity-1.html: Added. 10 * fast/css/matches-specificity-2-expected.html: Added. 11 * fast/css/matches-specificity-2.html: Added. 12 * fast/css/matches-specificity-3-expected.html: Added. 13 * fast/css/matches-specificity-3.html: Added. 14 * fast/css/matches-specificity-4-expected.html: Added. 15 * fast/css/matches-specificity-4.html: Added. 16 * fast/css/matches-specificity-5-expected.html: Added. 17 * fast/css/matches-specificity-5.html: Added. 18 * fast/css/matches-specificity-6-expected.html: Added. 19 * fast/css/matches-specificity-6.html: Added. 20 * fast/css/matches-specificity-7-expected.html: Added. 21 * fast/css/matches-specificity-7.html: Added. 22 * fast/css/matches-specificity-8-expected.html: Added. 23 * fast/css/matches-specificity-8.html: Added. 24 * fast/css/matches-specificity-9-expected.html: Added. 25 * fast/css/matches-specificity-9.html: Added. 26 * fast/css/matches-specificity-10-expected.html: Added. 27 * fast/css/matches-specificity-10.html: Added. 28 1 29 2014-11-18 Chris Dumez <cdumez@apple.com> 2 30 -
trunk/Source/WebCore/ChangeLog
r176303 r176307 1 2014-11-18 Benjamin Poulain <benjamin@webkit.org> 2 3 Add the initial implementation of dynamic specificity for :matches() 4 https://bugs.webkit.org/show_bug.cgi?id=138822 5 6 Reviewed by Andreas Kling. 7 8 Previously we completely ignored the selector list of :matches() when computing 9 the specificity of the selector. 10 11 The spec (http://dev.w3.org/csswg/selectors4/#specificity) says: 12 "The specificity of a :matches() pseudo-class, however, is the specificity 13 of the most specific complex selector that matched the given element." 14 15 This patch does just that. 16 17 In the CSS JIT, we only consider specificities that can be computed statically 18 for now, this should be extended later. 19 When the specificity is dynamic, we fall back to SelectorChecker. In that case, 20 we execute every selector of the selector list and we keep the maximum value 21 as the specificity for the whole :matches(). 22 23 Tests: fast/css/matches-specificity-1.html 24 fast/css/matches-specificity-2.html 25 fast/css/matches-specificity-3.html 26 fast/css/matches-specificity-4.html 27 fast/css/matches-specificity-5.html 28 fast/css/matches-specificity-6.html 29 fast/css/matches-specificity-7.html 30 fast/css/matches-specificity-8.html 31 fast/css/matches-specificity-9.html 32 fast/css/matches-specificity-10.html 33 34 * css/CSSSelector.cpp: 35 (WebCore::selectorSpecificity): 36 (WebCore::maxSpecificity): 37 (WebCore::CSSSelector::specificity): 38 (WebCore::simpleSelectorSpecificityInternal): 39 (WebCore::CSSSelector::simpleSelectorSpecificity): 40 :matches() itself should not have any specificity. The specificity of its components 41 is computed in SelectorChecker. 42 43 Since :matches() is no longer accounted as a class B specificity, I had to finish 44 the specificity of :not() or some test breaks. 45 46 * css/CSSSelector.h: 47 * css/PageRuleCollector.cpp: 48 (WebCore::comparePageRules): 49 * css/SelectorChecker.cpp: 50 (WebCore::SelectorChecker::checkOne): 51 We can no longer shortcut the execution when context.pseudoElementEffective is false. 52 There is no guarantee that a following selector wouldn't match with a higher specificity. 53 54 * cssjit/SelectorCompiler.cpp: 55 (WebCore::SelectorCompiler::addPseudoClassType): 56 (WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator): 57 (WebCore::SelectorCompiler::constructFragments): 58 (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker): 59 1 60 2014-11-18 David Kilzer <ddkilzer@apple.com> 2 61 -
trunk/Source/WebCore/css/CSSSelector.cpp
r176241 r176307 60 60 } 61 61 62 static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity); 63 64 static unsigned selectorSpecificity(const CSSSelector& firstSimpleSelector, bool isComputingMaximumSpecificity) 65 { 66 unsigned total = simpleSelectorSpecificityInternal(firstSimpleSelector, isComputingMaximumSpecificity); 67 68 for (const CSSSelector* selector = firstSimpleSelector.tagHistory(); selector; selector = selector->tagHistory()) 69 total = CSSSelector::addSpecificities(total, simpleSelectorSpecificityInternal(*selector, isComputingMaximumSpecificity)); 70 return total; 71 } 72 73 static unsigned maxSpecificity(const CSSSelectorList& selectorList) 74 { 75 unsigned maxSpecificity = 0; 76 for (const CSSSelector* subSelector = selectorList.first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) 77 maxSpecificity = std::max(maxSpecificity, selectorSpecificity(*subSelector, true)); 78 return maxSpecificity; 79 } 80 62 81 unsigned CSSSelector::specificity() const 63 82 { … … 65 84 return specificityForPage() & maxValueMask; 66 85 67 unsigned total = simpleSelectorSpecificity(); 68 69 for (const CSSSelector* selector = this->tagHistory(); selector; selector = selector->tagHistory()) 70 total = addSpecificities(total, selector->simpleSelectorSpecificity()); 71 return total; 72 } 73 74 unsigned CSSSelector::simpleSelectorSpecificity() const 75 { 76 ASSERT_WITH_MESSAGE(!isForPage(), "At the time of this writing, page selectors are not treated as real selectors that are matched. The value computed here only account for real selectors."); 77 78 switch (match()) { 79 case Id: 86 return selectorSpecificity(*this, false); 87 } 88 89 static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity) 90 { 91 ASSERT_WITH_MESSAGE(!simpleSelector.isForPage(), "At the time of this writing, page selectors are not treated as real selectors that are matched. The value computed here only account for real selectors."); 92 93 switch (simpleSelector.match()) { 94 case CSSSelector::Id: 80 95 return static_cast<unsigned>(SelectorSpecificityIncrement::ClassA); 81 96 82 case PagePseudoClass:97 case CSSSelector::PagePseudoClass: 83 98 break; 84 case PseudoClass: 85 #if ENABLE(CSS_SELECTORS_LEVEL4) 86 if (pseudoClassType() == PseudoClassNot) { 87 ASSERT_WITH_MESSAGE(selectorList() && selectorList()->first(), "The parser should never generate a valid selector for an empty :not()."); 88 89 unsigned maxSpecificity = 0; 90 for (const CSSSelector* subSelector = selectorList()->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) 91 maxSpecificity = std::max(maxSpecificity, subSelector->specificity()); 92 return maxSpecificity; 99 case CSSSelector::PseudoClass: 100 #if ENABLE(CSS_SELECTORS_LEVEL4) 101 if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassMatches) { 102 ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :matches()."); 103 if (!isComputingMaximumSpecificity) 104 return 0; 105 return maxSpecificity(*simpleSelector.selectorList()); 106 } 107 108 if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassNot) { 109 ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :not()."); 110 return maxSpecificity(*simpleSelector.selectorList()); 93 111 } 94 112 FALLTHROUGH; … … 98 116 FALLTHROUGH; 99 117 #endif 100 case Exact:101 case C lass:102 case Set:103 case List:104 case Hyphen:105 case C ontain:106 case Begin:107 case End:118 case CSSSelector::Exact: 119 case CSSSelector::Class: 120 case CSSSelector::Set: 121 case CSSSelector::List: 122 case CSSSelector::Hyphen: 123 case CSSSelector::Contain: 124 case CSSSelector::Begin: 125 case CSSSelector::End: 108 126 return static_cast<unsigned>(SelectorSpecificityIncrement::ClassB); 109 case Tag:110 return ( tagQName().localName() != starAtom) ? static_cast<unsigned>(SelectorSpecificityIncrement::ClassC) : 0;111 case PseudoElement:127 case CSSSelector::Tag: 128 return (simpleSelector.tagQName().localName() != starAtom) ? static_cast<unsigned>(SelectorSpecificityIncrement::ClassC) : 0; 129 case CSSSelector::PseudoElement: 112 130 return static_cast<unsigned>(SelectorSpecificityIncrement::ClassC); 113 case Unknown:131 case CSSSelector::Unknown: 114 132 return 0; 115 133 } 116 134 ASSERT_NOT_REACHED(); 117 135 return 0; 136 } 137 138 unsigned CSSSelector::simpleSelectorSpecificity() const 139 { 140 return simpleSelectorSpecificityInternal(*this, false); 118 141 } 119 142 -
trunk/Source/WebCore/css/CSSSelector.h
r176241 r176307 60 60 61 61 unsigned specificity() const; 62 unsigned specificityForPage() const; 62 63 unsigned simpleSelectorSpecificity() const; 63 64 static unsigned addSpecificities(unsigned, unsigned); … … 313 314 314 315 unsigned simpleSelectorSpecificityForPage() const; 315 unsigned specificityForPage() const;316 316 317 317 // Hide. -
trunk/Source/WebCore/css/PageRuleCollector.cpp
r173569 r176307 38 38 static inline bool comparePageRules(const StyleRulePage* r1, const StyleRulePage* r2) 39 39 { 40 return r1->selector()->specificity () < r2->selector()->specificity();40 return r1->selector()->specificityForPage() < r2->selector()->specificityForPage(); 41 41 } 42 42 -
trunk/Source/WebCore/css/SelectorChecker.cpp
r176241 r176307 727 727 { 728 728 bool hasMatchedAnything = false; 729 unsigned maxSpecificity = 0; 730 729 731 MatchType localMatchType = MatchType::VirtualPseudoElementOnly; 730 732 for (const CSSSelector* subselector = selector->selectorList()->first(); subselector; subselector = CSSSelectorList::next(subselector)) { … … 738 740 MatchResult result = matchRecursively(subcontext, localDynamicPseudoIdSet, localSpecificity); 739 741 if (result.match == Match::SelectorMatches) { 740 if (!context.pseudoElementEffective) { 741 // When pseudo elements are not effective in this fragment (e.g. it's not righmost fragment), 742 // it's not necessary to check all selectors to collect pseudo element ids. 743 ASSERT(!localDynamicPseudoIdSet); 744 return true; 745 } 742 maxSpecificity = std::max(maxSpecificity, localSpecificity); 746 743 747 744 if (result.matchType == MatchType::Element) … … 752 749 } 753 750 } 754 if (hasMatchedAnything) 751 if (hasMatchedAnything) { 755 752 matchType = localMatchType; 753 specificity = CSSSelector::addSpecificities(specificity, maxSpecificity); 754 } 756 755 return hasMatchedAnything; 757 756 } -
trunk/Source/WebCore/cssjit/SelectorCompiler.cpp
r176275 r176307 219 219 unsigned registerRequirements = std::numeric_limits<unsigned>::max(); 220 220 unsigned stackRequirements = std::numeric_limits<unsigned>::max(); 221 unsigned staticSpecificity = 0; 221 222 bool clobberElementAddressRegister = true; 222 223 }; … … 358 359 StackAllocator::StackReference m_startElement; 359 360 361 #if CSS_SELECTOR_JIT_DEBUGGING 360 362 const CSSSelector* m_originalSelector; 363 #endif 361 364 }; 362 365 … … 463 466 } 464 467 465 static inline FunctionType addPseudoClassType(const CSSSelector& selector, SelectorFragment& fragment, SelectorContext selectorContext, FragmentsLevel fragmentLevel, FragmentPositionInRootFragments positionInRootFragments, bool visitedMatchEnabled, VisitedMode& visitedMode, PseudoElementMatchingBehavior pseudoElementMatchingBehavior)468 static inline FunctionType addPseudoClassType(const CSSSelector& selector, SelectorFragment& fragment, unsigned& internalSpecificity, SelectorContext selectorContext, FragmentsLevel fragmentLevel, FragmentPositionInRootFragments positionInRootFragments, bool visitedMatchEnabled, VisitedMode& visitedMode, PseudoElementMatchingBehavior pseudoElementMatchingBehavior) 466 469 { 467 470 CSSSelector::PseudoClassType type = selector.pseudoClassType(); … … 760 763 const CSSSelectorList* selectorList = selector.selectorList(); 761 764 FunctionType functionType = FunctionType::SimpleSelectorChecker; 765 unsigned firstFragmentListSpecificity = 0; 766 bool firstFragmentListSpecificitySet = false; 762 767 for (const CSSSelector* subselector = selectorList->first(); subselector; subselector = CSSSelectorList::next(subselector)) { 763 768 SelectorFragmentList selectorFragments; … … 777 782 return FunctionType::CannotCompile; 778 783 784 if (firstFragmentListSpecificitySet) { 785 // The CSS JIT does not handle dynamic specificity yet. 786 if (selectorContext == SelectorContext::RuleCollector && selectorFragments.staticSpecificity != firstFragmentListSpecificity) 787 return FunctionType::CannotCompile; 788 } else { 789 firstFragmentListSpecificitySet = true; 790 firstFragmentListSpecificity = selectorFragments.staticSpecificity; 791 } 792 779 793 functionType = mostRestrictiveFunctionType(functionType, localFunctionType); 780 794 matchesList.append(selectorFragments); … … 784 798 if (matchesList.isEmpty()) 785 799 return FunctionType::CannotMatchAnything; 800 801 internalSpecificity = firstFragmentListSpecificity; 786 802 787 803 fragment.matchesFilters.append(matchesList); … … 806 822 , m_visitedMode(VisitedMode::None) 807 823 , m_descendantBacktrackingStartInUse(false) 824 #if CSS_SELECTOR_JIT_DEBUGGING 808 825 , m_originalSelector(rootSelector) 826 #endif 809 827 { 810 828 #if CSS_SELECTOR_JIT_DEBUGGING … … 836 854 FragmentRelation relationToPreviousFragment = FragmentRelation::Rightmost; 837 855 FunctionType functionType = FunctionType::SimpleSelectorChecker; 856 unsigned specificity = 0; 838 857 for (const CSSSelector* selector = rootSelector; selector; selector = selector->tagHistory()) { 858 specificity = CSSSelector::addSpecificities(specificity, selector->simpleSelectorSpecificity()); 859 839 860 CSSSelector::Relation relation = selector->relation(); 840 861 … … 875 896 if (fragment.pseudoElementSelector && isScrollbarPseudoElement(fragment.pseudoElementSelector->pseudoElementType())) 876 897 functionType = mostRestrictiveFunctionType(functionType, addScrollbarPseudoClassType(*selector, fragment)); 877 else 878 functionType = mostRestrictiveFunctionType(functionType, addPseudoClassType(*selector, fragment, selectorContext, fragmentLevel, subPosition, visitedMatchEnabled, visitedMode, pseudoElementMatchingBehavior)); 898 else { 899 unsigned internalSpecificity = 0; 900 functionType = mostRestrictiveFunctionType(functionType, addPseudoClassType(*selector, fragment, internalSpecificity, selectorContext, fragmentLevel, subPosition, visitedMatchEnabled, visitedMode, pseudoElementMatchingBehavior)); 901 specificity = CSSSelector::addSpecificities(specificity, internalSpecificity); 902 } 879 903 if (!pseudoClassOnlyMatchesLinksInQuirksMode(*selector)) 880 904 fragment.onlyMatchesLinksInQuirksMode = false; … … 976 1000 fragment = SelectorFragment(); 977 1001 } 1002 1003 selectorFragments.staticSpecificity = specificity; 1004 978 1005 return functionType; 979 1006 } … … 1618 1645 1619 1646 if (m_selectorContext == SelectorContext::RuleCollector) { 1620 unsigned specificity = m_ originalSelector->specificity();1647 unsigned specificity = m_selectorFragments.staticSpecificity; 1621 1648 if (m_functionType == FunctionType::SelectorCheckerWithCheckingContext) 1622 1649 m_assembler.store32(Assembler::TrustedImm32(specificity), JSC::GPRInfo::argumentGPR2);
Note:
See TracChangeset
for help on using the changeset viewer.