1/*
2 * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "CSSSelectorList.h"
29#include "ExceptionOr.h"
30#include "NodeList.h"
31#include "SelectorCompiler.h"
32#include <wtf/HashMap.h>
33#include <wtf/Vector.h>
34#include <wtf/text/AtomStringHash.h>
35
36namespace WebCore {
37
38class CSSSelector;
39class ContainerNode;
40class Document;
41class Element;
42
43class SelectorDataList {
44public:
45 explicit SelectorDataList(const CSSSelectorList&);
46 bool matches(Element&) const;
47 Element* closest(Element&) const;
48 Ref<NodeList> queryAll(ContainerNode& rootNode) const;
49 Element* queryFirst(ContainerNode& rootNode) const;
50
51private:
52 struct SelectorData {
53 SelectorData(const CSSSelector* selector)
54 : selector(selector)
55#if ENABLE(CSS_SELECTOR_JIT) && CSS_SELECTOR_JIT_PROFILING
56 , m_compiledSelectorUseCount(0)
57#endif
58 {
59 }
60
61 const CSSSelector* selector;
62#if ENABLE(CSS_SELECTOR_JIT)
63 mutable JSC::MacroAssemblerCodeRef<CSSSelectorPtrTag> compiledSelectorCodeRef;
64 mutable SelectorCompilationStatus compilationStatus;
65#if CSS_SELECTOR_JIT_PROFILING
66 ~SelectorData()
67 {
68 if (compiledSelectorCodeRef.code().executableAddress())
69 dataLogF("SelectorData compiled selector %d \"%s\"\n", m_compiledSelectorUseCount, selector->selectorText().utf8().data());
70 }
71 mutable unsigned m_compiledSelectorUseCount;
72 void compiledSelectorUsed() const { m_compiledSelectorUseCount++; }
73#endif
74#endif // ENABLE(CSS_SELECTOR_JIT)
75 };
76
77 bool selectorMatches(const SelectorData&, Element&, const ContainerNode& rootNode) const;
78 Element* selectorClosest(const SelectorData&, Element&, const ContainerNode& rootNode) const;
79
80 template <typename SelectorQueryTrait> void execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
81 template <typename SelectorQueryTrait> void executeFastPathForIdSelector(const ContainerNode& rootNode, const SelectorData&, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType&) const;
82 template <typename SelectorQueryTrait> void executeSingleTagNameSelectorData(const ContainerNode& rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
83 template <typename SelectorQueryTrait> void executeSingleClassNameSelectorData(const ContainerNode& rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
84 template <typename SelectorQueryTrait> void executeSingleSelectorData(const ContainerNode& rootNode, const ContainerNode& searchRootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
85 template <typename SelectorQueryTrait> void executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
86#if ENABLE(CSS_SELECTOR_JIT)
87 template <typename SelectorQueryTrait> void executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
88 template <typename SelectorQueryTrait> void executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
89 template <typename SelectorQueryTrait> void executeCompiledSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
90 static bool compileSelector(const SelectorData&);
91#endif // ENABLE(CSS_SELECTOR_JIT)
92
93 Vector<SelectorData> m_selectors;
94 mutable enum MatchType {
95 CompilableSingle,
96 CompilableSingleWithRootFilter,
97 CompilableMultipleSelectorMatch,
98 CompiledSingle,
99 CompiledSingleWithRootFilter,
100 CompiledMultipleSelectorMatch,
101 SingleSelector,
102 SingleSelectorWithRootFilter,
103 RightMostWithIdMatch,
104 TagNameMatch,
105 ClassNameMatch,
106 MultipleSelectorMatch,
107 } m_matchType;
108};
109
110class SelectorQuery {
111 WTF_MAKE_NONCOPYABLE(SelectorQuery);
112 WTF_MAKE_FAST_ALLOCATED;
113
114public:
115 explicit SelectorQuery(CSSSelectorList&&);
116 bool matches(Element&) const;
117 Element* closest(Element&) const;
118 Ref<NodeList> queryAll(ContainerNode& rootNode) const;
119 Element* queryFirst(ContainerNode& rootNode) const;
120
121private:
122 CSSSelectorList m_selectorList;
123 SelectorDataList m_selectors;
124};
125
126class SelectorQueryCache {
127 WTF_MAKE_FAST_ALLOCATED;
128public:
129 ExceptionOr<SelectorQuery&> add(const String&, Document&);
130private:
131 HashMap<String, std::unique_ptr<SelectorQuery>> m_entries;
132};
133
134inline bool SelectorQuery::matches(Element& element) const
135{
136 return m_selectors.matches(element);
137}
138
139inline Element* SelectorQuery::closest(Element& element) const
140{
141 return m_selectors.closest(element);
142}
143
144inline Ref<NodeList> SelectorQuery::queryAll(ContainerNode& rootNode) const
145{
146 return m_selectors.queryAll(rootNode);
147}
148
149inline Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const
150{
151 return m_selectors.queryFirst(rootNode);
152}
153
154} // namespace WebCore
155