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