Improve use of NeverDestroyed
[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, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 "RenderRegion.h"
39 #include "SVGElement.h"
40 #include "SelectorCompiler.h"
41 #include "SelectorFilter.h"
42 #include "ShadowRoot.h"
43 #include "StyleProperties.h"
44 #include "StyleScope.h"
45 #include "StyledElement.h"
46 #include <wtf/SetForScope.h>
47
48 namespace WebCore {
49
50 static const StyleProperties& leftToRightDeclaration()
51 {
52     static auto& declaration = [] () -> const StyleProperties& {
53         auto properties = MutableStyleProperties::create();
54         properties->setProperty(CSSPropertyDirection, CSSValueLtr);
55         return properties.leakRef();
56     }();
57     return declaration;
58 }
59
60 static const StyleProperties& rightToLeftDeclaration()
61 {
62     static auto& declaration = [] () -> const StyleProperties& {
63         auto properties = MutableStyleProperties::create();
64         properties->setProperty(CSSPropertyDirection, CSSValueRtl);
65         return properties.leakRef();
66     }();
67     return declaration;
68 }
69
70 class MatchRequest {
71 public:
72     MatchRequest(const RuleSet* ruleSet, bool includeEmptyRules = false, Style::ScopeOrdinal styleScopeOrdinal = Style::ScopeOrdinal::Element)
73         : ruleSet(ruleSet)
74         , includeEmptyRules(includeEmptyRules)
75         , styleScopeOrdinal(styleScopeOrdinal)
76     {
77     }
78     const RuleSet* ruleSet;
79     const bool includeEmptyRules;
80     Style::ScopeOrdinal styleScopeOrdinal;
81 };
82
83 ElementRuleCollector::ElementRuleCollector(const Element& element, const DocumentRuleSets& ruleSets, const SelectorFilter* selectorFilter)
84     : m_element(element)
85     , m_authorStyle(ruleSets.authorStyle())
86     , m_userStyle(ruleSets.userStyle())
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 != NOPSEUDO), "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::collectMatchingRulesForRegion(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
168 {
169     if (!m_regionForStyling)
170         return;
171
172     unsigned size = matchRequest.ruleSet->regionSelectorsAndRuleSets().size();
173     for (unsigned i = 0; i < size; ++i) {
174         const CSSSelector* regionSelector = matchRequest.ruleSet->regionSelectorsAndRuleSets().at(i).selector;
175         if (checkRegionSelector(regionSelector, m_regionForStyling->generatingElement())) {
176             RuleSet* regionRules = matchRequest.ruleSet->regionSelectorsAndRuleSets().at(i).ruleSet.get();
177             ASSERT(regionRules);
178             collectMatchingRules(MatchRequest(regionRules, matchRequest.includeEmptyRules), ruleRange);
179         }
180     }
181 }
182
183 void ElementRuleCollector::sortAndTransferMatchedRules()
184 {
185     if (m_matchedRules.isEmpty())
186         return;
187
188     sortMatchedRules();
189
190     if (m_mode == SelectorChecker::Mode::CollectingRules) {
191         for (const MatchedRule& matchedRule : m_matchedRules)
192             m_matchedRuleList.append(matchedRule.ruleData->rule());
193         return;
194     }
195
196     for (const MatchedRule& matchedRule : m_matchedRules) {
197         m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(), matchedRule.styleScopeOrdinal);
198     }
199 }
200
201 void ElementRuleCollector::matchAuthorRules(bool includeEmptyRules)
202 {
203     clearMatchedRules();
204
205     m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
206     StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
207
208     {
209         MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
210         collectMatchingRules(matchRequest, ruleRange);
211         collectMatchingRulesForRegion(matchRequest, ruleRange);
212     }
213
214     auto* parent = m_element.parentElement();
215     if (parent && parent->shadowRoot())
216         matchSlottedPseudoElementRules(includeEmptyRules, ruleRange);
217
218     if (m_element.shadowRoot())
219         matchHostPseudoClassRules(includeEmptyRules, ruleRange);
220
221     if (m_element.isInShadowTree())
222         matchAuthorShadowPseudoElementRules(includeEmptyRules, ruleRange);
223
224     sortAndTransferMatchedRules();
225 }
226
227 void ElementRuleCollector::matchAuthorShadowPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
228 {
229     ASSERT(m_element.isInShadowTree());
230     auto& shadowRoot = *m_element.containingShadowRoot();
231     if (shadowRoot.mode() != ShadowRootMode::UserAgent)
232         return;
233     // Look up shadow pseudo elements also from the host scope author style as they are web-exposed.
234     auto& hostAuthorRules = Style::Scope::forNode(*shadowRoot.host()).resolver().ruleSets().authorStyle();
235     MatchRequest hostAuthorRequest { &hostAuthorRules, includeEmptyRules, Style::ScopeOrdinal::ContainingHost };
236     collectMatchingShadowPseudoElementRules(hostAuthorRequest, ruleRange);
237 }
238
239 void ElementRuleCollector::matchHostPseudoClassRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
240 {
241     ASSERT(m_element.shadowRoot());
242
243     auto& shadowAuthorStyle = m_element.shadowRoot()->styleScope().resolver().ruleSets().authorStyle();
244     auto& shadowHostRules = shadowAuthorStyle.hostPseudoClassRules();
245     if (shadowHostRules.isEmpty())
246         return;
247
248     SetForScope<bool> change(m_isMatchingHostPseudoClass, true);
249
250     MatchRequest hostMatchRequest { nullptr, includeEmptyRules, Style::ScopeOrdinal::Shadow };
251     collectMatchingRulesForList(&shadowHostRules, hostMatchRequest, ruleRange);
252 }
253
254 void ElementRuleCollector::matchSlottedPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange)
255 {
256     auto* slot = m_element.assignedSlot();
257     auto styleScopeOrdinal = Style::ScopeOrdinal::FirstSlot;
258
259     for (; slot; slot = slot->assignedSlot(), ++styleScopeOrdinal) {
260         auto& styleScope = Style::Scope::forNode(*slot);
261         if (!styleScope.resolver().ruleSets().isAuthorStyleDefined())
262             continue;
263         // Find out if there are any ::slotted rules in the shadow tree matching the current slot.
264         // FIXME: This is really part of the slot style and could be cached when resolving it.
265         ElementRuleCollector collector(*slot, styleScope.resolver().ruleSets().authorStyle(), nullptr);
266         auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(includeEmptyRules);
267         if (!slottedPseudoElementRules)
268             continue;
269         // Match in the current scope.
270         SetForScope<bool> change(m_isMatchingSlottedPseudoElements, true);
271
272         MatchRequest scopeMatchRequest(nullptr, includeEmptyRules, styleScopeOrdinal);
273         collectMatchingRulesForList(slottedPseudoElementRules.get(), scopeMatchRequest, ruleRange);
274
275         m_keepAliveSlottedPseudoElementRules.append(WTFMove(slottedPseudoElementRules));
276     }
277 }
278
279 void ElementRuleCollector::collectMatchingShadowPseudoElementRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
280 {
281     ASSERT(matchRequest.ruleSet);
282     ASSERT(m_element.containingShadowRoot()->mode() == ShadowRootMode::UserAgent);
283
284     auto& rules = *matchRequest.ruleSet;
285 #if ENABLE(VIDEO_TRACK)
286     // FXIME: WebVTT should not be done by styling UA shadow trees like this.
287     if (m_element.isWebVTTElement())
288         collectMatchingRulesForList(rules.cuePseudoRules(), matchRequest, ruleRange);
289 #endif
290     auto& pseudoId = m_element.shadowPseudoId();
291     if (!pseudoId.isEmpty())
292         collectMatchingRulesForList(rules.shadowPseudoElementRules(pseudoId), matchRequest, ruleRange);
293 }
294
295 std::unique_ptr<RuleSet::RuleDataVector> ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules)
296 {
297     ASSERT(is<HTMLSlotElement>(m_element));
298
299     clearMatchedRules();
300
301     m_mode = SelectorChecker::Mode::CollectingRules;
302
303     // Match global author rules.
304     MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
305     StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
306     collectMatchingRulesForList(&m_authorStyle.slottedPseudoElementRules(), matchRequest, ruleRange);
307
308     if (m_matchedRules.isEmpty())
309         return { };
310
311     auto ruleDataVector = std::make_unique<RuleSet::RuleDataVector>();
312     ruleDataVector->reserveInitialCapacity(m_matchedRules.size());
313     for (auto& matchedRule : m_matchedRules)
314         ruleDataVector->uncheckedAppend(*matchedRule.ruleData);
315
316     return ruleDataVector;
317 }
318
319 void ElementRuleCollector::matchUserRules(bool includeEmptyRules)
320 {
321     if (!m_userStyle)
322         return;
323     
324     clearMatchedRules();
325
326     m_result.ranges.lastUserRule = m_result.matchedProperties().size() - 1;
327     MatchRequest matchRequest(m_userStyle, includeEmptyRules);
328     StyleResolver::RuleRange ruleRange = m_result.ranges.userRuleRange();
329     collectMatchingRules(matchRequest, ruleRange);
330     collectMatchingRulesForRegion(matchRequest, ruleRange);
331
332     sortAndTransferMatchedRules();
333 }
334
335 void ElementRuleCollector::matchUARules()
336 {
337     // First we match rules from the user agent sheet.
338     if (CSSDefaultStyleSheets::simpleDefaultStyleSheet)
339         m_result.isCacheable = false;
340     RuleSet* userAgentStyleSheet = m_isPrintStyle
341         ? CSSDefaultStyleSheets::defaultPrintStyle : CSSDefaultStyleSheets::defaultStyle;
342     matchUARules(userAgentStyleSheet);
343
344     // In quirks mode, we match rules from the quirks user agent sheet.
345     if (m_element.document().inQuirksMode())
346         matchUARules(CSSDefaultStyleSheets::defaultQuirksStyle);
347 }
348
349 void ElementRuleCollector::matchUARules(RuleSet* rules)
350 {
351     clearMatchedRules();
352     
353     m_result.ranges.lastUARule = m_result.matchedProperties().size() - 1;
354     StyleResolver::RuleRange ruleRange = m_result.ranges.UARuleRange();
355     collectMatchingRules(MatchRequest(rules), ruleRange);
356
357     sortAndTransferMatchedRules();
358 }
359
360 static const CSSSelector* findSlottedPseudoElementSelector(const CSSSelector* selector)
361 {
362     for (; selector; selector = selector->tagHistory()) {
363         if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
364             if (auto* list = selector->selectorList())
365                 return list->first();
366             break;
367         }
368     };
369     return nullptr;
370 }
371
372 inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
373 {
374     // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet.
375     // This is limited to HTML only so we don't need to check the namespace (because of tag name match).
376     MatchBasedOnRuleHash matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash();
377     if (matchBasedOnRuleHash != MatchBasedOnRuleHash::None && m_element.isHTMLElement()) {
378         ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == NOPSEUDO, "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.");
379
380         switch (matchBasedOnRuleHash) {
381         case MatchBasedOnRuleHash::None:
382             ASSERT_NOT_REACHED();
383             break;
384         case MatchBasedOnRuleHash::Universal:
385             specificity = 0;
386             break;
387         case MatchBasedOnRuleHash::ClassA:
388             specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassA);
389             break;
390         case MatchBasedOnRuleHash::ClassB:
391             specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
392             break;
393         case MatchBasedOnRuleHash::ClassC:
394             specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassC);
395             break;
396         }
397         return true;
398     }
399
400 #if ENABLE(CSS_SELECTOR_JIT)
401     void* compiledSelectorChecker = ruleData.compiledSelectorCodeRef().code().executableAddress();
402     if (!compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::NotCompiled) {
403         JSC::VM& vm = m_element.document().scriptExecutionContext()->vm();
404         SelectorCompilationStatus compilationStatus;
405         JSC::MacroAssemblerCodeRef compiledSelectorCodeRef;
406         compilationStatus = SelectorCompiler::compileSelector(ruleData.selector(), &vm, SelectorCompiler::SelectorContext::RuleCollector, compiledSelectorCodeRef);
407
408         ruleData.setCompiledSelector(compilationStatus, compiledSelectorCodeRef);
409         compiledSelectorChecker = ruleData.compiledSelectorCodeRef().code().executableAddress();
410     }
411
412     if (compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) {
413         SelectorCompiler::RuleCollectorSimpleSelectorChecker selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus());
414 #if !ASSERT_MSG_DISABLED
415         unsigned ignoreSpecificity;
416         ASSERT_WITH_MESSAGE(!selectorChecker(&m_element, &ignoreSpecificity) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
417 #endif
418 #if CSS_SELECTOR_JIT_PROFILING
419         ruleData.compiledSelectorUsed();
420 #endif
421         bool selectorMatches = selectorChecker(&m_element, &specificity);
422
423         if (selectorMatches && ruleData.containsUncommonAttributeSelector())
424             m_didMatchUncommonAttributeSelector = true;
425
426         return selectorMatches;
427     }
428 #endif // ENABLE(CSS_SELECTOR_JIT)
429
430     SelectorChecker::CheckingContext context(m_mode);
431     context.pseudoId = m_pseudoStyleRequest.pseudoId;
432     context.scrollbar = m_pseudoStyleRequest.scrollbar;
433     context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;
434     context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass;
435
436     bool selectorMatches;
437 #if ENABLE(CSS_SELECTOR_JIT)
438     if (compiledSelectorChecker) {
439         ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
440
441         SelectorCompiler::RuleCollectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
442
443 #if CSS_SELECTOR_JIT_PROFILING
444         ruleData.compiledSelectorUsed();
445 #endif
446         selectorMatches = selectorChecker(&m_element, &context, &specificity);
447     } else
448 #endif // ENABLE(CSS_SELECTOR_JIT)
449     {
450         auto* selector = ruleData.selector();
451         if (m_isMatchingSlottedPseudoElements) {
452             selector = findSlottedPseudoElementSelector(ruleData.selector());
453             if (!selector)
454                 return false;
455         }
456         // Slow path.
457         SelectorChecker selectorChecker(m_element.document());
458         selectorMatches = selectorChecker.match(*selector, m_element, context, specificity);
459     }
460
461     if (ruleData.containsUncommonAttributeSelector()) {
462         if (selectorMatches || context.pseudoIDSet)
463             m_didMatchUncommonAttributeSelector = true;
464     }
465     m_matchedPseudoElementIds.merge(context.pseudoIDSet);
466     m_styleRelations.appendVector(context.styleRelations);
467
468     return selectorMatches;
469 }
470
471 void ElementRuleCollector::collectMatchingRulesForList(const RuleSet::RuleDataVector* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
472 {
473     if (!rules)
474         return;
475
476     for (unsigned i = 0, size = rules->size(); i < size; ++i) {
477         const RuleData& ruleData = rules->data()[i];
478
479         if (!ruleData.canMatchPseudoElement() && m_pseudoStyleRequest.pseudoId != NOPSEUDO)
480             continue;
481
482         if (m_selectorFilter && m_selectorFilter->fastRejectSelector<RuleData::maximumIdentifierCount>(ruleData.descendantSelectorIdentifierHashes()))
483             continue;
484
485         StyleRule* rule = ruleData.rule();
486
487         // If the rule has no properties to apply, then ignore it in the non-debug mode.
488         // Note that if we get null back here, it means we have a rule with deferred properties,
489         // and that means we always have to consider it.
490         const StyleProperties* properties = rule->propertiesWithoutDeferredParsing();
491         if (properties && properties->isEmpty() && !matchRequest.includeEmptyRules)
492             continue;
493
494         // FIXME: Exposing the non-standard getMatchedCSSRules API to web is the only reason this is needed.
495         if (m_sameOriginOnly && !ruleData.hasDocumentSecurityOrigin())
496             continue;
497
498         unsigned specificity;
499         if (ruleMatches(ruleData, specificity))
500             addMatchedRule(ruleData, specificity, matchRequest.styleScopeOrdinal, ruleRange);
501     }
502 }
503
504 static inline bool compareRules(MatchedRule r1, MatchedRule r2)
505 {
506     // For normal properties the earlier scope wins. This may be reversed by !important which is handled when resolving cascade.
507     if (r1.styleScopeOrdinal != r2.styleScopeOrdinal)
508         return r1.styleScopeOrdinal > r2.styleScopeOrdinal;
509
510     if (r1.specificity != r2.specificity)
511         return r1.specificity < r2.specificity;
512
513     return r1.ruleData->position() < r2.ruleData->position();
514 }
515
516 void ElementRuleCollector::sortMatchedRules()
517 {
518     std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules);
519 }
520
521 void ElementRuleCollector::matchAllRules(bool matchAuthorAndUserStyles, bool includeSMILProperties)
522 {
523     matchUARules();
524
525     // Now we check user sheet rules.
526     if (matchAuthorAndUserStyles)
527         matchUserRules(false);
528
529     // Now check author rules, beginning first with presentational attributes mapped from HTML.
530     if (is<StyledElement>(m_element)) {
531         auto& styledElement = downcast<StyledElement>(m_element);
532         addElementStyleProperties(styledElement.presentationAttributeStyle());
533
534         // Now we check additional mapped declarations.
535         // Tables and table cells share an additional mapped rule that must be applied
536         // after all attributes, since their mapped style depends on the values of multiple attributes.
537         addElementStyleProperties(styledElement.additionalPresentationAttributeStyle());
538
539         if (is<HTMLElement>(styledElement)) {
540             bool isAuto;
541             TextDirection textDirection = downcast<HTMLElement>(styledElement).directionalityIfhasDirAutoAttribute(isAuto);
542             if (isAuto)
543                 m_result.addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
544         }
545     }
546     
547     // Check the rules in author sheets next.
548     if (matchAuthorAndUserStyles)
549         matchAuthorRules(false);
550
551     if (matchAuthorAndUserStyles && is<StyledElement>(m_element)) {
552         auto& styledElement = downcast<StyledElement>(m_element);
553         // Now check our inline style attribute.
554         if (styledElement.inlineStyle()) {
555             // Inline style is immutable as long as there is no CSSOM wrapper.
556             // FIXME: Media control shadow trees seem to have problems with caching.
557             bool isInlineStyleCacheable = !styledElement.inlineStyle()->isMutable() && !styledElement.isInShadowTree();
558             // FIXME: Constify.
559             addElementStyleProperties(styledElement.inlineStyle(), isInlineStyleCacheable);
560         }
561
562         // Now check SMIL animation override style.
563         if (includeSMILProperties && is<SVGElement>(styledElement))
564             addElementStyleProperties(downcast<SVGElement>(styledElement).animatedSMILStyleProperties(), false /* isCacheable */);
565     }
566 }
567
568 bool ElementRuleCollector::hasAnyMatchingRules(const RuleSet* ruleSet)
569 {
570     clearMatchedRules();
571
572     m_mode = SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements;
573     int firstRuleIndex = -1, lastRuleIndex = -1;
574     StyleResolver::RuleRange ruleRange(firstRuleIndex, lastRuleIndex);
575     collectMatchingRules(MatchRequest(ruleSet), ruleRange);
576
577     return !m_matchedRules.isEmpty();
578 }
579
580 } // namespace WebCore