diff --git a/servo/components/style/build_gecko.rs b/servo/components/style/build_gecko.rs index 2ca2d7348632..e3708c184592 100644 --- a/servo/components/style/build_gecko.rs +++ b/servo/components/style/build_gecko.rs @@ -491,6 +491,7 @@ mod bindings { "RawGeckoNode", "RawGeckoAnimationValueList", "RawServoAnimationValue", + "RawServoAnimationValueList", "RawGeckoPresContext", "RawGeckoPresContextOwned", "ThreadSafeURIHolder", @@ -593,6 +594,7 @@ mod bindings { let servo_borrow_types = [ "nsCSSValue", "RawGeckoAnimationValueList", + "RawServoAnimationValueList", ]; for &ty in structs_types.iter() { builder = builder.hide_type(ty) diff --git a/servo/components/style/dom.rs b/servo/components/style/dom.rs index 90eacdf22bde..8a023e764c3e 100644 --- a/servo/components/style/dom.rs +++ b/servo/components/style/dom.rs @@ -227,6 +227,11 @@ pub trait PresentationalHintsSynthetizer { where V: Push; } +/// The animation rules. The first one is for Animation cascade level, and the second one is for +/// Transition cascade level. +pub struct AnimationRules(pub Option>>, + pub Option>>); + /// The element trait, the main abstraction the style crate acts over. pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { /// The concrete node type. @@ -248,6 +253,11 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// Get this element's style attribute. fn style_attribute(&self) -> Option<&Arc>>; + /// Get this element's animation rules. + fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules { + AnimationRules(None, None) + } + /// Get this element's state, for non-tree-structural pseudos. fn get_state(&self) -> ElementState; diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs index 8b74844590bc..6456bfea90cb 100644 --- a/servo/components/style/gecko/wrapper.rs +++ b/servo/components/style/gecko/wrapper.rs @@ -16,7 +16,7 @@ use atomic_refcell::AtomicRefCell; use data::ElementData; -use dom::{LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; +use dom::{AnimationRules, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::StdoutErrorReporter; @@ -30,10 +30,12 @@ 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_GetAnimationRule; use gecko_bindings::bindings::Gecko_GetStyleContext; use gecko_bindings::structs; use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode}; use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext}; +use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel; use gecko_bindings::structs::NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO; use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE; use parking_lot::RwLock; @@ -335,6 +337,15 @@ impl<'le> TElement for GeckoElement<'le> { declarations.map(|s| s.as_arc_opt()).unwrap_or(None) } + fn get_animation_rules(&self, pseudo: Option<&PseudoElement>) -> AnimationRules { + let atom_ptr = pseudo.map(|p| p.as_atom().as_ptr()).unwrap_or(ptr::null_mut()); + unsafe { + AnimationRules( + Gecko_GetAnimationRule(self.0, atom_ptr, CascadeLevel::Animations).into_arc_opt(), + Gecko_GetAnimationRule(self.0, atom_ptr, CascadeLevel::Transitions).into_arc_opt()) + } + } + fn get_state(&self) -> ElementState { unsafe { ElementState::from_bits_truncate(Gecko_ElementState(self.0)) diff --git a/servo/components/style/gecko_bindings/bindings.rs b/servo/components/style/gecko_bindings/bindings.rs index 16bfaf40fff5..2c13323bd831 100644 --- a/servo/components/style/gecko_bindings/bindings.rs +++ b/servo/components/style/gecko_bindings/bindings.rs @@ -3,11 +3,13 @@ pub use nsstring::{nsACString, nsAString}; type nsACString_internal = nsACString; type nsAString_internal = nsAString; +use gecko_bindings::structs::EffectCompositor_CascadeLevel; use gecko_bindings::structs::RawGeckoDocument; use gecko_bindings::structs::RawGeckoElement; use gecko_bindings::structs::RawGeckoNode; use gecko_bindings::structs::RawGeckoAnimationValueList; use gecko_bindings::structs::RawServoAnimationValue; +use gecko_bindings::structs::RawServoAnimationValueBorrowedList; use gecko_bindings::structs::RawGeckoPresContext; use gecko_bindings::structs::RawGeckoPresContextOwned; use gecko_bindings::structs::ThreadSafeURIHolder; @@ -224,6 +226,8 @@ pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>; pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList; pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>; +pub type RawServoAnimationValueBorrowedListBorrowed<'a> = &'a RawServoAnimationValueBorrowedList; +pub type RawServoAnimationValueBorrowedListBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueBorrowedList>; extern "C" { pub fn Gecko_EnsureTArrayCapacity(aArray: *mut ::std::os::raw::c_void, @@ -498,6 +502,12 @@ extern "C" { pub fn Gecko_GetServoDeclarationBlock(element: RawGeckoElementBorrowed) -> RawServoDeclarationBlockStrongBorrowedOrNull; } +extern "C" { + pub fn Gecko_GetAnimationRule(element: RawGeckoElementBorrowed, + aAtom: *mut nsIAtom, + aCascadeLevel: EffectCompositor_CascadeLevel) + -> RawServoDeclarationBlockStrong; +} extern "C" { pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32) -> *mut nsIAtom; @@ -1217,6 +1227,16 @@ extern "C" { ServoComputedValuesBorrowed) -> ServoComputedValuesStrong; } +extern "C" { + pub fn Servo_AnimationValues_Interpolate(from: RawServoAnimationValueBorrowed, + to: RawServoAnimationValueBorrowed, + progress: f64) + -> RawServoAnimationValueStrong; +} +extern "C" { + pub fn Servo_AnimationValues_Uncompute(value: RawServoAnimationValueBorrowedListBorrowed) + -> RawServoDeclarationBlockStrong; +} extern "C" { pub fn Servo_AnimationValues_Populate(arg1: RawGeckoAnimationValueListBorrowedMut, diff --git a/servo/components/style/gecko_bindings/structs_debug.rs b/servo/components/style/gecko_bindings/structs_debug.rs index 21113f4bca94..7b5df8fb80bf 100644 --- a/servo/components/style/gecko_bindings/structs_debug.rs +++ b/servo/components/style/gecko_bindings/structs_debug.rs @@ -5273,6 +5273,12 @@ pub mod root { impl Clone for StyleComplexColor { fn clone(&self) -> Self { *self } } + #[repr(u32)] + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub enum EffectCompositor_CascadeLevel { + Animations = 0, + Transitions = 1, + } #[repr(C)] #[derive(Debug)] pub struct PropertyStyleAnimationValuePair { @@ -17953,6 +17959,10 @@ pub mod root { pub type RawGeckoPresContextBorrowedMut = *mut root::RawGeckoPresContext; pub type RawGeckoAnimationValueListBorrowedMut = *mut root::RawGeckoAnimationValueList; + pub type RawServoAnimationValueBorrowedList = + root::nsTArray<*const root::RawServoAnimationValue>; + pub type RawServoAnimationValueBorrowedListBorrowed = + *const root::RawServoAnimationValueBorrowedList; #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum nsCSSTokenSerializationType { diff --git a/servo/components/style/gecko_bindings/structs_release.rs b/servo/components/style/gecko_bindings/structs_release.rs index ef9d9638d431..6a0d4927d07a 100644 --- a/servo/components/style/gecko_bindings/structs_release.rs +++ b/servo/components/style/gecko_bindings/structs_release.rs @@ -5191,6 +5191,12 @@ pub mod root { impl Clone for StyleComplexColor { fn clone(&self) -> Self { *self } } + #[repr(u32)] + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub enum EffectCompositor_CascadeLevel { + Animations = 0, + Transitions = 1, + } #[repr(C)] #[derive(Debug)] pub struct PropertyStyleAnimationValuePair { @@ -17726,6 +17732,10 @@ pub mod root { pub type RawGeckoPresContextBorrowedMut = *mut root::RawGeckoPresContext; pub type RawGeckoAnimationValueListBorrowedMut = *mut root::RawGeckoAnimationValueList; + pub type RawServoAnimationValueBorrowedList = + root::nsTArray<*const root::RawServoAnimationValue>; + pub type RawServoAnimationValueBorrowedListBorrowed = + *const root::RawServoAnimationValueBorrowedList; #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum nsCSSTokenSerializationType { diff --git a/servo/components/style/matching.rs b/servo/components/style/matching.rs index 63165927a8a5..11c1a85b382b 100644 --- a/servo/components/style/matching.rs +++ b/servo/components/style/matching.rs @@ -589,12 +589,14 @@ pub trait MatchMethods : TElement { let mut applicable_declarations: Vec = Vec::with_capacity(16); let stylist = &context.shared.stylist; let style_attribute = self.style_attribute(); + let animation_rules = self.get_animation_rules(None); // Compute the primary rule node. let mut primary_relations = stylist.push_applicable_declarations(self, parent_bf, style_attribute, + animation_rules, None, &mut applicable_declarations, MatchingReason::ForStyling); @@ -604,7 +606,9 @@ pub trait MatchMethods : TElement { let mut per_pseudo: PseudoRuleNodes = HashMap::with_hasher(Default::default()); SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| { debug_assert!(applicable_declarations.is_empty()); + let pseudo_animation_rules = self.get_animation_rules(Some(&pseudo)); stylist.push_applicable_declarations(self, parent_bf, None, + pseudo_animation_rules, Some(&pseudo.clone()), &mut applicable_declarations, MatchingReason::ForStyling); diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs index 27ffea363d1f..4d8e3eb32f90 100644 --- a/servo/components/style/stylist.rs +++ b/servo/components/style/stylist.rs @@ -8,7 +8,7 @@ use {Atom, LocalName}; use data::ComputedStyle; -use dom::{PresentationalHintsSynthetizer, TElement}; +use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement}; use error_reporting::StdoutErrorReporter; use keyframes::KeyframesAnimation; use media_queries::Device; @@ -21,6 +21,7 @@ use rule_tree::{RuleTree, StrongRuleNode, StyleSource}; use selector_parser::{ElementExt, SelectorImpl, PseudoElement, Snapshot}; use selectors::Element; use selectors::bloom::BloomFilter; +use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS}; use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS}; use selectors::matching::{MatchingReason, StyleRelations, matches_complex_selector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; @@ -386,6 +387,7 @@ impl Stylist { self.push_applicable_declarations(element, None, None, + AnimationRules(None, None), Some(pseudo), &mut declarations, MatchingReason::ForStyling); @@ -490,6 +492,7 @@ impl Stylist { element: &E, parent_bf: Option<&BloomFilter>, style_attribute: Option<&Arc>>, + animation_rules: AnimationRules, pseudo_element: Option<&PseudoElement>, applicable_declarations: &mut V, reason: MatchingReason) -> StyleRelations @@ -560,7 +563,18 @@ impl Stylist { debug!("style attr: {:?}", relations); - // Step 5: Author-supplied `!important` rules. + // Step 5: Animations. + // The animations sheet (CSS animations, script-generated animations, + // and CSS transitions that are no longer tied to CSS markup) + if let Some(anim) = animation_rules.0 { + relations |= AFFECTED_BY_ANIMATIONS; + Push::push( + applicable_declarations, + ApplicableDeclarationBlock::from_declarations(anim.clone(), Importance::Normal)); + } + debug!("animation: {:?}", relations); + + // Step 6: Author-supplied `!important` rules. map.author.get_all_matching_rules(element, parent_bf, applicable_declarations, @@ -570,7 +584,7 @@ impl Stylist { debug!("author important: {:?}", relations); - // Step 6: `!important` style attributes. + // Step 7: `!important` style attributes. if let Some(sa) = style_attribute { if sa.read().any_important() { relations |= AFFECTED_BY_STYLE_ATTRIBUTE; @@ -582,7 +596,7 @@ impl Stylist { debug!("style attr important: {:?}", relations); - // Step 7: User `!important` rules. + // Step 8: User `!important` rules. map.user.get_all_matching_rules(element, parent_bf, applicable_declarations, @@ -595,7 +609,7 @@ impl Stylist { debug!("skipping non-agent rules"); } - // Step 8: UA `!important` rules. + // Step 9: UA `!important` rules. map.user_agent.get_all_matching_rules(element, parent_bf, applicable_declarations, @@ -605,6 +619,16 @@ impl Stylist { debug!("UA important: {:?}", relations); + // Step 10: Transitions. + // The transitions sheet (CSS transitions that are tied to CSS markup) + if let Some(anim) = animation_rules.1 { + relations |= AFFECTED_BY_TRANSITIONS; + Push::push( + applicable_declarations, + ApplicableDeclarationBlock::from_declarations(anim.clone(), Importance::Normal)); + } + debug!("transition: {:?}", relations); + debug!("push_applicable_declarations: shareable: {:?}", relations); relations diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index bcf393bb4a0e..b487abe941f0 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -39,6 +39,8 @@ use style::gecko_bindings::bindings::RawGeckoAnimationValueListBorrowedMut; use style::gecko_bindings::bindings::RawGeckoElementBorrowed; use style::gecko_bindings::bindings::RawGeckoPresContextBorrowed; use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed; +use style::gecko_bindings::bindings::RawServoAnimationValueBorrowedListBorrowed; +use style::gecko_bindings::bindings::RawServoAnimationValueStrong; use style::gecko_bindings::bindings::RawServoImportRuleBorrowed; use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull; use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t; @@ -58,7 +60,7 @@ use style::parser::{ParserContext, ParserContextExtraData}; use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration}; use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock, PropertyId}; use style::properties::{apply_declarations, parse_one_declaration}; -use style::properties::animated_properties::AnimationValue; +use style::properties::animated_properties::{AnimationValue, Interpolate}; use style::restyle_hints::RestyleHint; use style::selector_parser::PseudoElementCascadeType; use style::sequential; @@ -165,6 +167,39 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed, behavior == structs::TraversalRootBehavior::UnstyledChildrenOnly); } +#[no_mangle] +pub extern "C" fn Servo_AnimationValues_Interpolate(from: RawServoAnimationValueBorrowed, + to: RawServoAnimationValueBorrowed, + progress: f64) + -> RawServoAnimationValueStrong +{ + let from_value = AnimationValue::as_arc(&from); + let to_value = AnimationValue::as_arc(&to); + if let Ok(value) = from_value.interpolate(to_value, progress) { + Arc::new(value).into_strong() + } else { + RawServoAnimationValueStrong::null() + } +} + +#[no_mangle] +pub extern "C" fn Servo_AnimationValues_Uncompute(value: RawServoAnimationValueBorrowedListBorrowed) + -> RawServoDeclarationBlockStrong +{ + let uncomputed_values = value.into_iter() + .map(|v| { + let raw_anim = unsafe { v.as_ref().unwrap() }; + let anim = AnimationValue::as_arc(&raw_anim); + (anim.uncompute(), Importance::Normal) + }) + .collect(); + + Arc::new(RwLock::new(PropertyDeclarationBlock { + declarations: uncomputed_values, + important_count: 0, + })).into_strong() +} + /// Takes a ServoAnimationValues and populates it with the animation values corresponding /// to a given property declaration block #[no_mangle]