Bug 1353966 - Part 1: Implement discrete type animation for position related properties. r?hiro draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Mon, 08 May 2017 10:15:10 +0900
changeset 573819 cf65d503eb0809598f4f641d8d12b96b1dc265fa
parent 571081 4b134293293043d247f8dcfd076ca9fc853332b4
child 627415 a02ee794e76a18ddf7af3322f395c51628c0ba9f
push id57516
push userbmo:dakatsuka@mozilla.com
push dateMon, 08 May 2017 01:16:41 +0000
reviewershiro
bugs1353966
milestone55.0a1
Bug 1353966 - Part 1: Implement discrete type animation for position related properties. r?hiro In this patch, implement following position related properties. * align-content * align-self * box-sizing * flex-direction * flex-wrap * grid-auto-columns * grid-auto-flow * grid-auto-rows * grid-column-end * grid-column-startgrid-row-end * grid-row-start, * justify-content * justify-items * justify-self * object-fit MozReview-Commit-ID: LcDYUc1AFtN
servo/components/style/gecko_bindings/sugar/ns_style_coord.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/properties/longhand/position.mako.rs
servo/components/style/values/specified/align.rs
--- a/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs
@@ -15,16 +15,45 @@ impl nsStyleCoord {
     pub fn null() -> Self {
         // Can't construct directly because it has private fields
         let mut coord: Self = unsafe { mem::zeroed() };
         coord.leaky_set_null();
         coord
     }
 }
 
+impl PartialEq for nsStyleCoord {
+    fn eq(&self, other: &Self) -> bool {
+        if self.unit() != other.unit() {
+            return false;
+        }
+
+        use gecko_bindings::structs::root::nsStyleUnit::*;
+        unsafe {
+            match self.unit() {
+                eStyleUnit_Null |
+                eStyleUnit_Normal |
+                eStyleUnit_Auto |
+                eStyleUnit_None => { true }
+                eStyleUnit_Percent |
+                eStyleUnit_Factor |
+                eStyleUnit_Degree |
+                eStyleUnit_Grad |
+                eStyleUnit_Radian |
+                eStyleUnit_Turn |
+                eStyleUnit_FlexFraction => { self.get_float() == other.get_float() }
+                eStyleUnit_Coord |
+                eStyleUnit_Integer |
+                eStyleUnit_Enumerated => { self.get_integer() == other.get_integer() }
+                eStyleUnit_Calc => { self.get_calc_value() == other.get_calc_value() }
+            }
+        }
+    }
+}
+
 impl CoordData for nsStyleCoord {
     #[inline]
     fn unit(&self) -> nsStyleUnit {
         unsafe {
             *self.get_mUnit()
         }
     }
     #[inline]
@@ -49,16 +78,29 @@ impl nsStyleCoord_CalcValue {
         nsStyleCoord_CalcValue {
             mLength: 0,
             mPercent: 0.0,
             mHasPercent: false,
         }
     }
 }
 
+impl PartialEq for nsStyleCoord_CalcValue {
+    fn eq(&self, other: &Self) -> bool {
+        if self.mHasPercent != other.mHasPercent {
+            return false;
+        }
+
+        match self.mHasPercent {
+            true => { self.mPercent != other.mPercent }
+            _ => { self.mLength != other.mLength }
+        }
+    }
+}
+
 impl nsStyleSides {
     /// Immutably get the `nsStyleCoord`-like object representing the side at
     /// index `index`.
     #[inline]
     pub fn data_at(&self, index: usize) -> SidesData {
         SidesData {
             sides: self,
             index: index,
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1089,34 +1089,56 @@ fn static_assert() {
     }
 
     pub fn set_align_content(&mut self, v: longhands::align_content::computed_value::T) {
         self.gecko.mAlignContent = v.bits()
     }
 
     ${impl_simple_copy('align_content', 'mAlignContent')}
 
+    pub fn clone_align_content(&self) -> longhands::align_content::computed_value::T {
+        use values::specified::align::AlignJustifyContent;
+        AlignJustifyContent(self.gecko.mAlignContent)
+    }
+
     pub fn set_justify_content(&mut self, v: longhands::justify_content::computed_value::T) {
         self.gecko.mJustifyContent = v.bits()
     }
 
     ${impl_simple_copy('justify_content', 'mJustifyContent')}
 
+    pub fn clone_justify_content(&self) -> longhands::justify_content::computed_value::T {
+        use values::specified::align::AlignJustifyContent;
+        AlignJustifyContent(self.gecko.mJustifyContent)
+    }
+
     pub fn set_align_self(&mut self, v: longhands::align_self::computed_value::T) {
         self.gecko.mAlignSelf = v.0.bits()
     }
 
     ${impl_simple_copy('align_self', 'mAlignSelf')}
 
+    pub fn clone_align_self(&self) -> longhands::align_self::computed_value::T {
+        use values::specified::align::{AlignFlags, AlignJustifySelf};
+        AlignJustifySelf(AlignFlags::from_bits(self.gecko.mAlignSelf)
+                                              .expect("mAlignSelf contains valid flags"))
+    }
+
     pub fn set_justify_self(&mut self, v: longhands::justify_self::computed_value::T) {
         self.gecko.mJustifySelf = v.0.bits()
     }
 
     ${impl_simple_copy('justify_self', 'mJustifySelf')}
 
+    pub fn clone_justify_self(&self) -> longhands::justify_self::computed_value::T {
+        use values::specified::align::{AlignFlags, AlignJustifySelf};
+        AlignJustifySelf(AlignFlags::from_bits(self.gecko.mJustifySelf)
+                                              .expect("mJustifySelf contains valid flags"))
+    }
+
     pub fn set_align_items(&mut self, v: longhands::align_items::computed_value::T) {
         self.gecko.mAlignItems = v.0.bits()
     }
 
     ${impl_simple_copy('align_items', 'mAlignItems')}
 
     pub fn clone_align_items(&self) -> longhands::align_items::computed_value::T {
         use values::specified::align::{AlignFlags, AlignItems};
@@ -1142,16 +1164,25 @@ fn static_assert() {
         // TODO: guess what to do with box-sizing: padding-box
         self.gecko.mBoxSizing = match v {
             T::content_box => StyleBoxSizing::Content,
             T::border_box => StyleBoxSizing::Border
         }
     }
     ${impl_simple_copy('box_sizing', 'mBoxSizing')}
 
+    pub fn clone_box_sizing(&self) -> longhands::box_sizing::computed_value::T {
+        use computed_values::box_sizing::T;
+        use gecko_bindings::structs::StyleBoxSizing;
+        match self.gecko.mBoxSizing {
+            StyleBoxSizing::Content => T::content_box,
+            StyleBoxSizing::Border => T::border_box
+        }
+    }
+
     pub fn set_order(&mut self, v: longhands::order::computed_value::T) {
         self.gecko.mOrder = v;
     }
 
     pub fn clone_order(&self) -> longhands::order::computed_value::T {
         self.gecko.mOrder
     }
 
@@ -1170,16 +1201,26 @@ fn static_assert() {
         }).unwrap_or(0);
     }
 
     pub fn copy_${value.name}_from(&mut self, other: &Self) {
         self.gecko.${value.gecko}.mHasSpan = other.gecko.${value.gecko}.mHasSpan;
         self.gecko.${value.gecko}.mInteger = other.gecko.${value.gecko}.mInteger;
         self.gecko.${value.gecko}.mLineName.assign(&*other.gecko.${value.gecko}.mLineName);
     }
+
+    pub fn clone_${value.name}(&self) -> longhands::${value.name}::computed_value::T {
+        use computed_values::${value.name}::T;
+
+        T {
+            is_span: self.gecko.${value.gecko}.mHasSpan,
+            ident: Some(self.gecko.${value.gecko}.mLineName.to_string()),
+            integer: Some(self.gecko.${value.gecko}.mInteger),
+        }
+    }
     % endfor
 
     % for kind in ["rows", "columns"]:
     pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_rows::computed_value::T) {
         use values::specified::grid::TrackSize;
 
         match v {
             TrackSize::FitContent(lop) => {
@@ -1200,16 +1241,34 @@ fn static_assert() {
             },
         }
     }
 
     pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) {
         self.gecko.mGridAuto${kind.title()}Min.copy_from(&other.gecko.mGridAuto${kind.title()}Min);
         self.gecko.mGridAuto${kind.title()}Max.copy_from(&other.gecko.mGridAuto${kind.title()}Max);
     }
+
+    pub fn clone_grid_auto_${kind}(&self) -> longhands::grid_auto_rows::computed_value::T {
+        use gecko_bindings::structs::root::nsStyleUnit::eStyleUnit_None;
+        use values::specified::grid::{TrackSize, TrackBreadth};
+        use values::computed::length::LengthOrPercentage;
+        let ref min = self.gecko.mGridAuto${kind.title()}Min;
+        let ref max = self.gecko.mGridAuto${kind.title()}Max;
+
+        if min.unit() == eStyleUnit_None {
+            debug_assert!(max.unit() != eStyleUnit_None);
+            TrackSize::FitContent(LengthOrPercentage::from_gecko_style_coord(max).unwrap())
+        } else if min == max {
+            TrackSize::Breadth(TrackBreadth::from_gecko_style_coord(max).unwrap())
+        } else {
+            TrackSize::MinMax(TrackBreadth::from_gecko_style_coord(min).unwrap(),
+                              TrackBreadth::from_gecko_style_coord(max).unwrap())
+        }
+    }
     % endfor
 
     pub fn set_grid_auto_flow(&mut self, v: longhands::grid_auto_flow::computed_value::T) {
         use gecko_bindings::structs::NS_STYLE_GRID_AUTO_FLOW_ROW;
         use gecko_bindings::structs::NS_STYLE_GRID_AUTO_FLOW_COLUMN;
         use gecko_bindings::structs::NS_STYLE_GRID_AUTO_FLOW_DENSE;
         use properties::longhands::grid_auto_flow::computed_value::AutoFlow::{Row, Column};
 
@@ -1223,16 +1282,30 @@ fn static_assert() {
         self.gecko.mGridAutoFlow |= value as u8;
 
         if v.dense {
             self.gecko.mGridAutoFlow |= NS_STYLE_GRID_AUTO_FLOW_DENSE as u8;
         }
     }
 
     ${impl_simple_copy('grid_auto_flow', 'mGridAutoFlow')}
+
+    pub fn clone_grid_auto_flow(&self) -> longhands::grid_auto_flow::computed_value::T {
+        use computed_values::grid_auto_flow::T;
+        use gecko_bindings::structs::NS_STYLE_GRID_AUTO_FLOW_ROW;
+        use gecko_bindings::structs::NS_STYLE_GRID_AUTO_FLOW_DENSE;
+        use properties::longhands::grid_auto_flow::computed_value::AutoFlow::{Row, Column};
+
+        let auto_flow_row:u8 = NS_STYLE_GRID_AUTO_FLOW_ROW as u8;
+        let auto_flow_dence:u8 = NS_STYLE_GRID_AUTO_FLOW_DENSE as u8;
+        T {
+            autoflow: if self.gecko.mGridAutoFlow & auto_flow_row == auto_flow_row { Row } else { Column },
+            dense: self.gecko.mGridAutoFlow & auto_flow_dence == auto_flow_dence,
+        }
+    }
 </%self:impl_trait>
 
 <% skip_outline_longhands = " ".join("outline-style outline-width".split() +
                                      ["-moz-outline-radius-{0}".format(x.ident.replace("_", ""))
                                       for x in CORNERS]) %>
 <%self:impl_trait style_struct_name="Outline"
                   skip_longhands="${skip_outline_longhands}"
                   skip_additionals="*">
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -344,17 +344,17 @@ impl AnimatedProperty {
     /// animation at `progress`.
     pub fn update(&self, style: &mut ComputedValues, progress: f64) {
         match *self {
             % for prop in data.longhands:
                 % if prop.animatable:
                     AnimatedProperty::${prop.camel_case}(ref from, ref to) => {
                         // https://w3c.github.io/web-animations/#discrete-animation-type
                         % if prop.animation_value_type == "discrete":
-                            let value = if progress < 0.5 { *from } else { *to };
+                            let value = if progress < 0.5 { from.clone() } else { to.clone() };
                         % else:
                             let value = match from.interpolate(to, progress) {
                                 Ok(value) => value,
                                 Err(()) => return,
                             };
                         % endif
                         style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value);
                     }
@@ -586,19 +586,19 @@ impl Interpolate for AnimationValue {
         match (self, other) {
             % for prop in data.longhands:
                 % if prop.animatable:
                     (&AnimationValue::${prop.camel_case}(ref from),
                      &AnimationValue::${prop.camel_case}(ref to)) => {
                         // https://w3c.github.io/web-animations/#discrete-animation-type
                         % if prop.animation_value_type == "discrete":
                             if progress < 0.5 {
-                                Ok(AnimationValue::${prop.camel_case}(*from))
+                                Ok(AnimationValue::${prop.camel_case}(from.clone()))
                             } else {
-                                Ok(AnimationValue::${prop.camel_case}(*to))
+                                Ok(AnimationValue::${prop.camel_case}(to.clone()))
                             }
                         % else:
                             from.interpolate(to, progress).map(AnimationValue::${prop.camel_case})
                         % endif
                     }
                 % endif
             % endfor
             _ => {
--- a/servo/components/style/properties/longhand/position.mako.rs
+++ b/servo/components/style/properties/longhand/position.mako.rs
@@ -32,69 +32,69 @@
 
 
 // CSS Flexible Box Layout Module Level 1
 // http://www.w3.org/TR/css3-flexbox/
 
 // Flex container properties
 ${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property",
-                         extra_prefixes="webkit", animation_value_type="none")}
+                         extra_prefixes="webkit", animation_value_type="discrete")}
 
 ${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property",
-                         extra_prefixes="webkit", animation_value_type="none")}
+                         extra_prefixes="webkit", animation_value_type="discrete")}
 
 % if product == "servo":
     // FIXME: Update Servo to support the same Syntax as Gecko.
     ${helpers.single_keyword("justify-content", "flex-start stretch flex-end center space-between space-around",
                              extra_prefixes="webkit",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
-                             animation_value_type="none")}
+                             animation_value_type="discrete")}
 % else:
     ${helpers.predefined_type(name="justify-content",
                               type="AlignJustifyContent",
                               initial_value="specified::AlignJustifyContent::normal()",
                               spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                               extra_prefixes="webkit",
-                              animation_value_type="none")}
+                              animation_value_type="discrete")}
 % endif
 
 % if product == "servo":
     // FIXME: Update Servo to support the same Syntax as Gecko.
     ${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around",
                              extra_prefixes="webkit",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-content",
-                             animation_value_type="none")}
+                             animation_value_type="discrete")}
 
     ${helpers.single_keyword("align-items",
                              "stretch flex-start flex-end center baseline",
                              extra_prefixes="webkit",
                              spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
                              animation_value_type="discrete")}
 % else:
     ${helpers.predefined_type(name="align-content",
                               type="AlignJustifyContent",
                               initial_value="specified::AlignJustifyContent::normal()",
                               spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                               extra_prefixes="webkit",
-                              animation_value_type="none")}
+                              animation_value_type="discrete")}
 
     ${helpers.predefined_type(name="align-items",
                               type="AlignItems",
                               initial_value="specified::AlignItems::normal()",
                               spec="https://drafts.csswg.org/css-align/#propdef-align-items",
                               extra_prefixes="webkit",
                               animation_value_type="discrete")}
 
     ${helpers.predefined_type(name="justify-items",
                               type="JustifyItems",
                               initial_value="specified::JustifyItems::auto()",
                               spec="https://drafts.csswg.org/css-align/#propdef-justify-items",
-                              animation_value_type="none")}
+                              animation_value_type="discrete")}
 % endif
 
 // Flex item properties
 ${helpers.predefined_type("flex-grow", "Number",
                           "0.0", "parse_non_negative",
                           spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
                           extra_prefixes="webkit",
                           animation_value_type="ComputedValue")}
@@ -107,30 +107,30 @@
 
 // https://drafts.csswg.org/css-align/#align-self-property
 % if product == "servo":
     // FIXME: Update Servo to support the same syntax as Gecko.
     ${helpers.single_keyword("align-self", "auto stretch flex-start flex-end center baseline",
                              need_clone=True,
                              extra_prefixes="webkit",
                              spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
-                             animation_value_type="none")}
+                             animation_value_type="discrete")}
 % else:
     ${helpers.predefined_type(name="align-self",
                               type="AlignJustifySelf",
                               initial_value="specified::AlignJustifySelf::auto()",
                               spec="https://drafts.csswg.org/css-align/#align-self-property",
                               extra_prefixes="webkit",
-                              animation_value_type="none")}
+                              animation_value_type="discrete")}
 
     ${helpers.predefined_type(name="justify-self",
                               type="AlignJustifySelf",
                               initial_value="specified::AlignJustifySelf::auto()",
                               spec="https://drafts.csswg.org/css-align/#justify-self-property",
-                              animation_value_type="none")}
+                              animation_value_type="discrete")}
 % endif
 
 // https://drafts.csswg.org/css-flexbox/#propdef-order
 ${helpers.predefined_type("order", "Integer", "0",
                           extra_prefixes="webkit",
                           animation_value_type="ComputedValue",
                           spec="https://drafts.csswg.org/css-flexbox/#order-property")}
 
@@ -273,20 +273,20 @@
                                   allow_quirks=not logical)}
     % endif
 % endfor
 
 ${helpers.single_keyword("box-sizing",
                          "content-box border-box",
                          extra_prefixes="moz webkit",
                          spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
-                         animation_value_type="none")}
+                         animation_value_type="discrete")}
 
 ${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
-                         products="gecko", animation_value_type="none",
+                         products="gecko", animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-images/#propdef-object-fit")}
 
 ${helpers.predefined_type("object-position",
                           "Position",
                           "computed::Position::zero()",
                           products="gecko",
                           boxed="True",
                           spec="https://drafts.csswg.org/css-images-3/#the-object-position",
@@ -299,37 +299,37 @@
                               spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind,
                               animation_value_type="ComputedValue",
                               products="gecko")}
 
     % for range in ["start", "end"]:
         ${helpers.predefined_type("grid-%s-%s" % (kind, range),
                                   "GridLine",
                                   "Default::default()",
-                                  animation_value_type="none",
+                                  animation_value_type="discrete",
                                   spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
                                   products="gecko",
                                   boxed=True)}
     % endfor
 
     // NOTE: According to the spec, this should handle multiple values of `<track-size>`,
     // but gecko supports only a single value
     ${helpers.predefined_type("grid-auto-%ss" % kind,
                               "TrackSize",
                               "Default::default()",
-                              animation_value_type="none",
+                              animation_value_type="discrete",
                               spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
                               products="gecko",
                               boxed=True)}
 % endfor
 
 <%helpers:longhand name="grid-auto-flow"
         spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow"
         products="gecko"
-        animation_value_type="none">
+        animation_value_type="discrete">
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
     use values::computed::ComputedValueAsSpecified;
 
     pub type SpecifiedValue = computed_value::T;
 
     pub mod computed_value {
--- a/servo/components/style/values/specified/align.rs
+++ b/servo/components/style/values/specified/align.rs
@@ -110,17 +110,17 @@ const ALIGN_ALL_SHIFT: u32 = structs::NS
 /// Value of the `align-content` or `justify-content` property.
 ///
 /// https://drafts.csswg.org/css-align/#content-distribution
 ///
 /// The 16-bit field stores the primary value in its lower 8 bits, and the optional fallback value
 /// in its upper 8 bits.  This matches the representation of these properties in Gecko.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
-pub struct AlignJustifyContent(u16);
+pub struct AlignJustifyContent(pub u16);
 
 impl AlignJustifyContent {
     /// The initial value 'normal'
     #[inline]
     pub fn normal() -> Self {
         Self::new(ALIGN_NORMAL)
     }