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/inspector/InspectorInstrumentation.h"
     33 
     34 namespace WebCore {
     35 
     36 class CSSSelector;
     37 class Element;
     38 class RenderScrollbar;
     39 class RenderStyle;
     40 
     41 class SelectorChecker {
     42     WTF_MAKE_NONCOPYABLE(SelectorChecker);
     43 public:
     44     enum Match { SelectorMatches, SelectorFailsLocally, SelectorFailsAllSiblings, SelectorFailsCompletely };
     45     enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled };
     46     enum Mode { ResolvingStyle = 0, CollectingRules, QueryingRules, SharingRules };
     47     explicit SelectorChecker(Document*, Mode);
     48     enum BehaviorAtBoundary {
     49         DoesNotCrossBoundary = 0,
     50         CrossesBoundary = 1,
     51         StaysWithinTreeScope = 2,
     52         BoundaryBehaviorMask = 3, // 2bit for boundary behavior
     53         ScopeContainsLastMatchedElement = 4,
     54         ScopeIsShadowHost = 8
     55     };
     56 
     57     struct SelectorCheckingContext {
     58         // Initial selector constructor
     59         SelectorCheckingContext(const CSSSelector* selector, Element* element, VisitedMatchType visitedMatchType)
     60             : selector(selector)
     61             , element(element)
     62             , scope(0)
     63             , visitedMatchType(visitedMatchType)
     64             , pseudoId(NOPSEUDO)
     65             , elementStyle(0)
     66             , scrollbar(0)
     67             , scrollbarPart(NoPart)
     68             , isSubSelector(false)
     69             , hasScrollbarPseudo(false)
     70             , hasSelectionPseudo(false)
     71             , behaviorAtBoundary(DoesNotCrossBoundary)
     72         { }
     73 
     74         const CSSSelector* selector;
     75         Element* element;
     76         const ContainerNode* scope;
     77         VisitedMatchType visitedMatchType;
     78         PseudoId pseudoId;
     79         RenderStyle* elementStyle;
     80         RenderScrollbar* scrollbar;
     81         ScrollbarPart scrollbarPart;
     82         bool isSubSelector;
     83         bool hasScrollbarPseudo;
     84         bool hasSelectionPseudo;
     85         BehaviorAtBoundary behaviorAtBoundary;
     86     };
     87 
     88     template<typename SiblingTraversalStrategy>
     89     Match match(const SelectorCheckingContext&, PseudoId&, const SiblingTraversalStrategy&) const;
     90 
     91     template<typename SiblingTraversalStrategy>
     92     Match matchForShadowDistributed(const Element*, const SiblingTraversalStrategy&, PseudoId&, SelectorCheckingContext& nextContext) const;
     93 
     94     template<typename SiblingTraversalStrategy>
     95     bool checkOne(const SelectorCheckingContext&, const SiblingTraversalStrategy&) const;
     96 
     97     bool strictParsing() const { return m_strictParsing; }
     98 
     99     Mode mode() const { return m_mode; }
    100 
    101     static bool tagMatches(const Element*, const QualifiedName&);
    102     static bool isCommonPseudoClassSelector(const CSSSelector*);
    103     static bool matchesFocusPseudoClass(const Element*);
    104     static bool checkExactAttribute(const Element*, const QualifiedName& selectorAttributeName, const StringImpl* value);
    105 
    106     enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
    107     static unsigned determineLinkMatchType(const CSSSelector*);
    108 
    109 private:
    110     bool checkScrollbarPseudoClass(const SelectorCheckingContext&, Document*, const CSSSelector*) const;
    111     Element* parentElement(const SelectorCheckingContext&) const;
    112     bool scopeContainsLastMatchedElement(const SelectorCheckingContext&) const;
    113 
    114     static bool isFrameFocused(const Element*);
    115 
    116     bool m_strictParsing;
    117     bool m_documentIsHTML;
    118     Mode m_mode;
    119 };
    120 
    121 inline bool SelectorChecker::isCommonPseudoClassSelector(const CSSSelector* selector)
    122 {
    123     if (selector->m_match != CSSSelector::PseudoClass)
    124         return false;
    125     CSSSelector::PseudoType pseudoType = selector->pseudoType();
    126     return pseudoType == CSSSelector::PseudoLink
    127         || pseudoType == CSSSelector::PseudoAnyLink
    128         || pseudoType == CSSSelector::PseudoVisited
    129         || pseudoType == CSSSelector::PseudoFocus;
    130 }
    131 
    132 inline bool SelectorChecker::tagMatches(const Element* element, const QualifiedName& tagQName)
    133 {
    134     if (tagQName == anyQName())
    135         return true;
    136     const AtomicString& localName = tagQName.localName();
    137     if (localName != starAtom && localName != element->localName())
    138         return false;
    139     const AtomicString& namespaceURI = tagQName.namespaceURI();
    140     return namespaceURI == starAtom || namespaceURI == element->namespaceURI();
    141 }
    142 
    143 inline bool SelectorChecker::checkExactAttribute(const Element* element, const QualifiedName& selectorAttributeName, const StringImpl* value)
    144 {
    145     if (!element->hasAttributesWithoutUpdate())
    146         return false;
    147     unsigned size = element->attributeCount();
    148     for (unsigned i = 0; i < size; ++i) {
    149         const Attribute* attribute = element->attributeItem(i);
    150         if (attribute->matches(selectorAttributeName) && (!value || attribute->value().impl() == value))
    151             return true;
    152     }
    153     return false;
    154 }
    155 
    156 }
    157 
    158 #endif
    159