1/*
2 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 *               1999 Waldo Bastian (bastian@kde.org)
4 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#ifndef CSSSelector_h
23#define CSSSelector_h
24
25#include "core/dom/QualifiedName.h"
26#include "core/rendering/style/RenderStyleConstants.h"
27#include "wtf/OwnPtr.h"
28#include "wtf/PassOwnPtr.h"
29
30namespace blink {
31    class CSSSelectorList;
32
33    // This class represents a selector for a StyleRule.
34
35    // CSS selector representation is somewhat complicated and subtle. A representative list of selectors is
36    // in CSSSelectorTest; run it in a debug build to see useful debugging output.
37    //
38    // ** tagHistory() and relation():
39    //
40    // Selectors are represented as a linked list of simple selectors (defined more or less according to
41    // http://www.w3.org/TR/css3-selectors/#simple-selectors-dfn). The tagHistory() method returns the next
42    // simple selector in the list. The relation() method returns the relationship of the current simple selector to
43    // the one in tagHistory(). For example, the CSS selector .a.b #c is represented as:
44    //
45    // selectorText(): .a.b #c
46    // --> (relation == Descendant)
47    //   selectorText(): .a.b
48    //   --> (relation == SubSelector)
49    //     selectorText(): .b
50    //
51    // Note that currently a bare selector such as ".a" has a relation() of Descendant. This is a bug - instead the relation should be
52    // "None".
53    //
54    // The order of tagHistory() varies depending on the situation.
55    // * Relations using combinators (http://www.w3.org/TR/css3-selectors/#combinators), such as descendant, sibling, etc., are parsed
56    //   right-to-left (in the example above, this is why .c is earlier in the tagHistory() chain than .a.b).
57    // * SubSelector relations are parsed left-to-right in most cases (such as the .a.b example above); a counter-example is the
58    //   ::content pseudo-element. Most (all?) other pseudo elements and pseudo classes are parsed left-to-right.
59    // * ShadowPseudo relations are parsed right-to-left. Example: summary::-webkit-details-marker is parsed as:
60    //   selectorText(): summary::-webkit-details-marker
61    //    --> (relation == ShadowPseudo)
62    //     selectorText(): summary
63    //
64    // ** match():
65    //
66    // The match of the current simple selector tells us the type of selector, such as class, id, tagname, or pseudo-class.
67    // Inline comments in the Match enum give examples of when each type would occur.
68    //
69    // ** value(), attribute():
70    //
71    // value() tells you the value of the simple selector. For example, for class selectors, value() will tell you the class string,
72    // and for id selectors it will tell you the id(). See below for the special case of attribute selectors.
73    //
74    // ** Attribute selectors.
75    //
76    // Attribute selectors return the attribute name in the attribute() method. The value() method returns the value matched against
77    // in case of selectors like [attr="value"].
78    //
79    // ** isCustomPseudoElement():
80    //
81    // It appears this is used only for pseudo elements that appear in user-agent shadow DOM. They are not exposed to author-created
82    // shadow DOM.
83
84    class CSSSelector {
85        WTF_MAKE_FAST_ALLOCATED;
86    public:
87        CSSSelector();
88        CSSSelector(const CSSSelector&);
89        explicit CSSSelector(const QualifiedName&, bool tagIsForNamespaceRule = false);
90
91        ~CSSSelector();
92
93        /**
94         * Re-create selector text from selector's data
95         */
96        String selectorText(const String& = "") const;
97
98        // checks if the 2 selectors (including sub selectors) agree.
99        bool operator==(const CSSSelector&) const;
100
101        // tag == -1 means apply to all elements (Selector = *)
102
103        // http://www.w3.org/TR/css3-selectors/#specificity
104        // We use 256 as the base of the specificity number system.
105        unsigned specificity() const;
106
107        /* how the attribute value has to match.... Default is Exact */
108        enum Match {
109            Unknown = 0,
110            Tag, // Example: div
111            Id, // Example: #id
112            Class, // example: .class
113            PseudoClass, // Example:  :nth-child(2)
114            PseudoElement, // Example: ::first-line
115            PagePseudoClass, // ??
116            Exact, // Example: E[foo="bar"]
117            Set, // Example: E[foo]
118            Hyphen, // Example: E[foo|="bar"]
119            List, // Example: E[foo~="bar"]
120            Contain, // css3: E[foo*="bar"]
121            Begin, // css3: E[foo^="bar"]
122            End, // css3: E[foo$="bar"]
123            FirstAttributeSelectorMatch = Exact,
124        };
125
126        enum Relation {
127            Descendant = 0, // "Space" combinator
128            Child, // > combinator
129            DirectAdjacent, // + combinator
130            IndirectAdjacent, // ~ combinator
131            SubSelector, // "No space" combinator
132            ShadowPseudo, // Special case of shadow DOM pseudo elements / shadow pseudo element
133            ShadowDeep // /deep/ combinator
134        };
135
136        enum PseudoType {
137            PseudoNotParsed = 0,
138            PseudoUnknown,
139            PseudoEmpty,
140            PseudoFirstChild,
141            PseudoFirstOfType,
142            PseudoLastChild,
143            PseudoLastOfType,
144            PseudoOnlyChild,
145            PseudoOnlyOfType,
146            PseudoFirstLine,
147            PseudoFirstLetter,
148            PseudoNthChild,
149            PseudoNthOfType,
150            PseudoNthLastChild,
151            PseudoNthLastOfType,
152            PseudoLink,
153            PseudoVisited,
154            PseudoAny,
155            PseudoAnyLink,
156            PseudoAutofill,
157            PseudoHover,
158            PseudoDrag,
159            PseudoFocus,
160            PseudoActive,
161            PseudoChecked,
162            PseudoEnabled,
163            PseudoFullPageMedia,
164            PseudoDefault,
165            PseudoDisabled,
166            PseudoOptional,
167            PseudoRequired,
168            PseudoReadOnly,
169            PseudoReadWrite,
170            PseudoValid,
171            PseudoInvalid,
172            PseudoIndeterminate,
173            PseudoTarget,
174            PseudoBefore,
175            PseudoAfter,
176            PseudoBackdrop,
177            PseudoLang,
178            PseudoNot,
179            PseudoResizer,
180            PseudoRoot,
181            PseudoScope,
182            PseudoScrollbar,
183            PseudoScrollbarBack,
184            PseudoScrollbarButton,
185            PseudoScrollbarCorner,
186            PseudoScrollbarForward,
187            PseudoScrollbarThumb,
188            PseudoScrollbarTrack,
189            PseudoScrollbarTrackPiece,
190            PseudoWindowInactive,
191            PseudoCornerPresent,
192            PseudoDecrement,
193            PseudoIncrement,
194            PseudoHorizontal,
195            PseudoVertical,
196            PseudoStart,
197            PseudoEnd,
198            PseudoDoubleButton,
199            PseudoSingleButton,
200            PseudoNoButton,
201            PseudoSelection,
202            PseudoLeftPage,
203            PseudoRightPage,
204            PseudoFirstPage,
205            PseudoFullScreen,
206            PseudoFullScreenDocument,
207            PseudoFullScreenAncestor,
208            PseudoInRange,
209            PseudoOutOfRange,
210            PseudoUserAgentCustomElement,
211            PseudoWebKitCustomElement,
212            PseudoCue,
213            PseudoFutureCue,
214            PseudoPastCue,
215            PseudoUnresolved,
216            PseudoContent,
217            PseudoHost,
218            PseudoHostContext,
219            PseudoShadow,
220            PseudoSpatialNavigationFocus,
221            PseudoListBox
222        };
223
224        enum MarginBoxType {
225            TopLeftCornerMarginBox,
226            TopLeftMarginBox,
227            TopCenterMarginBox,
228            TopRightMarginBox,
229            TopRightCornerMarginBox,
230            BottomLeftCornerMarginBox,
231            BottomLeftMarginBox,
232            BottomCenterMarginBox,
233            BottomRightMarginBox,
234            BottomRightCornerMarginBox,
235            LeftTopMarginBox,
236            LeftMiddleMarginBox,
237            LeftBottomMarginBox,
238            RightTopMarginBox,
239            RightMiddleMarginBox,
240            RightBottomMarginBox,
241        };
242
243        enum AttributeMatchType {
244            CaseSensitive,
245            CaseInsensitive,
246        };
247
248        PseudoType pseudoType() const
249        {
250            if (m_pseudoType == PseudoNotParsed)
251                extractPseudoType();
252            return static_cast<PseudoType>(m_pseudoType);
253        }
254
255        static PseudoType parsePseudoType(const AtomicString&, bool hasArguments);
256        static PseudoId pseudoId(PseudoType);
257
258        // Selectors are kept in an array by CSSSelectorList. The next component of the selector is
259        // the next item in the array.
260        const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); }
261
262        const QualifiedName& tagQName() const;
263        const AtomicString& value() const;
264
265        // WARNING: Use of QualifiedName by attribute() is a lie.
266        // attribute() will return a QualifiedName with prefix and namespaceURI
267        // set to starAtom to mean "matches any namespace". Be very careful
268        // how you use the returned QualifiedName.
269        // http://www.w3.org/TR/css3-selectors/#attrnmsp
270        const QualifiedName& attribute() const;
271        AttributeMatchType attributeMatchType() const;
272        // Returns the argument of a parameterized selector. For example, nth-child(2) would have an argument of 2.
273        const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
274        const CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; }
275
276#ifndef NDEBUG
277        void show() const;
278        void show(int indent) const;
279#endif
280
281        void setValue(const AtomicString&);
282        void setAttribute(const QualifiedName&, AttributeMatchType);
283        void setArgument(const AtomicString&);
284        void setSelectorList(PassOwnPtr<CSSSelectorList>);
285        void setMatchUserAgentOnly();
286
287        bool parseNth() const;
288        bool matchNth(int count) const;
289
290        bool matchesPseudoElement() const;
291        bool isCustomPseudoElement() const;
292        bool isDirectAdjacentSelector() const { return m_relation == DirectAdjacent; }
293        bool isSiblingSelector() const;
294        bool isAttributeSelector() const;
295        bool isContentPseudoElement() const;
296        bool isShadowPseudoElement() const;
297        bool isHostPseudoClass() const;
298
299        // FIXME: selectors with no tagHistory() get a relation() of Descendant (and sometimes even SubSelector). It should instead be
300        // None.
301        Relation relation() const { return static_cast<Relation>(m_relation); }
302        void setRelation(Relation relation)
303        {
304            m_relation = relation;
305            ASSERT(static_cast<Relation>(m_relation) == relation); // using a bitfield.
306        }
307
308        Match match() const { return static_cast<Match>(m_match); }
309        void setMatch(Match match)
310        {
311            m_match = match;
312            ASSERT(static_cast<Match>(m_match) == match); // using a bitfield.
313        }
314
315        bool isLastInSelectorList() const { return m_isLastInSelectorList; }
316        void setLastInSelectorList() { m_isLastInSelectorList = true; }
317        bool isLastInTagHistory() const { return m_isLastInTagHistory; }
318        void setNotLastInTagHistory() { m_isLastInTagHistory = false; }
319
320        // http://dev.w3.org/csswg/selectors4/#compound
321        bool isCompound() const;
322
323        bool isForPage() const { return m_isForPage; }
324        void setForPage() { m_isForPage = true; }
325
326        bool relationIsAffectedByPseudoContent() const { return m_relationIsAffectedByPseudoContent; }
327        void setRelationIsAffectedByPseudoContent() { m_relationIsAffectedByPseudoContent = true; }
328
329    private:
330        unsigned m_relation           : 3; // enum Relation
331        mutable unsigned m_match      : 4; // enum Match
332        mutable unsigned m_pseudoType : 8; // PseudoType
333        mutable unsigned m_parsedNth      : 1; // Used for :nth-*
334        unsigned m_isLastInSelectorList   : 1;
335        unsigned m_isLastInTagHistory     : 1;
336        unsigned m_hasRareData            : 1;
337        unsigned m_isForPage              : 1;
338        unsigned m_tagIsForNamespaceRule  : 1;
339        unsigned m_relationIsAffectedByPseudoContent  : 1;
340
341        unsigned specificityForOneSelector() const;
342        unsigned specificityForPage() const;
343        void extractPseudoType() const;
344
345        // Hide.
346        CSSSelector& operator=(const CSSSelector&);
347
348        struct RareData : public RefCounted<RareData> {
349            static PassRefPtr<RareData> create(const AtomicString& value) { return adoptRef(new RareData(value)); }
350            ~RareData();
351
352            bool parseNth();
353            bool matchNth(int count);
354            int nthAValue() const { return m_bits.m_nth.m_a; }
355            void setNthAValue(int nthA) { m_bits.m_nth.m_a = nthA; }
356            int nthBValue() const { return m_bits.m_nth.m_b; }
357            void setNthBValue(int nthB) { m_bits.m_nth.m_b = nthB; }
358
359            AtomicString m_value;
360            union {
361                struct {
362                    int m_a; // Used for :nth-*
363                    int m_b; // Used for :nth-*
364                } m_nth;
365                AttributeMatchType m_attributeMatchType; // used for attribute selector (with value)
366            } m_bits;
367            QualifiedName m_attribute; // used for attribute selector
368            AtomicString m_argument; // Used for :contains, :lang, :nth-*
369            OwnPtr<CSSSelectorList> m_selectorList; // Used for :-webkit-any and :not
370
371        private:
372            RareData(const AtomicString& value);
373        };
374        void createRareData();
375
376        union DataUnion {
377            DataUnion() : m_value(0) { }
378            StringImpl* m_value;
379            QualifiedName::QualifiedNameImpl* m_tagQName;
380            RareData* m_rareData;
381        } m_data;
382    };
383
384inline const QualifiedName& CSSSelector::attribute() const
385{
386    ASSERT(isAttributeSelector());
387    ASSERT(m_hasRareData);
388    return m_data.m_rareData->m_attribute;
389}
390
391inline CSSSelector::AttributeMatchType CSSSelector::attributeMatchType() const
392{
393    ASSERT(isAttributeSelector());
394    ASSERT(m_hasRareData);
395    return m_data.m_rareData->m_bits.m_attributeMatchType;
396}
397
398inline bool CSSSelector::matchesPseudoElement() const
399{
400    if (m_pseudoType == PseudoUnknown)
401        extractPseudoType();
402    return m_match == PseudoElement;
403}
404
405inline bool CSSSelector::isCustomPseudoElement() const
406{
407    return m_match == PseudoElement && (m_pseudoType == PseudoUserAgentCustomElement || m_pseudoType == PseudoWebKitCustomElement);
408}
409
410inline bool CSSSelector::isHostPseudoClass() const
411{
412    return m_match == PseudoClass && (m_pseudoType == PseudoHost || m_pseudoType == PseudoHostContext);
413}
414
415inline bool CSSSelector::isSiblingSelector() const
416{
417    PseudoType type = pseudoType();
418    return m_relation == DirectAdjacent
419        || m_relation == IndirectAdjacent
420        || type == PseudoEmpty
421        || type == PseudoFirstChild
422        || type == PseudoFirstOfType
423        || type == PseudoLastChild
424        || type == PseudoLastOfType
425        || type == PseudoOnlyChild
426        || type == PseudoOnlyOfType
427        || type == PseudoNthChild
428        || type == PseudoNthOfType
429        || type == PseudoNthLastChild
430        || type == PseudoNthLastOfType;
431}
432
433inline bool CSSSelector::isAttributeSelector() const
434{
435    return m_match >= FirstAttributeSelectorMatch;
436}
437
438inline bool CSSSelector::isContentPseudoElement() const
439{
440    return m_match == PseudoElement && pseudoType() == PseudoContent;
441}
442
443inline bool CSSSelector::isShadowPseudoElement() const
444{
445    return m_match == PseudoElement && pseudoType() == PseudoShadow;
446}
447
448inline void CSSSelector::setValue(const AtomicString& value)
449{
450    ASSERT(m_match != Tag);
451    ASSERT(m_pseudoType == PseudoNotParsed);
452    // Need to do ref counting manually for the union.
453    if (m_hasRareData) {
454        m_data.m_rareData->m_value = value;
455        return;
456    }
457    if (m_data.m_value)
458        m_data.m_value->deref();
459    m_data.m_value = value.impl();
460    m_data.m_value->ref();
461}
462
463inline CSSSelector::CSSSelector()
464    : m_relation(Descendant)
465    , m_match(Unknown)
466    , m_pseudoType(PseudoNotParsed)
467    , m_parsedNth(false)
468    , m_isLastInSelectorList(false)
469    , m_isLastInTagHistory(true)
470    , m_hasRareData(false)
471    , m_isForPage(false)
472    , m_tagIsForNamespaceRule(false)
473    , m_relationIsAffectedByPseudoContent(false)
474{
475}
476
477inline CSSSelector::CSSSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
478    : m_relation(Descendant)
479    , m_match(Tag)
480    , m_pseudoType(PseudoNotParsed)
481    , m_parsedNth(false)
482    , m_isLastInSelectorList(false)
483    , m_isLastInTagHistory(true)
484    , m_hasRareData(false)
485    , m_isForPage(false)
486    , m_tagIsForNamespaceRule(tagIsForNamespaceRule)
487    , m_relationIsAffectedByPseudoContent(false)
488{
489    m_data.m_tagQName = tagQName.impl();
490    m_data.m_tagQName->ref();
491}
492
493inline CSSSelector::CSSSelector(const CSSSelector& o)
494    : m_relation(o.m_relation)
495    , m_match(o.m_match)
496    , m_pseudoType(o.m_pseudoType)
497    , m_parsedNth(o.m_parsedNth)
498    , m_isLastInSelectorList(o.m_isLastInSelectorList)
499    , m_isLastInTagHistory(o.m_isLastInTagHistory)
500    , m_hasRareData(o.m_hasRareData)
501    , m_isForPage(o.m_isForPage)
502    , m_tagIsForNamespaceRule(o.m_tagIsForNamespaceRule)
503    , m_relationIsAffectedByPseudoContent(o.m_relationIsAffectedByPseudoContent)
504{
505    if (o.m_match == Tag) {
506        m_data.m_tagQName = o.m_data.m_tagQName;
507        m_data.m_tagQName->ref();
508    } else if (o.m_hasRareData) {
509        m_data.m_rareData = o.m_data.m_rareData;
510        m_data.m_rareData->ref();
511    } else if (o.m_data.m_value) {
512        m_data.m_value = o.m_data.m_value;
513        m_data.m_value->ref();
514    }
515}
516
517inline CSSSelector::~CSSSelector()
518{
519    if (m_match == Tag)
520        m_data.m_tagQName->deref();
521    else if (m_hasRareData)
522        m_data.m_rareData->deref();
523    else if (m_data.m_value)
524        m_data.m_value->deref();
525}
526
527inline const QualifiedName& CSSSelector::tagQName() const
528{
529    ASSERT(m_match == Tag);
530    return *reinterpret_cast<const QualifiedName*>(&m_data.m_tagQName);
531}
532
533inline const AtomicString& CSSSelector::value() const
534{
535    ASSERT(m_match != Tag);
536    if (m_hasRareData)
537        return m_data.m_rareData->m_value;
538    // AtomicString is really just a StringImpl* so the cast below is safe.
539    // FIXME: Perhaps call sites could be changed to accept StringImpl?
540    return *reinterpret_cast<const AtomicString*>(&m_data.m_value);
541}
542
543} // namespace blink
544
545#endif // CSSSelector_h
546