Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / CSSSelector.h
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
30 namespace WebCore {
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             Exact, // Example: E[foo="bar"]
114             Set, // Example: E[foo]
115             List, // Example: E[foo~="bar"]
116             Hyphen, // Example: E[foo|="bar"]
117             PseudoClass, // Example:  :nth-child(2)
118             PseudoElement, // Example: ::first-line
119             Contain, // css3: E[foo*="bar"]
120             Begin, // css3: E[foo^="bar"]
121             End, // css3: E[foo$="bar"]
122             PagePseudoClass // ??
123         };
124
125         enum Relation {
126             Descendant = 0, // "Space" combinator
127             Child, // > combinator
128             DirectAdjacent, // + combinator
129             IndirectAdjacent, // ~ combinator
130             SubSelector, // "No space" combinator
131             ShadowPseudo, // Special case of shadow DOM pseudo elements / shadow pseudo element
132             ShadowDeep // /shadow-deep/ combinator
133         };
134
135         enum PseudoType {
136             PseudoNotParsed = 0,
137             PseudoUnknown,
138             PseudoEmpty,
139             PseudoFirstChild,
140             PseudoFirstOfType,
141             PseudoLastChild,
142             PseudoLastOfType,
143             PseudoOnlyChild,
144             PseudoOnlyOfType,
145             PseudoFirstLine,
146             PseudoFirstLetter,
147             PseudoNthChild,
148             PseudoNthOfType,
149             PseudoNthLastChild,
150             PseudoNthLastOfType,
151             PseudoLink,
152             PseudoVisited,
153             PseudoAny,
154             PseudoAnyLink,
155             PseudoAutofill,
156             PseudoHover,
157             PseudoDrag,
158             PseudoFocus,
159             PseudoActive,
160             PseudoChecked,
161             PseudoEnabled,
162             PseudoFullPageMedia,
163             PseudoDefault,
164             PseudoDisabled,
165             PseudoOptional,
166             PseudoRequired,
167             PseudoReadOnly,
168             PseudoReadWrite,
169             PseudoValid,
170             PseudoInvalid,
171             PseudoIndeterminate,
172             PseudoTarget,
173             PseudoBefore,
174             PseudoAfter,
175             PseudoBackdrop,
176             PseudoLang,
177             PseudoNot,
178             PseudoResizer,
179             PseudoRoot,
180             PseudoScope,
181             PseudoScrollbar,
182             PseudoScrollbarBack,
183             PseudoScrollbarButton,
184             PseudoScrollbarCorner,
185             PseudoScrollbarForward,
186             PseudoScrollbarThumb,
187             PseudoScrollbarTrack,
188             PseudoScrollbarTrackPiece,
189             PseudoWindowInactive,
190             PseudoCornerPresent,
191             PseudoDecrement,
192             PseudoIncrement,
193             PseudoHorizontal,
194             PseudoVertical,
195             PseudoStart,
196             PseudoEnd,
197             PseudoDoubleButton,
198             PseudoSingleButton,
199             PseudoNoButton,
200             PseudoSelection,
201             PseudoLeftPage,
202             PseudoRightPage,
203             PseudoFirstPage,
204             PseudoFullScreen,
205             PseudoFullScreenDocument,
206             PseudoFullScreenAncestor,
207             PseudoInRange,
208             PseudoOutOfRange,
209             PseudoUserAgentCustomElement,
210             PseudoWebKitCustomElement,
211             PseudoCue,
212             PseudoFutureCue,
213             PseudoPastCue,
214             PseudoUnresolved,
215             PseudoContent,
216             PseudoHost,
217             PseudoHostContext,
218             PseudoShadow
219         };
220
221         enum MarginBoxType {
222             TopLeftCornerMarginBox,
223             TopLeftMarginBox,
224             TopCenterMarginBox,
225             TopRightMarginBox,
226             TopRightCornerMarginBox,
227             BottomLeftCornerMarginBox,
228             BottomLeftMarginBox,
229             BottomCenterMarginBox,
230             BottomRightMarginBox,
231             BottomRightCornerMarginBox,
232             LeftTopMarginBox,
233             LeftMiddleMarginBox,
234             LeftBottomMarginBox,
235             RightTopMarginBox,
236             RightMiddleMarginBox,
237             RightBottomMarginBox,
238         };
239
240         PseudoType pseudoType() const
241         {
242             if (m_pseudoType == PseudoNotParsed)
243                 extractPseudoType();
244             return static_cast<PseudoType>(m_pseudoType);
245         }
246
247         static PseudoType parsePseudoType(const AtomicString&);
248         static PseudoId pseudoId(PseudoType);
249
250         // Selectors are kept in an array by CSSSelectorList. The next component of the selector is
251         // the next item in the array.
252         const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); }
253
254         const QualifiedName& tagQName() const;
255         const AtomicString& value() const;
256
257         // WARNING: Use of QualifiedName by attribute() is a lie.
258         // attribute() will return a QualifiedName with prefix and namespaceURI
259         // set to starAtom to mean "matches any namespace". Be very careful
260         // how you use the returned QualifiedName.
261         // http://www.w3.org/TR/css3-selectors/#attrnmsp
262         const QualifiedName& attribute() const;
263         // Returns the argument of a parameterized selector. For example, nth-child(2) would have an argument of 2.
264         const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
265         const CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; }
266
267 #ifndef NDEBUG
268         void show() const;
269         void show(int indent) const;
270 #endif
271
272         void setValue(const AtomicString&);
273         void setAttribute(const QualifiedName&);
274         void setArgument(const AtomicString&);
275         void setSelectorList(PassOwnPtr<CSSSelectorList>);
276         void setMatchUserAgentOnly();
277
278         bool parseNth() const;
279         bool matchNth(int count) const;
280
281         bool matchesPseudoElement() const;
282         bool isUnknownPseudoElement() const;
283         bool isCustomPseudoElement() const;
284         bool isDirectAdjacentSelector() const { return m_relation == DirectAdjacent; }
285         bool isSiblingSelector() const;
286         bool isAttributeSelector() const;
287         bool isContentPseudoElement() const;
288         bool isShadowPseudoElement() const;
289         bool isHostPseudoClass() const;
290
291         // FIXME: selectors with no tagHistory() get a relation() of Descendant (and sometimes even SubSelector). It should instead be
292         // None.
293         Relation relation() const { return static_cast<Relation>(m_relation); }
294
295         bool isLastInSelectorList() const { return m_isLastInSelectorList; }
296         void setLastInSelectorList() { m_isLastInSelectorList = true; }
297         bool isLastInTagHistory() const { return m_isLastInTagHistory; }
298         void setNotLastInTagHistory() { m_isLastInTagHistory = false; }
299
300         // http://dev.w3.org/csswg/selectors4/#compound
301         bool isCompound() const;
302
303         bool isForPage() const { return m_isForPage; }
304         void setForPage() { m_isForPage = true; }
305
306         bool relationIsAffectedByPseudoContent() const { return m_relationIsAffectedByPseudoContent; }
307         void setRelationIsAffectedByPseudoContent() { m_relationIsAffectedByPseudoContent = true; }
308
309         unsigned m_relation           : 3; // enum Relation
310         mutable unsigned m_match      : 4; // enum Match
311         mutable unsigned m_pseudoType : 8; // PseudoType
312
313     private:
314         mutable unsigned m_parsedNth      : 1; // Used for :nth-*
315         unsigned m_isLastInSelectorList   : 1;
316         unsigned m_isLastInTagHistory     : 1;
317         unsigned m_hasRareData            : 1;
318         unsigned m_isForPage              : 1;
319         unsigned m_tagIsForNamespaceRule  : 1;
320         unsigned m_relationIsAffectedByPseudoContent  : 1;
321
322         unsigned specificityForOneSelector() const;
323         unsigned specificityForPage() const;
324         void extractPseudoType() const;
325
326         // Hide.
327         CSSSelector& operator=(const CSSSelector&);
328
329         struct RareData : public RefCounted<RareData> {
330             static PassRefPtr<RareData> create(const AtomicString& value) { return adoptRef(new RareData(value)); }
331             ~RareData();
332
333             bool parseNth();
334             bool matchNth(int count);
335
336             AtomicString m_value;
337             int m_a; // Used for :nth-*
338             int m_b; // Used for :nth-*
339             QualifiedName m_attribute; // used for attribute selector
340             AtomicString m_argument; // Used for :contains, :lang, :nth-*
341             OwnPtr<CSSSelectorList> m_selectorList; // Used for :-webkit-any and :not
342
343         private:
344             RareData(const AtomicString& value);
345         };
346         void createRareData();
347
348         union DataUnion {
349             DataUnion() : m_value(0) { }
350             StringImpl* m_value;
351             QualifiedName::QualifiedNameImpl* m_tagQName;
352             RareData* m_rareData;
353         } m_data;
354     };
355
356 inline const QualifiedName& CSSSelector::attribute() const
357 {
358     ASSERT(isAttributeSelector());
359     ASSERT(m_hasRareData);
360     return m_data.m_rareData->m_attribute;
361 }
362
363 inline bool CSSSelector::matchesPseudoElement() const
364 {
365     if (m_pseudoType == PseudoUnknown)
366         extractPseudoType();
367     return m_match == PseudoElement;
368 }
369
370 inline bool CSSSelector::isUnknownPseudoElement() const
371 {
372     return m_match == PseudoElement && m_pseudoType == PseudoUnknown;
373 }
374
375 inline bool CSSSelector::isCustomPseudoElement() const
376 {
377     return m_match == PseudoElement && (m_pseudoType == PseudoUserAgentCustomElement || m_pseudoType == PseudoWebKitCustomElement);
378 }
379
380 inline bool CSSSelector::isHostPseudoClass() const
381 {
382     return m_match == PseudoClass && (m_pseudoType == PseudoHost || m_pseudoType == PseudoHostContext);
383 }
384
385 inline bool CSSSelector::isSiblingSelector() const
386 {
387     PseudoType type = pseudoType();
388     return m_relation == DirectAdjacent
389         || m_relation == IndirectAdjacent
390         || type == PseudoEmpty
391         || type == PseudoFirstChild
392         || type == PseudoFirstOfType
393         || type == PseudoLastChild
394         || type == PseudoLastOfType
395         || type == PseudoOnlyChild
396         || type == PseudoOnlyOfType
397         || type == PseudoNthChild
398         || type == PseudoNthOfType
399         || type == PseudoNthLastChild
400         || type == PseudoNthLastOfType;
401 }
402
403 inline bool CSSSelector::isAttributeSelector() const
404 {
405     return m_match == CSSSelector::Exact
406         || m_match ==  CSSSelector::Set
407         || m_match == CSSSelector::List
408         || m_match == CSSSelector::Hyphen
409         || m_match == CSSSelector::Contain
410         || m_match == CSSSelector::Begin
411         || m_match == CSSSelector::End;
412 }
413
414 inline bool CSSSelector::isContentPseudoElement() const
415 {
416     return m_match == PseudoElement && pseudoType() == PseudoContent;
417 }
418
419 inline bool CSSSelector::isShadowPseudoElement() const
420 {
421     return m_match == PseudoElement && pseudoType() == PseudoShadow;
422 }
423
424 inline void CSSSelector::setValue(const AtomicString& value)
425 {
426     ASSERT(m_match != Tag);
427     ASSERT(m_pseudoType == PseudoNotParsed);
428     // Need to do ref counting manually for the union.
429     if (m_hasRareData) {
430         m_data.m_rareData->m_value = value;
431         return;
432     }
433     if (m_data.m_value)
434         m_data.m_value->deref();
435     m_data.m_value = value.impl();
436     m_data.m_value->ref();
437 }
438
439 inline CSSSelector::CSSSelector()
440     : m_relation(Descendant)
441     , m_match(Unknown)
442     , m_pseudoType(PseudoNotParsed)
443     , m_parsedNth(false)
444     , m_isLastInSelectorList(false)
445     , m_isLastInTagHistory(true)
446     , m_hasRareData(false)
447     , m_isForPage(false)
448     , m_tagIsForNamespaceRule(false)
449     , m_relationIsAffectedByPseudoContent(false)
450 {
451 }
452
453 inline CSSSelector::CSSSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
454     : m_relation(Descendant)
455     , m_match(Tag)
456     , m_pseudoType(PseudoNotParsed)
457     , m_parsedNth(false)
458     , m_isLastInSelectorList(false)
459     , m_isLastInTagHistory(true)
460     , m_hasRareData(false)
461     , m_isForPage(false)
462     , m_tagIsForNamespaceRule(tagIsForNamespaceRule)
463     , m_relationIsAffectedByPseudoContent(false)
464 {
465     m_data.m_tagQName = tagQName.impl();
466     m_data.m_tagQName->ref();
467 }
468
469 inline CSSSelector::CSSSelector(const CSSSelector& o)
470     : m_relation(o.m_relation)
471     , m_match(o.m_match)
472     , m_pseudoType(o.m_pseudoType)
473     , m_parsedNth(o.m_parsedNth)
474     , m_isLastInSelectorList(o.m_isLastInSelectorList)
475     , m_isLastInTagHistory(o.m_isLastInTagHistory)
476     , m_hasRareData(o.m_hasRareData)
477     , m_isForPage(o.m_isForPage)
478     , m_tagIsForNamespaceRule(o.m_tagIsForNamespaceRule)
479     , m_relationIsAffectedByPseudoContent(o.m_relationIsAffectedByPseudoContent)
480 {
481     if (o.m_match == Tag) {
482         m_data.m_tagQName = o.m_data.m_tagQName;
483         m_data.m_tagQName->ref();
484     } else if (o.m_hasRareData) {
485         m_data.m_rareData = o.m_data.m_rareData;
486         m_data.m_rareData->ref();
487     } else if (o.m_data.m_value) {
488         m_data.m_value = o.m_data.m_value;
489         m_data.m_value->ref();
490     }
491 }
492
493 inline CSSSelector::~CSSSelector()
494 {
495     if (m_match == Tag)
496         m_data.m_tagQName->deref();
497     else if (m_hasRareData)
498         m_data.m_rareData->deref();
499     else if (m_data.m_value)
500         m_data.m_value->deref();
501 }
502
503 inline const QualifiedName& CSSSelector::tagQName() const
504 {
505     ASSERT(m_match == Tag);
506     return *reinterpret_cast<const QualifiedName*>(&m_data.m_tagQName);
507 }
508
509 inline const AtomicString& CSSSelector::value() const
510 {
511     ASSERT(m_match != Tag);
512     if (m_hasRareData)
513         return m_data.m_rareData->m_value;
514     // AtomicString is really just a StringImpl* so the cast below is safe.
515     // FIXME: Perhaps call sites could be changed to accept StringImpl?
516     return *reinterpret_cast<const AtomicString*>(&m_data.m_value);
517 }
518
519 } // namespace WebCore
520
521 #endif // CSSSelector_h