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