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