Use a 1-byte enum class for TextDirection
[WebKit-https.git] / Source / WebCore / dom / SelectorQuery.cpp
1 /*
2  * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
3  * Copyright (C) 2014 Yusuke Suzuki <utatane.tea@gmail.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "SelectorQuery.h"
29
30 #include "CSSParser.h"
31 #include "ElementDescendantIterator.h"
32 #include "HTMLNames.h"
33 #include "SelectorChecker.h"
34 #include "StaticNodeList.h"
35 #include "StyledElement.h"
36
37 namespace WebCore {
38
39 #if !ASSERT_DISABLED
40 static bool isSingleTagNameSelector(const CSSSelector& selector)
41 {
42     return selector.isLastInTagHistory() && selector.match() == CSSSelector::Tag;
43 }
44
45 static bool isSingleClassNameSelector(const CSSSelector& selector)
46 {
47     return selector.isLastInTagHistory() && selector.match() == CSSSelector::Class;
48 }
49 #endif
50
51 enum class IdMatchingType : uint8_t {
52     None,
53     Rightmost,
54     Filter
55 };
56
57 static bool canBeUsedForIdFastPath(const CSSSelector& selector)
58 {
59     return selector.match() == CSSSelector::Id
60         || (selector.match() == CSSSelector::Exact && selector.attribute() == HTMLNames::idAttr && !selector.attributeValueMatchingIsCaseInsensitive());
61 }
62
63 static IdMatchingType findIdMatchingType(const CSSSelector& firstSelector)
64 {
65     bool inRightmost = true;
66     for (const CSSSelector* selector = &firstSelector; selector; selector = selector->tagHistory()) {
67         if (canBeUsedForIdFastPath(*selector)) {
68             if (inRightmost)
69                 return IdMatchingType::Rightmost;
70             return IdMatchingType::Filter;
71         }
72         if (selector->relation() != CSSSelector::Subselector)
73             inRightmost = false;
74     }
75     return IdMatchingType::None;
76 }
77
78 SelectorDataList::SelectorDataList(const CSSSelectorList& selectorList)
79 {
80     unsigned selectorCount = 0;
81     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
82         selectorCount++;
83
84     m_selectors.reserveInitialCapacity(selectorCount);
85     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
86         m_selectors.uncheckedAppend(SelectorData(selector));
87
88     if (selectorCount == 1) {
89         const CSSSelector& selector = *m_selectors.first().selector;
90         if (selector.isLastInTagHistory()) {
91             switch (selector.match()) {
92             case CSSSelector::Tag:
93                 m_matchType = TagNameMatch;
94                 break;
95             case CSSSelector::Class:
96                 m_matchType = ClassNameMatch;
97                 break;
98             default:
99                 if (canBeUsedForIdFastPath(selector))
100                     m_matchType = RightMostWithIdMatch;
101                 else
102                     m_matchType = CompilableSingle;
103                 break;
104             }
105         } else {
106             switch (findIdMatchingType(selector)) {
107             case IdMatchingType::None:
108                 m_matchType = CompilableSingle;
109                 break;
110             case IdMatchingType::Rightmost:
111                 m_matchType = RightMostWithIdMatch;
112                 break;
113             case IdMatchingType::Filter:
114                 m_matchType = CompilableSingleWithRootFilter;
115                 break;
116             }
117         }
118     } else
119         m_matchType = CompilableMultipleSelectorMatch;
120 }
121
122 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
123 {
124     SelectorChecker selectorChecker(element.document());
125     SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
126     selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
127     unsigned ignoredSpecificity;
128     return selectorChecker.match(*selectorData.selector, element, selectorCheckingContext, ignoredSpecificity);
129 }
130
131 inline Element* SelectorDataList::selectorClosest(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
132 {
133     SelectorChecker selectorChecker(element.document());
134     SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
135     selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
136     unsigned ignoredSpecificity;
137     if (!selectorChecker.match(*selectorData.selector, element, selectorCheckingContext, ignoredSpecificity))
138         return nullptr;
139     return &element;
140 }
141
142 bool SelectorDataList::matches(Element& targetElement) const
143 {
144     for (auto& selctor : m_selectors) {
145         if (selectorMatches(selctor, targetElement, targetElement))
146             return true;
147     }
148     return false;
149 }
150
151 Element* SelectorDataList::closest(Element& targetElement) const
152 {
153     Element* currentNode = &targetElement;
154     do {
155         for (auto& selector : m_selectors) {
156             Element* candidateElement = selectorClosest(selector, *currentNode, targetElement);
157             if (candidateElement)
158                 return candidateElement;
159         }
160         currentNode = currentNode->parentElement();
161     } while (currentNode);
162     return nullptr;
163 }
164
165 struct AllElementExtractorSelectorQueryTrait {
166     typedef Vector<Ref<Element>> OutputType;
167     static const bool shouldOnlyMatchFirstElement = false;
168     ALWAYS_INLINE static void appendOutputForElement(OutputType& output, Element* element) { ASSERT(element); output.append(*element); }
169 };
170
171 Ref<NodeList> SelectorDataList::queryAll(ContainerNode& rootNode) const
172 {
173     Vector<Ref<Element>> result;
174     execute<AllElementExtractorSelectorQueryTrait>(rootNode, result);
175     return StaticElementList::create(WTFMove(result));
176 }
177
178 struct SingleElementExtractorSelectorQueryTrait {
179     typedef Element* OutputType;
180     static const bool shouldOnlyMatchFirstElement = true;
181     ALWAYS_INLINE static void appendOutputForElement(OutputType& output, Element* element)
182     {
183         ASSERT(element);
184         ASSERT(!output);
185         output = element;
186     }
187 };
188
189 Element* SelectorDataList::queryFirst(ContainerNode& rootNode) const
190 {
191     Element* result = nullptr;
192     execute<SingleElementExtractorSelectorQueryTrait>(rootNode, result);
193     return result;
194 }
195
196 static const CSSSelector* selectorForIdLookup(const ContainerNode& rootNode, const CSSSelector& firstSelector)
197 {
198     if (!rootNode.isConnected())
199         return nullptr;
200     if (rootNode.document().inQuirksMode())
201         return nullptr;
202
203     for (const CSSSelector* selector = &firstSelector; selector; selector = selector->tagHistory()) {
204         if (canBeUsedForIdFastPath(*selector))
205             return selector;
206         if (selector->relation() != CSSSelector::Subselector)
207             break;
208     }
209
210     return nullptr;
211 }
212
213 static inline bool isTreeScopeRoot(const ContainerNode& node)
214 {
215     return node.isDocumentNode() || node.isShadowRoot();
216 }
217
218 template <typename SelectorQueryTrait>
219 ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const ContainerNode& rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType& output) const
220 {
221     ASSERT(m_selectors.size() == 1);
222     ASSERT(idSelector);
223
224     const AtomicString& idToMatch = idSelector->value();
225     if (UNLIKELY(rootNode.treeScope().containsMultipleElementsWithId(idToMatch))) {
226         const Vector<Element*>* elements = rootNode.treeScope().getAllElementsById(idToMatch);
227         ASSERT(elements);
228         bool rootNodeIsTreeScopeRoot = isTreeScopeRoot(rootNode);
229         for (auto& element : *elements) {
230             if ((rootNodeIsTreeScopeRoot || element->isDescendantOf(rootNode)) && selectorMatches(selectorData, *element, rootNode)) {
231                 SelectorQueryTrait::appendOutputForElement(output, element);
232                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
233                     return;
234             }
235         }
236         return;
237     }
238
239     Element* element = rootNode.treeScope().getElementById(idToMatch);
240     if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode)))
241         return;
242     if (selectorMatches(selectorData, *element, rootNode))
243         SelectorQueryTrait::appendOutputForElement(output, element);
244 }
245
246 static ContainerNode& filterRootById(ContainerNode& rootNode, const CSSSelector& firstSelector)
247 {
248     if (!rootNode.isConnected())
249         return rootNode;
250     if (rootNode.document().inQuirksMode())
251         return rootNode;
252
253     // If there was an Id match in the rightmost Simple Selector, we should be in a RightMostWithIdMatch, not in filter.
254     // Thus we can skip the rightmost match.
255     const CSSSelector* selector = &firstSelector;
256     do {
257         ASSERT(!canBeUsedForIdFastPath(*selector));
258         if (selector->relation() != CSSSelector::Subselector)
259             break;
260         selector = selector->tagHistory();
261     } while (selector);
262
263     bool inAdjacentChain = false;
264     for (; selector; selector = selector->tagHistory()) {
265         if (canBeUsedForIdFastPath(*selector)) {
266             const AtomicString& idToMatch = selector->value();
267             if (ContainerNode* searchRoot = rootNode.treeScope().getElementById(idToMatch)) {
268                 if (LIKELY(!rootNode.treeScope().containsMultipleElementsWithId(idToMatch))) {
269                     if (inAdjacentChain)
270                         searchRoot = searchRoot->parentNode();
271                     if (searchRoot && (isTreeScopeRoot(rootNode) || searchRoot == &rootNode || searchRoot->isDescendantOf(rootNode)))
272                         return *searchRoot;
273                 }
274             }
275         }
276         if (selector->relation() == CSSSelector::Subselector)
277             continue;
278         if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent)
279             inAdjacentChain = true;
280         else
281             inAdjacentChain = false;
282     }
283     return rootNode;
284 }
285
286 static ALWAYS_INLINE bool localNameMatches(const Element& element, const AtomicString& localName, const AtomicString& lowercaseLocalName)
287 {
288     if (element.isHTMLElement() && element.document().isHTMLDocument())
289         return element.localName() == lowercaseLocalName;
290     return element.localName() == localName;
291
292 }
293
294 template <typename SelectorQueryTrait>
295 static inline void elementsForLocalName(const ContainerNode& rootNode, const AtomicString& localName, const AtomicString& lowercaseLocalName, typename SelectorQueryTrait::OutputType& output)
296 {
297     if (localName == lowercaseLocalName) {
298         for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
299             if (element.tagQName().localName() == localName) {
300                 SelectorQueryTrait::appendOutputForElement(output, &element);
301                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
302                 return;
303             }
304         }
305     } else {
306         for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
307             if (localNameMatches(element, localName, lowercaseLocalName)) {
308                 SelectorQueryTrait::appendOutputForElement(output, &element);
309                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
310                 return;
311             }
312         }
313     }
314 }
315
316 template <typename SelectorQueryTrait>
317 static inline void anyElement(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output)
318 {
319     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
320         SelectorQueryTrait::appendOutputForElement(output, &element);
321         if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
322             return;
323     }
324 }
325
326
327 template <typename SelectorQueryTrait>
328 ALWAYS_INLINE void SelectorDataList::executeSingleTagNameSelectorData(const ContainerNode& rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
329 {
330     ASSERT(m_selectors.size() == 1);
331     ASSERT(isSingleTagNameSelector(*selectorData.selector));
332
333     const QualifiedName& tagQualifiedName = selectorData.selector->tagQName();
334     const AtomicString& selectorLocalName = tagQualifiedName.localName();
335     const AtomicString& selectorLowercaseLocalName = selectorData.selector->tagLowercaseLocalName();
336     const AtomicString& selectorNamespaceURI = tagQualifiedName.namespaceURI();
337
338     if (selectorNamespaceURI == starAtom()) {
339         if (selectorLocalName != starAtom()) {
340             // Common case: name defined, selectorNamespaceURI is a wildcard.
341             elementsForLocalName<SelectorQueryTrait>(rootNode, selectorLocalName, selectorLowercaseLocalName, output);
342         } else {
343             // Other fairly common case: both are wildcards.
344             anyElement<SelectorQueryTrait>(rootNode, output);
345         }
346     } else {
347         // Fallback: NamespaceURI is set, selectorLocalName may be starAtom().
348         for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
349             if (element.namespaceURI() == selectorNamespaceURI && localNameMatches(element, selectorLocalName, selectorLowercaseLocalName)) {
350                 SelectorQueryTrait::appendOutputForElement(output, &element);
351                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
352                     return;
353             }
354         }
355     }
356 }
357
358 template <typename SelectorQueryTrait>
359 ALWAYS_INLINE void SelectorDataList::executeSingleClassNameSelectorData(const ContainerNode& rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
360 {
361     ASSERT(m_selectors.size() == 1);
362     ASSERT(isSingleClassNameSelector(*selectorData.selector));
363
364     const AtomicString& className = selectorData.selector->value();
365     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
366         if (element.hasClass() && element.classNames().contains(className)) {
367             SelectorQueryTrait::appendOutputForElement(output, &element);
368             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
369                 return;
370         }
371     }
372 }
373
374 template <typename SelectorQueryTrait>
375 ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const ContainerNode& rootNode, const ContainerNode& searchRootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
376 {
377     ASSERT(m_selectors.size() == 1);
378
379     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
380         if (selectorMatches(selectorData, element, rootNode)) {
381             SelectorQueryTrait::appendOutputForElement(output, &element);
382             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
383                 return;
384         }
385     }
386 }
387
388 template <typename SelectorQueryTrait>
389 ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
390 {
391     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
392         for (auto& selector : m_selectors) {
393             if (selectorMatches(selector, element, rootNode)) {
394                 SelectorQueryTrait::appendOutputForElement(output, &element);
395                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
396                     return;
397                 break;
398             }
399         }
400     }
401 }
402
403 #if ENABLE(CSS_SELECTOR_JIT)
404 template <typename SelectorQueryTrait>
405 ALWAYS_INLINE void SelectorDataList::executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
406 {
407     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
408 #if CSS_SELECTOR_JIT_PROFILING
409         selectorData.compiledSelectorUsed();
410 #else
411         UNUSED_PARAM(selectorData);
412 #endif
413         if (selectorChecker(&element)) {
414             SelectorQueryTrait::appendOutputForElement(output, &element);
415             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
416                 return;
417         }
418     }
419 }
420
421 template <typename SelectorQueryTrait>
422 ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
423 {
424     SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules);
425     checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
426
427     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
428 #if CSS_SELECTOR_JIT_PROFILING
429         selectorData.compiledSelectorUsed();
430 #else
431         UNUSED_PARAM(selectorData);
432 #endif
433         if (selectorChecker(&element, &checkingContext)) {
434             SelectorQueryTrait::appendOutputForElement(output, &element);
435             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
436                 return;
437         }
438     }
439 }
440
441 template <typename SelectorQueryTrait>
442 ALWAYS_INLINE void SelectorDataList::executeCompiledSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
443 {
444     SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules);
445     checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
446     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
447         for (auto& selector : m_selectors) {
448 #if CSS_SELECTOR_JIT_PROFILING
449             selector.compiledSelectorUsed();
450 #endif
451             bool matched = false;
452             void* compiledSelectorChecker = selector.compiledSelectorCodeRef.code().executableAddress();
453             if (selector.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
454                 auto selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, selector.compilationStatus);
455                 matched = selectorChecker(&element);
456             } else {
457                 ASSERT(selector.compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
458                 auto selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selector.compilationStatus);
459                 matched = selectorChecker(&element, &checkingContext);
460             }
461             if (matched) {
462                 SelectorQueryTrait::appendOutputForElement(output, &element);
463                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
464                     return;
465                 break;
466             }
467         }
468     }
469 }
470
471 static bool isCompiledSelector(SelectorCompilationStatus compilationStatus)
472 {
473     return compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker || compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext;
474 }
475
476 bool SelectorDataList::compileSelector(const SelectorData& selectorData)
477 {
478     if (selectorData.compilationStatus != SelectorCompilationStatus::NotCompiled)
479         return isCompiledSelector(selectorData.compilationStatus);
480
481     selectorData.compilationStatus = SelectorCompiler::compileSelector(selectorData.selector, SelectorCompiler::SelectorContext::QuerySelector, selectorData.compiledSelectorCodeRef);
482     return isCompiledSelector(selectorData.compilationStatus);
483 }
484
485
486 #endif // ENABLE(CSS_SELECTOR_JIT)
487
488 template <typename SelectorQueryTrait>
489 ALWAYS_INLINE void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
490 {
491     ContainerNode* searchRootNode = &rootNode;
492     switch (m_matchType) {
493     case RightMostWithIdMatch:
494         {
495         const SelectorData& selectorData = m_selectors.first();
496         if (const CSSSelector* idSelector = selectorForIdLookup(*searchRootNode, *selectorData.selector)) {
497             executeFastPathForIdSelector<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), idSelector, output);
498             break;
499         }
500 #if ENABLE(CSS_SELECTOR_JIT)
501         if (compileSelector(selectorData))
502             goto CompiledSingleCase;
503 #endif // ENABLE(CSS_SELECTOR_JIT)
504         goto SingleSelectorCase;
505         ASSERT_NOT_REACHED();
506         }
507
508     case CompilableSingleWithRootFilter:
509     case CompilableSingle:
510         {
511 #if ENABLE(CSS_SELECTOR_JIT)
512         const SelectorData& selectorData = m_selectors.first();
513         ASSERT(selectorData.compilationStatus == SelectorCompilationStatus::NotCompiled);
514         ASSERT(m_matchType == CompilableSingle || m_matchType == CompilableSingleWithRootFilter);
515         if (compileSelector(selectorData)) {
516             if (m_matchType == CompilableSingle) {
517                 m_matchType = CompiledSingle;
518                 goto CompiledSingleCase;
519             }
520             ASSERT(m_matchType == CompilableSingleWithRootFilter);
521             m_matchType = CompiledSingleWithRootFilter;
522             goto CompiledSingleWithRootFilterCase;
523         }
524 #endif // ENABLE(CSS_SELECTOR_JIT)
525         if (m_matchType == CompilableSingle) {
526             m_matchType = SingleSelector;
527             goto SingleSelectorCase;
528         }
529         ASSERT(m_matchType == CompilableSingleWithRootFilter);
530         m_matchType = SingleSelectorWithRootFilter;
531         goto SingleSelectorWithRootFilterCase;
532         ASSERT_NOT_REACHED();
533         }
534
535 #if ENABLE(CSS_SELECTOR_JIT)
536     case CompiledSingleWithRootFilter:
537         CompiledSingleWithRootFilterCase:
538         searchRootNode = &filterRootById(*searchRootNode, *m_selectors.first().selector);
539         FALLTHROUGH;
540     case CompiledSingle:
541         {
542         CompiledSingleCase:
543         const SelectorData& selectorData = m_selectors.first();
544         void* compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
545         if (selectorData.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
546             SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
547             executeCompiledSimpleSelectorChecker<SelectorQueryTrait>(*searchRootNode, selectorChecker, output, selectorData);
548         } else {
549             ASSERT(selectorData.compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
550             SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selectorData.compilationStatus);
551             executeCompiledSelectorCheckerWithCheckingContext<SelectorQueryTrait>(rootNode, *searchRootNode, selectorChecker, output, selectorData);
552         }
553         break;
554         }
555 #else
556     case CompiledSingleWithRootFilter:
557     case CompiledSingle:
558         ASSERT_NOT_REACHED();
559 #if ASSERT_DISABLED
560         FALLTHROUGH;
561 #endif
562 #endif // ENABLE(CSS_SELECTOR_JIT)
563
564     case SingleSelectorWithRootFilter:
565         SingleSelectorWithRootFilterCase:
566         searchRootNode = &filterRootById(*searchRootNode, *m_selectors.first().selector);
567         FALLTHROUGH;
568     case SingleSelector:
569         SingleSelectorCase:
570         executeSingleSelectorData<SelectorQueryTrait>(rootNode, *searchRootNode, m_selectors.first(), output);
571         break;
572
573     case TagNameMatch:
574         executeSingleTagNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
575         break;
576     case ClassNameMatch:
577         executeSingleClassNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
578         break;
579     case CompilableMultipleSelectorMatch:
580 #if ENABLE(CSS_SELECTOR_JIT)
581         {
582         for (auto& selector : m_selectors) {
583             if (!compileSelector(selector)) {
584                 m_matchType = MultipleSelectorMatch;
585                 goto MultipleSelectorMatch;
586             }
587         }
588         m_matchType = CompiledMultipleSelectorMatch;
589         goto CompiledMultipleSelectorMatch;
590         }
591 #else
592         FALLTHROUGH;
593 #endif // ENABLE(CSS_SELECTOR_JIT)
594     case CompiledMultipleSelectorMatch:
595 #if ENABLE(CSS_SELECTOR_JIT)
596         CompiledMultipleSelectorMatch:
597         executeCompiledSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output);
598         break;
599 #else
600         FALLTHROUGH;
601 #endif // ENABLE(CSS_SELECTOR_JIT)
602     case MultipleSelectorMatch:
603 #if ENABLE(CSS_SELECTOR_JIT)
604         MultipleSelectorMatch:
605 #endif
606         executeSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output);
607         break;
608     }
609 }
610
611 SelectorQuery::SelectorQuery(CSSSelectorList&& selectorList)
612     : m_selectorList(WTFMove(selectorList))
613     , m_selectors(m_selectorList)
614 {
615 }
616
617 ExceptionOr<SelectorQuery&> SelectorQueryCache::add(const String& selectors, Document& document)
618 {
619     if (auto* entry = m_entries.get(selectors))
620         return *entry;
621
622     CSSParser parser(document);
623     CSSSelectorList selectorList;
624     parser.parseSelector(selectors, selectorList);
625
626     if (!selectorList.first() || selectorList.hasInvalidSelector())
627         return Exception { SyntaxError };
628
629     if (selectorList.selectorsNeedNamespaceResolution())
630         return Exception { SyntaxError };
631
632     const int maximumSelectorQueryCacheSize = 256;
633     if (m_entries.size() == maximumSelectorQueryCacheSize)
634         m_entries.remove(m_entries.begin());
635
636     return *m_entries.add(selectors, std::make_unique<SelectorQuery>(WTFMove(selectorList))).iterator->value;
637 }
638
639 }