mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #17834 - emilio:animation-fc-crash, r=heycam
stylo: Fix the interaction of frame construction restyles with animation restyles. Fixes bug 1383001.
This commit is contained in:
commit
30d6d6024b
5 changed files with 37 additions and 53 deletions
|
@ -298,22 +298,16 @@ impl ElementData {
|
||||||
self.styles.primary.is_some()
|
self.styles.primary.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether we have any outstanding style invalidation.
|
|
||||||
pub fn has_invalidations(&self) -> bool {
|
|
||||||
self.restyle.hint.has_self_invalidations()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the kind of restyling that we're going to need to do on this
|
/// Returns the kind of restyling that we're going to need to do on this
|
||||||
/// element, based of the stored restyle hint.
|
/// element, based of the stored restyle hint.
|
||||||
pub fn restyle_kind(&self,
|
pub fn restyle_kind(
|
||||||
shared_context: &SharedStyleContext)
|
&self,
|
||||||
-> RestyleKind {
|
shared_context: &SharedStyleContext
|
||||||
|
) -> RestyleKind {
|
||||||
if shared_context.traversal_flags.for_animation_only() {
|
if shared_context.traversal_flags.for_animation_only() {
|
||||||
return self.restyle_kind_for_animation(shared_context);
|
return self.restyle_kind_for_animation(shared_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(!self.has_styles() || self.has_invalidations(),
|
|
||||||
"Should've stopped earlier");
|
|
||||||
if !self.has_styles() {
|
if !self.has_styles() {
|
||||||
return RestyleKind::MatchAndCascade;
|
return RestyleKind::MatchAndCascade;
|
||||||
}
|
}
|
||||||
|
@ -335,9 +329,10 @@ impl ElementData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the kind of restyling for animation-only restyle.
|
/// Returns the kind of restyling for animation-only restyle.
|
||||||
pub fn restyle_kind_for_animation(&self,
|
fn restyle_kind_for_animation(
|
||||||
shared_context: &SharedStyleContext)
|
&self,
|
||||||
-> RestyleKind {
|
shared_context: &SharedStyleContext,
|
||||||
|
) -> RestyleKind {
|
||||||
debug_assert!(shared_context.traversal_flags.for_animation_only());
|
debug_assert!(shared_context.traversal_flags.for_animation_only());
|
||||||
debug_assert!(self.has_styles(),
|
debug_assert!(self.has_styles(),
|
||||||
"Unstyled element shouldn't be traversed during \
|
"Unstyled element shouldn't be traversed during \
|
||||||
|
@ -350,8 +345,8 @@ impl ElementData {
|
||||||
if hint.has_animation_hint() {
|
if hint.has_animation_hint() {
|
||||||
return RestyleKind::CascadeWithReplacements(hint & RestyleHint::for_animations());
|
return RestyleKind::CascadeWithReplacements(hint & RestyleHint::for_animations());
|
||||||
}
|
}
|
||||||
return RestyleKind::CascadeOnly;
|
|
||||||
|
|
||||||
|
return RestyleKind::CascadeOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if important rules are different.
|
/// Return true if important rules are different.
|
||||||
|
@ -362,9 +357,11 @@ impl ElementData {
|
||||||
/// the check which properties do they want.
|
/// the check which properties do they want.
|
||||||
/// If it costs too much, get_properties_overriding_animations() should return a set
|
/// If it costs too much, get_properties_overriding_animations() should return a set
|
||||||
/// containing only opacity and transform properties.
|
/// containing only opacity and transform properties.
|
||||||
pub fn important_rules_are_different(&self,
|
pub fn important_rules_are_different(
|
||||||
rules: &StrongRuleNode,
|
&self,
|
||||||
guards: &StylesheetGuards) -> bool {
|
rules: &StrongRuleNode,
|
||||||
|
guards: &StylesheetGuards
|
||||||
|
) -> bool {
|
||||||
debug_assert!(self.has_styles());
|
debug_assert!(self.has_styles());
|
||||||
let (important_rules, _custom) =
|
let (important_rules, _custom) =
|
||||||
self.styles.primary().rules().get_properties_overriding_animations(&guards);
|
self.styles.primary().rules().get_properties_overriding_animations(&guards);
|
||||||
|
|
|
@ -470,19 +470,12 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
||||||
/// Flags this element as having handled already its snapshot.
|
/// Flags this element as having handled already its snapshot.
|
||||||
unsafe fn set_handled_snapshot(&self);
|
unsafe fn set_handled_snapshot(&self);
|
||||||
|
|
||||||
/// Returns whether the element's styles are up-to-date.
|
|
||||||
fn has_current_styles(&self, data: &ElementData) -> bool {
|
|
||||||
if self.has_snapshot() && !self.handled_snapshot() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.has_styles() && !data.has_invalidations()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the element's styles are up-to-date for |traversal_flags|.
|
/// Returns whether the element's styles are up-to-date for |traversal_flags|.
|
||||||
fn has_current_styles_for_traversal(&self,
|
fn has_current_styles_for_traversal(
|
||||||
data: &ElementData,
|
&self,
|
||||||
traversal_flags: TraversalFlags) -> bool {
|
data: &ElementData,
|
||||||
|
traversal_flags: TraversalFlags,
|
||||||
|
) -> bool {
|
||||||
if traversal_flags.for_animation_only() {
|
if traversal_flags.for_animation_only() {
|
||||||
// In animation-only restyle we never touch snapshots and don't
|
// In animation-only restyle we never touch snapshots and don't
|
||||||
// care about them. But we can't assert '!self.handled_snapshot()'
|
// care about them. But we can't assert '!self.handled_snapshot()'
|
||||||
|
@ -499,7 +492,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.has_styles() && !data.has_invalidations()
|
data.has_styles() && !data.restyle.hint.has_non_animation_hint()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flags an element and its ancestors with a given `DescendantsBit`.
|
/// Flags an element and its ancestors with a given `DescendantsBit`.
|
||||||
|
|
|
@ -52,17 +52,7 @@ where
|
||||||
{
|
{
|
||||||
let parent_el = element.inheritance_parent();
|
let parent_el = element.inheritance_parent();
|
||||||
let parent_data = parent_el.as_ref().and_then(|e| e.borrow_data());
|
let parent_data = parent_el.as_ref().and_then(|e| e.borrow_data());
|
||||||
let parent_style = parent_data.as_ref().map(|d| {
|
let parent_style = parent_data.as_ref().map(|d| d.styles.primary());
|
||||||
// Sometimes Gecko eagerly styles things without processing
|
|
||||||
// pending restyles first. In general we'd like to avoid this,
|
|
||||||
// but there can be good reasons (for example, needing to
|
|
||||||
// construct a frame for some small piece of newly-added
|
|
||||||
// content in order to do something specific with that frame,
|
|
||||||
// but not wanting to flush all of layout).
|
|
||||||
debug_assert!(cfg!(feature = "gecko") ||
|
|
||||||
parent_el.unwrap().has_current_styles(d));
|
|
||||||
d.styles.primary()
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut layout_parent_el = parent_el.clone();
|
let mut layout_parent_el = parent_el.clone();
|
||||||
let layout_parent_data;
|
let layout_parent_data;
|
||||||
|
|
|
@ -374,9 +374,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
parent: E,
|
parent: E,
|
||||||
parent_data: &ElementData,
|
parent_data: &ElementData,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// See the comment on `cascade_node` for why we allow this on Gecko.
|
|
||||||
debug_assert!(cfg!(feature = "gecko") ||
|
debug_assert!(cfg!(feature = "gecko") ||
|
||||||
parent.has_current_styles(parent_data));
|
parent.has_current_styles_for_traversal(parent_data, context.shared.traversal_flags));
|
||||||
|
|
||||||
// If the parent computed display:none, we don't style the subtree.
|
// If the parent computed display:none, we don't style the subtree.
|
||||||
if parent_data.styles.is_display_none() {
|
if parent_data.styles.is_display_none() {
|
||||||
|
|
|
@ -275,21 +275,26 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
||||||
(Root::Normal, Restyle::ForThrottledAnimationFlush)
|
(Root::Normal, Restyle::ForThrottledAnimationFlush)
|
||||||
=> TraversalFlags::empty(),
|
=> TraversalFlags::empty(),
|
||||||
(Root::UnstyledChildrenOnly, Restyle::Normal) |
|
(Root::UnstyledChildrenOnly, Restyle::Normal) |
|
||||||
(Root::UnstyledChildrenOnly, Restyle::ForNewlyBoundElement) |
|
(Root::UnstyledChildrenOnly, Restyle::ForNewlyBoundElement)
|
||||||
(Root::UnstyledChildrenOnly, Restyle::ForThrottledAnimationFlush)
|
|
||||||
=> UNSTYLED_CHILDREN_ONLY,
|
=> UNSTYLED_CHILDREN_ONLY,
|
||||||
(Root::Normal, Restyle::ForCSSRuleChanges) => FOR_CSS_RULE_CHANGES,
|
(Root::Normal, Restyle::ForCSSRuleChanges) => FOR_CSS_RULE_CHANGES,
|
||||||
(Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT,
|
(Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT,
|
||||||
_ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"),
|
_ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let needs_animation_only_restyle = element.has_animation_only_dirty_descendants() ||
|
// It makes no sense to do an animation restyle when we're restyling
|
||||||
element.has_animation_restyle_hints();
|
// newly-inserted content.
|
||||||
if needs_animation_only_restyle {
|
if !traversal_flags.contains(UNSTYLED_CHILDREN_ONLY) {
|
||||||
traverse_subtree(element,
|
let needs_animation_only_restyle =
|
||||||
raw_data,
|
element.has_animation_only_dirty_descendants() ||
|
||||||
traversal_flags | ANIMATION_ONLY,
|
element.has_animation_restyle_hints();
|
||||||
unsafe { &*snapshots });
|
|
||||||
|
if needs_animation_only_restyle {
|
||||||
|
traverse_subtree(element,
|
||||||
|
raw_data,
|
||||||
|
traversal_flags | ANIMATION_ONLY,
|
||||||
|
unsafe { &*snapshots });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if restyle_behavior == Restyle::ForThrottledAnimationFlush {
|
if restyle_behavior == Restyle::ForThrottledAnimationFlush {
|
||||||
|
@ -2814,7 +2819,7 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
|
||||||
TraversalFlags::empty()
|
TraversalFlags::empty()
|
||||||
};
|
};
|
||||||
debug_assert!(element.has_current_styles_for_traversal(&*data, flags),
|
debug_assert!(element.has_current_styles_for_traversal(&*data, flags),
|
||||||
"Resolving style on element without current styles");
|
"Resolving style on {:?} without current styles: {:?}", element, data);
|
||||||
data.styles.primary().clone().into()
|
data.styles.primary().clone().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue