style: Add invalidation support for ::slotted().

Bug: 1424607
Reviewed-by: heycam
MozReview-Commit-ID: 8pIVUx27o7x
This commit is contained in:
Emilio Cobos Álvarez 2017-12-17 17:56:15 +01:00
parent 040379208e
commit b26f3280d2
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
7 changed files with 294 additions and 110 deletions

View file

@ -363,6 +363,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
LayoutIterator(self.as_node().dom_children()) LayoutIterator(self.as_node().dom_children())
} }
fn is_html_element(&self) -> bool {
unsafe { self.element.is_html_element() }
}
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> { fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
unsafe { unsafe {
(*self.element.style_attribute()).as_ref().map(|x| x.borrow_arc()) (*self.element.style_attribute()).as_ref().map(|x| x.borrow_arc())

View file

@ -416,6 +416,20 @@ pub trait TElement
F: FnMut(Self), F: FnMut(Self),
{} {}
/// Return whether this element is an element in the HTML namespace.
fn is_html_element(&self) -> bool;
/// Returns whether this element is a <html:slot> element.
fn is_html_slot_element(&self) -> bool {
self.get_local_name() == &*local_name!("slot") &&
self.is_html_element()
}
/// Return the list of slotted nodes of this node.
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
&[]
}
/// For a given NAC element, return the closest non-NAC ancestor, which is /// For a given NAC element, return the closest non-NAC ancestor, which is
/// guaranteed to exist. /// guaranteed to exist.
fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> { fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> {

View file

@ -8,7 +8,8 @@
use Atom; use Atom;
use context::QuirksMode; use context::QuirksMode;
use dom::{TDocument, TElement, TNode}; use dom::{TDocument, TElement, TNode};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector}; use invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation};
use invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
use selectors::{Element, NthIndexCache, SelectorList}; use selectors::{Element, NthIndexCache, SelectorList};
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::matching::{self, MatchingContext, MatchingMode}; use selectors::matching::{self, MatchingContext, MatchingMode};
@ -143,7 +144,7 @@ where
&mut self, &mut self,
element: E, element: E,
self_invalidations: &mut InvalidationVector<'a>, self_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut InvalidationVector<'a>, descendant_invalidations: &mut DescendantInvalidationLists<'a>,
_sibling_invalidations: &mut InvalidationVector<'a>, _sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool { ) -> bool {
// TODO(emilio): If the element is not a root element, and // TODO(emilio): If the element is not a root element, and
@ -163,7 +164,7 @@ where
let target_vector = let target_vector =
if self.matching_context.scope_element.is_some() { if self.matching_context.scope_element.is_some() {
descendant_invalidations &mut descendant_invalidations.dom_descendants
} else { } else {
self_invalidations self_invalidations
}; };

View file

@ -610,10 +610,7 @@ impl<'le> GeckoElement<'le> {
self.as_node().node_info().mInner.mNamespaceID self.as_node().node_info().mInner.mNamespaceID
} }
fn is_html_element(&self) -> bool { #[inline]
self.namespace_id() == (structs::root::kNameSpaceID_XHTML as i32)
}
fn is_xul_element(&self) -> bool { fn is_xul_element(&self) -> bool {
self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32) self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32)
} }
@ -974,6 +971,40 @@ impl<'le> TElement for GeckoElement<'le> {
self.as_node().owner_doc().as_node() self.as_node().owner_doc().as_node()
} }
#[inline]
fn is_html_element(&self) -> bool {
self.namespace_id() == (structs::root::kNameSpaceID_XHTML as i32)
}
/// Return the list of slotted nodes of this node.
#[inline]
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
if !self.is_html_slot_element() || !self.is_in_shadow_tree() {
return &[];
}
let slot: &structs::HTMLSlotElement = unsafe {
mem::transmute(self.0)
};
if cfg!(debug_assertions) {
let base: &RawGeckoElement = &slot._base._base._base._base;
assert_eq!(base as *const _, self.0 as *const _, "Bad cast");
}
let assigned_nodes: &[structs::RefPtr<structs::nsINode>] =
&*slot.mAssignedNodes;
debug_assert_eq!(
mem::size_of::<structs::RefPtr<structs::nsINode>>(),
mem::size_of::<Self::ConcreteNode>(),
"Bad cast!"
);
unsafe { mem::transmute(assigned_nodes) }
}
/// Execute `f` for each anonymous content child element (apart from /// Execute `f` for each anonymous content child element (apart from
/// ::before and ::after) whose originating element is `self`. /// ::before and ::after) whose originating element is `self`.
fn each_anonymous_content_child<F>(&self, mut f: F) fn each_anonymous_content_child<F>(&self, mut f: F)

View file

@ -13,7 +13,8 @@ use dom::TElement;
use element_state::ElementState; use element_state::ElementState;
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper}; use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use invalidation::element::invalidation_map::*; use invalidation::element::invalidation_map::*;
use invalidation::element::invalidator::{InvalidationVector, Invalidation, InvalidationProcessor}; use invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
use invalidation::element::restyle_hints::RestyleHint; use invalidation::element::restyle_hints::RestyleHint;
use selector_map::SelectorMap; use selector_map::SelectorMap;
use selector_parser::Snapshot; use selector_parser::Snapshot;
@ -47,7 +48,7 @@ where
classes_removed: &'a SmallVec<[Atom; 8]>, classes_removed: &'a SmallVec<[Atom; 8]>,
classes_added: &'a SmallVec<[Atom; 8]>, classes_added: &'a SmallVec<[Atom; 8]>,
state_changes: ElementState, state_changes: ElementState,
descendant_invalidations: &'a mut InvalidationVector<'selectors>, descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>,
sibling_invalidations: &'a mut InvalidationVector<'selectors>, sibling_invalidations: &'a mut InvalidationVector<'selectors>,
invalidates_self: bool, invalidates_self: bool,
} }
@ -109,7 +110,7 @@ where
&mut self, &mut self,
element: E, element: E,
_self_invalidations: &mut InvalidationVector<'a>, _self_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut InvalidationVector<'a>, descendant_invalidations: &mut DescendantInvalidationLists<'a>,
sibling_invalidations: &mut InvalidationVector<'a>, sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool { ) -> bool {
debug_assert!(element.has_snapshot(), "Why bothering?"); debug_assert!(element.has_snapshot(), "Why bothering?");
@ -236,7 +237,10 @@ where
// //
// This number is completely made-up, but the page that made us add this // This number is completely made-up, but the page that made us add this
// code generated 1960+ invalidations (bug 1420741). // code generated 1960+ invalidations (bug 1420741).
if descendant_invalidations.len() > 150 { //
// We don't look at slotted_descendants because those don't propagate
// down more than one level anyway.
if descendant_invalidations.dom_descendants.len() > 150 {
self.data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS); self.data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
} }
@ -509,36 +513,52 @@ where
} }
fn note_dependency(&mut self, dependency: &'selectors Dependency) { fn note_dependency(&mut self, dependency: &'selectors Dependency) {
if dependency.affects_self() { debug_assert!(self.dependency_may_be_relevant(dependency));
let invalidation_kind = dependency.invalidation_kind();
if matches!(invalidation_kind, DependencyInvalidationKind::Element) {
self.invalidates_self = true; self.invalidates_self = true;
return;
} }
if dependency.affects_descendants() {
debug_assert_ne!(dependency.selector_offset, 0); debug_assert_ne!(dependency.selector_offset, 0);
debug_assert_ne!(dependency.selector_offset, dependency.selector.len()); debug_assert_ne!(
debug_assert!(!dependency.affects_later_siblings()); dependency.selector_offset,
self.descendant_invalidations.push(Invalidation::new( dependency.selector.len()
);
let invalidation = Invalidation::new(
&dependency.selector, &dependency.selector,
dependency.selector.len() - dependency.selector_offset + 1, dependency.selector.len() - dependency.selector_offset + 1,
)); );
} else if dependency.affects_later_siblings() {
debug_assert_ne!(dependency.selector_offset, 0); match invalidation_kind {
debug_assert_ne!(dependency.selector_offset, dependency.selector.len()); DependencyInvalidationKind::Element => unreachable!(),
self.sibling_invalidations.push(Invalidation::new( DependencyInvalidationKind::ElementAndDescendants => {
&dependency.selector, self.invalidates_self = true;
dependency.selector.len() - dependency.selector_offset + 1, self.descendant_invalidations.dom_descendants.push(invalidation);
)); }
DependencyInvalidationKind::Descendants => {
self.descendant_invalidations.dom_descendants.push(invalidation);
}
DependencyInvalidationKind::Siblings => {
self.sibling_invalidations.push(invalidation);
}
DependencyInvalidationKind::SlottedElements => {
self.descendant_invalidations.slotted_descendants.push(invalidation);
}
} }
} }
/// Returns whether `dependency` may cause us to invalidate the style of /// Returns whether `dependency` may cause us to invalidate the style of
/// more elements than what we've already invalidated. /// more elements than what we've already invalidated.
fn dependency_may_be_relevant(&self, dependency: &Dependency) -> bool { fn dependency_may_be_relevant(&self, dependency: &Dependency) -> bool {
if dependency.affects_descendants() || dependency.affects_later_siblings() { match dependency.invalidation_kind() {
return true; DependencyInvalidationKind::Element => !self.invalidates_self,
} DependencyInvalidationKind::SlottedElements => self.element.is_html_slot_element(),
DependencyInvalidationKind::ElementAndDescendants |
debug_assert!(dependency.affects_self()); DependencyInvalidationKind::Siblings |
!self.invalidates_self DependencyInvalidationKind::Descendants => true,
}
} }
} }

View file

@ -63,6 +63,25 @@ pub struct Dependency {
pub selector_offset: usize, pub selector_offset: usize,
} }
/// The kind of elements down the tree this dependency may affect.
#[derive(Debug, Eq, PartialEq)]
pub enum DependencyInvalidationKind {
/// This dependency may affect the element that changed itself.
Element,
/// This dependency affects the style of the element itself, and also the
/// style of its descendants.
///
/// TODO(emilio): Each time this feels more of a hack for eager pseudos...
ElementAndDescendants,
/// This dependency may affect descendants down the tree.
Descendants,
/// This dependency may affect siblings to the right of the element that
/// changed.
Siblings,
/// This dependency may affect slotted elements of the element that changed.
SlottedElements,
}
impl Dependency { impl Dependency {
/// Returns the combinator to the right of the partial selector this /// Returns the combinator to the right of the partial selector this
/// dependency represents. /// dependency represents.
@ -76,28 +95,19 @@ impl Dependency {
Some(self.selector.combinator_at_match_order(self.selector_offset - 1)) Some(self.selector.combinator_at_match_order(self.selector_offset - 1))
} }
/// Whether this dependency affects the style of the element. /// The kind of invalidation that this would generate.
/// pub fn invalidation_kind(&self) -> DependencyInvalidationKind {
/// NOTE(emilio): pseudo-elements need to be here to account for eager match self.combinator() {
/// pseudos, since they just grab the style from the originating element. None => DependencyInvalidationKind::Element,
///
/// TODO(emilio): We could look at the selector itself to see if it's an
/// eager pseudo, and return false here if not.
pub fn affects_self(&self) -> bool {
matches!(self.combinator(), None | Some(Combinator::PseudoElement))
}
/// Whether this dependency may affect style of any of our descendants.
pub fn affects_descendants(&self) -> bool {
matches!(self.combinator(), Some(Combinator::PseudoElement) |
Some(Combinator::Child) | Some(Combinator::Child) |
Some(Combinator::Descendant)) Some(Combinator::Descendant) => DependencyInvalidationKind::Descendants,
Some(Combinator::LaterSibling) |
Some(Combinator::NextSibling) => DependencyInvalidationKind::Siblings,
// TODO(emilio): We could look at the selector itself to see if it's
// an eager pseudo, and return only Descendants here if not.
Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants,
Some(Combinator::SlotAssignment) => DependencyInvalidationKind::SlottedElements,
} }
/// Whether this dependency may affect style of any of our later siblings.
pub fn affects_later_siblings(&self) -> bool {
matches!(self.combinator(), Some(Combinator::NextSibling) |
Some(Combinator::LaterSibling))
} }
} }

View file

@ -39,7 +39,7 @@ where
&mut self, &mut self,
element: E, element: E,
self_invalidations: &mut InvalidationVector<'a>, self_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut InvalidationVector<'a>, descendant_invalidations: &mut DescendantInvalidationLists<'a>,
sibling_invalidations: &mut InvalidationVector<'a>, sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool; ) -> bool;
@ -58,6 +58,25 @@ where
fn invalidated_descendants(&mut self, element: E, child: E); fn invalidated_descendants(&mut self, element: E, child: E);
} }
/// Different invalidation lists for descendants.
#[derive(Debug, Default)]
pub struct DescendantInvalidationLists<'a> {
/// Invalidations for normal DOM children and pseudo-elements.
///
/// TODO(emilio): Having a list of invalidations just for pseudo-elements
/// may save some work here and there.
pub dom_descendants: InvalidationVector<'a>,
/// Invalidations for slotted children of an element.
pub slotted_descendants: InvalidationVector<'a>,
}
impl<'a> DescendantInvalidationLists<'a> {
fn is_empty(&self) -> bool {
self.dom_descendants.is_empty() &&
self.slotted_descendants.is_empty()
}
}
/// The struct that takes care of encapsulating all the logic on where and how /// The struct that takes care of encapsulating all the logic on where and how
/// element styles need to be invalidated. /// element styles need to be invalidated.
pub struct TreeStyleInvalidator<'a, 'b, E, P: 'a> pub struct TreeStyleInvalidator<'a, 'b, E, P: 'a>
@ -75,13 +94,22 @@ where
/// A vector of invalidations, optimized for small invalidation sets. /// A vector of invalidations, optimized for small invalidation sets.
pub type InvalidationVector<'a> = SmallVec<[Invalidation<'a>; 10]>; pub type InvalidationVector<'a> = SmallVec<[Invalidation<'a>; 10]>;
/// The kind of descendant invalidation we're processing.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum DescendantInvalidationKind {
/// A DOM descendant invalidation.
Dom,
/// A ::slotted() descendant invalidation.
Slotted,
}
/// The kind of invalidation we're processing. /// The kind of invalidation we're processing.
/// ///
/// We can use this to avoid pushing invalidations of the same kind to our /// We can use this to avoid pushing invalidations of the same kind to our
/// descendants or siblings. /// descendants or siblings.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum InvalidationKind { enum InvalidationKind {
Descendant, Descendant(DescendantInvalidationKind),
Sibling, Sibling,
} }
@ -126,21 +154,27 @@ impl<'a> Invalidation<'a> {
// //
// We should be able to do better here! // We should be able to do better here!
match self.selector.combinator_at_parse_order(self.offset - 1) { match self.selector.combinator_at_parse_order(self.offset - 1) {
Combinator::Descendant |
Combinator::LaterSibling |
Combinator::PseudoElement => true,
Combinator::SlotAssignment |
Combinator::NextSibling | Combinator::NextSibling |
Combinator::Child => false, Combinator::Child => false,
_ => true,
} }
} }
fn kind(&self) -> InvalidationKind { fn kind(&self) -> InvalidationKind {
if self.offset == 0 { if self.offset == 0 {
return InvalidationKind::Descendant; return InvalidationKind::Descendant(DescendantInvalidationKind::Dom);
} }
if self.selector.combinator_at_parse_order(self.offset - 1).is_ancestor() { match self.selector.combinator_at_parse_order(self.offset - 1) {
InvalidationKind::Descendant Combinator::Child |
} else { Combinator::Descendant |
InvalidationKind::Sibling Combinator::PseudoElement => InvalidationKind::Descendant(DescendantInvalidationKind::Dom),
Combinator::SlotAssignment => InvalidationKind::Descendant(DescendantInvalidationKind::Slotted),
Combinator::NextSibling |
Combinator::LaterSibling => InvalidationKind::Sibling,
} }
} }
} }
@ -230,7 +264,7 @@ where
debug!("StyleTreeInvalidator::invalidate({:?})", self.element); debug!("StyleTreeInvalidator::invalidate({:?})", self.element);
let mut self_invalidations = InvalidationVector::new(); let mut self_invalidations = InvalidationVector::new();
let mut descendant_invalidations = InvalidationVector::new(); let mut descendant_invalidations = DescendantInvalidationLists::default();
let mut sibling_invalidations = InvalidationVector::new(); let mut sibling_invalidations = InvalidationVector::new();
let mut invalidated_self = self.processor.collect_invalidations( let mut invalidated_self = self.processor.collect_invalidations(
@ -242,7 +276,7 @@ where
debug!("Collected invalidations (self: {}): ", invalidated_self); debug!("Collected invalidations (self: {}): ", invalidated_self);
debug!(" > self: {}, {:?}", self_invalidations.len(), self_invalidations); debug!(" > self: {}, {:?}", self_invalidations.len(), self_invalidations);
debug!(" > descendants: {}, {:?}", descendant_invalidations.len(), descendant_invalidations); debug!(" > descendants: {:?}", descendant_invalidations);
debug!(" > siblings: {}, {:?}", sibling_invalidations.len(), sibling_invalidations); debug!(" > siblings: {}, {:?}", sibling_invalidations.len(), sibling_invalidations);
let invalidated_self_from_collection = invalidated_self; let invalidated_self_from_collection = invalidated_self;
@ -251,6 +285,7 @@ where
&self_invalidations, &self_invalidations,
&mut descendant_invalidations, &mut descendant_invalidations,
&mut sibling_invalidations, &mut sibling_invalidations,
DescendantInvalidationKind::Dom,
); );
if invalidated_self && !invalidated_self_from_collection { if invalidated_self && !invalidated_self_from_collection {
@ -260,7 +295,11 @@ where
let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations); let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations);
let invalidated_siblings = self.invalidate_siblings(&mut sibling_invalidations); let invalidated_siblings = self.invalidate_siblings(&mut sibling_invalidations);
InvalidationResult { invalidated_self, invalidated_descendants, invalidated_siblings } InvalidationResult {
invalidated_self,
invalidated_descendants,
invalidated_siblings,
}
} }
/// Go through later DOM siblings, invalidating style as needed using the /// Go through later DOM siblings, invalidating style as needed using the
@ -286,7 +325,8 @@ where
self.processor, self.processor,
); );
let mut invalidations_for_descendants = InvalidationVector::new(); let mut invalidations_for_descendants =
DescendantInvalidationLists::default();
let invalidated_sibling = let invalidated_sibling =
sibling_invalidator.process_sibling_invalidations( sibling_invalidator.process_sibling_invalidations(
&mut invalidations_for_descendants, &mut invalidations_for_descendants,
@ -301,7 +341,7 @@ where
any_invalidated |= any_invalidated |=
sibling_invalidator.invalidate_descendants( sibling_invalidator.invalidate_descendants(
&invalidations_for_descendants &invalidations_for_descendants,
); );
if sibling_invalidations.is_empty() { if sibling_invalidations.is_empty() {
@ -324,7 +364,8 @@ where
let result = self.invalidate_child( let result = self.invalidate_child(
child, child,
invalidations, invalidations,
&mut sibling_invalidations &mut sibling_invalidations,
DescendantInvalidationKind::Dom,
); );
// Roots of NAC subtrees can indeed generate sibling invalidations, but // Roots of NAC subtrees can indeed generate sibling invalidations, but
@ -344,8 +385,10 @@ where
child: E, child: E,
invalidations: &[Invalidation<'b>], invalidations: &[Invalidation<'b>],
sibling_invalidations: &mut InvalidationVector<'b>, sibling_invalidations: &mut InvalidationVector<'b>,
descendant_invalidation_kind: DescendantInvalidationKind,
) -> bool { ) -> bool {
let mut invalidations_for_descendants = InvalidationVector::new(); let mut invalidations_for_descendants =
DescendantInvalidationLists::default();
let mut invalidated_child = false; let mut invalidated_child = false;
let invalidated_descendants = { let invalidated_descendants = {
@ -366,13 +409,16 @@ where
invalidations, invalidations,
&mut invalidations_for_descendants, &mut invalidations_for_descendants,
sibling_invalidations, sibling_invalidations,
descendant_invalidation_kind,
); );
if invalidated_child { if invalidated_child {
child_invalidator.processor.invalidated_self(child); child_invalidator.processor.invalidated_self(child);
} }
child_invalidator.invalidate_descendants(&invalidations_for_descendants) child_invalidator.invalidate_descendants(
&invalidations_for_descendants,
)
}; };
// The child may not be a flattened tree child of the current element, // The child may not be a flattened tree child of the current element,
@ -418,10 +464,6 @@ where
// //
// This probably needs a shadow root check on `child` here, and // This probably needs a shadow root check on `child` here, and
// recursing if that's the case. // recursing if that's the case.
//
// Also, what's the deal with HTML <content>? We don't need to
// support that for now, though we probably need to recurse into the
// distributed children too.
let child = match child.as_element() { let child = match child.as_element() {
Some(e) => e, Some(e) => e,
None => continue, None => continue,
@ -431,15 +473,14 @@ where
child, child,
invalidations, invalidations,
&mut sibling_invalidations, &mut sibling_invalidations,
DescendantInvalidationKind::Dom,
); );
} }
any_descendant any_descendant
} }
/// Given a descendant invalidation list, go through the current element's fn invalidate_slotted_elements(
/// descendants, and invalidate style on them.
fn invalidate_descendants(
&mut self, &mut self,
invalidations: &[Invalidation<'b>], invalidations: &[Invalidation<'b>],
) -> bool { ) -> bool {
@ -447,6 +488,83 @@ where
return false; return false;
} }
let mut any = false;
let mut sibling_invalidations = InvalidationVector::new();
let element = self.element;
for node in element.slotted_nodes() {
let element = match node.as_element() {
Some(e) => e,
None => continue,
};
any |= self.invalidate_child(
element,
invalidations,
&mut sibling_invalidations,
DescendantInvalidationKind::Slotted,
);
debug_assert!(
sibling_invalidations.is_empty(),
"::slotted() shouldn't have sibling combinators to the right, \
this makes no sense! {:?}",
sibling_invalidations
);
}
any
}
fn invalidate_non_slotted_descendants(
&mut self,
invalidations: &[Invalidation<'b>],
) -> bool {
if invalidations.is_empty() {
return false;
}
if self.processor.light_tree_only() {
let node = self.element.as_node();
return self.invalidate_dom_descendants_of(node, invalidations);
}
let mut any_descendant = false;
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations);
}
if let Some(before) = self.element.before_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(before, invalidations);
}
let node = self.element.as_node();
any_descendant |=
self.invalidate_dom_descendants_of(node, invalidations);
if let Some(after) = self.element.after_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(after, invalidations);
}
any_descendant |= self.invalidate_nac(invalidations);
any_descendant
}
/// Given the descendant invalidation lists, go through the current
/// element's descendants, and invalidate style on them.
fn invalidate_descendants(
&mut self,
invalidations: &DescendantInvalidationLists<'b>,
) -> bool {
if invalidations.is_empty() {
return false;
}
debug!("StyleTreeInvalidator::invalidate_descendants({:?})", debug!("StyleTreeInvalidator::invalidate_descendants({:?})",
self.element); self.element);
debug!(" > {:?}", invalidations); debug!(" > {:?}", invalidations);
@ -465,35 +583,12 @@ where
} }
} }
if self.processor.light_tree_only() {
let node = self.element.as_node();
return self.invalidate_dom_descendants_of(node, invalidations);
}
let mut any_descendant = false; let mut any_descendant = false;
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |= any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations); self.invalidate_non_slotted_descendants(&invalidations.dom_descendants);
}
// TODO(emilio): Having a list of invalidations just for pseudo-elements
// may save some work here and there.
if let Some(before) = self.element.before_pseudo_element() {
any_descendant |= any_descendant |=
self.invalidate_pseudo_element_or_nac(before, invalidations); self.invalidate_slotted_elements(&invalidations.slotted_descendants);
}
let node = self.element.as_node();
any_descendant |=
self.invalidate_dom_descendants_of(node, invalidations);
if let Some(after) = self.element.after_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(after, invalidations);
}
any_descendant |= self.invalidate_nac(invalidations);
any_descendant any_descendant
} }
@ -511,7 +606,7 @@ where
/// Returns whether invalidated the current element's style. /// Returns whether invalidated the current element's style.
fn process_sibling_invalidations( fn process_sibling_invalidations(
&mut self, &mut self,
descendant_invalidations: &mut InvalidationVector<'b>, descendant_invalidations: &mut DescendantInvalidationLists<'b>,
sibling_invalidations: &mut InvalidationVector<'b>, sibling_invalidations: &mut InvalidationVector<'b>,
) -> bool { ) -> bool {
let mut i = 0; let mut i = 0;
@ -547,8 +642,9 @@ where
fn process_descendant_invalidations( fn process_descendant_invalidations(
&mut self, &mut self,
invalidations: &[Invalidation<'b>], invalidations: &[Invalidation<'b>],
descendant_invalidations: &mut InvalidationVector<'b>, descendant_invalidations: &mut DescendantInvalidationLists<'b>,
sibling_invalidations: &mut InvalidationVector<'b>, sibling_invalidations: &mut InvalidationVector<'b>,
descendant_invalidation_kind: DescendantInvalidationKind,
) -> bool { ) -> bool {
let mut invalidated = false; let mut invalidated = false;
@ -557,14 +653,19 @@ where
invalidation, invalidation,
descendant_invalidations, descendant_invalidations,
sibling_invalidations, sibling_invalidations,
InvalidationKind::Descendant, InvalidationKind::Descendant(descendant_invalidation_kind),
); );
invalidated |= result.invalidated_self; invalidated |= result.invalidated_self;
if invalidation.effective_for_next() { if invalidation.effective_for_next() {
let mut invalidation = invalidation.clone(); let mut invalidation = invalidation.clone();
invalidation.matched_by_any_previous |= result.matched; invalidation.matched_by_any_previous |= result.matched;
descendant_invalidations.push(invalidation.clone()); debug_assert_eq!(
descendant_invalidation_kind,
DescendantInvalidationKind::Dom,
"Slotted invalidations don't propagate."
);
descendant_invalidations.dom_descendants.push(invalidation);
} }
} }
@ -580,7 +681,7 @@ where
fn process_invalidation( fn process_invalidation(
&mut self, &mut self,
invalidation: &Invalidation<'b>, invalidation: &Invalidation<'b>,
descendant_invalidations: &mut InvalidationVector<'b>, descendant_invalidations: &mut DescendantInvalidationLists<'b>,
sibling_invalidations: &mut InvalidationVector<'b>, sibling_invalidations: &mut InvalidationVector<'b>,
invalidation_kind: InvalidationKind, invalidation_kind: InvalidationKind,
) -> SingleInvalidationResult { ) -> SingleInvalidationResult {
@ -732,8 +833,11 @@ where
already been matched before"); already been matched before");
} else { } else {
match next_invalidation_kind { match next_invalidation_kind {
InvalidationKind::Descendant => { InvalidationKind::Descendant(DescendantInvalidationKind::Dom) => {
descendant_invalidations.push(next_invalidation); descendant_invalidations.dom_descendants.push(next_invalidation);
}
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) => {
descendant_invalidations.slotted_descendants.push(next_invalidation);
} }
InvalidationKind::Sibling => { InvalidationKind::Sibling => {
sibling_invalidations.push(next_invalidation); sibling_invalidations.push(next_invalidation);