7d23d1cf4e04e4f9240fbbf94c62f37befc2900d
[WebKit-https.git] / WebCore / css / CSSSelector.cpp
1 /*
2  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  *               1999 Waldo Bastian (bastian@kde.org)
4  *               2001 Andreas Schlapbach (schlpbch@iam.unibe.ch)
5  *               2001-2003 Dirk Mueller (mueller@kde.org)
6  * Copyright (C) 2002, 2006, 2007, 2008 Apple Inc. All rights reserved.
7  * Copyright (C) 2008 David Smith (catfish.man@gmail.com)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "config.h"
26 #include "CSSSelector.h"
27
28 #include "wtf/Assertions.h"
29 #include "HTMLNames.h"
30
31 #include <wtf/HashMap.h>
32 #include <wtf/StdLibExtras.h>
33
34 namespace WebCore {
35     
36 using namespace HTMLNames;
37
38 unsigned int CSSSelector::specificity()
39 {
40     // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
41     // isn't quite correct.
42     int s = (m_tag.localName() == starAtom ? 0 : 1);
43     switch (m_match) {
44         case Id:
45             s += 0x10000;
46             break;
47         case Exact:
48         case Class:
49         case Set:
50         case List:
51         case Hyphen:
52         case PseudoClass:
53         case PseudoElement:
54         case Contain:
55         case Begin:
56         case End:
57             s += 0x100;
58         case None:
59             break;
60     }
61
62     if (CSSSelector* tagHistory = this->tagHistory())
63         s += tagHistory->specificity();
64
65     // make sure it doesn't overflow
66     return s & 0xffffff;
67 }
68
69 PseudoId CSSSelector::pseudoId(PseudoType type)
70 {
71     switch (type) {
72     case PseudoFirstLine:
73         return FIRST_LINE;
74     case PseudoFirstLetter:
75         return FIRST_LETTER;
76     case PseudoSelection:
77         return SELECTION;
78     case PseudoBefore:
79         return BEFORE;
80     case PseudoAfter:
81         return AFTER;
82     case PseudoFileUploadButton:
83         return FILE_UPLOAD_BUTTON;
84     case PseudoInputPlaceholder:
85         return INPUT_PLACEHOLDER;
86     case PseudoSliderThumb:
87         return SLIDER_THUMB;
88     case PseudoSearchCancelButton:
89         return SEARCH_CANCEL_BUTTON;
90     case PseudoSearchDecoration:
91         return SEARCH_DECORATION;
92     case PseudoSearchResultsDecoration:
93         return SEARCH_RESULTS_DECORATION;
94     case PseudoSearchResultsButton:
95         return SEARCH_RESULTS_BUTTON;
96     case PseudoMediaControlsPanel:
97         return MEDIA_CONTROLS_PANEL;
98     case PseudoMediaControlsMuteButton:
99         return MEDIA_CONTROLS_MUTE_BUTTON;
100     case PseudoMediaControlsPlayButton:
101         return MEDIA_CONTROLS_PLAY_BUTTON;
102     case PseudoMediaControlsTimelineContainer:
103         return MEDIA_CONTROLS_TIMELINE_CONTAINER;
104     case PseudoMediaControlsVolumeSliderContainer:
105         return MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER;
106     case PseudoMediaControlsCurrentTimeDisplay:
107         return MEDIA_CONTROLS_CURRENT_TIME_DISPLAY;
108     case PseudoMediaControlsTimeRemainingDisplay:
109         return MEDIA_CONTROLS_TIME_REMAINING_DISPLAY;
110     case PseudoMediaControlsTimeline:
111         return MEDIA_CONTROLS_TIMELINE;
112     case PseudoMediaControlsVolumeSlider:
113         return MEDIA_CONTROLS_VOLUME_SLIDER;
114     case PseudoMediaControlsSeekBackButton:
115         return MEDIA_CONTROLS_SEEK_BACK_BUTTON;
116     case PseudoMediaControlsSeekForwardButton:
117         return MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
118     case PseudoMediaControlsRewindButton:
119         return MEDIA_CONTROLS_REWIND_BUTTON;
120     case PseudoMediaControlsReturnToRealtimeButton:
121         return MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON;
122     case PseudoMediaControlsToggleClosedCaptions:
123         return MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON;
124     case PseudoMediaControlsStatusDisplay:
125         return MEDIA_CONTROLS_STATUS_DISPLAY;
126     case PseudoMediaControlsFullscreenButton:
127         return MEDIA_CONTROLS_FULLSCREEN_BUTTON;
128     case PseudoScrollbar:
129         return SCROLLBAR;
130     case PseudoScrollbarButton:
131         return SCROLLBAR_BUTTON;
132     case PseudoScrollbarCorner:
133         return SCROLLBAR_CORNER;
134     case PseudoScrollbarThumb:
135         return SCROLLBAR_THUMB;
136     case PseudoScrollbarTrack:
137         return SCROLLBAR_TRACK;
138     case PseudoScrollbarTrackPiece:
139         return SCROLLBAR_TRACK_PIECE;
140     case PseudoResizer:
141         return RESIZER;
142     case PseudoInnerSpinButton:
143         return INNER_SPIN_BUTTON;
144     case PseudoOuterSpinButton:
145         return OUTER_SPIN_BUTTON;
146     case PseudoProgressBarValue:
147 #if ENABLE(PROGRESS_TAG)
148         return PROGRESS_BAR_VALUE;
149 #else
150         ASSERT_NOT_REACHED();
151         return NOPSEUDO;
152 #endif
153     case PseudoInputListButton:
154 #if ENABLE(DATALIST)
155         return INPUT_LIST_BUTTON;
156 #endif
157     case PseudoUnknown:
158     case PseudoEmpty:
159     case PseudoFirstChild:
160     case PseudoFirstOfType:
161     case PseudoLastChild:
162     case PseudoLastOfType:
163     case PseudoOnlyChild:
164     case PseudoOnlyOfType:
165     case PseudoNthChild:
166     case PseudoNthOfType:
167     case PseudoNthLastChild:
168     case PseudoNthLastOfType:
169     case PseudoLink:
170     case PseudoVisited:
171     case PseudoAnyLink:
172     case PseudoAutofill:
173     case PseudoHover:
174     case PseudoDrag:
175     case PseudoFocus:
176     case PseudoActive:
177     case PseudoChecked:
178     case PseudoEnabled:
179     case PseudoFullPageMedia:
180     case PseudoDefault:
181     case PseudoDisabled:
182     case PseudoOptional:
183     case PseudoRequired:
184     case PseudoReadOnly:
185     case PseudoReadWrite:
186     case PseudoValid:
187     case PseudoInvalid:
188     case PseudoIndeterminate:
189     case PseudoTarget:
190     case PseudoLang:
191     case PseudoNot:
192     case PseudoRoot:
193     case PseudoScrollbarBack:
194     case PseudoScrollbarForward:
195     case PseudoWindowInactive:
196     case PseudoCornerPresent:
197     case PseudoDecrement:
198     case PseudoIncrement:
199     case PseudoHorizontal:
200     case PseudoVertical:
201     case PseudoStart:
202     case PseudoEnd:
203     case PseudoDoubleButton:
204     case PseudoSingleButton:
205     case PseudoNoButton:
206     case PseudoFirstPage:
207     case PseudoLeftPage:
208     case PseudoRightPage:
209         return NOPSEUDO;
210     case PseudoNotParsed:
211         ASSERT_NOT_REACHED();
212         return NOPSEUDO;
213     }
214
215     ASSERT_NOT_REACHED();
216     return NOPSEUDO;
217 }
218
219 static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
220 {
221     DEFINE_STATIC_LOCAL(AtomicString, active, ("active"));
222     DEFINE_STATIC_LOCAL(AtomicString, after, ("after"));
223     DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link"));
224     DEFINE_STATIC_LOCAL(AtomicString, autofill, ("-webkit-autofill"));
225     DEFINE_STATIC_LOCAL(AtomicString, before, ("before"));
226     DEFINE_STATIC_LOCAL(AtomicString, checked, ("checked"));
227     DEFINE_STATIC_LOCAL(AtomicString, fileUploadButton, ("-webkit-file-upload-button"));
228     DEFINE_STATIC_LOCAL(AtomicString, defaultString, ("default"));
229     DEFINE_STATIC_LOCAL(AtomicString, disabled, ("disabled"));
230     DEFINE_STATIC_LOCAL(AtomicString, readOnly, ("read-only"));
231     DEFINE_STATIC_LOCAL(AtomicString, readWrite, ("read-write"));
232     DEFINE_STATIC_LOCAL(AtomicString, valid, ("valid"));
233     DEFINE_STATIC_LOCAL(AtomicString, invalid, ("invalid"));
234     DEFINE_STATIC_LOCAL(AtomicString, drag, ("-webkit-drag"));
235     DEFINE_STATIC_LOCAL(AtomicString, dragAlias, ("-khtml-drag")); // was documented with this name in Apple documentation, so keep an alia
236     DEFINE_STATIC_LOCAL(AtomicString, empty, ("empty"));
237     DEFINE_STATIC_LOCAL(AtomicString, enabled, ("enabled"));
238     DEFINE_STATIC_LOCAL(AtomicString, firstChild, ("first-child"));
239     DEFINE_STATIC_LOCAL(AtomicString, firstLetter, ("first-letter"));
240     DEFINE_STATIC_LOCAL(AtomicString, firstLine, ("first-line"));
241     DEFINE_STATIC_LOCAL(AtomicString, firstOfType, ("first-of-type"));
242     DEFINE_STATIC_LOCAL(AtomicString, fullPageMedia, ("-webkit-full-page-media"));
243     DEFINE_STATIC_LOCAL(AtomicString, nthChild, ("nth-child("));
244     DEFINE_STATIC_LOCAL(AtomicString, nthOfType, ("nth-of-type("));
245     DEFINE_STATIC_LOCAL(AtomicString, nthLastChild, ("nth-last-child("));
246     DEFINE_STATIC_LOCAL(AtomicString, nthLastOfType, ("nth-last-of-type("));
247     DEFINE_STATIC_LOCAL(AtomicString, focus, ("focus"));
248     DEFINE_STATIC_LOCAL(AtomicString, hover, ("hover"));
249     DEFINE_STATIC_LOCAL(AtomicString, indeterminate, ("indeterminate"));
250     DEFINE_STATIC_LOCAL(AtomicString, innerSpinButton, ("-webkit-inner-spin-button"));
251 #if ENABLE(DATALIST)
252     DEFINE_STATIC_LOCAL(AtomicString, inputListButton, ("-webkit-input-list-button"));
253 #endif
254     DEFINE_STATIC_LOCAL(AtomicString, inputPlaceholder, ("-webkit-input-placeholder"));
255     DEFINE_STATIC_LOCAL(AtomicString, lastChild, ("last-child"));
256     DEFINE_STATIC_LOCAL(AtomicString, lastOfType, ("last-of-type"));
257     DEFINE_STATIC_LOCAL(AtomicString, link, ("link"));
258     DEFINE_STATIC_LOCAL(AtomicString, lang, ("lang("));
259     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPanel, ("-webkit-media-controls-panel"));
260     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsMuteButton, ("-webkit-media-controls-mute-button"));
261     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPlayButton, ("-webkit-media-controls-play-button"));
262     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeline, ("-webkit-media-controls-timeline"));
263     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSlider, ("-webkit-media-controls-volume-slider"));
264     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekBackButton, ("-webkit-media-controls-seek-back-button"));
265     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekForwardButton, ("-webkit-media-controls-seek-forward-button"));
266     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsRewindButton, ("-webkit-media-controls-rewind-button"));
267     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsReturnToRealtimeButton, ("-webkit-media-controls-return-to-realtime-button"));
268     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsToggleClosedCaptionsButton, ("-webkit-media-controls-toggle-closed-captions-button"));
269     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsStatusDisplay, ("-webkit-media-controls-status-display"));
270     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsFullscreenButton, ("-webkit-media-controls-fullscreen-button"));
271     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimelineContainer, ("-webkit-media-controls-timeline-container"));
272     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSliderContainer, ("-webkit-media-controls-volume-slider-container"));
273     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsCurrentTimeDisplay, ("-webkit-media-controls-current-time-display"));
274     DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeRemainingDisplay, ("-webkit-media-controls-time-remaining-display"));
275     DEFINE_STATIC_LOCAL(AtomicString, notStr, ("not("));
276     DEFINE_STATIC_LOCAL(AtomicString, onlyChild, ("only-child"));
277     DEFINE_STATIC_LOCAL(AtomicString, onlyOfType, ("only-of-type"));
278     DEFINE_STATIC_LOCAL(AtomicString, optional, ("optional"));
279     DEFINE_STATIC_LOCAL(AtomicString, outerSpinButton, ("-webkit-outer-spin-button"));
280 #if ENABLE(PROGRESS_TAG)
281     DEFINE_STATIC_LOCAL(AtomicString, progressBarValue, ("-webkit-progress-bar-value"));
282 #endif
283     DEFINE_STATIC_LOCAL(AtomicString, required, ("required"));
284     DEFINE_STATIC_LOCAL(AtomicString, resizer, ("-webkit-resizer"));
285     DEFINE_STATIC_LOCAL(AtomicString, root, ("root"));
286     DEFINE_STATIC_LOCAL(AtomicString, scrollbar, ("-webkit-scrollbar"));
287     DEFINE_STATIC_LOCAL(AtomicString, scrollbarButton, ("-webkit-scrollbar-button"));
288     DEFINE_STATIC_LOCAL(AtomicString, scrollbarCorner, ("-webkit-scrollbar-corner"));
289     DEFINE_STATIC_LOCAL(AtomicString, scrollbarThumb, ("-webkit-scrollbar-thumb"));
290     DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrack, ("-webkit-scrollbar-track"));
291     DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrackPiece, ("-webkit-scrollbar-track-piece"));
292     DEFINE_STATIC_LOCAL(AtomicString, searchCancelButton, ("-webkit-search-cancel-button"));
293     DEFINE_STATIC_LOCAL(AtomicString, searchDecoration, ("-webkit-search-decoration"));
294     DEFINE_STATIC_LOCAL(AtomicString, searchResultsDecoration, ("-webkit-search-results-decoration"));
295     DEFINE_STATIC_LOCAL(AtomicString, searchResultsButton, ("-webkit-search-results-button"));
296     DEFINE_STATIC_LOCAL(AtomicString, selection, ("selection"));
297     DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-thumb"));
298     DEFINE_STATIC_LOCAL(AtomicString, target, ("target"));
299     DEFINE_STATIC_LOCAL(AtomicString, visited, ("visited"));
300     DEFINE_STATIC_LOCAL(AtomicString, windowInactive, ("window-inactive"));
301     DEFINE_STATIC_LOCAL(AtomicString, decrement, ("decrement"));
302     DEFINE_STATIC_LOCAL(AtomicString, increment, ("increment"));
303     DEFINE_STATIC_LOCAL(AtomicString, start, ("start"));
304     DEFINE_STATIC_LOCAL(AtomicString, end, ("end"));
305     DEFINE_STATIC_LOCAL(AtomicString, horizontal, ("horizontal"));
306     DEFINE_STATIC_LOCAL(AtomicString, vertical, ("vertical"));
307     DEFINE_STATIC_LOCAL(AtomicString, doubleButton, ("double-button"));
308     DEFINE_STATIC_LOCAL(AtomicString, singleButton, ("single-button"));
309     DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button"));
310     DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present"));
311     // Paged Media pseudo-classes
312     DEFINE_STATIC_LOCAL(AtomicString, firstPage, ("first"));
313     DEFINE_STATIC_LOCAL(AtomicString, leftPage, ("left"));
314     DEFINE_STATIC_LOCAL(AtomicString, rightPage, ("right"));
315
316     static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0;
317     if (!nameToPseudoType) {
318         nameToPseudoType = new HashMap<AtomicStringImpl*, CSSSelector::PseudoType>;
319         nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive);
320         nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter);
321         nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink);
322         nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill);
323         nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore);
324         nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked);
325         nameToPseudoType->set(fileUploadButton.impl(), CSSSelector::PseudoFileUploadButton);
326         nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault);
327         nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled);
328         nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly);
329         nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite);
330         nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid);
331         nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid);
332         nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag);
333         nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag);
334         nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled);
335         nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty);
336         nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild);
337         nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia);
338 #if ENABLE(DATALIST)
339         nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton);
340 #endif
341         nameToPseudoType->set(inputPlaceholder.impl(), CSSSelector::PseudoInputPlaceholder);
342         nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild);
343         nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType);
344         nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild);
345         nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType);
346         nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter);
347         nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine);
348         nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType);
349         nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus);
350         nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover);
351         nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate);
352         nameToPseudoType->set(innerSpinButton.impl(), CSSSelector::PseudoInnerSpinButton);
353         nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink);
354         nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang);
355         nameToPseudoType->set(mediaControlsPanel.impl(), CSSSelector::PseudoMediaControlsPanel);
356         nameToPseudoType->set(mediaControlsMuteButton.impl(), CSSSelector::PseudoMediaControlsMuteButton);
357         nameToPseudoType->set(mediaControlsPlayButton.impl(), CSSSelector::PseudoMediaControlsPlayButton);
358         nameToPseudoType->set(mediaControlsCurrentTimeDisplay.impl(), CSSSelector::PseudoMediaControlsCurrentTimeDisplay);
359         nameToPseudoType->set(mediaControlsTimeRemainingDisplay.impl(), CSSSelector::PseudoMediaControlsTimeRemainingDisplay);
360         nameToPseudoType->set(mediaControlsTimeline.impl(), CSSSelector::PseudoMediaControlsTimeline);
361         nameToPseudoType->set(mediaControlsVolumeSlider.impl(), CSSSelector::PseudoMediaControlsVolumeSlider);
362         nameToPseudoType->set(mediaControlsSeekBackButton.impl(), CSSSelector::PseudoMediaControlsSeekBackButton);
363         nameToPseudoType->set(mediaControlsSeekForwardButton.impl(), CSSSelector::PseudoMediaControlsSeekForwardButton);
364         nameToPseudoType->set(mediaControlsRewindButton.impl(), CSSSelector::PseudoMediaControlsRewindButton);
365         nameToPseudoType->set(mediaControlsReturnToRealtimeButton.impl(), CSSSelector::PseudoMediaControlsReturnToRealtimeButton);
366         nameToPseudoType->set(mediaControlsToggleClosedCaptionsButton.impl(), CSSSelector::PseudoMediaControlsToggleClosedCaptions);
367         nameToPseudoType->set(mediaControlsStatusDisplay.impl(), CSSSelector::PseudoMediaControlsStatusDisplay);
368         nameToPseudoType->set(mediaControlsFullscreenButton.impl(), CSSSelector::PseudoMediaControlsFullscreenButton);
369         nameToPseudoType->set(mediaControlsTimelineContainer.impl(), CSSSelector::PseudoMediaControlsTimelineContainer);
370         nameToPseudoType->set(mediaControlsVolumeSliderContainer.impl(), CSSSelector::PseudoMediaControlsVolumeSliderContainer);
371         nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot);
372         nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild);
373         nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType);
374         nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild);
375         nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType);
376         nameToPseudoType->set(outerSpinButton.impl(), CSSSelector::PseudoOuterSpinButton);
377 #if ENABLE(PROGRESS_TAG)
378         nameToPseudoType->set(progressBarValue.impl(), CSSSelector::PseudoProgressBarValue);
379 #endif
380         nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot);
381         nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive);
382         nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement);
383         nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement);
384         nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart);
385         nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd);
386         nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal);
387         nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical);
388         nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton);
389         nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton);
390         nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton);
391         nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional);
392         nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired);
393         nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer);
394         nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar);
395         nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton);
396         nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner);
397         nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb);
398         nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack);
399         nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece);
400         nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent);
401         nameToPseudoType->set(searchCancelButton.impl(), CSSSelector::PseudoSearchCancelButton);
402         nameToPseudoType->set(searchDecoration.impl(), CSSSelector::PseudoSearchDecoration);
403         nameToPseudoType->set(searchResultsDecoration.impl(), CSSSelector::PseudoSearchResultsDecoration);
404         nameToPseudoType->set(searchResultsButton.impl(), CSSSelector::PseudoSearchResultsButton);
405         nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection);
406         nameToPseudoType->set(sliderThumb.impl(), CSSSelector::PseudoSliderThumb);
407         nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget);
408         nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited);
409         nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage);
410         nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage);
411         nameToPseudoType->set(rightPage.impl(), CSSSelector::PseudoRightPage);
412     }
413     return nameToPseudoType;
414 }
415
416 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
417 {
418     if (name.isNull())
419         return PseudoUnknown;
420     HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap();
421     HashMap<AtomicStringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl());
422     return slot == nameToPseudoType->end() ? PseudoUnknown : slot->second;
423 }
424
425 void CSSSelector::extractPseudoType() const
426 {
427     if (m_match != PseudoClass && m_match != PseudoElement)
428         return;
429
430     m_pseudoType = parsePseudoType(m_value);
431
432     bool element = false; // pseudo-element
433     bool compat = false; // single colon compatbility mode
434
435     switch (m_pseudoType) {
436     case PseudoAfter:
437     case PseudoBefore:
438     case PseudoFirstLetter:
439     case PseudoFirstLine:
440         compat = true;
441     case PseudoFileUploadButton:
442     case PseudoInputListButton:
443     case PseudoInputPlaceholder:
444     case PseudoInnerSpinButton:
445     case PseudoMediaControlsPanel:
446     case PseudoMediaControlsMuteButton:
447     case PseudoMediaControlsPlayButton:
448     case PseudoMediaControlsCurrentTimeDisplay:
449     case PseudoMediaControlsTimeRemainingDisplay:
450     case PseudoMediaControlsTimeline:
451     case PseudoMediaControlsVolumeSlider:
452     case PseudoMediaControlsSeekBackButton:
453     case PseudoMediaControlsSeekForwardButton:
454     case PseudoMediaControlsRewindButton:
455     case PseudoMediaControlsReturnToRealtimeButton:
456     case PseudoMediaControlsToggleClosedCaptions:
457     case PseudoMediaControlsStatusDisplay:
458     case PseudoMediaControlsFullscreenButton:
459     case PseudoMediaControlsTimelineContainer:
460     case PseudoMediaControlsVolumeSliderContainer:
461     case PseudoOuterSpinButton:
462     case PseudoProgressBarValue:
463     case PseudoResizer:
464     case PseudoScrollbar:
465     case PseudoScrollbarCorner:
466     case PseudoScrollbarButton:
467     case PseudoScrollbarThumb:
468     case PseudoScrollbarTrack:
469     case PseudoScrollbarTrackPiece:
470     case PseudoSearchCancelButton:
471     case PseudoSearchDecoration:
472     case PseudoSearchResultsDecoration:
473     case PseudoSearchResultsButton:
474     case PseudoSelection:
475     case PseudoSliderThumb:
476         element = true;
477         break;
478     case PseudoUnknown:
479     case PseudoEmpty:
480     case PseudoFirstChild:
481     case PseudoFirstOfType:
482     case PseudoLastChild:
483     case PseudoLastOfType:
484     case PseudoOnlyChild:
485     case PseudoOnlyOfType:
486     case PseudoNthChild:
487     case PseudoNthOfType:
488     case PseudoNthLastChild:
489     case PseudoNthLastOfType:
490     case PseudoLink:
491     case PseudoVisited:
492     case PseudoAnyLink:
493     case PseudoAutofill:
494     case PseudoHover:
495     case PseudoDrag:
496     case PseudoFocus:
497     case PseudoActive:
498     case PseudoChecked:
499     case PseudoEnabled:
500     case PseudoFullPageMedia:
501     case PseudoDefault:
502     case PseudoDisabled:
503     case PseudoOptional:
504     case PseudoRequired:
505     case PseudoReadOnly:
506     case PseudoReadWrite:
507     case PseudoValid:
508     case PseudoInvalid:
509     case PseudoIndeterminate:
510     case PseudoTarget:
511     case PseudoLang:
512     case PseudoNot:
513     case PseudoRoot:
514     case PseudoScrollbarBack:
515     case PseudoScrollbarForward:
516     case PseudoWindowInactive:
517     case PseudoCornerPresent:
518     case PseudoDecrement:
519     case PseudoIncrement:
520     case PseudoHorizontal:
521     case PseudoVertical:
522     case PseudoStart:
523     case PseudoEnd:
524     case PseudoDoubleButton:
525     case PseudoSingleButton:
526     case PseudoNoButton:
527     case PseudoNotParsed:
528     case PseudoFirstPage:
529     case PseudoLeftPage:
530     case PseudoRightPage:
531         break;
532     }
533
534     if (m_match == PseudoClass && element) {
535         if (!compat)
536             m_pseudoType = PseudoUnknown;
537         else
538            m_match = PseudoElement;
539     } else if (m_match == PseudoElement && !element)
540         m_pseudoType = PseudoUnknown;
541 }
542
543 bool CSSSelector::operator==(const CSSSelector& other)
544 {
545     const CSSSelector* sel1 = this;
546     const CSSSelector* sel2 = &other;
547
548     while (sel1 && sel2) {
549         if (sel1->m_tag != sel2->m_tag || sel1->attribute() != sel2->attribute() ||
550              sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match ||
551              sel1->m_value != sel2->m_value ||
552              sel1->pseudoType() != sel2->pseudoType() ||
553              sel1->argument() != sel2->argument())
554             return false;
555         sel1 = sel1->tagHistory();
556         sel2 = sel2->tagHistory();
557     }
558
559     if (sel1 || sel2)
560         return false;
561
562     return true;
563 }
564
565 String CSSSelector::selectorText() const
566 {
567     String str = "";
568
569     const AtomicString& prefix = m_tag.prefix();
570     const AtomicString& localName = m_tag.localName();
571     if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
572         if (prefix.isNull())
573             str = localName;
574         else
575             str = prefix + "|" + localName;
576     }
577
578     const CSSSelector* cs = this;
579     while (true) {
580         if (cs->m_match == CSSSelector::Id) {
581             str += "#";
582             str += cs->m_value;
583         } else if (cs->m_match == CSSSelector::Class) {
584             str += ".";
585             str += cs->m_value;
586         } else if (cs->m_match == CSSSelector::PseudoClass) {
587             str += ":";
588             str += cs->m_value;
589             if (cs->pseudoType() == PseudoNot) {
590                 if (CSSSelector* subSel = cs->simpleSelector())
591                     str += subSel->selectorText();
592                 str += ")";
593             } else if (cs->pseudoType() == PseudoLang
594                     || cs->pseudoType() == PseudoNthChild
595                     || cs->pseudoType() == PseudoNthLastChild
596                     || cs->pseudoType() == PseudoNthOfType
597                     || cs->pseudoType() == PseudoNthLastOfType) {
598                 str += cs->argument();
599                 str += ")";
600             }
601         } else if (cs->m_match == CSSSelector::PseudoElement) {
602             str += "::";
603             str += cs->m_value;
604         } else if (cs->hasAttribute()) {
605             str += "[";
606             const AtomicString& prefix = cs->attribute().prefix();
607             if (!prefix.isNull())
608                 str += prefix + "|";
609             str += cs->attribute().localName();
610             switch (cs->m_match) {
611                 case CSSSelector::Exact:
612                     str += "=";
613                     break;
614                 case CSSSelector::Set:
615                     // set has no operator or value, just the attrName
616                     str += "]";
617                     break;
618                 case CSSSelector::List:
619                     str += "~=";
620                     break;
621                 case CSSSelector::Hyphen:
622                     str += "|=";
623                     break;
624                 case CSSSelector::Begin:
625                     str += "^=";
626                     break;
627                 case CSSSelector::End:
628                     str += "$=";
629                     break;
630                 case CSSSelector::Contain:
631                     str += "*=";
632                     break;
633                 default:
634                     break;
635             }
636             if (cs->m_match != CSSSelector::Set) {
637                 str += "\"";
638                 str += cs->m_value;
639                 str += "\"]";
640             }
641         }
642         if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
643             break;
644         cs = cs->tagHistory();
645     }
646
647     if (CSSSelector* tagHistory = cs->tagHistory()) {
648         String tagHistoryText = tagHistory->selectorText();
649         if (cs->relation() == CSSSelector::DirectAdjacent)
650             str = tagHistoryText + " + " + str;
651         else if (cs->relation() == CSSSelector::IndirectAdjacent)
652             str = tagHistoryText + " ~ " + str;
653         else if (cs->relation() == CSSSelector::Child)
654             str = tagHistoryText + " > " + str;
655         else
656             // Descendant
657             str = tagHistoryText + " " + str;
658     }
659
660     return str;
661 }
662     
663 void CSSSelector::setTagHistory(CSSSelector* tagHistory) 
664
665     if (m_hasRareData) 
666         m_data.m_rareData->m_tagHistory.set(tagHistory); 
667     else 
668         m_data.m_tagHistory = tagHistory; 
669 }
670
671 const QualifiedName& CSSSelector::attribute() const
672
673     switch (m_match) {
674     case Id:
675         return idAttr;
676     case Class:
677         return classAttr;
678     default:
679         return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName();
680     }
681 }
682
683 void CSSSelector::setAttribute(const QualifiedName& value) 
684
685     createRareData(); 
686     m_data.m_rareData->m_attribute = value; 
687 }
688     
689 void CSSSelector::setArgument(const AtomicString& value) 
690
691     createRareData(); 
692     m_data.m_rareData->m_argument = value; 
693 }
694
695 void CSSSelector::setSimpleSelector(CSSSelector* value)
696 {
697     createRareData(); 
698     m_data.m_rareData->m_simpleSelector.set(value); 
699 }
700
701 bool CSSSelector::parseNth()
702 {
703     if (!m_hasRareData)
704         return false;
705     if (m_parsedNth)
706         return true;
707     m_parsedNth = m_data.m_rareData->parseNth();
708     return m_parsedNth;
709 }
710
711 bool CSSSelector::matchNth(int count)
712 {
713     ASSERT(m_hasRareData);
714     return m_data.m_rareData->matchNth(count);
715 }
716
717 bool CSSSelector::isSimple() const
718 {
719     if (simpleSelector() || tagHistory() || matchesPseudoElement())
720         return false;
721
722     int numConditions = 0;
723
724     // hasTag() cannot be be used here because namespace may not be nullAtom.
725     // Example:
726     //     @namespace "http://www.w3.org/2000/svg";
727     //     svg:not(:root) { ...
728     if (m_tag != starAtom)
729         numConditions++;
730
731     if (m_match == Id || m_match == Class || m_match == PseudoClass)
732         numConditions++;
733
734     if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
735         numConditions++;
736
737     // numConditions is 0 for a universal selector.
738     // numConditions is 1 for other simple selectors.
739     return numConditions <= 1;
740 }
741
742 // a helper function for parsing nth-arguments
743 bool CSSSelector::RareData::parseNth()
744 {
745     String argument = m_argument.lower();
746     
747     if (argument.isEmpty())
748         return false;
749     
750     m_a = 0;
751     m_b = 0;
752     if (argument == "odd") {
753         m_a = 2;
754         m_b = 1;
755     } else if (argument == "even") {
756         m_a = 2;
757         m_b = 0;
758     } else {
759         int n = argument.find('n');
760         if (n != -1) {
761             if (argument[0] == '-') {
762                 if (n == 1)
763                     m_a = -1; // -n == -1n
764                 else
765                     m_a = argument.substring(0, n).toInt();
766             } else if (!n)
767                 m_a = 1; // n == 1n
768             else
769                 m_a = argument.substring(0, n).toInt();
770             
771             int p = argument.find('+', n);
772             if (p != -1)
773                 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
774             else {
775                 p = argument.find('-', n);
776                 if (p != -1)
777                     m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
778             }
779         } else
780             m_b = argument.toInt();
781     }
782     return true;
783 }
784
785 // a helper function for checking nth-arguments
786 bool CSSSelector::RareData::matchNth(int count)
787 {
788     if (!m_a)
789         return count == m_b;
790     else if (m_a > 0) {
791         if (count < m_b)
792             return false;
793         return (count - m_b) % m_a == 0;
794     } else {
795         if (count > m_b)
796             return false;
797         return (m_b - count) % (-m_a) == 0;
798     }
799 }
800     
801 } // namespace WebCore