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