1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 //! Helper module to build up a selector safely and efficiently.
6 //!
7 //! Our selector representation is designed to optimize matching, and has
8 //! several requirements:
9 //! * All simple selectors and combinators are stored inline in the same buffer
10 //! as Component instances.
11 //! * We store the top-level compound selectors from right to left, i.e. in
12 //! matching order.
13 //! * We store the simple selectors for each combinator from left to right, so
14 //! that we match the cheaper simple selectors first.
15 //!
16 //! Meeting all these constraints without extra memmove traffic during parsing
17 //! is non-trivial. This module encapsulates those details and presents an
18 //! easy-to-use API for the parser.
19
20 use parser::{Combinator, Component, SelectorImpl};
21 use servo_arc::{Arc, HeaderWithLength, ThinArc};
22 use sink::Push;
23 use smallvec::{self, SmallVec};
24 use std::cmp;
25 use std::iter;
26 use std::ops::Add;
27 use std::ptr;
28 use std::slice;
29
30 /// Top-level SelectorBuilder struct. This should be stack-allocated by the
31 /// consumer and never moved (because it contains a lot of inline data that
32 /// would be slow to memmov).
33 ///
34 /// After instantation, callers may call the push_simple_selector() and
35 /// push_combinator() methods to append selector data as it is encountered
36 /// (from left to right). Once the process is complete, callers should invoke
37 /// build(), which transforms the contents of the SelectorBuilder into a heap-
38 /// allocated Selector and leaves the builder in a drained state.
39 pub struct SelectorBuilder<Impl: SelectorImpl> {
40 /// The entire sequence of simple selectors, from left to right, without combinators.
41 ///
42 /// We make this large because the result of parsing a selector is fed into a new
43 /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also,
44 /// Components are large enough that we don't have much cache locality benefit
45 /// from reserving stack space for fewer of them.
46 simple_selectors: SmallVec<[Component<Impl>; 32]>,
47 /// The combinators, and the length of the compound selector to their left.
48 combinators: SmallVec<[(Combinator, usize); 16]>,
49 /// The length of the current compount selector.
50 current_len: usize,
51 }
52
53 impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
54 #[inline(always)]
default() -> Self55 fn default() -> Self {
56 SelectorBuilder {
57 simple_selectors: SmallVec::new(),
58 combinators: SmallVec::new(),
59 current_len: 0,
60 }
61 }
62 }
63
64 impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
push(&mut self, value: Component<Impl>)65 fn push(&mut self, value: Component<Impl>) {
66 self.push_simple_selector(value);
67 }
68 }
69
70 impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
71 /// Pushes a simple selector onto the current compound selector.
72 #[inline(always)]
push_simple_selector(&mut self, ss: Component<Impl>)73 pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
74 debug_assert!(!ss.is_combinator());
75 self.simple_selectors.push(ss);
76 self.current_len += 1;
77 }
78
79 /// Completes the current compound selector and starts a new one, delimited
80 /// by the given combinator.
81 #[inline(always)]
push_combinator(&mut self, c: Combinator)82 pub fn push_combinator(&mut self, c: Combinator) {
83 self.combinators.push((c, self.current_len));
84 self.current_len = 0;
85 }
86
87 /// Returns true if no simple selectors have ever been pushed to this builder.
88 #[inline(always)]
is_empty(&self) -> bool89 pub fn is_empty(&self) -> bool {
90 self.simple_selectors.is_empty()
91 }
92
93 /// Returns true if combinators have ever been pushed to this builder.
94 #[inline(always)]
has_combinators(&self) -> bool95 pub fn has_combinators(&self) -> bool {
96 !self.combinators.is_empty()
97 }
98
99 /// Consumes the builder, producing a Selector.
100 #[inline(always)]
build( &mut self, parsed_pseudo: bool, parsed_slotted: bool, ) -> ThinArc<SpecificityAndFlags, Component<Impl>>101 pub fn build(
102 &mut self,
103 parsed_pseudo: bool,
104 parsed_slotted: bool,
105 ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
106 // Compute the specificity and flags.
107 let mut spec = SpecificityAndFlags(specificity(self.simple_selectors.iter()));
108 if parsed_pseudo {
109 spec.0 |= HAS_PSEUDO_BIT;
110 }
111
112 if parsed_slotted {
113 spec.0 |= HAS_SLOTTED_BIT;
114 }
115
116 self.build_with_specificity_and_flags(spec)
117 }
118
119
120 /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
121 /// that unit tests can pass an explicit specificity.
122 #[inline(always)]
build_with_specificity_and_flags(&mut self, spec: SpecificityAndFlags) -> ThinArc<SpecificityAndFlags, Component<Impl>>123 pub fn build_with_specificity_and_flags(&mut self, spec: SpecificityAndFlags)
124 -> ThinArc<SpecificityAndFlags, Component<Impl>> {
125 // First, compute the total number of Components we'll need to allocate
126 // space for.
127 let full_len = self.simple_selectors.len() + self.combinators.len();
128
129 // Create the header.
130 let header = HeaderWithLength::new(spec, full_len);
131
132 // Create the Arc using an iterator that drains our buffers.
133
134 // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
135 // This is similar to SmallVec::drain, but we use a slice here because
136 // we’re gonna traverse it non-linearly.
137 let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
138 unsafe {
139 // Panic-safety: if SelectorBuilderIter is not iterated to the end,
140 // some simple selectors will safely leak.
141 self.simple_selectors.set_len(0)
142 }
143 let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
144 let iter = SelectorBuilderIter {
145 current_simple_selectors: current.iter(),
146 rest_of_simple_selectors: rest,
147 combinators: self.combinators.drain().rev(),
148 };
149
150 Arc::into_thin(Arc::from_header_and_iter(header, iter))
151 }
152 }
153
154 struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
155 current_simple_selectors: slice::Iter<'a, Component<Impl>>,
156 rest_of_simple_selectors: &'a [Component<Impl>],
157 combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>,
158 }
159
160 impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
len(&self) -> usize161 fn len(&self) -> usize {
162 self.current_simple_selectors.len() +
163 self.rest_of_simple_selectors.len() +
164 self.combinators.len()
165 }
166 }
167
168 impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
169 type Item = Component<Impl>;
170 #[inline(always)]
next(&mut self) -> Option<Self::Item>171 fn next(&mut self) -> Option<Self::Item> {
172 if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
173 // Move a simple selector out of this slice iterator.
174 // This is safe because we’ve called SmallVec::set_len(0) above,
175 // so SmallVec::drop won’t drop this simple selector.
176 unsafe {
177 Some(ptr::read(simple_selector_ref))
178 }
179 } else {
180 self.combinators.next().map(|(combinator, len)| {
181 let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
182 self.rest_of_simple_selectors = rest;
183 self.current_simple_selectors = current.iter();
184 Component::Combinator(combinator)
185 })
186 }
187 }
188
size_hint(&self) -> (usize, Option<usize>)189 fn size_hint(&self) -> (usize, Option<usize>) {
190 (self.len(), Some(self.len()))
191 }
192 }
193
split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T])194 fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
195 s.split_at(s.len() - at)
196 }
197
198 pub const HAS_PSEUDO_BIT: u32 = 1 << 30;
199 pub const HAS_SLOTTED_BIT: u32 = 1 << 31;
200
201 /// We use ten bits for each specificity kind (id, class, element), and the two
202 /// high bits for the pseudo and slotted flags.
203 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
204 pub struct SpecificityAndFlags(pub u32);
205
206 impl SpecificityAndFlags {
207 #[inline]
specificity(&self) -> u32208 pub fn specificity(&self) -> u32 {
209 self.0 & !(HAS_PSEUDO_BIT | HAS_SLOTTED_BIT)
210 }
211
212 #[inline]
has_pseudo_element(&self) -> bool213 pub fn has_pseudo_element(&self) -> bool {
214 (self.0 & HAS_PSEUDO_BIT) != 0
215 }
216
217 #[inline]
is_slotted(&self) -> bool218 pub fn is_slotted(&self) -> bool {
219 (self.0 & HAS_SLOTTED_BIT) != 0
220 }
221 }
222
223 const MAX_10BIT: u32 = (1u32 << 10) - 1;
224
225 #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
226 struct Specificity {
227 id_selectors: u32,
228 class_like_selectors: u32,
229 element_selectors: u32,
230 }
231
232 impl Add for Specificity {
233 type Output = Specificity;
234
add(self, rhs: Specificity) -> Specificity235 fn add(self, rhs: Specificity) -> Specificity {
236 Specificity {
237 id_selectors: self.id_selectors + rhs.id_selectors,
238 class_like_selectors:
239 self.class_like_selectors + rhs.class_like_selectors,
240 element_selectors:
241 self.element_selectors + rhs.element_selectors,
242 }
243 }
244 }
245
246 impl Default for Specificity {
default() -> Specificity247 fn default() -> Specificity {
248 Specificity {
249 id_selectors: 0,
250 class_like_selectors: 0,
251 element_selectors: 0,
252 }
253 }
254 }
255
256 impl From<u32> for Specificity {
from(value: u32) -> Specificity257 fn from(value: u32) -> Specificity {
258 assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
259 Specificity {
260 id_selectors: value >> 20,
261 class_like_selectors: (value >> 10) & MAX_10BIT,
262 element_selectors: value & MAX_10BIT,
263 }
264 }
265 }
266
267 impl From<Specificity> for u32 {
from(specificity: Specificity) -> u32268 fn from(specificity: Specificity) -> u32 {
269 cmp::min(specificity.id_selectors, MAX_10BIT) << 20
270 | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
271 | cmp::min(specificity.element_selectors, MAX_10BIT)
272 }
273 }
274
specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> u32 where Impl: SelectorImpl275 fn specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> u32
276 where Impl: SelectorImpl
277 {
278 complex_selector_specificity(iter).into()
279 }
280
complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>) -> Specificity where Impl: SelectorImpl281 fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>)
282 -> Specificity
283 where Impl: SelectorImpl
284 {
285 fn simple_selector_specificity<Impl>(
286 simple_selector: &Component<Impl>,
287 specificity: &mut Specificity,
288 )
289 where
290 Impl: SelectorImpl
291 {
292 match *simple_selector {
293 Component::Combinator(..) => unreachable!(),
294 // FIXME(emilio): Spec doesn't define any particular specificity for
295 // ::slotted(), so apply the general rule for pseudos per:
296 //
297 // https://github.com/w3c/csswg-drafts/issues/1915
298 //
299 // Though other engines compute it dynamically, so maybe we should
300 // do that instead, eventually.
301 Component::Slotted(..) |
302 Component::PseudoElement(..) |
303 Component::LocalName(..) => {
304 specificity.element_selectors += 1
305 }
306 Component::ID(..) => {
307 specificity.id_selectors += 1
308 }
309 Component::Class(..) |
310 Component::AttributeInNoNamespace { .. } |
311 Component::AttributeInNoNamespaceExists { .. } |
312 Component::AttributeOther(..) |
313
314 Component::FirstChild | Component::LastChild |
315 Component::OnlyChild | Component::Root |
316 Component::Empty | Component::Scope |
317 Component::NthChild(..) |
318 Component::NthLastChild(..) |
319 Component::NthOfType(..) |
320 Component::NthLastOfType(..) |
321 Component::FirstOfType | Component::LastOfType |
322 Component::OnlyOfType |
323 Component::NonTSPseudoClass(..) => {
324 specificity.class_like_selectors += 1
325 }
326 Component::ExplicitUniversalType |
327 Component::ExplicitAnyNamespace |
328 Component::ExplicitNoNamespace |
329 Component::DefaultNamespace(..) |
330 Component::Namespace(..) => {
331 // Does not affect specificity
332 }
333 Component::Negation(ref negated) => {
334 for ss in negated.iter() {
335 simple_selector_specificity(&ss, specificity);
336 }
337 }
338 }
339 }
340
341 let mut specificity = Default::default();
342 for simple_selector in &mut iter {
343 simple_selector_specificity(&simple_selector, &mut specificity);
344 }
345 specificity
346 }
347