Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 1999-2003 Lars Knoll (knoll (at) kde.org)
      3  *               1999 Waldo Bastian (bastian (at) kde.org)
      4  *               2001 Andreas Schlapbach (schlpbch (at) iam.unibe.ch)
      5  *               2001-2003 Dirk Mueller (mueller (at) kde.org)
      6  * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      7  * Copyright (C) 2008 David Smith (catfish.man (at) 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 "core/css/CSSSelector.h"
     28 
     29 #include "HTMLNames.h"
     30 #include "RuntimeEnabledFeatures.h"
     31 #include "core/css/CSSOMUtils.h"
     32 #include "core/css/CSSSelectorList.h"
     33 #include "wtf/Assertions.h"
     34 #include "wtf/HashMap.h"
     35 #include "wtf/StdLibExtras.h"
     36 #include "wtf/text/StringBuilder.h"
     37 #include "wtf/text/StringHash.h"
     38 
     39 namespace WebCore {
     40 
     41 using namespace HTMLNames;
     42 
     43 struct SameSizeAsCSSSelector {
     44     unsigned bitfields;
     45     void *pointers[1];
     46 };
     47 
     48 COMPILE_ASSERT(sizeof(CSSSelector) == sizeof(SameSizeAsCSSSelector), CSSSelectorShouldStaySmall);
     49 
     50 void CSSSelector::createRareData()
     51 {
     52     ASSERT(m_match != Tag);
     53     if (m_hasRareData)
     54         return;
     55     // Move the value to the rare data stucture.
     56     m_data.m_rareData = RareData::create(adoptRef(m_data.m_value)).leakRef();
     57     m_hasRareData = true;
     58 }
     59 
     60 unsigned CSSSelector::specificity() const
     61 {
     62     // make sure the result doesn't overflow
     63     static const unsigned maxValueMask = 0xffffff;
     64     static const unsigned idMask = 0xff0000;
     65     static const unsigned classMask = 0xff00;
     66     static const unsigned elementMask = 0xff;
     67 
     68     if (isForPage())
     69         return specificityForPage() & maxValueMask;
     70 
     71     unsigned total = 0;
     72     unsigned temp = 0;
     73 
     74     for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
     75         temp = total + selector->specificityForOneSelector();
     76         // Clamp each component to its max in the case of overflow.
     77         if ((temp & idMask) < (total & idMask))
     78             total |= idMask;
     79         else if ((temp & classMask) < (total & classMask))
     80             total |= classMask;
     81         else if ((temp & elementMask) < (total & elementMask))
     82             total |= elementMask;
     83         else
     84             total = temp;
     85     }
     86     return total;
     87 }
     88 
     89 inline unsigned CSSSelector::specificityForOneSelector() const
     90 {
     91     // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
     92     // isn't quite correct.
     93     switch (m_match) {
     94     case Id:
     95         return 0x10000;
     96     case Exact:
     97     case Class:
     98     case Set:
     99     case List:
    100     case Hyphen:
    101     case PseudoClass:
    102     case PseudoElement:
    103     case Contain:
    104     case Begin:
    105     case End:
    106         // FIXME: PseudoAny should base the specificity on the sub-selectors.
    107         // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
    108         if (pseudoType() == PseudoNot) {
    109             ASSERT(selectorList());
    110             return selectorList()->first()->specificityForOneSelector();
    111         }
    112         return 0x100;
    113     case Tag:
    114         return (tagQName().localName() != starAtom) ? 1 : 0;
    115     case Unknown:
    116         return 0;
    117     }
    118     ASSERT_NOT_REACHED();
    119     return 0;
    120 }
    121 
    122 unsigned CSSSelector::specificityForPage() const
    123 {
    124     // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
    125     unsigned s = 0;
    126 
    127     for (const CSSSelector* component = this; component; component = component->tagHistory()) {
    128         switch (component->m_match) {
    129         case Tag:
    130             s += tagQName().localName() == starAtom ? 0 : 4;
    131             break;
    132         case PseudoClass:
    133             switch (component->pseudoType()) {
    134             case PseudoFirstPage:
    135                 s += 2;
    136                 break;
    137             case PseudoLeftPage:
    138             case PseudoRightPage:
    139                 s += 1;
    140                 break;
    141             case PseudoNotParsed:
    142                 break;
    143             default:
    144                 ASSERT_NOT_REACHED();
    145             }
    146             break;
    147         default:
    148             break;
    149         }
    150     }
    151     return s;
    152 }
    153 
    154 PseudoId CSSSelector::pseudoId(PseudoType type)
    155 {
    156     switch (type) {
    157     case PseudoFirstLine:
    158         return FIRST_LINE;
    159     case PseudoFirstLetter:
    160         return FIRST_LETTER;
    161     case PseudoSelection:
    162         return SELECTION;
    163     case PseudoBefore:
    164         return BEFORE;
    165     case PseudoAfter:
    166         return AFTER;
    167     case PseudoBackdrop:
    168         return BACKDROP;
    169     case PseudoScrollbar:
    170         return SCROLLBAR;
    171     case PseudoScrollbarButton:
    172         return SCROLLBAR_BUTTON;
    173     case PseudoScrollbarCorner:
    174         return SCROLLBAR_CORNER;
    175     case PseudoScrollbarThumb:
    176         return SCROLLBAR_THUMB;
    177     case PseudoScrollbarTrack:
    178         return SCROLLBAR_TRACK;
    179     case PseudoScrollbarTrackPiece:
    180         return SCROLLBAR_TRACK_PIECE;
    181     case PseudoResizer:
    182         return RESIZER;
    183     case PseudoFullScreen:
    184         return FULL_SCREEN;
    185     case PseudoFullScreenDocument:
    186         return FULL_SCREEN_DOCUMENT;
    187     case PseudoFullScreenAncestor:
    188         return FULL_SCREEN_ANCESTOR;
    189     case PseudoUnknown:
    190     case PseudoEmpty:
    191     case PseudoFirstChild:
    192     case PseudoFirstOfType:
    193     case PseudoLastChild:
    194     case PseudoLastOfType:
    195     case PseudoOnlyChild:
    196     case PseudoOnlyOfType:
    197     case PseudoNthChild:
    198     case PseudoNthOfType:
    199     case PseudoNthLastChild:
    200     case PseudoNthLastOfType:
    201     case PseudoLink:
    202     case PseudoVisited:
    203     case PseudoAny:
    204     case PseudoAnyLink:
    205     case PseudoAutofill:
    206     case PseudoHover:
    207     case PseudoDrag:
    208     case PseudoFocus:
    209     case PseudoActive:
    210     case PseudoChecked:
    211     case PseudoEnabled:
    212     case PseudoFullPageMedia:
    213     case PseudoDefault:
    214     case PseudoDisabled:
    215     case PseudoOptional:
    216     case PseudoRequired:
    217     case PseudoReadOnly:
    218     case PseudoReadWrite:
    219     case PseudoValid:
    220     case PseudoInvalid:
    221     case PseudoIndeterminate:
    222     case PseudoTarget:
    223     case PseudoLang:
    224     case PseudoNot:
    225     case PseudoRoot:
    226     case PseudoScope:
    227     case PseudoScrollbarBack:
    228     case PseudoScrollbarForward:
    229     case PseudoWindowInactive:
    230     case PseudoCornerPresent:
    231     case PseudoDecrement:
    232     case PseudoIncrement:
    233     case PseudoHorizontal:
    234     case PseudoVertical:
    235     case PseudoStart:
    236     case PseudoEnd:
    237     case PseudoDoubleButton:
    238     case PseudoSingleButton:
    239     case PseudoNoButton:
    240     case PseudoFirstPage:
    241     case PseudoLeftPage:
    242     case PseudoRightPage:
    243     case PseudoInRange:
    244     case PseudoOutOfRange:
    245     case PseudoUserAgentCustomElement:
    246     case PseudoWebKitCustomElement:
    247     case PseudoCue:
    248     case PseudoFutureCue:
    249     case PseudoPastCue:
    250     case PseudoSeamlessDocument:
    251     case PseudoDistributed:
    252     case PseudoPart:
    253     case PseudoUnresolved:
    254     case PseudoContent:
    255     case PseudoHost:
    256         return NOPSEUDO;
    257     case PseudoNotParsed:
    258         ASSERT_NOT_REACHED();
    259         return NOPSEUDO;
    260     }
    261 
    262     ASSERT_NOT_REACHED();
    263     return NOPSEUDO;
    264 }
    265 
    266 static HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
    267 {
    268     DEFINE_STATIC_LOCAL(AtomicString, active, ("active", AtomicString::ConstructFromLiteral));
    269     DEFINE_STATIC_LOCAL(AtomicString, after, ("after", AtomicString::ConstructFromLiteral));
    270     DEFINE_STATIC_LOCAL(AtomicString, any, ("-webkit-any(", AtomicString::ConstructFromLiteral));
    271     DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link", AtomicString::ConstructFromLiteral));
    272     DEFINE_STATIC_LOCAL(AtomicString, autofill, ("-webkit-autofill", AtomicString::ConstructFromLiteral));
    273     DEFINE_STATIC_LOCAL(AtomicString, backdrop, ("backdrop", AtomicString::ConstructFromLiteral));
    274     DEFINE_STATIC_LOCAL(AtomicString, before, ("before", AtomicString::ConstructFromLiteral));
    275     DEFINE_STATIC_LOCAL(AtomicString, checked, ("checked", AtomicString::ConstructFromLiteral));
    276     DEFINE_STATIC_LOCAL(AtomicString, defaultString, ("default", AtomicString::ConstructFromLiteral));
    277     DEFINE_STATIC_LOCAL(AtomicString, disabled, ("disabled", AtomicString::ConstructFromLiteral));
    278     DEFINE_STATIC_LOCAL(AtomicString, readOnly, ("read-only", AtomicString::ConstructFromLiteral));
    279     DEFINE_STATIC_LOCAL(AtomicString, readWrite, ("read-write", AtomicString::ConstructFromLiteral));
    280     DEFINE_STATIC_LOCAL(AtomicString, valid, ("valid", AtomicString::ConstructFromLiteral));
    281     DEFINE_STATIC_LOCAL(AtomicString, invalid, ("invalid", AtomicString::ConstructFromLiteral));
    282     DEFINE_STATIC_LOCAL(AtomicString, drag, ("-webkit-drag", AtomicString::ConstructFromLiteral));
    283     DEFINE_STATIC_LOCAL(AtomicString, dragAlias, ("-khtml-drag", AtomicString::ConstructFromLiteral)); // was documented with this name in Apple documentation, so keep an alia
    284     DEFINE_STATIC_LOCAL(AtomicString, empty, ("empty", AtomicString::ConstructFromLiteral));
    285     DEFINE_STATIC_LOCAL(AtomicString, enabled, ("enabled", AtomicString::ConstructFromLiteral));
    286     DEFINE_STATIC_LOCAL(AtomicString, firstChild, ("first-child", AtomicString::ConstructFromLiteral));
    287     DEFINE_STATIC_LOCAL(AtomicString, firstLetter, ("first-letter", AtomicString::ConstructFromLiteral));
    288     DEFINE_STATIC_LOCAL(AtomicString, firstLine, ("first-line", AtomicString::ConstructFromLiteral));
    289     DEFINE_STATIC_LOCAL(AtomicString, firstOfType, ("first-of-type", AtomicString::ConstructFromLiteral));
    290     DEFINE_STATIC_LOCAL(AtomicString, fullPageMedia, ("-webkit-full-page-media", AtomicString::ConstructFromLiteral));
    291     DEFINE_STATIC_LOCAL(AtomicString, nthChild, ("nth-child(", AtomicString::ConstructFromLiteral));
    292     DEFINE_STATIC_LOCAL(AtomicString, nthOfType, ("nth-of-type(", AtomicString::ConstructFromLiteral));
    293     DEFINE_STATIC_LOCAL(AtomicString, nthLastChild, ("nth-last-child(", AtomicString::ConstructFromLiteral));
    294     DEFINE_STATIC_LOCAL(AtomicString, nthLastOfType, ("nth-last-of-type(", AtomicString::ConstructFromLiteral));
    295     DEFINE_STATIC_LOCAL(AtomicString, focus, ("focus", AtomicString::ConstructFromLiteral));
    296     DEFINE_STATIC_LOCAL(AtomicString, hover, ("hover", AtomicString::ConstructFromLiteral));
    297     DEFINE_STATIC_LOCAL(AtomicString, indeterminate, ("indeterminate", AtomicString::ConstructFromLiteral));
    298     DEFINE_STATIC_LOCAL(AtomicString, lastChild, ("last-child", AtomicString::ConstructFromLiteral));
    299     DEFINE_STATIC_LOCAL(AtomicString, lastOfType, ("last-of-type", AtomicString::ConstructFromLiteral));
    300     DEFINE_STATIC_LOCAL(AtomicString, link, ("link", AtomicString::ConstructFromLiteral));
    301     DEFINE_STATIC_LOCAL(AtomicString, lang, ("lang(", AtomicString::ConstructFromLiteral));
    302     DEFINE_STATIC_LOCAL(AtomicString, notStr, ("not(", AtomicString::ConstructFromLiteral));
    303     DEFINE_STATIC_LOCAL(AtomicString, onlyChild, ("only-child", AtomicString::ConstructFromLiteral));
    304     DEFINE_STATIC_LOCAL(AtomicString, onlyOfType, ("only-of-type", AtomicString::ConstructFromLiteral));
    305     DEFINE_STATIC_LOCAL(AtomicString, optional, ("optional", AtomicString::ConstructFromLiteral));
    306     DEFINE_STATIC_LOCAL(AtomicString, required, ("required", AtomicString::ConstructFromLiteral));
    307     DEFINE_STATIC_LOCAL(AtomicString, resizer, ("-webkit-resizer", AtomicString::ConstructFromLiteral));
    308     DEFINE_STATIC_LOCAL(AtomicString, root, ("root", AtomicString::ConstructFromLiteral));
    309     DEFINE_STATIC_LOCAL(AtomicString, scrollbar, ("-webkit-scrollbar", AtomicString::ConstructFromLiteral));
    310     DEFINE_STATIC_LOCAL(AtomicString, scrollbarButton, ("-webkit-scrollbar-button", AtomicString::ConstructFromLiteral));
    311     DEFINE_STATIC_LOCAL(AtomicString, scrollbarCorner, ("-webkit-scrollbar-corner", AtomicString::ConstructFromLiteral));
    312     DEFINE_STATIC_LOCAL(AtomicString, scrollbarThumb, ("-webkit-scrollbar-thumb", AtomicString::ConstructFromLiteral));
    313     DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrack, ("-webkit-scrollbar-track", AtomicString::ConstructFromLiteral));
    314     DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrackPiece, ("-webkit-scrollbar-track-piece", AtomicString::ConstructFromLiteral));
    315     DEFINE_STATIC_LOCAL(AtomicString, selection, ("selection", AtomicString::ConstructFromLiteral));
    316     DEFINE_STATIC_LOCAL(AtomicString, target, ("target", AtomicString::ConstructFromLiteral));
    317     DEFINE_STATIC_LOCAL(AtomicString, visited, ("visited", AtomicString::ConstructFromLiteral));
    318     DEFINE_STATIC_LOCAL(AtomicString, windowInactive, ("window-inactive", AtomicString::ConstructFromLiteral));
    319     DEFINE_STATIC_LOCAL(AtomicString, decrement, ("decrement", AtomicString::ConstructFromLiteral));
    320     DEFINE_STATIC_LOCAL(AtomicString, increment, ("increment", AtomicString::ConstructFromLiteral));
    321     DEFINE_STATIC_LOCAL(AtomicString, start, ("start", AtomicString::ConstructFromLiteral));
    322     DEFINE_STATIC_LOCAL(AtomicString, end, ("end", AtomicString::ConstructFromLiteral));
    323     DEFINE_STATIC_LOCAL(AtomicString, horizontal, ("horizontal", AtomicString::ConstructFromLiteral));
    324     DEFINE_STATIC_LOCAL(AtomicString, vertical, ("vertical", AtomicString::ConstructFromLiteral));
    325     DEFINE_STATIC_LOCAL(AtomicString, doubleButton, ("double-button", AtomicString::ConstructFromLiteral));
    326     DEFINE_STATIC_LOCAL(AtomicString, singleButton, ("single-button", AtomicString::ConstructFromLiteral));
    327     DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button", AtomicString::ConstructFromLiteral));
    328     DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present", AtomicString::ConstructFromLiteral));
    329     // Paged Media pseudo-classes
    330     DEFINE_STATIC_LOCAL(AtomicString, firstPage, ("first", AtomicString::ConstructFromLiteral));
    331     DEFINE_STATIC_LOCAL(AtomicString, leftPage, ("left", AtomicString::ConstructFromLiteral));
    332     DEFINE_STATIC_LOCAL(AtomicString, rightPage, ("right", AtomicString::ConstructFromLiteral));
    333     DEFINE_STATIC_LOCAL(AtomicString, fullScreen, ("-webkit-full-screen", AtomicString::ConstructFromLiteral));
    334     DEFINE_STATIC_LOCAL(AtomicString, fullScreenDocument, ("-webkit-full-screen-document", AtomicString::ConstructFromLiteral));
    335     DEFINE_STATIC_LOCAL(AtomicString, fullScreenAncestor, ("-webkit-full-screen-ancestor", AtomicString::ConstructFromLiteral));
    336     DEFINE_STATIC_LOCAL(AtomicString, cue, ("cue(", AtomicString::ConstructFromLiteral));
    337     DEFINE_STATIC_LOCAL(AtomicString, cueWithoutParen, ("cue", AtomicString::ConstructFromLiteral));
    338     DEFINE_STATIC_LOCAL(AtomicString, futureCue, ("future", AtomicString::ConstructFromLiteral));
    339     DEFINE_STATIC_LOCAL(AtomicString, pastCue, ("past", AtomicString::ConstructFromLiteral));
    340     DEFINE_STATIC_LOCAL(AtomicString, seamlessDocument, ("-webkit-seamless-document", AtomicString::ConstructFromLiteral));
    341     DEFINE_STATIC_LOCAL(AtomicString, distributed, ("-webkit-distributed(", AtomicString::ConstructFromLiteral));
    342     DEFINE_STATIC_LOCAL(AtomicString, inRange, ("in-range", AtomicString::ConstructFromLiteral));
    343     DEFINE_STATIC_LOCAL(AtomicString, outOfRange, ("out-of-range", AtomicString::ConstructFromLiteral));
    344     DEFINE_STATIC_LOCAL(AtomicString, scope, ("scope", AtomicString::ConstructFromLiteral));
    345     DEFINE_STATIC_LOCAL(AtomicString, part, ("part(", AtomicString::ConstructFromLiteral));
    346     DEFINE_STATIC_LOCAL(AtomicString, unresolved, ("unresolved", AtomicString::ConstructFromLiteral));
    347     DEFINE_STATIC_LOCAL(AtomicString, content, ("content", AtomicString::ConstructFromLiteral));
    348     DEFINE_STATIC_LOCAL(AtomicString, host, ("host", AtomicString::ConstructFromLiteral));
    349     DEFINE_STATIC_LOCAL(AtomicString, hostWithParams, ("host(", AtomicString::ConstructFromLiteral));
    350 
    351     static HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0;
    352     if (!nameToPseudoType) {
    353         nameToPseudoType = new HashMap<StringImpl*, CSSSelector::PseudoType>;
    354         nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive);
    355         nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter);
    356         nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink);
    357         nameToPseudoType->set(any.impl(), CSSSelector::PseudoAny);
    358         nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill);
    359         nameToPseudoType->set(backdrop.impl(), CSSSelector::PseudoBackdrop);
    360         nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore);
    361         nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked);
    362         nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault);
    363         nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled);
    364         nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly);
    365         nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite);
    366         nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid);
    367         nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid);
    368         nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag);
    369         nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag);
    370         nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled);
    371         nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty);
    372         nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild);
    373         nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia);
    374         nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild);
    375         nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType);
    376         nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild);
    377         nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType);
    378         nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter);
    379         nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine);
    380         nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType);
    381         nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus);
    382         nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover);
    383         nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate);
    384         nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink);
    385         nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang);
    386         nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot);
    387         nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild);
    388         nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType);
    389         nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild);
    390         nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType);
    391         nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot);
    392         nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive);
    393         nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement);
    394         nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement);
    395         nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart);
    396         nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd);
    397         nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal);
    398         nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical);
    399         nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton);
    400         nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton);
    401         nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton);
    402         nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional);
    403         nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired);
    404         nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer);
    405         nameToPseudoType->set(scope.impl(), CSSSelector::PseudoScope);
    406         nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar);
    407         nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton);
    408         nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner);
    409         nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb);
    410         nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack);
    411         nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece);
    412         nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent);
    413         nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection);
    414         nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget);
    415         nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited);
    416         nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage);
    417         nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage);
    418         nameToPseudoType->set(rightPage.impl(), CSSSelector::PseudoRightPage);
    419         nameToPseudoType->set(fullScreen.impl(), CSSSelector::PseudoFullScreen);
    420         nameToPseudoType->set(fullScreenDocument.impl(), CSSSelector::PseudoFullScreenDocument);
    421         nameToPseudoType->set(fullScreenAncestor.impl(), CSSSelector::PseudoFullScreenAncestor);
    422         nameToPseudoType->set(cue.impl(), CSSSelector::PseudoCue);
    423         nameToPseudoType->set(cueWithoutParen.impl(), CSSSelector::PseudoWebKitCustomElement);
    424         nameToPseudoType->set(futureCue.impl(), CSSSelector::PseudoFutureCue);
    425         nameToPseudoType->set(pastCue.impl(), CSSSelector::PseudoPastCue);
    426         nameToPseudoType->set(seamlessDocument.impl(), CSSSelector::PseudoSeamlessDocument);
    427         nameToPseudoType->set(distributed.impl(), CSSSelector::PseudoDistributed);
    428         nameToPseudoType->set(inRange.impl(), CSSSelector::PseudoInRange);
    429         nameToPseudoType->set(outOfRange.impl(), CSSSelector::PseudoOutOfRange);
    430         if (RuntimeEnabledFeatures::shadowDOMEnabled()) {
    431             nameToPseudoType->set(part.impl(), CSSSelector::PseudoPart);
    432             nameToPseudoType->set(host.impl(), CSSSelector::PseudoHost);
    433             nameToPseudoType->set(hostWithParams.impl(), CSSSelector::PseudoHost);
    434             nameToPseudoType->set(content.impl(), CSSSelector::PseudoContent);
    435         }
    436         if (RuntimeEnabledFeatures::customDOMElementsEnabled() || RuntimeEnabledFeatures::embedderCustomElementsEnabled())
    437             nameToPseudoType->set(unresolved.impl(), CSSSelector::PseudoUnresolved);
    438     }
    439     return nameToPseudoType;
    440 }
    441 
    442 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
    443 {
    444     if (name.isNull())
    445         return PseudoUnknown;
    446     HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap();
    447     HashMap<StringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl());
    448 
    449     if (slot != nameToPseudoType->end())
    450         return slot->value;
    451 
    452     if (name.startsWith("-webkit-"))
    453         return PseudoWebKitCustomElement;
    454     if (name.startsWith("x-") || name.startsWith("cue"))
    455         return PseudoUserAgentCustomElement;
    456 
    457     return PseudoUnknown;
    458 }
    459 
    460 void CSSSelector::extractPseudoType() const
    461 {
    462     if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass)
    463         return;
    464 
    465     m_pseudoType = parsePseudoType(value());
    466 
    467     bool element = false; // pseudo-element
    468     bool compat = false; // single colon compatbility mode
    469     bool isPagePseudoClass = false; // Page pseudo-class
    470 
    471     switch (m_pseudoType) {
    472     case PseudoAfter:
    473     case PseudoBefore:
    474     case PseudoCue:
    475     case PseudoFirstLetter:
    476     case PseudoFirstLine:
    477         compat = true;
    478     case PseudoBackdrop:
    479     case PseudoDistributed:
    480     case PseudoResizer:
    481     case PseudoScrollbar:
    482     case PseudoScrollbarCorner:
    483     case PseudoScrollbarButton:
    484     case PseudoScrollbarThumb:
    485     case PseudoScrollbarTrack:
    486     case PseudoScrollbarTrackPiece:
    487     case PseudoSelection:
    488     case PseudoUserAgentCustomElement:
    489     case PseudoWebKitCustomElement:
    490     case PseudoPart:
    491     case PseudoContent:
    492         element = true;
    493         break;
    494     case PseudoUnknown:
    495     case PseudoEmpty:
    496     case PseudoFirstChild:
    497     case PseudoFirstOfType:
    498     case PseudoLastChild:
    499     case PseudoLastOfType:
    500     case PseudoOnlyChild:
    501     case PseudoOnlyOfType:
    502     case PseudoNthChild:
    503     case PseudoNthOfType:
    504     case PseudoNthLastChild:
    505     case PseudoNthLastOfType:
    506     case PseudoLink:
    507     case PseudoVisited:
    508     case PseudoAny:
    509     case PseudoAnyLink:
    510     case PseudoAutofill:
    511     case PseudoHover:
    512     case PseudoDrag:
    513     case PseudoFocus:
    514     case PseudoActive:
    515     case PseudoChecked:
    516     case PseudoEnabled:
    517     case PseudoFullPageMedia:
    518     case PseudoDefault:
    519     case PseudoDisabled:
    520     case PseudoOptional:
    521     case PseudoRequired:
    522     case PseudoReadOnly:
    523     case PseudoReadWrite:
    524     case PseudoScope:
    525     case PseudoValid:
    526     case PseudoInvalid:
    527     case PseudoIndeterminate:
    528     case PseudoTarget:
    529     case PseudoLang:
    530     case PseudoNot:
    531     case PseudoRoot:
    532     case PseudoScrollbarBack:
    533     case PseudoScrollbarForward:
    534     case PseudoWindowInactive:
    535     case PseudoCornerPresent:
    536     case PseudoDecrement:
    537     case PseudoIncrement:
    538     case PseudoHorizontal:
    539     case PseudoVertical:
    540     case PseudoStart:
    541     case PseudoEnd:
    542     case PseudoDoubleButton:
    543     case PseudoSingleButton:
    544     case PseudoNoButton:
    545     case PseudoNotParsed:
    546     case PseudoFullScreen:
    547     case PseudoFullScreenDocument:
    548     case PseudoFullScreenAncestor:
    549     case PseudoSeamlessDocument:
    550     case PseudoInRange:
    551     case PseudoOutOfRange:
    552     case PseudoFutureCue:
    553     case PseudoPastCue:
    554     case PseudoHost:
    555     case PseudoUnresolved:
    556         break;
    557     case PseudoFirstPage:
    558     case PseudoLeftPage:
    559     case PseudoRightPage:
    560         isPagePseudoClass = true;
    561         break;
    562     }
    563 
    564     bool matchPagePseudoClass = (m_match == PagePseudoClass);
    565     if (matchPagePseudoClass != isPagePseudoClass)
    566         m_pseudoType = PseudoUnknown;
    567     else if (m_match == PseudoClass && element) {
    568         if (!compat)
    569             m_pseudoType = PseudoUnknown;
    570         else
    571             m_match = PseudoElement;
    572     } else if (m_match == PseudoElement && !element)
    573         m_pseudoType = PseudoUnknown;
    574 }
    575 
    576 bool CSSSelector::operator==(const CSSSelector& other) const
    577 {
    578     const CSSSelector* sel1 = this;
    579     const CSSSelector* sel2 = &other;
    580 
    581     while (sel1 && sel2) {
    582         if (sel1->attribute() != sel2->attribute()
    583             || sel1->relation() != sel2->relation()
    584             || sel1->m_match != sel2->m_match
    585             || sel1->value() != sel2->value()
    586             || sel1->pseudoType() != sel2->pseudoType()
    587             || sel1->argument() != sel2->argument()) {
    588             return false;
    589         }
    590         if (sel1->m_match == Tag) {
    591             if (sel1->tagQName() != sel2->tagQName())
    592                 return false;
    593         }
    594         sel1 = sel1->tagHistory();
    595         sel2 = sel2->tagHistory();
    596     }
    597 
    598     if (sel1 || sel2)
    599         return false;
    600 
    601     return true;
    602 }
    603 
    604 String CSSSelector::selectorText(const String& rightSide) const
    605 {
    606     StringBuilder str;
    607 
    608     if (m_match == CSSSelector::Tag && !m_tagIsForNamespaceRule) {
    609         if (tagQName().prefix().isNull())
    610             str.append(tagQName().localName());
    611         else {
    612             str.append(tagQName().prefix().string());
    613             str.append('|');
    614             str.append(tagQName().localName());
    615         }
    616     }
    617 
    618     const CSSSelector* cs = this;
    619     while (true) {
    620         if (cs->m_match == CSSSelector::Id) {
    621             str.append('#');
    622             serializeIdentifier(cs->value(), str);
    623         } else if (cs->m_match == CSSSelector::Class) {
    624             str.append('.');
    625             serializeIdentifier(cs->value(), str);
    626         } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) {
    627             str.append(':');
    628             str.append(cs->value());
    629 
    630             switch (cs->pseudoType()) {
    631             case PseudoNot:
    632                 ASSERT(cs->selectorList());
    633                 str.append(cs->selectorList()->first()->selectorText());
    634                 str.append(')');
    635                 break;
    636             case PseudoLang:
    637             case PseudoNthChild:
    638             case PseudoNthLastChild:
    639             case PseudoNthOfType:
    640             case PseudoNthLastOfType:
    641                 str.append(cs->argument());
    642                 str.append(')');
    643                 break;
    644             case PseudoAny: {
    645                 const CSSSelector* firstSubSelector = cs->selectorList()->first();
    646                 for (const CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) {
    647                     if (subSelector != firstSubSelector)
    648                         str.append(',');
    649                     str.append(subSelector->selectorText());
    650                 }
    651                 str.append(')');
    652                 break;
    653             }
    654             case PseudoHost: {
    655                 if (cs->selectorList()) {
    656                     const CSSSelector* firstSubSelector = cs->selectorList()->first();
    657                     for (const CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) {
    658                         if (subSelector != firstSubSelector)
    659                             str.append(',');
    660                         str.append(subSelector->selectorText());
    661                     }
    662                     str.append(')');
    663                 }
    664                 break;
    665             }
    666             default:
    667                 break;
    668             }
    669         } else if (cs->m_match == CSSSelector::PseudoElement) {
    670             str.appendLiteral("::");
    671             str.append(cs->value());
    672 
    673             switch (cs->pseudoType()) {
    674             case PseudoPart:
    675                 str.append(cs->argument());
    676                 str.append(')');
    677                 break;
    678             case PseudoContent:
    679                 if (cs->relation() == CSSSelector::SubSelector && cs->tagHistory())
    680                     return cs->tagHistory()->selectorText() + str.toString() + rightSide;
    681                 break;
    682             default:
    683                 break;
    684             }
    685         } else if (cs->isAttributeSelector()) {
    686             str.append('[');
    687             const AtomicString& prefix = cs->attribute().prefix();
    688             if (!prefix.isNull()) {
    689                 str.append(prefix);
    690                 str.append("|");
    691             }
    692             str.append(cs->attribute().localName());
    693             switch (cs->m_match) {
    694                 case CSSSelector::Exact:
    695                     str.append('=');
    696                     break;
    697                 case CSSSelector::Set:
    698                     // set has no operator or value, just the attrName
    699                     str.append(']');
    700                     break;
    701                 case CSSSelector::List:
    702                     str.appendLiteral("~=");
    703                     break;
    704                 case CSSSelector::Hyphen:
    705                     str.appendLiteral("|=");
    706                     break;
    707                 case CSSSelector::Begin:
    708                     str.appendLiteral("^=");
    709                     break;
    710                 case CSSSelector::End:
    711                     str.appendLiteral("$=");
    712                     break;
    713                 case CSSSelector::Contain:
    714                     str.appendLiteral("*=");
    715                     break;
    716                 default:
    717                     break;
    718             }
    719             if (cs->m_match != CSSSelector::Set) {
    720                 serializeString(cs->value(), str);
    721                 str.append(']');
    722             }
    723         }
    724         if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
    725             break;
    726         cs = cs->tagHistory();
    727     }
    728 
    729     if (const CSSSelector* tagHistory = cs->tagHistory()) {
    730         switch (cs->relation()) {
    731         case CSSSelector::Descendant:
    732             if (cs->relationIsAffectedByPseudoContent() && tagHistory->pseudoType() != CSSSelector::PseudoContent)
    733                 return tagHistory->selectorText("::-webkit-distributed(" + str.toString() + rightSide + ")");
    734             return tagHistory->selectorText(" " + str.toString() + rightSide);
    735         case CSSSelector::Child:
    736             if (cs->relationIsAffectedByPseudoContent() && tagHistory->pseudoType() != CSSSelector::PseudoContent)
    737                 return tagHistory->selectorText("::-webkit-distributed(> " + str.toString() + rightSide + ")");
    738             return tagHistory->selectorText(" > " + str.toString() + rightSide);
    739         case CSSSelector::DirectAdjacent:
    740             return tagHistory->selectorText(" + " + str.toString() + rightSide);
    741         case CSSSelector::IndirectAdjacent:
    742             return tagHistory->selectorText(" ~ " + str.toString() + rightSide);
    743         case CSSSelector::SubSelector:
    744             ASSERT_NOT_REACHED();
    745         case CSSSelector::ShadowPseudo:
    746             return tagHistory->selectorText(str.toString() + rightSide);
    747         }
    748     }
    749     return str.toString() + rightSide;
    750 }
    751 
    752 void CSSSelector::setAttribute(const QualifiedName& value)
    753 {
    754     createRareData();
    755     m_data.m_rareData->m_attribute = value;
    756 }
    757 
    758 void CSSSelector::setArgument(const AtomicString& value)
    759 {
    760     createRareData();
    761     m_data.m_rareData->m_argument = value;
    762 }
    763 
    764 void CSSSelector::setSelectorList(PassOwnPtr<CSSSelectorList> selectorList)
    765 {
    766     createRareData();
    767     m_data.m_rareData->m_selectorList = selectorList;
    768 }
    769 
    770 void CSSSelector::setMatchUserAgentOnly()
    771 {
    772     createRareData();
    773     m_data.m_rareData->m_matchUserAgentOnly = true;
    774 }
    775 
    776 static bool validateSubSelector(const CSSSelector* selector)
    777 {
    778     switch (selector->m_match) {
    779     case CSSSelector::Tag:
    780     case CSSSelector::Id:
    781     case CSSSelector::Class:
    782     case CSSSelector::Exact:
    783     case CSSSelector::Set:
    784     case CSSSelector::List:
    785     case CSSSelector::Hyphen:
    786     case CSSSelector::Contain:
    787     case CSSSelector::Begin:
    788     case CSSSelector::End:
    789         return true;
    790     case CSSSelector::PseudoElement:
    791         return false;
    792     case CSSSelector::PagePseudoClass:
    793     case CSSSelector::PseudoClass:
    794         break;
    795     }
    796 
    797     switch (selector->pseudoType()) {
    798     case CSSSelector::PseudoEmpty:
    799     case CSSSelector::PseudoLink:
    800     case CSSSelector::PseudoVisited:
    801     case CSSSelector::PseudoTarget:
    802     case CSSSelector::PseudoEnabled:
    803     case CSSSelector::PseudoDisabled:
    804     case CSSSelector::PseudoChecked:
    805     case CSSSelector::PseudoIndeterminate:
    806     case CSSSelector::PseudoNthChild:
    807     case CSSSelector::PseudoNthLastChild:
    808     case CSSSelector::PseudoNthOfType:
    809     case CSSSelector::PseudoNthLastOfType:
    810     case CSSSelector::PseudoFirstChild:
    811     case CSSSelector::PseudoLastChild:
    812     case CSSSelector::PseudoFirstOfType:
    813     case CSSSelector::PseudoLastOfType:
    814     case CSSSelector::PseudoOnlyOfType:
    815         return true;
    816     default:
    817         return false;
    818     }
    819 }
    820 
    821 bool CSSSelector::isCompound() const
    822 {
    823     if (!validateSubSelector(this))
    824         return false;
    825 
    826     const CSSSelector* prevSubSelector = this;
    827     const CSSSelector* subSelector = tagHistory();
    828 
    829     while (subSelector) {
    830         if (prevSubSelector->relation() != CSSSelector::SubSelector)
    831             return false;
    832         if (!validateSubSelector(subSelector))
    833             return false;
    834 
    835         prevSubSelector = subSelector;
    836         subSelector = subSelector->tagHistory();
    837     }
    838 
    839     return true;
    840 }
    841 
    842 bool CSSSelector::parseNth() const
    843 {
    844     if (!m_hasRareData)
    845         return false;
    846     if (m_parsedNth)
    847         return true;
    848     m_parsedNth = m_data.m_rareData->parseNth();
    849     return m_parsedNth;
    850 }
    851 
    852 bool CSSSelector::matchNth(int count) const
    853 {
    854     ASSERT(m_hasRareData);
    855     return m_data.m_rareData->matchNth(count);
    856 }
    857 
    858 CSSSelector::RareData::RareData(PassRefPtr<StringImpl> value)
    859     : m_value(value.leakRef())
    860     , m_a(0)
    861     , m_b(0)
    862     , m_attribute(anyQName())
    863     , m_argument(nullAtom)
    864     , m_matchUserAgentOnly(0)
    865 {
    866 }
    867 
    868 CSSSelector::RareData::~RareData()
    869 {
    870     if (m_value)
    871         m_value->deref();
    872 }
    873 
    874 // a helper function for parsing nth-arguments
    875 bool CSSSelector::RareData::parseNth()
    876 {
    877     String argument = m_argument.lower();
    878 
    879     if (argument.isEmpty())
    880         return false;
    881 
    882     m_a = 0;
    883     m_b = 0;
    884     if (argument == "odd") {
    885         m_a = 2;
    886         m_b = 1;
    887     } else if (argument == "even") {
    888         m_a = 2;
    889         m_b = 0;
    890     } else {
    891         size_t n = argument.find('n');
    892         if (n != notFound) {
    893             if (argument[0] == '-') {
    894                 if (n == 1)
    895                     m_a = -1; // -n == -1n
    896                 else
    897                     m_a = argument.substring(0, n).toInt();
    898             } else if (!n)
    899                 m_a = 1; // n == 1n
    900             else
    901                 m_a = argument.substring(0, n).toInt();
    902 
    903             size_t p = argument.find('+', n);
    904             if (p != notFound)
    905                 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
    906             else {
    907                 p = argument.find('-', n);
    908                 if (p != notFound)
    909                     m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
    910             }
    911         } else
    912             m_b = argument.toInt();
    913     }
    914     return true;
    915 }
    916 
    917 // a helper function for checking nth-arguments
    918 bool CSSSelector::RareData::matchNth(int count)
    919 {
    920     if (!m_a)
    921         return count == m_b;
    922     else if (m_a > 0) {
    923         if (count < m_b)
    924             return false;
    925         return (count - m_b) % m_a == 0;
    926     } else {
    927         if (count > m_b)
    928             return false;
    929         return (m_b - count) % (-m_a) == 0;
    930     }
    931 }
    932 
    933 } // namespace WebCore
    934