• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@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@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@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
SelectorCheckingContextSelectorCheckingContext61         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 {
MatchResultMatchResult96         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 
strictParsing()110     bool strictParsing() const { return m_strictParsing; }
111 
mode()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 
isCommonPseudoClassSelector(const CSSSelector & selector)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 
tagMatches(const Element & element,const QualifiedName & tagQName)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 
checkExactAttribute(const Element & element,const QualifiedName & selectorAttributeName,const StringImpl * value)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 
isHostInItsShadowTree(const Element & element,const ContainerNode * scope)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