Propagate dirty bits after invalidation if needed.

This commit is contained in:
Wei-Cheng Pan 2017-08-28 18:41:07 +08:00
parent c98b362e65
commit 22ace048cb
3 changed files with 73 additions and 20 deletions

View file

@ -6,6 +6,7 @@
use context::{SharedStyleContext, StackLimitChecker}; use context::{SharedStyleContext, StackLimitChecker};
use dom::TElement; use dom::TElement;
use invalidation::element::invalidator::InvalidationResult;
use invalidation::element::restyle_hints::RestyleHint; use invalidation::element::restyle_hints::RestyleHint;
use properties::ComputedValues; use properties::ComputedValues;
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
@ -329,10 +330,10 @@ impl ElementData {
element: E, element: E,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
stack_limit_checker: Option<&StackLimitChecker>, stack_limit_checker: Option<&StackLimitChecker>,
) { ) -> InvalidationResult {
// In animation-only restyle we shouldn't touch snapshot at all. // In animation-only restyle we shouldn't touch snapshot at all.
if shared_context.traversal_flags.for_animation_only() { if shared_context.traversal_flags.for_animation_only() {
return; return InvalidationResult::empty();
} }
use invalidation::element::invalidator::TreeStyleInvalidator; use invalidation::element::invalidator::TreeStyleInvalidator;
@ -345,17 +346,20 @@ impl ElementData {
element.handled_snapshot(), element.handled_snapshot(),
element.implemented_pseudo_element()); element.implemented_pseudo_element());
if element.has_snapshot() && !element.handled_snapshot() { if !element.has_snapshot() || element.handled_snapshot() {
let invalidator = TreeStyleInvalidator::new( return InvalidationResult::empty();
element,
Some(self),
shared_context,
stack_limit_checker,
);
invalidator.invalidate();
unsafe { element.set_handled_snapshot() }
debug_assert!(element.handled_snapshot());
} }
let invalidator = TreeStyleInvalidator::new(
element,
Some(self),
shared_context,
stack_limit_checker,
);
let result = invalidator.invalidate();
unsafe { element.set_handled_snapshot() }
debug_assert!(element.handled_snapshot());
result
} }
/// Returns true if this element has styles. /// Returns true if this element has styles.

View file

@ -115,7 +115,7 @@ impl fmt::Debug for Invalidation {
} }
/// The result of processing a single invalidation for a given element. /// The result of processing a single invalidation for a given element.
struct InvalidationResult { struct SingleInvalidationResult {
/// Whether the element itself was invalidated. /// Whether the element itself was invalidated.
invalidated_self: bool, invalidated_self: bool,
/// Whether the invalidation matched, either invalidating the element or /// Whether the invalidation matched, either invalidating the element or
@ -123,6 +123,42 @@ struct InvalidationResult {
matched: bool, matched: bool,
} }
/// The result of a whole invalidation process for a given element.
pub struct InvalidationResult {
/// Whether the element itself was invalidated.
invalidated_self: bool,
/// Whether the element's descendants were invalidated.
invalidated_descendants: bool,
/// Whether the element's siblings were invalidated.
invalidated_siblings: bool,
}
impl InvalidationResult {
/// Create an emtpy result.
pub fn empty() -> Self {
Self {
invalidated_self: false,
invalidated_descendants: false,
invalidated_siblings: false,
}
}
/// Whether the invalidation has invalidate the element itself.
pub fn has_invalidated_self(&self) -> bool {
self.invalidated_self
}
/// Whether the invalidation has invalidate desendants.
pub fn has_invalidated_descendants(&self) -> bool {
self.invalidated_descendants
}
/// Whether the invalidation has invalidate siblings.
pub fn has_invalidated_siblings(&self) -> bool {
self.invalidated_siblings
}
}
impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E> impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
where E: TElement, where E: TElement,
{ {
@ -142,7 +178,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
} }
/// Perform the invalidation pass. /// Perform the invalidation pass.
pub fn invalidate(mut self) { pub fn invalidate(mut self) -> InvalidationResult {
debug!("StyleTreeInvalidator::invalidate({:?})", self.element); debug!("StyleTreeInvalidator::invalidate({:?})", self.element);
debug_assert!(self.element.has_snapshot(), "Why bothering?"); debug_assert!(self.element.has_snapshot(), "Why bothering?");
debug_assert!(self.data.is_some(), "How exactly?"); debug_assert!(self.data.is_some(), "How exactly?");
@ -155,7 +191,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
let snapshot = wrapper.snapshot().expect("has_snapshot lied"); let snapshot = wrapper.snapshot().expect("has_snapshot lied");
if !snapshot.has_attrs() && state_changes.is_empty() { if !snapshot.has_attrs() && state_changes.is_empty() {
return; return InvalidationResult::empty();
} }
// If we are sensitive to visitedness and the visited state changed, we // If we are sensitive to visitedness and the visited state changed, we
@ -252,8 +288,10 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
debug!("Collected invalidations (self: {}): ", invalidated_self); debug!("Collected invalidations (self: {}): ", invalidated_self);
debug!(" > descendants: {:?}", descendant_invalidations); debug!(" > descendants: {:?}", descendant_invalidations);
debug!(" > siblings: {:?}", sibling_invalidations); debug!(" > siblings: {:?}", sibling_invalidations);
self.invalidate_descendants(&descendant_invalidations); let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations);
self.invalidate_siblings(&mut sibling_invalidations); let invalidated_siblings = self.invalidate_siblings(&mut sibling_invalidations);
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
@ -585,7 +623,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
descendant_invalidations: &mut InvalidationVector, descendant_invalidations: &mut InvalidationVector,
sibling_invalidations: &mut InvalidationVector, sibling_invalidations: &mut InvalidationVector,
invalidation_kind: InvalidationKind, invalidation_kind: InvalidationKind,
) -> InvalidationResult { ) -> SingleInvalidationResult {
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})", debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
self.element, invalidation, invalidation_kind); self.element, invalidation, invalidation_kind);
@ -759,7 +797,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
} }
} }
InvalidationResult { invalidated_self, matched, } SingleInvalidationResult { invalidated_self, matched, }
} }
} }

View file

@ -3719,6 +3719,17 @@ pub extern "C" fn Servo_ProcessInvalidations(set: RawServoStyleSetBorrowed,
let mut data = data.as_mut().map(|d| &mut **d); let mut data = data.as_mut().map(|d| &mut **d);
if let Some(ref mut data) = data { if let Some(ref mut data) = data {
data.invalidate_style_if_needed(element, &shared_style_context, None); let result = data.invalidate_style_if_needed(element, &shared_style_context, None);
if result.has_invalidated_siblings() {
let parent = element.traversal_parent().expect("How could we invalidate siblings without a common parent?");
unsafe {
parent.set_dirty_descendants();
bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
}
} else if result.has_invalidated_descendants() {
unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
} else if result.has_invalidated_self() {
unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
}
} }
} }