servo: Merge #16850 - Merge keyframes at the same offset (from hiikezoe:merge-keyframe); r=birtles,SimonSapin

This is a PR for https://bugzilla.mozilla.org/show_bug.cgi?id=1354947 .
---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors

- [X] These changes do not require tests because it's for stylo

Source-Repo: https://github.com/servo/servo
Source-Revision: c5e31def29c62d885468f33cdc13446036b39bd8

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : c1d4968c42c51bbb6a4012ef7cafbff2728e8e94
This commit is contained in:
Hiroyuki Ikezoe 2017-05-13 14:05:40 -05:00
Родитель fc81f181c7
Коммит b8f09b427c
5 изменённых файлов: 1069 добавлений и 1066 удалений

Просмотреть файл

@ -991,11 +991,25 @@ extern "C" {
src: *mut nsStyleDisplay);
}
extern "C" {
pub fn Gecko_AnimationAppendKeyframe(keyframes:
RawGeckoKeyframeListBorrowedMut,
offset: f32,
timingFunction:
*const nsTimingFunction)
pub fn Gecko_GetOrCreateKeyframeAtStart(keyframes:
RawGeckoKeyframeListBorrowedMut,
offset: f32,
timingFunction:
*const nsTimingFunction)
-> *mut Keyframe;
}
extern "C" {
pub fn Gecko_GetOrCreateInitialKeyframe(keyframes:
RawGeckoKeyframeListBorrowedMut,
timingFunction:
*const nsTimingFunction)
-> *mut Keyframe;
}
extern "C" {
pub fn Gecko_GetOrCreateFinalKeyframe(keyframes:
RawGeckoKeyframeListBorrowedMut,
timingFunction:
*const nsTimingFunction)
-> *mut Keyframe;
}
extern "C" {
@ -1669,14 +1683,14 @@ extern "C" {
author_style_disabled: bool);
}
extern "C" {
pub fn Servo_StyleSet_FillKeyframesForName(set: RawServoStyleSetBorrowed,
property: *const nsACString,
timing_function:
nsTimingFunctionBorrowed,
computed_values:
ServoComputedValuesBorrowed,
keyframe_list:
RawGeckoKeyframeListBorrowedMut)
pub fn Servo_StyleSet_GetKeyframesForName(set: RawServoStyleSetBorrowed,
property: *const nsACString,
timing_function:
nsTimingFunctionBorrowed,
computed_values:
ServoComputedValuesBorrowed,
keyframe_list:
RawGeckoKeyframeListBorrowedMut)
-> bool;
}
extern "C" {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -251,6 +251,14 @@ impl LonghandIdSet {
self.storage[bit / 32] &= !(1 << (bit % 32));
}
/// Clear all bits
#[inline]
pub fn clear(&mut self) {
for cell in &mut self.storage {
*cell = 0
}
}
/// Set the corresponding bit of TransitionProperty.
/// This function will panic if TransitionProperty::All is given.
pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) {

Просмотреть файл

@ -40,7 +40,9 @@ use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedVal
use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed};
use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
use style::gecko_bindings::bindings::{nsACString, nsAString};
use style::gecko_bindings::bindings::Gecko_AnimationAppendKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
use style::gecko_bindings::bindings::RawGeckoAnimationPropertySegmentBorrowed;
use style::gecko_bindings::bindings::RawGeckoComputedKeyframeValuesListBorrowedMut;
use style::gecko_bindings::bindings::RawGeckoComputedTimingBorrowed;
@ -75,7 +77,7 @@ use style::media_queries::{MediaList, parse_media_query_list};
use style::parallel;
use style::parser::{LengthParsingMode, ParserContext};
use style::properties::{CascadeFlags, ComputedValues, Importance, ParsedDeclaration, StyleBuilder};
use style::properties::{PropertyDeclarationBlock, PropertyId};
use style::properties::{LonghandIdSet, PropertyDeclarationBlock, PropertyId};
use style::properties::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
use style::properties::animated_properties::{Animatable, AnimationValue, TransitionProperty};
use style::properties::parse_one_declaration;
@ -2186,73 +2188,154 @@ pub extern "C" fn Servo_AssertTreeIsClean(root: RawGeckoElementBorrowed) {
assert_subtree_is_clean(root);
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSetBorrowed,
name: *const nsACString,
timing_function: nsTimingFunctionBorrowed,
style: ServoComputedValuesBorrowed,
keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
use style::gecko_bindings::structs::Keyframe;
use style::properties::LonghandIdSet;
fn append_computed_property_value(keyframe: *mut structs::Keyframe,
style: &ComputedValues,
property: &TransitionProperty,
shared_lock: &SharedRwLock) {
let block = style.to_declaration_block(property.clone().into());
unsafe {
let index = (*keyframe).mPropertyValues.len();
(*keyframe).mPropertyValues.set_len((index + 1) as u32);
(*keyframe).mPropertyValues[index].mProperty = property.into();
// FIXME. Bug 1360398: Do not set computed values once we handles
// missing keyframes with additive composition.
(*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky(
Arc::new(shared_lock.wrap(block)));
}
}
fn fill_in_missing_keyframe_values(all_properties: &[TransitionProperty],
timing_function: nsTimingFunctionBorrowed,
style: &ComputedValues,
properties_set_at_offset: &LonghandIdSet,
offset: f32,
keyframes: RawGeckoKeyframeListBorrowedMut,
shared_lock: &SharedRwLock) {
debug_assert!(offset == 0. || offset == 1.,
"offset should be 0. or 1.");
let needs_filling = all_properties.iter().any(|ref property| {
!properties_set_at_offset.has_transition_property_bit(property)
});
// Return earli if all animated properties are already set.
if !needs_filling {
return;
}
let keyframe = match offset {
0. => unsafe {
Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function)
},
1. => unsafe {
Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function)
},
_ => unreachable!("offset should be 0. or 1."),
};
// Append properties that have not been set at this offset.
for ref property in all_properties.iter() {
if !properties_set_at_offset.has_transition_property_bit(property) {
append_computed_property_value(keyframe,
style,
property,
shared_lock);
}
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_GetKeyframesForName(raw_data: RawServoStyleSetBorrowed,
name: *const nsACString,
inherited_timing_function: nsTimingFunctionBorrowed,
style: ServoComputedValuesBorrowed,
keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
debug_assert!(keyframes.len() == 0,
"keyframes should be initially empty");
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) };
let animation = match data.stylist.animations().get(&name) {
Some(animation) => animation,
None => return false,
};
let style = ComputedValues::as_arc(&style);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
if let Some(ref animation) = data.stylist.animations().get(&name) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
for step in &animation.steps {
// Override timing_function if the keyframe has animation-timing-function.
let timing_function = if let Some(val) = step.get_animation_timing_function(&guard) {
val.into()
} else {
*timing_function
};
let mut properties_set_at_current_offset = LonghandIdSet::new();
let mut properties_set_at_start = LonghandIdSet::new();
let mut properties_set_at_end = LonghandIdSet::new();
let mut has_complete_initial_keyframe = false;
let mut has_complete_final_keyframe = false;
let mut current_offset = -1.;
let keyframe = unsafe {
Gecko_AnimationAppendKeyframe(keyframes,
step.start_percentage.0 as f32,
&timing_function)
};
// Iterate over the keyframe rules backwards so we can drop overridden
// properties (since declarations in later rules override those in earlier
// ones).
for step in animation.steps.iter().rev() {
if step.start_percentage.0 != current_offset {
properties_set_at_current_offset.clear();
current_offset = step.start_percentage.0;
}
fn add_computed_property_value(keyframe: *mut Keyframe,
index: usize,
style: &ComputedValues,
property: &TransitionProperty,
shared_lock: &SharedRwLock) {
let block = style.to_declaration_block(property.clone().into());
unsafe {
(*keyframe).mPropertyValues.set_len((index + 1) as u32);
(*keyframe).mPropertyValues[index].mProperty = property.into();
// FIXME. Do not set computed values once we handles missing keyframes
// with additive composition.
(*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky(
Arc::new(shared_lock.wrap(block)));
// Override timing_function if the keyframe has an animation-timing-function.
let timing_function = match step.get_animation_timing_function(&guard) {
Some(val) => val.into(),
None => *inherited_timing_function,
};
// Look for an existing keyframe with the same offset and timing
// function or else add a new keyframe at the beginning of the keyframe
// array.
let keyframe = unsafe {
Gecko_GetOrCreateKeyframeAtStart(keyframes,
step.start_percentage.0 as f32,
&timing_function)
};
match step.value {
KeyframesStepValue::ComputedValues => {
// In KeyframesAnimation::from_keyframes if there is no 0% or
// 100% keyframe at all, we will create a 'ComputedValues' step
// to represent that all properties animated by the keyframes
// animation should be set to the underlying computed value for
// that keyframe.
for property in animation.properties_changed.iter() {
append_computed_property_value(keyframe,
style,
property,
&global_style_data.shared_lock);
}
}
if current_offset == 0.0 {
has_complete_initial_keyframe = true;
} else if current_offset == 1.0 {
has_complete_final_keyframe = true;
}
},
KeyframesStepValue::Declarations { ref block } => {
let guard = block.read_with(&guard);
// Filter out non-animatable properties.
let animatable =
guard.declarations()
.iter()
.filter(|&&(ref declaration, _)| {
declaration.is_animatable()
});
match step.value {
KeyframesStepValue::ComputedValues => {
for (index, property) in animation.properties_changed.iter().enumerate() {
add_computed_property_value(
keyframe, index, style, property, &global_style_data.shared_lock);
}
},
KeyframesStepValue::Declarations { ref block } => {
let guard = block.read_with(&guard);
// Filter out non-animatable properties.
let animatable =
guard.declarations()
.iter()
.filter(|&&(ref declaration, _)| {
declaration.is_animatable()
});
let mut index = unsafe { (*keyframe).mPropertyValues.len() };
for &(ref declaration, _) in animatable {
let property = TransitionProperty::from_declaration(declaration).unwrap();
if !properties_set_at_current_offset.has_transition_property_bit(&property) {
properties_set_at_current_offset.set_transition_property_bit(&property);
if current_offset == 0.0 {
properties_set_at_start.set_transition_property_bit(&property);
} else if current_offset == 1.0 {
properties_set_at_end.set_transition_property_bit(&property);
}
let mut seen = LonghandIdSet::new();
for (index, &(ref declaration, _)) in animatable.enumerate() {
unsafe {
let property = TransitionProperty::from_declaration(declaration).unwrap();
(*keyframe).mPropertyValues.set_len((index + 1) as u32);
@ -2262,31 +2345,34 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
PropertyDeclarationBlock::with_one(
declaration.clone(), Importance::Normal
))));
if step.start_percentage.0 == 0. ||
step.start_percentage.0 == 1. {
seen.set_transition_property_bit(&property);
}
}
index += 1;
}
// Append missing property values in the initial or the finial keyframes.
if step.start_percentage.0 == 0. ||
step.start_percentage.0 == 1. {
let mut index = unsafe { (*keyframe).mPropertyValues.len() };
for property in animation.properties_changed.iter() {
if !seen.has_transition_property_bit(&property) {
add_computed_property_value(
keyframe, index, style, property, &global_style_data.shared_lock);
index += 1;
}
}
}
},
}
}
},
}
return true
}
false
// Append property values that are missing in the initial or the final keyframes.
if !has_complete_initial_keyframe {
fill_in_missing_keyframe_values(&animation.properties_changed,
inherited_timing_function,
style,
&properties_set_at_start,
0.,
keyframes,
&global_style_data.shared_lock);
}
if !has_complete_final_keyframe {
fill_in_missing_keyframe_values(&animation.properties_changed,
inherited_timing_function,
style,
&properties_set_at_end,
1.,
keyframes,
&global_style_data.shared_lock);
}
true
}
#[no_mangle]