1use crate::attr::CaseSensitivity;
6use crate::bloom::BloomFilter;
7use crate::nth_index_cache::{NthIndexCache, NthIndexCacheInner};
8use crate::parser::{Selector, SelectorImpl};
9use crate::relative_selector::cache::RelativeSelectorCache;
10use crate::relative_selector::filter::RelativeSelectorFilterMap;
11use crate::tree::{Element, OpaqueElement};
12
13#[derive(Clone, Copy, Debug, PartialEq)]
18pub enum MatchingMode {
19 Normal,
21
22 ForStatelessPseudoElement,
34}
35
36#[derive(Clone, Copy, Debug, Eq, PartialEq)]
38pub enum VisitedHandlingMode {
39 AllLinksUnvisited,
41 AllLinksVisitedAndUnvisited,
47 RelevantLinkVisited,
51}
52
53impl VisitedHandlingMode {
54 #[inline]
55 pub fn matches_visited(&self) -> bool {
56 matches!(
57 *self,
58 VisitedHandlingMode::RelevantLinkVisited
59 | VisitedHandlingMode::AllLinksVisitedAndUnvisited
60 )
61 }
62
63 #[inline]
64 pub fn matches_unvisited(&self) -> bool {
65 matches!(
66 *self,
67 VisitedHandlingMode::AllLinksUnvisited
68 | VisitedHandlingMode::AllLinksVisitedAndUnvisited
69 )
70 }
71}
72
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub enum IncludeStartingStyle {
77 No,
80 Yes,
84}
85
86#[derive(Clone, Copy, Debug, PartialEq)]
89pub enum NeedsSelectorFlags {
90 No,
91 Yes,
92}
93
94#[derive(Clone, Copy, PartialEq)]
96pub enum MatchingForInvalidation {
97 No,
98 Yes,
99 YesForComparison,
100}
101
102impl MatchingForInvalidation {
103 pub fn is_for_invalidation(&self) -> bool {
105 matches!(*self, Self::Yes | Self::YesForComparison)
106 }
107}
108
109#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
113pub enum QuirksMode {
114 Quirks,
116 LimitedQuirks,
118 NoQuirks,
120}
121
122impl QuirksMode {
123 #[inline]
124 pub fn classes_and_ids_case_sensitivity(self) -> CaseSensitivity {
125 match self {
126 QuirksMode::NoQuirks | QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
127 QuirksMode::Quirks => CaseSensitivity::AsciiCaseInsensitive,
128 }
129 }
130}
131
132#[derive(Default)]
134pub struct SelectorCaches {
135 pub nth_index: NthIndexCache,
137 pub relative_selector: RelativeSelectorCache,
139 pub relative_selector_filter_map: RelativeSelectorFilterMap,
141}
142
143pub struct MatchingContext<'a, Impl>
147where
148 Impl: SelectorImpl,
149{
150 matching_mode: MatchingMode,
152 pub bloom_filter: Option<&'a BloomFilter>,
154 pub scope_element: Option<OpaqueElement>,
166
167 pub current_host: Option<OpaqueElement>,
169
170 visited_handling: VisitedHandlingMode,
172
173 pub include_starting_style: IncludeStartingStyle,
175
176 pub has_starting_style: bool,
178
179 pub featureless: bool,
181
182 nesting_level: usize,
184
185 in_negation: bool,
187
188 pub pseudo_element_matching_fn: Option<&'a dyn Fn(&Impl::PseudoElement) -> bool>,
191
192 pub extra_data: Impl::ExtraMatchingData<'a>,
194
195 current_relative_selector_anchor: Option<OpaqueElement>,
197
198 quirks_mode: QuirksMode,
199 needs_selector_flags: NeedsSelectorFlags,
200
201 matching_for_invalidation: MatchingForInvalidation,
203
204 pub selector_caches: &'a mut SelectorCaches,
206
207 classes_and_ids_case_sensitivity: CaseSensitivity,
208 _impl: ::std::marker::PhantomData<Impl>,
209}
210
211impl<'a, Impl> MatchingContext<'a, Impl>
212where
213 Impl: SelectorImpl,
214{
215 pub fn new(
217 matching_mode: MatchingMode,
218 bloom_filter: Option<&'a BloomFilter>,
219 selector_caches: &'a mut SelectorCaches,
220 quirks_mode: QuirksMode,
221 needs_selector_flags: NeedsSelectorFlags,
222 matching_for_invalidation: MatchingForInvalidation,
223 ) -> Self {
224 Self::new_for_visited(
225 matching_mode,
226 bloom_filter,
227 selector_caches,
228 VisitedHandlingMode::AllLinksUnvisited,
229 IncludeStartingStyle::No,
230 quirks_mode,
231 needs_selector_flags,
232 matching_for_invalidation,
233 )
234 }
235
236 pub fn new_for_visited(
238 matching_mode: MatchingMode,
239 bloom_filter: Option<&'a BloomFilter>,
240 selector_caches: &'a mut SelectorCaches,
241 visited_handling: VisitedHandlingMode,
242 include_starting_style: IncludeStartingStyle,
243 quirks_mode: QuirksMode,
244 needs_selector_flags: NeedsSelectorFlags,
245 matching_for_invalidation: MatchingForInvalidation,
246 ) -> Self {
247 Self {
248 matching_mode,
249 bloom_filter,
250 visited_handling,
251 include_starting_style,
252 has_starting_style: false,
253 quirks_mode,
254 classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
255 needs_selector_flags,
256 matching_for_invalidation,
257 scope_element: None,
258 current_host: None,
259 featureless: false,
260 nesting_level: 0,
261 in_negation: false,
262 pseudo_element_matching_fn: None,
263 extra_data: Default::default(),
264 current_relative_selector_anchor: None,
265 selector_caches,
266 _impl: ::std::marker::PhantomData,
267 }
268 }
269
270 #[inline]
272 pub fn nth_index_cache(
273 &mut self,
274 is_of_type: bool,
275 is_from_end: bool,
276 selectors: &[Selector<Impl>],
277 ) -> &mut NthIndexCacheInner {
278 self.selector_caches
279 .nth_index
280 .get(is_of_type, is_from_end, selectors)
281 }
282
283 #[inline]
285 pub fn is_nested(&self) -> bool {
286 self.nesting_level != 0
287 }
288
289 #[inline]
291 pub fn in_negation(&self) -> bool {
292 self.in_negation
293 }
294
295 #[inline]
297 pub fn quirks_mode(&self) -> QuirksMode {
298 self.quirks_mode
299 }
300
301 #[inline]
303 pub fn matching_mode(&self) -> MatchingMode {
304 self.matching_mode
305 }
306
307 #[inline]
309 pub fn needs_selector_flags(&self) -> bool {
310 self.needs_selector_flags == NeedsSelectorFlags::Yes
311 }
312
313 #[inline]
315 pub fn matching_for_invalidation(&self) -> bool {
316 self.matching_for_invalidation.is_for_invalidation()
317 }
318
319 #[inline]
321 pub fn matching_for_invalidation_comparison(&self) -> Option<bool> {
322 match self.matching_for_invalidation {
323 MatchingForInvalidation::No => None,
324 MatchingForInvalidation::Yes => Some(false),
325 MatchingForInvalidation::YesForComparison => Some(true),
326 }
327 }
328
329 #[inline]
331 pub fn for_invalidation_comparison<F, R>(&mut self, f: F) -> R
332 where
333 F: FnOnce(&mut Self) -> R,
334 {
335 debug_assert!(
336 self.matching_for_invalidation(),
337 "Not matching for invalidation?"
338 );
339 let prev = self.matching_for_invalidation;
340 self.matching_for_invalidation = MatchingForInvalidation::YesForComparison;
341 let result = f(self);
342 self.matching_for_invalidation = prev;
343 result
344 }
345
346 #[inline]
348 pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
349 self.classes_and_ids_case_sensitivity
350 }
351
352 #[inline]
354 pub fn nest<F, R>(&mut self, f: F) -> R
355 where
356 F: FnOnce(&mut Self) -> R,
357 {
358 self.nesting_level += 1;
359 let result = f(self);
360 self.nesting_level -= 1;
361 result
362 }
363
364 #[inline]
367 pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
368 where
369 F: FnOnce(&mut Self) -> R,
370 {
371 let old_in_negation = self.in_negation;
372 self.in_negation = !self.in_negation;
373 let result = self.nest(f);
374 self.in_negation = old_in_negation;
375 result
376 }
377
378 #[inline]
379 pub fn visited_handling(&self) -> VisitedHandlingMode {
380 self.visited_handling
381 }
382
383 #[inline]
385 pub fn with_featureless<F, R>(&mut self, featureless: bool, f: F) -> R
386 where
387 F: FnOnce(&mut Self) -> R,
388 {
389 let orig = self.featureless;
390 self.featureless = featureless;
391 let result = f(self);
392 self.featureless = orig;
393 result
394 }
395
396 #[inline]
400 pub fn featureless(&self) -> bool {
401 self.featureless
402 }
403
404 #[inline]
406 pub fn with_visited_handling_mode<F, R>(
407 &mut self,
408 handling_mode: VisitedHandlingMode,
409 f: F,
410 ) -> R
411 where
412 F: FnOnce(&mut Self) -> R,
413 {
414 let original_handling_mode = self.visited_handling;
415 self.visited_handling = handling_mode;
416 let result = f(self);
417 self.visited_handling = original_handling_mode;
418 result
419 }
420
421 #[inline]
424 pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
425 where
426 E: Element,
427 F: FnOnce(&mut Self) -> R,
428 {
429 let original_host = self.current_host.take();
430 self.current_host = host.map(|h| h.opaque());
431 let result = f(self);
432 self.current_host = original_host;
433 result
434 }
435
436 #[inline]
439 pub fn shadow_host(&self) -> Option<OpaqueElement> {
440 self.current_host
441 }
442
443 #[inline]
446 pub fn nest_for_relative_selector<F, R>(&mut self, anchor: OpaqueElement, f: F) -> R
447 where
448 F: FnOnce(&mut Self) -> R,
449 {
450 debug_assert!(
451 self.current_relative_selector_anchor.is_none(),
452 "Nesting should've been rejected at parse time"
453 );
454 self.current_relative_selector_anchor = Some(anchor);
455 let result = self.nest(f);
456 self.current_relative_selector_anchor = None;
457 result
458 }
459
460 #[inline]
462 pub fn nest_for_scope<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
463 where
464 F: FnOnce(&mut Self) -> R,
465 {
466 let original_scope_element = self.scope_element;
467 self.scope_element = scope;
468 let result = f(self);
469 self.scope_element = original_scope_element;
470 result
471 }
472
473 #[inline]
476 pub fn nest_for_scope_condition<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
477 where
478 F: FnOnce(&mut Self) -> R,
479 {
480 let original_matching_mode = self.matching_mode;
481 self.matching_mode = MatchingMode::Normal;
484 let result = self.nest_for_scope(scope, f);
485 self.matching_mode = original_matching_mode;
486 result
487 }
488
489 #[inline]
491 pub fn relative_selector_anchor(&self) -> Option<OpaqueElement> {
492 self.current_relative_selector_anchor
493 }
494}