From 1b39041a8cd407d3edb9d436b02c19ccabd35002 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Wed, 27 Sep 2017 12:50:03 +0900 Subject: [PATCH] Factor custom properties in keyframes into compute values in each keyframe --- .../style/properties/declaration_block.rs | 54 +++++++++++++++---- .../helpers/animated_properties.mako.rs | 13 +++-- ports/geckolib/glue.rs | 39 ++++++++++++-- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index 231972396bc..25cb0991626 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -151,16 +151,21 @@ pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> { iter: DeclarationImportanceIterator<'a>, context: &'cx mut Context<'cx_a>, default_values: &'a ComputedValues, + /// Custom properties in a keyframe if exists. + extra_custom_properties: &'a Option>, } impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> { fn new(declarations: &'a PropertyDeclarationBlock, context: &'cx mut Context<'cx_a>, - default_values: &'a ComputedValues) -> AnimationValueIterator<'a, 'cx, 'cx_a> { + default_values: &'a ComputedValues, + extra_custom_properties: &'a Option>, + ) -> AnimationValueIterator<'a, 'cx, 'cx_a> { AnimationValueIterator { iter: declarations.declaration_importance_iter(), - context: context, - default_values: default_values, + context, + default_values, + extra_custom_properties, } } } @@ -175,8 +180,12 @@ impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> { Some((decl, importance)) => { if importance == Importance::Normal { let property = AnimatableLonghand::from_declaration(decl); - let animation = AnimationValue::from_declaration(decl, &mut self.context, - self.default_values); + let animation = AnimationValue::from_declaration( + decl, + &mut self.context, + self.extra_custom_properties, + self.default_values + ); debug_assert!(property.is_none() == animation.is_none(), "The failure condition of AnimatableLonghand::from_declaration \ and AnimationValue::from_declaration should be the same"); @@ -248,11 +257,13 @@ impl PropertyDeclarationBlock { } /// Return an iterator of (AnimatableLonghand, AnimationValue). - pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>(&'a self, - context: &'cx mut Context<'cx_a>, - default_values: &'a ComputedValues) - -> AnimationValueIterator<'a, 'cx, 'cx_a> { - AnimationValueIterator::new(self, context, default_values) + pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>( + &'a self, + context: &'cx mut Context<'cx_a>, + default_values: &'a ComputedValues, + extra_custom_properties: &'a Option>, + ) -> AnimationValueIterator<'a, 'cx, 'cx_a> { + AnimationValueIterator::new(self, context, default_values, extra_custom_properties) } /// Returns whether this block contains any declaration with `!important`. @@ -652,6 +663,29 @@ impl PropertyDeclarationBlock { decl.get_css_wide_keyword().is_some() ) } + + /// Returns a custom properties map which is the result of cascading custom + /// properties in this declaration block along with context's custom + /// properties. + pub fn cascade_custom_properties_with_context( + &self, + context: &Context, + ) -> Option> { + let inherited_custom_properties = context.style().custom_properties(); + let mut custom_properties = None; + // FIXME: Use PrecomputedHasher instead. + let mut seen_custom = HashSet::new(); + + for declaration in self.normal_declaration_iter() { + if let PropertyDeclaration::Custom(ref name, ref value) = *declaration { + ::custom_properties::cascade( + &mut custom_properties, &inherited_custom_properties, + &mut seen_custom, name, value.borrow()); + } + } + ::custom_properties::finish_cascade( + custom_properties, &inherited_custom_properties) + } } impl ToCss for PropertyDeclarationBlock { diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 5f98b7e5c0a..6c6b07238e5 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -26,6 +26,7 @@ use properties::longhands::visibility::computed_value::T as Visibility; #[cfg(feature = "gecko")] use properties::{PropertyId, PropertyDeclarationId, LonghandId}; #[cfg(feature = "gecko")] use properties::{ShorthandId}; use selectors::parser::SelectorParseError; +use servo_arc::Arc; use smallvec::SmallVec; use std::borrow::Cow; use std::cmp; @@ -568,6 +569,7 @@ impl AnimationValue { pub fn from_declaration( decl: &PropertyDeclaration, context: &mut Context, + extra_custom_properties: &Option>, initial: &ComputedValues ) -> Option { use properties::LonghandId; @@ -641,9 +643,14 @@ impl AnimationValue { } }, PropertyDeclaration::WithVariables(id, ref unparsed) => { - let custom_props = context.style().custom_properties(); - let substituted = unparsed.substitute_variables(id, &custom_props, context.quirks_mode); - AnimationValue::from_declaration(&substituted, context, initial) + let substituted = if extra_custom_properties.is_some() { + unparsed.substitute_variables( + id, &extra_custom_properties, context.quirks_mode) + } else { + unparsed.substitute_variables( + id, &context.style().custom_properties(), context.quirks_mode) + }; + AnimationValue::from_declaration(&substituted, context, extra_custom_properties, initial) }, _ => None // non animatable properties will get included because of shorthands. ignore. } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 69ea011a979..f49258a5cd3 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -3342,7 +3342,23 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis let guard = global_style_data.shared_lock.read(); let default_values = data.default_computed_values(); + let mut raw_custom_properties_block; // To make the raw block alive in the scope. for (index, keyframe) in keyframes.iter().enumerate() { + let mut custom_properties = None; + for property in keyframe.mPropertyValues.iter() { + // Find the block for custom properties first. + if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable { + raw_custom_properties_block = unsafe { + &*property.mServoDeclarationBlock.mRawPtr.clone() + }; + let guard = Locked::::as_arc( + &raw_custom_properties_block).read_with(&guard); + custom_properties = guard.cascade_custom_properties_with_context(&context); + // There should be one PropertyDeclarationBlock for custom properties. + break; + } + } + let ref mut animation_values = computed_keyframes[index]; let mut seen = LonghandIdSet::new(); @@ -3393,8 +3409,13 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() }; let declarations = Locked::::as_arc(&declarations); let guard = declarations.read_with(&guard); + let iter = guard.to_animation_value_iter( + &mut context, + &default_values, + &custom_properties, + ); - for anim in guard.to_animation_value_iter(&mut context, &default_values) { + for anim in iter { maybe_append_animation_value(anim.0, Some(anim.1)); } } @@ -3433,7 +3454,13 @@ pub extern "C" fn Servo_GetAnimationValues(declarations: RawServoDeclarationBloc let declarations = Locked::::as_arc(&declarations); let guard = declarations.read_with(&guard); - for (index, anim) in guard.to_animation_value_iter(&mut context, &default_values).enumerate() { + let no_extra_custom_properties = None; // SMIL has no extra custom properties. + let iter = guard.to_animation_value_iter( + &mut context, + &default_values, + &no_extra_custom_properties, + ); + for (index, anim) in iter.enumerate() { unsafe { animation_values.set_len((index + 1) as u32) }; animation_values[index].set_arc_leaky(Arc::new(anim.1)); } @@ -3472,7 +3499,13 @@ pub extern "C" fn Servo_AnimationValue_Compute(element: RawGeckoElementBorrowed, // We only compute the first element in declarations. match declarations.read_with(&guard).declaration_importance_iter().next() { Some((decl, imp)) if imp == Importance::Normal => { - let animation = AnimationValue::from_declaration(decl, &mut context, default_values); + let no_extra_custom_properties = None; // No extra custom properties for devtools. + let animation = AnimationValue::from_declaration( + decl, + &mut context, + &no_extra_custom_properties, + default_values, + ); animation.map_or(RawServoAnimationValueStrong::null(), |value| { Arc::new(value).into_strong() })