Bug 1329878 - Add add() method to Animatable interface; r?hiro draft
authorBrian Birtles <birtles@gmail.com>
Mon, 15 May 2017 11:01:22 +0900
changeset 577584 1bd8e35533e41129f10b214f70929d2ab16f7468
parent 577583 507b216ffd116becf97c38751bc242b6b9640899
child 577585 ad04b288c0ec8fd8b9fbdf1814fa9d851eda414e
push id58723
push userbbirtles@mozilla.com
push dateMon, 15 May 2017 02:05:49 +0000
reviewershiro
bugs1329878
milestone55.0a1
Bug 1329878 - Add add() method to Animatable interface; r?hiro MozReview-Commit-ID: Ii4qKzX1kw8
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -113,16 +113,20 @@
                 % if delegate_animate:
                     use properties::animated_properties::Animatable;
                     impl Animatable for T {
                         fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
                             -> Result<Self, ()> {
                             self.0.add_weighted(&other.0, self_portion, other_portion).map(T)
                         }
 
+                        fn add(&self, other: &Self) -> Result<Self, ()> {
+                            self.0.add(&other.0).map(T)
+                        }
+
                         #[inline]
                         fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
                             self.0.compute_distance(&other.0)
                         }
 
                         #[inline]
                         fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
                             self.0.compute_squared_distance(&other.0)
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -603,16 +603,40 @@ impl Animatable for AnimationValue {
             % endfor
             _ => {
                 panic!("Expected weighted addition of computed values of the same \
                         property, got: {:?}, {:?}", self, other);
             }
         }
     }
 
+    fn add(&self, other: &Self) -> Result<Self, ()> {
+        match (self, other) {
+            % for prop in data.longhands:
+                % if prop.animatable:
+                    % if prop.animation_value_type == "discrete":
+                        (&AnimationValue::${prop.camel_case}(_),
+                         &AnimationValue::${prop.camel_case}(_)) => {
+                            Err(())
+                        }
+                    % else:
+                        (&AnimationValue::${prop.camel_case}(ref from),
+                         &AnimationValue::${prop.camel_case}(ref to)) => {
+                            from.add(to).map(AnimationValue::${prop.camel_case})
+                        }
+                    % endif
+                % endif
+            % endfor
+            _ => {
+                panic!("Expected weighted addition of computed values of the same \
+                        property, got: {:?}, {:?}", self, other);
+            }
+        }
+    }
+
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         match (self, other) {
             % for prop in data.longhands:
                 % if prop.animatable:
                     % if prop.animation_value_type != "discrete":
                         (&AnimationValue::${prop.camel_case}(ref from),
                          &AnimationValue::${prop.camel_case}(ref to)) => {
                             from.compute_distance(to)
@@ -643,16 +667,23 @@ pub trait Animatable: Sized {
 
     /// [Interpolates][interpolation] a value with another for a given property.
     ///
     /// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation
     fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
         self.add_weighted(other, 1.0 - progress, progress)
     }
 
+    /// Returns the [sum][animation-addition] of this value and |other|.
+    ///
+    /// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition
+    fn add(&self, other: &Self) -> Result<Self, ()> {
+        self.add_weighted(other, 1.0, 1.0)
+    }
+
     /// Compute distance between a value and another for a given property.
     fn compute_distance(&self, _other: &Self) -> Result<f64, ()>  { Err(()) }
 
     /// In order to compute the Euclidean distance of a list or property value with multiple
     /// components, we need to compute squared distance for each element, so the vector can sum it
     /// and then get its squared root as the distance.
     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
         self.compute_distance(other).map(|d| d * d)
@@ -786,26 +817,22 @@ impl Animatable for Angle {
     }
 }
 
 /// https://drafts.csswg.org/css-transitions/#animtype-visibility
 impl Animatable for Visibility {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
-            (Visibility::visible, _) | (_, Visibility::visible) => {
-                Ok(if self_portion >= 0.0 && self_portion <= 1.0 &&
-                      other_portion >= 0.0 && other_portion <= 1.0 {
-                    Visibility::visible
-                } else if self_portion > other_portion {
-                    *self
-                } else {
-                    *other
-                })
-            }
+            (Visibility::visible, _) => {
+                Ok(if self_portion > 0.0 { *self } else { *other })
+            },
+            (_, Visibility::visible) => {
+                Ok(if other_portion > 0.0 { *other } else { *self })
+            },
             _ => Err(()),
         }
     }
 
     #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         if *self == *other {
             Ok(0.0)
@@ -1493,16 +1520,31 @@ impl Animatable for ClipRect {
                     }
                     (None, None) => unreachable!(),
                 };
                 result.push(shadow);
             }
 
             Ok(${item}List(result))
         }
+
+        fn add(&self, other: &Self) -> Result<Self, ()> {
+            let len = self.0.len() + other.0.len();
+
+            let mut result = if len > 1 {
+                SmallVec::from_vec(Vec::with_capacity(len))
+            } else {
+                SmallVec::new()
+            };
+
+            result.extend(self.0.iter().cloned());
+            result.extend(other.0.iter().cloned());
+
+            Ok(${item}List(result))
+        }
     }
 </%def>
 
 ${impl_animatable_for_shadow('BoxShadow', 'CSSParserColor::RGBA(RGBA::transparent())',)}
 ${impl_animatable_for_shadow('TextShadow', 'CSSParserColor::RGBA(RGBA::transparent())',)}
 
 /// Check if it's possible to do a direct numerical interpolation
 /// between these two transform lists.
@@ -2434,16 +2476,33 @@ impl Animatable for TransformList {
             _ => {
                 // http://dev.w3.org/csswg/css-transforms/#none-none-animation
                 TransformList(None)
             }
         };
 
         Ok(result)
     }
+
+    fn add(&self, other: &Self) -> Result<Self, ()> {
+        match (&self.0, &other.0) {
+            (&Some(ref from_list), &Some(ref to_list)) => {
+                Ok(TransformList(Some([&from_list[..], &to_list[..]].concat())))
+            }
+            (&Some(_), &None) => {
+                Ok(self.clone())
+            }
+            (&None, &Some(_)) => {
+                Ok(other.clone())
+            }
+            _ => {
+                Ok(TransformList(None))
+            }
+        }
+    }
 }
 
 impl<T, U> Animatable for Either<T, U>
         where T: Animatable + Copy, U: Animatable + Copy,
 {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {