1use crate::parser::{
27 Combinator, Component, ParseRelative, RelativeSelector, Selector, SelectorData, SelectorImpl,
28};
29use crate::sink::Push;
30use bitflags::bitflags;
31use derive_more::{Add, AddAssign};
32use servo_arc::Arc;
33use smallvec::SmallVec;
34use std::cmp;
35use std::slice;
36
37#[cfg(feature = "to_shmem")]
38use to_shmem_derive::ToShmem;
39
40#[derive(Debug)]
48pub struct SelectorBuilder<Impl: SelectorImpl> {
49 components: SmallVec<[Component<Impl>; 32]>,
54 last_compound_start: Option<usize>,
55}
56
57impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
58 fn push(&mut self, value: Component<Impl>) {
59 self.push_simple_selector(value);
60 }
61}
62
63impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
64 #[inline(always)]
66 pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
67 debug_assert!(!ss.is_combinator());
68 self.components.push(ss);
69 }
70
71 #[inline(always)]
74 pub fn push_combinator(&mut self, c: Combinator) {
75 self.reverse_last_compound();
76 self.components.push(Component::Combinator(c));
77 self.last_compound_start = Some(self.components.len());
78 }
79
80 fn reverse_last_compound(&mut self) {
81 let start = self.last_compound_start.unwrap_or(0);
82 self.components[start..].reverse();
83 }
84
85 #[inline(always)]
87 pub fn has_combinators(&self) -> bool {
88 self.last_compound_start.is_some()
89 }
90
91 #[inline(always)]
93 pub fn build(&mut self, parse_relative: ParseRelative) -> SelectorData<Impl> {
94 let sf = specificity_and_flags(
96 self.components.iter(),
97 false,
98 );
99 self.build_with_specificity_and_flags(sf, parse_relative)
100 }
101
102 #[inline(always)]
105 pub(crate) fn build_with_specificity_and_flags(
106 &mut self,
107 mut spec: SpecificityAndFlags,
108 parse_relative: ParseRelative,
109 ) -> SelectorData<Impl> {
110 let implicit_addition = match parse_relative {
111 ParseRelative::ForNesting if !spec.flags.intersects(SelectorFlags::HAS_PARENT) => {
112 Some((Component::ParentSelector, SelectorFlags::HAS_PARENT))
113 },
114 ParseRelative::ForScope
115 if !spec
116 .flags
117 .intersects(SelectorFlags::HAS_SCOPE | SelectorFlags::HAS_PARENT) =>
118 {
119 Some((Component::ImplicitScope, SelectorFlags::HAS_SCOPE))
120 },
121 _ => None,
122 };
123 let implicit_selector_and_combinator;
124 let implicit_selector = if let Some((component, flag)) = implicit_addition {
125 spec.flags.insert(flag);
126 implicit_selector_and_combinator =
127 [Component::Combinator(Combinator::Descendant), component];
128 &implicit_selector_and_combinator[..]
129 } else {
130 &[]
131 };
132
133 if self.last_compound_start.is_none() {
136 return Arc::from_header_and_iter(
137 spec,
138 ExactChain(self.components.drain(..), implicit_selector.iter().cloned()),
139 );
140 }
141
142 self.reverse_last_compound();
143 Arc::from_header_and_iter(
144 spec,
145 ExactChain(
146 self.components.drain(..).rev(),
147 implicit_selector.iter().cloned(),
148 ),
149 )
150 }
151}
152
153impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
154 #[inline(always)]
155 fn default() -> Self {
156 SelectorBuilder {
157 components: SmallVec::new(),
158 last_compound_start: None,
159 }
160 }
161}
162
163struct ExactChain<A, B>(A, B);
166
167impl<A, B, Item> ExactSizeIterator for ExactChain<A, B>
168where
169 A: ExactSizeIterator<Item = Item>,
170 B: ExactSizeIterator<Item = Item>,
171{
172 fn len(&self) -> usize {
173 self.0.len() + self.1.len()
174 }
175}
176
177impl<A, B, Item> Iterator for ExactChain<A, B>
178where
179 A: ExactSizeIterator<Item = Item>,
180 B: ExactSizeIterator<Item = Item>,
181{
182 type Item = Item;
183
184 #[inline(always)]
185 fn next(&mut self) -> Option<Self::Item> {
186 self.0.next().or_else(|| self.1.next())
187 }
188
189 fn size_hint(&self) -> (usize, Option<usize>) {
190 let len = self.len();
191 (len, Some(len))
192 }
193}
194
195#[derive(Clone, Copy, Default, Eq, PartialEq)]
197#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
198pub(crate) struct SelectorFlags(u8);
199
200bitflags! {
201 impl SelectorFlags: u8 {
202 const HAS_PSEUDO = 1 << 0;
203 const HAS_SLOTTED = 1 << 1;
204 const HAS_PART = 1 << 2;
205 const HAS_PARENT = 1 << 3;
206 const HAS_HOST = 1 << 4;
207 const HAS_SCOPE = 1 << 5;
208 }
209}
210
211impl core::fmt::Debug for SelectorFlags {
212 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
213 if self.is_empty() {
214 write!(f, "{:#x}", Self::empty().bits())
215 } else {
216 bitflags::parser::to_writer(self, f)
217 }
218 }
219}
220
221impl SelectorFlags {
222 pub(crate) fn forbidden_for_nesting() -> Self {
229 Self::HAS_PSEUDO | Self::HAS_SLOTTED | Self::HAS_PART
230 }
231}
232
233#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
234#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
235pub struct SpecificityAndFlags {
236 pub(crate) specificity: u32,
239 pub(crate) flags: SelectorFlags,
241}
242
243const MAX_10BIT: u32 = (1u32 << 10) - 1;
244
245#[derive(Add, AddAssign, Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
246pub(crate) struct Specificity {
247 id_selectors: u32,
248 class_like_selectors: u32,
249 element_selectors: u32,
250}
251
252impl Specificity {
253 #[inline]
255 pub fn single_class_like() -> Self {
256 Specificity {
257 id_selectors: 0,
258 class_like_selectors: 1,
259 element_selectors: 0,
260 }
261 }
262}
263
264impl From<u32> for Specificity {
265 #[inline]
266 fn from(value: u32) -> Specificity {
267 assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
268 Specificity {
269 id_selectors: value >> 20,
270 class_like_selectors: (value >> 10) & MAX_10BIT,
271 element_selectors: value & MAX_10BIT,
272 }
273 }
274}
275
276impl From<Specificity> for u32 {
277 #[inline]
278 fn from(specificity: Specificity) -> u32 {
279 cmp::min(specificity.id_selectors, MAX_10BIT) << 20
280 | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
281 | cmp::min(specificity.element_selectors, MAX_10BIT)
282 }
283}
284
285fn specificity_and_flags<Impl>(
286 iter: slice::Iter<Component<Impl>>,
287 for_nesting_parent: bool,
288) -> SpecificityAndFlags
289where
290 Impl: SelectorImpl,
291{
292 fn component_specificity<Impl>(
293 simple_selector: &Component<Impl>,
294 specificity: &mut Specificity,
295 flags: &mut SelectorFlags,
296 for_nesting_parent: bool,
297 ) where
298 Impl: SelectorImpl,
299 {
300 match *simple_selector {
301 Component::Combinator(..) => {},
302 Component::ParentSelector => flags.insert(SelectorFlags::HAS_PARENT),
303 Component::Part(..) => {
304 flags.insert(SelectorFlags::HAS_PART);
305 if !for_nesting_parent {
306 specificity.element_selectors += 1
307 }
308 },
309 Component::PseudoElement(ref pseudo) => {
310 use crate::parser::PseudoElement;
311 flags.insert(SelectorFlags::HAS_PSEUDO);
312 if !for_nesting_parent {
313 specificity.element_selectors += pseudo.specificity_count();
314 }
315 },
316 Component::LocalName(..) => specificity.element_selectors += 1,
317 Component::Slotted(ref selector) => {
318 flags.insert(SelectorFlags::HAS_SLOTTED);
319 if !for_nesting_parent {
320 specificity.element_selectors += 1;
321 *specificity += Specificity::from(selector.specificity());
328 }
329 flags.insert(selector.flags());
330 },
331 Component::Host(ref selector) => {
332 flags.insert(SelectorFlags::HAS_HOST);
333 specificity.class_like_selectors += 1;
334 if let Some(ref selector) = *selector {
335 *specificity += Specificity::from(selector.specificity());
337 flags.insert(selector.flags());
338 }
339 },
340 Component::ID(..) => {
341 specificity.id_selectors += 1;
342 },
343 Component::Class(..)
344 | Component::AttributeInNoNamespace { .. }
345 | Component::AttributeInNoNamespaceExists { .. }
346 | Component::AttributeOther(..)
347 | Component::Root
348 | Component::Empty
349 | Component::Nth(..)
350 | Component::NonTSPseudoClass(..) => {
351 specificity.class_like_selectors += 1;
352 },
353 Component::Scope | Component::ImplicitScope => {
354 flags.insert(SelectorFlags::HAS_SCOPE);
355 if matches!(*simple_selector, Component::Scope) {
356 specificity.class_like_selectors += 1;
357 }
358 },
359 Component::NthOf(ref nth_of_data) => {
360 specificity.class_like_selectors += 1;
367 let sf = selector_list_specificity_and_flags(
368 nth_of_data.selectors().iter(),
369 for_nesting_parent,
370 );
371 *specificity += Specificity::from(sf.specificity);
372 flags.insert(sf.flags);
373 },
374 Component::Where(ref list)
380 | Component::Negation(ref list)
381 | Component::Is(ref list) => {
382 let sf = selector_list_specificity_and_flags(
383 list.slice().iter(),
384 true,
385 );
386 if !matches!(*simple_selector, Component::Where(..)) {
387 *specificity += Specificity::from(sf.specificity);
388 }
389 flags.insert(sf.flags);
390 },
391 Component::Has(ref relative_selectors) => {
392 let sf = relative_selector_list_specificity_and_flags(
393 relative_selectors,
394 for_nesting_parent,
395 );
396 *specificity += Specificity::from(sf.specificity);
397 flags.insert(sf.flags);
398 },
399 Component::ExplicitUniversalType
400 | Component::ExplicitAnyNamespace
401 | Component::ExplicitNoNamespace
402 | Component::DefaultNamespace(..)
403 | Component::Namespace(..)
404 | Component::RelativeSelectorAnchor
405 | Component::Invalid(..) => {
406 },
408 }
409 }
410
411 let mut specificity = Default::default();
412 let mut flags = Default::default();
413 for simple_selector in iter {
414 component_specificity(
415 &simple_selector,
416 &mut specificity,
417 &mut flags,
418 for_nesting_parent,
419 );
420 }
421 SpecificityAndFlags {
422 specificity: specificity.into(),
423 flags,
424 }
425}
426
427pub(crate) fn selector_list_specificity_and_flags<'a, Impl: SelectorImpl>(
429 itr: impl Iterator<Item = &'a Selector<Impl>>,
430 for_nesting_parent: bool,
431) -> SpecificityAndFlags {
432 let mut specificity = 0;
433 let mut flags = SelectorFlags::empty();
434 for selector in itr {
435 let selector_flags = selector.flags();
436 let selector_specificity = if for_nesting_parent
437 && selector_flags.intersects(SelectorFlags::forbidden_for_nesting())
438 {
439 specificity_and_flags(selector.iter_raw_match_order(), for_nesting_parent).specificity
441 } else {
442 selector.specificity()
443 };
444 specificity = std::cmp::max(specificity, selector_specificity);
445 flags.insert(selector.flags());
446 }
447 SpecificityAndFlags { specificity, flags }
448}
449
450pub(crate) fn relative_selector_list_specificity_and_flags<Impl: SelectorImpl>(
451 list: &[RelativeSelector<Impl>],
452 for_nesting_parent: bool,
453) -> SpecificityAndFlags {
454 selector_list_specificity_and_flags(list.iter().map(|rel| &rel.selector), for_nesting_parent)
455}