Remove excessive include directives from WebCore/css
[WebKit-https.git] / Source / WebCore / 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, 2014 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 #pragma once
23
24 #include "QualifiedName.h"
25 #include "RenderStyleConstants.h"
26
27 namespace WebCore {
28     class CSSSelectorList;
29
30     enum class SelectorSpecificityIncrement {
31         ClassA = 0x10000,
32         ClassB = 0x100,
33         ClassC = 1
34     };
35
36     // this class represents a selector for a StyleRule
37     class CSSSelector {
38         WTF_MAKE_FAST_ALLOCATED;
39     public:
40         CSSSelector();
41         CSSSelector(const CSSSelector&);
42         explicit CSSSelector(const QualifiedName&, bool tagIsForNamespaceRule = false);
43
44         ~CSSSelector();
45
46         /**
47          * Re-create selector text from selector's data
48          */
49         String selectorText(const String& = emptyString()) const;
50
51         // checks if the 2 selectors (including sub selectors) agree.
52         bool operator==(const CSSSelector&) const;
53
54         static const unsigned maxValueMask = 0xffffff;
55         static const unsigned idMask = 0xff0000;
56         static const unsigned classMask = 0xff00;
57         static const unsigned elementMask = 0xff;
58
59         unsigned staticSpecificity(bool& ok) const;
60         unsigned specificityForPage() const;
61         unsigned simpleSelectorSpecificity() const;
62         static unsigned addSpecificities(unsigned, unsigned);
63
64         /* how the attribute value has to match.... Default is Exact */
65         enum Match {
66             Unknown = 0,
67             Tag,
68             Id,
69             Class,
70             Exact,
71             Set,
72             List,
73             Hyphen,
74             PseudoClass,
75             PseudoElement,
76             Contain, // css3: E[foo*="bar"]
77             Begin, // css3: E[foo^="bar"]
78             End, // css3: E[foo$="bar"]
79             PagePseudoClass
80         };
81
82         enum RelationType {
83             Subselector,
84             DescendantSpace,
85             Child,
86             DirectAdjacent,
87             IndirectAdjacent,
88 #if ENABLE(CSS_SELECTORS_LEVEL4)
89             DescendantDoubleChild,
90 #endif
91             ShadowDescendant
92         };
93
94         enum PseudoClassType {
95             PseudoClassUnknown = 0,
96             PseudoClassEmpty,
97             PseudoClassFirstChild,
98             PseudoClassFirstOfType,
99             PseudoClassLastChild,
100             PseudoClassLastOfType,
101             PseudoClassOnlyChild,
102             PseudoClassOnlyOfType,
103             PseudoClassNthChild,
104             PseudoClassNthOfType,
105             PseudoClassNthLastChild,
106             PseudoClassNthLastOfType,
107             PseudoClassLink,
108             PseudoClassVisited,
109             PseudoClassAny,
110             PseudoClassAnyLink,
111             PseudoClassAnyLinkDeprecated,
112             PseudoClassAutofill,
113             PseudoClassHover,
114             PseudoClassDrag,
115             PseudoClassFocus,
116             PseudoClassFocusWithin,
117             PseudoClassActive,
118             PseudoClassChecked,
119             PseudoClassEnabled,
120             PseudoClassFullPageMedia,
121             PseudoClassDefault,
122             PseudoClassDisabled,
123             PseudoClassMatches,
124             PseudoClassOptional,
125             PseudoClassPlaceholderShown,
126             PseudoClassRequired,
127             PseudoClassReadOnly,
128             PseudoClassReadWrite,
129             PseudoClassValid,
130             PseudoClassInvalid,
131             PseudoClassIndeterminate,
132             PseudoClassTarget,
133             PseudoClassLang,
134             PseudoClassNot,
135             PseudoClassRoot,
136             PseudoClassScope,
137             PseudoClassWindowInactive,
138             PseudoClassCornerPresent,
139             PseudoClassDecrement,
140             PseudoClassIncrement,
141             PseudoClassHorizontal,
142             PseudoClassVertical,
143             PseudoClassStart,
144             PseudoClassEnd,
145             PseudoClassDoubleButton,
146             PseudoClassSingleButton,
147             PseudoClassNoButton,
148 #if ENABLE(FULLSCREEN_API)
149             PseudoClassFullScreen,
150             PseudoClassFullScreenDocument,
151             PseudoClassFullScreenAncestor,
152             PseudoClassAnimatingFullScreenTransition,
153 #endif
154             PseudoClassInRange,
155             PseudoClassOutOfRange,
156 #if ENABLE(VIDEO_TRACK)
157             PseudoClassFuture,
158             PseudoClassPast,
159 #endif
160 #if ENABLE(CSS_SELECTORS_LEVEL4)
161             PseudoClassDir,
162             PseudoClassRole,
163 #endif
164             PseudoClassHost,
165             PseudoClassDefined,
166         };
167
168         enum PseudoElementType {
169             PseudoElementUnknown = 0,
170             PseudoElementAfter,
171             PseudoElementBefore,
172 #if ENABLE(VIDEO_TRACK)
173             PseudoElementCue,
174 #endif
175             PseudoElementFirstLetter,
176             PseudoElementFirstLine,
177             PseudoElementResizer,
178             PseudoElementScrollbar,
179             PseudoElementScrollbarButton,
180             PseudoElementScrollbarCorner,
181             PseudoElementScrollbarThumb,
182             PseudoElementScrollbarTrack,
183             PseudoElementScrollbarTrackPiece,
184             PseudoElementSelection,
185             PseudoElementSlotted,
186             PseudoElementUserAgentCustom,
187             PseudoElementWebKitCustom,
188
189             // WebKitCustom that appeared in an old prefixed form
190             // and need special handling.
191             PseudoElementWebKitCustomLegacyPrefixed,
192         };
193
194         enum PagePseudoClassType {
195             PagePseudoClassFirst = 1,
196             PagePseudoClassLeft,
197             PagePseudoClassRight,
198         };
199
200         enum MarginBoxType {
201             TopLeftCornerMarginBox,
202             TopLeftMarginBox,
203             TopCenterMarginBox,
204             TopRightMarginBox,
205             TopRightCornerMarginBox,
206             BottomLeftCornerMarginBox,
207             BottomLeftMarginBox,
208             BottomCenterMarginBox,
209             BottomRightMarginBox,
210             BottomRightCornerMarginBox,
211             LeftTopMarginBox,
212             LeftMiddleMarginBox,
213             LeftBottomMarginBox,
214             RightTopMarginBox,
215             RightMiddleMarginBox,
216             RightBottomMarginBox,
217         };
218
219         enum AttributeMatchType {
220             CaseSensitive,
221             CaseInsensitive,
222         };
223
224         static PseudoElementType parsePseudoElementType(const String&);
225         static PseudoId pseudoId(PseudoElementType);
226
227         // Selectors are kept in an array by CSSSelectorList. The next component of the selector is
228         // the next item in the array.
229         const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); }
230
231         const QualifiedName& tagQName() const;
232         const AtomicString& tagLowercaseLocalName() const;
233
234         const AtomicString& value() const;
235         const AtomicString& serializingValue() const;
236         const QualifiedName& attribute() const;
237         const AtomicString& attributeCanonicalLocalName() const;
238         const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
239         bool attributeValueMatchingIsCaseInsensitive() const;
240         const Vector<AtomicString>* langArgumentList() const { return m_hasRareData ? m_data.m_rareData->m_langArgumentList.get() : nullptr; }
241         const CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : nullptr; }
242
243         void setValue(const AtomicString&, bool matchLowerCase = false);
244         
245         // FIXME-NEWPARSER: These two methods can go away once the old parser is gone.
246         void setAttribute(const QualifiedName&, bool);
247         void setAttributeValueMatchingIsCaseInsensitive(bool);
248         void setAttribute(const QualifiedName&, bool convertToLowercase, AttributeMatchType);
249         void setNth(int a, int b);
250         void setArgument(const AtomicString&);
251         void setLangArgumentList(std::unique_ptr<Vector<AtomicString>>);
252         void setSelectorList(std::unique_ptr<CSSSelectorList>);
253
254         bool parseNth() const;
255         bool matchNth(int count) const;
256         int nthA() const;
257         int nthB() const;
258
259 #if ENABLE(CSS_SELECTORS_LEVEL4)
260         bool hasDescendantRelation() const { return relation() == DescendantSpace || relation() == DescendantDoubleChild; }
261 #else
262         bool hasDescendantRelation() const { return relation() == DescendantSpace; }
263 #endif
264
265         bool hasDescendantOrChildRelation() const { return relation() == Child || hasDescendantRelation(); }
266
267         PseudoClassType pseudoClassType() const
268         {
269             ASSERT(match() == PseudoClass);
270             return static_cast<PseudoClassType>(m_pseudoType);
271         }
272         void setPseudoClassType(PseudoClassType pseudoType)
273         {
274             m_pseudoType = pseudoType;
275             ASSERT(m_pseudoType == pseudoType);
276         }
277
278         PseudoElementType pseudoElementType() const
279         {
280             ASSERT(match() == PseudoElement);
281             return static_cast<PseudoElementType>(m_pseudoType);
282         }
283         void setPseudoElementType(PseudoElementType pseudoElementType)
284         {
285             m_pseudoType = pseudoElementType;
286             ASSERT(m_pseudoType == pseudoElementType);
287         }
288
289         PagePseudoClassType pagePseudoClassType() const
290         {
291             ASSERT(match() == PagePseudoClass);
292             return static_cast<PagePseudoClassType>(m_pseudoType);
293         }
294         void setPagePseudoType(PagePseudoClassType pagePseudoType)
295         {
296             m_pseudoType = pagePseudoType;
297             ASSERT(m_pseudoType == pagePseudoType);
298         }
299
300         bool matchesPseudoElement() const;
301         bool isUnknownPseudoElement() const;
302         bool isCustomPseudoElement() const;
303         bool isWebKitCustomPseudoElement() const;
304         bool isSiblingSelector() const;
305         bool isAttributeSelector() const;
306
307         RelationType relation() const { return static_cast<RelationType>(m_relation); }
308         void setRelation(RelationType relation)
309         {
310             m_relation = relation;
311             ASSERT(m_relation == relation);
312         }
313
314         Match match() const { return static_cast<Match>(m_match); }
315         void setMatch(Match match)
316         {
317             m_match = match;
318             ASSERT(m_match == match);
319         }
320
321         bool isLastInSelectorList() const { return m_isLastInSelectorList; }
322         void setLastInSelectorList() { m_isLastInSelectorList = true; }
323         bool isLastInTagHistory() const { return m_isLastInTagHistory; }
324         void setNotLastInTagHistory() { m_isLastInTagHistory = false; }
325
326         bool isForPage() const { return m_isForPage; }
327         void setForPage() { m_isForPage = true; }
328
329     private:
330         unsigned m_relation              : 4; // enum RelationType.
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_hasNameWithCase       : 1;
338         unsigned m_isForPage             : 1;
339         unsigned m_tagIsForNamespaceRule : 1;
340         unsigned m_caseInsensitiveAttributeValueMatching : 1;
341 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
342         unsigned m_destructorHasBeenCalled : 1;
343 #endif
344
345         unsigned simpleSelectorSpecificityForPage() const;
346
347         // Hide.
348         CSSSelector& operator=(const CSSSelector&);
349
350         struct RareData : public RefCounted<RareData> {
351             static Ref<RareData> create(AtomicString&& value) { return adoptRef(*new RareData(WTFMove(value))); }
352             ~RareData();
353
354             bool parseNth();
355             bool matchNth(int count);
356
357             // For quirks mode, class and id are case-insensitive. In the case where uppercase
358             // letters are used in quirks mode, |m_matchingValue| holds the lowercase class/id
359             // and |m_serializingValue| holds the original string.
360             AtomicString m_matchingValue;
361             AtomicString m_serializingValue;
362             
363             int m_a; // Used for :nth-*
364             int m_b; // Used for :nth-*
365             QualifiedName m_attribute; // used for attribute selector
366             AtomicString m_attributeCanonicalLocalName;
367             AtomicString m_argument; // Used for :contains and :nth-*
368             std::unique_ptr<Vector<AtomicString>> m_langArgumentList; // Used for :lang arguments.
369             std::unique_ptr<CSSSelectorList> m_selectorList; // Used for :matches() and :not().
370         
371         private:
372             RareData(AtomicString&& value);
373         };
374         void createRareData();
375
376         struct NameWithCase : public RefCounted<NameWithCase> {
377             NameWithCase(const QualifiedName& originalName, const AtomicString& lowercaseName)
378                 : m_originalName(originalName)
379                 , m_lowercaseLocalName(lowercaseName)
380             {
381                 ASSERT(originalName.localName() != lowercaseName);
382             }
383
384             const QualifiedName m_originalName;
385             const AtomicString m_lowercaseLocalName;
386         };
387
388         union DataUnion {
389             DataUnion() : m_value(0) { }
390             AtomicStringImpl* m_value;
391             QualifiedName::QualifiedNameImpl* m_tagQName;
392             RareData* m_rareData;
393             NameWithCase* m_nameWithCase;
394         } m_data;
395     };
396
397 inline const QualifiedName& CSSSelector::attribute() const
398 {
399     ASSERT(isAttributeSelector());
400     ASSERT(m_hasRareData);
401     return m_data.m_rareData->m_attribute;
402 }
403
404 inline const AtomicString& CSSSelector::attributeCanonicalLocalName() const
405 {
406     ASSERT(isAttributeSelector());
407     ASSERT(m_hasRareData);
408     return m_data.m_rareData->m_attributeCanonicalLocalName;
409 }
410
411 inline bool CSSSelector::matchesPseudoElement() const
412 {
413     return match() == PseudoElement;
414 }
415
416 inline bool CSSSelector::isUnknownPseudoElement() const
417 {
418     return match() == PseudoElement && pseudoElementType() == PseudoElementUnknown;
419 }
420
421 inline bool CSSSelector::isCustomPseudoElement() const
422 {
423     return match() == PseudoElement
424         && (pseudoElementType() == PseudoElementUserAgentCustom
425             || pseudoElementType() == PseudoElementWebKitCustom
426             || pseudoElementType() == PseudoElementWebKitCustomLegacyPrefixed);
427 }
428
429 inline bool CSSSelector::isWebKitCustomPseudoElement() const
430 {
431     return pseudoElementType() == PseudoElementWebKitCustom || pseudoElementType() == PseudoElementWebKitCustomLegacyPrefixed;
432 }
433
434 static inline bool pseudoClassIsRelativeToSiblings(CSSSelector::PseudoClassType type)
435 {
436     return type == CSSSelector::PseudoClassEmpty
437         || type == CSSSelector::PseudoClassFirstChild
438         || type == CSSSelector::PseudoClassFirstOfType
439         || type == CSSSelector::PseudoClassLastChild
440         || type == CSSSelector::PseudoClassLastOfType
441         || type == CSSSelector::PseudoClassOnlyChild
442         || type == CSSSelector::PseudoClassOnlyOfType
443         || type == CSSSelector::PseudoClassNthChild
444         || type == CSSSelector::PseudoClassNthOfType
445         || type == CSSSelector::PseudoClassNthLastChild
446         || type == CSSSelector::PseudoClassNthLastOfType;
447 }
448
449 inline bool CSSSelector::isSiblingSelector() const
450 {
451     return relation() == DirectAdjacent
452         || relation() == IndirectAdjacent
453         || (match() == CSSSelector::PseudoClass && pseudoClassIsRelativeToSiblings(pseudoClassType()));
454 }
455
456 inline bool CSSSelector::isAttributeSelector() const
457 {
458     return match() == CSSSelector::Exact
459         || match() ==  CSSSelector::Set
460         || match() == CSSSelector::List
461         || match() == CSSSelector::Hyphen
462         || match() == CSSSelector::Contain
463         || match() == CSSSelector::Begin
464         || match() == CSSSelector::End;
465 }
466
467 inline void CSSSelector::setValue(const AtomicString& value, bool matchLowerCase)
468 {
469     ASSERT(match() != Tag);
470     AtomicString matchingValue = matchLowerCase ? value.convertToASCIILowercase() : value;
471     if (!m_hasRareData && matchingValue != value)
472         createRareData();
473     
474     // Need to do ref counting manually for the union.
475     if (!m_hasRareData) {
476         if (m_data.m_value)
477             m_data.m_value->deref();
478         m_data.m_value = value.impl();
479         m_data.m_value->ref();
480         return;
481     }
482
483     m_data.m_rareData->m_matchingValue = WTFMove(matchingValue);
484     m_data.m_rareData->m_serializingValue = value;
485 }
486
487 inline CSSSelector::CSSSelector()
488     : m_relation(DescendantSpace)
489     , m_match(Unknown)
490     , m_pseudoType(0)
491     , m_parsedNth(false)
492     , m_isLastInSelectorList(false)
493     , m_isLastInTagHistory(true)
494     , m_hasRareData(false)
495     , m_hasNameWithCase(false)
496     , m_isForPage(false)
497     , m_tagIsForNamespaceRule(false)
498     , m_caseInsensitiveAttributeValueMatching(false)
499 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
500     , m_destructorHasBeenCalled(false)
501 #endif
502 {
503 }
504
505 inline CSSSelector::CSSSelector(const CSSSelector& o)
506     : m_relation(o.m_relation)
507     , m_match(o.m_match)
508     , m_pseudoType(o.m_pseudoType)
509     , m_parsedNth(o.m_parsedNth)
510     , m_isLastInSelectorList(o.m_isLastInSelectorList)
511     , m_isLastInTagHistory(o.m_isLastInTagHistory)
512     , m_hasRareData(o.m_hasRareData)
513     , m_hasNameWithCase(o.m_hasNameWithCase)
514     , m_isForPage(o.m_isForPage)
515     , m_tagIsForNamespaceRule(o.m_tagIsForNamespaceRule)
516     , m_caseInsensitiveAttributeValueMatching(o.m_caseInsensitiveAttributeValueMatching)
517 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
518     , m_destructorHasBeenCalled(false)
519 #endif
520 {
521     if (o.m_hasRareData) {
522         m_data.m_rareData = o.m_data.m_rareData;
523         m_data.m_rareData->ref();
524     } else if (o.m_hasNameWithCase) {
525         m_data.m_nameWithCase = o.m_data.m_nameWithCase;
526         m_data.m_nameWithCase->ref();
527     } if (o.match() == Tag) {
528         m_data.m_tagQName = o.m_data.m_tagQName;
529         m_data.m_tagQName->ref();
530     } else if (o.m_data.m_value) {
531         m_data.m_value = o.m_data.m_value;
532         m_data.m_value->ref();
533     }
534 }
535
536 inline CSSSelector::~CSSSelector()
537 {
538     ASSERT_WITH_SECURITY_IMPLICATION(!m_destructorHasBeenCalled);
539 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
540     m_destructorHasBeenCalled = true;
541 #endif
542     if (m_hasRareData) {
543         m_data.m_rareData->deref();
544         m_data.m_rareData = nullptr;
545         m_hasRareData = false;
546     } else if (m_hasNameWithCase) {
547         m_data.m_nameWithCase->deref();
548         m_data.m_nameWithCase = nullptr;
549         m_hasNameWithCase = false;
550     } else if (match() == Tag) {
551         m_data.m_tagQName->deref();
552         m_data.m_tagQName = nullptr;
553         m_match = Unknown;
554     } else if (m_data.m_value) {
555         m_data.m_value->deref();
556         m_data.m_value = nullptr;
557     }
558 }
559
560 inline const QualifiedName& CSSSelector::tagQName() const
561 {
562     ASSERT(match() == Tag);
563     if (m_hasNameWithCase)
564         return m_data.m_nameWithCase->m_originalName;
565     return *reinterpret_cast<const QualifiedName*>(&m_data.m_tagQName);
566 }
567
568 inline const AtomicString& CSSSelector::tagLowercaseLocalName() const
569 {
570     if (m_hasNameWithCase)
571         return m_data.m_nameWithCase->m_lowercaseLocalName;
572     return m_data.m_tagQName->m_localName;
573 }
574
575 inline const AtomicString& CSSSelector::value() const
576 {
577     ASSERT(match() != Tag);
578     if (m_hasRareData)
579         return m_data.m_rareData->m_matchingValue;
580
581     // AtomicString is really just an AtomicStringImpl* so the cast below is safe.
582     return *reinterpret_cast<const AtomicString*>(&m_data.m_value);
583 }
584
585 inline const AtomicString& CSSSelector::serializingValue() const
586 {
587     ASSERT(match() != Tag);
588     if (m_hasRareData)
589         return m_data.m_rareData->m_serializingValue;
590     
591     // AtomicString is really just an AtomicStringImpl* so the cast below is safe.
592     return *reinterpret_cast<const AtomicString*>(&m_data.m_value);
593 }
594
595 inline void CSSSelector::setAttributeValueMatchingIsCaseInsensitive(bool isCaseInsensitive)
596 {
597     ASSERT(isAttributeSelector() && match() != CSSSelector::Set);
598     m_caseInsensitiveAttributeValueMatching = isCaseInsensitive;
599 }
600     
601 inline bool CSSSelector::attributeValueMatchingIsCaseInsensitive() const
602 {
603     return m_caseInsensitiveAttributeValueMatching;
604 }
605
606 } // namespace WebCore