• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  *               1999 Waldo Bastian (bastian@kde.org)
4  * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifndef CSSSelector_h
23 #define CSSSelector_h
24 
25 #include "QualifiedName.h"
26 #include "RenderStyleConstants.h"
27 #include <wtf/Noncopyable.h>
28 #include <wtf/OwnPtr.h>
29 #include <wtf/PassOwnPtr.h>
30 
31 namespace WebCore {
32     class CSSSelectorList;
33 
34     // this class represents a selector for a StyleRule
35     class CSSSelector {
36         WTF_MAKE_NONCOPYABLE(CSSSelector); WTF_MAKE_FAST_ALLOCATED;
37     public:
CSSSelector()38         CSSSelector()
39             : m_relation(Descendant)
40             , m_match(None)
41             , m_pseudoType(PseudoNotParsed)
42             , m_parsedNth(false)
43             , m_isLastInSelectorList(false)
44             , m_isLastInTagHistory(true)
45             , m_hasRareData(false)
46             , m_isForPage(false)
47             , m_deleted(false)
48             , m_tag(anyQName())
49         {
50         }
51 
CSSSelector(const QualifiedName & qName)52         CSSSelector(const QualifiedName& qName)
53             : m_relation(Descendant)
54             , m_match(None)
55             , m_pseudoType(PseudoNotParsed)
56             , m_parsedNth(false)
57             , m_isLastInSelectorList(false)
58             , m_isLastInTagHistory(true)
59             , m_hasRareData(false)
60             , m_isForPage(false)
61             , m_deleted(false)
62             , m_tag(qName)
63         {
64         }
65 
~CSSSelector()66         ~CSSSelector()
67         {
68             if (m_deleted)
69                 CRASH();
70             m_deleted = true;
71             if (m_hasRareData)
72                 delete m_data.m_rareData;
73             else if (m_data.m_value)
74                 m_data.m_value->deref();
75         }
76 
77         /**
78          * Re-create selector text from selector's data
79          */
80         String selectorText() const;
81 
82         // checks if the 2 selectors (including sub selectors) agree.
83         bool operator==(const CSSSelector&);
84 
85         // tag == -1 means apply to all elements (Selector = *)
86 
87         unsigned specificity() const;
88 
89         /* how the attribute value has to match.... Default is Exact */
90         enum Match {
91             None = 0,
92             Id,
93             Class,
94             Exact,
95             Set,
96             List,
97             Hyphen,
98             PseudoClass,
99             PseudoElement,
100             Contain, // css3: E[foo*="bar"]
101             Begin, // css3: E[foo^="bar"]
102             End, // css3: E[foo$="bar"]
103             PagePseudoClass
104         };
105 
106         enum Relation {
107             Descendant = 0,
108             Child,
109             DirectAdjacent,
110             IndirectAdjacent,
111             SubSelector,
112             ShadowDescendant
113         };
114 
115         enum PseudoType {
116             PseudoNotParsed = 0,
117             PseudoUnknown,
118             PseudoEmpty,
119             PseudoFirstChild,
120             PseudoFirstOfType,
121             PseudoLastChild,
122             PseudoLastOfType,
123             PseudoOnlyChild,
124             PseudoOnlyOfType,
125             PseudoFirstLine,
126             PseudoFirstLetter,
127             PseudoNthChild,
128             PseudoNthOfType,
129             PseudoNthLastChild,
130             PseudoNthLastOfType,
131             PseudoLink,
132             PseudoVisited,
133             PseudoAny,
134             PseudoAnyLink,
135             PseudoAutofill,
136             PseudoHover,
137             PseudoDrag,
138             PseudoFocus,
139             PseudoActive,
140             PseudoChecked,
141             PseudoEnabled,
142             PseudoFullPageMedia,
143             PseudoDefault,
144             PseudoDisabled,
145             PseudoInputPlaceholder,
146             PseudoOptional,
147             PseudoRequired,
148             PseudoReadOnly,
149             PseudoReadWrite,
150             PseudoValid,
151             PseudoInvalid,
152             PseudoIndeterminate,
153             PseudoTarget,
154             PseudoBefore,
155             PseudoAfter,
156             PseudoLang,
157             PseudoNot,
158             PseudoResizer,
159             PseudoRoot,
160             PseudoScrollbar,
161             PseudoScrollbarBack,
162             PseudoScrollbarButton,
163             PseudoScrollbarCorner,
164             PseudoScrollbarForward,
165             PseudoScrollbarThumb,
166             PseudoScrollbarTrack,
167             PseudoScrollbarTrackPiece,
168             PseudoWindowInactive,
169             PseudoCornerPresent,
170             PseudoDecrement,
171             PseudoIncrement,
172             PseudoHorizontal,
173             PseudoVertical,
174             PseudoStart,
175             PseudoEnd,
176             PseudoDoubleButton,
177             PseudoSingleButton,
178             PseudoNoButton,
179             PseudoSelection,
180             PseudoFileUploadButton,
181             PseudoSearchCancelButton,
182             PseudoSearchDecoration,
183             PseudoSearchResultsDecoration,
184             PseudoSearchResultsButton,
185             PseudoInputListButton,
186 #if ENABLE(INPUT_SPEECH)
187             PseudoInputSpeechButton,
188 #endif
189             PseudoInnerSpinButton,
190             PseudoOuterSpinButton,
191             PseudoLeftPage,
192             PseudoRightPage,
193             PseudoFirstPage,
194 #if ENABLE(FULLSCREEN_API)
195             PseudoFullScreen,
196             PseudoFullScreenDocument,
197 #endif
198             PseudoInRange,
199             PseudoOutOfRange,
200         };
201 
202         enum MarginBoxType {
203             TopLeftCornerMarginBox,
204             TopLeftMarginBox,
205             TopCenterMarginBox,
206             TopRightMarginBox,
207             TopRightCornerMarginBox,
208             BottomLeftCornerMarginBox,
209             BottomLeftMarginBox,
210             BottomCenterMarginBox,
211             BottomRightMarginBox,
212             BottomRightCornerMarginBox,
213             LeftTopMarginBox,
214             LeftMiddleMarginBox,
215             LeftBottomMarginBox,
216             RightTopMarginBox,
217             RightMiddleMarginBox,
218             RightBottomMarginBox,
219         };
220 
pseudoType()221         PseudoType pseudoType() const
222         {
223             if (m_pseudoType == PseudoNotParsed)
224                 extractPseudoType();
225             return static_cast<PseudoType>(m_pseudoType);
226         }
227 
228         static PseudoType parsePseudoType(const AtomicString&);
229         static PseudoId pseudoId(PseudoType);
230 
231         // Selectors are kept in an array by CSSSelectorList. The next component of the selector is
232         // the next item in the array.
tagHistory()233         CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); }
234 
hasTag()235         bool hasTag() const { return m_tag != anyQName(); }
hasAttribute()236         bool hasAttribute() const { return m_match == Id || m_match == Class || (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()); }
237 
tag()238         const QualifiedName& tag() const { return m_tag; }
239         // AtomicString is really just an AtomicStringImpl* so the cast below is safe.
240         // FIXME: Perhaps call sites could be changed to accept AtomicStringImpl?
value()241         const AtomicString& value() const { return *reinterpret_cast<const AtomicString*>(m_hasRareData ? &m_data.m_rareData->m_value : &m_data.m_value); }
242         const QualifiedName& attribute() const;
argument()243         const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
selectorList()244         CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; }
245 
setTag(const QualifiedName & value)246         void setTag(const QualifiedName& value) { m_tag = value; }
247         void setValue(const AtomicString&);
248         void setAttribute(const QualifiedName&);
249         void setArgument(const AtomicString&);
250         void setSelectorList(PassOwnPtr<CSSSelectorList>);
251 
252         bool parseNth();
253         bool matchNth(int count);
254 
255         bool matchesPseudoElement() const;
256         bool isUnknownPseudoElement() const;
257         bool isSiblingSelector() const;
258 
relation()259         Relation relation() const { return static_cast<Relation>(m_relation); }
260 
isLastInSelectorList()261         bool isLastInSelectorList() const { return m_isLastInSelectorList; }
setLastInSelectorList()262         void setLastInSelectorList() { m_isLastInSelectorList = true; }
isLastInTagHistory()263         bool isLastInTagHistory() const { return m_isLastInTagHistory; }
setNotLastInTagHistory()264         void setNotLastInTagHistory() { m_isLastInTagHistory = false; }
265 
266         bool isSimple() const;
267 
isForPage()268         bool isForPage() const { return m_isForPage; }
setForPage()269         void setForPage() { m_isForPage = true; }
270 
271         unsigned m_relation           : 3; // enum Relation
272         mutable unsigned m_match      : 4; // enum Match
273         mutable unsigned m_pseudoType : 8; // PseudoType
274 
275     private:
276         bool m_parsedNth              : 1; // Used for :nth-*
277         bool m_isLastInSelectorList   : 1;
278         bool m_isLastInTagHistory     : 1;
279         bool m_hasRareData            : 1;
280         bool m_isForPage              : 1;
281         // FIXME: Remove once http://webkit.org/b/56124 is fixed.
282         bool m_deleted                : 1;
283 
284         unsigned specificityForOneSelector() const;
285         unsigned specificityForPage() const;
286         void extractPseudoType() const;
287 
288         struct RareData {
289             WTF_MAKE_NONCOPYABLE(RareData); WTF_MAKE_FAST_ALLOCATED;
290         public:
291             RareData(PassRefPtr<AtomicStringImpl> value);
292             ~RareData();
293 
294             bool parseNth();
295             bool matchNth(int count);
296 
297             AtomicStringImpl* m_value; // Plain pointer to keep things uniform with the union.
298             int m_a; // Used for :nth-*
299             int m_b; // Used for :nth-*
300             QualifiedName m_attribute; // used for attribute selector
301             AtomicString m_argument; // Used for :contains, :lang and :nth-*
302             OwnPtr<CSSSelectorList> m_selectorList; // Used for :-webkit-any and :not
303         };
304         void createRareData();
305 
306         union DataUnion {
DataUnion()307             DataUnion() : m_value(0) { }
308             AtomicStringImpl* m_value;
309             RareData* m_rareData;
310         } m_data;
311 
312         QualifiedName m_tag;
313     };
314 
matchesPseudoElement()315 inline bool CSSSelector::matchesPseudoElement() const
316 {
317     if (m_pseudoType == PseudoUnknown)
318         extractPseudoType();
319     return m_match == PseudoElement;
320 }
321 
isUnknownPseudoElement()322 inline bool CSSSelector::isUnknownPseudoElement() const
323 {
324     return m_match == PseudoElement && m_pseudoType == PseudoUnknown;
325 }
326 
isSiblingSelector()327 inline bool CSSSelector::isSiblingSelector() const
328 {
329     PseudoType type = pseudoType();
330     return m_relation == DirectAdjacent
331         || m_relation == IndirectAdjacent
332         || type == PseudoEmpty
333         || type == PseudoFirstChild
334         || type == PseudoFirstOfType
335         || type == PseudoLastChild
336         || type == PseudoLastOfType
337         || type == PseudoOnlyChild
338         || type == PseudoOnlyOfType
339         || type == PseudoNthChild
340         || type == PseudoNthOfType
341         || type == PseudoNthLastChild
342         || type == PseudoNthLastOfType;
343 }
344 
setValue(const AtomicString & value)345 inline void CSSSelector::setValue(const AtomicString& value)
346 {
347     // Need to do ref counting manually for the union.
348     if (m_hasRareData) {
349         m_data.m_rareData->m_value = value.impl();
350         m_data.m_rareData->m_value->ref();
351         return;
352     }
353     m_data.m_value = value.impl();
354     m_data.m_value->ref();
355 }
356 
move(PassOwnPtr<CSSSelector> from,CSSSelector * to)357 inline void move(PassOwnPtr<CSSSelector> from, CSSSelector* to)
358 {
359     memcpy(to, from.get(), sizeof(CSSSelector));
360     // We want to free the memory (which was allocated with fastNew), but we
361     // don't want the destructor to run since it will affect the copy we've just made.
362     fastDeleteSkippingDestructor(from.leakPtr());
363 }
364 
365 } // namespace WebCore
366 
367 #endif // CSSSelector_h
368