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