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.
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.
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.
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.
27 #include "CSSSelector.h"
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>
39 using namespace HTMLNames;
41 void CSSSelector::createRareData()
45 // Move the value to the rare data stucture.
46 m_data.m_rareData = new RareData(adoptRef(m_data.m_value));
50 unsigned CSSSelector::specificity() const
52 // make sure the result doesn't overflow
53 static const unsigned maxValueMask = 0xffffff;
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;
63 inline unsigned CSSSelector::specificityForOneSelector() const
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);
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();
95 unsigned CSSSelector::specificityForPage() const
97 // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
98 unsigned s = (m_tag.localName() == starAtom ? 0 : 4);
100 switch (pseudoType()) {
101 case PseudoFirstPage:
105 case PseudoRightPage:
108 case PseudoNotParsed:
111 ASSERT_NOT_REACHED();
116 PseudoId CSSSelector::pseudoId(PseudoType type)
119 case PseudoFirstLine:
121 case PseudoFirstLetter:
123 case PseudoSelection:
129 case PseudoScrollbar:
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;
143 #if ENABLE(FULLSCREEN_API)
144 case PseudoFullScreen:
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;
154 case PseudoInputListButton:
156 return INPUT_LIST_BUTTON;
160 case PseudoFirstChild:
161 case PseudoFirstOfType:
162 case PseudoLastChild:
163 case PseudoLastOfType:
164 case PseudoOnlyChild:
165 case PseudoOnlyOfType:
167 case PseudoNthOfType:
168 case PseudoNthLastChild:
169 case PseudoNthLastOfType:
181 case PseudoFullPageMedia:
187 case PseudoReadWrite:
190 case PseudoIndeterminate:
195 case PseudoScrollbarBack:
196 case PseudoScrollbarForward:
197 case PseudoWindowInactive:
198 case PseudoCornerPresent:
199 case PseudoDecrement:
200 case PseudoIncrement:
201 case PseudoHorizontal:
205 case PseudoDoubleButton:
206 case PseudoSingleButton:
208 case PseudoFirstPage:
210 case PseudoRightPage:
212 case PseudoOutOfRange:
214 case PseudoNotParsed:
215 ASSERT_NOT_REACHED();
219 ASSERT_NOT_REACHED();
223 static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
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"));
255 DEFINE_STATIC_LOCAL(AtomicString, inputListButton, ("-webkit-input-list-button"));
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"));
298 DEFINE_STATIC_LOCAL(AtomicString, inRange, ("in-range"));
299 DEFINE_STATIC_LOCAL(AtomicString, outOfRange, ("out-of-range"));
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);
324 nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton);
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);
376 nameToPseudoType->set(inRange.impl(), CSSSelector::PseudoInRange);
377 nameToPseudoType->set(outOfRange.impl(), CSSSelector::PseudoOutOfRange);
379 return nameToPseudoType;
382 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
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;
391 bool CSSSelector::isUnknownPseudoType(const AtomicString& name)
393 return parsePseudoType(name) == PseudoUnknown;
396 void CSSSelector::extractPseudoType() const
398 if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass)
401 m_pseudoType = parsePseudoType(value());
403 bool element = false; // pseudo-element
404 bool compat = false; // single colon compatbility mode
405 bool isPagePseudoClass = false; // Page pseudo-class
407 switch (m_pseudoType) {
410 case PseudoFirstLetter:
411 case PseudoFirstLine:
413 case PseudoInputListButton:
415 case PseudoScrollbar:
416 case PseudoScrollbarCorner:
417 case PseudoScrollbarButton:
418 case PseudoScrollbarThumb:
419 case PseudoScrollbarTrack:
420 case PseudoScrollbarTrackPiece:
421 case PseudoSelection:
426 case PseudoFirstChild:
427 case PseudoFirstOfType:
428 case PseudoLastChild:
429 case PseudoLastOfType:
430 case PseudoOnlyChild:
431 case PseudoOnlyOfType:
433 case PseudoNthOfType:
434 case PseudoNthLastChild:
435 case PseudoNthLastOfType:
447 case PseudoFullPageMedia:
453 case PseudoReadWrite:
456 case PseudoIndeterminate:
461 case PseudoScrollbarBack:
462 case PseudoScrollbarForward:
463 case PseudoWindowInactive:
464 case PseudoCornerPresent:
465 case PseudoDecrement:
466 case PseudoIncrement:
467 case PseudoHorizontal:
471 case PseudoDoubleButton:
472 case PseudoSingleButton:
474 case PseudoNotParsed:
475 #if ENABLE(FULLSCREEN_API)
476 case PseudoFullScreen:
477 case PseudoFullScreenDocument:
478 case PseudoFullScreenAncestor:
479 case PseudoAnimatingFullScreenTransition:
482 case PseudoOutOfRange:
484 case PseudoFirstPage:
486 case PseudoRightPage:
487 isPagePseudoClass = true;
491 bool matchPagePseudoClass = (m_match == PagePseudoClass);
492 if (matchPagePseudoClass != isPagePseudoClass)
493 m_pseudoType = PseudoUnknown;
494 else if (m_match == PseudoClass && element) {
496 m_pseudoType = PseudoUnknown;
498 m_match = PseudoElement;
499 } else if (m_match == PseudoElement && !element)
500 m_pseudoType = PseudoUnknown;
503 bool CSSSelector::operator==(const CSSSelector& other)
505 const CSSSelector* sel1 = this;
506 const CSSSelector* sel2 = &other;
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())
515 sel1 = sel1->tagHistory();
516 sel2 = sel2->tagHistory();
525 String CSSSelector::selectorText() const
529 const AtomicString& prefix = m_tag.prefix();
530 const AtomicString& localName = m_tag.localName();
531 if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
535 str = prefix.string();
537 str.append(localName);
541 const CSSSelector* cs = this;
543 if (cs->m_match == CSSSelector::Id) {
545 serializeIdentifier(cs->value(), str);
546 } else if (cs->m_match == CSSSelector::Class) {
548 serializeIdentifier(cs->value(), str);
549 } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) {
553 switch (cs->pseudoType()) {
555 ASSERT(cs->selectorList());
556 str += cs->selectorList()->first()->selectorText();
561 case PseudoNthLastChild:
562 case PseudoNthOfType:
563 case PseudoNthLastOfType:
564 str += cs->argument();
568 CSSSelector* firstSubSelector = cs->selectorList()->first();
569 for (CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) {
570 if (subSelector != firstSubSelector)
572 str += subSelector->selectorText();
580 } else if (cs->m_match == CSSSelector::PseudoElement) {
583 } else if (cs->hasAttribute()) {
585 const AtomicString& prefix = cs->attribute().prefix();
586 if (!prefix.isNull()) {
590 str += cs->attribute().localName();
591 switch (cs->m_match) {
592 case CSSSelector::Exact:
595 case CSSSelector::Set:
596 // set has no operator or value, just the attrName
599 case CSSSelector::List:
602 case CSSSelector::Hyphen:
605 case CSSSelector::Begin:
608 case CSSSelector::End:
611 case CSSSelector::Contain:
617 if (cs->m_match != CSSSelector::Set) {
618 serializeString(cs->value(), str);
622 if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
624 cs = cs->tagHistory();
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;
637 str = tagHistoryText + " " + str;
643 const QualifiedName& CSSSelector::attribute() const
651 return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName();
655 void CSSSelector::setAttribute(const QualifiedName& value)
658 m_data.m_rareData->m_attribute = value;
661 void CSSSelector::setArgument(const AtomicString& value)
664 m_data.m_rareData->m_argument = value;
667 void CSSSelector::setSelectorList(PassOwnPtr<CSSSelectorList> selectorList)
670 m_data.m_rareData->m_selectorList = selectorList;
673 bool CSSSelector::parseNth()
679 m_parsedNth = m_data.m_rareData->parseNth();
683 bool CSSSelector::matchNth(int count)
685 ASSERT(m_hasRareData);
686 return m_data.m_rareData->matchNth(count);
689 bool CSSSelector::isSimple() const
691 if (selectorList() || tagHistory() || matchesPseudoElement())
694 int numConditions = 0;
696 // hasTag() cannot be be used here because namespace may not be nullAtom.
698 // @namespace "http://www.w3.org/2000/svg";
699 // svg:not(:root) { ...
700 if (m_tag != starAtom)
703 if (m_match == Id || m_match == Class || m_match == PseudoClass)
706 if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
709 // numConditions is 0 for a universal selector.
710 // numConditions is 1 for other simple selectors.
711 return numConditions <= 1;
714 CSSSelector::RareData::RareData(PassRefPtr<AtomicStringImpl> value)
715 : m_value(value.leakRef())
718 , m_attribute(anyQName())
719 , m_argument(nullAtom)
723 CSSSelector::RareData::~RareData()
729 // a helper function for parsing nth-arguments
730 bool CSSSelector::RareData::parseNth()
732 String argument = m_argument.lower();
734 if (argument.isEmpty())
739 if (argument == "odd") {
742 } else if (argument == "even") {
746 size_t n = argument.find('n');
748 if (argument[0] == '-') {
750 m_a = -1; // -n == -1n
752 m_a = argument.substring(0, n).toInt();
756 m_a = argument.substring(0, n).toInt();
758 size_t p = argument.find('+', n);
760 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
762 p = argument.find('-', n);
764 m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
767 m_b = argument.toInt();
772 // a helper function for checking nth-arguments
773 bool CSSSelector::RareData::matchNth(int count)
780 return (count - m_b) % m_a == 0;
784 return (m_b - count) % (-m_a) == 0;
788 } // namespace WebCore