Add a pseudoclass that matches img elements that are backed by an attachment
[WebKit-https.git] / Source / WebCore / css / SelectorChecker.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-2016 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) 2014 Yusuke Suzuki <utatane.tea@gmail.com>
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 "SelectorChecker.h"
31
32 #include "CSSSelector.h"
33 #include "CSSSelectorList.h"
34 #include "Document.h"
35 #include "ElementTraversal.h"
36 #include "Frame.h"
37 #include "FrameSelection.h"
38 #include "HTMLDocument.h"
39 #include "HTMLNames.h"
40 #include "HTMLParserIdioms.h"
41 #include "HTMLSlotElement.h"
42 #include "InspectorInstrumentation.h"
43 #include "Page.h"
44 #include "RenderElement.h"
45 #include "SelectorCheckerTestFunctions.h"
46 #include "ShadowRoot.h"
47 #include "Text.h"
48
49 namespace WebCore {
50
51 using namespace HTMLNames;
52
53 enum class VisitedMatchType : unsigned char {
54     Disabled, Enabled
55 };
56
57 struct SelectorChecker::LocalContext {
58     LocalContext(const CSSSelector& selector, const Element& element, VisitedMatchType visitedMatchType, PseudoId pseudoId)
59         : selector(&selector)
60         , element(&element)
61         , visitedMatchType(visitedMatchType)
62         , firstSelectorOfTheFragment(&selector)
63         , pseudoId(pseudoId)
64     { }
65
66     const CSSSelector* selector;
67     const Element* element;
68     VisitedMatchType visitedMatchType;
69     const CSSSelector* firstSelectorOfTheFragment;
70     PseudoId pseudoId;
71     bool isMatchElement { true };
72     bool isSubjectOrAdjacentElement { true };
73     bool inFunctionalPseudoClass { false };
74     bool pseudoElementEffective { true };
75     bool hasScrollbarPseudo { false };
76     bool hasSelectionPseudo { false };
77     bool mayMatchHostPseudoClass { false };
78
79 };
80
81 static inline void addStyleRelation(SelectorChecker::CheckingContext& checkingContext, const Element& element, Style::Relation::Type type, unsigned value = 1)
82 {
83     ASSERT(value == 1 || type == Style::Relation::NthChildIndex || type == Style::Relation::AffectedByEmpty);
84     if (checkingContext.resolvingMode != SelectorChecker::Mode::ResolvingStyle)
85         return;
86     if (type == Style::Relation::AffectsNextSibling && !checkingContext.styleRelations.isEmpty()) {
87         auto& last = checkingContext.styleRelations.last();
88         if (last.type == Style::Relation::AffectsNextSibling && last.element == element.nextElementSibling()) {
89             ++last.value;
90             last.element = &element;
91             return;
92         }
93     }
94     checkingContext.styleRelations.append({ element, type, value });
95 }
96
97 static inline bool isFirstChildElement(const Element& element)
98 {
99     return !ElementTraversal::previousSibling(element);
100 }
101
102 static inline bool isLastChildElement(const Element& element)
103 {
104     return !ElementTraversal::nextSibling(element);
105 }
106
107 static inline bool isFirstOfType(const Element& element, const QualifiedName& type)
108 {
109     for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) {
110         if (sibling->hasTagName(type))
111             return false;
112     }
113     return true;
114 }
115
116 static inline bool isLastOfType(const Element& element, const QualifiedName& type)
117 {
118     for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
119         if (sibling->hasTagName(type))
120             return false;
121     }
122     return true;
123 }
124
125 static inline int countElementsBefore(const Element& element)
126 {
127     int count = 0;
128     for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) {
129         unsigned index = sibling->childIndex();
130         if (index) {
131             count += index;
132             break;
133         }
134         count++;
135     }
136     return count;
137 }
138
139 static inline int countElementsOfTypeBefore(const Element& element, const QualifiedName& type)
140 {
141     int count = 0;
142     for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) {
143         if (sibling->hasTagName(type))
144             ++count;
145     }
146     return count;
147 }
148
149 static inline int countElementsAfter(const Element& element)
150 {
151     int count = 0;
152     for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling))
153         ++count;
154     return count;
155 }
156
157 static inline int countElementsOfTypeAfter(const Element& element, const QualifiedName& type)
158 {
159     int count = 0;
160     for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
161         if (sibling->hasTagName(type))
162             ++count;
163     }
164     return count;
165 }
166
167 SelectorChecker::SelectorChecker(Document& document)
168     : m_strictParsing(!document.inQuirksMode())
169     , m_documentIsHTML(document.isHTMLDocument())
170 {
171 }
172
173 bool SelectorChecker::match(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const
174 {
175     specificity = 0;
176
177     LocalContext context(selector, element, checkingContext.resolvingMode == SelectorChecker::Mode::QueryingRules ? VisitedMatchType::Disabled : VisitedMatchType::Enabled, checkingContext.pseudoId);
178
179     if (checkingContext.isMatchingHostPseudoClass) {
180         ASSERT(element.shadowRoot());
181         context.mayMatchHostPseudoClass = true;
182     }
183
184     PseudoIdSet pseudoIdSet;
185     MatchResult result = matchRecursively(checkingContext, context, pseudoIdSet, specificity);
186     if (result.match != Match::SelectorMatches)
187         return false;
188     if (checkingContext.pseudoId != PseudoId::None && !pseudoIdSet.has(checkingContext.pseudoId))
189         return false;
190
191     if (checkingContext.pseudoId == PseudoId::None && pseudoIdSet) {
192         PseudoIdSet publicPseudoIdSet = pseudoIdSet & PseudoIdSet::fromMask(static_cast<unsigned>(PseudoId::PublicPseudoIdMask));
193         if (checkingContext.resolvingMode == Mode::ResolvingStyle && publicPseudoIdSet)
194             checkingContext.pseudoIDSet = publicPseudoIdSet;
195
196         // When ignoring virtual pseudo elements, the context's pseudo should also be PseudoId::None but that does
197         // not cause a failure.
198         return checkingContext.resolvingMode == Mode::CollectingRulesIgnoringVirtualPseudoElements || result.matchType == MatchType::Element;
199     }
200     return true;
201 }
202
203 bool SelectorChecker::matchHostPseudoClass(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const
204 {
205     ASSERT(element.shadowRoot());
206     ASSERT(selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost);
207
208     specificity = selector.simpleSelectorSpecificity();
209
210     if (auto* selectorList = selector.selectorList()) {
211         LocalContext context(*selectorList->first(), element, VisitedMatchType::Enabled, PseudoId::None);
212         context.inFunctionalPseudoClass = true;
213         context.pseudoElementEffective = false;
214         PseudoIdSet ignoreDynamicPseudo;
215         unsigned subselectorSpecificity = 0;
216         if (matchRecursively(checkingContext, context, ignoreDynamicPseudo, subselectorSpecificity).match != Match::SelectorMatches)
217             return false;
218         specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity);
219     }
220     return true;
221 }
222
223 inline static bool hasScrollbarPseudoElement(const PseudoIdSet& dynamicPseudoIdSet)
224 {
225     PseudoIdSet scrollbarIdSet = { PseudoId::Scrollbar, PseudoId::ScrollbarThumb, PseudoId::ScrollbarButton, PseudoId::ScrollbarTrack, PseudoId::ScrollbarTrackPiece, PseudoId::ScrollbarCorner };
226     if (dynamicPseudoIdSet & scrollbarIdSet)
227         return true;
228
229     // PseudoId::Resizer does not always have a scrollbar but it is a scrollbar-like pseudo element
230     // because it can have more than one pseudo element.
231     return dynamicPseudoIdSet.has(PseudoId::Resizer);
232 }
233
234 static SelectorChecker::LocalContext localContextForParent(const SelectorChecker::LocalContext& context)
235 {
236     SelectorChecker::LocalContext updatedContext(context);
237     // Disable :visited matching when we see the first link.
238     if (context.element->isLink())
239         updatedContext.visitedMatchType = VisitedMatchType::Disabled;
240
241     updatedContext.isMatchElement = false;
242     updatedContext.isSubjectOrAdjacentElement = false;
243
244     if (updatedContext.mayMatchHostPseudoClass) {
245         updatedContext.element = nullptr;
246         return updatedContext;
247     }
248
249     // Move to the shadow host if matching :host and the parent is the shadow root.
250     if (context.selector->match() == CSSSelector::PseudoClass && context.selector->pseudoClassType() == CSSSelector::PseudoClassHost && is<ShadowRoot>(context.element->parentNode())) {
251         updatedContext.element = downcast<ShadowRoot>(*context.element->parentNode()).host();
252         updatedContext.mayMatchHostPseudoClass = true;
253         return updatedContext;
254     }
255
256     updatedContext.element = context.element->parentElement();
257     return updatedContext;
258 }
259
260 // Recursive check of selectors and combinators
261 // It can return 4 different values:
262 // * SelectorMatches          - the selector matches the element e
263 // * SelectorFailsLocally     - the selector fails for the element e
264 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
265 // * SelectorFailsCompletely  - the selector fails for e and any sibling or ancestor of e
266 SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet, unsigned& specificity) const
267 {
268     MatchType matchType = MatchType::Element;
269
270     // The first selector has to match.
271     if (!checkOne(checkingContext, context, dynamicPseudoIdSet, matchType, specificity))
272         return MatchResult::fails(Match::SelectorFailsLocally);
273
274     if (context.selector->match() == CSSSelector::PseudoElement) {
275         if (context.selector->isCustomPseudoElement()) {
276             // In functional pseudo class, custom pseudo elements are always disabled.
277             // FIXME: We should accept custom pseudo elements inside :matches().
278             if (context.inFunctionalPseudoClass)
279                 return MatchResult::fails(Match::SelectorFailsCompletely);
280             if (ShadowRoot* root = context.element->containingShadowRoot()) {
281                 if (context.element->shadowPseudoId() != context.selector->value())
282                     return MatchResult::fails(Match::SelectorFailsLocally);
283
284                 if (context.selector->isWebKitCustomPseudoElement() && root->mode() != ShadowRootMode::UserAgent)
285                     return MatchResult::fails(Match::SelectorFailsLocally);
286             } else
287                 return MatchResult::fails(Match::SelectorFailsLocally);
288         } else {
289             if (!context.pseudoElementEffective)
290                 return MatchResult::fails(Match::SelectorFailsCompletely);
291
292             if (checkingContext.resolvingMode == Mode::QueryingRules)
293                 return MatchResult::fails(Match::SelectorFailsCompletely);
294
295             PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoElementType());
296             if (pseudoId != PseudoId::None)
297                 dynamicPseudoIdSet.add(pseudoId);
298             matchType = MatchType::VirtualPseudoElementOnly;
299         }
300     }
301
302     // The rest of the selectors has to match
303     auto relation = context.selector->relation();
304
305     // Prepare next selector
306     const CSSSelector* leftSelector = context.selector->tagHistory();
307     if (!leftSelector)
308         return MatchResult::matches(matchType);
309
310     LocalContext nextContext(context);
311     nextContext.selector = leftSelector;
312
313     if (relation != CSSSelector::Subselector) {
314         // Bail-out if this selector is irrelevant for the pseudoId
315         if (context.pseudoId != PseudoId::None && !dynamicPseudoIdSet.has(context.pseudoId))
316             return MatchResult::fails(Match::SelectorFailsCompletely);
317
318         // Disable :visited matching when we try to match anything else than an ancestors.
319         if (!context.selector->hasDescendantOrChildRelation())
320             nextContext.visitedMatchType = VisitedMatchType::Disabled;
321
322         nextContext.pseudoId = PseudoId::None;
323         // Virtual pseudo element is only effective in the rightmost fragment.
324         nextContext.pseudoElementEffective = false;
325         nextContext.isMatchElement = false;
326     }
327
328     switch (relation) {
329     case CSSSelector::DescendantSpace:
330         nextContext = localContextForParent(nextContext);
331         nextContext.firstSelectorOfTheFragment = nextContext.selector;
332         for (; nextContext.element; nextContext = localContextForParent(nextContext)) {
333             PseudoIdSet ignoreDynamicPseudo;
334             unsigned descendantsSpecificity = 0;
335             MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, descendantsSpecificity);
336             ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
337
338             if (result.match == Match::SelectorMatches)
339                 specificity = CSSSelector::addSpecificities(specificity, descendantsSpecificity);
340
341             if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
342                 return MatchResult::updateWithMatchType(result, matchType);
343         }
344         return MatchResult::fails(Match::SelectorFailsCompletely);
345
346     case CSSSelector::Child:
347         {
348             nextContext = localContextForParent(nextContext);
349             if (!nextContext.element)
350                 return MatchResult::fails(Match::SelectorFailsCompletely);
351             nextContext.firstSelectorOfTheFragment = nextContext.selector;
352             PseudoIdSet ignoreDynamicPseudo;
353             unsigned childSpecificity = 0;
354             MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, childSpecificity);
355             ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
356
357             if (result.match == Match::SelectorMatches)
358                 specificity = CSSSelector::addSpecificities(specificity, childSpecificity);
359
360             if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
361                 return MatchResult::updateWithMatchType(result, matchType);
362             return MatchResult::fails(Match::SelectorFailsAllSiblings);
363         }
364
365     case CSSSelector::DirectAdjacent:
366         {
367             auto relation = context.isMatchElement ? Style::Relation::AffectedByPreviousSibling : Style::Relation::DescendantsAffectedByPreviousSibling;
368             addStyleRelation(checkingContext, *context.element, relation);
369
370             Element* previousElement = context.element->previousElementSibling();
371             if (!previousElement)
372                 return MatchResult::fails(Match::SelectorFailsAllSiblings);
373
374             addStyleRelation(checkingContext, *previousElement, Style::Relation::AffectsNextSibling);
375
376             nextContext.element = previousElement;
377             nextContext.firstSelectorOfTheFragment = nextContext.selector;
378             PseudoIdSet ignoreDynamicPseudo;
379             unsigned adjacentSpecificity = 0;
380             MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, adjacentSpecificity);
381             ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
382
383             if (result.match == Match::SelectorMatches)
384                 specificity = CSSSelector::addSpecificities(specificity, adjacentSpecificity);
385
386             return MatchResult::updateWithMatchType(result, matchType);
387         }
388     case CSSSelector::IndirectAdjacent: {
389         auto relation = context.isMatchElement ? Style::Relation::AffectedByPreviousSibling : Style::Relation::DescendantsAffectedByPreviousSibling;
390         addStyleRelation(checkingContext, *context.element, relation);
391
392         nextContext.element = context.element->previousElementSibling();
393         nextContext.firstSelectorOfTheFragment = nextContext.selector;
394         for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) {
395             addStyleRelation(checkingContext, *nextContext.element, Style::Relation::AffectsNextSibling);
396
397             PseudoIdSet ignoreDynamicPseudo;
398             unsigned indirectAdjacentSpecificity = 0;
399             MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, indirectAdjacentSpecificity);
400             ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
401
402             if (result.match == Match::SelectorMatches)
403                 specificity = CSSSelector::addSpecificities(specificity, indirectAdjacentSpecificity);
404
405             if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsAllSiblings || result.match == Match::SelectorFailsCompletely)
406                 return MatchResult::updateWithMatchType(result, matchType);
407         };
408         return MatchResult::fails(Match::SelectorFailsAllSiblings);
409     }
410     case CSSSelector::Subselector:
411         {
412             // a selector is invalid if something follows a pseudo-element
413             // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
414             // to follow the pseudo elements.
415             nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudoIdSet);
416             nextContext.hasSelectionPseudo = dynamicPseudoIdSet.has(PseudoId::Selection);
417             if ((context.isMatchElement || checkingContext.resolvingMode == Mode::CollectingRules) && dynamicPseudoIdSet
418                 && !nextContext.hasSelectionPseudo
419                 && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass))
420                 return MatchResult::fails(Match::SelectorFailsCompletely);
421
422             unsigned subselectorSpecificity = 0;
423             MatchResult result = matchRecursively(checkingContext, nextContext, dynamicPseudoIdSet, subselectorSpecificity);
424
425             if (result.match == Match::SelectorMatches)
426                 specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity);
427
428             return MatchResult::updateWithMatchType(result, matchType);
429         }
430     case CSSSelector::ShadowDescendant:
431         {
432             Element* shadowHostNode = context.element->shadowHost();
433             if (!shadowHostNode)
434                 return MatchResult::fails(Match::SelectorFailsCompletely);
435             nextContext.element = shadowHostNode;
436             nextContext.firstSelectorOfTheFragment = nextContext.selector;
437             nextContext.isSubjectOrAdjacentElement = false;
438             PseudoIdSet ignoreDynamicPseudo;
439             unsigned shadowDescendantSpecificity = 0;
440             MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, shadowDescendantSpecificity);
441
442             if (result.match == Match::SelectorMatches)
443                 specificity = CSSSelector::addSpecificities(specificity, shadowDescendantSpecificity);
444
445             return MatchResult::updateWithMatchType(result, matchType);
446         }
447     }
448
449
450     ASSERT_NOT_REACHED();
451     return MatchResult::fails(Match::SelectorFailsCompletely);
452 }
453
454 static bool attributeValueMatches(const Attribute& attribute, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive)
455 {
456     const AtomicString& value = attribute.value();
457     ASSERT(!value.isNull());
458
459     switch (match) {
460     case CSSSelector::Set:
461         break;
462     case CSSSelector::Exact:
463         if (caseSensitive ? selectorValue != value : !equalIgnoringASCIICase(selectorValue, value))
464             return false;
465         break;
466     case CSSSelector::List:
467         {
468             // Ignore empty selectors or selectors containing spaces.
469             if (selectorValue.isEmpty() || selectorValue.find(isHTMLSpace<UChar>) != notFound)
470                 return false;
471
472             unsigned startSearchAt = 0;
473             while (true) {
474                 size_t foundPos;
475                 if (caseSensitive)
476                     foundPos = value.find(selectorValue, startSearchAt);
477                 else
478                     foundPos = value.findIgnoringASCIICase(selectorValue, startSearchAt);
479                 if (foundPos == notFound)
480                     return false;
481                 if (!foundPos || isHTMLSpace(value[foundPos - 1])) {
482                     unsigned endStr = foundPos + selectorValue.length();
483                     if (endStr == value.length() || isHTMLSpace(value[endStr]))
484                         break; // We found a match.
485                 }
486
487                 // No match. Keep looking.
488                 startSearchAt = foundPos + 1;
489             }
490             break;
491         }
492     case CSSSelector::Contain: {
493         bool valueContainsSelectorValue;
494         if (caseSensitive)
495             valueContainsSelectorValue = value.contains(selectorValue);
496         else
497             valueContainsSelectorValue = value.containsIgnoringASCIICase(selectorValue);
498
499         if (!valueContainsSelectorValue || selectorValue.isEmpty())
500             return false;
501
502         break;
503     }
504     case CSSSelector::Begin:
505         if (selectorValue.isEmpty())
506             return false;
507         if (caseSensitive) {
508             if (!value.startsWith(selectorValue))
509                 return false;
510         } else {
511             if (!value.startsWithIgnoringASCIICase(selectorValue))
512                 return false;
513         }
514         break;
515     case CSSSelector::End:
516         if (selectorValue.isEmpty())
517             return false;
518         if (caseSensitive) {
519             if (!value.endsWith(selectorValue))
520                 return false;
521         } else {
522             if (!value.endsWithIgnoringASCIICase(selectorValue))
523                 return false;
524         }
525         break;
526     case CSSSelector::Hyphen:
527         if (value.length() < selectorValue.length())
528             return false;
529         if (caseSensitive) {
530             if (!value.startsWith(selectorValue))
531                 return false;
532         } else {
533             if (!value.startsWithIgnoringASCIICase(selectorValue))
534                 return false;
535         }
536         // It they start the same, check for exact match or following '-':
537         if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-')
538             return false;
539         break;
540     default:
541         ASSERT_NOT_REACHED();
542         return false;
543     }
544
545     return true;
546 }
547
548 static bool anyAttributeMatches(const Element& element, const CSSSelector& selector, const QualifiedName& selectorAttr, bool caseSensitive)
549 {
550     ASSERT(element.hasAttributesWithoutUpdate());
551     for (const Attribute& attribute : element.attributesIterator()) {
552         if (!attribute.matches(selectorAttr.prefix(), element.isHTMLElement() ? selector.attributeCanonicalLocalName() : selectorAttr.localName(), selectorAttr.namespaceURI()))
553             continue;
554
555         if (attributeValueMatches(attribute, selector.match(), selector.value(), caseSensitive))
556             return true;
557     }
558
559     return false;
560 }
561
562 bool SelectorChecker::attributeSelectorMatches(const Element& element, const QualifiedName& attributeName, const AtomicString& attributeValue, const CSSSelector& selector)
563 {
564     ASSERT(selector.isAttributeSelector());
565     auto& selectorAttribute = selector.attribute();
566     auto& selectorName = element.isHTMLElement() ? selector.attributeCanonicalLocalName() : selectorAttribute.localName();
567     if (!Attribute::nameMatchesFilter(attributeName, selectorAttribute.prefix(), selectorName, selectorAttribute.namespaceURI()))
568         return false;
569     bool caseSensitive = true;
570     if (selector.attributeValueMatchingIsCaseInsensitive())
571         caseSensitive = false;
572     else if (element.document().isHTMLDocument() && element.isHTMLElement() && !HTMLDocument::isCaseSensitiveAttribute(selector.attribute()))
573         caseSensitive = false;
574     return attributeValueMatches(Attribute(attributeName, attributeValue), selector.match(), selector.value(), caseSensitive);
575 }
576
577 static bool canMatchHoverOrActiveInQuirksMode(const SelectorChecker::LocalContext& context)
578 {
579     // For quirks mode, follow this: http://quirks.spec.whatwg.org/#the-:active-and-:hover-quirk
580     // In quirks mode, a compound selector 'selector' that matches the following conditions must not match elements that would not also match the ':any-link' selector.
581     //
582     //    selector uses the ':active' or ':hover' pseudo-classes.
583     //    selector does not use a type selector.
584     //    selector does not use an attribute selector.
585     //    selector does not use an ID selector.
586     //    selector does not use a class selector.
587     //    selector does not use a pseudo-class selector other than ':active' and ':hover'.
588     //    selector does not use a pseudo-element selector.
589     //    selector is not part of an argument to a functional pseudo-class or pseudo-element.
590     if (context.inFunctionalPseudoClass)
591         return true;
592
593     for (const CSSSelector* selector = context.firstSelectorOfTheFragment; selector; selector = selector->tagHistory()) {
594         switch (selector->match()) {
595         case CSSSelector::Tag:
596             if (selector->tagQName() != anyQName())
597                 return true;
598             break;
599         case CSSSelector::PseudoClass: {
600             CSSSelector::PseudoClassType pseudoClassType = selector->pseudoClassType();
601             if (pseudoClassType != CSSSelector::PseudoClassHover && pseudoClassType != CSSSelector::PseudoClassActive)
602                 return true;
603             break;
604         }
605         case CSSSelector::Id:
606         case CSSSelector::Class:
607         case CSSSelector::Exact:
608         case CSSSelector::Set:
609         case CSSSelector::List:
610         case CSSSelector::Hyphen:
611         case CSSSelector::Contain:
612         case CSSSelector::Begin:
613         case CSSSelector::End:
614         case CSSSelector::PagePseudoClass:
615         case CSSSelector::PseudoElement:
616             return true;
617         case CSSSelector::Unknown:
618             ASSERT_NOT_REACHED();
619             break;
620         }
621
622         auto relation = selector->relation();
623         if (relation == CSSSelector::ShadowDescendant)
624             return true;
625
626         if (relation != CSSSelector::Subselector)
627             return false;
628     }
629     return false;
630 }
631
632 static inline bool tagMatches(const Element& element, const CSSSelector& simpleSelector)
633 {
634     const QualifiedName& tagQName = simpleSelector.tagQName();
635
636     if (tagQName == anyQName())
637         return true;
638
639     const AtomicString& localName = (element.isHTMLElement() && element.document().isHTMLDocument()) ? simpleSelector.tagLowercaseLocalName() : tagQName.localName();
640
641     if (localName != starAtom() && localName != element.localName())
642         return false;
643     const AtomicString& namespaceURI = tagQName.namespaceURI();
644     return namespaceURI == starAtom() || namespaceURI == element.namespaceURI();
645 }
646
647 bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet, MatchType& matchType, unsigned& specificity) const
648 {
649     const Element& element = *context.element;
650     const CSSSelector& selector = *context.selector;
651
652     specificity = CSSSelector::addSpecificities(specificity, selector.simpleSelectorSpecificity());
653
654     if (context.mayMatchHostPseudoClass) {
655         // :host doesn't combine with anything except pseudo elements.
656         bool isHostPseudoClass = selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost;
657         bool isPseudoElement = selector.match() == CSSSelector::PseudoElement;
658         if (!isHostPseudoClass && !isPseudoElement)
659             return false;
660     }
661
662     if (selector.match() == CSSSelector::Tag)
663         return tagMatches(element, selector);
664
665     if (selector.match() == CSSSelector::Class)
666         return element.hasClass() && element.classNames().contains(selector.value());
667
668     if (selector.match() == CSSSelector::Id) {
669         ASSERT(!selector.value().isNull());
670         return element.idForStyleResolution() == selector.value();
671     }
672
673     if (selector.isAttributeSelector()) {
674         if (!element.hasAttributes())
675             return false;
676
677         const QualifiedName& attr = selector.attribute();
678         bool caseSensitive = true;
679         if (selector.attributeValueMatchingIsCaseInsensitive())
680             caseSensitive = false;
681         else if (m_documentIsHTML && element.isHTMLElement() && !HTMLDocument::isCaseSensitiveAttribute(attr))
682             caseSensitive = false;
683
684         return anyAttributeMatches(element, selector, attr, caseSensitive);
685     }
686
687     if (selector.match() == CSSSelector::PseudoClass) {
688         // Handle :not up front.
689         if (selector.pseudoClassType() == CSSSelector::PseudoClassNot) {
690             const CSSSelectorList* selectorList = selector.selectorList();
691
692             for (const CSSSelector* subselector = selectorList->first(); subselector; subselector = CSSSelectorList::next(subselector)) {
693                 LocalContext subcontext(context);
694                 subcontext.inFunctionalPseudoClass = true;
695                 subcontext.pseudoElementEffective = false;
696                 subcontext.selector = subselector;
697                 subcontext.firstSelectorOfTheFragment = selectorList->first();
698                 PseudoIdSet ignoreDynamicPseudo;
699
700                 unsigned ignoredSpecificity;
701                 if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches) {
702                     ASSERT(!ignoreDynamicPseudo);
703                     return false;
704                 }
705             }
706             return true;
707         }
708         if (context.hasScrollbarPseudo) {
709             // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
710             // (since there are no elements involved except with window-inactive).
711             return checkScrollbarPseudoClass(checkingContext, element, selector);
712         }
713
714         // Normal element pseudo class checking.
715         switch (selector.pseudoClassType()) {
716             // Pseudo classes:
717         case CSSSelector::PseudoClassNot:
718             break; // Already handled up above.
719         case CSSSelector::PseudoClassEmpty:
720             {
721                 bool result = true;
722                 for (Node* node = element.firstChild(); node; node = node->nextSibling()) {
723                     if (is<Element>(*node)) {
724                         result = false;
725                         break;
726                     }
727                     if (is<Text>(*node)) {
728                         Text& textNode = downcast<Text>(*node);
729                         if (!textNode.data().isEmpty()) {
730                             result = false;
731                             break;
732                         }
733                     }
734                 }
735                 addStyleRelation(checkingContext, *context.element, Style::Relation::AffectedByEmpty, result);
736
737                 return result;
738             }
739         case CSSSelector::PseudoClassFirstChild: {
740             // first-child matches the first child that is an element
741             bool isFirstChild = isFirstChildElement(element);
742             auto* parent = element.parentNode();
743             if (is<Element>(parent))
744                 addStyleRelation(checkingContext, downcast<Element>(*parent), Style::Relation::ChildrenAffectedByFirstChildRules);
745             else if (!is<ShadowRoot>(parent))
746                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
747             if (!isFirstChild)
748                 break;
749             addStyleRelation(checkingContext, element, Style::Relation::FirstChild);
750             return true;
751         }
752         case CSSSelector::PseudoClassFirstOfType: {
753             // first-of-type matches the first element of its type
754             auto* parent = element.parentNode();
755             if (is<Element>(parent)) {
756                 auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
757                 addStyleRelation(checkingContext, downcast<Element>(*parent), relation);
758             } else if (!is<ShadowRoot>(parent))
759                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
760             return isFirstOfType(element, element.tagQName());
761         }
762         case CSSSelector::PseudoClassLastChild: {
763             // last-child matches the last child that is an element
764             auto* parent = element.parentNode();
765             bool isLastChild = isLastChildElement(element);
766             if (is<Element>(parent)) {
767                 auto& parentElement = downcast<Element>(*parent);
768                 if (!parentElement.isFinishedParsingChildren())
769                     isLastChild = false;
770                 addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByLastChildRules);
771             } else if (!is<ShadowRoot>(parent))
772                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
773             if (!isLastChild)
774                 break;
775             addStyleRelation(checkingContext, element, Style::Relation::LastChild);
776             return true;
777         }
778         case CSSSelector::PseudoClassLastOfType: {
779             // last-of-type matches the last element of its type
780             auto* parent = element.parentNode();
781             if (is<Element>(parent)) {
782                 auto& parentElement = downcast<Element>(*parent);
783                 auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
784                 addStyleRelation(checkingContext, parentElement, relation);
785                 if (!parentElement.isFinishedParsingChildren())
786                     return false;
787             } else if (!is<ShadowRoot>(parent))
788                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
789             return isLastOfType(element, element.tagQName());
790         }
791         case CSSSelector::PseudoClassOnlyChild: {
792             auto* parent = element.parentNode();
793             bool firstChild = isFirstChildElement(element);
794             bool onlyChild = firstChild && isLastChildElement(element);
795             if (is<Element>(parent)) {
796                 auto& parentElement = downcast<Element>(*parent);
797                 addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByFirstChildRules);
798                 addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByLastChildRules);
799                 if (!parentElement.isFinishedParsingChildren())
800                     onlyChild = false;
801             } else if (!is<ShadowRoot>(parent))
802                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
803             if (firstChild)
804                 addStyleRelation(checkingContext, element, Style::Relation::FirstChild);
805             if (onlyChild)
806                 addStyleRelation(checkingContext, element, Style::Relation::LastChild);
807             return onlyChild;
808         }
809         case CSSSelector::PseudoClassOnlyOfType: {
810             // FIXME: This selector is very slow.
811             auto* parent = element.parentNode();
812             if (is<Element>(parent)) {
813                 auto& parentElement = downcast<Element>(*parent);
814                 auto forwardRelation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
815                 addStyleRelation(checkingContext, parentElement, forwardRelation);
816                 auto backwardRelation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
817                 addStyleRelation(checkingContext, parentElement, backwardRelation);
818
819                 if (!parentElement.isFinishedParsingChildren())
820                     return false;
821             } else if (!is<ShadowRoot>(parent))
822                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
823             return isFirstOfType(element, element.tagQName()) && isLastOfType(element, element.tagQName());
824         }
825         case CSSSelector::PseudoClassMatches:
826             {
827                 bool hasMatchedAnything = false;
828                 unsigned maxSpecificity = 0;
829
830                 MatchType localMatchType = MatchType::VirtualPseudoElementOnly;
831                 for (const CSSSelector* subselector = selector.selectorList()->first(); subselector; subselector = CSSSelectorList::next(subselector)) {
832                     LocalContext subcontext(context);
833                     subcontext.inFunctionalPseudoClass = true;
834                     subcontext.pseudoElementEffective = context.pseudoElementEffective;
835                     subcontext.selector = subselector;
836                     subcontext.firstSelectorOfTheFragment = subselector;
837                     PseudoIdSet localDynamicPseudoIdSet;
838                     unsigned localSpecificity = 0;
839                     MatchResult result = matchRecursively(checkingContext, subcontext, localDynamicPseudoIdSet, localSpecificity);
840                     if (result.match == Match::SelectorMatches) {
841                         maxSpecificity = std::max(maxSpecificity, localSpecificity);
842
843                         if (result.matchType == MatchType::Element)
844                             localMatchType = MatchType::Element;
845
846                         dynamicPseudoIdSet.merge(localDynamicPseudoIdSet);
847                         hasMatchedAnything = true;
848                     }
849                 }
850                 if (hasMatchedAnything) {
851                     matchType = localMatchType;
852                     specificity = CSSSelector::addSpecificities(specificity, maxSpecificity);
853                 }
854                 return hasMatchedAnything;
855             }
856         case CSSSelector::PseudoClassPlaceholderShown:
857             if (is<HTMLTextFormControlElement>(element)) {
858                 addStyleRelation(checkingContext, element, Style::Relation::Unique);
859                 return downcast<HTMLTextFormControlElement>(element).isPlaceholderVisible();
860             }
861             return false;
862         case CSSSelector::PseudoClassNthChild: {
863             auto* parent = element.parentNode();
864             if (is<Element>(parent)) {
865                 auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
866                 addStyleRelation(checkingContext, downcast<Element>(*parent), relation);
867             } else if (!is<ShadowRoot>(parent))
868                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
869
870             if (const CSSSelectorList* selectorList = selector.selectorList()) {
871                 unsigned selectorListSpecificity;
872                 if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity))
873                     return false;
874                 specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity);
875             }
876
877             int count = 1;
878             if (const CSSSelectorList* selectorList = selector.selectorList()) {
879                 for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) {
880                     unsigned ignoredSpecificity;
881                     if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity))
882                         ++count;
883                 }
884             } else {
885                 count += countElementsBefore(element);
886                 addStyleRelation(checkingContext, element, Style::Relation::NthChildIndex, count);
887             }
888
889             if (selector.matchNth(count))
890                 return true;
891             break;
892         }
893         case CSSSelector::PseudoClassNthOfType: {
894             auto* parent = element.parentNode();
895             if (is<Element>(parent)) {
896                 auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
897                 addStyleRelation(checkingContext, downcast<Element>(*parent), relation);
898             } else if (!is<ShadowRoot>(parent))
899                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
900
901             int count = 1 + countElementsOfTypeBefore(element, element.tagQName());
902             if (selector.matchNth(count))
903                 return true;
904             break;
905         }
906         case CSSSelector::PseudoClassNthLastChild: {
907             auto* parent = element.parentNode();
908             if (is<Element>(parent)) {
909                 auto& parentElement = downcast<Element>(*parent);
910                 if (const CSSSelectorList* selectorList = selector.selectorList()) {
911                     unsigned selectorListSpecificity;
912                     if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity))
913                         return false;
914                     specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity);
915
916                     addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules);
917                 } else {
918                     auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
919                     addStyleRelation(checkingContext, parentElement, relation);
920                 }
921                 if (!parentElement.isFinishedParsingChildren())
922                     return false;
923             } else if (!is<ShadowRoot>(parent))
924                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
925
926             int count = 1;
927             if (const CSSSelectorList* selectorList = selector.selectorList()) {
928                 for (Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
929                     unsigned ignoredSpecificity;
930                     if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity))
931                         ++count;
932                 }
933             } else
934                 count += countElementsAfter(element);
935
936             return selector.matchNth(count);
937         }
938         case CSSSelector::PseudoClassNthLastOfType: {
939             auto* parent = element.parentNode();
940             if (is<Element>(parent)) {
941                 auto& parentElement = downcast<Element>(*parent);
942                 auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
943                 addStyleRelation(checkingContext, parentElement, relation);
944
945                 if (!parentElement.isFinishedParsingChildren())
946                     return false;
947             } else if (!is<ShadowRoot>(parent))
948                 break; // FIXME: Add the support for specifying relations on ShadowRoot.
949             int count = 1 + countElementsOfTypeAfter(element, element.tagQName());
950             return selector.matchNth(count);
951         }
952         case CSSSelector::PseudoClassTarget:
953             if (&element == element.document().cssTarget())
954                 return true;
955             break;
956         case CSSSelector::PseudoClassAny:
957             {
958                 LocalContext subcontext(context);
959                 subcontext.inFunctionalPseudoClass = true;
960                 subcontext.pseudoElementEffective = false;
961                 for (subcontext.selector = selector.selectorList()->first(); subcontext.selector; subcontext.selector = CSSSelectorList::next(subcontext.selector)) {
962                     subcontext.firstSelectorOfTheFragment = subcontext.selector;
963                     PseudoIdSet ignoreDynamicPseudo;
964                     unsigned ingoredSpecificity = 0;
965                     if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, ingoredSpecificity).match == Match::SelectorMatches)
966                         return true;
967                 }
968             }
969             break;
970         case CSSSelector::PseudoClassAutofill:
971             return isAutofilled(element);
972         case CSSSelector::PseudoClassAutofillStrongPassword:
973             return isAutofilledStrongPassword(element);
974         case CSSSelector::PseudoClassAnyLink:
975         case CSSSelector::PseudoClassAnyLinkDeprecated:
976         case CSSSelector::PseudoClassLink:
977             // :visited and :link matches are separated later when applying the style. Here both classes match all links...
978             return element.isLink();
979         case CSSSelector::PseudoClassVisited:
980             // ...except if :visited matching is disabled for ancestor/sibling matching.
981             // Inside functional pseudo class except for :not, :visited never matches.
982             if (context.inFunctionalPseudoClass)
983                 return false;
984             return element.isLink() && context.visitedMatchType == VisitedMatchType::Enabled;
985         case CSSSelector::PseudoClassDrag:
986             addStyleRelation(checkingContext, element, Style::Relation::AffectedByDrag);
987
988             if (element.renderer() && element.renderer()->isDragging())
989                 return true;
990             break;
991         case CSSSelector::PseudoClassFocus:
992             return matchesFocusPseudoClass(element);
993         case CSSSelector::PseudoClassFocusWithin:
994             addStyleRelation(checkingContext, element, Style::Relation::AffectedByFocusWithin);
995             return element.hasFocusWithin();
996         case CSSSelector::PseudoClassHover:
997             if (m_strictParsing || element.isLink() || canMatchHoverOrActiveInQuirksMode(context)) {
998                 addStyleRelation(checkingContext, element, Style::Relation::AffectedByHover);
999
1000                 // See the comment in generateElementIsHovered() in SelectorCompiler.
1001                 if (checkingContext.resolvingMode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && !context.isMatchElement)
1002                     return true;
1003
1004                 if (element.hovered() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassHover))
1005                     return true;
1006             }
1007             break;
1008         case CSSSelector::PseudoClassActive:
1009             if (m_strictParsing || element.isLink() || canMatchHoverOrActiveInQuirksMode(context)) {
1010                 addStyleRelation(checkingContext, element, Style::Relation::AffectedByActive);
1011
1012                 if (element.active() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassActive))
1013                     return true;
1014             }
1015             break;
1016         case CSSSelector::PseudoClassEnabled:
1017             return matchesEnabledPseudoClass(element);
1018         case CSSSelector::PseudoClassFullPageMedia:
1019             return isMediaDocument(element);
1020         case CSSSelector::PseudoClassDefault:
1021             return matchesDefaultPseudoClass(element);
1022         case CSSSelector::PseudoClassDisabled:
1023             return matchesDisabledPseudoClass(element);
1024         case CSSSelector::PseudoClassReadOnly:
1025             return matchesReadOnlyPseudoClass(element);
1026         case CSSSelector::PseudoClassReadWrite:
1027             return matchesReadWritePseudoClass(element);
1028         case CSSSelector::PseudoClassOptional:
1029             return isOptionalFormControl(element);
1030         case CSSSelector::PseudoClassRequired:
1031             return isRequiredFormControl(element);
1032         case CSSSelector::PseudoClassValid:
1033             return isValid(element);
1034         case CSSSelector::PseudoClassInvalid:
1035             return isInvalid(element);
1036         case CSSSelector::PseudoClassChecked:
1037             return isChecked(element);
1038         case CSSSelector::PseudoClassIndeterminate:
1039             return matchesIndeterminatePseudoClass(element);
1040         case CSSSelector::PseudoClassRoot:
1041             if (&element == element.document().documentElement())
1042                 return true;
1043             break;
1044         case CSSSelector::PseudoClassLang:
1045             {
1046                 ASSERT(selector.langArgumentList() && !selector.langArgumentList()->isEmpty());
1047                 return matchesLangPseudoClass(element, *selector.langArgumentList());
1048             }
1049 #if ENABLE(FULLSCREEN_API)
1050         case CSSSelector::PseudoClassFullScreen:
1051             return matchesFullScreenPseudoClass(element);
1052         case CSSSelector::PseudoClassAnimatingFullScreenTransition:
1053             return matchesFullScreenAnimatingFullScreenTransitionPseudoClass(element);
1054         case CSSSelector::PseudoClassFullScreenAncestor:
1055             return matchesFullScreenAncestorPseudoClass(element);
1056         case CSSSelector::PseudoClassFullScreenDocument:
1057             return matchesFullScreenDocumentPseudoClass(element);
1058         case CSSSelector::PseudoClassFullScreenControlsHidden:
1059             return matchesFullScreenControlsHiddenPseudoClass(element);
1060 #endif
1061         case CSSSelector::PseudoClassInRange:
1062             return isInRange(element);
1063         case CSSSelector::PseudoClassOutOfRange:
1064             return isOutOfRange(element);
1065 #if ENABLE(VIDEO_TRACK)
1066         case CSSSelector::PseudoClassFuture:
1067             return matchesFutureCuePseudoClass(element);
1068         case CSSSelector::PseudoClassPast:
1069             return matchesPastCuePseudoClass(element);
1070 #endif
1071
1072         case CSSSelector::PseudoClassScope: {
1073             const Node* contextualReferenceNode = !checkingContext.scope ? element.document().documentElement() : checkingContext.scope;
1074             if (&element == contextualReferenceNode)
1075                 return true;
1076             break;
1077         }
1078         case CSSSelector::PseudoClassHost: {
1079             if (!context.mayMatchHostPseudoClass)
1080                 return false;
1081             unsigned hostSpecificity;
1082             if (!matchHostPseudoClass(selector, element, checkingContext, hostSpecificity))
1083                 return false;
1084             specificity = CSSSelector::addSpecificities(specificity, hostSpecificity);
1085             return true;
1086         }
1087         case CSSSelector::PseudoClassDefined:
1088             return isDefinedElement(element);
1089         case CSSSelector::PseudoClassWindowInactive:
1090             return isWindowInactive(element);
1091
1092         case CSSSelector::PseudoClassHorizontal:
1093         case CSSSelector::PseudoClassVertical:
1094         case CSSSelector::PseudoClassDecrement:
1095         case CSSSelector::PseudoClassIncrement:
1096         case CSSSelector::PseudoClassStart:
1097         case CSSSelector::PseudoClassEnd:
1098         case CSSSelector::PseudoClassDoubleButton:
1099         case CSSSelector::PseudoClassSingleButton:
1100         case CSSSelector::PseudoClassNoButton:
1101         case CSSSelector::PseudoClassCornerPresent:
1102             return false;
1103
1104 #if ENABLE(CSS_SELECTORS_LEVEL4)
1105         // FIXME: Implement :dir() selector.
1106         case CSSSelector::PseudoClassDir:
1107             return false;
1108
1109         // FIXME: Implement :role() selector.
1110         case CSSSelector::PseudoClassRole:
1111             return false;
1112 #endif
1113
1114 #if ENABLE(ATTACHMENT_ELEMENT)
1115         case CSSSelector::PseudoClassHasAttachment:
1116             return hasAttachment(element);
1117 #endif
1118
1119         case CSSSelector::PseudoClassUnknown:
1120             ASSERT_NOT_REACHED();
1121             break;
1122         }
1123         return false;
1124     }
1125 #if ENABLE(VIDEO_TRACK)
1126     if (selector.match() == CSSSelector::PseudoElement && selector.pseudoElementType() == CSSSelector::PseudoElementCue) {
1127         LocalContext subcontext(context);
1128
1129         const CSSSelector* const & selector = context.selector;
1130         for (subcontext.selector = selector->selectorList()->first(); subcontext.selector; subcontext.selector = CSSSelectorList::next(subcontext.selector)) {
1131             subcontext.firstSelectorOfTheFragment = subcontext.selector;
1132             subcontext.inFunctionalPseudoClass = true;
1133             subcontext.pseudoElementEffective = false;
1134             PseudoIdSet ignoredDynamicPseudo;
1135             unsigned ignoredSpecificity = 0;
1136             if (matchRecursively(checkingContext, subcontext, ignoredDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches)
1137                 return true;
1138         }
1139         return false;
1140     }
1141 #endif
1142     if (selector.match() == CSSSelector::PseudoElement && selector.pseudoElementType() == CSSSelector::PseudoElementSlotted) {
1143         // We see ::slotted() pseudo elements when collecting slotted rules from the slot shadow tree only.
1144         ASSERT(checkingContext.resolvingMode == Mode::CollectingRules);
1145         return is<HTMLSlotElement>(element);
1146     }
1147     return true;
1148 }
1149
1150 bool SelectorChecker::matchSelectorList(CheckingContext& checkingContext, const LocalContext& context, const Element& element, const CSSSelectorList& selectorList, unsigned& specificity) const
1151 {
1152     specificity = 0;
1153     bool hasMatchedAnything = false;
1154
1155     for (const CSSSelector* subselector = selectorList.first(); subselector; subselector = CSSSelectorList::next(subselector)) {
1156         LocalContext subcontext(context);
1157         subcontext.element = &element;
1158         subcontext.selector = subselector;
1159         subcontext.inFunctionalPseudoClass = true;
1160         subcontext.pseudoElementEffective = false;
1161         subcontext.firstSelectorOfTheFragment = subselector;
1162         PseudoIdSet ignoreDynamicPseudo;
1163         unsigned localSpecificity = 0;
1164         if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, localSpecificity).match == Match::SelectorMatches) {
1165             ASSERT(!ignoreDynamicPseudo);
1166
1167             hasMatchedAnything = true;
1168             specificity = std::max(specificity, localSpecificity);
1169         }
1170     }
1171     return hasMatchedAnything;
1172 }
1173
1174 bool SelectorChecker::checkScrollbarPseudoClass(const CheckingContext& checkingContext, const Element& element, const CSSSelector& selector) const
1175 {
1176     ASSERT(selector.match() == CSSSelector::PseudoClass);
1177
1178     switch (selector.pseudoClassType()) {
1179     case CSSSelector::PseudoClassWindowInactive:
1180         return isWindowInactive(element);
1181     case CSSSelector::PseudoClassEnabled:
1182         return scrollbarMatchesEnabledPseudoClass(checkingContext);
1183     case CSSSelector::PseudoClassDisabled:
1184         return scrollbarMatchesDisabledPseudoClass(checkingContext);
1185     case CSSSelector::PseudoClassHover:
1186         return scrollbarMatchesHoverPseudoClass(checkingContext);
1187     case CSSSelector::PseudoClassActive:
1188         return scrollbarMatchesActivePseudoClass(checkingContext);
1189     case CSSSelector::PseudoClassHorizontal:
1190         return scrollbarMatchesHorizontalPseudoClass(checkingContext);
1191     case CSSSelector::PseudoClassVertical:
1192         return scrollbarMatchesVerticalPseudoClass(checkingContext);
1193     case CSSSelector::PseudoClassDecrement:
1194         return scrollbarMatchesDecrementPseudoClass(checkingContext);
1195     case CSSSelector::PseudoClassIncrement:
1196         return scrollbarMatchesIncrementPseudoClass(checkingContext);
1197     case CSSSelector::PseudoClassStart:
1198         return scrollbarMatchesStartPseudoClass(checkingContext);
1199     case CSSSelector::PseudoClassEnd:
1200         return scrollbarMatchesEndPseudoClass(checkingContext);
1201     case CSSSelector::PseudoClassDoubleButton:
1202         return scrollbarMatchesDoubleButtonPseudoClass(checkingContext);
1203     case CSSSelector::PseudoClassSingleButton:
1204         return scrollbarMatchesSingleButtonPseudoClass(checkingContext);
1205     case CSSSelector::PseudoClassNoButton:
1206         return scrollbarMatchesNoButtonPseudoClass(checkingContext);
1207     case CSSSelector::PseudoClassCornerPresent:
1208         return scrollbarMatchesCornerPresentPseudoClass(checkingContext);
1209     default:
1210         return false;
1211     }
1212 }
1213
1214 unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector)
1215 {
1216     unsigned linkMatchType = MatchAll;
1217
1218     // Statically determine if this selector will match a link in visited, unvisited or any state, or never.
1219     // :visited never matches other elements than the innermost link element.
1220     for (; selector; selector = selector->tagHistory()) {
1221         if (selector->match() == CSSSelector::PseudoClass) {
1222             switch (selector->pseudoClassType()) {
1223             case CSSSelector::PseudoClassLink:
1224                 linkMatchType &= ~SelectorChecker::MatchVisited;
1225                 break;
1226             case CSSSelector::PseudoClassVisited:
1227                 linkMatchType &= ~SelectorChecker::MatchLink;
1228                 break;
1229             default:
1230                 break;
1231             }
1232         }
1233         auto relation = selector->relation();
1234         if (relation == CSSSelector::Subselector)
1235             continue;
1236         if (!selector->hasDescendantOrChildRelation())
1237             return linkMatchType;
1238         if (linkMatchType != MatchAll)
1239             return linkMatchType;
1240     }
1241     return linkMatchType;
1242 }
1243
1244 static bool isFrameFocused(const Element& element)
1245 {
1246     return element.document().frame() && element.document().frame()->selection().isFocusedAndActive();
1247 }
1248
1249 bool SelectorChecker::matchesFocusPseudoClass(const Element& element)
1250 {
1251     if (InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocus))
1252         return true;
1253     return element.focused() && isFrameFocused(element);
1254 }
1255
1256 }