mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
style: fix invalidation of sibling combinators in different slots
This extends the code to deal with sibling invalidation to handle the case where the flat tree doesn't match the DOM tree. In the test-case for example, dom is: * details * summary id=a * summary But flat tree is: * details * slot * summary id=a * slot * summary Differential Revision: https://phabricator.services.mozilla.com/D159150
This commit is contained in:
parent
6cb665df95
commit
f14f1fa440
6 changed files with 66 additions and 11 deletions
|
@ -211,6 +211,18 @@ pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
|
||||||
self.parent_node().and_then(|n| n.as_element())
|
self.parent_node().and_then(|n| n.as_element())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this node's parent element, or shadow host if it's a shadow root.
|
||||||
|
fn parent_element_or_host(&self) -> Option<Self::ConcreteElement> {
|
||||||
|
let parent = self.parent_node()?;
|
||||||
|
if let Some(e) = parent.as_element() {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
if let Some(root) = parent.as_shadow_root() {
|
||||||
|
return Some(root.host());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts self into an `OpaqueNode`.
|
/// Converts self into an `OpaqueNode`.
|
||||||
fn opaque(&self) -> OpaqueNode;
|
fn opaque(&self) -> OpaqueNode;
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,10 @@ where
|
||||||
Q::append_element(self.results, e);
|
Q::append_element(self.results, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalidated_sibling(&mut self, e: E, _of: E) {
|
||||||
|
Q::append_element(self.results, e);
|
||||||
|
}
|
||||||
|
|
||||||
fn recursion_limit_exceeded(&mut self, _e: E) {}
|
fn recursion_limit_exceeded(&mut self, _e: E) {}
|
||||||
fn invalidated_descendants(&mut self, _e: E, _child: E) {}
|
fn invalidated_descendants(&mut self, _e: E, _child: E) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,4 +130,8 @@ where
|
||||||
fn invalidated_self(&mut self, element: E) {
|
fn invalidated_self(&mut self, element: E) {
|
||||||
state_and_attributes::invalidated_self(element);
|
state_and_attributes::invalidated_self(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalidated_sibling(&mut self, sibling: E, of: E) {
|
||||||
|
state_and_attributes::invalidated_sibling(sibling, of);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,10 @@ where
|
||||||
/// Executes an action when `Self` is invalidated.
|
/// Executes an action when `Self` is invalidated.
|
||||||
fn invalidated_self(&mut self, element: E);
|
fn invalidated_self(&mut self, element: E);
|
||||||
|
|
||||||
|
/// Executes an action when `sibling` is invalidated as a sibling of
|
||||||
|
/// `of`.
|
||||||
|
fn invalidated_sibling(&mut self, sibling: E, of: E);
|
||||||
|
|
||||||
/// Executes an action when any descendant of `Self` is invalidated.
|
/// Executes an action when any descendant of `Self` is invalidated.
|
||||||
fn invalidated_descendants(&mut self, element: E, child: E);
|
fn invalidated_descendants(&mut self, element: E, child: E);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +401,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
if invalidated_sibling {
|
if invalidated_sibling {
|
||||||
sibling_invalidator.processor.invalidated_self(sibling);
|
sibling_invalidator.processor.invalidated_sibling(sibling, self.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
any_invalidated |= invalidated_sibling;
|
any_invalidated |= invalidated_sibling;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use crate::context::SharedStyleContext;
|
use crate::context::SharedStyleContext;
|
||||||
use crate::data::ElementData;
|
use crate::data::ElementData;
|
||||||
use crate::dom::TElement;
|
use crate::dom::{TElement, TNode};
|
||||||
use crate::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
|
use crate::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
|
||||||
use crate::invalidation::element::invalidation_map::*;
|
use crate::invalidation::element::invalidation_map::*;
|
||||||
use crate::invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
|
use crate::invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
|
||||||
|
@ -118,14 +118,10 @@ pub fn should_process_descendants(data: &ElementData) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Propagates the bits after invalidating a descendant child.
|
/// Propagates the bits after invalidating a descendant child.
|
||||||
pub fn invalidated_descendants<E>(element: E, child: E)
|
pub fn propagate_dirty_bit_up_to<E>(ancestor: E, child: E)
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
if !child.has_data() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
||||||
// but may be arbitrarily deep.
|
// but may be arbitrarily deep.
|
||||||
//
|
//
|
||||||
|
@ -136,10 +132,22 @@ where
|
||||||
unsafe { parent.set_dirty_descendants() };
|
unsafe { parent.set_dirty_descendants() };
|
||||||
current = parent.traversal_parent();
|
current = parent.traversal_parent();
|
||||||
|
|
||||||
if parent == element {
|
if parent == ancestor {
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debug_assert!(false, "Should've found {:?} as an ancestor of {:?}", ancestor, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Propagates the bits after invalidating a descendant child, if needed.
|
||||||
|
pub fn invalidated_descendants<E>(element: E, child: E)
|
||||||
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
|
if !child.has_data() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
propagate_dirty_bit_up_to(element, child)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the appropriate restyle hint after invalidating the style of a given
|
/// Sets the appropriate restyle hint after invalidating the style of a given
|
||||||
|
@ -153,6 +161,22 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the appropriate hint after invalidating the style of a sibling.
|
||||||
|
pub fn invalidated_sibling<E>(element: E, of: E)
|
||||||
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
|
debug_assert_eq!(element.as_node().parent_node(), of.as_node().parent_node(), "Should be siblings");
|
||||||
|
invalidated_self(element);
|
||||||
|
if element.traversal_parent() != of.traversal_parent() {
|
||||||
|
let parent = element.as_node().parent_element_or_host();
|
||||||
|
debug_assert!(parent.is_some(), "How can we have siblings without parent nodes?");
|
||||||
|
if let Some(e) = parent {
|
||||||
|
propagate_dirty_bit_up_to(e, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E>
|
impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E>
|
||||||
for StateAndAttrInvalidationProcessor<'a, 'b, E>
|
for StateAndAttrInvalidationProcessor<'a, 'b, E>
|
||||||
where
|
where
|
||||||
|
@ -366,6 +390,11 @@ where
|
||||||
debug_assert_ne!(element, self.element);
|
debug_assert_ne!(element, self.element);
|
||||||
invalidated_self(element);
|
invalidated_self(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalidated_sibling(&mut self, element: E, of: E) {
|
||||||
|
debug_assert_ne!(element, self.element);
|
||||||
|
invalidated_sibling(element, of);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'selectors, E> Collector<'a, 'b, 'selectors, E>
|
impl<'a, 'b, 'selectors, E> Collector<'a, 'b, 'selectors, E>
|
||||||
|
|
|
@ -157,6 +157,8 @@ pub trait DomTraversal<E: TElement>: Sync {
|
||||||
/// such, we have a pre-traversal step to handle that part and determine whether
|
/// such, we have a pre-traversal step to handle that part and determine whether
|
||||||
/// a full traversal is needed.
|
/// a full traversal is needed.
|
||||||
fn pre_traverse(root: E, shared_context: &SharedStyleContext) -> PreTraverseToken<E> {
|
fn pre_traverse(root: E, shared_context: &SharedStyleContext) -> PreTraverseToken<E> {
|
||||||
|
use crate::invalidation::element::state_and_attributes::propagate_dirty_bit_up_to;
|
||||||
|
|
||||||
let traversal_flags = shared_context.traversal_flags;
|
let traversal_flags = shared_context.traversal_flags;
|
||||||
|
|
||||||
let mut data = root.mutate_data();
|
let mut data = root.mutate_data();
|
||||||
|
@ -174,11 +176,11 @@ pub trait DomTraversal<E: TElement>: Sync {
|
||||||
);
|
);
|
||||||
|
|
||||||
if invalidation_result.has_invalidated_siblings() {
|
if invalidation_result.has_invalidated_siblings() {
|
||||||
let actual_root = root.traversal_parent().expect(
|
let actual_root = root.as_node().parent_element_or_host().expect(
|
||||||
"How in the world can you invalidate \
|
"How in the world can you invalidate \
|
||||||
siblings without a parent?",
|
siblings without a parent?",
|
||||||
);
|
);
|
||||||
unsafe { actual_root.set_dirty_descendants() }
|
propagate_dirty_bit_up_to(actual_root, root);
|
||||||
return PreTraverseToken(Some(actual_root));
|
return PreTraverseToken(Some(actual_root));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue