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