Reviewed by Geoff Garen.
[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         break;
529     case PseudoFirstPage:
530     case PseudoLeftPage:
531     case PseudoRightPage:
532         // FIXME: These should only be allowed in @page rules. Disabled them altogether until that's implemented correctly.
533         m_pseudoType = PseudoUnknown;
534         return;
535     }
536
537     if (m_match == PseudoClass && element) {
538         if (!compat)
539             m_pseudoType = PseudoUnknown;
540         else
541            m_match = PseudoElement;
542     } else if (m_match == PseudoElement && !element)
543         m_pseudoType = PseudoUnknown;
544 }
545
546 bool CSSSelector::operator==(const CSSSelector& other)
547 {
548     const CSSSelector* sel1 = this;
549     const CSSSelector* sel2 = &other;
550
551     while (sel1 && sel2) {
552         if (sel1->m_tag != sel2->m_tag || sel1->attribute() != sel2->attribute() ||
553              sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match ||
554              sel1->m_value != sel2->m_value ||
555              sel1->pseudoType() != sel2->pseudoType() ||
556              sel1->argument() != sel2->argument())
557             return false;
558         sel1 = sel1->tagHistory();
559         sel2 = sel2->tagHistory();
560     }
561
562     if (sel1 || sel2)
563         return false;
564
565     return true;
566 }
567
568 String CSSSelector::selectorText() const
569 {
570     String str = "";
571
572     const AtomicString& prefix = m_tag.prefix();
573     const AtomicString& localName = m_tag.localName();
574     if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
575         if (prefix.isNull())
576             str = localName;
577         else
578             str = prefix + "|" + localName;
579     }
580
581     const CSSSelector* cs = this;
582     while (true) {
583         if (cs->m_match == CSSSelector::Id) {
584             str += "#";
585             str += cs->m_value;
586         } else if (cs->m_match == CSSSelector::Class) {
587             str += ".";
588             str += cs->m_value;
589         } else if (cs->m_match == CSSSelector::PseudoClass) {
590             str += ":";
591             str += cs->m_value;
592             if (cs->pseudoType() == PseudoNot) {
593                 if (CSSSelector* subSel = cs->simpleSelector())
594                     str += subSel->selectorText();
595                 str += ")";
596             } else if (cs->pseudoType() == PseudoLang
597                     || cs->pseudoType() == PseudoNthChild
598                     || cs->pseudoType() == PseudoNthLastChild
599                     || cs->pseudoType() == PseudoNthOfType
600                     || cs->pseudoType() == PseudoNthLastOfType) {
601                 str += cs->argument();
602                 str += ")";
603             }
604         } else if (cs->m_match == CSSSelector::PseudoElement) {
605             str += "::";
606             str += cs->m_value;
607         } else if (cs->hasAttribute()) {
608             str += "[";
609             const AtomicString& prefix = cs->attribute().prefix();
610             if (!prefix.isNull())
611                 str += prefix + "|";
612             str += cs->attribute().localName();
613             switch (cs->m_match) {
614                 case CSSSelector::Exact:
615                     str += "=";
616                     break;
617                 case CSSSelector::Set:
618                     // set has no operator or value, just the attrName
619                     str += "]";
620                     break;
621                 case CSSSelector::List:
622                     str += "~=";
623                     break;
624                 case CSSSelector::Hyphen:
625                     str += "|=";
626                     break;
627                 case CSSSelector::Begin:
628                     str += "^=";
629                     break;
630                 case CSSSelector::End:
631                     str += "$=";
632                     break;
633                 case CSSSelector::Contain:
634                     str += "*=";
635                     break;
636                 default:
637                     break;
638             }
639             if (cs->m_match != CSSSelector::Set) {
640                 str += "\"";
641                 str += cs->m_value;
642                 str += "\"]";
643             }
644         }
645         if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
646             break;
647         cs = cs->tagHistory();
648     }
649
650     if (CSSSelector* tagHistory = cs->tagHistory()) {
651         String tagHistoryText = tagHistory->selectorText();
652         if (cs->relation() == CSSSelector::DirectAdjacent)
653             str = tagHistoryText + " + " + str;
654         else if (cs->relation() == CSSSelector::IndirectAdjacent)
655             str = tagHistoryText + " ~ " + str;
656         else if (cs->relation() == CSSSelector::Child)
657             str = tagHistoryText + " > " + str;
658         else
659             // Descendant
660             str = tagHistoryText + " " + str;
661     }
662
663     return str;
664 }
665     
666 void CSSSelector::setTagHistory(CSSSelector* tagHistory) 
667
668     if (m_hasRareData) 
669         m_data.m_rareData->m_tagHistory.set(tagHistory); 
670     else 
671         m_data.m_tagHistory = tagHistory; 
672 }
673
674 const QualifiedName& CSSSelector::attribute() const
675
676     switch (m_match) {
677     case Id:
678         return idAttr;
679     case Class:
680         return classAttr;
681     default:
682         return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName();
683     }
684 }
685
686 void CSSSelector::setAttribute(const QualifiedName& value) 
687
688     createRareData(); 
689     m_data.m_rareData->m_attribute = value; 
690 }
691     
692 void CSSSelector::setArgument(const AtomicString& value) 
693
694     createRareData(); 
695     m_data.m_rareData->m_argument = value; 
696 }
697
698 void CSSSelector::setSimpleSelector(CSSSelector* value)
699 {
700     createRareData(); 
701     m_data.m_rareData->m_simpleSelector.set(value); 
702 }
703
704 bool CSSSelector::parseNth()
705 {
706     if (!m_hasRareData)
707         return false;
708     if (m_parsedNth)
709         return true;
710     m_parsedNth = m_data.m_rareData->parseNth();
711     return m_parsedNth;
712 }
713
714 bool CSSSelector::matchNth(int count)
715 {
716     ASSERT(m_hasRareData);
717     return m_data.m_rareData->matchNth(count);
718 }
719
720 bool CSSSelector::isSimple() const
721 {
722     if (simpleSelector() || tagHistory() || matchesPseudoElement())
723         return false;
724
725     int numConditions = 0;
726
727     // hasTag() cannot be be used here because namespace may not be nullAtom.
728     // Example:
729     //     @namespace "http://www.w3.org/2000/svg";
730     //     svg:not(:root) { ...
731     if (m_tag != starAtom)
732         numConditions++;
733
734     if (m_match == Id || m_match == Class || m_match == PseudoClass)
735         numConditions++;
736
737     if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
738         numConditions++;
739
740     // numConditions is 0 for a universal selector.
741     // numConditions is 1 for other simple selectors.
742     return numConditions <= 1;
743 }
744
745 // a helper function for parsing nth-arguments
746 bool CSSSelector::RareData::parseNth()
747 {
748     String argument = m_argument.lower();
749     
750     if (argument.isEmpty())
751         return false;
752     
753     m_a = 0;
754     m_b = 0;
755     if (argument == "odd") {
756         m_a = 2;
757         m_b = 1;
758     } else if (argument == "even") {
759         m_a = 2;
760         m_b = 0;
761     } else {
762         int n = argument.find('n');
763         if (n != -1) {
764             if (argument[0] == '-') {
765                 if (n == 1)
766                     m_a = -1; // -n == -1n
767                 else
768                     m_a = argument.substring(0, n).toInt();
769             } else if (!n)
770                 m_a = 1; // n == 1n
771             else
772                 m_a = argument.substring(0, n).toInt();
773             
774             int p = argument.find('+', n);
775             if (p != -1)
776                 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
777             else {
778                 p = argument.find('-', n);
779                 if (p != -1)
780                     m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
781             }
782         } else
783             m_b = argument.toInt();
784     }
785     return true;
786 }
787
788 // a helper function for checking nth-arguments
789 bool CSSSelector::RareData::matchNth(int count)
790 {
791     if (!m_a)
792         return count == m_b;
793     else if (m_a > 0) {
794         if (count < m_b)
795             return false;
796         return (count - m_b) % m_a == 0;
797     } else {
798         if (count > m_b)
799             return false;
800         return (m_b - count) % (-m_a) == 0;
801     }
802 }
803     
804 } // namespace WebCore