diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 872cf913d9f..adf47842e82 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -451,10 +451,6 @@ impl<'le> TElement for ServoLayoutElement<'le> { self.element.has_selector_flags(flags) } - fn update_animations(&self, _pseudo: Option<&PseudoElement>) { - panic!("this should be only called on gecko"); - } - fn has_animations(&self, _pseudo: Option<&PseudoElement>) -> bool { panic!("this should be only called on gecko"); } diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index b485efa48ee..39a7afeb44e 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -282,7 +282,8 @@ mod bindings { .raw_line("use data::ElementData;") .hide_type("nsString") .bitfield_enum("nsChangeHint") - .bitfield_enum("nsRestyleHint"); + .bitfield_enum("nsRestyleHint") + .constified_enum("UpdateAnimationsTasks"); let whitelist_vars = [ "NS_THEME_.*", "NODE_.*", @@ -306,6 +307,7 @@ mod bindings { "mozilla::TraversalRootBehavior", "mozilla::StyleShapeRadius", "mozilla::StyleGrid.*", + "mozilla::UpdateAnimationsTasks", "mozilla::LookAndFeel", ".*ThreadSafe.*Holder", "AnonymousContent", @@ -667,6 +669,7 @@ mod bindings { "Loader", "ServoStyleSheet", "EffectCompositor_CascadeLevel", + "UpdateAnimationsTasks", ]; struct ArrayType { cpp_type: &'static str, diff --git a/components/style/context.rs b/components/style/context.rs index 27943243ddf..c0ded1483ce 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -12,9 +12,10 @@ use data::ElementData; use dom::{OpaqueNode, TNode, TElement, SendElement}; use error_reporting::ParseErrorReporter; use euclid::Size2D; +#[cfg(feature = "gecko")] use gecko_bindings::structs; use matching::StyleSharingCandidateCache; use parking_lot::RwLock; -use selector_parser::PseudoElement; +#[cfg(feature = "gecko")] use selector_parser::PseudoElement; use selectors::matching::ElementSelectorFlags; use servo_config::opts; use shared_lock::StylesheetGuards; @@ -194,6 +195,22 @@ impl TraversalStatistics { } } +#[cfg(feature = "gecko")] +bitflags! { + /// Represents which tasks are performed in a SequentialTask of UpdateAnimations. + pub flags UpdateAnimationsTasks: u8 { + /// Update CSS Animations. + const CSS_ANIMATIONS = structs::UpdateAnimationsTasks_CSSAnimations, + /// Update CSS Transitions. + const CSS_TRANSITIONS = structs::UpdateAnimationsTasks_CSSTransitions, + /// Update effect properties. + const EFFECT_PROPERTIES = structs::UpdateAnimationsTasks_EffectProperties, + /// Update animation cacade results for animations running on the compositor. + const CASCADE_RESULTS = structs::UpdateAnimationsTasks_CascadeResults, + } +} + + /// A task to be run in sequential mode on the parent (non-worker) thread. This /// is used by the style system to queue up work which is not safe to do during /// the parallel traversal. @@ -202,9 +219,10 @@ pub enum SequentialTask { /// element that we don't have exclusive access to (i.e. the parent). SetSelectorFlags(SendElement, ElementSelectorFlags), - /// Marks that we need to create/remove/update CSS animations after the - /// first traversal. - UpdateAnimations(SendElement, Option), + #[cfg(feature = "gecko")] + /// Marks that we need to update CSS animations, update effect properties of + /// any type of animations after the normal traversal. + UpdateAnimations(SendElement, Option, UpdateAnimationsTasks), } impl SequentialTask { @@ -216,8 +234,9 @@ impl SequentialTask { SetSelectorFlags(el, flags) => { unsafe { el.set_selector_flags(flags) }; } - UpdateAnimations(el, pseudo) => { - unsafe { el.update_animations(pseudo.as_ref()) }; + #[cfg(feature = "gecko")] + UpdateAnimations(el, pseudo, tasks) => { + unsafe { el.update_animations(pseudo.as_ref(), tasks) }; } } } @@ -228,10 +247,12 @@ impl SequentialTask { SetSelectorFlags(unsafe { SendElement::new(el) }, flags) } - /// Creates a task to update CSS Animations on a given (pseudo-)element. - pub fn update_animations(el: E, pseudo: Option) -> Self { + #[cfg(feature = "gecko")] + /// Creates a task to update various animation state on a given (pseudo-)element. + pub fn update_animations(el: E, pseudo: Option, + tasks: UpdateAnimationsTasks) -> Self { use self::SequentialTask::*; - UpdateAnimations(unsafe { SendElement::new(el) }, pseudo) + UpdateAnimations(unsafe { SendElement::new(el) }, pseudo, tasks) } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 4301c1d3b8e..9d25013b15e 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -9,6 +9,7 @@ use {Atom, Namespace, LocalName}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; +#[cfg(feature = "gecko")] use context::UpdateAnimationsTasks; use data::ElementData; use element_state::ElementState; use properties::{ComputedValues, PropertyDeclarationBlock}; @@ -366,9 +367,10 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// Returns true if the element has all the specified selector flags. fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool; - /// Creates a task to update CSS Animations on a given (pseudo-)element. - /// Note: Gecko only. - fn update_animations(&self, _pseudo: Option<&PseudoElement>); + /// Creates a task to update various animation state on a given (pseudo-)element. + #[cfg(feature = "gecko")] + fn update_animations(&self, _pseudo: Option<&PseudoElement>, + tasks: UpdateAnimationsTasks); /// Returns true if the element has relevant animations. Relevant /// animations are those animations that are affecting the element's style diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index ab58dd53fa1..fe11fb7ff10 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -15,6 +15,7 @@ //! the separation between the style system implementation and everything else. use atomic_refcell::AtomicRefCell; +use context::UpdateAnimationsTasks; use data::ElementData; use dom::{AnimationRules, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthetizer}; @@ -555,7 +556,8 @@ impl<'le> TElement for GeckoElement<'le> { (self.flags() & node_flags) == node_flags } - fn update_animations(&self, pseudo: Option<&PseudoElement>) { + fn update_animations(&self, pseudo: Option<&PseudoElement>, + tasks: UpdateAnimationsTasks) { // We have to update animations even if the element has no computed style // since it means the element is in a display:none subtree, we should destroy // all CSS animations in display:none subtree. @@ -584,7 +586,8 @@ impl<'le> TElement for GeckoElement<'le> { unsafe { Gecko_UpdateAnimations(self.0, atom_ptr, computed_values_opt, - parent_values_opt); + parent_values_opt, + tasks.bits()); } } diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index ee9da0172d9..dd5196defa6 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -176,6 +176,7 @@ use gecko_bindings::structs::nsresult; use gecko_bindings::structs::Loader; use gecko_bindings::structs::ServoStyleSheet; use gecko_bindings::structs::EffectCompositor_CascadeLevel; +use gecko_bindings::structs::UpdateAnimationsTasks; pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray; pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong; pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules; @@ -610,7 +611,8 @@ extern "C" { aComputedValues: ServoComputedValuesBorrowedOrNull, aParentComputedValues: - ServoComputedValuesBorrowedOrNull); + ServoComputedValuesBorrowedOrNull, + aTaskBits: UpdateAnimationsTasks); } extern "C" { pub fn Gecko_ElementHasAnimations(aElement: RawGeckoElementBorrowed, diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs index 1e0a925355e..8e9f8e850f1 100644 --- a/components/style/gecko_bindings/structs_debug.rs +++ b/components/style/gecko_bindings/structs_debug.rs @@ -6151,6 +6151,19 @@ pub mod root { Normal = 0, UnstyledChildrenOnly = 1, } + pub const UpdateAnimationsTasks_CSSAnimations: + root::mozilla::UpdateAnimationsTasks = + 1; + pub const UpdateAnimationsTasks_CSSTransitions: + root::mozilla::UpdateAnimationsTasks = + 2; + pub const UpdateAnimationsTasks_EffectProperties: + root::mozilla::UpdateAnimationsTasks = + 4; + pub const UpdateAnimationsTasks_CascadeResults: + root::mozilla::UpdateAnimationsTasks = + 8; + pub type UpdateAnimationsTasks = u8; pub type CSSPseudoElementTypeBase = u8; pub const CSSPseudoElementType_InheritingAnonBox: root::mozilla::CSSPseudoElementType = diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs index f24f1bacda9..4d1e510b6f7 100644 --- a/components/style/gecko_bindings/structs_release.rs +++ b/components/style/gecko_bindings/structs_release.rs @@ -6066,6 +6066,19 @@ pub mod root { Normal = 0, UnstyledChildrenOnly = 1, } + pub const UpdateAnimationsTasks_CSSAnimations: + root::mozilla::UpdateAnimationsTasks = + 1; + pub const UpdateAnimationsTasks_CSSTransitions: + root::mozilla::UpdateAnimationsTasks = + 2; + pub const UpdateAnimationsTasks_EffectProperties: + root::mozilla::UpdateAnimationsTasks = + 4; + pub const UpdateAnimationsTasks_CascadeResults: + root::mozilla::UpdateAnimationsTasks = + 8; + pub type UpdateAnimationsTasks = u8; pub type CSSPseudoElementTypeBase = u8; pub const CSSPseudoElementType_InheritingAnonBox: root::mozilla::CSSPseudoElementType = diff --git a/components/style/matching.rs b/components/style/matching.rs index c0eb82d9086..edf97c044f9 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -638,11 +638,15 @@ trait PrivateMatchMethods: TElement { new_values: &mut Arc, pseudo: Option<&PseudoElement>, _possibly_expired_animations: &mut Vec) { + use context::CSS_ANIMATIONS; + use context::UpdateAnimationsTasks; + 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 mut tasks = UpdateAnimationsTasks::empty(); let needs_update_animations = old_values.as_ref().map_or(has_new_animation_style, |ref old| { let ref old_box_style = old.get_box(); @@ -658,8 +662,12 @@ trait PrivateMatchMethods: TElement { has_animations) }); if needs_update_animations { + tasks.insert(CSS_ANIMATIONS); + } + if !tasks.is_empty() { let task = SequentialTask::update_animations(self.as_node().as_element().unwrap(), - pseudo.cloned()); + pseudo.cloned(), + tasks); context.thread_local.tasks.push(task); } }