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