mirror of
https://github.com/servo/servo.git
synced 2025-06-21 15:49:04 +01:00
Some of the stuff, in particular inside GeckoBindings stuff should be refactored to be less ugly and duplicate a bit less code, but the rest of the code should be landable as is. Some invalidation changes are already needed because we weren't matching with the right shadow host during invalidation (which made existing ::part() tests fail). Pending invalidation work: * Making exportparts work right on the snapshots. * Invalidating parts from descendant hosts. They're not very hard but I need to think how to best implement it: * Maybe get rid of ShadowRoot::mParts and just walk DOM descendants in the Shadow DOM. * Maybe implement a ElementHasExportPartsAttr much like HasPartAttr and use that to keep the list of elements. * Maybe invalidate :host and ::part() together in here[1] * Maybe something else. Opinions? [1]: https://searchfox.org/mozilla-central/rev/131338e5017bc0283d86fb73844407b9a2155c98/servo/components/style/invalidation/element/invalidator.rs#561 Differential Revision: https://phabricator.services.mozilla.com/D53730
117 lines
3.9 KiB
Rust
117 lines
3.9 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
//! An invalidation processor for style changes due to document state changes.
|
|
|
|
use crate::dom::TElement;
|
|
use crate::element_state::DocumentState;
|
|
use crate::invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
|
|
use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
|
|
use crate::invalidation::element::state_and_attributes;
|
|
use crate::stylist::CascadeData;
|
|
use selectors::matching::{MatchingContext, MatchingMode, QuirksMode, VisitedHandlingMode};
|
|
|
|
/// A struct holding the members necessary to invalidate document state
|
|
/// selectors.
|
|
pub struct InvalidationMatchingData {
|
|
/// The document state that has changed, which makes it always match.
|
|
pub document_state: DocumentState,
|
|
}
|
|
|
|
impl Default for InvalidationMatchingData {
|
|
#[inline(always)]
|
|
fn default() -> Self {
|
|
Self {
|
|
document_state: DocumentState::empty(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An invalidation processor for style changes due to state and attribute
|
|
/// changes.
|
|
pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> {
|
|
rules: I,
|
|
matching_context: MatchingContext<'a, E::Impl>,
|
|
document_states_changed: DocumentState,
|
|
}
|
|
|
|
impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> {
|
|
/// Creates a new DocumentStateInvalidationProcessor.
|
|
#[inline]
|
|
pub fn new(rules: I, document_states_changed: DocumentState, quirks_mode: QuirksMode) -> Self {
|
|
let mut matching_context = MatchingContext::new_for_visited(
|
|
MatchingMode::Normal,
|
|
None,
|
|
None,
|
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
|
|
quirks_mode,
|
|
);
|
|
|
|
matching_context.extra_data = InvalidationMatchingData {
|
|
document_state: document_states_changed,
|
|
};
|
|
|
|
Self {
|
|
rules,
|
|
document_states_changed,
|
|
matching_context,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, E, I> InvalidationProcessor<'a, E> for DocumentStateInvalidationProcessor<'a, E, I>
|
|
where
|
|
E: TElement,
|
|
I: Iterator<Item = &'a CascadeData>,
|
|
{
|
|
fn collect_invalidations(
|
|
&mut self,
|
|
_element: E,
|
|
self_invalidations: &mut InvalidationVector<'a>,
|
|
_descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
|
_sibling_invalidations: &mut InvalidationVector<'a>,
|
|
) -> bool {
|
|
for cascade_data in &mut self.rules {
|
|
let map = cascade_data.invalidation_map();
|
|
for dependency in &map.document_state_selectors {
|
|
if !dependency.state.intersects(self.document_states_changed) {
|
|
continue;
|
|
}
|
|
|
|
// We pass `None` as a scope, as document state selectors aren't
|
|
// affected by the current scope.
|
|
self_invalidations.push(Invalidation::new(
|
|
&dependency.selector,
|
|
/* scope = */ None,
|
|
0,
|
|
));
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
|
|
&mut self.matching_context
|
|
}
|
|
|
|
fn recursion_limit_exceeded(&mut self, _: E) {
|
|
unreachable!("We don't run document state invalidation with stack limits")
|
|
}
|
|
|
|
fn should_process_descendants(&mut self, element: E) -> bool {
|
|
match element.borrow_data() {
|
|
Some(d) => state_and_attributes::should_process_descendants(&d),
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
fn invalidated_descendants(&mut self, element: E, child: E) {
|
|
state_and_attributes::invalidated_descendants(element, child)
|
|
}
|
|
|
|
fn invalidated_self(&mut self, element: E) {
|
|
state_and_attributes::invalidated_self(element);
|
|
}
|
|
}
|