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 = RareData::create(adoptRef(m_data.m_value)).leakRef();
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 && selectorList())
85 s += selectorList()->first()->specificityForOneSelector();
94 unsigned CSSSelector::specificityForPage() const
96 // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
97 unsigned s = (m_tag.localName() == starAtom ? 0 : 4);
99 switch (pseudoType()) {
100 case PseudoFirstPage:
104 case PseudoRightPage:
107 case PseudoNotParsed:
110 ASSERT_NOT_REACHED();
115 PseudoId CSSSelector::pseudoId(PseudoType type)
118 case PseudoFirstLine:
120 case PseudoFirstLetter:
122 case PseudoSelection:
128 case PseudoScrollbar:
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;
142 #if ENABLE(FULLSCREEN_API)
143 case PseudoFullScreen:
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;
154 case PseudoFirstChild:
155 case PseudoFirstOfType:
156 case PseudoLastChild:
157 case PseudoLastOfType:
158 case PseudoOnlyChild:
159 case PseudoOnlyOfType:
161 case PseudoNthOfType:
162 case PseudoNthLastChild:
163 case PseudoNthLastOfType:
175 case PseudoFullPageMedia:
181 case PseudoReadWrite:
184 case PseudoIndeterminate:
190 case PseudoScrollbarBack:
191 case PseudoScrollbarForward:
192 case PseudoWindowInactive:
193 case PseudoCornerPresent:
194 case PseudoDecrement:
195 case PseudoIncrement:
196 case PseudoHorizontal:
200 case PseudoDoubleButton:
201 case PseudoSingleButton:
203 case PseudoFirstPage:
205 case PseudoRightPage:
207 case PseudoOutOfRange:
209 case PseudoNotParsed:
210 ASSERT_NOT_REACHED();
214 ASSERT_NOT_REACHED();
218 static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
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"));
291 DEFINE_STATIC_LOCAL(AtomicString, inRange, ("in-range"));
292 DEFINE_STATIC_LOCAL(AtomicString, outOfRange, ("out-of-range"));
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);
367 nameToPseudoType->set(inRange.impl(), CSSSelector::PseudoInRange);
368 nameToPseudoType->set(outOfRange.impl(), CSSSelector::PseudoOutOfRange);
370 return nameToPseudoType;
373 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
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;
382 bool CSSSelector::isUnknownPseudoType(const AtomicString& name)
384 return parsePseudoType(name) == PseudoUnknown;
387 void CSSSelector::extractPseudoType() const
389 if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass)
392 m_pseudoType = parsePseudoType(value());
394 bool element = false; // pseudo-element
395 bool compat = false; // single colon compatbility mode
396 bool isPagePseudoClass = false; // Page pseudo-class
398 switch (m_pseudoType) {
401 case PseudoFirstLetter:
402 case PseudoFirstLine:
405 case PseudoScrollbar:
406 case PseudoScrollbarCorner:
407 case PseudoScrollbarButton:
408 case PseudoScrollbarThumb:
409 case PseudoScrollbarTrack:
410 case PseudoScrollbarTrackPiece:
411 case PseudoSelection:
416 case PseudoFirstChild:
417 case PseudoFirstOfType:
418 case PseudoLastChild:
419 case PseudoLastOfType:
420 case PseudoOnlyChild:
421 case PseudoOnlyOfType:
423 case PseudoNthOfType:
424 case PseudoNthLastChild:
425 case PseudoNthLastOfType:
437 case PseudoFullPageMedia:
443 case PseudoReadWrite:
446 case PseudoIndeterminate:
452 case PseudoScrollbarBack:
453 case PseudoScrollbarForward:
454 case PseudoWindowInactive:
455 case PseudoCornerPresent:
456 case PseudoDecrement:
457 case PseudoIncrement:
458 case PseudoHorizontal:
462 case PseudoDoubleButton:
463 case PseudoSingleButton:
465 case PseudoNotParsed:
466 #if ENABLE(FULLSCREEN_API)
467 case PseudoFullScreen:
468 case PseudoFullScreenDocument:
469 case PseudoFullScreenAncestor:
470 case PseudoAnimatingFullScreenTransition:
473 case PseudoOutOfRange:
475 case PseudoFirstPage:
477 case PseudoRightPage:
478 isPagePseudoClass = true;
482 bool matchPagePseudoClass = (m_match == PagePseudoClass);
483 if (matchPagePseudoClass != isPagePseudoClass)
484 m_pseudoType = PseudoUnknown;
485 else if (m_match == PseudoClass && element) {
487 m_pseudoType = PseudoUnknown;
489 m_match = PseudoElement;
490 } else if (m_match == PseudoElement && !element)
491 m_pseudoType = PseudoUnknown;
494 bool CSSSelector::operator==(const CSSSelector& other)
496 const CSSSelector* sel1 = this;
497 const CSSSelector* sel2 = &other;
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())
506 sel1 = sel1->tagHistory();
507 sel2 = sel2->tagHistory();
516 String CSSSelector::selectorText() const
520 const AtomicString& prefix = m_tag.prefix();
521 const AtomicString& localName = m_tag.localName();
522 if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
526 str = prefix.string();
528 str.append(localName);
532 const CSSSelector* cs = this;
534 if (cs->m_match == CSSSelector::Id) {
536 serializeIdentifier(cs->value(), str);
537 } else if (cs->m_match == CSSSelector::Class) {
539 serializeIdentifier(cs->value(), str);
540 } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) {
544 switch (cs->pseudoType()) {
546 if (CSSSelectorList* selectorList = cs->selectorList())
547 str += selectorList->first()->selectorText();
552 case PseudoNthLastChild:
553 case PseudoNthOfType:
554 case PseudoNthLastOfType:
555 str += cs->argument();
559 CSSSelector* firstSubSelector = cs->selectorList()->first();
560 for (CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) {
561 if (subSelector != firstSubSelector)
563 str += subSelector->selectorText();
571 } else if (cs->m_match == CSSSelector::PseudoElement) {
574 } else if (cs->isAttributeSelector()) {
576 const AtomicString& prefix = cs->attribute().prefix();
577 if (!prefix.isNull()) {
581 str += cs->attribute().localName();
582 switch (cs->m_match) {
583 case CSSSelector::Exact:
586 case CSSSelector::Set:
587 // set has no operator or value, just the attrName
590 case CSSSelector::List:
593 case CSSSelector::Hyphen:
596 case CSSSelector::Begin:
599 case CSSSelector::End:
602 case CSSSelector::Contain:
608 if (cs->m_match != CSSSelector::Set) {
609 serializeString(cs->value(), str);
613 if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
615 cs = cs->tagHistory();
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;
630 str = tagHistoryText + " " + str;
636 void CSSSelector::setAttribute(const QualifiedName& value)
639 m_data.m_rareData->m_attribute = value;
642 void CSSSelector::setArgument(const AtomicString& value)
645 m_data.m_rareData->m_argument = value;
648 void CSSSelector::setSelectorList(PassOwnPtr<CSSSelectorList> selectorList)
651 m_data.m_rareData->m_selectorList = selectorList;
654 bool CSSSelector::parseNth()
660 m_parsedNth = m_data.m_rareData->parseNth();
664 bool CSSSelector::matchNth(int count)
666 ASSERT(m_hasRareData);
667 return m_data.m_rareData->matchNth(count);
670 bool CSSSelector::isSimple() const
672 if (selectorList() || tagHistory() || matchesPseudoElement())
675 int numConditions = 0;
677 // hasTag() cannot be be used here because namespace may not be nullAtom.
679 // @namespace "http://www.w3.org/2000/svg";
680 // svg:not(:root) { ...
681 if (m_tag != starAtom)
684 if (m_match == Id || m_match == Class || m_match == PseudoClass)
687 if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
690 // numConditions is 0 for a universal selector.
691 // numConditions is 1 for other simple selectors.
692 return numConditions <= 1;
695 CSSSelector::RareData::RareData(PassRefPtr<AtomicStringImpl> value)
696 : m_value(value.leakRef())
699 , m_attribute(anyQName())
700 , m_argument(nullAtom)
704 CSSSelector::RareData::~RareData()
710 // a helper function for parsing nth-arguments
711 bool CSSSelector::RareData::parseNth()
713 String argument = m_argument.lower();
715 if (argument.isEmpty())
720 if (argument == "odd") {
723 } else if (argument == "even") {
727 size_t n = argument.find('n');
729 if (argument[0] == '-') {
731 m_a = -1; // -n == -1n
733 m_a = argument.substring(0, n).toInt();
737 m_a = argument.substring(0, n).toInt();
739 size_t p = argument.find('+', n);
741 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
743 p = argument.find('-', n);
745 m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
748 m_b = argument.toInt();
753 // a helper function for checking nth-arguments
754 bool CSSSelector::RareData::matchNth(int count)
761 return (count - m_b) % m_a == 0;
765 return (m_b - count) % (-m_a) == 0;
769 } // namespace WebCore