initial import
[vuplus_webkit] / Source / 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 "CSSSelectorList.h"
31 #include "HTMLNames.h"
32 #include <wtf/Assertions.h>
33 #include <wtf/HashMap.h>
34 #include <wtf/StdLibExtras.h>
35 #include <wtf/Vector.h>
36
37 namespace WebCore {
38
39 using namespace HTMLNames;
40     
41 void CSSSelector::createRareData()
42 {
43     if (m_hasRareData) 
44         return;
45     // Move the value to the rare data stucture.
46     m_data.m_rareData = new RareData(adoptRef(m_data.m_value));
47     m_hasRareData = true;
48 }
49
50 unsigned CSSSelector::specificity() const
51 {
52     // make sure the result doesn't overflow
53     static const unsigned maxValueMask = 0xffffff;
54     unsigned total = 0;
55     for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
56         if (selector->m_isForPage)
57             return (total + selector->specificityForPage()) & maxValueMask;
58         total = (total + selector->specificityForOneSelector()) & maxValueMask;
59     }
60     return total;
61 }
62
63 inline unsigned CSSSelector::specificityForOneSelector() const
64 {
65     // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
66     // isn't quite correct.
67     unsigned s = (m_tag.localName() == starAtom ? 0 : 1);
68     switch (m_match) {
69     case Id:
70         s += 0x10000;
71         break;
72     case Exact:
73     case Class:
74     case Set:
75     case List:
76     case Hyphen:
77     case PseudoClass:
78     case PseudoElement:
79     case Contain:
80     case Begin:
81     case End:
82         // FIXME: PsuedoAny should base the specificity on the sub-selectors.
83         // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
84         if (pseudoType() == PseudoNot) {
85             ASSERT(selectorList());
86             s += selectorList()->first()->specificityForOneSelector();
87         } else
88             s += 0x100;
89     case None:
90         break;
91     }
92     return s;
93 }
94
95 unsigned CSSSelector::specificityForPage() const
96 {
97     // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
98     unsigned s = (m_tag.localName() == starAtom ? 0 : 4);
99
100     switch (pseudoType()) {
101     case PseudoFirstPage:
102         s += 2;
103         break;
104     case PseudoLeftPage:
105     case PseudoRightPage:
106         s += 1;
107         break;
108     case PseudoNotParsed:
109         break;
110     default:
111         ASSERT_NOT_REACHED();
112     }
113     return s;
114 }
115
116 PseudoId CSSSelector::pseudoId(PseudoType type)
117 {
118     switch (type) {
119     case PseudoFirstLine:
120         return FIRST_LINE;
121     case PseudoFirstLetter:
122         return FIRST_LETTER;
123     case PseudoSelection:
124         return SELECTION;
125     case PseudoBefore:
126         return BEFORE;
127     case PseudoAfter:
128         return AFTER;
129     case PseudoScrollbar:
130         return SCROLLBAR;
131     case PseudoScrollbarButton:
132         return SCROLLBAR_BUTTON;
133     case PseudoScrollbarCorner:
134         return SCROLLBAR_CORNER;
135     case PseudoScrollbarThumb:
136         return SCROLLBAR_THUMB;
137     case PseudoScrollbarTrack:
138         return SCROLLBAR_TRACK;
139     case PseudoScrollbarTrackPiece:
140         return SCROLLBAR_TRACK_PIECE;
141     case PseudoResizer:
142         return RESIZER;
143 #if ENABLE(FULLSCREEN_API)
144     case PseudoFullScreen:
145         return FULL_SCREEN;
146     case PseudoFullScreenDocument:
147         return FULL_SCREEN_DOCUMENT;
148     case PseudoFullScreenAncestor:
149         return FULL_SCREEN_ANCESTOR;
150     case PseudoAnimatingFullScreenTransition:
151         return ANIMATING_FULL_SCREEN_TRANSITION;
152 #endif
153             
154     case PseudoInputListButton:
155 #if ENABLE(DATALIST)
156         return INPUT_LIST_BUTTON;
157 #endif
158     case PseudoUnknown:
159     case PseudoEmpty:
160     case PseudoFirstChild:
161     case PseudoFirstOfType:
162     case PseudoLastChild:
163     case PseudoLastOfType:
164     case PseudoOnlyChild:
165     case PseudoOnlyOfType:
166     case PseudoNthChild:
167     case PseudoNthOfType:
168     case PseudoNthLastChild:
169     case PseudoNthLastOfType:
170     case PseudoLink:
171     case PseudoVisited:
172     case PseudoAny:
173     case PseudoAnyLink:
174     case PseudoAutofill:
175     case PseudoHover:
176     case PseudoDrag:
177     case PseudoFocus:
178     case PseudoActive:
179     case PseudoChecked:
180     case PseudoEnabled:
181     case PseudoFullPageMedia:
182     case PseudoDefault:
183     case PseudoDisabled:
184     case PseudoOptional:
185     case PseudoRequired:
186     case PseudoReadOnly:
187     case PseudoReadWrite:
188     case PseudoValid:
189     case PseudoInvalid:
190     case PseudoIndeterminate:
191     case PseudoTarget:
192     case PseudoLang:
193     case PseudoNot:
194     case PseudoRoot:
195     case PseudoScrollbarBack:
196     case PseudoScrollbarForward:
197     case PseudoWindowInactive:
198     case PseudoCornerPresent:
199     case PseudoDecrement:
200     case PseudoIncrement:
201     case PseudoHorizontal:
202     case PseudoVertical:
203     case PseudoStart:
204     case PseudoEnd:
205     case PseudoDoubleButton:
206     case PseudoSingleButton:
207     case PseudoNoButton:
208     case PseudoFirstPage:
209     case PseudoLeftPage:
210     case PseudoRightPage:
211     case PseudoInRange:
212     case PseudoOutOfRange:
213         return NOPSEUDO;
214     case PseudoNotParsed:
215         ASSERT_NOT_REACHED();
216         return NOPSEUDO;
217     }
218
219     ASSERT_NOT_REACHED();
220     return NOPSEUDO;
221 }
222
223 static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
224 {
225     DEFINE_STATIC_LOCAL(AtomicString, active, ("active"));
226     DEFINE_STATIC_LOCAL(AtomicString, after, ("after"));
227     DEFINE_STATIC_LOCAL(AtomicString, any, ("-webkit-any("));
228     DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link"));
229     DEFINE_STATIC_LOCAL(AtomicString, autofill, ("-webkit-autofill"));
230     DEFINE_STATIC_LOCAL(AtomicString, before, ("before"));
231     DEFINE_STATIC_LOCAL(AtomicString, checked, ("checked"));
232     DEFINE_STATIC_LOCAL(AtomicString, defaultString, ("default"));
233     DEFINE_STATIC_LOCAL(AtomicString, disabled, ("disabled"));
234     DEFINE_STATIC_LOCAL(AtomicString, readOnly, ("read-only"));
235     DEFINE_STATIC_LOCAL(AtomicString, readWrite, ("read-write"));
236     DEFINE_STATIC_LOCAL(AtomicString, valid, ("valid"));
237     DEFINE_STATIC_LOCAL(AtomicString, invalid, ("invalid"));
238     DEFINE_STATIC_LOCAL(AtomicString, drag, ("-webkit-drag"));
239     DEFINE_STATIC_LOCAL(AtomicString, dragAlias, ("-khtml-drag")); // was documented with this name in Apple documentation, so keep an alia
240     DEFINE_STATIC_LOCAL(AtomicString, empty, ("empty"));
241     DEFINE_STATIC_LOCAL(AtomicString, enabled, ("enabled"));
242     DEFINE_STATIC_LOCAL(AtomicString, firstChild, ("first-child"));
243     DEFINE_STATIC_LOCAL(AtomicString, firstLetter, ("first-letter"));
244     DEFINE_STATIC_LOCAL(AtomicString, firstLine, ("first-line"));
245     DEFINE_STATIC_LOCAL(AtomicString, firstOfType, ("first-of-type"));
246     DEFINE_STATIC_LOCAL(AtomicString, fullPageMedia, ("-webkit-full-page-media"));
247     DEFINE_STATIC_LOCAL(AtomicString, nthChild, ("nth-child("));
248     DEFINE_STATIC_LOCAL(AtomicString, nthOfType, ("nth-of-type("));
249     DEFINE_STATIC_LOCAL(AtomicString, nthLastChild, ("nth-last-child("));
250     DEFINE_STATIC_LOCAL(AtomicString, nthLastOfType, ("nth-last-of-type("));
251     DEFINE_STATIC_LOCAL(AtomicString, focus, ("focus"));
252     DEFINE_STATIC_LOCAL(AtomicString, hover, ("hover"));
253     DEFINE_STATIC_LOCAL(AtomicString, indeterminate, ("indeterminate"));
254 #if ENABLE(DATALIST)
255     DEFINE_STATIC_LOCAL(AtomicString, inputListButton, ("-webkit-input-list-button"));
256 #endif
257     DEFINE_STATIC_LOCAL(AtomicString, lastChild, ("last-child"));
258     DEFINE_STATIC_LOCAL(AtomicString, lastOfType, ("last-of-type"));
259     DEFINE_STATIC_LOCAL(AtomicString, link, ("link"));
260     DEFINE_STATIC_LOCAL(AtomicString, lang, ("lang("));
261     DEFINE_STATIC_LOCAL(AtomicString, notStr, ("not("));
262     DEFINE_STATIC_LOCAL(AtomicString, onlyChild, ("only-child"));
263     DEFINE_STATIC_LOCAL(AtomicString, onlyOfType, ("only-of-type"));
264     DEFINE_STATIC_LOCAL(AtomicString, optional, ("optional"));
265     DEFINE_STATIC_LOCAL(AtomicString, required, ("required"));
266     DEFINE_STATIC_LOCAL(AtomicString, resizer, ("-webkit-resizer"));
267     DEFINE_STATIC_LOCAL(AtomicString, root, ("root"));
268     DEFINE_STATIC_LOCAL(AtomicString, scrollbar, ("-webkit-scrollbar"));
269     DEFINE_STATIC_LOCAL(AtomicString, scrollbarButton, ("-webkit-scrollbar-button"));
270     DEFINE_STATIC_LOCAL(AtomicString, scrollbarCorner, ("-webkit-scrollbar-corner"));
271     DEFINE_STATIC_LOCAL(AtomicString, scrollbarThumb, ("-webkit-scrollbar-thumb"));
272     DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrack, ("-webkit-scrollbar-track"));
273     DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrackPiece, ("-webkit-scrollbar-track-piece"));
274     DEFINE_STATIC_LOCAL(AtomicString, selection, ("selection"));
275     DEFINE_STATIC_LOCAL(AtomicString, target, ("target"));
276     DEFINE_STATIC_LOCAL(AtomicString, visited, ("visited"));
277     DEFINE_STATIC_LOCAL(AtomicString, windowInactive, ("window-inactive"));
278     DEFINE_STATIC_LOCAL(AtomicString, decrement, ("decrement"));
279     DEFINE_STATIC_LOCAL(AtomicString, increment, ("increment"));
280     DEFINE_STATIC_LOCAL(AtomicString, start, ("start"));
281     DEFINE_STATIC_LOCAL(AtomicString, end, ("end"));
282     DEFINE_STATIC_LOCAL(AtomicString, horizontal, ("horizontal"));
283     DEFINE_STATIC_LOCAL(AtomicString, vertical, ("vertical"));
284     DEFINE_STATIC_LOCAL(AtomicString, doubleButton, ("double-button"));
285     DEFINE_STATIC_LOCAL(AtomicString, singleButton, ("single-button"));
286     DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button"));
287     DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present"));
288     // Paged Media pseudo-classes
289     DEFINE_STATIC_LOCAL(AtomicString, firstPage, ("first"));
290     DEFINE_STATIC_LOCAL(AtomicString, leftPage, ("left"));
291     DEFINE_STATIC_LOCAL(AtomicString, rightPage, ("right"));
292 #if ENABLE(FULLSCREEN_API)
293     DEFINE_STATIC_LOCAL(AtomicString, fullScreen, ("-webkit-full-screen"));
294     DEFINE_STATIC_LOCAL(AtomicString, fullScreenDocument, ("-webkit-full-screen-document"));
295     DEFINE_STATIC_LOCAL(AtomicString, fullScreenAncestor, ("-webkit-full-screen-ancestor"));
296     DEFINE_STATIC_LOCAL(AtomicString, animatingFullScreenTransition, ("-webkit-animating-full-screen-transition"));
297 #endif
298     DEFINE_STATIC_LOCAL(AtomicString, inRange, ("in-range"));
299     DEFINE_STATIC_LOCAL(AtomicString, outOfRange, ("out-of-range"));
300
301     static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0;
302     if (!nameToPseudoType) {
303         nameToPseudoType = new HashMap<AtomicStringImpl*, CSSSelector::PseudoType>;
304         nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive);
305         nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter);
306         nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink);
307         nameToPseudoType->set(any.impl(), CSSSelector::PseudoAny);
308         nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill);
309         nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore);
310         nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked);
311         nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault);
312         nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled);
313         nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly);
314         nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite);
315         nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid);
316         nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid);
317         nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag);
318         nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag);
319         nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled);
320         nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty);
321         nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild);
322         nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia);
323 #if ENABLE(DATALIST)
324         nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton);
325 #endif
326         nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild);
327         nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType);
328         nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild);
329         nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType);
330         nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter);
331         nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine);
332         nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType);
333         nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus);
334         nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover);
335         nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate);
336         nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink);
337         nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang);
338         nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot);
339         nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild);
340         nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType);
341         nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild);
342         nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType);
343         nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot);
344         nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive);
345         nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement);
346         nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement);
347         nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart);
348         nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd);
349         nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal);
350         nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical);
351         nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton);
352         nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton);
353         nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton);
354         nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional);
355         nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired);
356         nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer);
357         nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar);
358         nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton);
359         nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner);
360         nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb);
361         nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack);
362         nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece);
363         nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent);
364         nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection);
365         nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget);
366         nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited);
367         nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage);
368         nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage);
369         nameToPseudoType->set(rightPage.impl(), CSSSelector::PseudoRightPage);
370 #if ENABLE(FULLSCREEN_API)
371         nameToPseudoType->set(fullScreen.impl(), CSSSelector::PseudoFullScreen);
372         nameToPseudoType->set(fullScreenDocument.impl(), CSSSelector::PseudoFullScreenDocument);
373         nameToPseudoType->set(fullScreenAncestor.impl(), CSSSelector::PseudoFullScreenAncestor);
374         nameToPseudoType->set(animatingFullScreenTransition.impl(), CSSSelector::PseudoAnimatingFullScreenTransition);
375 #endif
376         nameToPseudoType->set(inRange.impl(), CSSSelector::PseudoInRange);
377         nameToPseudoType->set(outOfRange.impl(), CSSSelector::PseudoOutOfRange);
378     }
379     return nameToPseudoType;
380 }
381
382 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
383 {
384     if (name.isNull())
385         return PseudoUnknown;
386     HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap();
387     HashMap<AtomicStringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl());
388     return slot == nameToPseudoType->end() ? PseudoUnknown : slot->second;
389 }
390
391 bool CSSSelector::isUnknownPseudoType(const AtomicString& name)
392 {
393     return parsePseudoType(name) == PseudoUnknown;
394 }
395
396 void CSSSelector::extractPseudoType() const
397 {
398     if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass)
399         return;
400
401     m_pseudoType = parsePseudoType(value());
402
403     bool element = false; // pseudo-element
404     bool compat = false; // single colon compatbility mode
405     bool isPagePseudoClass = false; // Page pseudo-class
406
407     switch (m_pseudoType) {
408     case PseudoAfter:
409     case PseudoBefore:
410     case PseudoFirstLetter:
411     case PseudoFirstLine:
412         compat = true;
413     case PseudoInputListButton:
414     case PseudoResizer:
415     case PseudoScrollbar:
416     case PseudoScrollbarCorner:
417     case PseudoScrollbarButton:
418     case PseudoScrollbarThumb:
419     case PseudoScrollbarTrack:
420     case PseudoScrollbarTrackPiece:
421     case PseudoSelection:
422         element = true;
423         break;
424     case PseudoUnknown:
425     case PseudoEmpty:
426     case PseudoFirstChild:
427     case PseudoFirstOfType:
428     case PseudoLastChild:
429     case PseudoLastOfType:
430     case PseudoOnlyChild:
431     case PseudoOnlyOfType:
432     case PseudoNthChild:
433     case PseudoNthOfType:
434     case PseudoNthLastChild:
435     case PseudoNthLastOfType:
436     case PseudoLink:
437     case PseudoVisited:
438     case PseudoAny:
439     case PseudoAnyLink:
440     case PseudoAutofill:
441     case PseudoHover:
442     case PseudoDrag:
443     case PseudoFocus:
444     case PseudoActive:
445     case PseudoChecked:
446     case PseudoEnabled:
447     case PseudoFullPageMedia:
448     case PseudoDefault:
449     case PseudoDisabled:
450     case PseudoOptional:
451     case PseudoRequired:
452     case PseudoReadOnly:
453     case PseudoReadWrite:
454     case PseudoValid:
455     case PseudoInvalid:
456     case PseudoIndeterminate:
457     case PseudoTarget:
458     case PseudoLang:
459     case PseudoNot:
460     case PseudoRoot:
461     case PseudoScrollbarBack:
462     case PseudoScrollbarForward:
463     case PseudoWindowInactive:
464     case PseudoCornerPresent:
465     case PseudoDecrement:
466     case PseudoIncrement:
467     case PseudoHorizontal:
468     case PseudoVertical:
469     case PseudoStart:
470     case PseudoEnd:
471     case PseudoDoubleButton:
472     case PseudoSingleButton:
473     case PseudoNoButton:
474     case PseudoNotParsed:
475 #if ENABLE(FULLSCREEN_API)
476     case PseudoFullScreen:
477     case PseudoFullScreenDocument:
478     case PseudoFullScreenAncestor:
479     case PseudoAnimatingFullScreenTransition:
480 #endif
481     case PseudoInRange:
482     case PseudoOutOfRange:
483         break;
484     case PseudoFirstPage:
485     case PseudoLeftPage:
486     case PseudoRightPage:
487         isPagePseudoClass = true;
488         break;
489     }
490
491     bool matchPagePseudoClass = (m_match == PagePseudoClass);
492     if (matchPagePseudoClass != isPagePseudoClass)
493         m_pseudoType = PseudoUnknown;
494     else if (m_match == PseudoClass && element) {
495         if (!compat)
496             m_pseudoType = PseudoUnknown;
497         else
498            m_match = PseudoElement;
499     } else if (m_match == PseudoElement && !element)
500         m_pseudoType = PseudoUnknown;
501 }
502
503 bool CSSSelector::operator==(const CSSSelector& other)
504 {
505     const CSSSelector* sel1 = this;
506     const CSSSelector* sel2 = &other;
507
508     while (sel1 && sel2) {
509         if (sel1->m_tag != sel2->m_tag || sel1->attribute() != sel2->attribute() ||
510              sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match ||
511              sel1->value() != sel2->value() ||
512              sel1->pseudoType() != sel2->pseudoType() ||
513              sel1->argument() != sel2->argument())
514             return false;
515         sel1 = sel1->tagHistory();
516         sel2 = sel2->tagHistory();
517     }
518
519     if (sel1 || sel2)
520         return false;
521
522     return true;
523 }
524
525 String CSSSelector::selectorText() const
526 {
527     String str = "";
528
529     const AtomicString& prefix = m_tag.prefix();
530     const AtomicString& localName = m_tag.localName();
531     if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
532         if (prefix.isNull())
533             str = localName;
534         else {
535             str = prefix.string();
536             str.append("|");
537             str.append(localName);
538         }
539     }
540
541     const CSSSelector* cs = this;
542     while (true) {
543         if (cs->m_match == CSSSelector::Id) {
544             str += "#";
545             serializeIdentifier(cs->value(), str);
546         } else if (cs->m_match == CSSSelector::Class) {
547             str += ".";
548             serializeIdentifier(cs->value(), str);
549         } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) {
550             str += ":";
551             str += cs->value();
552
553             switch (cs->pseudoType()) {
554             case PseudoNot:
555                 ASSERT(cs->selectorList());
556                 str += cs->selectorList()->first()->selectorText();
557                 str += ")";
558                 break;
559             case PseudoLang:
560             case PseudoNthChild:
561             case PseudoNthLastChild:
562             case PseudoNthOfType:
563             case PseudoNthLastOfType:
564                 str += cs->argument();
565                 str += ")";
566                 break;
567             case PseudoAny: {
568                 CSSSelector* firstSubSelector = cs->selectorList()->first();
569                 for (CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) {
570                     if (subSelector != firstSubSelector)
571                         str += ",";
572                     str += subSelector->selectorText();
573                 }
574                 str += ")";
575                 break;
576             }
577             default:
578                 break;
579             }
580         } else if (cs->m_match == CSSSelector::PseudoElement) {
581             str += "::";
582             str += cs->value();
583         } else if (cs->hasAttribute()) {
584             str += "[";
585             const AtomicString& prefix = cs->attribute().prefix();
586             if (!prefix.isNull()) {
587                 str.append(prefix);
588                 str.append("|");
589             }
590             str += cs->attribute().localName();
591             switch (cs->m_match) {
592                 case CSSSelector::Exact:
593                     str += "=";
594                     break;
595                 case CSSSelector::Set:
596                     // set has no operator or value, just the attrName
597                     str += "]";
598                     break;
599                 case CSSSelector::List:
600                     str += "~=";
601                     break;
602                 case CSSSelector::Hyphen:
603                     str += "|=";
604                     break;
605                 case CSSSelector::Begin:
606                     str += "^=";
607                     break;
608                 case CSSSelector::End:
609                     str += "$=";
610                     break;
611                 case CSSSelector::Contain:
612                     str += "*=";
613                     break;
614                 default:
615                     break;
616             }
617             if (cs->m_match != CSSSelector::Set) {
618                 serializeString(cs->value(), str);
619                 str += "]";
620             }
621         }
622         if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
623             break;
624         cs = cs->tagHistory();
625     }
626
627     if (CSSSelector* tagHistory = cs->tagHistory()) {
628         String tagHistoryText = tagHistory->selectorText();
629         if (cs->relation() == CSSSelector::DirectAdjacent)
630             str = tagHistoryText + " + " + str;
631         else if (cs->relation() == CSSSelector::IndirectAdjacent)
632             str = tagHistoryText + " ~ " + str;
633         else if (cs->relation() == CSSSelector::Child)
634             str = tagHistoryText + " > " + str;
635         else
636             // Descendant
637             str = tagHistoryText + " " + str;
638     }
639
640     return str;
641 }
642
643 const QualifiedName& CSSSelector::attribute() const
644
645     switch (m_match) {
646     case Id:
647         return idAttr;
648     case Class:
649         return classAttr;
650     default:
651         return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName();
652     }
653 }
654
655 void CSSSelector::setAttribute(const QualifiedName& value) 
656
657     createRareData(); 
658     m_data.m_rareData->m_attribute = value; 
659 }
660     
661 void CSSSelector::setArgument(const AtomicString& value) 
662
663     createRareData(); 
664     m_data.m_rareData->m_argument = value; 
665 }
666     
667 void CSSSelector::setSelectorList(PassOwnPtr<CSSSelectorList> selectorList)
668 {
669     createRareData(); 
670     m_data.m_rareData->m_selectorList = selectorList;
671 }
672
673 bool CSSSelector::parseNth()
674 {
675     if (!m_hasRareData)
676         return false;
677     if (m_parsedNth)
678         return true;
679     m_parsedNth = m_data.m_rareData->parseNth();
680     return m_parsedNth;
681 }
682
683 bool CSSSelector::matchNth(int count)
684 {
685     ASSERT(m_hasRareData);
686     return m_data.m_rareData->matchNth(count);
687 }
688
689 bool CSSSelector::isSimple() const
690 {
691     if (selectorList() || tagHistory() || matchesPseudoElement())
692         return false;
693
694     int numConditions = 0;
695
696     // hasTag() cannot be be used here because namespace may not be nullAtom.
697     // Example:
698     //     @namespace "http://www.w3.org/2000/svg";
699     //     svg:not(:root) { ...
700     if (m_tag != starAtom)
701         numConditions++;
702
703     if (m_match == Id || m_match == Class || m_match == PseudoClass)
704         numConditions++;
705
706     if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
707         numConditions++;
708
709     // numConditions is 0 for a universal selector.
710     // numConditions is 1 for other simple selectors.
711     return numConditions <= 1;
712 }
713
714 CSSSelector::RareData::RareData(PassRefPtr<AtomicStringImpl> value)
715     : m_value(value.leakRef())
716     , m_a(0)
717     , m_b(0)
718     , m_attribute(anyQName())
719     , m_argument(nullAtom)
720 {
721 }
722
723 CSSSelector::RareData::~RareData()
724 {
725     if (m_value)
726         m_value->deref();
727 }
728     
729 // a helper function for parsing nth-arguments
730 bool CSSSelector::RareData::parseNth()
731 {
732     String argument = m_argument.lower();
733     
734     if (argument.isEmpty())
735         return false;
736     
737     m_a = 0;
738     m_b = 0;
739     if (argument == "odd") {
740         m_a = 2;
741         m_b = 1;
742     } else if (argument == "even") {
743         m_a = 2;
744         m_b = 0;
745     } else {
746         size_t n = argument.find('n');
747         if (n != notFound) {
748             if (argument[0] == '-') {
749                 if (n == 1)
750                     m_a = -1; // -n == -1n
751                 else
752                     m_a = argument.substring(0, n).toInt();
753             } else if (!n)
754                 m_a = 1; // n == 1n
755             else
756                 m_a = argument.substring(0, n).toInt();
757             
758             size_t p = argument.find('+', n);
759             if (p != notFound)
760                 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
761             else {
762                 p = argument.find('-', n);
763                 if (p != notFound)
764                     m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
765             }
766         } else
767             m_b = argument.toInt();
768     }
769     return true;
770 }
771
772 // a helper function for checking nth-arguments
773 bool CSSSelector::RareData::matchNth(int count)
774 {
775     if (!m_a)
776         return count == m_b;
777     else if (m_a > 0) {
778         if (count < m_b)
779             return false;
780         return (count - m_b) % m_a == 0;
781     } else {
782         if (count > m_b)
783             return false;
784         return (m_b - count) % (-m_a) == 0;
785     }
786 }
787
788 } // namespace WebCore