Bug 1335998 - Part 1: Define ComputedOperation::InterpolateMatrix. draft
authorBoris Chiou <boris.chiou@gmail.com>
Thu, 25 May 2017 16:15:13 +0800
changeset 589576 c1f529e3a30eab69b1d17365fa12a0d9ac492599
parent 589301 2c6289f56812c30254acfdddabcfec1e149c0336
child 589577 a975479666b4e9d07f04b8045d358d071b312012
push id62434
push userbmo:boris.chiou@gmail.com
push dateTue, 06 Jun 2017 12:26:50 +0000
bugs1335998
milestone55.0a1
Bug 1335998 - Part 1: Define ComputedOperation::InterpolateMatrix. We use this arm to store the interpolated result of two mismatched transform lists, and we resolve it until we know the reference box size (on Gecko side). The conversion from ComputedOperation::InterpolateMatrix to eCSSKeyword_interpolatematrix will be implemented later in this patch series. MozReview-Commit-ID: EIv0a6krwi9
servo/components/layout/fragment.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/properties/longhand/box.mako.rs
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -2891,16 +2891,20 @@ impl Fragment {
                 transform::ComputedOperation::MatrixWithPercents(_) => {
                     // `-moz-transform` is not implemented in Servo yet.
                     unreachable!()
                 }
                 transform::ComputedOperation::Skew(theta_x, theta_y) => {
                     Matrix4D::create_skew(Radians::new(theta_x.radians()),
                                           Radians::new(theta_y.radians()))
                 }
+                transform::ComputedOperation::InterpolateMatrix { .. } => {
+                    // TODO: Convert InterpolateMatrix into a valid Matrix4D by the reference box.
+                    Matrix4D::identity()
+                }
             };
 
             transform = transform.pre_mul(&matrix);
         }
 
         Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
     }
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -2319,16 +2319,21 @@ fn static_assert() {
                     ${transform_function_arm("Matrix", "matrix3d", ["number"] * 16)}
                     ${transform_function_arm("MatrixWithPercents", "matrix3d", ["number"] * 12 + ["lop"] * 2
                                              + ["length"] + ["number"])}
                     ${transform_function_arm("Skew", "skew", ["angle"] * 2)}
                     ${transform_function_arm("Translate", "translate3d", ["lop", "lop", "length"])}
                     ${transform_function_arm("Scale", "scale3d", ["number"] * 3)}
                     ${transform_function_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])}
                     ${transform_function_arm("Perspective", "perspective", ["length"])}
+                    _ => {
+                        // TODO: Convert ComputedOperation::InterpolateMatrix into
+                        //       eCSSKeyword_interpolatematrix.
+                        gecko_value.mUnit = structs::nsCSSUnit::eCSSUnit_None;
+                    }
                 }
                 cur = (*cur).mNext;
             }
         }
         debug_assert!(iter.next().is_none());
         unsafe { output.set_move(list) };
     }
 
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -1634,16 +1634,17 @@ fn build_identity_transform_list(list: &
             TransformOperation::Rotate(..) => {
                 result.push(TransformOperation::Rotate(0.0, 0.0, 1.0, Angle::zero()));
             }
             TransformOperation::Perspective(..) => {
                 // http://dev.w3.org/csswg/css-transforms/#identity-transform-function
                 let identity = ComputedMatrix::identity();
                 result.push(TransformOperation::Matrix(identity));
             }
+            TransformOperation::InterpolateMatrix { .. } => panic!("Not supported"),
         }
     }
 
     result
 }
 
 /// A wrapper for calling add_weighted that interpolates the distance of the two values from
 /// an initial_value and uses that to produce an interpolated value.
@@ -1735,18 +1736,23 @@ fn add_weighted_transform_lists(from_lis
                 }
                 _ => {
                     // This should be unreachable due to the can_interpolate_list() call.
                     unreachable!();
                 }
             }
         }
     } else {
-        // TODO(gw): Implement matrix decomposition and interpolation
-        result.extend_from_slice(from_list);
+        use values::specified::Percentage;
+        let from_transform_list = TransformList(Some(from_list.to_vec()));
+        let to_transform_list = TransformList(Some(to_list.to_vec()));
+        result.push(
+            TransformOperation::InterpolateMatrix { from_list: from_transform_list,
+                                                    to_list: to_transform_list,
+                                                    progress: Percentage(other_portion as f32) });
     }
 
     TransformList(Some(result))
 }
 
 /// https://drafts.csswg.org/css-transforms/#Rotate3dDefined
 fn rotate_to_matrix(x: f32, y: f32, z: f32, a: Angle) -> ComputedMatrix {
     let half_rad = a.radians() / 2.0;
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -1108,28 +1108,28 @@
 
 <%helpers:longhand name="transform" extra_prefixes="webkit"
                    animation_value_type="ComputedValue"
                    flags="CREATES_STACKING_CONTEXT FIXPOS_CB"
                    spec="https://drafts.csswg.org/css-transforms/#propdef-transform">
     use app_units::Au;
     use values::computed::{LengthOrPercentageOrNumber as ComputedLoPoNumber, LengthOrNumber as ComputedLoN};
     use values::computed::{LengthOrPercentage as ComputedLoP, Length as ComputedLength};
-    use values::specified::{Angle, Length, LengthOrPercentage};
+    use values::specified::{Angle, Length, LengthOrPercentage, Percentage};
     use values::specified::{LengthOrNumber, LengthOrPercentageOrNumber as LoPoNumber, Number};
     use style_traits::ToCss;
     use style_traits::values::Css;
 
     use std::fmt;
 
     pub mod computed_value {
         use app_units::Au;
         use values::CSSFloat;
         use values::computed;
-        use values::computed::{Length, LengthOrPercentage};
+        use values::computed::{Length, LengthOrPercentage, Percentage};
 
         #[derive(Clone, Copy, Debug, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         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: CSSFloat, pub m42: CSSFloat, pub m43: CSSFloat, pub m44: CSSFloat,
@@ -1176,16 +1176,30 @@
             MatrixWithPercents(ComputedMatrixWithPercents),
             Skew(computed::Angle, computed::Angle),
             Translate(computed::LengthOrPercentage,
                       computed::LengthOrPercentage,
                       computed::Length),
             Scale(CSSFloat, CSSFloat, CSSFloat),
             Rotate(CSSFloat, CSSFloat, CSSFloat, computed::Angle),
             Perspective(computed::Length),
+            // For mismatched transform lists.
+            // A vector of |ComptuedOperation| could contain an |InterpolateMatrix| and other
+            // |ComputedOperation|s, and multiple nested |InterpolateMatrix|s is acceptable.
+            // e.g.
+            // [ InterpolateMatrix { from_list: [ InterpolateMatrix { ... },
+            //                                    Scale(...) ],
+            //                       to_list: [ InterpolateMatrix { from_list: ...,
+            //                                                      to_list: [ InterpolateMatrix,
+            //                                                                 ... ],
+            //                                                      progress: ... } ],
+            //                       progress: ... } ]
+            InterpolateMatrix { from_list: T,
+                                to_list: T,
+                                progress: Percentage },
         }
 
         #[derive(Clone, Debug, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub struct T(pub Option<Vec<ComputedOperation>>);
     }
 
     /// Describes a single parsed
@@ -1255,16 +1269,20 @@
         Rotate3D(Number, Number, Number, Angle),
         /// Specifies a perspective projection matrix.
         ///
         /// Part of CSS Transform Module Level 2 and defined at
         /// [ยง 13.1. 3D Transform Function](https://drafts.csswg.org/css-transforms-2/#funcdef-perspective).
         ///
         /// The value must be greater than or equal to zero.
         Perspective(specified::Length),
+        /// A intermediate type for interpolation of mismatched transform lists.
+        InterpolateMatrix { from_list: SpecifiedValue,
+                            to_list: SpecifiedValue,
+                            progress: Percentage },
     }
 
     impl ToCss for computed_value::T {
         fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
             // TODO(pcwalton)
             Ok(())
         }
     }
@@ -1319,16 +1337,17 @@
                 Rotate(theta) => write!(dest, "rotate({})", Css(theta)),
                 RotateX(theta) => write!(dest, "rotateX({})", Css(theta)),
                 RotateY(theta) => write!(dest, "rotateY({})", Css(theta)),
                 RotateZ(theta) => write!(dest, "rotateZ({})", Css(theta)),
                 Rotate3D(x, y, z, theta) => write!(
                     dest, "rotate3d({}, {}, {}, {})",
                     Css(x), Css(y), Css(z), Css(theta)),
                 Perspective(ref length) => write!(dest, "perspective({})", Css(length)),
+                _ => unreachable!(),
             }
         }
     }
 
     #[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     pub struct SpecifiedValue(Vec<SpecifiedOperation>);
 
@@ -1860,16 +1879,23 @@
                     }
                     SkewY(theta_y) => {
                         let theta_y = theta_y.to_computed_value(context);
                         result.push(computed_value::ComputedOperation::Skew(computed::Angle::zero(), theta_y));
                     }
                     Perspective(ref d) => {
                         result.push(computed_value::ComputedOperation::Perspective(d.to_computed_value(context)));
                     }
+                    InterpolateMatrix { ref from_list, ref to_list, progress } => {
+                        result.push(computed_value::ComputedOperation::InterpolateMatrix {
+                            from_list: from_list.to_computed_value(context),
+                            to_list: to_list.to_computed_value(context),
+                            progress: progress
+                        });
+                    }
                 };
             }
 
             computed_value::T(Some(result))
         }
 
         #[inline]
         fn from_computed_value(computed: &computed_value::T) -> Self {
@@ -1943,16 +1969,25 @@
                                     specified::Angle::from_computed_value(theta_x),
                                     Some(specified::Angle::from_computed_value(theta_y))))
                         }
                         computed_value::ComputedOperation::Perspective(ref d) => {
                             result.push(SpecifiedOperation::Perspective(
                                 ToComputedValue::from_computed_value(d)
                             ));
                         }
+                        computed_value::ComputedOperation::InterpolateMatrix { ref from_list,
+                                                                               ref to_list,
+                                                                               progress } => {
+                            result.push(SpecifiedOperation::InterpolateMatrix {
+                                from_list: SpecifiedValue::from_computed_value(from_list),
+                                to_list: SpecifiedValue::from_computed_value(to_list),
+                                progress: progress
+                            });
+                        }
                     };
                 }
                 result
             }).unwrap_or(Vec::new()))
         }
     }
 
     // Converts computed LengthOrPercentageOrNumber into computed