Factor custom properties in keyframes into compute values in each keyframe

This commit is contained in:
Hiroyuki Ikezoe 2017-09-27 12:50:03 +09:00
parent ded0c713db
commit 1b39041a8c
3 changed files with 90 additions and 16 deletions

View file

@ -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<Arc<::custom_properties::CustomPropertiesMap>>,
}
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<Arc<::custom_properties::CustomPropertiesMap>>,
) -> 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<Arc<::custom_properties::CustomPropertiesMap>>,
) -> 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<Arc<::custom_properties::CustomPropertiesMap>> {
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 {

View file

@ -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<Arc<::custom_properties::CustomPropertiesMap>>,
initial: &ComputedValues
) -> Option<Self> {
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.
}

View file

@ -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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::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::<PropertyDeclarationBlock>::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()
})