mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
style: Implement the even more forgiving interpolation rules for transform lists.
As discussed in: https://github.com/w3c/csswg-drafts/issues/927 with tentative spec text: https://github.com/w3c/csswg-drafts/pull/3215 Differential Revision: https://phabricator.services.mozilla.com/D9185
This commit is contained in:
parent
e5da0ebd1d
commit
fc59165ff3
1 changed files with 103 additions and 70 deletions
|
@ -1356,11 +1356,11 @@ fn is_matched_operation(first: &ComputedTransformOperation, second: &ComputedTra
|
||||||
&TransformOperation::RotateZ(..)) |
|
&TransformOperation::RotateZ(..)) |
|
||||||
(&TransformOperation::Perspective(..),
|
(&TransformOperation::Perspective(..),
|
||||||
&TransformOperation::Perspective(..)) => true,
|
&TransformOperation::Perspective(..)) => true,
|
||||||
// we animate scale and translate operations against each other
|
// Match functions that have the same primitive transform function
|
||||||
(a, b) if a.is_translate() && b.is_translate() => true,
|
(a, b) if a.is_translate() && b.is_translate() => true,
|
||||||
(a, b) if a.is_scale() && b.is_scale() => true,
|
(a, b) if a.is_scale() && b.is_scale() => true,
|
||||||
(a, b) if a.is_rotate() && b.is_rotate() => true,
|
(a, b) if a.is_rotate() && b.is_rotate() => true,
|
||||||
// InterpolateMatrix and AccumulateMatrix are for mismatched transform.
|
// InterpolateMatrix and AccumulateMatrix are for mismatched transforms
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2468,79 +2468,112 @@ impl Animate for ComputedTransform {
|
||||||
return Ok(Transform(result));
|
return Ok(Transform(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-transforms-1/#transform-transform-neutral-extend-animation
|
let this = Cow::Borrowed(&self.0);
|
||||||
fn match_operations_if_possible<'a>(
|
let other = Cow::Borrowed(&other.0);
|
||||||
this: &mut Cow<'a, Vec<ComputedTransformOperation>>,
|
|
||||||
other: &mut Cow<'a, Vec<ComputedTransformOperation>>,
|
|
||||||
) -> bool {
|
|
||||||
if !this.iter().zip(other.iter()).all(|(this, other)| is_matched_operation(this, other)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if this.len() == other.len() {
|
// Interpolate the common prefix
|
||||||
return true;
|
let mut result = this
|
||||||
}
|
.iter()
|
||||||
|
.zip(other.iter())
|
||||||
|
.take_while(|(this, other)| is_matched_operation(this, other))
|
||||||
|
.map(|(this, other)| this.animate(other, procedure))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let (shorter, longer) =
|
// Deal with the remainders
|
||||||
if this.len() < other.len() {
|
let this_remainder = if this.len() > result.len() {
|
||||||
(this.to_mut(), other)
|
Some(&this[result.len()..])
|
||||||
} else {
|
} else {
|
||||||
(other.to_mut(), this)
|
None
|
||||||
};
|
};
|
||||||
|
let other_remainder = if other.len() > result.len() {
|
||||||
|
Some(&other[result.len()..])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
shorter.reserve(longer.len());
|
match (this_remainder, other_remainder) {
|
||||||
for op in longer.iter().skip(shorter.len()) {
|
// If there is a remainder from *both* lists we must have had mismatched functions.
|
||||||
shorter.push(op.to_animated_zero().unwrap());
|
// => Add the remainders to a suitable ___Matrix function.
|
||||||
}
|
(Some(this_remainder), Some(other_remainder)) => match procedure {
|
||||||
|
Procedure::Add => {
|
||||||
// The resulting operations won't be matched regardless if the
|
debug_assert!(false, "Should have already dealt with add by the point");
|
||||||
// extended component is already InterpolateMatrix /
|
return Err(());
|
||||||
// AccumulateMatrix.
|
}
|
||||||
//
|
Procedure::Interpolate { progress } => {
|
||||||
// Otherwise they should be matching operations all the time.
|
result.push(TransformOperation::InterpolateMatrix {
|
||||||
let already_mismatched = matches!(
|
from_list: Transform(this_remainder.to_vec()),
|
||||||
longer[0],
|
to_list: Transform(other_remainder.to_vec()),
|
||||||
TransformOperation::InterpolateMatrix { .. } |
|
progress: Percentage(progress as f32),
|
||||||
TransformOperation::AccumulateMatrix { .. }
|
});
|
||||||
);
|
}
|
||||||
|
Procedure::Accumulate { count } => {
|
||||||
debug_assert_eq!(
|
result.push(TransformOperation::AccumulateMatrix {
|
||||||
!already_mismatched,
|
from_list: Transform(this_remainder.to_vec()),
|
||||||
longer.iter().zip(shorter.iter()).all(|(this, other)| is_matched_operation(this, other)),
|
to_list: Transform(other_remainder.to_vec()),
|
||||||
"ToAnimatedZero should generate matched operations"
|
count: cmp::min(count, i32::max_value() as u64) as i32,
|
||||||
);
|
});
|
||||||
|
}
|
||||||
!already_mismatched
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut this = Cow::Borrowed(&self.0);
|
|
||||||
let mut other = Cow::Borrowed(&other.0);
|
|
||||||
|
|
||||||
if match_operations_if_possible(&mut this, &mut other) {
|
|
||||||
return Ok(Transform(
|
|
||||||
this.iter().zip(other.iter())
|
|
||||||
.map(|(this, other)| this.animate(other, procedure))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
match procedure {
|
|
||||||
Procedure::Add => Err(()),
|
|
||||||
Procedure::Interpolate { progress } => {
|
|
||||||
Ok(Transform(vec![TransformOperation::InterpolateMatrix {
|
|
||||||
from_list: Transform(this.into_owned()),
|
|
||||||
to_list: Transform(other.into_owned()),
|
|
||||||
progress: Percentage(progress as f32),
|
|
||||||
}]))
|
|
||||||
},
|
|
||||||
Procedure::Accumulate { count } => {
|
|
||||||
Ok(Transform(vec![TransformOperation::AccumulateMatrix {
|
|
||||||
from_list: Transform(this.into_owned()),
|
|
||||||
to_list: Transform(other.into_owned()),
|
|
||||||
count: cmp::min(count, i32::max_value() as u64) as i32,
|
|
||||||
}]))
|
|
||||||
},
|
},
|
||||||
|
// If there is a remainder from just one list, then one list must be shorter but
|
||||||
|
// completely match the type of the corresponding functions in the longer list.
|
||||||
|
// => Interpolate the remainder with identity transforms.
|
||||||
|
(Some(remainder), None) | (None, Some(remainder)) => {
|
||||||
|
let fill_right = this_remainder.is_some();
|
||||||
|
result.append(
|
||||||
|
&mut remainder
|
||||||
|
.iter()
|
||||||
|
.map(|transform| {
|
||||||
|
let identity = transform.to_animated_zero().unwrap();
|
||||||
|
|
||||||
|
match transform {
|
||||||
|
// We can't interpolate/accumulate ___Matrix types directly with a
|
||||||
|
// matrix. Instead we need to wrap it in another ___Matrix type.
|
||||||
|
TransformOperation::AccumulateMatrix { .. }
|
||||||
|
| TransformOperation::InterpolateMatrix { .. } => {
|
||||||
|
let transform_list = Transform(vec![transform.clone()]);
|
||||||
|
let identity_list = Transform(vec![identity]);
|
||||||
|
let (from_list, to_list) = if fill_right {
|
||||||
|
(transform_list, identity_list)
|
||||||
|
} else {
|
||||||
|
(identity_list, transform_list)
|
||||||
|
};
|
||||||
|
|
||||||
|
match procedure {
|
||||||
|
Procedure::Add => Err(()),
|
||||||
|
Procedure::Interpolate { progress } => {
|
||||||
|
Ok(TransformOperation::InterpolateMatrix {
|
||||||
|
from_list,
|
||||||
|
to_list,
|
||||||
|
progress: Percentage(progress as f32),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Procedure::Accumulate { count } => {
|
||||||
|
Ok(TransformOperation::AccumulateMatrix {
|
||||||
|
from_list,
|
||||||
|
to_list,
|
||||||
|
count: cmp::min(count, i32::max_value() as u64)
|
||||||
|
as i32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let (lhs, rhs) = if fill_right {
|
||||||
|
(transform, &identity)
|
||||||
|
} else {
|
||||||
|
(&identity, transform)
|
||||||
|
};
|
||||||
|
lhs.animate(rhs, procedure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(None, None) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Transform(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue