2010-07-08 Eric Carlson <eric.carlson@apple.com>
[WebKit-https.git] / WebCore / css / CSSSelector.h
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 "RenderStyleConstants.h"
26 #include "QualifiedName.h"
27 #include <wtf/Noncopyable.h>
28 #include <wtf/OwnPtr.h>
29 #include <wtf/PassOwnPtr.h>
30
31 namespace WebCore {
32
33     // this class represents a selector for a StyleRule
34     class CSSSelector : public Noncopyable {
35     public:
36         CSSSelector()
37             : m_relation(Descendant)
38             , m_match(None)
39             , m_pseudoType(PseudoNotParsed)
40             , m_parsedNth(false)
41             , m_isLastInSelectorList(false)
42             , m_hasRareData(false)
43             , m_isForPage(false)
44             , m_tag(anyQName())
45         {
46         }
47
48         CSSSelector(const QualifiedName& qName)
49             : m_relation(Descendant)
50             , m_match(None)
51             , m_pseudoType(PseudoNotParsed)
52             , m_parsedNth(false)
53             , m_isLastInSelectorList(false)
54             , m_hasRareData(false)
55             , m_isForPage(false)
56             , m_tag(qName)
57         {
58         }
59
60         ~CSSSelector()
61         {
62             if (m_hasRareData)
63                 delete m_data.m_rareData;
64             else
65                 delete m_data.m_tagHistory;
66         }
67
68         /**
69          * Re-create selector text from selector's data
70          */
71         String selectorText() const;
72
73         // checks if the 2 selectors (including sub selectors) agree.
74         bool operator==(const CSSSelector&);
75
76         // tag == -1 means apply to all elements (Selector = *)
77
78         unsigned specificity();
79
80         /* how the attribute value has to match.... Default is Exact */
81         enum Match {
82             None = 0,
83             Id,
84             Class,
85             Exact,
86             Set,
87             List,
88             Hyphen,
89             PseudoClass,
90             PseudoElement,
91             Contain, // css3: E[foo*="bar"]
92             Begin, // css3: E[foo^="bar"]
93             End, // css3: E[foo$="bar"]
94             PagePseudoClass
95         };
96
97         enum Relation {
98             Descendant = 0,
99             Child,
100             DirectAdjacent,
101             IndirectAdjacent,
102             SubSelector
103         };
104
105         enum PseudoType {
106             PseudoNotParsed = 0,
107             PseudoUnknown,
108             PseudoEmpty,
109             PseudoFirstChild,
110             PseudoFirstOfType,
111             PseudoLastChild,
112             PseudoLastOfType,
113             PseudoOnlyChild,
114             PseudoOnlyOfType,
115             PseudoFirstLine,
116             PseudoFirstLetter,
117             PseudoNthChild,
118             PseudoNthOfType,
119             PseudoNthLastChild,
120             PseudoNthLastOfType,
121             PseudoLink,
122             PseudoVisited,
123             PseudoAnyLink,
124             PseudoAutofill,
125             PseudoHover,
126             PseudoDrag,
127             PseudoFocus,
128             PseudoActive,
129             PseudoChecked,
130             PseudoEnabled,
131             PseudoFullPageMedia,
132             PseudoDefault,
133             PseudoDisabled,
134             PseudoInputPlaceholder,
135             PseudoOptional,
136             PseudoRequired,
137             PseudoReadOnly,
138             PseudoReadWrite,
139             PseudoValid,
140             PseudoInvalid,
141             PseudoIndeterminate,
142             PseudoTarget,
143             PseudoBefore,
144             PseudoAfter,
145             PseudoLang,
146             PseudoNot,
147             PseudoResizer,
148             PseudoRoot,
149             PseudoScrollbar,
150             PseudoScrollbarBack,
151             PseudoScrollbarButton,
152             PseudoScrollbarCorner,
153             PseudoScrollbarForward,
154             PseudoScrollbarThumb,
155             PseudoScrollbarTrack,
156             PseudoScrollbarTrackPiece,
157             PseudoWindowInactive,
158             PseudoCornerPresent,
159             PseudoDecrement,
160             PseudoIncrement,
161             PseudoHorizontal,
162             PseudoVertical,
163             PseudoStart,
164             PseudoEnd,
165             PseudoDoubleButton,
166             PseudoSingleButton,
167             PseudoNoButton,
168             PseudoSelection,
169             PseudoFileUploadButton,
170             PseudoSliderThumb,
171             PseudoSearchCancelButton,
172             PseudoSearchDecoration,
173             PseudoSearchResultsDecoration,
174             PseudoSearchResultsButton,
175             PseudoMediaControlsPanel,
176             PseudoMediaControlsMuteButton,
177             PseudoMediaControlsPlayButton,
178             PseudoMediaControlsTimelineContainer,
179             PseudoMediaControlsVolumeSliderContainer,
180             PseudoMediaControlsVolumeSliderMuteButton,
181             PseudoMediaControlsCurrentTimeDisplay,
182             PseudoMediaControlsTimeRemainingDisplay,
183             PseudoMediaControlsToggleClosedCaptions,
184             PseudoMediaControlsTimeline,
185             PseudoMediaControlsVolumeSlider,
186             PseudoMediaControlsSeekBackButton,
187             PseudoMediaControlsSeekForwardButton,
188             PseudoMediaControlsRewindButton,
189             PseudoMediaControlsReturnToRealtimeButton,
190             PseudoMediaControlsStatusDisplay,
191             PseudoMediaControlsFullscreenButton,
192             PseudoMeterHorizontalBar,
193             PseudoMeterVerticalBar,
194             PseudoMeterHorizontalOptimum,
195             PseudoMeterHorizontalSuboptimal,
196             PseudoMeterHorizontalEvenLessGood,
197             PseudoMeterVerticalOptimum,
198             PseudoMeterVerticalSuboptimal,
199             PseudoMeterVerticalEvenLessGood,
200             PseudoInputListButton,
201 #if ENABLE(INPUT_SPEECH)
202             PseudoInputSpeechButton,
203 #endif
204             PseudoInnerSpinButton,
205             PseudoOuterSpinButton,
206             PseudoProgressBarValue,
207             PseudoLeftPage,
208             PseudoRightPage,
209             PseudoFirstPage,
210         };
211
212         enum MarginBoxType {
213             TopLeftCornerMarginBox,
214             TopLeftMarginBox,
215             TopCenterMarginBox,
216             TopRightMarginBox,
217             TopRightCornerMarginBox,
218             BottomLeftCornerMarginBox,
219             BottomLeftMarginBox,
220             BottomCenterMarginBox,
221             BottomRightMarginBox,
222             BottomRightCornerMarginBox,
223             LeftTopMarginBox,
224             LeftMiddleMarginBox,
225             LeftBottomMarginBox,
226             RightTopMarginBox,
227             RightMiddleMarginBox,
228             RightBottomMarginBox,
229         };
230
231         PseudoType pseudoType() const
232         {
233             if (m_pseudoType == PseudoNotParsed)
234                 extractPseudoType();
235             return static_cast<PseudoType>(m_pseudoType);
236         }
237
238         static PseudoType parsePseudoType(const AtomicString&);
239         static PseudoId pseudoId(PseudoType);
240
241         CSSSelector* tagHistory() const { return m_hasRareData ? m_data.m_rareData->m_tagHistory.get() : m_data.m_tagHistory; }
242         void setTagHistory(CSSSelector* tagHistory);
243
244         bool hasTag() const { return m_tag != anyQName(); }
245         bool hasAttribute() const { return m_match == Id || m_match == Class || (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()); }
246         
247         const QualifiedName& attribute() const;
248         const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
249         CSSSelector* simpleSelector() const { return m_hasRareData ? m_data.m_rareData->m_simpleSelector.get() : 0; }
250         
251         void setAttribute(const QualifiedName& value);
252         void setArgument(const AtomicString& value);
253         void setSimpleSelector(CSSSelector* value);
254         
255         bool parseNth();
256         bool matchNth(int count);
257
258         bool matchesPseudoElement() const 
259         { 
260             if (m_pseudoType == PseudoUnknown)
261                 extractPseudoType();
262             return m_match == PseudoElement;
263         }
264
265         Relation relation() const { return static_cast<Relation>(m_relation); }
266
267         bool isLastInSelectorList() const { return m_isLastInSelectorList; }
268         void setLastInSelectorList() { m_isLastInSelectorList = true; }
269         bool isSimple() const;
270
271         bool isForPage() const { return m_isForPage; }
272         void setForPage() { m_isForPage = true; }
273
274         unsigned m_relation           : 3; // enum Relation
275         mutable unsigned m_match      : 4; // enum Match
276         mutable unsigned m_pseudoType : 8; // PseudoType
277         
278     private:
279         bool m_parsedNth              : 1; // Used for :nth-* 
280         bool m_isLastInSelectorList   : 1;
281         bool m_hasRareData            : 1;
282         bool m_isForPage              : 1;
283
284         unsigned specificityForPage();
285         void extractPseudoType() const;
286
287         struct RareData : Noncopyable {
288             RareData(PassOwnPtr<CSSSelector> tagHistory)
289                 : m_a(0)
290                 , m_b(0)
291                 , m_tagHistory(tagHistory)
292                 , m_attribute(anyQName())
293                 , m_argument(nullAtom)
294             {
295             }
296
297             bool parseNth();
298             bool matchNth(int count);
299
300             int m_a; // Used for :nth-*
301             int m_b; // Used for :nth-*
302             OwnPtr<CSSSelector> m_tagHistory;
303             OwnPtr<CSSSelector> m_simpleSelector; // Used for :not.
304             QualifiedName m_attribute; // used for attribute selector
305             AtomicString m_argument; // Used for :contains, :lang and :nth-*
306         };
307
308         void createRareData()
309         {
310             if (m_hasRareData) 
311                 return;
312             m_data.m_rareData = new RareData(adoptPtr(m_data.m_tagHistory));
313             m_hasRareData = true;
314         }
315         
316         union DataUnion {
317             DataUnion() : m_tagHistory(0) { }
318             CSSSelector* m_tagHistory;
319             RareData* m_rareData;
320         } m_data;
321         
322     public:
323         mutable AtomicString m_value;
324         QualifiedName m_tag;
325     };
326
327 } // namespace WebCore
328
329 #endif // CSSSelector_h