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