d95fca32c9c184873755a44150577c07a2ec9680
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 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  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "core/css/SelectorChecker.h"
30
31 #include "core/HTMLNames.h"
32 #include "core/css/CSSSelectorList.h"
33 #include "core/css/SiblingTraversalStrategies.h"
34 #include "core/dom/Document.h"
35 #include "core/dom/ElementTraversal.h"
36 #include "core/dom/FullscreenElementStack.h"
37 #include "core/dom/NodeRenderStyle.h"
38 #include "core/dom/StyleEngine.h"
39 #include "core/dom/Text.h"
40 #include "core/dom/shadow/InsertionPoint.h"
41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "core/editing/FrameSelection.h"
43 #include "core/frame/LocalFrame.h"
44 #include "core/html/HTMLDocument.h"
45 #include "core/html/HTMLFrameElementBase.h"
46 #include "core/html/HTMLInputElement.h"
47 #include "core/html/HTMLOptionElement.h"
48 #include "core/html/HTMLSelectElement.h"
49 #include "core/html/parser/HTMLParserIdioms.h"
50 #include "core/html/track/vtt/VTTElement.h"
51 #include "core/inspector/InspectorInstrumentation.h"
52 #include "core/page/FocusController.h"
53 #include "core/page/Page.h"
54 #include "core/rendering/RenderObject.h"
55 #include "core/rendering/RenderScrollbar.h"
56 #include "core/rendering/style/RenderStyle.h"
57 #include "platform/scroll/ScrollableArea.h"
58 #include "platform/scroll/ScrollbarTheme.h"
59
60 namespace blink {
61
62 using namespace HTMLNames;
63
64 SelectorChecker::SelectorChecker(Document& document, Mode mode)
65     : m_strictParsing(!document.inQuirksMode())
66     , m_documentIsHTML(document.isHTMLDocument())
67     , m_mode(mode)
68 {
69 }
70
71 static bool matchesCustomPseudoElement(const Element* element, const CSSSelector& selector)
72 {
73     ShadowRoot* root = element->containingShadowRoot();
74     if (!root || root->type() != ShadowRoot::UserAgentShadowRoot)
75         return false;
76
77     if (element->shadowPseudoId() != selector.value())
78         return false;
79
80     return true;
81 }
82
83 static Element* parentElement(const SelectorChecker::SelectorCheckingContext& context)
84 {
85     // - If context.scope is a shadow root, we should walk up to its shadow host.
86     // - If context.scope is some element in some shadow tree and querySelector initialized the context,
87     //   e.g. shadowRoot.querySelector(':host *'),
88     //   (a) context.element has the same treescope as context.scope, need to walk up to its shadow host.
89     //   (b) Otherwise, should not walk up from a shadow root to a shadow host.
90     if (context.scope && (context.scope == context.element->containingShadowRoot() || context.scope->treeScope() == context.element->treeScope()))
91         return context.element->parentOrShadowHostElement();
92     return context.element->parentElement();
93 }
94
95 static bool scopeContainsLastMatchedElement(const SelectorChecker::SelectorCheckingContext& context)
96 {
97     if (!(context.contextFlags & SelectorChecker::ScopeContainsLastMatchedElement))
98         return true;
99
100     ASSERT(context.scope);
101     if (context.scope->treeScope() == context.element->treeScope())
102         return true;
103
104     // Because Blink treats a shadow host's TreeScope as a separate one from its descendent shadow roots,
105     // if the last matched element is a shadow host, the condition above isn't met, even though it
106     // should be.
107     return context.element == context.scope->shadowHost() && (!context.previousElement || context.previousElement->isInDescendantTreeOf(context.element));
108 }
109
110 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheckingContext& context)
111 {
112     if (context.scope && context.scope->isInShadowTree())
113         return context.element == context.scope->shadowHost();
114
115     return false;
116 }
117
118 // Recursive check of selectors and combinators
119 // It can return 4 different values:
120 // * SelectorMatches          - the selector matches the element e
121 // * SelectorFailsLocally     - the selector fails for the element e
122 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
123 // * SelectorFailsCompletely  - the selector fails for e and any sibling or ancestor of e
124 template<typename SiblingTraversalStrategy>
125 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* result) const
126 {
127     // first selector has to match
128     unsigned specificity = 0;
129     if (!checkOne(context, siblingTraversalStrategy, &specificity))
130         return SelectorFailsLocally;
131
132     if (context.selector->match() == CSSSelector::PseudoElement) {
133         if (context.selector->isCustomPseudoElement()) {
134             if (!matchesCustomPseudoElement(context.element, *context.selector))
135                 return SelectorFailsLocally;
136         } else if (context.selector->isContentPseudoElement()) {
137             if (!context.element->isInShadowTree() || !context.element->isInsertionPoint())
138                 return SelectorFailsLocally;
139         } else if (context.selector->isShadowPseudoElement()) {
140             if (!context.element->isInShadowTree() || !context.previousElement)
141                 return SelectorFailsCompletely;
142         } else {
143             if ((!context.elementStyle && m_mode == ResolvingStyle) || m_mode == QueryingRules)
144                 return SelectorFailsLocally;
145
146             PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoType());
147             if (pseudoId == FIRST_LETTER)
148                 context.element->document().styleEngine()->setUsesFirstLetterRules(true);
149             if (pseudoId != NOPSEUDO && m_mode != SharingRules && result)
150                 result->dynamicPseudo = pseudoId;
151         }
152     }
153
154     // Prepare next selector
155     if (context.selector->isLastInTagHistory()) {
156         if (scopeContainsLastMatchedElement(context)) {
157             if (result)
158                 result->specificity += specificity;
159             return SelectorMatches;
160         }
161         return SelectorFailsLocally;
162     }
163
164     Match match;
165     if (context.selector->relation() != CSSSelector::SubSelector) {
166         // Abort if the next selector would exceed the scope.
167         if (nextSelectorExceedsScope(context))
168             return SelectorFailsCompletely;
169
170         // Bail-out if this selector is irrelevant for the pseudoId
171         if (context.pseudoId != NOPSEUDO && (!result || context.pseudoId != result->dynamicPseudo))
172             return SelectorFailsCompletely;
173
174         if (result) {
175             TemporaryChange<PseudoId> dynamicPseudoScope(result->dynamicPseudo, NOPSEUDO);
176             match = matchForRelation(context, siblingTraversalStrategy, result);
177         } else {
178             return matchForRelation(context, siblingTraversalStrategy, 0);
179         }
180     } else {
181         match = matchForSubSelector(context, siblingTraversalStrategy, result);
182     }
183     if (match != SelectorMatches || !result)
184         return match;
185
186     result->specificity += specificity;
187     return SelectorMatches;
188 }
189
190 static inline SelectorChecker::SelectorCheckingContext prepareNextContextForRelation(const SelectorChecker::SelectorCheckingContext& context)
191 {
192     SelectorChecker::SelectorCheckingContext nextContext(context);
193     ASSERT(context.selector->tagHistory());
194     nextContext.selector = context.selector->tagHistory();
195     return nextContext;
196 }
197
198 static inline bool isAuthorShadowRoot(const Node* node)
199 {
200     return node && node->isShadowRoot() && toShadowRoot(node)->type() == ShadowRoot::AuthorShadowRoot;
201 }
202
203 template<typename SiblingTraversalStrategy>
204 SelectorChecker::Match SelectorChecker::matchForSubSelector(const SelectorCheckingContext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* result) const
205 {
206     SelectorCheckingContext nextContext = prepareNextContextForRelation(context);
207
208     PseudoId dynamicPseudo = result ? result->dynamicPseudo : NOPSEUDO;
209     // a selector is invalid if something follows a pseudo-element
210     // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
211     // to follow the pseudo elements.
212     nextContext.hasScrollbarPseudo = dynamicPseudo != NOPSEUDO && (context.scrollbar || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER);
213     nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION;
214     if ((context.elementStyle || m_mode == CollectingCSSRules || m_mode == CollectingStyleRules || m_mode == QueryingRules) && dynamicPseudo != NOPSEUDO
215         && !nextContext.hasSelectionPseudo
216         && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass))
217         return SelectorFailsCompletely;
218
219     nextContext.isSubSelector = true;
220     return match(nextContext, siblingTraversalStrategy, result);
221 }
222
223 static bool selectorMatchesShadowRoot(const CSSSelector* selector)
224 {
225     return selector && selector->isShadowPseudoElement();
226 }
227
228 template<typename SiblingTraversalStrategy>
229 SelectorChecker::Match SelectorChecker::matchForPseudoShadow(const ContainerNode* node, const SelectorCheckingContext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* result) const
230 {
231     if (!isAuthorShadowRoot(node))
232         return SelectorFailsCompletely;
233     return match(context, siblingTraversalStrategy, result);
234 }
235
236 template<typename SiblingTraversalStrategy>
237 SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingContext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* result) const
238 {
239     SelectorCheckingContext nextContext = prepareNextContextForRelation(context);
240     nextContext.previousElement = context.element;
241
242     CSSSelector::Relation relation = context.selector->relation();
243
244     // Disable :visited matching when we see the first link or try to match anything else than an ancestors.
245     if (!context.isSubSelector && (context.element->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child)))
246         nextContext.visitedMatchType = VisitedMatchDisabled;
247
248     nextContext.pseudoId = NOPSEUDO;
249
250     switch (relation) {
251     case CSSSelector::Descendant:
252         if (context.selector->relationIsAffectedByPseudoContent()) {
253             for (Element* element = context.element; element; element = element->parentElement()) {
254                 if (matchForShadowDistributed(element, siblingTraversalStrategy, nextContext, result) == SelectorMatches)
255                     return SelectorMatches;
256             }
257             return SelectorFailsCompletely;
258         }
259         nextContext.isSubSelector = false;
260         nextContext.elementStyle = 0;
261
262         if (selectorMatchesShadowRoot(nextContext.selector))
263             return matchForPseudoShadow(context.element->containingShadowRoot(), nextContext, siblingTraversalStrategy, result);
264
265         for (nextContext.element = parentElement(context); nextContext.element; nextContext.element = parentElement(nextContext)) {
266             Match match = this->match(nextContext, siblingTraversalStrategy, result);
267             if (match == SelectorMatches || match == SelectorFailsCompletely)
268                 return match;
269             if (nextSelectorExceedsScope(nextContext))
270                 return SelectorFailsCompletely;
271         }
272         return SelectorFailsCompletely;
273     case CSSSelector::Child:
274         {
275             if (context.selector->relationIsAffectedByPseudoContent())
276                 return matchForShadowDistributed(context.element, siblingTraversalStrategy, nextContext, result);
277
278             nextContext.isSubSelector = false;
279             nextContext.elementStyle = 0;
280
281             if (selectorMatchesShadowRoot(nextContext.selector))
282                 return matchForPseudoShadow(context.element->parentNode(), nextContext, siblingTraversalStrategy, result);
283
284             nextContext.element = parentElement(context);
285             if (!nextContext.element)
286                 return SelectorFailsCompletely;
287             return match(nextContext, siblingTraversalStrategy, result);
288         }
289     case CSSSelector::DirectAdjacent:
290         // Shadow roots can't have sibling elements
291         if (selectorMatchesShadowRoot(nextContext.selector))
292             return SelectorFailsCompletely;
293
294         if (m_mode == ResolvingStyle) {
295             if (ContainerNode* parent = context.element->parentElementOrShadowRoot())
296                 parent->setChildrenAffectedByDirectAdjacentRules();
297         }
298         nextContext.element = ElementTraversal::previousSibling(*context.element);
299         if (!nextContext.element)
300             return SelectorFailsAllSiblings;
301         nextContext.isSubSelector = false;
302         nextContext.elementStyle = 0;
303         return match(nextContext, siblingTraversalStrategy, result);
304
305     case CSSSelector::IndirectAdjacent:
306         // Shadow roots can't have sibling elements
307         if (selectorMatchesShadowRoot(nextContext.selector))
308             return SelectorFailsCompletely;
309
310         if (m_mode == ResolvingStyle) {
311             if (ContainerNode* parent = context.element->parentElementOrShadowRoot())
312                 parent->setChildrenAffectedByIndirectAdjacentRules();
313         }
314         nextContext.element = ElementTraversal::previousSibling(*context.element);
315         nextContext.isSubSelector = false;
316         nextContext.elementStyle = 0;
317         for (; nextContext.element; nextContext.element = ElementTraversal::previousSibling(*nextContext.element)) {
318             Match match = this->match(nextContext, siblingTraversalStrategy, result);
319             if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
320                 return match;
321         };
322         return SelectorFailsAllSiblings;
323
324     case CSSSelector::ShadowPseudo:
325         {
326             // If we're in the same tree-scope as the scoping element, then following a shadow descendant combinator would escape that and thus the scope.
327             if (context.scope && context.scope->shadowHost() && context.scope->shadowHost()->treeScope() == context.element->treeScope())
328                 return SelectorFailsCompletely;
329
330             Element* shadowHost = context.element->shadowHost();
331             if (!shadowHost)
332                 return SelectorFailsCompletely;
333             nextContext.element = shadowHost;
334             nextContext.isSubSelector = false;
335             nextContext.elementStyle = 0;
336             return this->match(nextContext, siblingTraversalStrategy, result);
337         }
338
339     case CSSSelector::ShadowDeep:
340         {
341             nextContext.isSubSelector = false;
342             nextContext.elementStyle = 0;
343             for (nextContext.element = context.element->parentOrShadowHostElement(); nextContext.element; nextContext.element = nextContext.element->parentOrShadowHostElement()) {
344                 Match match = this->match(nextContext, siblingTraversalStrategy, result);
345                 if (match == SelectorMatches || match == SelectorFailsCompletely)
346                     return match;
347                 if (nextSelectorExceedsScope(nextContext))
348                     return SelectorFailsCompletely;
349             }
350             return SelectorFailsCompletely;
351         }
352
353     case CSSSelector::SubSelector:
354         ASSERT_NOT_REACHED();
355     }
356
357     ASSERT_NOT_REACHED();
358     return SelectorFailsCompletely;
359 }
360
361 template<typename SiblingTraversalStrategy>
362 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* element, const SiblingTraversalStrategy& siblingTraversalStrategy, SelectorCheckingContext& nextContext, MatchResult* result) const
363 {
364     ASSERT(element);
365     WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
366     collectDestinationInsertionPoints(*element, insertionPoints);
367     for (size_t i = 0; i < insertionPoints.size(); ++i) {
368         nextContext.element = insertionPoints[i];
369         if (m_mode == SharingRules)
370             nextContext.scope = insertionPoints[i]->containingShadowRoot();
371         nextContext.isSubSelector = false;
372         nextContext.elementStyle = 0;
373         if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatches)
374             return SelectorMatches;
375     }
376     return SelectorFailsLocally;
377 }
378
379 template<typename CharType>
380 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned length)
381 {
382     for (unsigned i = 0; i < length; ++i)
383         if (isHTMLSpace<CharType>(string[i]))
384             return true;
385     return false;
386 }
387
388 static inline bool containsHTMLSpace(const AtomicString& string)
389 {
390     if (LIKELY(string.is8Bit()))
391         return containsHTMLSpaceTemplate<LChar>(string.characters8(), string.length());
392     return containsHTMLSpaceTemplate<UChar>(string.characters16(), string.length());
393 }
394
395 static bool attributeValueMatches(const Attribute& attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive)
396 {
397     const AtomicString& value = attributeItem.value();
398     if (value.isNull())
399         return false;
400
401     switch (match) {
402     case CSSSelector::Exact:
403         if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selectorValue, value))
404             return false;
405         break;
406     case CSSSelector::List:
407         {
408             // Ignore empty selectors or selectors containing HTML spaces
409             if (selectorValue.isEmpty() || containsHTMLSpace(selectorValue))
410                 return false;
411
412             unsigned startSearchAt = 0;
413             while (true) {
414                 size_t foundPos = value.find(selectorValue, startSearchAt, caseSensitive);
415                 if (foundPos == kNotFound)
416                     return false;
417                 if (!foundPos || isHTMLSpace<UChar>(value[foundPos - 1])) {
418                     unsigned endStr = foundPos + selectorValue.length();
419                     if (endStr == value.length() || isHTMLSpace<UChar>(value[endStr]))
420                         break; // We found a match.
421                 }
422
423                 // No match. Keep looking.
424                 startSearchAt = foundPos + 1;
425             }
426             break;
427         }
428     case CSSSelector::Contain:
429         if (!value.contains(selectorValue, caseSensitive) || selectorValue.isEmpty())
430             return false;
431         break;
432     case CSSSelector::Begin:
433         if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
434             return false;
435         break;
436     case CSSSelector::End:
437         if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
438             return false;
439         break;
440     case CSSSelector::Hyphen:
441         if (value.length() < selectorValue.length())
442             return false;
443         if (!value.startsWith(selectorValue, caseSensitive))
444             return false;
445         // It they start the same, check for exact match or following '-':
446         if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-')
447             return false;
448         break;
449     case CSSSelector::PseudoClass:
450     case CSSSelector::PseudoElement:
451     default:
452         break;
453     }
454
455     return true;
456 }
457
458 static bool anyAttributeMatches(Element& element, CSSSelector::Match match, const CSSSelector& selector)
459 {
460     const QualifiedName& selectorAttr = selector.attribute();
461     ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from the CSS grammar.
462
463     // Synchronize the attribute in case it is lazy-computed.
464     // Currently all lazy properties have a null namespace, so only pass localName().
465     element.synchronizeAttribute(selectorAttr.localName());
466
467     const AtomicString& selectorValue = selector.value();
468     bool caseInsensitive = selector.attributeMatchType() == CSSSelector::CaseInsensitive;
469
470     AttributeCollection attributes = element.attributesWithoutUpdate();
471     AttributeCollection::iterator end = attributes.end();
472     for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
473         const Attribute& attributeItem = *it;
474
475         if (!attributeItem.matches(selectorAttr))
476             continue;
477
478         if (attributeValueMatches(attributeItem, match, selectorValue, !caseInsensitive))
479             return true;
480
481         if (caseInsensitive)
482             continue;
483
484         // Legacy dictates that values of some attributes should be compared in
485         // a case-insensitive manner regardless of whether the case insensitive
486         // flag is set or not.
487         bool legacyCaseInsensitive = element.document().isHTMLDocument() && !HTMLDocument::isCaseSensitiveAttribute(selectorAttr);
488
489         // If case-insensitive, re-check, and count if result differs.
490         // See http://code.google.com/p/chromium/issues/detail?id=327060
491         if (legacyCaseInsensitive && attributeValueMatches(attributeItem, match, selectorValue, false)) {
492             UseCounter::count(element.document(), UseCounter::CaseInsensitiveAttrSelectorMatch);
493             return true;
494         }
495     }
496
497     return false;
498 }
499
500 template<typename SiblingTraversalStrategy>
501 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const
502 {
503     ASSERT(context.element);
504     Element& element = *context.element;
505     ASSERT(context.selector);
506     const CSSSelector& selector = *context.selector;
507
508     bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.scope);
509
510     // Only :host and :ancestor should match the host: http://drafts.csswg.org/css-scoping/#host-element
511     if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass()
512         && !(context.contextFlags & TreatShadowHostAsNormalScope))
513         return false;
514
515     if (selector.match() == CSSSelector::Tag)
516         return SelectorChecker::tagMatches(element, selector.tagQName());
517
518     if (selector.match() == CSSSelector::Class)
519         return element.hasClass() && element.classNames().contains(selector.value());
520
521     if (selector.match() == CSSSelector::Id)
522         return element.hasID() && element.idForStyleResolution() == selector.value();
523
524     if (selector.isAttributeSelector())
525         return anyAttributeMatches(element, selector.match(), selector);
526
527     if (selector.match() == CSSSelector::PseudoClass) {
528         // Handle :not up front.
529         if (selector.pseudoType() == CSSSelector::PseudoNot) {
530             SelectorCheckingContext subContext(context);
531             subContext.isSubSelector = true;
532             ASSERT(selector.selectorList());
533             for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) {
534                 // :not cannot nest. I don't really know why this is a
535                 // restriction in CSS3, but it is, so let's honor it.
536                 // the parser enforces that this never occurs
537                 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot);
538                 // We select between :visited and :link when applying. We don't know which one applied (or not) yet.
539                 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled))
540                     return true;
541                 // context.scope is not available if m_mode == SharingRules.
542                 // We cannot determine whether :host or :scope matches a given element or not.
543                 if (m_mode == SharingRules && (subContext.selector->isHostPseudoClass() || subContext.selector->pseudoType() == CSSSelector::PseudoScope))
544                     return true;
545                 if (!checkOne(subContext, DOMSiblingTraversalStrategy()))
546                     return true;
547             }
548         } else if (context.hasScrollbarPseudo) {
549             // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
550             // (since there are no elements involved).
551             return checkScrollbarPseudoClass(context, &element.document(), selector);
552         } else if (context.hasSelectionPseudo) {
553             if (selector.pseudoType() == CSSSelector::PseudoWindowInactive)
554                 return !element.document().page()->focusController().isActive();
555         }
556
557         // Normal element pseudo class checking.
558         switch (selector.pseudoType()) {
559             // Pseudo classes:
560         case CSSSelector::PseudoNot:
561             break; // Already handled up above.
562         case CSSSelector::PseudoEmpty:
563             {
564                 bool result = true;
565                 for (Node* n = element.firstChild(); n; n = n->nextSibling()) {
566                     if (n->isElementNode()) {
567                         result = false;
568                         break;
569                     }
570                     if (n->isTextNode()) {
571                         Text* textNode = toText(n);
572                         if (!textNode->data().isEmpty()) {
573                             result = false;
574                             break;
575                         }
576                     }
577                 }
578                 if (m_mode == ResolvingStyle) {
579                     element.setStyleAffectedByEmpty();
580                     if (context.elementStyle)
581                         context.elementStyle->setEmptyState(result);
582                     else if (element.renderStyle() && (element.document().styleEngine()->usesSiblingRules() || element.renderStyle()->unique()))
583                         element.renderStyle()->setEmptyState(result);
584                 }
585                 return result;
586             }
587         case CSSSelector::PseudoFirstChild:
588             // first-child matches the first child that is an element
589             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
590                 bool result = siblingTraversalStrategy.isFirstChild(element);
591                 if (m_mode == ResolvingStyle) {
592                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
593                     parent->setChildrenAffectedByFirstChildRules();
594                     if (result && childStyle)
595                         childStyle->setFirstChildState();
596                 }
597                 return result;
598             }
599             break;
600         case CSSSelector::PseudoFirstOfType:
601             // first-of-type matches the first element of its type
602             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
603                 bool result = siblingTraversalStrategy.isFirstOfType(element, element.tagQName());
604                 if (m_mode == ResolvingStyle)
605                     parent->setChildrenAffectedByForwardPositionalRules();
606                 return result;
607             }
608             break;
609         case CSSSelector::PseudoLastChild:
610             // last-child matches the last child that is an element
611             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
612                 bool result = parent->isFinishedParsingChildren() && siblingTraversalStrategy.isLastChild(element);
613                 if (m_mode == ResolvingStyle) {
614                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
615                     parent->setChildrenAffectedByLastChildRules();
616                     if (result && childStyle)
617                         childStyle->setLastChildState();
618                 }
619                 return result;
620             }
621             break;
622         case CSSSelector::PseudoLastOfType:
623             // last-of-type matches the last element of its type
624             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
625                 if (m_mode == ResolvingStyle)
626                     parent->setChildrenAffectedByBackwardPositionalRules();
627                 if (!parent->isFinishedParsingChildren())
628                     return false;
629                 return siblingTraversalStrategy.isLastOfType(element, element.tagQName());
630             }
631             break;
632         case CSSSelector::PseudoOnlyChild:
633             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
634                 bool firstChild = siblingTraversalStrategy.isFirstChild(element);
635                 bool onlyChild = firstChild && parent->isFinishedParsingChildren() && siblingTraversalStrategy.isLastChild(element);
636                 if (m_mode == ResolvingStyle) {
637                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
638                     parent->setChildrenAffectedByFirstChildRules();
639                     parent->setChildrenAffectedByLastChildRules();
640                     if (firstChild && childStyle)
641                         childStyle->setFirstChildState();
642                     if (onlyChild && childStyle)
643                         childStyle->setLastChildState();
644                 }
645                 return onlyChild;
646             }
647             break;
648         case CSSSelector::PseudoOnlyOfType:
649             // FIXME: This selector is very slow.
650             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
651                 if (m_mode == ResolvingStyle) {
652                     parent->setChildrenAffectedByForwardPositionalRules();
653                     parent->setChildrenAffectedByBackwardPositionalRules();
654                 }
655                 if (!parent->isFinishedParsingChildren())
656                     return false;
657                 return siblingTraversalStrategy.isFirstOfType(element, element.tagQName()) && siblingTraversalStrategy.isLastOfType(element, element.tagQName());
658             }
659             break;
660         case CSSSelector::PseudoNthChild:
661             if (!selector.parseNth())
662                 break;
663             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
664                 int count = 1 + siblingTraversalStrategy.countElementsBefore(element);
665                 if (m_mode == ResolvingStyle) {
666                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element.renderStyle();
667                     if (childStyle)
668                         childStyle->setUnique();
669                     parent->setChildrenAffectedByForwardPositionalRules();
670                 }
671
672                 if (selector.matchNth(count))
673                     return true;
674             }
675             break;
676         case CSSSelector::PseudoNthOfType:
677             if (!selector.parseNth())
678                 break;
679             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
680                 int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefore(element, element.tagQName());
681                 if (m_mode == ResolvingStyle)
682                     parent->setChildrenAffectedByForwardPositionalRules();
683
684                 if (selector.matchNth(count))
685                     return true;
686             }
687             break;
688         case CSSSelector::PseudoNthLastChild:
689             if (!selector.parseNth())
690                 break;
691             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
692                 if (m_mode == ResolvingStyle)
693                     parent->setChildrenAffectedByBackwardPositionalRules();
694                 if (!parent->isFinishedParsingChildren())
695                     return false;
696                 int count = 1 + siblingTraversalStrategy.countElementsAfter(element);
697                 if (selector.matchNth(count))
698                     return true;
699             }
700             break;
701         case CSSSelector::PseudoNthLastOfType:
702             if (!selector.parseNth())
703                 break;
704             if (ContainerNode* parent = element.parentElementOrDocumentFragment()) {
705                 if (m_mode == ResolvingStyle)
706                     parent->setChildrenAffectedByBackwardPositionalRules();
707                 if (!parent->isFinishedParsingChildren())
708                     return false;
709
710                 int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfter(element, element.tagQName());
711                 if (selector.matchNth(count))
712                     return true;
713             }
714             break;
715         case CSSSelector::PseudoTarget:
716             if (element == element.document().cssTarget())
717                 return true;
718             break;
719         case CSSSelector::PseudoAny:
720             {
721                 SelectorCheckingContext subContext(context);
722                 subContext.isSubSelector = true;
723                 ASSERT(selector.selectorList());
724                 for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
725                     if (match(subContext, siblingTraversalStrategy) == SelectorMatches)
726                         return true;
727                 }
728             }
729             break;
730         case CSSSelector::PseudoAutofill:
731             if (!element.isFormControlElement())
732                 break;
733             return toHTMLFormControlElement(element).isAutofilled();
734         case CSSSelector::PseudoAnyLink:
735         case CSSSelector::PseudoLink:
736             // :visited and :link matches are separated later when applying the style. Here both classes match all links...
737             return element.isLink();
738         case CSSSelector::PseudoVisited:
739             // ...except if :visited matching is disabled for ancestor/sibling matching.
740             return element.isLink() && context.visitedMatchType == VisitedMatchEnabled;
741         case CSSSelector::PseudoDrag:
742             if (m_mode == ResolvingStyle) {
743                 if (context.elementStyle)
744                     context.elementStyle->setAffectedByDrag();
745                 else
746                     element.setChildrenOrSiblingsAffectedByDrag();
747             }
748             if (element.renderer() && element.renderer()->isDragging())
749                 return true;
750             break;
751         case CSSSelector::PseudoFocus:
752             if (m_mode == ResolvingStyle) {
753                 if (context.elementStyle)
754                     context.elementStyle->setAffectedByFocus();
755                 else
756                     element.setChildrenOrSiblingsAffectedByFocus();
757             }
758             return matchesFocusPseudoClass(element);
759         case CSSSelector::PseudoHover:
760             // If we're in quirks mode, then hover should never match anchors with no
761             // href and *:hover should not match anything. This is important for sites like wsj.com.
762             if (m_strictParsing || context.isSubSelector || element.isLink()) {
763                 if (m_mode == ResolvingStyle) {
764                     if (context.elementStyle)
765                         context.elementStyle->setAffectedByHover();
766                     else
767                         element.setChildrenOrSiblingsAffectedByHover();
768                 }
769                 if (element.hovered() || InspectorInstrumentation::forcePseudoState(&element, CSSSelector::PseudoHover))
770                     return true;
771             }
772             break;
773         case CSSSelector::PseudoActive:
774             // If we're in quirks mode, then :active should never match anchors with no
775             // href and *:active should not match anything.
776             if (m_strictParsing || context.isSubSelector || element.isLink()) {
777                 if (m_mode == ResolvingStyle) {
778                     if (context.elementStyle)
779                         context.elementStyle->setAffectedByActive();
780                     else
781                         element.setChildrenOrSiblingsAffectedByActive();
782                 }
783                 if (element.active() || InspectorInstrumentation::forcePseudoState(&element, CSSSelector::PseudoActive))
784                     return true;
785             }
786             break;
787         case CSSSelector::PseudoEnabled:
788             if (element.isFormControlElement() || isHTMLOptionElement(element) || isHTMLOptGroupElement(element))
789                 return !element.isDisabledFormControl();
790             else if (isHTMLAnchorElement(element) || isHTMLAreaElement(element))
791                 return element.isLink();
792             break;
793         case CSSSelector::PseudoFullPageMedia:
794             return element.document().isMediaDocument();
795             break;
796         case CSSSelector::PseudoDefault:
797             return element.isDefaultButtonForForm();
798         case CSSSelector::PseudoDisabled:
799             if (element.isFormControlElement() || isHTMLOptionElement(element) || isHTMLOptGroupElement(element))
800                 return element.isDisabledFormControl();
801             break;
802         case CSSSelector::PseudoReadOnly:
803             return element.matchesReadOnlyPseudoClass();
804         case CSSSelector::PseudoReadWrite:
805             return element.matchesReadWritePseudoClass();
806         case CSSSelector::PseudoOptional:
807             return element.isOptionalFormControl();
808         case CSSSelector::PseudoRequired:
809             return element.isRequiredFormControl();
810         case CSSSelector::PseudoValid:
811             element.document().setContainsValidityStyleRules();
812             return element.willValidate() && element.isValidFormControlElement();
813         case CSSSelector::PseudoInvalid:
814             element.document().setContainsValidityStyleRules();
815             return element.willValidate() && !element.isValidFormControlElement();
816         case CSSSelector::PseudoChecked:
817             {
818                 if (isHTMLInputElement(element)) {
819                     HTMLInputElement& inputElement = toHTMLInputElement(element);
820                     // Even though WinIE allows checked and indeterminate to
821                     // co-exist, the CSS selector spec says that you can't be
822                     // both checked and indeterminate. We will behave like WinIE
823                     // behind the scenes and just obey the CSS spec here in the
824                     // test for matching the pseudo.
825                     if (inputElement.shouldAppearChecked() && !inputElement.shouldAppearIndeterminate())
826                         return true;
827                 } else if (isHTMLOptionElement(element) && toHTMLOptionElement(element).selected())
828                     return true;
829                 break;
830             }
831         case CSSSelector::PseudoIndeterminate:
832             return element.shouldAppearIndeterminate();
833         case CSSSelector::PseudoRoot:
834             if (element == element.document().documentElement())
835                 return true;
836             break;
837         case CSSSelector::PseudoLang:
838             {
839                 AtomicString value;
840                 if (element.isVTTElement())
841                     value = toVTTElement(element).language();
842                 else
843                     value = element.computeInheritedLanguage();
844                 const AtomicString& argument = selector.argument();
845                 if (value.isEmpty() || !value.startsWith(argument, false))
846                     break;
847                 if (value.length() != argument.length() && value[argument.length()] != '-')
848                     break;
849                 return true;
850             }
851         case CSSSelector::PseudoFullScreen:
852             // While a Document is in the fullscreen state, and the document's current fullscreen
853             // element is an element in the document, the 'full-screen' pseudoclass applies to
854             // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
855             // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
856             if (isHTMLFrameElementBase(element) && element.containsFullScreenElement())
857                 return true;
858             if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(element.document())) {
859                 if (!fullscreen->webkitIsFullScreen())
860                     return false;
861                 return element == fullscreen->webkitCurrentFullScreenElement();
862             }
863             return false;
864         case CSSSelector::PseudoFullScreenAncestor:
865             return element.containsFullScreenElement();
866         case CSSSelector::PseudoFullScreenDocument:
867             // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
868             // to all elements of that Document.
869             if (!FullscreenElementStack::isFullScreen(element.document()))
870                 return false;
871             return true;
872         case CSSSelector::PseudoInRange:
873             element.document().setContainsValidityStyleRules();
874             return element.isInRange();
875         case CSSSelector::PseudoOutOfRange:
876             element.document().setContainsValidityStyleRules();
877             return element.isOutOfRange();
878         case CSSSelector::PseudoFutureCue:
879             return (element.isVTTElement() && !toVTTElement(element).isPastNode());
880         case CSSSelector::PseudoPastCue:
881             return (element.isVTTElement() && toVTTElement(element).isPastNode());
882
883         case CSSSelector::PseudoScope:
884             {
885                 if (m_mode == SharingRules)
886                     return true;
887                 const Node* contextualReferenceNode = !context.scope ? element.document().documentElement() : context.scope;
888                 if (element == contextualReferenceNode)
889                     return true;
890                 break;
891             }
892
893         case CSSSelector::PseudoUnresolved:
894             if (element.isUnresolvedCustomElement())
895                 return true;
896             break;
897
898         case CSSSelector::PseudoHost:
899         case CSSSelector::PseudoHostContext:
900             {
901                 if (m_mode == SharingRules)
902                     return true;
903                 // :host only matches a shadow host when :host is in a shadow tree of the shadow host.
904                 if (!context.scope)
905                     return false;
906                 const ContainerNode* shadowHost = context.scope->shadowHost();
907                 if (!shadowHost || shadowHost != element)
908                     return false;
909                 ASSERT(element.shadow());
910
911                 // For empty parameter case, i.e. just :host or :host().
912                 if (!selector.selectorList()) // Use *'s specificity. So just 0.
913                     return true;
914
915                 SelectorCheckingContext subContext(context);
916                 subContext.isSubSelector = true;
917
918                 bool matched = false;
919                 unsigned maxSpecificity = 0;
920
921                 // If one of simple selectors matches an element, returns SelectorMatches. Just "OR".
922                 for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
923                     subContext.contextFlags = TreatShadowHostAsNormalScope;
924                     subContext.scope = context.scope;
925                     // Use NodeRenderingTraversal to traverse a composed ancestor list of a given element.
926                     Element* nextElement = &element;
927                     SelectorCheckingContext hostContext(subContext);
928                     do {
929                         MatchResult subResult;
930                         hostContext.element = nextElement;
931                         if (match(hostContext, siblingTraversalStrategy, &subResult) == SelectorMatches) {
932                             matched = true;
933                             // Consider div:host(div:host(div:host(div:host...))).
934                             maxSpecificity = std::max(maxSpecificity, hostContext.selector->specificity() + subResult.specificity);
935                             break;
936                         }
937                         hostContext.contextFlags = DefaultBehavior;
938                         hostContext.scope = nullptr;
939
940                         if (selector.pseudoType() == CSSSelector::PseudoHost)
941                             break;
942
943                         hostContext.elementStyle = 0;
944                         nextElement = NodeRenderingTraversal::parentElement(nextElement);
945                     } while (nextElement);
946                 }
947                 if (matched) {
948                     if (specificity)
949                         *specificity = maxSpecificity;
950                     return true;
951                 }
952             }
953             break;
954         case CSSSelector::PseudoSpatialNavigationFocus:
955             return context.isUARule && matchesSpatialNavigationFocusPseudoClass(element);
956         case CSSSelector::PseudoListBox:
957             return context.isUARule && matchesListBoxPseudoClass(element);
958
959         case CSSSelector::PseudoHorizontal:
960         case CSSSelector::PseudoVertical:
961         case CSSSelector::PseudoDecrement:
962         case CSSSelector::PseudoIncrement:
963         case CSSSelector::PseudoStart:
964         case CSSSelector::PseudoEnd:
965         case CSSSelector::PseudoDoubleButton:
966         case CSSSelector::PseudoSingleButton:
967         case CSSSelector::PseudoNoButton:
968         case CSSSelector::PseudoCornerPresent:
969             return false;
970
971         case CSSSelector::PseudoUnknown:
972         case CSSSelector::PseudoNotParsed:
973         default:
974             ASSERT_NOT_REACHED();
975             break;
976         }
977         return false;
978     } else if (selector.match() == CSSSelector::PseudoElement && selector.pseudoType() == CSSSelector::PseudoCue) {
979         SelectorCheckingContext subContext(context);
980         subContext.isSubSelector = true;
981         subContext.contextFlags = DefaultBehavior;
982
983         const CSSSelector* contextSelector = context.selector;
984         ASSERT(contextSelector);
985         for (subContext.selector = contextSelector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
986             if (match(subContext, siblingTraversalStrategy) == SelectorMatches)
987                 return true;
988         }
989         return false;
990     }
991     // ### add the rest of the checks...
992     return true;
993 }
994
995 bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& context, Document* document, const CSSSelector& selector) const
996 {
997     RenderScrollbar* scrollbar = context.scrollbar;
998     ScrollbarPart part = context.scrollbarPart;
999
1000     // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
1001     // pseudo class and just apply to everything.
1002     if (selector.pseudoType() == CSSSelector::PseudoWindowInactive)
1003         return !document->page()->focusController().isActive();
1004
1005     if (!scrollbar)
1006         return false;
1007
1008     ASSERT(selector.match() == CSSSelector::PseudoClass);
1009     switch (selector.pseudoType()) {
1010     case CSSSelector::PseudoEnabled:
1011         return scrollbar->enabled();
1012     case CSSSelector::PseudoDisabled:
1013         return !scrollbar->enabled();
1014     case CSSSelector::PseudoHover:
1015         {
1016             ScrollbarPart hoveredPart = scrollbar->hoveredPart();
1017             if (part == ScrollbarBGPart)
1018                 return hoveredPart != NoPart;
1019             if (part == TrackBGPart)
1020                 return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
1021             return part == hoveredPart;
1022         }
1023     case CSSSelector::PseudoActive:
1024         {
1025             ScrollbarPart pressedPart = scrollbar->pressedPart();
1026             if (part == ScrollbarBGPart)
1027                 return pressedPart != NoPart;
1028             if (part == TrackBGPart)
1029                 return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
1030             return part == pressedPart;
1031         }
1032     case CSSSelector::PseudoHorizontal:
1033         return scrollbar->orientation() == HorizontalScrollbar;
1034     case CSSSelector::PseudoVertical:
1035         return scrollbar->orientation() == VerticalScrollbar;
1036     case CSSSelector::PseudoDecrement:
1037         return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart;
1038     case CSSSelector::PseudoIncrement:
1039         return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
1040     case CSSSelector::PseudoStart:
1041         return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart;
1042     case CSSSelector::PseudoEnd:
1043         return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
1044     case CSSSelector::PseudoDoubleButton:
1045         {
1046             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1047             if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
1048                 return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
1049             if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
1050                 return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
1051             return false;
1052         }
1053     case CSSSelector::PseudoSingleButton:
1054         {
1055             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1056             if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
1057                 return buttonsPlacement == ScrollbarButtonsSingle;
1058             return false;
1059         }
1060     case CSSSelector::PseudoNoButton:
1061         {
1062             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1063             if (part == BackTrackPart)
1064                 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
1065             if (part == ForwardTrackPart)
1066                 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
1067             return false;
1068         }
1069     case CSSSelector::PseudoCornerPresent:
1070         return scrollbar->scrollableArea()->isScrollCornerVisible();
1071     default:
1072         return false;
1073     }
1074 }
1075
1076 unsigned SelectorChecker::determineLinkMatchType(const CSSSelector& selector)
1077 {
1078     unsigned linkMatchType = MatchAll;
1079
1080     // Statically determine if this selector will match a link in visited, unvisited or any state, or never.
1081     // :visited never matches other elements than the innermost link element.
1082     for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
1083         switch (current->pseudoType()) {
1084         case CSSSelector::PseudoNot:
1085             {
1086                 // :not(:visited) is equivalent to :link. Parser enforces that :not can't nest.
1087                 ASSERT(current->selectorList());
1088                 for (const CSSSelector* subSelector = current->selectorList()->first(); subSelector; subSelector = subSelector->tagHistory()) {
1089                     CSSSelector::PseudoType subType = subSelector->pseudoType();
1090                     if (subType == CSSSelector::PseudoVisited)
1091                         linkMatchType &= ~SelectorChecker::MatchVisited;
1092                     else if (subType == CSSSelector::PseudoLink)
1093                         linkMatchType &= ~SelectorChecker::MatchLink;
1094                 }
1095             }
1096             break;
1097         case CSSSelector::PseudoLink:
1098             linkMatchType &= ~SelectorChecker::MatchVisited;
1099             break;
1100         case CSSSelector::PseudoVisited:
1101             linkMatchType &= ~SelectorChecker::MatchLink;
1102             break;
1103         default:
1104             // We don't support :link and :visited inside :-webkit-any.
1105             break;
1106         }
1107         CSSSelector::Relation relation = current->relation();
1108         if (relation == CSSSelector::SubSelector)
1109             continue;
1110         if (relation != CSSSelector::Descendant && relation != CSSSelector::Child)
1111             return linkMatchType;
1112         if (linkMatchType != MatchAll)
1113             return linkMatchType;
1114     }
1115     return linkMatchType;
1116 }
1117
1118 bool SelectorChecker::isFrameFocused(const Element& element)
1119 {
1120     return element.document().frame() && element.document().frame()->selection().isFocusedAndActive();
1121 }
1122
1123 bool SelectorChecker::matchesFocusPseudoClass(const Element& element)
1124 {
1125     if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element), CSSSelector::PseudoFocus))
1126         return true;
1127     return element.focused() && isFrameFocused(element);
1128 }
1129
1130 bool SelectorChecker::matchesSpatialNavigationFocusPseudoClass(const Element& element)
1131 {
1132     return isHTMLOptionElement(element) && toHTMLOptionElement(element).spatialNavigationFocused() && isFrameFocused(element);
1133 }
1134
1135 bool SelectorChecker::matchesListBoxPseudoClass(const Element& element)
1136 {
1137     return isHTMLSelectElement(element) && !toHTMLSelectElement(element).usesMenuList();
1138 }
1139
1140 template
1141 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, const DOMSiblingTraversalStrategy&, MatchResult*) const;
1142
1143 template
1144 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, const ShadowDOMSiblingTraversalStrategy&, MatchResult*) const;
1145
1146 }