Use a 1-byte enum class for TextDirection
[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     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 == 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.");
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     auto& compiledSelector = ruleData.rule()->compiledSelectorForListIndex(ruleData.selectorListIndex());
387     void* compiledSelectorChecker = compiledSelector.codeRef.code().executableAddress();
388     if (!compiledSelectorChecker && compiledSelector.status == SelectorCompilationStatus::NotCompiled) {
389         compiledSelector.status = SelectorCompiler::compileSelector(ruleData.selector(), SelectorCompiler::SelectorContext::RuleCollector, compiledSelector.codeRef);
390
391         compiledSelectorChecker = compiledSelector.codeRef.code().executableAddress();
392     }
393
394     if (compiledSelectorChecker && compiledSelector.status == SelectorCompilationStatus::SimpleSelectorChecker) {
395         auto selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, compiledSelector.status);
396 #if !ASSERT_MSG_DISABLED
397         unsigned ignoreSpecificity;
398         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.");
399 #endif
400 #if CSS_SELECTOR_JIT_PROFILING
401         ruleData.compiledSelectorUsed();
402 #endif
403         bool selectorMatches = selectorChecker(&m_element, &specificity);
404
405         if (selectorMatches && ruleData.containsUncommonAttributeSelector())
406             m_didMatchUncommonAttributeSelector = true;
407
408         return selectorMatches;
409     }
410 #endif // ENABLE(CSS_SELECTOR_JIT)
411
412     SelectorChecker::CheckingContext context(m_mode);
413     context.pseudoId = m_pseudoStyleRequest.pseudoId;
414     context.scrollbar = m_pseudoStyleRequest.scrollbar;
415     context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;
416     context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass;
417
418     bool selectorMatches;
419 #if ENABLE(CSS_SELECTOR_JIT)
420     if (compiledSelectorChecker) {
421         ASSERT(compiledSelector.status == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
422
423         auto selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, compiledSelector.status);
424
425 #if CSS_SELECTOR_JIT_PROFILING
426         compiledSelector.useCount++;
427 #endif
428         selectorMatches = selectorChecker(&m_element, &context, &specificity);
429     } else
430 #endif // ENABLE(CSS_SELECTOR_JIT)
431     {
432         auto* selector = ruleData.selector();
433         if (m_isMatchingSlottedPseudoElements) {
434             selector = findSlottedPseudoElementSelector(ruleData.selector());
435             if (!selector)
436                 return false;
437         }
438         // Slow path.
439         SelectorChecker selectorChecker(m_element.document());
440         selectorMatches = selectorChecker.match(*selector, m_element, context, specificity);
441     }
442
443     if (ruleData.containsUncommonAttributeSelector()) {
444         if (selectorMatches || context.pseudoIDSet)
445             m_didMatchUncommonAttributeSelector = true;
446     }
447     m_matchedPseudoElementIds.merge(context.pseudoIDSet);
448     m_styleRelations.appendVector(context.styleRelations);
449
450     return selectorMatches;
451 }
452
453 void ElementRuleCollector::collectMatchingRulesForList(const RuleSet::RuleDataVector* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
454 {
455     if (!rules)
456         return;
457
458     for (unsigned i = 0, size = rules->size(); i < size; ++i) {
459         const RuleData& ruleData = rules->data()[i];
460
461         if (!ruleData.canMatchPseudoElement() && m_pseudoStyleRequest.pseudoId != PseudoId::None)
462             continue;
463
464         if (m_selectorFilter && m_selectorFilter->fastRejectSelector(ruleData.descendantSelectorIdentifierHashes()))
465             continue;
466
467         StyleRule* rule = ruleData.rule();
468
469         // If the rule has no properties to apply, then ignore it in the non-debug mode.
470         // Note that if we get null back here, it means we have a rule with deferred properties,
471         // and that means we always have to consider it.
472         const StyleProperties* properties = rule->propertiesWithoutDeferredParsing();
473         if (properties && properties->isEmpty() && !matchRequest.includeEmptyRules)
474             continue;
475
476         unsigned specificity;
477         if (ruleMatches(ruleData, specificity))
478             addMatchedRule(ruleData, specificity, matchRequest.styleScopeOrdinal, ruleRange);
479     }
480 }
481
482 static inline bool compareRules(MatchedRule r1, MatchedRule r2)
483 {
484     // For normal properties the earlier scope wins. This may be reversed by !important which is handled when resolving cascade.
485     if (r1.styleScopeOrdinal != r2.styleScopeOrdinal)
486         return r1.styleScopeOrdinal > r2.styleScopeOrdinal;
487
488     if (r1.specificity != r2.specificity)
489         return r1.specificity < r2.specificity;
490
491     return r1.ruleData->position() < r2.ruleData->position();
492 }
493
494 void ElementRuleCollector::sortMatchedRules()
495 {
496     std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules);
497 }
498
499 void ElementRuleCollector::matchAllRules(bool matchAuthorAndUserStyles, bool includeSMILProperties)
500 {
501     matchUARules();
502
503     // Now we check user sheet rules.
504     if (matchAuthorAndUserStyles)
505         matchUserRules(false);
506
507     // Now check author rules, beginning first with presentational attributes mapped from HTML.
508     if (is<StyledElement>(m_element)) {
509         auto& styledElement = downcast<StyledElement>(m_element);
510         addElementStyleProperties(styledElement.presentationAttributeStyle());
511
512         // Now we check additional mapped declarations.
513         // Tables and table cells share an additional mapped rule that must be applied
514         // after all attributes, since their mapped style depends on the values of multiple attributes.
515         addElementStyleProperties(styledElement.additionalPresentationAttributeStyle());
516
517         if (is<HTMLElement>(styledElement)) {
518             bool isAuto;
519             TextDirection textDirection = downcast<HTMLElement>(styledElement).directionalityIfhasDirAutoAttribute(isAuto);
520             if (isAuto)
521                 m_result.addMatchedProperties(textDirection == TextDirection::LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
522         }
523     }
524     
525     // Check the rules in author sheets next.
526     if (matchAuthorAndUserStyles)
527         matchAuthorRules(false);
528
529     if (matchAuthorAndUserStyles && is<StyledElement>(m_element)) {
530         auto& styledElement = downcast<StyledElement>(m_element);
531         // Now check our inline style attribute.
532         if (styledElement.inlineStyle()) {
533             // Inline style is immutable as long as there is no CSSOM wrapper.
534             // FIXME: Media control shadow trees seem to have problems with caching.
535             bool isInlineStyleCacheable = !styledElement.inlineStyle()->isMutable() && !styledElement.isInShadowTree();
536             // FIXME: Constify.
537             addElementStyleProperties(styledElement.inlineStyle(), isInlineStyleCacheable);
538         }
539
540         // Now check SMIL animation override style.
541         if (includeSMILProperties && is<SVGElement>(styledElement))
542             addElementStyleProperties(downcast<SVGElement>(styledElement).animatedSMILStyleProperties(), false /* isCacheable */);
543     }
544 }
545
546 bool ElementRuleCollector::hasAnyMatchingRules(const RuleSet* ruleSet)
547 {
548     clearMatchedRules();
549
550     m_mode = SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements;
551     int firstRuleIndex = -1, lastRuleIndex = -1;
552     StyleResolver::RuleRange ruleRange(firstRuleIndex, lastRuleIndex);
553     collectMatchingRules(MatchRequest(ruleSet), ruleRange);
554
555     return !m_matchedRules.isEmpty();
556 }
557
558 } // namespace WebCore