mirror of
https://github.com/servo/servo.git
synced 2025-06-19 06:38:59 +01:00
Add Servo_ComposeAnimationSegment which composes an animation segment.
This commit is contained in:
parent
1f5551c397
commit
52c81a0a84
2 changed files with 185 additions and 114 deletions
|
@ -2776,9 +2776,22 @@ extern "C" {
|
|||
RawGeckoAnimationPropertySegmentBorrowed,
|
||||
computed_timing:
|
||||
RawGeckoComputedTimingBorrowed,
|
||||
iteration_composite:
|
||||
iter_composite:
|
||||
IterationCompositeOperation);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_ComposeAnimationSegment(animation_segment:
|
||||
RawGeckoAnimationPropertySegmentBorrowed,
|
||||
underlying_value:
|
||||
RawServoAnimationValueBorrowedOrNull,
|
||||
last_value:
|
||||
RawServoAnimationValueBorrowedOrNull,
|
||||
iter_composite:
|
||||
IterationCompositeOperation,
|
||||
progress: f64,
|
||||
current_iteration: u64)
|
||||
-> RawServoAnimationValueStrong;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_DeclarationBlock_PropertyIsSet(declarations:
|
||||
RawServoDeclarationBlockBorrowed,
|
||||
|
|
|
@ -67,6 +67,7 @@ use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowed;
|
|||
use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowedMut;
|
||||
use style::gecko_bindings::bindings::RawGeckoServoStyleRuleListBorrowedMut;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueBorrowedOrNull;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueMapBorrowedMut;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueStrong;
|
||||
use style::gecko_bindings::bindings::RawServoAnimationValueTableBorrowed;
|
||||
|
@ -411,6 +412,157 @@ pub extern "C" fn Servo_AnimationValues_ComputeDistance(from: RawServoAnimationV
|
|||
from_value.compute_squared_distance(to_value).map(|d| d.sqrt()).unwrap_or(-1.0)
|
||||
}
|
||||
|
||||
/// Compute one of the endpoints for the interpolation interval, compositing it with the
|
||||
/// underlying value if needed.
|
||||
/// An None returned value means, "Just use endpoint_value as-is."
|
||||
/// It is the responsibility of the caller to ensure that |underlying_value| is provided
|
||||
/// when it will be used.
|
||||
fn composite_endpoint(
|
||||
endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
|
||||
composite: CompositeOperation,
|
||||
underlying_value: Option<&AnimationValue>,
|
||||
) -> Option<AnimationValue> {
|
||||
match endpoint_value {
|
||||
Some(endpoint_value) => {
|
||||
match composite {
|
||||
CompositeOperation::Add => {
|
||||
underlying_value
|
||||
.expect("We should have an underlying_value")
|
||||
.animate(endpoint_value, Procedure::Add).ok()
|
||||
},
|
||||
CompositeOperation::Accumulate => {
|
||||
underlying_value
|
||||
.expect("We should have an underlying value")
|
||||
.animate(endpoint_value, Procedure::Accumulate { count: 1 })
|
||||
.ok()
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
None => underlying_value.map(|v| v.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Accumulate one of the endpoints of the animation interval.
|
||||
/// A returned value of None means, "Just use endpoint_value as-is."
|
||||
fn accumulate_endpoint(
|
||||
endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
|
||||
composited_value: Option<AnimationValue>,
|
||||
last_value: &AnimationValue,
|
||||
current_iteration: u64
|
||||
) -> Option<AnimationValue> {
|
||||
debug_assert!(endpoint_value.is_some() || composited_value.is_some(),
|
||||
"Should have a suitable value to use");
|
||||
|
||||
let count = current_iteration;
|
||||
match composited_value {
|
||||
Some(endpoint) => {
|
||||
last_value
|
||||
.animate(&endpoint, Procedure::Accumulate { count })
|
||||
.ok()
|
||||
.or(Some(endpoint))
|
||||
},
|
||||
None => {
|
||||
last_value
|
||||
.animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
|
||||
.ok()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Compose the animation segment. We composite it with the underlying_value and last_value if
|
||||
/// needed.
|
||||
/// The caller is responsible for providing an underlying value and last value
|
||||
/// in all situations where there are needed.
|
||||
fn compose_animation_segment(
|
||||
segment: RawGeckoAnimationPropertySegmentBorrowed,
|
||||
underlying_value: Option<&AnimationValue>,
|
||||
last_value: Option<&AnimationValue>,
|
||||
iteration_composite: IterationCompositeOperation,
|
||||
current_iteration: u64,
|
||||
total_progress: f64,
|
||||
segment_progress: f64,
|
||||
) -> AnimationValue {
|
||||
// Extract keyframe values.
|
||||
let raw_from_value;
|
||||
let keyframe_from_value = if !segment.mFromValue.mServo.mRawPtr.is_null() {
|
||||
raw_from_value = unsafe { &*segment.mFromValue.mServo.mRawPtr };
|
||||
Some(AnimationValue::as_arc(&raw_from_value))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let raw_to_value;
|
||||
let keyframe_to_value = if !segment.mToValue.mServo.mRawPtr.is_null() {
|
||||
raw_to_value = unsafe { &*segment.mToValue.mServo.mRawPtr };
|
||||
Some(AnimationValue::as_arc(&raw_to_value))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut composited_from_value = composite_endpoint(keyframe_from_value,
|
||||
segment.mFromComposite,
|
||||
underlying_value);
|
||||
let mut composited_to_value = composite_endpoint(keyframe_to_value,
|
||||
segment.mToComposite,
|
||||
underlying_value);
|
||||
|
||||
debug_assert!(keyframe_from_value.is_some() || composited_from_value.is_some(),
|
||||
"Should have a suitable from value to use");
|
||||
debug_assert!(keyframe_to_value.is_some() || composited_to_value.is_some(),
|
||||
"Should have a suitable to value to use");
|
||||
|
||||
// Apply iteration composite behavior.
|
||||
if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
|
||||
let last_value = last_value.unwrap_or_else(|| {
|
||||
underlying_value.expect("Should have a valid underlying value")
|
||||
});
|
||||
|
||||
composited_from_value = accumulate_endpoint(keyframe_from_value,
|
||||
composited_from_value,
|
||||
last_value,
|
||||
current_iteration);
|
||||
composited_to_value = accumulate_endpoint(keyframe_to_value,
|
||||
composited_to_value,
|
||||
last_value,
|
||||
current_iteration);
|
||||
}
|
||||
|
||||
// Use the composited value if there is one, otherwise, use the original keyframe value.
|
||||
let from = composited_from_value.as_ref().unwrap_or_else(|| keyframe_from_value.unwrap());
|
||||
let to = composited_to_value.as_ref().unwrap_or_else(|| keyframe_to_value.unwrap());
|
||||
|
||||
if segment.mToKey == segment.mFromKey {
|
||||
return if total_progress < 0. { from.clone() } else { to.clone() };
|
||||
}
|
||||
|
||||
match from.animate(to, Procedure::Interpolate { progress: segment_progress }) {
|
||||
Ok(value) => value,
|
||||
_ => if segment_progress < 0.5 { from.clone() } else { to.clone() },
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_ComposeAnimationSegment(
|
||||
segment: RawGeckoAnimationPropertySegmentBorrowed,
|
||||
underlying_value: RawServoAnimationValueBorrowedOrNull,
|
||||
last_value: RawServoAnimationValueBorrowedOrNull,
|
||||
iteration_composite: IterationCompositeOperation,
|
||||
progress: f64,
|
||||
current_iteration: u64
|
||||
) -> RawServoAnimationValueStrong {
|
||||
let underlying_value = AnimationValue::arc_from_borrowed(&underlying_value).map(|v| &**v);
|
||||
let last_value = AnimationValue::arc_from_borrowed(&last_value).map(|v| &**v);
|
||||
let result = compose_animation_segment(segment,
|
||||
underlying_value,
|
||||
last_value,
|
||||
iteration_composite,
|
||||
current_iteration,
|
||||
progress,
|
||||
progress);
|
||||
Arc::new(result).into_strong()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_AnimationCompose(raw_value_map: RawServoAnimationValueMapBorrowedMut,
|
||||
base_values: RawServoAnimationValueTableBorrowed,
|
||||
|
@ -461,125 +613,31 @@ pub extern "C" fn Servo_AnimationCompose(raw_value_map: RawServoAnimationValueMa
|
|||
return;
|
||||
}
|
||||
|
||||
// Extract keyframe values.
|
||||
let raw_from_value;
|
||||
let keyframe_from_value = if !segment.mFromValue.mServo.mRawPtr.is_null() {
|
||||
raw_from_value = unsafe { &*segment.mFromValue.mServo.mRawPtr };
|
||||
Some(AnimationValue::as_arc(&raw_from_value))
|
||||
let raw_last_value;
|
||||
let last_value = if !last_segment.mToValue.mServo.mRawPtr.is_null() {
|
||||
raw_last_value = unsafe { &*last_segment.mToValue.mServo.mRawPtr };
|
||||
Some(&**AnimationValue::as_arc(&raw_last_value))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let raw_to_value;
|
||||
let keyframe_to_value = if !segment.mToValue.mServo.mRawPtr.is_null() {
|
||||
raw_to_value = unsafe { &*segment.mToValue.mServo.mRawPtr };
|
||||
Some(AnimationValue::as_arc(&raw_to_value))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Composite with underlying value.
|
||||
// A return value of None means, "Just use keyframe_value as-is."
|
||||
let composite_endpoint = |keyframe_value: Option<&RawOffsetArc<AnimationValue>>,
|
||||
composite_op: CompositeOperation| -> Option<AnimationValue> {
|
||||
match keyframe_value {
|
||||
Some(keyframe_value) => {
|
||||
match composite_op {
|
||||
CompositeOperation::Add => {
|
||||
debug_assert!(need_underlying_value,
|
||||
"Should have detected we need an underlying value");
|
||||
underlying_value.as_ref().unwrap().animate(keyframe_value, Procedure::Add).ok()
|
||||
},
|
||||
CompositeOperation::Accumulate => {
|
||||
debug_assert!(need_underlying_value,
|
||||
"Should have detected we need an underlying value");
|
||||
underlying_value
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.animate(keyframe_value, Procedure::Accumulate { count: 1 })
|
||||
.ok()
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
None => {
|
||||
debug_assert!(need_underlying_value,
|
||||
"Should have detected we need an underlying value");
|
||||
underlying_value.clone()
|
||||
},
|
||||
}
|
||||
};
|
||||
let mut composited_from_value = composite_endpoint(keyframe_from_value, segment.mFromComposite);
|
||||
let mut composited_to_value = composite_endpoint(keyframe_to_value, segment.mToComposite);
|
||||
|
||||
debug_assert!(keyframe_from_value.is_some() || composited_from_value.is_some(),
|
||||
"Should have a suitable from value to use");
|
||||
debug_assert!(keyframe_to_value.is_some() || composited_to_value.is_some(),
|
||||
"Should have a suitable to value to use");
|
||||
|
||||
// Apply iteration composite behavior.
|
||||
if iteration_composite == IterationCompositeOperation::Accumulate &&
|
||||
computed_timing.mCurrentIteration > 0 {
|
||||
let raw_last_value;
|
||||
let last_value = if !last_segment.mToValue.mServo.mRawPtr.is_null() {
|
||||
raw_last_value = unsafe { &*last_segment.mToValue.mServo.mRawPtr };
|
||||
&*AnimationValue::as_arc(&raw_last_value)
|
||||
} else {
|
||||
debug_assert!(need_underlying_value,
|
||||
"Should have detected we need an underlying value");
|
||||
underlying_value.as_ref().unwrap()
|
||||
};
|
||||
|
||||
// As with composite_endpoint, a return value of None means, "Use keyframe_value as-is."
|
||||
let apply_iteration_composite = |keyframe_value: Option<&RawOffsetArc<AnimationValue>>,
|
||||
composited_value: Option<AnimationValue>|
|
||||
-> Option<AnimationValue> {
|
||||
let count = computed_timing.mCurrentIteration;
|
||||
match composited_value {
|
||||
Some(endpoint) => {
|
||||
last_value
|
||||
.animate(&endpoint, Procedure::Accumulate { count })
|
||||
.ok()
|
||||
.or(Some(endpoint))
|
||||
},
|
||||
None => {
|
||||
last_value
|
||||
.animate(keyframe_value.unwrap(), Procedure::Accumulate { count })
|
||||
.ok()
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
composited_from_value = apply_iteration_composite(keyframe_from_value,
|
||||
composited_from_value);
|
||||
composited_to_value = apply_iteration_composite(keyframe_to_value,
|
||||
composited_to_value);
|
||||
}
|
||||
|
||||
// Use the composited value if there is one, otherwise, use the original keyframe value.
|
||||
let from_value = composited_from_value.as_ref().unwrap_or_else(|| keyframe_from_value.unwrap());
|
||||
let to_value = composited_to_value.as_ref().unwrap_or_else(|| keyframe_to_value.unwrap());
|
||||
|
||||
let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
|
||||
if segment.mToKey == segment.mFromKey {
|
||||
if progress < 0. {
|
||||
value_map.insert(property, from_value.clone());
|
||||
} else {
|
||||
value_map.insert(property, to_value.clone());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let pos = unsafe {
|
||||
Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag)
|
||||
};
|
||||
if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress: pos }) {
|
||||
value_map.insert(property, value);
|
||||
} else if pos < 0.5 {
|
||||
value_map.insert(property, from_value.clone());
|
||||
let position = if segment.mToKey == segment.mFromKey {
|
||||
// Note: compose_animation_segment doesn't use this value
|
||||
// if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
|
||||
progress
|
||||
} else {
|
||||
value_map.insert(property, to_value.clone());
|
||||
}
|
||||
unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
|
||||
};
|
||||
|
||||
let result = compose_animation_segment(segment,
|
||||
underlying_value.as_ref(),
|
||||
last_value,
|
||||
iteration_composite,
|
||||
computed_timing.mCurrentIteration,
|
||||
progress,
|
||||
position);
|
||||
value_map.insert(property, result);
|
||||
}
|
||||
|
||||
macro_rules! get_property_id_from_nscsspropertyid {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue