diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-06-09 16:32:54 -0600 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-06-09 16:32:54 -0600 |
commit | 8236221acf0f23f2217bf8b2346411396bd04f3c (patch) | |
tree | 7c075f5890d4e74e074e334dad322191fdead8f4 | |
parent | 0dec64caf01c98d10e72b73e35b994127c23e81f (diff) | |
parent | 6dd082278d2d627f9d088c14dfd635990ff3183b (diff) | |
download | servo-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.rs | 17 | ||||
-rw-r--r-- | components/layout/model.rs | 11 | ||||
-rw-r--r-- | components/style/animation.rs | 177 | ||||
-rw-r--r-- | components/style/properties.mako.rs | 76 | ||||
-rw-r--r-- | components/style/values.rs | 2 |
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; |