fd98ccc4a96b2400f3f633a523305affe447fe33
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / SelectorChecker.h
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 WebCore {
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 BehaviorAtBoundary {
51         DoesNotCrossBoundary = 0,
52         // FIXME: refactor to remove BoundaryBehavior (i.e. DoesNotCrossBoundary and StaysWithinTreeScope).
53         StaysWithinTreeScope = 2,
54         BoundaryBehaviorMask = 3, // 2bit for boundary behavior
55         ScopeContainsLastMatchedElement = 4,
56         ScopeIsShadowHost = 8,
57         TreatShadowHostAsNormalScope = 16,
58
59         ScopeIsShadowHostInPseudoHostParameter = ScopeIsShadowHost | TreatShadowHostAsNormalScope
60     };
61
62     enum MatchingTagType {
63         MatchingElement = 0,
64         MatchingHostInItsShadowTree
65     };
66
67     struct SelectorCheckingContext {
68         // Initial selector constructor
69         SelectorCheckingContext(const CSSSelector& selector, Element* element, VisitedMatchType visitedMatchType)
70             : selector(&selector)
71             , element(element)
72             , scope(0)
73             , visitedMatchType(visitedMatchType)
74             , pseudoId(NOPSEUDO)
75             , elementStyle(0)
76             , scrollbar(0)
77             , scrollbarPart(NoPart)
78             , isSubSelector(false)
79             , hasScrollbarPseudo(false)
80             , hasSelectionPseudo(false)
81             , behaviorAtBoundary(DoesNotCrossBoundary)
82         { }
83
84         const CSSSelector* selector;
85         Element* element;
86         const ContainerNode* scope;
87         VisitedMatchType visitedMatchType;
88         PseudoId pseudoId;
89         RenderStyle* elementStyle;
90         RenderScrollbar* scrollbar;
91         ScrollbarPart scrollbarPart;
92         bool isSubSelector;
93         bool hasScrollbarPseudo;
94         bool hasSelectionPseudo;
95         BehaviorAtBoundary behaviorAtBoundary;
96     };
97
98     struct MatchResult {
99         MatchResult()
100             : dynamicPseudo(NOPSEUDO)
101             , specificity(0) { }
102
103         PseudoId dynamicPseudo;
104         unsigned specificity;
105     };
106
107     template<typename SiblingTraversalStrategy>
108     Match match(const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult* = 0) const;
109
110     template<typename SiblingTraversalStrategy>
111     bool checkOne(const SelectorCheckingContext&, const SiblingTraversalStrategy&, unsigned* specificity = 0) const;
112
113     bool strictParsing() const { return m_strictParsing; }
114
115     Mode mode() const { return m_mode; }
116
117     static bool tagMatches(const Element&, const QualifiedName&, MatchingTagType = MatchingElement);
118     static bool isCommonPseudoClassSelector(const CSSSelector&);
119     static bool matchesFocusPseudoClass(const Element&);
120     static bool checkExactAttribute(const Element&, const QualifiedName& selectorAttributeName, const StringImpl* value);
121
122     enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
123     static unsigned determineLinkMatchType(const CSSSelector&);
124
125     static bool isHostInItsShadowTree(const Element&, BehaviorAtBoundary, const ContainerNode* scope);
126
127 private:
128     template<typename SiblingTraversalStrategy>
129     Match matchForSubSelector(const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
130     template<typename SiblingTraversalStrategy>
131     Match matchForRelation(const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
132     template<typename SiblingTraversalStrategy>
133     Match matchForShadowDistributed(const Element*, const SiblingTraversalStrategy&, SelectorCheckingContext& nextContext, MatchResult* = 0) const;
134
135     bool checkScrollbarPseudoClass(const SelectorCheckingContext&, Document*, const CSSSelector&) const;
136     Element* parentElement(const SelectorCheckingContext&, bool allowToCrossBoundary = false) const;
137     bool scopeContainsLastMatchedElement(const SelectorCheckingContext&) const;
138
139     static bool isFrameFocused(const Element&);
140
141     bool m_strictParsing;
142     bool m_documentIsHTML;
143     Mode m_mode;
144 };
145
146 inline bool SelectorChecker::isCommonPseudoClassSelector(const CSSSelector& selector)
147 {
148     if (selector.m_match != CSSSelector::PseudoClass)
149         return false;
150     CSSSelector::PseudoType pseudoType = selector.pseudoType();
151     return pseudoType == CSSSelector::PseudoLink
152         || pseudoType == CSSSelector::PseudoAnyLink
153         || pseudoType == CSSSelector::PseudoVisited
154         || pseudoType == CSSSelector::PseudoFocus;
155 }
156
157 inline bool SelectorChecker::tagMatches(const Element& element, const QualifiedName& tagQName, MatchingTagType matchingTagType)
158 {
159     if (tagQName == anyQName())
160         return true;
161     const AtomicString& localName = tagQName.localName();
162     if (localName != starAtom && (localName != element.localName() || matchingTagType == MatchingHostInItsShadowTree))
163         return false;
164     const AtomicString& namespaceURI = tagQName.namespaceURI();
165     return namespaceURI == starAtom || namespaceURI == element.namespaceURI();
166 }
167
168 inline bool SelectorChecker::checkExactAttribute(const Element& element, const QualifiedName& selectorAttributeName, const StringImpl* value)
169 {
170     if (!element.hasAttributesWithoutUpdate())
171         return false;
172     unsigned size = element.attributeCount();
173     for (unsigned i = 0; i < size; ++i) {
174         const Attribute* attribute = element.attributeItem(i);
175         if (attribute->matches(selectorAttributeName) && (!value || attribute->value().impl() == value))
176             return true;
177     }
178     return false;
179 }
180
181 inline bool SelectorChecker::isHostInItsShadowTree(const Element& element, BehaviorAtBoundary behaviorAtBoundary, const ContainerNode* scope)
182 {
183     return (behaviorAtBoundary & (ScopeIsShadowHost | TreatShadowHostAsNormalScope)) == ScopeIsShadowHost && scope == element;
184 }
185
186 }
187
188 #endif