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!(self.matching_for_invalidation(), "Not matching for invalidation?");
336 let prev = self.matching_for_invalidation;
337 self.matching_for_invalidation = MatchingForInvalidation::YesForComparison;
338 let result = f(self);
339 self.matching_for_invalidation = prev;
340 result
341 }
342
343 #[inline]
345 pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
346 self.classes_and_ids_case_sensitivity
347 }
348
349 #[inline]
351 pub fn nest<F, R>(&mut self, f: F) -> R
352 where
353 F: FnOnce(&mut Self) -> R,
354 {
355 self.nesting_level += 1;
356 let result = f(self);
357 self.nesting_level -= 1;
358 result
359 }
360
361 #[inline]
364 pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
365 where
366 F: FnOnce(&mut Self) -> R,
367 {
368 let old_in_negation = self.in_negation;
369 self.in_negation = !self.in_negation;
370 let result = self.nest(f);
371 self.in_negation = old_in_negation;
372 result
373 }
374
375 #[inline]
376 pub fn visited_handling(&self) -> VisitedHandlingMode {
377 self.visited_handling
378 }
379
380 #[inline]
382 pub fn with_featureless<F, R>(
383 &mut self,
384 featureless: bool,
385 f: F,
386 ) -> R
387 where
388 F: FnOnce(&mut Self) -> R,
389 {
390 let orig = self.featureless;
391 self.featureless = featureless;
392 let result = f(self);
393 self.featureless = orig;
394 result
395 }
396
397 #[inline]
401 pub fn featureless(&self) -> bool {
402 self.featureless
403 }
404
405 #[inline]
407 pub fn with_visited_handling_mode<F, R>(
408 &mut self,
409 handling_mode: VisitedHandlingMode,
410 f: F,
411 ) -> R
412 where
413 F: FnOnce(&mut Self) -> R,
414 {
415 let original_handling_mode = self.visited_handling;
416 self.visited_handling = handling_mode;
417 let result = f(self);
418 self.visited_handling = original_handling_mode;
419 result
420 }
421
422 #[inline]
425 pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
426 where
427 E: Element,
428 F: FnOnce(&mut Self) -> R,
429 {
430 let original_host = self.current_host.take();
431 self.current_host = host.map(|h| h.opaque());
432 let result = f(self);
433 self.current_host = original_host;
434 result
435 }
436
437 #[inline]
440 pub fn shadow_host(&self) -> Option<OpaqueElement> {
441 self.current_host
442 }
443
444 #[inline]
447 pub fn nest_for_relative_selector<F, R>(&mut self, anchor: OpaqueElement, f: F) -> R
448 where
449 F: FnOnce(&mut Self) -> R,
450 {
451 debug_assert!(
452 self.current_relative_selector_anchor.is_none(),
453 "Nesting should've been rejected at parse time"
454 );
455 self.current_relative_selector_anchor = Some(anchor);
456 let result = self.nest(f);
457 self.current_relative_selector_anchor = None;
458 result
459 }
460
461 #[inline]
463 pub fn nest_for_scope<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
464 where
465 F: FnOnce(&mut Self) -> R,
466 {
467 let original_scope_element = self.scope_element;
468 self.scope_element = scope;
469 let result = f(self);
470 self.scope_element = original_scope_element;
471 result
472 }
473
474 #[inline]
477 pub fn nest_for_scope_condition<F, R>(&mut self, scope: Option<OpaqueElement>, f: F) -> R
478 where
479 F: FnOnce(&mut Self) -> R,
480 {
481 let original_matching_mode = self.matching_mode;
482 self.matching_mode = MatchingMode::Normal;
485 let result = self.nest_for_scope(scope, f);
486 self.matching_mode = original_matching_mode;
487 result
488 }
489
490 #[inline]
492 pub fn relative_selector_anchor(&self) -> Option<OpaqueElement> {
493 self.current_relative_selector_anchor
494 }
495}