aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-06-09 16:32:54 -0600
committerbors-servo <metajack+bors@gmail.com>2015-06-09 16:32:54 -0600
commit8236221acf0f23f2217bf8b2346411396bd04f3c (patch)
tree7c075f5890d4e74e074e334dad322191fdead8f4
parent0dec64caf01c98d10e72b73e35b994127c23e81f (diff)
parent6dd082278d2d627f9d088c14dfd635990ff3183b (diff)
downloadservo-8236221acf0f23f2217bf8b2346411396bd04f3c.tar.gz
servo-8236221acf0f23f2217bf8b2346411396bd04f3c.zip
Auto merge of #6280 - glennw:transform-transitions, r=nox
Also tidy up some of the ComputedMatrix code. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6280) <!-- Reviewable:end -->
-rw-r--r--components/layout/display_list_builder.rs17
-rw-r--r--components/layout/model.rs11
-rw-r--r--components/style/animation.rs177
-rw-r--r--components/style/properties.mako.rs76
-rw-r--r--components/style/values.rs2
5 files changed, 212 insertions, 71 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index f2cf382a23a..5491e9d0bc6 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -1163,16 +1163,13 @@ impl FragmentDisplayListBuilding for Fragment {
let matrix = match operation {
&transform::ComputedOperation::Rotate(ax, ay, az, theta) => {
let theta = f32::consts::PI_2 - theta.radians();
- let transform = Matrix4::create_rotation(ax, ay, az, theta);
- pre_transform.mul(&transform).mul(&post_transform)
+ Matrix4::create_rotation(ax, ay, az, theta)
}
&transform::ComputedOperation::Perspective(d) => {
- let transform = Matrix4::create_perspective(d.to_f32_px());
- pre_transform.mul(&transform).mul(&post_transform)
+ Matrix4::create_perspective(d.to_f32_px())
}
&transform::ComputedOperation::Scale(sx, sy, sz) => {
- let transform = Matrix4::create_scale(sx, sy, sz);
- pre_transform.mul(&transform).mul(&post_transform)
+ Matrix4::create_scale(sx, sy, sz)
}
&transform::ComputedOperation::Translate(tx, ty, tz) => {
let tx = tx.to_au(border_box.size.width).to_f32_px();
@@ -1181,17 +1178,17 @@ impl FragmentDisplayListBuilding for Fragment {
Matrix4::create_translation(tx, ty, tz)
}
&transform::ComputedOperation::Matrix(m) => {
- let transform = m.to_gfx_matrix(&border_box.size);
- pre_transform.mul(&transform).mul(&post_transform)
+ m.to_gfx_matrix()
}
&transform::ComputedOperation::Skew(sx, sy) => {
- let transform = Matrix4::create_skew(sx, sy);
- pre_transform.mul(&transform).mul(&post_transform)
+ Matrix4::create_skew(sx, sy)
}
};
transform = transform.mul(&matrix);
}
+
+ transform = pre_transform.mul(&transform).mul(&post_transform);
}
// FIXME(pcwalton): Is this vertical-writing-direction-safe?
diff --git a/components/layout/model.rs b/components/layout/model.rs
index 87e4d3cf3db..ad6dd66cf17 100644
--- a/components/layout/model.rs
+++ b/components/layout/model.rs
@@ -8,7 +8,7 @@
use fragment::Fragment;
-use geom::{Matrix4, SideOffsets2D, Size2D};
+use geom::{Matrix4, SideOffsets2D};
use std::cmp::{max, min};
use std::fmt;
use style::computed_values::transform::ComputedMatrix;
@@ -426,19 +426,16 @@ pub fn padding_from_style(style: &ComputedValues, containing_block_inline_size:
}
pub trait ToGfxMatrix {
- fn to_gfx_matrix(&self, containing_size: &Size2D<Au>) -> Matrix4<f32>;
+ fn to_gfx_matrix(&self) -> Matrix4<f32>;
}
impl ToGfxMatrix for ComputedMatrix {
- fn to_gfx_matrix(&self, containing_size: &Size2D<Au>) -> Matrix4<f32> {
+ fn to_gfx_matrix(&self) -> Matrix4<f32> {
Matrix4 {
m11: self.m11 as f32, m12: self.m12 as f32, m13: self.m13 as f32, m14: self.m14 as f32,
m21: self.m21 as f32, m22: self.m22 as f32, m23: self.m23 as f32, m24: self.m24 as f32,
m31: self.m31 as f32, m32: self.m32 as f32, m33: self.m33 as f32, m34: self.m34 as f32,
- m41: self.m41.to_au(containing_size.width).to_f32_px(),
- m42: self.m42.to_au(containing_size.height).to_f32_px(),
- m43: self.m43 as f32,
- m44: self.m44 as f32
+ m41: self.m41 as f32, m42: self.m42 as f32, m43: self.m43 as f32, m44: self.m44 as f32
}
}
}
diff --git a/components/style/animation.rs b/components/style/animation.rs
index d8652b3ea0e..cecf676c5e5 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -17,7 +17,11 @@ use properties::longhands::text_shadow::computed_value::TextShadow;
use properties::longhands::text_shadow::computed_value::T as TextShadowList;
use properties::longhands::background_position::computed_value::T as BackgroundPosition;
use properties::longhands::transition_property;
-use values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, LengthOrPercentage, Length, Time};
+use properties::longhands::transform::computed_value::ComputedMatrix;
+use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
+use properties::longhands::transform::computed_value::T as TransformList;
+use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
+use values::computed::{LengthAndPercentage, LengthOrPercentage, Length, Time};
use values::CSSFloat;
use cssparser::{RGBA, Color};
@@ -92,6 +96,10 @@ impl PropertyAnimation {
AnimatedProperty::TextShadow(old_style.get_effects().text_shadow.clone(),
new_style.get_effects().text_shadow.clone())
}
+ TransitionProperty::Transform => {
+ AnimatedProperty::Transform(old_style.get_effects().transform.clone(),
+ new_style.get_effects().transform.clone())
+ }
}
}
}
@@ -220,6 +228,7 @@ impl PropertyAnimation {
[TextIndent; mutate_inheritedtext; text_indent],
[TextShadow; mutate_effects; text_shadow],
[Top; mutate_positionoffsets; top],
+ [Transform; mutate_effects; transform],
[VerticalAlign; mutate_box; vertical_align],
[Visibility; mutate_inheritedbox; visibility],
[Width; mutate_box; width],
@@ -274,6 +283,7 @@ enum AnimatedProperty {
TextIndent(LengthOrPercentage, LengthOrPercentage),
TextShadow(TextShadowList, TextShadowList),
Top(LengthOrPercentageOrAuto, LengthOrPercentageOrAuto),
+ Transform(TransformList, TransformList),
VerticalAlign(VerticalAlign, VerticalAlign),
Visibility(Visibility, Visibility),
Width(LengthOrPercentageOrAuto, LengthOrPercentageOrAuto),
@@ -329,6 +339,7 @@ impl AnimatedProperty {
AnimatedProperty::Visibility(ref a, ref b) => a == b,
AnimatedProperty::WordSpacing(ref a, ref b) => a == b,
AnimatedProperty::ZIndex(ref a, ref b) => a == b,
+ AnimatedProperty::Transform(ref a, ref b) => a == b,
}
}
}
@@ -495,6 +506,17 @@ impl Interpolate for LengthOrPercentage {
}
}
+impl Interpolate for LengthAndPercentage {
+ #[inline]
+ fn interpolate(&self, other: &LengthAndPercentage, time: f32)
+ -> Option<LengthAndPercentage> {
+ Some(LengthAndPercentage {
+ length: self.length.interpolate(&other.length, time).unwrap(),
+ percentage: self.percentage.interpolate(&other.percentage, time).unwrap(),
+ })
+ }
+}
+
impl Interpolate for LengthOrPercentageOrAuto {
#[inline]
fn interpolate(&self, other: &LengthOrPercentageOrAuto, time: f32)
@@ -670,6 +692,159 @@ impl Interpolate for TextShadowList {
}
}
+/// Check if it's possible to do a direct numerical interpolation
+/// between these two transform lists.
+/// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation
+fn can_interpolate_list(from_list: &Vec<TransformOperation>,
+ to_list: &Vec<TransformOperation>) -> bool {
+ // Lists must be equal length
+ if from_list.len() != to_list.len() {
+ return false;
+ }
+
+ // Each transform operation must match primitive type in other list
+ for (from, to) in from_list.iter().zip(to_list.iter()) {
+ match (from, to) {
+ (&TransformOperation::Matrix(..), &TransformOperation::Matrix(..)) |
+ (&TransformOperation::Skew(..), &TransformOperation::Skew(..)) |
+ (&TransformOperation::Translate(..), &TransformOperation::Translate(..)) |
+ (&TransformOperation::Scale(..), &TransformOperation::Scale(..)) |
+ (&TransformOperation::Rotate(..), &TransformOperation::Rotate(..)) |
+ (&TransformOperation::Perspective(..), &TransformOperation::Perspective(..)) => {}
+ _ => {
+ return false;
+ }
+ }
+ }
+
+ true
+}
+
+/// Interpolate two transform lists.
+/// http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms
+fn interpolate_transform_list(from_list: &Vec<TransformOperation>,
+ to_list: &Vec<TransformOperation>,
+ time: f32) -> TransformList {
+ let mut result = vec!();
+
+ if can_interpolate_list(from_list, to_list) {
+ for (from, to) in from_list.iter().zip(to_list.iter()) {
+ match (from, to) {
+ (&TransformOperation::Matrix(from),
+ &TransformOperation::Matrix(_to)) => {
+ // TODO(gw): Implement matrix decomposition and interpolation
+ result.push(TransformOperation::Matrix(from));
+ }
+ (&TransformOperation::Skew(fx, fy),
+ &TransformOperation::Skew(tx, ty)) => {
+ let ix = fx.interpolate(&tx, time).unwrap();
+ let iy = fy.interpolate(&ty, time).unwrap();
+ result.push(TransformOperation::Skew(ix, iy));
+ }
+ (&TransformOperation::Translate(fx, fy, fz),
+ &TransformOperation::Translate(tx, ty, tz)) => {
+ let ix = fx.interpolate(&tx, time).unwrap();
+ let iy = fy.interpolate(&ty, time).unwrap();
+ let iz = fz.interpolate(&tz, time).unwrap();
+ result.push(TransformOperation::Translate(ix, iy, iz));
+ }
+ (&TransformOperation::Scale(fx, fy, fz),
+ &TransformOperation::Scale(tx, ty, tz)) => {
+ let ix = fx.interpolate(&tx, time).unwrap();
+ let iy = fy.interpolate(&ty, time).unwrap();
+ let iz = fz.interpolate(&tz, time).unwrap();
+ result.push(TransformOperation::Scale(ix, iy, iz));
+ }
+ (&TransformOperation::Rotate(fx, fy, fz, fa),
+ &TransformOperation::Rotate(_tx, _ty, _tz, _ta)) => {
+ // TODO(gw): Implement matrix decomposition and interpolation
+ result.push(TransformOperation::Rotate(fx, fy, fz, fa));
+ }
+ (&TransformOperation::Perspective(fd),
+ &TransformOperation::Perspective(_td)) => {
+ // TODO(gw): Implement matrix decomposition and interpolation
+ result.push(TransformOperation::Perspective(fd));
+ }
+ _ => {
+ // This should be unreachable due to the can_interpolate_list() call.
+ unreachable!();
+ }
+ }
+ }
+ } else {
+ // TODO(gw): Implement matrix decomposition and interpolation
+ result.push_all(from_list);
+ }
+
+ Some(result)
+}
+
+/// Build an equivalent 'identity transform function list' based
+/// on an existing transform list.
+/// http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+fn build_identity_transform_list(list: &Vec<TransformOperation>) -> Vec<TransformOperation> {
+ let mut result = vec!();
+
+ for operation in list {
+ match operation {
+ &TransformOperation::Matrix(..) => {
+ let identity = ComputedMatrix::identity();
+ result.push(TransformOperation::Matrix(identity));
+ }
+ &TransformOperation::Skew(..) => {
+ result.push(TransformOperation::Skew(0.0, 0.0));
+ }
+ &TransformOperation::Translate(..) => {
+ result.push(TransformOperation::Translate(LengthAndPercentage::zero(),
+ LengthAndPercentage::zero(),
+ Au(0)));
+ }
+ &TransformOperation::Scale(..) => {
+ result.push(TransformOperation::Scale(1.0, 1.0, 1.0));
+ }
+ &TransformOperation::Rotate(..) => {
+ result.push(TransformOperation::Rotate(0.0, 0.0, 1.0, Angle(0.0)));
+ }
+ &TransformOperation::Perspective(..) => {
+ // http://dev.w3.org/csswg/css-transforms/#identity-transform-function
+ let identity = ComputedMatrix::identity();
+ result.push(TransformOperation::Matrix(identity));
+ }
+ }
+ }
+
+ result
+}
+
+impl Interpolate for TransformList {
+ #[inline]
+ fn interpolate(&self, other: &TransformList, time: f32) -> Option<TransformList> {
+ // http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms
+ let result = match (self, other) {
+ (&Some(ref from_list), &Some(ref to_list)) => {
+ // Two lists of transforms
+ interpolate_transform_list(from_list, &to_list, time)
+ }
+ (&Some(ref from_list), &None) => {
+ // http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+ let to_list = build_identity_transform_list(from_list);
+ interpolate_transform_list(from_list, &to_list, time)
+ }
+ (&None, &Some(ref to_list)) => {
+ // http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+ let from_list = build_identity_transform_list(to_list);
+ interpolate_transform_list(&from_list, to_list, time)
+ }
+ (&None, &None) => {
+ // http://dev.w3.org/csswg/css-transforms/#none-none-animation
+ None
+ }
+ };
+
+ Some(result)
+ }
+}
+
/// Accesses an element of an array, "wrapping around" using modular arithmetic. This is needed
/// to handle values of differing lengths according to CSS-TRANSITIONS § 2.
pub trait GetMod {
diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs
index ca4af9f18ff..5bc292e85b3 100644
--- a/components/style/properties.mako.rs
+++ b/components/style/properties.mako.rs
@@ -3131,17 +3131,24 @@ pub mod longhands {
pub mod computed_value {
use values::CSSFloat;
use values::computed;
- use values::specified;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ComputedMatrix {
pub m11: CSSFloat, pub m12: CSSFloat, pub m13: CSSFloat, pub m14: CSSFloat,
pub m21: CSSFloat, pub m22: CSSFloat, pub m23: CSSFloat, pub m24: CSSFloat,
pub m31: CSSFloat, pub m32: CSSFloat, pub m33: CSSFloat, pub m34: CSSFloat,
- pub m41: computed::LengthAndPercentage,
- pub m42: computed::LengthAndPercentage,
- pub m43: CSSFloat,
- pub m44: CSSFloat,
+ pub m41: CSSFloat, pub m42: CSSFloat, pub m43: CSSFloat, pub m44: CSSFloat,
+ }
+
+ impl ComputedMatrix {
+ pub fn identity() -> ComputedMatrix {
+ ComputedMatrix {
+ m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0,
+ m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0,
+ m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0,
+ m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0
+ }
+ }
}
#[derive(Clone, Debug, PartialEq)]
@@ -3152,30 +3159,14 @@ pub mod longhands {
computed::LengthAndPercentage,
computed::Length),
Scale(CSSFloat, CSSFloat, CSSFloat),
- Rotate(CSSFloat, CSSFloat, CSSFloat, specified::Angle),
+ Rotate(CSSFloat, CSSFloat, CSSFloat, computed::Angle),
Perspective(computed::Length),
}
pub type T = Option<Vec<ComputedOperation>>;
}
- #[derive(Clone, Debug, PartialEq)]
- pub struct SpecifiedMatrix {
- m11: CSSFloat, m12: CSSFloat, m13: CSSFloat, m14: CSSFloat,
- m21: CSSFloat, m22: CSSFloat, m23: CSSFloat, m24: CSSFloat,
- m31: CSSFloat, m32: CSSFloat, m33: CSSFloat, m34: CSSFloat,
- m41: specified::LengthAndPercentage,
- m42: specified::LengthAndPercentage,
- m43: specified::Length,
- m44: CSSFloat,
- }
-
- impl ToCss for SpecifiedMatrix {
- fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
- // TODO(pcwalton)
- Ok(())
- }
- }
+ pub use self::computed_value::ComputedMatrix as SpecifiedMatrix;
fn parse_two_lengths_or_percentages(input: &mut Parser)
-> Result<(specified::LengthAndPercentage,
@@ -3259,19 +3250,12 @@ pub mod longhands {
if values.len() != 6 {
return Err(())
}
- let (tx, ty, tz) =
- (specified::Length::Absolute(Au::from_f32_px(values[4])),
- specified::Length::Absolute(Au::from_f32_px(values[5])),
- specified::Length::Absolute(Au(0)));
- let (tx, ty) =
- (specified::LengthAndPercentage::from_length(tx),
- specified::LengthAndPercentage::from_length(ty));
result.push(SpecifiedOperation::Matrix(
SpecifiedMatrix {
m11: values[0], m12: values[1], m13: 0.0, m14: 0.0,
m21: values[2], m22: values[3], m23: 0.0, m24: 0.0,
m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0,
- m41: tx, m42: ty, m43: tz, m44: 1.0
+ m41: values[4], m42: values[5], m43: 0.0, m44: 1.0
}));
Ok(())
}))
@@ -3284,19 +3268,12 @@ pub mod longhands {
if values.len() != 16 {
return Err(())
}
- let (tx, ty, tz) =
- (specified::Length::Absolute(Au::from_f32_px(values[12])),
- specified::Length::Absolute(Au::from_f32_px(values[13])),
- specified::Length::Absolute(Au::from_f32_px(values[14])));
- let (tx, ty) =
- (specified::LengthAndPercentage::from_length(tx),
- specified::LengthAndPercentage::from_length(ty));
result.push(SpecifiedOperation::Matrix(
SpecifiedMatrix {
m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3],
m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7],
m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11],
- m41: tx, m42: ty, m43: tz, m44: values[15]
+ m41: values[12], m42: values[13], m43: values[14], m44: values[15]
}));
Ok(())
}))
@@ -3490,21 +3467,12 @@ pub mod longhands {
for operation in self.0.iter() {
match *operation {
SpecifiedOperation::Matrix(ref matrix) => {
- let m = computed_value::ComputedMatrix {
- m11: matrix.m11, m12: matrix.m12, m13: matrix.m13, m14: matrix.m14,
- m21: matrix.m21, m22: matrix.m22, m23: matrix.m23, m24: matrix.m24,
- m31: matrix.m31, m32: matrix.m32, m33: matrix.m33, m34: matrix.m34,
- m41: matrix.m41.to_computed_value(context),
- m42: matrix.m42.to_computed_value(context),
- m43: matrix.m43.to_computed_value(context).to_f32_px(),
- m44: matrix.m44
- };
- result.push(computed_value::ComputedOperation::Matrix(m));
+ result.push(computed_value::ComputedOperation::Matrix(*matrix));
}
SpecifiedOperation::Translate(ref tx, ref ty, ref tz) => {
result.push(computed_value::ComputedOperation::Translate(tx.to_computed_value(context),
- ty.to_computed_value(context),
- tz.to_computed_value(context)));
+ ty.to_computed_value(context),
+ tz.to_computed_value(context)));
}
SpecifiedOperation::Scale(sx, sy, sz) => {
result.push(computed_value::ComputedOperation::Scale(sx, sy, sz));
@@ -4023,6 +3991,7 @@ pub mod longhands {
TextIndent,
TextShadow,
Top,
+ Transform,
VerticalAlign,
Visibility,
Width,
@@ -4030,7 +3999,7 @@ pub mod longhands {
ZIndex,
}
- pub static ALL_TRANSITION_PROPERTIES: [TransitionProperty; 44] = [
+ pub static ALL_TRANSITION_PROPERTIES: [TransitionProperty; 45] = [
TransitionProperty::BackgroundColor,
TransitionProperty::BackgroundPosition,
TransitionProperty::BorderBottomColor,
@@ -4070,6 +4039,7 @@ pub mod longhands {
TransitionProperty::TextIndent,
TransitionProperty::TextShadow,
TransitionProperty::Top,
+ TransitionProperty::Transform,
TransitionProperty::VerticalAlign,
TransitionProperty::Visibility,
TransitionProperty::Width,
@@ -4120,6 +4090,7 @@ pub mod longhands {
TransitionProperty::TextIndent => dest.write_str("text-indent"),
TransitionProperty::TextShadow => dest.write_str("text-shadow"),
TransitionProperty::Top => dest.write_str("top"),
+ TransitionProperty::Transform => dest.write_str("transform"),
TransitionProperty::VerticalAlign => dest.write_str("vertical-align"),
TransitionProperty::Visibility => dest.write_str("visibility"),
TransitionProperty::Width => dest.write_str("width"),
@@ -4196,6 +4167,7 @@ pub mod longhands {
"text-indent" => Ok(TransitionProperty::TextIndent),
"text-shadow" => Ok(TransitionProperty::TextShadow),
"top" => Ok(TransitionProperty::Top),
+ "transform" => Ok(TransitionProperty::Transform),
"vertical-align" => Ok(TransitionProperty::VerticalAlign),
"visibility" => Ok(TransitionProperty::Visibility),
"width" => Ok(TransitionProperty::Width),
diff --git a/components/style/values.rs b/components/style/values.rs
index 992ee08a79d..fde7f715689 100644
--- a/components/style/values.rs
+++ b/components/style/values.rs
@@ -888,7 +888,7 @@ pub mod specified {
}
pub mod computed {
- pub use super::specified::{BorderStyle, Time};
+ pub use super::specified::{Angle, BorderStyle, Time};
use super::specified::{AngleOrCorner};
use super::{specified, CSSFloat};
pub use cssparser::Color as CSSColor;