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