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, PartialEq)]
76pub enum NeedsSelectorFlags {
77 No,
78 Yes,
79}
80
81#[derive(Clone, Copy, PartialEq)]
83pub enum MatchingForInvalidation {
84 No,
85 Yes,
86 YesForComparison,
87}
88
89impl MatchingForInvalidation {
90 pub fn is_for_invalidation(&self) -> bool {
92 matches!(*self, Self::Yes | Self::YesForComparison)
93 }
94}
95
96#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
100pub enum QuirksMode {
101 Quirks,
103 LimitedQuirks,
105 NoQuirks,
107}
108
109impl QuirksMode {
110 #[inline]
111 pub fn classes_and_ids_case_sensitivity(self) -> CaseSensitivity {
112 match self {
113 QuirksMode::NoQuirks | QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
114 QuirksMode::Quirks => CaseSensitivity::AsciiCaseInsensitive,
115 }
116 }
117}
118
119#[derive(Default)]
121pub struct SelectorCaches {
122 pub nth_index: NthIndexCache,
124 pub relative_selector: RelativeSelectorCache,
126 pub relative_selector_filter_map: RelativeSelectorFilterMap,
128}
129
130pub struct MatchingContext<'a, Impl>
134where
135 Impl: SelectorImpl,
136{
137 matching_mode: MatchingMode,
139 pub bloom_filter: Option<&'a BloomFilter>,
141 pub scope_element: Option<OpaqueElement>,
153
154 pub current_host: Option<OpaqueElement>,
156
157 visited_handling: VisitedHandlingMode,
159
160 pub featureless: bool,
162
163 nesting_level: usize,
165
166 in_negation: bool,
168
169 pub pseudo_element_matching_fn: Option<&'a dyn Fn(&Impl::PseudoElement) -> bool>,
172
173 pub extra_data: Impl::ExtraMatchingData<'a>,
175
176 current_relative_selector_anchor: Option<OpaqueElement>,
178
179 quirks_mode: QuirksMode,
180 needs_selector_flags: NeedsSelectorFlags,
181
182 matching_for_invalidation: MatchingForInvalidation,
184
185 matching_for_revalidation: bool,
187
188 pub selector_caches: &'a mut SelectorCaches,
190
191 classes_and_ids_case_sensitivity: CaseSensitivity,
192 _impl: ::std::marker::PhantomData<Impl>,
193}
194
195impl<'a, Impl> MatchingContext<'a, Impl>
196where
197 Impl: SelectorImpl,
198{
199 pub fn new(
201 matching_mode: MatchingMode,
202 bloom_filter: Option<&'a BloomFilter>,
203 selector_caches: &'a mut SelectorCaches,
204 quirks_mode: QuirksMode,
205 needs_selector_flags: NeedsSelectorFlags,
206 matching_for_invalidation: MatchingForInvalidation,
207 ) -> Self {
208 Self::new_internal(
209 matching_mode,
210 bloom_filter,
211 selector_caches,
212 VisitedHandlingMode::AllLinksUnvisited,
213 quirks_mode,
214 needs_selector_flags,
215 matching_for_invalidation,
216 false,
217 )
218 }
219
220 pub fn new_for_revalidation(
222 bloom_filter: Option<&'a BloomFilter>,
223 selector_caches: &'a mut SelectorCaches,
224 quirks_mode: QuirksMode,
225 needs_selector_flags: NeedsSelectorFlags,
226 ) -> Self {
227 Self::new_internal(
228 MatchingMode::Normal,
231 bloom_filter,
232 selector_caches,
233 VisitedHandlingMode::AllLinksUnvisited,
234 quirks_mode,
235 needs_selector_flags,
236 MatchingForInvalidation::No,
237 true,
238 )
239 }
240
241 pub fn new_for_visited(
243 matching_mode: MatchingMode,
244 bloom_filter: Option<&'a BloomFilter>,
245 selector_caches: &'a mut SelectorCaches,
246 visited_handling: VisitedHandlingMode,
247 quirks_mode: QuirksMode,
248 needs_selector_flags: NeedsSelectorFlags,
249 matching_for_invalidation: MatchingForInvalidation,
250 ) -> Self {
251 Self::new_internal(
252 matching_mode,
253 bloom_filter,
254 selector_caches,
255 visited_handling,
256 quirks_mode,
257 needs_selector_flags,
258 matching_for_invalidation,
259 false,
260 )
261 }
262
263 fn new_internal(
264 matching_mode: MatchingMode,
265 bloom_filter: Option<&'a BloomFilter>,
266 selector_caches: &'a mut SelectorCaches,
267 visited_handling: VisitedHandlingMode,
268 quirks_mode: QuirksMode,
269 needs_selector_flags: NeedsSelectorFlags,
270 matching_for_invalidation: MatchingForInvalidation,
271 matching_for_revalidation: bool,
272 ) -> Self {
273 Self {
274 matching_mode,
275 bloom_filter,
276 visited_handling,
277 quirks_mode,
278 classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
279 needs_selector_flags,
280 matching_for_invalidation,
281 matching_for_revalidation,
282 scope_element: None,
283 current_host: None,
284 featureless: false,
285 nesting_level: 0,
286 in_negation: false,
287 pseudo_element_matching_fn: None,
288 extra_data: Default::default(),
289 current_relative_selector_anchor: None,
290 selector_caches,
291 _impl: ::std::marker::PhantomData,
292 }
293 }
294
295 #[inline]
297 pub fn nth_index_cache(
298 &mut self,
299 is_of_type: bool,
300 is_from_end: bool,
301 selectors: &[Selector<Impl>],
302 ) -> &mut NthIndexCacheInner {
303 self.selector_caches
304 .nth_index
305 .get(is_of_type, is_from_end, selectors)
306 }
307
308 #[inline]
310 pub fn is_nested(&self) -> bool {
311 self.nesting_level != 0
312 }
313
314 #[inline]
316 pub fn in_negation(&self) -> bool {
317 self.in_negation
318 }
319
320 #[inline]
322 pub fn quirks_mode(&self) -> QuirksMode {
323 self.quirks_mode
324 }
325
326 #[inline]
328 pub fn matching_mode(&self) -> MatchingMode {
329 self.matching_mode
330 }
331
332 #[inline]
334 pub fn needs_selector_flags(&self) -> bool {
335 self.needs_selector_flags == NeedsSelectorFlags::Yes
336 }
337
338 #[inline]
340 pub fn matching_for_invalidation(&self) -> bool {
341 self.matching_for_invalidation.is_for_invalidation()
342 }
343
344 #[inline]
346 pub fn matching_for_revalidation(&self) -> bool {
347 self.matching_for_revalidation
348 }
349
350 #[inline]
352 pub fn matching_for_invalidation_comparison(&self) -> Option<bool> {
353 match self.matching_for_invalidation {
354 MatchingForInvalidation::No => None,
355 MatchingForInvalidation::Yes => Some(false),
356 MatchingForInvalidation::YesForComparison => Some(true),
357 }
358 }
359
360 #[inline]
362 pub fn for_invalidation_comparison<F, R>(&mut self, f: F) -> R
363 where
364 F: FnOnce(&mut Self) -> R,
365 {
366 debug_assert!(
367 self.matching_for_invalidation(),
368 "Not matching for invalidation?"
369 );
370 let prev = self.matching_for_invalidation;
371 self.matching_for_invalidation = MatchingForInvalidation::YesForComparison;
372 let result = f(self);
373 self.matching_for_invalidation = prev;
374 result
375 }
376
377 #[inline]
379 pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
380 self.classes_and_ids_case_sensitivity
381 }
382
383 #[inline]
385 pub fn nest<F, R>(&mut self, f: F) -> R
386 where
387 F: FnOnce(&mut Self) -> R,
388 {
389 self.nesting_level += 1;
390 let result = f(self);
391 self.nesting_level -= 1;
392 result
393 }
394
395 #[inline]
398 pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
399 where
400 F: FnOnce(&mut Self) -> R,
401 {
402 let old_in_negation = self.in_negation;
403 self.in_negation = !self.in_negation;
404 let result = self.nest(f);
405 self.in_negation = old_in_negation;
406 result
407 }
408
409 #[inline]
410 pub fn visited_handling(&self) -> VisitedHandlingMode {
411 self.visited_handling
412 }
413
414 #[inline]
416 pub fn with_featureless<F, R>(&mut self, featureless: bool, f: F) -> R
417 where
418 F: FnOnce(&mut Self) -> R,
419 {
420 let orig = self.featureless;
421 self.featureless = featureless;
422 let result = f(self);
423 self.featureless = orig;
424 result
425 }
426
427 #[inline]
431 pub fn featureless(&self) -> bool {
432 self.featureless
433 }
434
435 #[inline]
437 pub fn with_visited_handling_mode<F, R>(
438 &mut self,
439 handling_mode: VisitedHandlingMode,
440 f: F,
441 ) -> R
442 where
443 F: FnOnce(&mut Self) -> R,
444 {
445 let original_handling_mode = self.visited_handling;
446 self.visited_handling = handling_mode;
447 let result = f(self);
448 self.visited_handling = original_handling_mode;
449 result
450 }
451
452 #[inline]
455 pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
456 where
457 E: Element,
458 F: FnOnce(&mut Self) -> R,
459 {
460 let original_host = self.current_host.take();
461 self.current_host = host.map(|h| h.opaque());
462 let result = f(self);
463 self.current_host = original_host;
464 result
465 }
466
467 #[inline]
470 pub fn shadow_host(&self) -> Option<OpaqueElement> {
471 self.current_host
472 }
473
474 #[inline]
477 pub fn nest_for_relative_selector<F, R>(&mut self, anchor: OpaqueElement, f: F) -> R
478 where
479 F: FnOnce(&mut Self) -> R,
480 {
481 debug_assert!(
482 self.current_relative_selector_anchor.is_none(),
483 "Nesting should've been rejected at parse time"
484 );
485 self.current_relative_selector_anchor = Some(anchor);
486 let result = self.nest(f);
487 self.current_relative_selector_anchor = None;
488 result
489 }
490
491 #[inline]
493 pub fn nest_for_scope<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
494 where
495 F: FnOnce(&mut Self) -> R,
496 {
497 let original_scope_element = self.scope_element;
498 self.scope_element = scope;
499 let result = f(self);
500 self.scope_element = original_scope_element;
501 result
502 }
503
504 #[inline]
507 pub fn nest_for_scope_condition<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
508 where
509 F: FnOnce(&mut Self) -> R,
510 {
511 let original_matching_mode = self.matching_mode;
512 self.matching_mode = MatchingMode::Normal;
515 let result = self.nest_for_scope(scope, f);
516 self.matching_mode = original_matching_mode;
517 result
518 }
519
520 #[inline]
522 pub fn relative_selector_anchor(&self) -> Option<OpaqueElement> {
523 self.current_relative_selector_anchor
524 }
525}