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 | ShadowDescendant |
89 | }; |
90 | |
91 | enum PseudoClassType { |
92 | PseudoClassUnknown = 0, |
93 | PseudoClassEmpty, |
94 | PseudoClassFirstChild, |
95 | PseudoClassFirstOfType, |
96 | PseudoClassLastChild, |
97 | PseudoClassLastOfType, |
98 | PseudoClassOnlyChild, |
99 | PseudoClassOnlyOfType, |
100 | PseudoClassNthChild, |
101 | PseudoClassNthOfType, |
102 | PseudoClassNthLastChild, |
103 | PseudoClassNthLastOfType, |
104 | PseudoClassLink, |
105 | PseudoClassVisited, |
106 | PseudoClassAny, |
107 | PseudoClassAnyLink, |
108 | PseudoClassAnyLinkDeprecated, |
109 | PseudoClassAutofill, |
110 | PseudoClassAutofillStrongPassword, |
111 | PseudoClassHover, |
112 | PseudoClassDrag, |
113 | PseudoClassFocus, |
114 | PseudoClassFocusWithin, |
115 | PseudoClassActive, |
116 | PseudoClassChecked, |
117 | PseudoClassEnabled, |
118 | PseudoClassFullPageMedia, |
119 | PseudoClassDefault, |
120 | PseudoClassDisabled, |
121 | PseudoClassMatches, |
122 | PseudoClassOptional, |
123 | PseudoClassPlaceholderShown, |
124 | PseudoClassRequired, |
125 | PseudoClassReadOnly, |
126 | PseudoClassReadWrite, |
127 | PseudoClassValid, |
128 | PseudoClassInvalid, |
129 | PseudoClassIndeterminate, |
130 | PseudoClassTarget, |
131 | PseudoClassLang, |
132 | PseudoClassNot, |
133 | PseudoClassRoot, |
134 | PseudoClassScope, |
135 | PseudoClassWindowInactive, |
136 | PseudoClassCornerPresent, |
137 | PseudoClassDecrement, |
138 | PseudoClassIncrement, |
139 | PseudoClassHorizontal, |
140 | PseudoClassVertical, |
141 | PseudoClassStart, |
142 | PseudoClassEnd, |
143 | PseudoClassDoubleButton, |
144 | PseudoClassSingleButton, |
145 | PseudoClassNoButton, |
146 | #if ENABLE(FULLSCREEN_API) |
147 | PseudoClassFullScreen, |
148 | PseudoClassFullScreenDocument, |
149 | PseudoClassFullScreenAncestor, |
150 | PseudoClassAnimatingFullScreenTransition, |
151 | PseudoClassFullScreenControlsHidden, |
152 | #endif |
153 | PseudoClassInRange, |
154 | PseudoClassOutOfRange, |
155 | #if ENABLE(VIDEO_TRACK) |
156 | PseudoClassFuture, |
157 | PseudoClassPast, |
158 | #endif |
159 | #if ENABLE(CSS_SELECTORS_LEVEL4) |
160 | PseudoClassDir, |
161 | PseudoClassRole, |
162 | #endif |
163 | PseudoClassHost, |
164 | PseudoClassDefined, |
165 | #if ENABLE(ATTACHMENT_ELEMENT) |
166 | PseudoClassHasAttachment, |
167 | #endif |
168 | }; |
169 | |
170 | enum PseudoElementType { |
171 | PseudoElementUnknown = 0, |
172 | PseudoElementAfter, |
173 | PseudoElementBefore, |
174 | #if ENABLE(VIDEO_TRACK) |
175 | PseudoElementCue, |
176 | #endif |
177 | PseudoElementFirstLetter, |
178 | PseudoElementFirstLine, |
179 | PseudoElementMarker, |
180 | PseudoElementResizer, |
181 | PseudoElementScrollbar, |
182 | PseudoElementScrollbarButton, |
183 | PseudoElementScrollbarCorner, |
184 | PseudoElementScrollbarThumb, |
185 | PseudoElementScrollbarTrack, |
186 | PseudoElementScrollbarTrackPiece, |
187 | PseudoElementSelection, |
188 | PseudoElementSlotted, |
189 | PseudoElementWebKitCustom, |
190 | |
191 | // WebKitCustom that appeared in an old prefixed form |
192 | // and need special handling. |
193 | PseudoElementWebKitCustomLegacyPrefixed, |
194 | }; |
195 | |
196 | enum PagePseudoClassType { |
197 | PagePseudoClassFirst = 1, |
198 | PagePseudoClassLeft, |
199 | PagePseudoClassRight, |
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 | enum AttributeMatchType { |
222 | CaseSensitive, |
223 | CaseInsensitive, |
224 | }; |
225 | |
226 | static PseudoElementType parsePseudoElementType(const String&); |
227 | static PseudoId pseudoId(PseudoElementType); |
228 | |
229 | // Selectors are kept in an array by CSSSelectorList. The next component of the selector is |
230 | // the next item in the array. |
231 | const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); } |
232 | |
233 | const QualifiedName& tagQName() const; |
234 | const AtomicString& tagLowercaseLocalName() const; |
235 | |
236 | const AtomicString& value() const; |
237 | const AtomicString& serializingValue() const; |
238 | const QualifiedName& attribute() const; |
239 | const AtomicString& attributeCanonicalLocalName() const; |
240 | const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom(); } |
241 | bool attributeValueMatchingIsCaseInsensitive() const; |
242 | const Vector<AtomicString>* langArgumentList() const { return m_hasRareData ? m_data.m_rareData->m_langArgumentList.get() : nullptr; } |
243 | const CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : nullptr; } |
244 | |
245 | void setValue(const AtomicString&, bool matchLowerCase = false); |
246 | |
247 | void setAttribute(const QualifiedName&, bool convertToLowercase, AttributeMatchType); |
248 | void setNth(int a, int b); |
249 | void setArgument(const AtomicString&); |
250 | void setLangArgumentList(std::unique_ptr<Vector<AtomicString>>); |
251 | void setSelectorList(std::unique_ptr<CSSSelectorList>); |
252 | |
253 | bool matchNth(int count) const; |
254 | int nthA() const; |
255 | int nthB() const; |
256 | |
257 | bool hasDescendantRelation() const { return relation() == DescendantSpace; } |
258 | |
259 | bool hasDescendantOrChildRelation() const { return relation() == Child || hasDescendantRelation(); } |
260 | |
261 | PseudoClassType pseudoClassType() const |
262 | { |
263 | ASSERT(match() == PseudoClass); |
264 | return static_cast<PseudoClassType>(m_pseudoType); |
265 | } |
266 | void setPseudoClassType(PseudoClassType pseudoType) |
267 | { |
268 | m_pseudoType = pseudoType; |
269 | ASSERT(m_pseudoType == pseudoType); |
270 | } |
271 | |
272 | PseudoElementType pseudoElementType() const |
273 | { |
274 | ASSERT(match() == PseudoElement); |
275 | return static_cast<PseudoElementType>(m_pseudoType); |
276 | } |
277 | void setPseudoElementType(PseudoElementType pseudoElementType) |
278 | { |
279 | m_pseudoType = pseudoElementType; |
280 | ASSERT(m_pseudoType == pseudoElementType); |
281 | } |
282 | |
283 | PagePseudoClassType pagePseudoClassType() const |
284 | { |
285 | ASSERT(match() == PagePseudoClass); |
286 | return static_cast<PagePseudoClassType>(m_pseudoType); |
287 | } |
288 | void setPagePseudoType(PagePseudoClassType pagePseudoType) |
289 | { |
290 | m_pseudoType = pagePseudoType; |
291 | ASSERT(m_pseudoType == pagePseudoType); |
292 | } |
293 | |
294 | bool matchesPseudoElement() const; |
295 | bool isUnknownPseudoElement() const; |
296 | bool isCustomPseudoElement() const; |
297 | bool isWebKitCustomPseudoElement() const; |
298 | bool isSiblingSelector() const; |
299 | bool isAttributeSelector() const; |
300 | |
301 | RelationType relation() const { return static_cast<RelationType>(m_relation); } |
302 | void setRelation(RelationType relation) |
303 | { |
304 | m_relation = relation; |
305 | ASSERT(m_relation == relation); |
306 | } |
307 | |
308 | Match match() const { return static_cast<Match>(m_match); } |
309 | void setMatch(Match match) |
310 | { |
311 | m_match = match; |
312 | ASSERT(m_match == match); |
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 | bool isForPage() const { return m_isForPage; } |
321 | void setForPage() { m_isForPage = true; } |
322 | |
323 | private: |
324 | unsigned m_relation : 4; // enum RelationType. |
325 | mutable unsigned m_match : 4; // enum Match. |
326 | mutable unsigned m_pseudoType : 8; // PseudoType. |
327 | unsigned m_isLastInSelectorList : 1; |
328 | unsigned m_isLastInTagHistory : 1; |
329 | unsigned m_hasRareData : 1; |
330 | unsigned m_hasNameWithCase : 1; |
331 | unsigned m_isForPage : 1; |
332 | unsigned m_tagIsForNamespaceRule : 1; |
333 | unsigned m_caseInsensitiveAttributeValueMatching : 1; |
334 | #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
335 | unsigned m_destructorHasBeenCalled : 1; |
336 | #endif |
337 | |
338 | unsigned simpleSelectorSpecificityForPage() const; |
339 | |
340 | // Hide. |
341 | CSSSelector& operator=(const CSSSelector&); |
342 | |
343 | struct RareData : public RefCounted<RareData> { |
344 | static Ref<RareData> create(AtomicString&& value) { return adoptRef(*new RareData(WTFMove(value))); } |
345 | ~RareData(); |
346 | |
347 | bool matchNth(int count); |
348 | |
349 | // For quirks mode, class and id are case-insensitive. In the case where uppercase |
350 | // letters are used in quirks mode, |m_matchingValue| holds the lowercase class/id |
351 | // and |m_serializingValue| holds the original string. |
352 | AtomicString m_matchingValue; |
353 | AtomicString m_serializingValue; |
354 | |
355 | int m_a; // Used for :nth-* |
356 | int m_b; // Used for :nth-* |
357 | QualifiedName m_attribute; // used for attribute selector |
358 | AtomicString m_attributeCanonicalLocalName; |
359 | AtomicString m_argument; // Used for :contains and :nth-* |
360 | std::unique_ptr<Vector<AtomicString>> m_langArgumentList; // Used for :lang arguments. |
361 | std::unique_ptr<CSSSelectorList> m_selectorList; // Used for :matches() and :not(). |
362 | |
363 | private: |
364 | RareData(AtomicString&& value); |
365 | }; |
366 | void createRareData(); |
367 | |
368 | struct NameWithCase : public RefCounted<NameWithCase> { |
369 | NameWithCase(const QualifiedName& originalName, const AtomicString& lowercaseName) |
370 | : m_originalName(originalName) |
371 | , m_lowercaseLocalName(lowercaseName) |
372 | { |
373 | ASSERT(originalName.localName() != lowercaseName); |
374 | } |
375 | |
376 | const QualifiedName m_originalName; |
377 | const AtomicString m_lowercaseLocalName; |
378 | }; |
379 | |
380 | union DataUnion { |
381 | DataUnion() : m_value(0) { } |
382 | AtomicStringImpl* m_value; |
383 | QualifiedName::QualifiedNameImpl* m_tagQName; |
384 | RareData* m_rareData; |
385 | NameWithCase* m_nameWithCase; |
386 | } m_data; |
387 | }; |
388 | |
389 | inline const QualifiedName& CSSSelector::attribute() const |
390 | { |
391 | ASSERT(isAttributeSelector()); |
392 | ASSERT(m_hasRareData); |
393 | return m_data.m_rareData->m_attribute; |
394 | } |
395 | |
396 | inline const AtomicString& CSSSelector::attributeCanonicalLocalName() const |
397 | { |
398 | ASSERT(isAttributeSelector()); |
399 | ASSERT(m_hasRareData); |
400 | return m_data.m_rareData->m_attributeCanonicalLocalName; |
401 | } |
402 | |
403 | inline bool CSSSelector::matchesPseudoElement() const |
404 | { |
405 | return match() == PseudoElement; |
406 | } |
407 | |
408 | inline bool CSSSelector::isUnknownPseudoElement() const |
409 | { |
410 | return match() == PseudoElement && pseudoElementType() == PseudoElementUnknown; |
411 | } |
412 | |
413 | inline bool CSSSelector::isCustomPseudoElement() const |
414 | { |
415 | return match() == PseudoElement |
416 | && (pseudoElementType() == PseudoElementWebKitCustom |
417 | || pseudoElementType() == PseudoElementWebKitCustomLegacyPrefixed); |
418 | } |
419 | |
420 | inline bool CSSSelector::isWebKitCustomPseudoElement() const |
421 | { |
422 | return pseudoElementType() == PseudoElementWebKitCustom || pseudoElementType() == PseudoElementWebKitCustomLegacyPrefixed; |
423 | } |
424 | |
425 | static inline bool pseudoClassIsRelativeToSiblings(CSSSelector::PseudoClassType type) |
426 | { |
427 | return type == CSSSelector::PseudoClassEmpty |
428 | || type == CSSSelector::PseudoClassFirstChild |
429 | || type == CSSSelector::PseudoClassFirstOfType |
430 | || type == CSSSelector::PseudoClassLastChild |
431 | || type == CSSSelector::PseudoClassLastOfType |
432 | || type == CSSSelector::PseudoClassOnlyChild |
433 | || type == CSSSelector::PseudoClassOnlyOfType |
434 | || type == CSSSelector::PseudoClassNthChild |
435 | || type == CSSSelector::PseudoClassNthOfType |
436 | || type == CSSSelector::PseudoClassNthLastChild |
437 | || type == CSSSelector::PseudoClassNthLastOfType; |
438 | } |
439 | |
440 | inline bool CSSSelector::isSiblingSelector() const |
441 | { |
442 | return relation() == DirectAdjacent |
443 | || relation() == IndirectAdjacent |
444 | || (match() == CSSSelector::PseudoClass && pseudoClassIsRelativeToSiblings(pseudoClassType())); |
445 | } |
446 | |
447 | inline bool CSSSelector::isAttributeSelector() const |
448 | { |
449 | return match() == CSSSelector::Exact |
450 | || match() == CSSSelector::Set |
451 | || match() == CSSSelector::List |
452 | || match() == CSSSelector::Hyphen |
453 | || match() == CSSSelector::Contain |
454 | || match() == CSSSelector::Begin |
455 | || match() == CSSSelector::End; |
456 | } |
457 | |
458 | inline void CSSSelector::setValue(const AtomicString& value, bool matchLowerCase) |
459 | { |
460 | ASSERT(match() != Tag); |
461 | AtomicString matchingValue = matchLowerCase ? value.convertToASCIILowercase() : value; |
462 | if (!m_hasRareData && matchingValue != value) |
463 | createRareData(); |
464 | |
465 | // Need to do ref counting manually for the union. |
466 | if (!m_hasRareData) { |
467 | if (m_data.m_value) |
468 | m_data.m_value->deref(); |
469 | m_data.m_value = value.impl(); |
470 | m_data.m_value->ref(); |
471 | return; |
472 | } |
473 | |
474 | m_data.m_rareData->m_matchingValue = WTFMove(matchingValue); |
475 | m_data.m_rareData->m_serializingValue = value; |
476 | } |
477 | |
478 | inline CSSSelector::CSSSelector() |
479 | : m_relation(DescendantSpace) |
480 | , m_match(Unknown) |
481 | , m_pseudoType(0) |
482 | , m_isLastInSelectorList(false) |
483 | , m_isLastInTagHistory(true) |
484 | , m_hasRareData(false) |
485 | , m_hasNameWithCase(false) |
486 | , m_isForPage(false) |
487 | , m_tagIsForNamespaceRule(false) |
488 | , m_caseInsensitiveAttributeValueMatching(false) |
489 | #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
490 | , m_destructorHasBeenCalled(false) |
491 | #endif |
492 | { |
493 | } |
494 | |
495 | inline CSSSelector::CSSSelector(const CSSSelector& o) |
496 | : m_relation(o.m_relation) |
497 | , m_match(o.m_match) |
498 | , m_pseudoType(o.m_pseudoType) |
499 | , m_isLastInSelectorList(o.m_isLastInSelectorList) |
500 | , m_isLastInTagHistory(o.m_isLastInTagHistory) |
501 | , m_hasRareData(o.m_hasRareData) |
502 | , m_hasNameWithCase(o.m_hasNameWithCase) |
503 | , m_isForPage(o.m_isForPage) |
504 | , m_tagIsForNamespaceRule(o.m_tagIsForNamespaceRule) |
505 | , m_caseInsensitiveAttributeValueMatching(o.m_caseInsensitiveAttributeValueMatching) |
506 | #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
507 | , m_destructorHasBeenCalled(false) |
508 | #endif |
509 | { |
510 | if (o.m_hasRareData) { |
511 | m_data.m_rareData = o.m_data.m_rareData; |
512 | m_data.m_rareData->ref(); |
513 | } else if (o.m_hasNameWithCase) { |
514 | m_data.m_nameWithCase = o.m_data.m_nameWithCase; |
515 | m_data.m_nameWithCase->ref(); |
516 | } if (o.match() == Tag) { |
517 | m_data.m_tagQName = o.m_data.m_tagQName; |
518 | m_data.m_tagQName->ref(); |
519 | } else if (o.m_data.m_value) { |
520 | m_data.m_value = o.m_data.m_value; |
521 | m_data.m_value->ref(); |
522 | } |
523 | } |
524 | |
525 | inline CSSSelector::~CSSSelector() |
526 | { |
527 | ASSERT_WITH_SECURITY_IMPLICATION(!m_destructorHasBeenCalled); |
528 | #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
529 | m_destructorHasBeenCalled = true; |
530 | #endif |
531 | if (m_hasRareData) { |
532 | m_data.m_rareData->deref(); |
533 | m_data.m_rareData = nullptr; |
534 | m_hasRareData = false; |
535 | } else if (m_hasNameWithCase) { |
536 | m_data.m_nameWithCase->deref(); |
537 | m_data.m_nameWithCase = nullptr; |
538 | m_hasNameWithCase = false; |
539 | } else if (match() == Tag) { |
540 | m_data.m_tagQName->deref(); |
541 | m_data.m_tagQName = nullptr; |
542 | m_match = Unknown; |
543 | } else if (m_data.m_value) { |
544 | m_data.m_value->deref(); |
545 | m_data.m_value = nullptr; |
546 | } |
547 | } |
548 | |
549 | inline const QualifiedName& CSSSelector::tagQName() const |
550 | { |
551 | ASSERT(match() == Tag); |
552 | if (m_hasNameWithCase) |
553 | return m_data.m_nameWithCase->m_originalName; |
554 | return *reinterpret_cast<const QualifiedName*>(&m_data.m_tagQName); |
555 | } |
556 | |
557 | inline const AtomicString& CSSSelector::tagLowercaseLocalName() const |
558 | { |
559 | if (m_hasNameWithCase) |
560 | return m_data.m_nameWithCase->m_lowercaseLocalName; |
561 | return m_data.m_tagQName->m_localName; |
562 | } |
563 | |
564 | inline const AtomicString& CSSSelector::value() const |
565 | { |
566 | ASSERT(match() != Tag); |
567 | if (m_hasRareData) |
568 | return m_data.m_rareData->m_matchingValue; |
569 | |
570 | // AtomicString is really just an AtomicStringImpl* so the cast below is safe. |
571 | return *reinterpret_cast<const AtomicString*>(&m_data.m_value); |
572 | } |
573 | |
574 | inline const AtomicString& CSSSelector::serializingValue() const |
575 | { |
576 | ASSERT(match() != Tag); |
577 | if (m_hasRareData) |
578 | return m_data.m_rareData->m_serializingValue; |
579 | |
580 | // AtomicString is really just an AtomicStringImpl* so the cast below is safe. |
581 | return *reinterpret_cast<const AtomicString*>(&m_data.m_value); |
582 | } |
583 | |
584 | inline bool CSSSelector::attributeValueMatchingIsCaseInsensitive() const |
585 | { |
586 | return m_caseInsensitiveAttributeValueMatching; |
587 | } |
588 | |
589 | } // namespace WebCore |
590 | |