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 #ifndef SelectorChecker_h
     29 #define SelectorChecker_h
     30 
     31 #include "core/css/CSSSelector.h"
     32 #include "core/dom/Element.h"
     33 #include "platform/scroll/ScrollTypes.h"
     34 
     35 namespace blink {
     36 
     37 class CSSSelector;
     38 class ContainerNode;
     39 class Element;
     40 class RenderScrollbar;
     41 class RenderStyle;
     42 
     43 class SelectorChecker {
     44     WTF_MAKE_NONCOPYABLE(SelectorChecker);
     45 public:
     46     enum Match { SelectorMatches, SelectorFailsLocally, SelectorFailsAllSiblings, SelectorFailsCompletely };
     47     enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled };
     48     enum Mode { ResolvingStyle = 0, CollectingStyleRules, CollectingCSSRules, QueryingRules, SharingRules };
     49     explicit SelectorChecker(Document&, Mode);
     50     enum ContextFlags {
     51         // FIXME: Revmoe DefaultBehavior.
     52         DefaultBehavior = 0,
     53         ScopeContainsLastMatchedElement = 1,
     54         TreatShadowHostAsNormalScope = 2,
     55     };
     56 
     57     struct SelectorCheckingContext {
     58         STACK_ALLOCATED();
     59     public:
     60         // Initial selector constructor
     61         SelectorCheckingContext(const CSSSelector& selector, Element* element, VisitedMatchType visitedMatchType)
     62             : selector(&selector)
     63             , element(element)
     64             , previousElement(nullptr)
     65             , scope(nullptr)
     66             , visitedMatchType(visitedMatchType)
     67             , pseudoId(NOPSEUDO)
     68             , elementStyle(0)
     69             , scrollbar(0)
     70             , scrollbarPart(NoPart)
     71             , isSubSelector(false)
     72             , hasScrollbarPseudo(false)
     73             , hasSelectionPseudo(false)
     74             , isUARule(false)
     75             , contextFlags(DefaultBehavior)
     76         {
     77         }
     78 
     79         const CSSSelector* selector;
     80         RawPtrWillBeMember<Element> element;
     81         RawPtrWillBeMember<Element> previousElement;
     82         RawPtrWillBeMember<const ContainerNode> scope;
     83         VisitedMatchType visitedMatchType;
     84         PseudoId pseudoId;
     85         RenderStyle* elementStyle;
     86         RenderScrollbar* scrollbar;
     87         ScrollbarPart scrollbarPart;
     88         bool isSubSelector;
     89         bool hasScrollbarPseudo;
     90         bool hasSelectionPseudo;
     91         bool isUARule;
     92         ContextFlags contextFlags;
     93     };
     94 
     95     struct MatchResult {
     96         MatchResult()
     97             : dynamicPseudo(NOPSEUDO)
     98             , specificity(0) { }
     99 
    100         PseudoId dynamicPseudo;
    101         unsigned specificity;
    102     };
    103 
    104     template<typename SiblingTraversalStrategy>
    105     Match match(const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult* = 0) const;
    106 
    107     template<typename SiblingTraversalStrategy>
    108     bool checkOne(const SelectorCheckingContext&, const SiblingTraversalStrategy&, unsigned* specificity = 0) const;
    109 
    110     bool strictParsing() const { return m_strictParsing; }
    111 
    112     Mode mode() const { return m_mode; }
    113 
    114     static bool tagMatches(const Element&, const QualifiedName&);
    115     static bool isCommonPseudoClassSelector(const CSSSelector&);
    116     static bool matchesFocusPseudoClass(const Element&);
    117     static bool matchesSpatialNavigationFocusPseudoClass(const Element&);
    118     static bool matchesListBoxPseudoClass(const Element&);
    119     static bool checkExactAttribute(const Element&, const QualifiedName& selectorAttributeName, const StringImpl* value);
    120 
    121     enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
    122     static unsigned determineLinkMatchType(const CSSSelector&);
    123 
    124     static bool isHostInItsShadowTree(const Element&, const ContainerNode* scope);
    125 
    126 private:
    127     template<typename SiblingTraversalStrategy>
    128     Match matchForSubSelector(const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
    129     template<typename SiblingTraversalStrategy>
    130     Match matchForRelation(const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
    131     template<typename SiblingTraversalStrategy>
    132     Match matchForShadowDistributed(const Element*, const SiblingTraversalStrategy&, SelectorCheckingContext& nextContext, MatchResult* = 0) const;
    133     template<typename SiblingTraversalStrategy>
    134     Match matchForPseudoShadow(const ContainerNode*, const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
    135 
    136     bool checkScrollbarPseudoClass(const SelectorCheckingContext&, Document*, const CSSSelector&) const;
    137 
    138     static bool isFrameFocused(const Element&);
    139 
    140     bool m_strictParsing;
    141     Mode m_mode;
    142 };
    143 
    144 inline bool SelectorChecker::isCommonPseudoClassSelector(const CSSSelector& selector)
    145 {
    146     if (selector.match() != CSSSelector::PseudoClass)
    147         return false;
    148     CSSSelector::PseudoType pseudoType = selector.pseudoType();
    149     return pseudoType == CSSSelector::PseudoLink
    150         || pseudoType == CSSSelector::PseudoAnyLink
    151         || pseudoType == CSSSelector::PseudoVisited
    152         || pseudoType == CSSSelector::PseudoFocus;
    153 }
    154 
    155 inline bool SelectorChecker::tagMatches(const Element& element, const QualifiedName& tagQName)
    156 {
    157     if (tagQName == anyQName())
    158         return true;
    159     const AtomicString& localName = tagQName.localName();
    160     if (localName != starAtom && localName != element.localName())
    161         return false;
    162     const AtomicString& namespaceURI = tagQName.namespaceURI();
    163     return namespaceURI == starAtom || namespaceURI == element.namespaceURI();
    164 }
    165 
    166 inline bool SelectorChecker::checkExactAttribute(const Element& element, const QualifiedName& selectorAttributeName, const StringImpl* value)
    167 {
    168     AttributeCollection attributes = element.attributesWithoutUpdate();
    169     AttributeCollection::iterator end = attributes.end();
    170     for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
    171         if (it->matches(selectorAttributeName) && (!value || it->value().impl() == value))
    172             return true;
    173     }
    174     return false;
    175 }
    176 
    177 inline bool SelectorChecker::isHostInItsShadowTree(const Element& element, const ContainerNode* scope)
    178 {
    179     return scope && scope->isInShadowTree() && scope->shadowHost() == element;
    180 }
    181 
    182 }
    183 
    184 #endif
    185