e683a97e1a867d45e4a0ad646d6389c59a41701d
[WebKit-https.git] / Source / WebCore / css / ElementRuleCollector.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  * Copyright (C) 2012 Google Inc. All rights reserved.
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public License
24  * along with this library; see the file COPYING.LIB.  If not, write to
25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26  * Boston, MA 02110-1301, USA.
27  */
28
29 #include "config.h"
30 #include "ElementRuleCollector.h"
31
32 #include "CSSDefaultStyleSheets.h"
33 #include "CSSRuleList.h"
34 #include "CSSSelector.h"
35 #include "CSSValueKeywords.h"
36 #include "HTMLElement.h"
37 #include "HTMLSlotElement.h"
38 #include "SVGElement.h"
39 #include "SelectorCompiler.h"
40 #include "SelectorFilter.h"
41 #include "ShadowRoot.h"
42 #include "StyleProperties.h"
43 #include "StyleScope.h"
44 #include "StyledElement.h"
45 #include <wtf/SetForScope.h>
46
47 namespace WebCore {
48
49 static const StyleProperties& leftToRightDeclaration()
50 {
51     static auto& declaration = [] () -> const StyleProperties& {
52         auto properties = MutableStyleProperties::create();
53         properties->setProperty(CSSPropertyDirection, CSSValueLtr);
54         return properties.leakRef();
55     }();
56     return declaration;
57 }
58
59 static const StyleProperties& rightToLeftDeclaration()
60 {
61     static auto& declaration = [] () -> const StyleProperties& {
62         auto properties = MutableStyleProperties::create();
63         properties->setProperty(CSSPropertyDirection, CSSValueRtl);
64         return properties.leakRef();
65     }();
66     return declaration;
67 }
68
69 class MatchRequest {
70 public:
71     MatchRequest(const RuleSet* ruleSet, bool includeEmptyRules = false, Style::ScopeOrdinal styleScopeOrdinal = Style::ScopeOrdinal::Element)
72         : ruleSet(ruleSet)
73         , includeEmptyRules(includeEmptyRules)
74         , styleScopeOrdinal(styleScopeOrdinal)
75     {
76     }
77     const RuleSet* ruleSet;
78     const bool includeEmptyRules;
79     Style::ScopeOrdinal styleScopeOrdinal;
80 };
81
82 ElementRuleCollector::ElementRuleCollector(const Element& element, const DocumentRuleSets& ruleSets, const SelectorFilter* selectorFilter)
83     : m_element(element)
84     , m_authorStyle(ruleSets.authorStyle())
85     , m_userStyle(ruleSets.userStyle())
86     , m_userAgentMediaQueryStyle(ruleSets.userAgentMediaQueryStyle())
87     , m_selectorFilter(selectorFilter)
88 {
89     ASSERT(!m_selectorFilter || m_selectorFilter->parentStackIsConsistent(element.parentNode()));
90 }
91
92 ElementRuleCollector::ElementRuleCollector(const Element& element, const RuleSet& authorStyle, const SelectorFilter* selectorFilter)
93     : m_element(element)
94     , m_authorStyle(authorStyle)
95     , m_selectorFilter(selectorFilter)
96 {
97     ASSERT(!m_selectorFilter || m_selectorFilter->parentStackIsConsistent(element.parentNode()));
98 }
99
100 StyleResolver::MatchResult& ElementRuleCollector::matchedResult()
101 {
102     ASSERT(m_mode == SelectorChecker::Mode::ResolvingStyle);
103     return m_result;
104 }
105
106 const Vector<RefPtr<StyleRule>>& ElementRuleCollector::matchedRuleList() const
107 {
108     ASSERT(m_mode == SelectorChecker::Mode::CollectingRules);
109     return m_matchedRuleList;
110 }
111
112 inline void ElementRuleCollector::addMatchedRule(const RuleData& ruleData, unsigned specificity, Style::ScopeOrdinal styleScopeOrdinal, StyleResolver::RuleRange& ruleRange)
113 {
114     // Update our first/last rule indices in the matched rules array.
115     ++ruleRange.lastRuleIndex;
116     if (ruleRange.firstRuleIndex == -1)
117         ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
118
119     m_matchedRules.append({ &ruleData, specificity, styleScopeOrdinal });
120 }
121
122 void ElementRuleCollector::clearMatchedRules()
123 {
124     m_matchedRules.clear();
125     m_keepAliveSlottedPseudoElementRules.clear();
126 }
127
128 inline void ElementRuleCollector::addElementStyleProperties(const StyleProperties* propertySet, bool isCacheable)
129 {
130     if (!propertySet)
131         return;
132     m_result.ranges.lastAuthorRule = m_result.matchedProperties().size();
133     if (m_result.ranges.firstAuthorRule == -1)
134         m_result.ranges.firstAuthorRule = m_result.ranges.lastAuthorRule;
135     m_result.addMatchedProperties(*propertySet);
136     if (!isCacheable)
137         m_result.isCacheable = false;
138 }
139
140 void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
141 {
142     ASSERT(matchRequest.ruleSet);
143     ASSERT_WITH_MESSAGE(!(m_mode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && m_pseudoStyleRequest.pseudoId != PseudoId::None), "When in StyleInvalidation or SharingRules, SelectorChecker does not try to match the pseudo ID. While ElementRuleCollector supports matching a particular pseudoId in this case, this would indicate a error at the call site since matching a particular element should be unnecessary.");
144
145     auto* shadowRoot = m_element.containingShadowRoot();
146     if (shadowRoot && shadowRoot->mode() == ShadowRootMode::UserAgent)
147         collectMatchingShadowPseudoElementRules(matchRequest, ruleRange);
148
149     // We need to collect the rules for id, class, tag, and everything else into a buffer and
150     // then sort the buffer.
151     auto& id = m_element.idForStyleResolution();
152     if (!id.isNull())
153         collectMatchingRulesForList(matchRequest.ruleSet->idRules(id), matchRequest, ruleRange);
154     if (m_element.hasClass()) {
155         for (size_t i = 0; i < m_element.classNames().size(); ++i)
156             collectMatchingRulesForList(matchRequest.ruleSet->classRules(m_element.classNames()[i]), matchRequest, ruleRange);
157     }
158
159     if (m_element.isLink())
160         collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange);
161     if (SelectorChecker::matchesFocusPseudoClass(m_element))
162         collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange);
163     collectMatchingRulesForList(matchRequest.ruleSet->tagRules(m_element.localName(), m_element.isHTMLElement() && m_element.document().isHTMLDocument()), matchRequest, ruleRange);
164     collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange);
165 }
166
167 void ElementRuleCollector::sortAndTransferMatchedRules()
168 {
169     if (m_matchedRules.isEmpty())
170         return;
171
172     sortMatchedRules();
173
174     if (m_mode == SelectorChecker::Mode::CollectingRules) {
175         for (const MatchedRule& matchedRule : m_matchedRules)
176             m_matchedRuleList.append(matchedRule.ruleData->rule());
177         return;
178     }
179
180     for (const MatchedRule& matchedRule : m_matchedRules) {
181         m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(), matchedRule.styleScopeOrdinal);
182     }
183 }
184
185 void ElementRuleCollector::matchAuthorRules(bool includeEmptyRules)
186 {
187     clearMatchedRules();
188
189     m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
190     StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
191
192     {
193         MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
194         collectMatchingRules(matchRequest, ruleRange);
195     }
196
197     auto* parent = m_element.parentElement();
198     if (parent && parent->shadowRoot())
199         matchSlottedPseudoElementRules(includeEmptyRules, ruleRange);
200
201     if (m_element.shadowRoot())
202         matchHostPseudoClassRules(includeEmptyRules, ruleRange);
203
204     if (m_element.isInShadowTree()) {
205         matchAuthorShadowPseudoElementRules(includeEmptyRules, ruleRange);
206
207         if (!m_element.partNames().isEmpty())
208             matchPartPseudoElementRules(includeEmptyRules, ruleRange);
209     }
210
211     sortAndTransferMatchedRules();
212 }
213
214 void ElementRuleCollector::matchAuthorShadowPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
215 {
216     ASSERT(m_element.isInShadowTree());
217     auto& shadowRoot = *m_element.containingShadowRoot();
218     if (shadowRoot.mode() != ShadowRootMode::UserAgent)
219         return;
220     // Look up shadow pseudo elements also from the host scope author style as they are web-exposed.
221     auto& hostAuthorRules = Style::Scope::forNode(*shadowRoot.host()).resolver().ruleSets().authorStyle();
222     MatchRequest hostAuthorRequest { &hostAuthorRules, includeEmptyRules, Style::ScopeOrdinal::ContainingHost };
223     collectMatchingShadowPseudoElementRules(hostAuthorRequest, ruleRange);
224 }
225
226 void ElementRuleCollector::matchHostPseudoClassRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
227 {
228     ASSERT(m_element.shadowRoot());
229
230     auto& shadowAuthorStyle = m_element.shadowRoot()->styleScope().resolver().ruleSets().authorStyle();
231     auto& shadowHostRules = shadowAuthorStyle.hostPseudoClassRules();
232     if (shadowHostRules.isEmpty())
233         return;
234
235     SetForScope<bool> change(m_isMatchingHostPseudoClass, true);
236
237     MatchRequest hostMatchRequest { nullptr, includeEmptyRules, Style::ScopeOrdinal::Shadow };
238     collectMatchingRulesForList(&shadowHostRules, hostMatchRequest, ruleRange);
239 }
240
241 void ElementRuleCollector::matchSlottedPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
242 {
243     auto* slot = m_element.assignedSlot();
244     auto styleScopeOrdinal = Style::ScopeOrdinal::FirstSlot;
245
246     for (; slot; slot = slot->assignedSlot(), ++styleScopeOrdinal) {
247         auto& styleScope = Style::Scope::forNode(*slot);
248         if (!styleScope.resolver().ruleSets().isAuthorStyleDefined())
249             continue;
250         // Find out if there are any ::slotted rules in the shadow tree matching the current slot.
251         // FIXME: This is really part of the slot style and could be cached when resolving it.
252         ElementRuleCollector collector(*slot, styleScope.resolver().ruleSets().authorStyle(), nullptr);
253         auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(includeEmptyRules);
254         if (!slottedPseudoElementRules)
255             continue;
256         // Match in the current scope.
257         SetForScope<bool> change(m_isMatchingSlottedPseudoElements, true);
258
259         MatchRequest scopeMatchRequest(nullptr, includeEmptyRules, styleScopeOrdinal);
260         collectMatchingRulesForList(slottedPseudoElementRules.get(), scopeMatchRequest, ruleRange);
261
262         m_keepAliveSlottedPseudoElementRules.append(WTFMove(slottedPseudoElementRules));
263     }
264 }
265
266 void ElementRuleCollector::matchPartPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
267 {
268     ASSERT(m_element.isInShadowTree());
269     auto& shadowRoot = *m_element.containingShadowRoot();
270     auto& hostAuthorRules = Style::Scope::forNode(*shadowRoot.host()).resolver().ruleSets().authorStyle();
271
272     MatchRequest hostAuthorRequest { &hostAuthorRules, includeEmptyRules, Style::ScopeOrdinal::ContainingHost };
273     collectMatchingRulesForList(&hostAuthorRules.partPseudoElementRules(), hostAuthorRequest, ruleRange);
274 }
275
276 void ElementRuleCollector::collectMatchingShadowPseudoElementRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
277 {
278     ASSERT(matchRequest.ruleSet);
279     ASSERT(m_element.containingShadowRoot()->mode() == ShadowRootMode::UserAgent);
280
281     auto& rules = *matchRequest.ruleSet;
282 #if ENABLE(VIDEO_TRACK)
283     // FXIME: WebVTT should not be done by styling UA shadow trees like this.
284     if (m_element.isWebVTTElement())
285         collectMatchingRulesForList(rules.cuePseudoRules(), matchRequest, ruleRange);
286 #endif
287     auto& pseudoId = m_element.shadowPseudoId();
288     if (!pseudoId.isEmpty())
289         collectMatchingRulesForList(rules.shadowPseudoElementRules(pseudoId), matchRequest, ruleRange);
290 }
291
292 std::unique_ptr<RuleSet::RuleDataVector> ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules)
293 {
294     ASSERT(is<HTMLSlotElement>(m_element));
295
296     clearMatchedRules();
297
298     m_mode = SelectorChecker::Mode::CollectingRules;
299
300     // Match global author rules.
301     MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
302     StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
303     collectMatchingRulesForList(&m_authorStyle.slottedPseudoElementRules(), matchRequest, ruleRange);
304
305     if (m_matchedRules.isEmpty())
306         return { };
307
308     auto ruleDataVector = makeUnique<RuleSet::RuleDataVector>();
309     ruleDataVector->reserveInitialCapacity(m_matchedRules.size());
310     for (auto& matchedRule : m_matchedRules)
311         ruleDataVector->uncheckedAppend(*matchedRule.ruleData);
312
313     return ruleDataVector;
314 }
315
316 void ElementRuleCollector::matchUserRules(bool includeEmptyRules)
317 {
318     if (!m_userStyle)
319         return;
320     
321     clearMatchedRules();
322
323     m_result.ranges.lastUserRule = m_result.matchedProperties().size() - 1;
324     MatchRequest matchRequest(m_userStyle, includeEmptyRules);
325     StyleResolver::RuleRange ruleRange = m_result.ranges.userRuleRange();
326     collectMatchingRules(matchRequest, ruleRange);
327
328     sortAndTransferMatchedRules();
329 }
330
331 void ElementRuleCollector::matchUARules()
332 {
333     // First we match rules from the user agent sheet.
334     if (CSSDefaultStyleSheets::simpleDefaultStyleSheet)
335         m_result.isCacheable = false;
336     RuleSet* userAgentStyleSheet = m_isPrintStyle
337         ? CSSDefaultStyleSheets::defaultPrintStyle : CSSDefaultStyleSheets::defaultStyle;
338     matchUARules(*userAgentStyleSheet);
339
340     // In quirks mode, we match rules from the quirks user agent sheet.
341     if (m_element.document().inQuirksMode())
342         matchUARules(*CSSDefaultStyleSheets::defaultQuirksStyle);
343
344     if (m_userAgentMediaQueryStyle)
345         matchUARules(*m_userAgentMediaQueryStyle);
346 }
347
348 void ElementRuleCollector::matchUARules(const RuleSet& rules)
349 {
350     clearMatchedRules();
351     
352     m_result.ranges.lastUARule = m_result.matchedProperties().size() - 1;
353     StyleResolver::RuleRange ruleRange = m_result.ranges.UARuleRange();
354     collectMatchingRules(MatchRequest(&rules), ruleRange);
355
356     sortAndTransferMatchedRules();
357 }
358
359 static const CSSSelector* findSlottedPseudoElementSelector(const CSSSelector* selector)
360 {
361     for (; selector; selector = selector->tagHistory()) {
362         if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
363             if (auto* list = selector->selectorList())
364                 return list->first();
365             break;
366         }
367     };
368     return nullptr;
369 }
370
371 inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
372 {
373     // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet.
374     // This is limited to HTML only so we don't need to check the namespace (because of tag name match).
375     MatchBasedOnRuleHash matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash();
376     if (matchBasedOnRuleHash != MatchBasedOnRuleHash::None && m_element.isHTMLElement()) {
377         ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == PseudoId::None, "If we match based on the rule hash while collecting for a particular pseudo element ID, we would add incorrect rules for that pseudo element ID. We should never end in ruleMatches() with a pseudo element if the ruleData cannot match any pseudo element.");
378
379         switch (matchBasedOnRuleHash) {
380         case MatchBasedOnRuleHash::None:
381             ASSERT_NOT_REACHED();
382             break;
383         case MatchBasedOnRuleHash::Universal:
384             specificity = 0;
385             break;
386         case MatchBasedOnRuleHash::ClassA:
387             specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassA);
388             break;
389         case MatchBasedOnRuleHash::ClassB:
390             specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
391             break;
392         case MatchBasedOnRuleHash::ClassC:
393             specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassC);
394             break;
395         }
396         return true;
397     }
398
399 #if ENABLE(CSS_SELECTOR_JIT)
400     auto& compiledSelector = ruleData.rule()->compiledSelectorForListIndex(ruleData.selectorListIndex());
401     void* compiledSelectorChecker = compiledSelector.codeRef.code().executableAddress();
402     if (!compiledSelectorChecker && compiledSelector.status == SelectorCompilationStatus::NotCompiled) {
403         compiledSelector.status = SelectorCompiler::compileSelector(ruleData.selector(), SelectorCompiler::SelectorContext::RuleCollector, compiledSelector.codeRef);
404
405         compiledSelectorChecker = compiledSelector.codeRef.code().executableAddress();
406     }
407
408     if (compiledSelectorChecker && compiledSelector.status == SelectorCompilationStatus::SimpleSelectorChecker) {
409         auto selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, compiledSelector.status);
410 #if !ASSERT_MSG_DISABLED
411         unsigned ignoreSpecificity;
412         ASSERT_WITH_MESSAGE(!selectorChecker(&m_element, &ignoreSpecificity) || m_pseudoStyleRequest.pseudoId == PseudoId::None, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
413 #endif
414 #if CSS_SELECTOR_JIT_PROFILING
415         ruleData.compiledSelectorUsed();
416 #endif
417         bool selectorMatches = selectorChecker(&m_element, &specificity);
418
419         if (selectorMatches && ruleData.containsUncommonAttributeSelector())
420             m_didMatchUncommonAttributeSelector = true;
421
422         return selectorMatches;
423     }
424 #endif // ENABLE(CSS_SELECTOR_JIT)
425
426     SelectorChecker::CheckingContext context(m_mode);
427     context.pseudoId = m_pseudoStyleRequest.pseudoId;
428     context.scrollbar = m_pseudoStyleRequest.scrollbar;
429     context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;
430     context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass;
431
432     bool selectorMatches;
433 #if ENABLE(CSS_SELECTOR_JIT)
434     if (compiledSelectorChecker) {
435         ASSERT(compiledSelector.status == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
436
437         auto selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, compiledSelector.status);
438
439 #if CSS_SELECTOR_JIT_PROFILING
440         compiledSelector.useCount++;
441 #endif
442         selectorMatches = selectorChecker(&m_element, &context, &specificity);
443     } else
444 #endif // ENABLE(CSS_SELECTOR_JIT)
445     {
446         auto* selector = ruleData.selector();
447         if (m_isMatchingSlottedPseudoElements) {
448             selector = findSlottedPseudoElementSelector(ruleData.selector());
449             if (!selector)
450                 return false;
451         }
452         // Slow path.
453         SelectorChecker selectorChecker(m_element.document());
454         selectorMatches = selectorChecker.match(*selector, m_element, context, specificity);
455     }
456
457     if (ruleData.containsUncommonAttributeSelector()) {
458         if (selectorMatches || context.pseudoIDSet)
459             m_didMatchUncommonAttributeSelector = true;
460     }
461     m_matchedPseudoElementIds.merge(context.pseudoIDSet);
462     m_styleRelations.appendVector(context.styleRelations);
463
464     return selectorMatches;
465 }
466
467 void ElementRuleCollector::collectMatchingRulesForList(const RuleSet::RuleDataVector* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
468 {
469     if (!rules)
470         return;
471
472     for (unsigned i = 0, size = rules->size(); i < size; ++i) {
473         const RuleData& ruleData = rules->data()[i];
474
475         if (!ruleData.canMatchPseudoElement() && m_pseudoStyleRequest.pseudoId != PseudoId::None)
476             continue;
477
478         if (m_selectorFilter && m_selectorFilter->fastRejectSelector(ruleData.descendantSelectorIdentifierHashes()))
479             continue;
480
481         StyleRule* rule = ruleData.rule();
482
483         // If the rule has no properties to apply, then ignore it in the non-debug mode.
484         // Note that if we get null back here, it means we have a rule with deferred properties,
485         // and that means we always have to consider it.
486         const StyleProperties* properties = rule->propertiesWithoutDeferredParsing();
487         if (properties && properties->isEmpty() && !matchRequest.includeEmptyRules)
488             continue;
489
490         unsigned specificity;
491         if (ruleMatches(ruleData, specificity))
492             addMatchedRule(ruleData, specificity, matchRequest.styleScopeOrdinal, ruleRange);
493     }
494 }
495
496 static inline bool compareRules(MatchedRule r1, MatchedRule r2)
497 {
498     // For normal properties the earlier scope wins. This may be reversed by !important which is handled when resolving cascade.
499     if (r1.styleScopeOrdinal != r2.styleScopeOrdinal)
500         return r1.styleScopeOrdinal > r2.styleScopeOrdinal;
501
502     if (r1.specificity != r2.specificity)
503         return r1.specificity < r2.specificity;
504
505     return r1.ruleData->position() < r2.ruleData->position();
506 }
507
508 void ElementRuleCollector::sortMatchedRules()
509 {
510     std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules);
511 }
512
513 void ElementRuleCollector::matchAllRules(bool matchAuthorAndUserStyles, bool includeSMILProperties)
514 {
515     matchUARules();
516
517     // Now we check user sheet rules.
518     if (matchAuthorAndUserStyles)
519         matchUserRules(false);
520
521     // Now check author rules, beginning first with presentational attributes mapped from HTML.
522     if (is<StyledElement>(m_element)) {
523         auto& styledElement = downcast<StyledElement>(m_element);
524         addElementStyleProperties(styledElement.presentationAttributeStyle());
525
526         // Now we check additional mapped declarations.
527         // Tables and table cells share an additional mapped rule that must be applied
528         // after all attributes, since their mapped style depends on the values of multiple attributes.
529         addElementStyleProperties(styledElement.additionalPresentationAttributeStyle());
530
531         if (is<HTMLElement>(styledElement)) {
532             bool isAuto;
533             TextDirection textDirection = downcast<HTMLElement>(styledElement).directionalityIfhasDirAutoAttribute(isAuto);
534             if (isAuto)
535                 m_result.addMatchedProperties(textDirection == TextDirection::LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
536         }
537     }
538     
539     // Check the rules in author sheets next.
540     if (matchAuthorAndUserStyles)
541         matchAuthorRules(false);
542
543     if (matchAuthorAndUserStyles && is<StyledElement>(m_element)) {
544         auto& styledElement = downcast<StyledElement>(m_element);
545         // Now check our inline style attribute.
546         if (styledElement.inlineStyle()) {
547             // Inline style is immutable as long as there is no CSSOM wrapper.
548             // FIXME: Media control shadow trees seem to have problems with caching.
549             bool isInlineStyleCacheable = !styledElement.inlineStyle()->isMutable() && !styledElement.isInShadowTree();
550             // FIXME: Constify.
551             addElementStyleProperties(styledElement.inlineStyle(), isInlineStyleCacheable);
552         }
553
554         // Now check SMIL animation override style.
555         if (includeSMILProperties && is<SVGElement>(styledElement))
556             addElementStyleProperties(downcast<SVGElement>(styledElement).animatedSMILStyleProperties(), false /* isCacheable */);
557     }
558 }
559
560 bool ElementRuleCollector::hasAnyMatchingRules(const RuleSet* ruleSet)
561 {
562     clearMatchedRules();
563
564     m_mode = SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements;
565     int firstRuleIndex = -1, lastRuleIndex = -1;
566     StyleResolver::RuleRange ruleRange(firstRuleIndex, lastRuleIndex);
567     collectMatchingRules(MatchRequest(ruleSet), ruleRange);
568
569     return !m_matchedRules.isEmpty();
570 }
571
572 } // namespace WebCore