diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index a9b175ab060..b8a38247fd7 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -450,6 +450,10 @@ impl<'le> TElement for ServoLayoutElement<'le> { fn update_animations(&self, _pseudo: Option<&PseudoElement>) { panic!("this should be only called on gecko"); } + + fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool { + panic!("this should be only called on gecko"); + } } impl<'le> PartialEq for ServoLayoutElement<'le> { diff --git a/components/style/dom.rs b/components/style/dom.rs index ebd60ee6c91..d4f8d979309 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -339,6 +339,9 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// Creates a task to update CSS Animations on a given (pseudo-)element. /// Note: Gecko only. fn update_animations(&self, _pseudo: Option<&PseudoElement>); + + /// Returns true if the element has a CSS animation. + fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool; } /// TNode and TElement aren't Send because we want to be careful and explicit diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 7ddd5938f74..4c3fd1e9b76 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -29,6 +29,7 @@ use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement, Gecko_MatchesE use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace}; use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags}; use gecko_bindings::bindings::Gecko_ClassOrClassList; +use gecko_bindings::bindings::Gecko_ElementHasCSSAnimations; use gecko_bindings::bindings::Gecko_GetAnimationRule; use gecko_bindings::bindings::Gecko_GetHTMLPresentationAttrDeclarationBlock; use gecko_bindings::bindings::Gecko_GetStyleAttrDeclarationBlock; @@ -526,6 +527,11 @@ impl<'le> TElement for GeckoElement<'le> { parent_values_opt); } } + + fn has_css_animations(&self, pseudo: Option<&PseudoElement>) -> bool { + let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo); + unsafe { Gecko_ElementHasCSSAnimations(self.0, atom_ptr) } + } } impl<'le> PartialEq for GeckoElement<'le> { diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 417a15ab5d9..2079ad8aa20 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -549,6 +549,11 @@ extern "C" { aParentComputedValues: ServoComputedValuesBorrowedOrNull); } +extern "C" { + pub fn Gecko_ElementHasCSSAnimations(aElement: RawGeckoElementBorrowed, + aPseudoTagOrNull: *mut nsIAtom) + -> bool; +} extern "C" { pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32) -> *mut nsIAtom; diff --git a/components/style/matching.rs b/components/style/matching.rs index 3b8ff1dad0a..b8d6d567338 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -605,21 +605,21 @@ trait PrivateMatchMethods: TElement { let ref new_box_style = new_values.get_box(); let has_new_animation_style = new_box_style.animation_name_count() >= 1 && new_box_style.animation_name_at(0).0.len() != 0; + let has_animations = self.has_css_animations(pseudo); + let needs_update_animations = old_values.as_ref().map_or(has_new_animation_style, |ref old| { let ref old_box_style = old.get_box(); let old_display_style = old_box_style.clone_display(); let new_display_style = new_box_style.clone_display(); - // FIXME: If we know that the element has no running CSS animations, - // we can also skip the case with checking no_animations. - // // FIXME: Bug 1344581: We still need to compare keyframe rules. !old_box_style.animations_equals(&new_box_style) || (old_display_style == display::T::none && new_display_style != display::T::none && has_new_animation_style) || (old_display_style != display::T::none && - new_display_style == display::T::none) + new_display_style == display::T::none && + has_animations) }); if needs_update_animations { let task = SequentialTask::update_animations(self.as_node().as_element().unwrap(),