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 #[allow(clippy::type_complexity)]
172 pub pseudo_element_matching_fn: Option<&'a dyn Fn(&Impl::PseudoElement) -> bool>,
173
174 pub extra_data: Impl::ExtraMatchingData<'a>,
176
177 current_relative_selector_anchor: Option<OpaqueElement>,
179
180 quirks_mode: QuirksMode,
181 needs_selector_flags: NeedsSelectorFlags,
182
183 matching_for_invalidation: MatchingForInvalidation,
185
186 matching_for_revalidation: bool,
188
189 pub selector_caches: &'a mut SelectorCaches,
191
192 classes_and_ids_case_sensitivity: CaseSensitivity,
193 _impl: ::std::marker::PhantomData<Impl>,
194}
195
196impl<'a, Impl> MatchingContext<'a, Impl>
197where
198 Impl: SelectorImpl,
199{
200 pub fn new(
202 matching_mode: MatchingMode,
203 bloom_filter: Option<&'a BloomFilter>,
204 selector_caches: &'a mut SelectorCaches,
205 quirks_mode: QuirksMode,
206 needs_selector_flags: NeedsSelectorFlags,
207 matching_for_invalidation: MatchingForInvalidation,
208 ) -> Self {
209 Self::new_internal(
210 matching_mode,
211 bloom_filter,
212 selector_caches,
213 VisitedHandlingMode::AllLinksUnvisited,
214 quirks_mode,
215 needs_selector_flags,
216 matching_for_invalidation,
217 false,
218 )
219 }
220
221 pub fn new_for_revalidation(
223 bloom_filter: Option<&'a BloomFilter>,
224 selector_caches: &'a mut SelectorCaches,
225 quirks_mode: QuirksMode,
226 needs_selector_flags: NeedsSelectorFlags,
227 ) -> Self {
228 Self::new_internal(
229 MatchingMode::Normal,
232 bloom_filter,
233 selector_caches,
234 VisitedHandlingMode::AllLinksUnvisited,
235 quirks_mode,
236 needs_selector_flags,
237 MatchingForInvalidation::No,
238 true,
239 )
240 }
241
242 pub fn new_for_visited(
244 matching_mode: MatchingMode,
245 bloom_filter: Option<&'a BloomFilter>,
246 selector_caches: &'a mut SelectorCaches,
247 visited_handling: VisitedHandlingMode,
248 quirks_mode: QuirksMode,
249 needs_selector_flags: NeedsSelectorFlags,
250 matching_for_invalidation: MatchingForInvalidation,
251 ) -> Self {
252 Self::new_internal(
253 matching_mode,
254 bloom_filter,
255 selector_caches,
256 visited_handling,
257 quirks_mode,
258 needs_selector_flags,
259 matching_for_invalidation,
260 false,
261 )
262 }
263
264 #[allow(clippy::too_many_arguments)]
265 fn new_internal(
266 matching_mode: MatchingMode,
267 bloom_filter: Option<&'a BloomFilter>,
268 selector_caches: &'a mut SelectorCaches,
269 visited_handling: VisitedHandlingMode,
270 quirks_mode: QuirksMode,
271 needs_selector_flags: NeedsSelectorFlags,
272 matching_for_invalidation: MatchingForInvalidation,
273 matching_for_revalidation: bool,
274 ) -> Self {
275 Self {
276 matching_mode,
277 bloom_filter,
278 visited_handling,
279 quirks_mode,
280 classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
281 needs_selector_flags,
282 matching_for_invalidation,
283 matching_for_revalidation,
284 scope_element: None,
285 current_host: None,
286 featureless: false,
287 nesting_level: 0,
288 in_negation: false,
289 pseudo_element_matching_fn: None,
290 extra_data: Default::default(),
291 current_relative_selector_anchor: None,
292 selector_caches,
293 _impl: ::std::marker::PhantomData,
294 }
295 }
296
297 #[inline]
299 pub fn nth_index_cache(
300 &mut self,
301 is_of_type: bool,
302 is_from_end: bool,
303 selectors: &[Selector<Impl>],
304 ) -> &mut NthIndexCacheInner {
305 self.selector_caches
306 .nth_index
307 .get(is_of_type, is_from_end, selectors)
308 }
309
310 #[inline]
312 pub fn is_nested(&self) -> bool {
313 self.nesting_level != 0
314 }
315
316 #[inline]
318 pub fn in_negation(&self) -> bool {
319 self.in_negation
320 }
321
322 #[inline]
324 pub fn quirks_mode(&self) -> QuirksMode {
325 self.quirks_mode
326 }
327
328 #[inline]
330 pub fn matching_mode(&self) -> MatchingMode {
331 self.matching_mode
332 }
333
334 #[inline]
336 pub fn needs_selector_flags(&self) -> bool {
337 self.needs_selector_flags == NeedsSelectorFlags::Yes
338 }
339
340 #[inline]
342 pub fn matching_for_invalidation(&self) -> bool {
343 self.matching_for_invalidation.is_for_invalidation()
344 }
345
346 #[inline]
348 pub fn matching_for_revalidation(&self) -> bool {
349 self.matching_for_revalidation
350 }
351
352 #[inline]
354 pub fn matching_for_invalidation_comparison(&self) -> Option<bool> {
355 match self.matching_for_invalidation {
356 MatchingForInvalidation::No => None,
357 MatchingForInvalidation::Yes => Some(false),
358 MatchingForInvalidation::YesForComparison => Some(true),
359 }
360 }
361
362 #[inline]
364 pub fn for_invalidation_comparison<F, R>(&mut self, f: F) -> R
365 where
366 F: FnOnce(&mut Self) -> R,
367 {
368 debug_assert!(
369 self.matching_for_invalidation(),
370 "Not matching for invalidation?"
371 );
372 let prev = self.matching_for_invalidation;
373 self.matching_for_invalidation = MatchingForInvalidation::YesForComparison;
374 let result = f(self);
375 self.matching_for_invalidation = prev;
376 result
377 }
378
379 #[inline]
381 pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
382 self.classes_and_ids_case_sensitivity
383 }
384
385 #[inline]
387 pub fn nest<F, R>(&mut self, f: F) -> R
388 where
389 F: FnOnce(&mut Self) -> R,
390 {
391 self.nesting_level += 1;
392 let result = f(self);
393 self.nesting_level -= 1;
394 result
395 }
396
397 #[inline]
400 pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
401 where
402 F: FnOnce(&mut Self) -> R,
403 {
404 let old_in_negation = self.in_negation;
405 self.in_negation = !self.in_negation;
406 let result = self.nest(f);
407 self.in_negation = old_in_negation;
408 result
409 }
410
411 #[inline]
412 pub fn visited_handling(&self) -> VisitedHandlingMode {
413 self.visited_handling
414 }
415
416 #[inline]
418 pub fn with_featureless<F, R>(&mut self, featureless: bool, f: F) -> R
419 where
420 F: FnOnce(&mut Self) -> R,
421 {
422 let orig = self.featureless;
423 self.featureless = featureless;
424 let result = f(self);
425 self.featureless = orig;
426 result
427 }
428
429 #[inline]
433 pub fn featureless(&self) -> bool {
434 self.featureless
435 }
436
437 #[inline]
439 pub fn with_visited_handling_mode<F, R>(
440 &mut self,
441 handling_mode: VisitedHandlingMode,
442 f: F,
443 ) -> R
444 where
445 F: FnOnce(&mut Self) -> R,
446 {
447 let original_handling_mode = self.visited_handling;
448 self.visited_handling = handling_mode;
449 let result = f(self);
450 self.visited_handling = original_handling_mode;
451 result
452 }
453
454 #[inline]
457 pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
458 where
459 E: Element,
460 F: FnOnce(&mut Self) -> R,
461 {
462 let original_host = self.current_host.take();
463 self.current_host = host.map(|h| h.opaque());
464 let result = f(self);
465 self.current_host = original_host;
466 result
467 }
468
469 #[inline]
472 pub fn shadow_host(&self) -> Option<OpaqueElement> {
473 self.current_host
474 }
475
476 #[inline]
479 pub fn nest_for_relative_selector<F, R>(&mut self, anchor: OpaqueElement, f: F) -> R
480 where
481 F: FnOnce(&mut Self) -> R,
482 {
483 debug_assert!(
484 self.current_relative_selector_anchor.is_none(),
485 "Nesting should've been rejected at parse time"
486 );
487 self.current_relative_selector_anchor = Some(anchor);
488 let result = self.nest(f);
489 self.current_relative_selector_anchor = None;
490 result
491 }
492
493 #[inline]
495 pub fn nest_for_scope<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
496 where
497 F: FnOnce(&mut Self) -> R,
498 {
499 let original_scope_element = self.scope_element;
500 self.scope_element = scope;
501 let result = f(self);
502 self.scope_element = original_scope_element;
503 result
504 }
505
506 #[inline]
509 pub fn nest_for_scope_condition<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
510 where
511 F: FnOnce(&mut Self) -> R,
512 {
513 let original_matching_mode = self.matching_mode;
514 self.matching_mode = MatchingMode::Normal;
517 let result = self.nest_for_scope(scope, f);
518 self.matching_mode = original_matching_mode;
519 result
520 }
521
522 #[inline]
524 pub fn relative_selector_anchor(&self) -> Option<OpaqueElement> {
525 self.current_relative_selector_anchor
526 }
527}