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::element_state::DocumentState; 9 use crate::invalidation::element::invalidation_map::Dependency; 10 use crate::invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector}; 11 use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor}; 12 use crate::invalidation::element::state_and_attributes; 13 use crate::stylist::CascadeData; 14 use selectors::matching::{MatchingContext, MatchingMode, QuirksMode, VisitedHandlingMode}; 15 16 /// A struct holding the members necessary to invalidate document state 17 /// selectors. 18 pub struct InvalidationMatchingData { 19 /// The document state that has changed, which makes it always match. 20 pub document_state: DocumentState, 21 } 22 23 impl Default for InvalidationMatchingData { 24 #[inline(always)] default() -> Self25 fn default() -> Self { 26 Self { 27 document_state: DocumentState::empty(), 28 } 29 } 30 } 31 32 /// An invalidation processor for style changes due to state and attribute 33 /// changes. 34 pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> { 35 rules: I, 36 matching_context: MatchingContext<'a, E::Impl>, 37 document_states_changed: DocumentState, 38 } 39 40 impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> { 41 /// Creates a new DocumentStateInvalidationProcessor. 42 #[inline] new(rules: I, document_states_changed: DocumentState, quirks_mode: QuirksMode) -> Self43 pub fn new(rules: I, document_states_changed: DocumentState, quirks_mode: QuirksMode) -> Self { 44 let mut matching_context = MatchingContext::new_for_visited( 45 MatchingMode::Normal, 46 None, 47 None, 48 VisitedHandlingMode::AllLinksVisitedAndUnvisited, 49 quirks_mode, 50 ); 51 52 matching_context.extra_data = InvalidationMatchingData { 53 document_state: document_states_changed, 54 }; 55 56 Self { 57 rules, 58 document_states_changed, 59 matching_context, 60 } 61 } 62 } 63 64 impl<'a, E, I> InvalidationProcessor<'a, E> for DocumentStateInvalidationProcessor<'a, E, I> 65 where 66 E: TElement, 67 I: Iterator<Item = &'a CascadeData>, 68 { check_outer_dependency(&mut self, _: &Dependency, _: E) -> bool69 fn check_outer_dependency(&mut self, _: &Dependency, _: E) -> bool { 70 debug_assert!( 71 false, 72 "how, we should only have parent-less dependencies here!" 73 ); 74 true 75 } 76 collect_invalidations( &mut self, _element: E, self_invalidations: &mut InvalidationVector<'a>, _descendant_invalidations: &mut DescendantInvalidationLists<'a>, _sibling_invalidations: &mut InvalidationVector<'a>, ) -> bool77 fn collect_invalidations( 78 &mut self, 79 _element: E, 80 self_invalidations: &mut InvalidationVector<'a>, 81 _descendant_invalidations: &mut DescendantInvalidationLists<'a>, 82 _sibling_invalidations: &mut InvalidationVector<'a>, 83 ) -> bool { 84 for cascade_data in &mut self.rules { 85 let map = cascade_data.invalidation_map(); 86 for dependency in &map.document_state_selectors { 87 if !dependency.state.intersects(self.document_states_changed) { 88 continue; 89 } 90 91 // We pass `None` as a scope, as document state selectors aren't 92 // affected by the current scope. 93 // 94 // FIXME(emilio): We should really pass the relevant host for 95 // self.rules, so that we invalidate correctly if the selector 96 // happens to have something like :host(:-moz-window-inactive) 97 // for example. 98 self_invalidations.push(Invalidation::new( 99 &dependency.dependency, 100 /* scope = */ None, 101 )); 102 } 103 } 104 105 false 106 } 107 matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl>108 fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> { 109 &mut self.matching_context 110 } 111 recursion_limit_exceeded(&mut self, _: E)112 fn recursion_limit_exceeded(&mut self, _: E) { 113 unreachable!("We don't run document state invalidation with stack limits") 114 } 115 should_process_descendants(&mut self, element: E) -> bool116 fn should_process_descendants(&mut self, element: E) -> bool { 117 match element.borrow_data() { 118 Some(d) => state_and_attributes::should_process_descendants(&d), 119 None => false, 120 } 121 } 122 invalidated_descendants(&mut self, element: E, child: E)123 fn invalidated_descendants(&mut self, element: E, child: E) { 124 state_and_attributes::invalidated_descendants(element, child) 125 } 126 invalidated_self(&mut self, element: E)127 fn invalidated_self(&mut self, element: E) { 128 state_and_attributes::invalidated_self(element); 129 } 130 } 131