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