document_state.rs (5374B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! An invalidation processor for style changes due to document state changes. 6 7 use crate::dom::TElement; 8 use crate::invalidation::element::invalidation_map::Dependency; 9 use crate::invalidation::element::invalidator::{ 10 DescendantInvalidationLists, InvalidationVector, SiblingTraversalMap, 11 }; 12 use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor}; 13 use crate::invalidation::element::state_and_attributes; 14 use crate::stylist::CascadeData; 15 use dom::DocumentState; 16 use selectors::matching::{ 17 IncludeStartingStyle, MatchingContext, MatchingForInvalidation, MatchingMode, 18 NeedsSelectorFlags, QuirksMode, SelectorCaches, VisitedHandlingMode, 19 }; 20 use selectors::OpaqueElement; 21 22 /// A struct holding the members necessary to invalidate document state 23 /// selectors. 24 #[derive(Debug)] 25 pub struct InvalidationMatchingData { 26 /// The document state that has changed, which makes it always match. 27 pub document_state: DocumentState, 28 } 29 30 impl Default for InvalidationMatchingData { 31 #[inline(always)] 32 fn default() -> Self { 33 Self { 34 document_state: DocumentState::empty(), 35 } 36 } 37 } 38 39 /// An invalidation processor for style changes due to state and attribute 40 /// changes. 41 pub struct DocumentStateInvalidationProcessor<'a, 'b, E: TElement, I> { 42 rules: I, 43 matching_context: MatchingContext<'a, E::Impl>, 44 traversal_map: SiblingTraversalMap<E>, 45 document_states_changed: DocumentState, 46 _marker: std::marker::PhantomData<&'b ()>, 47 } 48 49 impl<'a, 'b, E: TElement, I> DocumentStateInvalidationProcessor<'a, 'b, E, I> { 50 /// Creates a new DocumentStateInvalidationProcessor. 51 #[inline] 52 pub fn new( 53 rules: I, 54 document_states_changed: DocumentState, 55 selector_caches: &'a mut SelectorCaches, 56 quirks_mode: QuirksMode, 57 ) -> Self { 58 let mut matching_context = MatchingContext::<'a, E::Impl>::new_for_visited( 59 MatchingMode::Normal, 60 None, 61 selector_caches, 62 VisitedHandlingMode::AllLinksVisitedAndUnvisited, 63 IncludeStartingStyle::No, 64 quirks_mode, 65 NeedsSelectorFlags::No, 66 MatchingForInvalidation::No, 67 ); 68 69 matching_context.extra_data.invalidation_data.document_state = document_states_changed; 70 71 Self { 72 rules, 73 document_states_changed, 74 matching_context, 75 traversal_map: SiblingTraversalMap::default(), 76 _marker: std::marker::PhantomData, 77 } 78 } 79 } 80 81 impl<'a, 'b, E, I> InvalidationProcessor<'b, 'a, E> 82 for DocumentStateInvalidationProcessor<'a, 'b, E, I> 83 where 84 E: TElement, 85 I: Iterator<Item = &'b CascadeData>, 86 { 87 fn check_outer_dependency(&mut self, _: &Dependency, _: E, _: Option<OpaqueElement>) -> bool { 88 debug_assert!( 89 false, 90 "how, we should only have parent-less dependencies here!" 91 ); 92 true 93 } 94 95 fn collect_invalidations( 96 &mut self, 97 _element: E, 98 self_invalidations: &mut InvalidationVector<'b>, 99 _descendant_invalidations: &mut DescendantInvalidationLists<'b>, 100 _sibling_invalidations: &mut InvalidationVector<'b>, 101 ) -> bool { 102 for cascade_data in &mut self.rules { 103 let map = cascade_data.invalidation_map(); 104 for dependency in &map.document_state_selectors { 105 if !dependency.state.intersects(self.document_states_changed) { 106 continue; 107 } 108 109 // We pass `None` as a scope, as document state selectors aren't 110 // affected by the current scope. 111 // 112 // FIXME(emilio): We should really pass the relevant host for 113 // self.rules, so that we invalidate correctly if the selector 114 // happens to have something like :host(:-moz-window-inactive) 115 // for example. 116 self_invalidations.push(Invalidation::new( 117 &dependency.dependency, 118 /* host = */ None, 119 /* scope = */ None, 120 )); 121 } 122 } 123 124 false 125 } 126 127 fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> { 128 &mut self.matching_context 129 } 130 131 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> { 132 &self.traversal_map 133 } 134 135 fn recursion_limit_exceeded(&mut self, _: E) { 136 unreachable!("We don't run document state invalidation with stack limits") 137 } 138 139 fn should_process_descendants(&mut self, element: E) -> bool { 140 match element.borrow_data() { 141 Some(d) => state_and_attributes::should_process_descendants(&d), 142 None => false, 143 } 144 } 145 146 fn invalidated_descendants(&mut self, element: E, child: E) { 147 state_and_attributes::invalidated_descendants(element, child) 148 } 149 150 fn invalidated_self(&mut self, element: E) { 151 state_and_attributes::invalidated_self(element); 152 } 153 154 fn invalidated_sibling(&mut self, sibling: E, of: E) { 155 state_and_attributes::invalidated_sibling(sibling, of); 156 } 157 }