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
47namespace WebCore {
48
49static 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
59static 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
69class MatchRequest {
70public:
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
82ElementRuleCollector::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
92ElementRuleCollector::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
100StyleResolver::MatchResult& ElementRuleCollector::matchedResult()
101{
102 ASSERT(m_mode == SelectorChecker::Mode::ResolvingStyle);
103 return m_result;
104}
105
106const Vector<RefPtr<StyleRule>>& ElementRuleCollector::matchedRuleList() const
107{
108 ASSERT(m_mode == SelectorChecker::Mode::CollectingRules);
109 return m_matchedRuleList;
110}
111
112inline 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
122void ElementRuleCollector::clearMatchedRules()
123{
124 m_matchedRules.clear();
125 m_keepAliveSlottedPseudoElementRules.clear();
126}
127
128inline 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
140void 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
167void 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
185void 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
210void 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
222void 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
237void 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
262void 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
278std::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
302void 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
317void 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
334void 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
345static 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
357inline 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
453void 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
482static 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
494void ElementRuleCollector::sortMatchedRules()
495{
496 std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules);
497}
498
499void 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
546bool 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
559