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