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  * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 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 "QualifiedName.h"
     26 #include "RenderStyleConstants.h"
     27 #include <wtf/Noncopyable.h>
     28 #include <wtf/OwnPtr.h>
     29 #include <wtf/PassOwnPtr.h>
     30 
     31 namespace WebCore {
     32     class CSSSelectorList;
     33 
     34     // this class represents a selector for a StyleRule
     35     class CSSSelector {
     36         WTF_MAKE_NONCOPYABLE(CSSSelector); WTF_MAKE_FAST_ALLOCATED;
     37     public:
     38         CSSSelector()
     39             : m_relation(Descendant)
     40             , m_match(None)
     41             , m_pseudoType(PseudoNotParsed)
     42             , m_parsedNth(false)
     43             , m_isLastInSelectorList(false)
     44             , m_isLastInTagHistory(true)
     45             , m_hasRareData(false)
     46             , m_isForPage(false)
     47             , m_deleted(false)
     48             , m_tag(anyQName())
     49         {
     50         }
     51 
     52         CSSSelector(const QualifiedName& qName)
     53             : m_relation(Descendant)
     54             , m_match(None)
     55             , m_pseudoType(PseudoNotParsed)
     56             , m_parsedNth(false)
     57             , m_isLastInSelectorList(false)
     58             , m_isLastInTagHistory(true)
     59             , m_hasRareData(false)
     60             , m_isForPage(false)
     61             , m_deleted(false)
     62             , m_tag(qName)
     63         {
     64         }
     65 
     66         ~CSSSelector()
     67         {
     68             if (m_deleted)
     69                 CRASH();
     70             m_deleted = true;
     71             if (m_hasRareData)
     72                 delete m_data.m_rareData;
     73             else if (m_data.m_value)
     74                 m_data.m_value->deref();
     75         }
     76 
     77         /**
     78          * Re-create selector text from selector's data
     79          */
     80         String selectorText() const;
     81 
     82         // checks if the 2 selectors (including sub selectors) agree.
     83         bool operator==(const CSSSelector&);
     84 
     85         // tag == -1 means apply to all elements (Selector = *)
     86 
     87         unsigned specificity() const;
     88 
     89         /* how the attribute value has to match.... Default is Exact */
     90         enum Match {
     91             None = 0,
     92             Id,
     93             Class,
     94             Exact,
     95             Set,
     96             List,
     97             Hyphen,
     98             PseudoClass,
     99             PseudoElement,
    100             Contain, // css3: E[foo*="bar"]
    101             Begin, // css3: E[foo^="bar"]
    102             End, // css3: E[foo$="bar"]
    103             PagePseudoClass
    104         };
    105 
    106         enum Relation {
    107             Descendant = 0,
    108             Child,
    109             DirectAdjacent,
    110             IndirectAdjacent,
    111             SubSelector,
    112             ShadowDescendant
    113         };
    114 
    115         enum PseudoType {
    116             PseudoNotParsed = 0,
    117             PseudoUnknown,
    118             PseudoEmpty,
    119             PseudoFirstChild,
    120             PseudoFirstOfType,
    121             PseudoLastChild,
    122             PseudoLastOfType,
    123             PseudoOnlyChild,
    124             PseudoOnlyOfType,
    125             PseudoFirstLine,
    126             PseudoFirstLetter,
    127             PseudoNthChild,
    128             PseudoNthOfType,
    129             PseudoNthLastChild,
    130             PseudoNthLastOfType,
    131             PseudoLink,
    132             PseudoVisited,
    133             PseudoAny,
    134             PseudoAnyLink,
    135             PseudoAutofill,
    136             PseudoHover,
    137             PseudoDrag,
    138             PseudoFocus,
    139             PseudoActive,
    140             PseudoChecked,
    141             PseudoEnabled,
    142             PseudoFullPageMedia,
    143             PseudoDefault,
    144             PseudoDisabled,
    145             PseudoInputPlaceholder,
    146             PseudoOptional,
    147             PseudoRequired,
    148             PseudoReadOnly,
    149             PseudoReadWrite,
    150             PseudoValid,
    151             PseudoInvalid,
    152             PseudoIndeterminate,
    153             PseudoTarget,
    154             PseudoBefore,
    155             PseudoAfter,
    156             PseudoLang,
    157             PseudoNot,
    158             PseudoResizer,
    159             PseudoRoot,
    160             PseudoScrollbar,
    161             PseudoScrollbarBack,
    162             PseudoScrollbarButton,
    163             PseudoScrollbarCorner,
    164             PseudoScrollbarForward,
    165             PseudoScrollbarThumb,
    166             PseudoScrollbarTrack,
    167             PseudoScrollbarTrackPiece,
    168             PseudoWindowInactive,
    169             PseudoCornerPresent,
    170             PseudoDecrement,
    171             PseudoIncrement,
    172             PseudoHorizontal,
    173             PseudoVertical,
    174             PseudoStart,
    175             PseudoEnd,
    176             PseudoDoubleButton,
    177             PseudoSingleButton,
    178             PseudoNoButton,
    179             PseudoSelection,
    180             PseudoFileUploadButton,
    181             PseudoSearchCancelButton,
    182             PseudoSearchDecoration,
    183             PseudoSearchResultsDecoration,
    184             PseudoSearchResultsButton,
    185             PseudoInputListButton,
    186 #if ENABLE(INPUT_SPEECH)
    187             PseudoInputSpeechButton,
    188 #endif
    189             PseudoInnerSpinButton,
    190             PseudoOuterSpinButton,
    191             PseudoLeftPage,
    192             PseudoRightPage,
    193             PseudoFirstPage,
    194 #if ENABLE(FULLSCREEN_API)
    195             PseudoFullScreen,
    196             PseudoFullScreenDocument,
    197 #endif
    198             PseudoInRange,
    199             PseudoOutOfRange,
    200         };
    201 
    202         enum MarginBoxType {
    203             TopLeftCornerMarginBox,
    204             TopLeftMarginBox,
    205             TopCenterMarginBox,
    206             TopRightMarginBox,
    207             TopRightCornerMarginBox,
    208             BottomLeftCornerMarginBox,
    209             BottomLeftMarginBox,
    210             BottomCenterMarginBox,
    211             BottomRightMarginBox,
    212             BottomRightCornerMarginBox,
    213             LeftTopMarginBox,
    214             LeftMiddleMarginBox,
    215             LeftBottomMarginBox,
    216             RightTopMarginBox,
    217             RightMiddleMarginBox,
    218             RightBottomMarginBox,
    219         };
    220 
    221         PseudoType pseudoType() const
    222         {
    223             if (m_pseudoType == PseudoNotParsed)
    224                 extractPseudoType();
    225             return static_cast<PseudoType>(m_pseudoType);
    226         }
    227 
    228         static PseudoType parsePseudoType(const AtomicString&);
    229         static PseudoId pseudoId(PseudoType);
    230 
    231         // Selectors are kept in an array by CSSSelectorList. The next component of the selector is
    232         // the next item in the array.
    233         CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); }
    234 
    235         bool hasTag() const { return m_tag != anyQName(); }
    236         bool hasAttribute() const { return m_match == Id || m_match == Class || (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()); }
    237 
    238         const QualifiedName& tag() const { return m_tag; }
    239         // AtomicString is really just an AtomicStringImpl* so the cast below is safe.
    240         // FIXME: Perhaps call sites could be changed to accept AtomicStringImpl?
    241         const AtomicString& value() const { return *reinterpret_cast<const AtomicString*>(m_hasRareData ? &m_data.m_rareData->m_value : &m_data.m_value); }
    242         const QualifiedName& attribute() const;
    243         const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
    244         CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; }
    245 
    246         void setTag(const QualifiedName& value) { m_tag = value; }
    247         void setValue(const AtomicString&);
    248         void setAttribute(const QualifiedName&);
    249         void setArgument(const AtomicString&);
    250         void setSelectorList(PassOwnPtr<CSSSelectorList>);
    251 
    252         bool parseNth();
    253         bool matchNth(int count);
    254 
    255         bool matchesPseudoElement() const;
    256         bool isUnknownPseudoElement() const;
    257         bool isSiblingSelector() const;
    258 
    259         Relation relation() const { return static_cast<Relation>(m_relation); }
    260 
    261         bool isLastInSelectorList() const { return m_isLastInSelectorList; }
    262         void setLastInSelectorList() { m_isLastInSelectorList = true; }
    263         bool isLastInTagHistory() const { return m_isLastInTagHistory; }
    264         void setNotLastInTagHistory() { m_isLastInTagHistory = false; }
    265 
    266         bool isSimple() const;
    267 
    268         bool isForPage() const { return m_isForPage; }
    269         void setForPage() { m_isForPage = true; }
    270 
    271         unsigned m_relation           : 3; // enum Relation
    272         mutable unsigned m_match      : 4; // enum Match
    273         mutable unsigned m_pseudoType : 8; // PseudoType
    274 
    275     private:
    276         bool m_parsedNth              : 1; // Used for :nth-*
    277         bool m_isLastInSelectorList   : 1;
    278         bool m_isLastInTagHistory     : 1;
    279         bool m_hasRareData            : 1;
    280         bool m_isForPage              : 1;
    281         // FIXME: Remove once http://webkit.org/b/56124 is fixed.
    282         bool m_deleted                : 1;
    283 
    284         unsigned specificityForOneSelector() const;
    285         unsigned specificityForPage() const;
    286         void extractPseudoType() const;
    287 
    288         struct RareData {
    289             WTF_MAKE_NONCOPYABLE(RareData); WTF_MAKE_FAST_ALLOCATED;
    290         public:
    291             RareData(PassRefPtr<AtomicStringImpl> value);
    292             ~RareData();
    293 
    294             bool parseNth();
    295             bool matchNth(int count);
    296 
    297             AtomicStringImpl* m_value; // Plain pointer to keep things uniform with the union.
    298             int m_a; // Used for :nth-*
    299             int m_b; // Used for :nth-*
    300             QualifiedName m_attribute; // used for attribute selector
    301             AtomicString m_argument; // Used for :contains, :lang and :nth-*
    302             OwnPtr<CSSSelectorList> m_selectorList; // Used for :-webkit-any and :not
    303         };
    304         void createRareData();
    305 
    306         union DataUnion {
    307             DataUnion() : m_value(0) { }
    308             AtomicStringImpl* m_value;
    309             RareData* m_rareData;
    310         } m_data;
    311 
    312         QualifiedName m_tag;
    313     };
    314 
    315 inline bool CSSSelector::matchesPseudoElement() const
    316 {
    317     if (m_pseudoType == PseudoUnknown)
    318         extractPseudoType();
    319     return m_match == PseudoElement;
    320 }
    321 
    322 inline bool CSSSelector::isUnknownPseudoElement() const
    323 {
    324     return m_match == PseudoElement && m_pseudoType == PseudoUnknown;
    325 }
    326 
    327 inline bool CSSSelector::isSiblingSelector() const
    328 {
    329     PseudoType type = pseudoType();
    330     return m_relation == DirectAdjacent
    331         || m_relation == IndirectAdjacent
    332         || type == PseudoEmpty
    333         || type == PseudoFirstChild
    334         || type == PseudoFirstOfType
    335         || type == PseudoLastChild
    336         || type == PseudoLastOfType
    337         || type == PseudoOnlyChild
    338         || type == PseudoOnlyOfType
    339         || type == PseudoNthChild
    340         || type == PseudoNthOfType
    341         || type == PseudoNthLastChild
    342         || type == PseudoNthLastOfType;
    343 }
    344 
    345 inline void CSSSelector::setValue(const AtomicString& value)
    346 {
    347     // Need to do ref counting manually for the union.
    348     if (m_hasRareData) {
    349         m_data.m_rareData->m_value = value.impl();
    350         m_data.m_rareData->m_value->ref();
    351         return;
    352     }
    353     m_data.m_value = value.impl();
    354     m_data.m_value->ref();
    355 }
    356 
    357 inline void move(PassOwnPtr<CSSSelector> from, CSSSelector* to)
    358 {
    359     memcpy(to, from.get(), sizeof(CSSSelector));
    360     // We want to free the memory (which was allocated with fastNew), but we
    361     // don't want the destructor to run since it will affect the copy we've just made.
    362     fastDeleteSkippingDestructor(from.leakPtr());
    363 }
    364 
    365 } // namespace WebCore
    366 
    367 #endif // CSSSelector_h
    368