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 matching_for_revalidation: bool,
206
207 pub selector_caches: &'a mut SelectorCaches,
209
210 classes_and_ids_case_sensitivity: CaseSensitivity,
211 _impl: ::std::marker::PhantomData<Impl>,
212}
213
214impl<'a, Impl> MatchingContext<'a, Impl>
215where
216 Impl: SelectorImpl,
217{
218 pub fn new(
220 matching_mode: MatchingMode,
221 bloom_filter: Option<&'a BloomFilter>,
222 selector_caches: &'a mut SelectorCaches,
223 quirks_mode: QuirksMode,
224 needs_selector_flags: NeedsSelectorFlags,
225 matching_for_invalidation: MatchingForInvalidation,
226 ) -> Self {
227 Self::new_internal(
228 matching_mode,
229 bloom_filter,
230 selector_caches,
231 VisitedHandlingMode::AllLinksUnvisited,
232 IncludeStartingStyle::No,
233 quirks_mode,
234 needs_selector_flags,
235 matching_for_invalidation,
236 false,
237 )
238 }
239
240 pub fn new_for_revalidation(
242 bloom_filter: Option<&'a BloomFilter>,
243 selector_caches: &'a mut SelectorCaches,
244 quirks_mode: QuirksMode,
245 needs_selector_flags: NeedsSelectorFlags,
246 ) -> Self {
247 Self::new_internal(
248 MatchingMode::Normal,
251 bloom_filter,
252 selector_caches,
253 VisitedHandlingMode::AllLinksUnvisited,
254 IncludeStartingStyle::No,
255 quirks_mode,
256 needs_selector_flags,
257 MatchingForInvalidation::No,
258 true,
259 )
260 }
261
262 pub fn new_for_visited(
264 matching_mode: MatchingMode,
265 bloom_filter: Option<&'a BloomFilter>,
266 selector_caches: &'a mut SelectorCaches,
267 visited_handling: VisitedHandlingMode,
268 include_starting_style: IncludeStartingStyle,
269 quirks_mode: QuirksMode,
270 needs_selector_flags: NeedsSelectorFlags,
271 matching_for_invalidation: MatchingForInvalidation,
272 ) -> Self {
273 Self::new_internal(
274 matching_mode,
275 bloom_filter,
276 selector_caches,
277 visited_handling,
278 include_starting_style,
279 quirks_mode,
280 needs_selector_flags,
281 matching_for_invalidation,
282 false,
283 )
284 }
285
286 fn new_internal(
287 matching_mode: MatchingMode,
288 bloom_filter: Option<&'a BloomFilter>,
289 selector_caches: &'a mut SelectorCaches,
290 visited_handling: VisitedHandlingMode,
291 include_starting_style: IncludeStartingStyle,
292 quirks_mode: QuirksMode,
293 needs_selector_flags: NeedsSelectorFlags,
294 matching_for_invalidation: MatchingForInvalidation,
295 matching_for_revalidation: bool,
296 ) -> Self {
297 Self {
298 matching_mode,
299 bloom_filter,
300 visited_handling,
301 include_starting_style,
302 has_starting_style: false,
303 quirks_mode,
304 classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
305 needs_selector_flags,
306 matching_for_invalidation,
307 matching_for_revalidation,
308 scope_element: None,
309 current_host: None,
310 featureless: false,
311 nesting_level: 0,
312 in_negation: false,
313 pseudo_element_matching_fn: None,
314 extra_data: Default::default(),
315 current_relative_selector_anchor: None,
316 selector_caches,
317 _impl: ::std::marker::PhantomData,
318 }
319 }
320
321 #[inline]
323 pub fn nth_index_cache(
324 &mut self,
325 is_of_type: bool,
326 is_from_end: bool,
327 selectors: &[Selector<Impl>],
328 ) -> &mut NthIndexCacheInner {
329 self.selector_caches
330 .nth_index
331 .get(is_of_type, is_from_end, selectors)
332 }
333
334 #[inline]
336 pub fn is_nested(&self) -> bool {
337 self.nesting_level != 0
338 }
339
340 #[inline]
342 pub fn in_negation(&self) -> bool {
343 self.in_negation
344 }
345
346 #[inline]
348 pub fn quirks_mode(&self) -> QuirksMode {
349 self.quirks_mode
350 }
351
352 #[inline]
354 pub fn matching_mode(&self) -> MatchingMode {
355 self.matching_mode
356 }
357
358 #[inline]
360 pub fn needs_selector_flags(&self) -> bool {
361 self.needs_selector_flags == NeedsSelectorFlags::Yes
362 }
363
364 #[inline]
366 pub fn matching_for_invalidation(&self) -> bool {
367 self.matching_for_invalidation.is_for_invalidation()
368 }
369
370 #[inline]
372 pub fn matching_for_revalidation(&self) -> bool {
373 self.matching_for_revalidation
374 }
375
376 #[inline]
378 pub fn matching_for_invalidation_comparison(&self) -> Option<bool> {
379 match self.matching_for_invalidation {
380 MatchingForInvalidation::No => None,
381 MatchingForInvalidation::Yes => Some(false),
382 MatchingForInvalidation::YesForComparison => Some(true),
383 }
384 }
385
386 #[inline]
388 pub fn for_invalidation_comparison<F, R>(&mut self, f: F) -> R
389 where
390 F: FnOnce(&mut Self) -> R,
391 {
392 debug_assert!(
393 self.matching_for_invalidation(),
394 "Not matching for invalidation?"
395 );
396 let prev = self.matching_for_invalidation;
397 self.matching_for_invalidation = MatchingForInvalidation::YesForComparison;
398 let result = f(self);
399 self.matching_for_invalidation = prev;
400 result
401 }
402
403 #[inline]
405 pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
406 self.classes_and_ids_case_sensitivity
407 }
408
409 #[inline]
411 pub fn nest<F, R>(&mut self, f: F) -> R
412 where
413 F: FnOnce(&mut Self) -> R,
414 {
415 self.nesting_level += 1;
416 let result = f(self);
417 self.nesting_level -= 1;
418 result
419 }
420
421 #[inline]
424 pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
425 where
426 F: FnOnce(&mut Self) -> R,
427 {
428 let old_in_negation = self.in_negation;
429 self.in_negation = !self.in_negation;
430 let result = self.nest(f);
431 self.in_negation = old_in_negation;
432 result
433 }
434
435 #[inline]
436 pub fn visited_handling(&self) -> VisitedHandlingMode {
437 self.visited_handling
438 }
439
440 #[inline]
442 pub fn with_featureless<F, R>(&mut self, featureless: bool, f: F) -> R
443 where
444 F: FnOnce(&mut Self) -> R,
445 {
446 let orig = self.featureless;
447 self.featureless = featureless;
448 let result = f(self);
449 self.featureless = orig;
450 result
451 }
452
453 #[inline]
457 pub fn featureless(&self) -> bool {
458 self.featureless
459 }
460
461 #[inline]
463 pub fn with_visited_handling_mode<F, R>(
464 &mut self,
465 handling_mode: VisitedHandlingMode,
466 f: F,
467 ) -> R
468 where
469 F: FnOnce(&mut Self) -> R,
470 {
471 let original_handling_mode = self.visited_handling;
472 self.visited_handling = handling_mode;
473 let result = f(self);
474 self.visited_handling = original_handling_mode;
475 result
476 }
477
478 #[inline]
481 pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
482 where
483 E: Element,
484 F: FnOnce(&mut Self) -> R,
485 {
486 let original_host = self.current_host.take();
487 self.current_host = host.map(|h| h.opaque());
488 let result = f(self);
489 self.current_host = original_host;
490 result
491 }
492
493 #[inline]
496 pub fn shadow_host(&self) -> Option<OpaqueElement> {
497 self.current_host
498 }
499
500 #[inline]
503 pub fn nest_for_relative_selector<F, R>(&mut self, anchor: OpaqueElement, f: F) -> R
504 where
505 F: FnOnce(&mut Self) -> R,
506 {
507 debug_assert!(
508 self.current_relative_selector_anchor.is_none(),
509 "Nesting should've been rejected at parse time"
510 );
511 self.current_relative_selector_anchor = Some(anchor);
512 let result = self.nest(f);
513 self.current_relative_selector_anchor = None;
514 result
515 }
516
517 #[inline]
519 pub fn nest_for_scope<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
520 where
521 F: FnOnce(&mut Self) -> R,
522 {
523 let original_scope_element = self.scope_element;
524 self.scope_element = scope;
525 let result = f(self);
526 self.scope_element = original_scope_element;
527 result
528 }
529
530 #[inline]
533 pub fn nest_for_scope_condition<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
534 where
535 F: FnOnce(&mut Self) -> R,
536 {
537 let original_matching_mode = self.matching_mode;
538 self.matching_mode = MatchingMode::Normal;
541 let result = self.nest_for_scope(scope, f);
542 self.matching_mode = original_matching_mode;
543 result
544 }
545
546 #[inline]
548 pub fn relative_selector_anchor(&self) -> Option<OpaqueElement> {
549 self.current_relative_selector_anchor
550 }
551}