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