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