Bug 1390702 - Part 3: Implement Animatable for FontSettings. r?birtles draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 17 Aug 2017 15:34:19 +0900
changeset 648080 bd319c26bff16be870aca50eac1f81e2fed09e58
parent 648079 3e2b37dc6ae3fbf23f3beede9c00ce6b6b12ed19
child 648081 3bab5e9f34628caa68b705cfe4a94d88d35a9c52
child 648649 cdd33d910f1fe6d7aef8c25704a3e4d8e52ebedb
push id74615
push userbmo:dakatsuka@mozilla.com
push dateThu, 17 Aug 2017 07:11:15 +0000
reviewersbirtles
bugs1390702
milestone57.0a1
Bug 1390702 - Part 3: Implement Animatable for FontSettings. r?birtles MozReview-Commit-ID: 7xAGglOloUN
servo/components/style/properties/longhand/font.mako.rs
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -2044,18 +2044,141 @@ https://drafts.csswg.org/css-fonts-4/#lo
     impl ComputedValueAsSpecified for SpecifiedValue {}
 
     pub type SpecifiedValue = computed_value::T;
 
     no_viewport_percentage!(SpecifiedValue);
 
 
     pub mod computed_value {
-        use values::generics::{FontSettings, FontSettingTagFloat};
+        use properties::animated_properties::Animatable;
+        use values::animated::ToAnimatedZero;
+        use values::distance::{ComputeSquaredDistance, SquaredDistance};
+        use values::generics::{FontSettings, FontSettingTag, FontSettingTagFloat};
         pub type T = FontSettings<FontSettingTagFloat>;
+        type FontTag = FontSettingTag<FontSettingTagFloat>;
+
+        fn get_animatable_pairs<'a>(self_settings: &'a T, other_settings: &'a T)
+                                    -> Result<Vec<(&'a FontTag, &'a FontTag)>, ()> {
+            if let (&FontSettings::Tag(ref self_tags), &FontSettings::Tag(ref other_tags)) =
+                (self_settings, other_settings) {
+                fn contains(tags: &Vec<FontTag>, target: &FontTag) -> bool {
+                    for t in tags.iter() {
+                        if t.tag == target.tag {
+                            return true;
+                        }
+                    }
+                    false
+                }
+
+                fn contains_for_pair(tags: &Vec<(&FontTag, &FontTag)>, target: &FontTag) -> bool {
+                    for &(t, _) in tags.iter() {
+                        if t.tag == target.tag {
+                            return true;
+                        }
+                    }
+                    false
+                }
+
+                for st in self_tags {
+                    if !contains(other_tags, st) {
+                        return Err(());
+                    };
+                }
+                for ot in other_tags {
+                    if !contains(self_tags, ot) {
+                        return Err(());
+                    };
+                }
+
+                let mut vec: Vec<(&FontTag, &FontTag)> = Vec::with_capacity(self_tags.len());
+                for i in (0..self_tags.len()).rev() {
+                    let ref st = self_tags[i];
+                    if contains_for_pair(&vec, st) {
+                        continue;
+                    };
+                    for j in (0..other_tags.len()).rev() {
+                        let ref ot = other_tags[j];
+                        if ot.tag == st.tag {
+                            vec.push((st, ot));
+                            break;
+                        }
+                    }
+                };
+
+                Ok(vec)
+            } else {
+                Err(())
+            }
+        }
+
+        impl Animatable for T {
+            #[inline]
+            fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+                            -> Result<Self, ()> {
+                let pairs = get_animatable_pairs(self, other)?;
+                let animated: Vec<FontTag> = pairs.iter().map(|&(st, ot)| {
+                    st.add_weighted(&ot, self_portion, other_portion).unwrap()
+                }).collect();
+                Ok(FontSettings::Tag(animated))
+            }
+        }
+
+        impl ComputeSquaredDistance for T {
+            #[inline]
+            fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+                let pairs = get_animatable_pairs(self, other)?;
+                let mut distance = SquaredDistance::Value(0.);
+                for &(st, ot) in pairs.iter() {
+                    distance = distance + st.compute_squared_distance(&ot)?;
+                }
+                Ok(distance)
+            }
+        }
+
+        impl ToAnimatedZero for T {
+            #[inline]
+            fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+        }
+
+        impl Animatable for FontTag {
+            #[inline]
+            fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+                if self.tag != other.tag {
+                    return Err(());
+                }
+                let tag = self.tag;
+                let value = self.value.add_weighted(&other.value, self_portion, other_portion)?;
+                Ok(FontSettingTag{tag, value})
+            }
+        }
+
+        impl ComputeSquaredDistance for FontTag {
+            #[inline]
+            fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+                if self.tag != other.tag {
+                    return Err(());
+                }
+                self.value.compute_squared_distance(&other.value)
+            }
+        }
+
+        impl Animatable for FontSettingTagFloat {
+            #[inline]
+            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(FontSettingTagFloat)
+            }
+        }
+
+        impl ComputeSquaredDistance for FontSettingTagFloat {
+            #[inline]
+            fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+                self.0.compute_squared_distance(&other.0)
+            }
+        }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         FontSettings::Normal
     }
 
     /// normal | <feature-tag-value>#