Bug 1420928 - Shrink array for StyleAnimation and StyleTransition if possible. r?boris draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Thu, 04 Jan 2018 18:27:11 +0900
changeset 715635 1fc45251c115b7eb7cdf816dd2b7b8a293dd4966
parent 715634 7a02da7c2222802abee9c746e6c934fd7b75aeb5
child 715636 81bef384f7029fc1e2f997e78b75371d25080c35
push id94212
push userhikezoe@mozilla.com
push dateThu, 04 Jan 2018 09:34:32 +0000
reviewersboris
bugs1420928
milestone59.0a1
Bug 1420928 - Shrink array for StyleAnimation and StyleTransition if possible. r?boris MozReview-Commit-ID: 6wFdsx7NyOk
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs
servo/components/style/properties/gecko.mako.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1799,41 +1799,41 @@ Gecko_EnsureImageLayersLength(nsStyleIma
 
   for (size_t i = oldLength; i < aLen; ++i) {
     aLayers->mLayers[i].Initialize(aLayerType);
   }
 }
 
 template <typename StyleType>
 static void
-EnsureStyleAutoArrayLength(StyleType* aArray, size_t aLen)
+SetStyleAutoArrayLength(StyleType* aArray, size_t aLen)
 {
   size_t oldLength = aArray->Length();
 
-  aArray->EnsureLengthAtLeast(aLen);
+  aArray->SetLengthNonZero(aLen);
 
   for (size_t i = oldLength; i < aLen; ++i) {
     (*aArray)[i].SetInitialValues();
   }
 }
 
 void
-Gecko_EnsureStyleAnimationArrayLength(void* aArray, size_t aLen)
+Gecko_SetStyleAnimationArrayLength(void* aArray, size_t aLen)
 {
   auto base =
     static_cast<nsStyleAutoArray<StyleAnimation>*>(aArray);
-  EnsureStyleAutoArrayLength(base, aLen);
+  SetStyleAutoArrayLength(base, aLen);
 }
 
 void
-Gecko_EnsureStyleTransitionArrayLength(void* aArray, size_t aLen)
+Gecko_SetStyleTransitionArrayLength(void* aArray, size_t aLen)
 {
   auto base =
     reinterpret_cast<nsStyleAutoArray<StyleTransition>*>(aArray);
-  EnsureStyleAutoArrayLength(base, aLen);
+  SetStyleAutoArrayLength(base, aLen);
 }
 
 void
 Gecko_ClearWillChange(nsStyleDisplay* aDisplay, size_t aLength)
 {
   aDisplay->mWillChange.Clear();
   aDisplay->mWillChange.SetCapacity(aLength);
 }
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -456,18 +456,18 @@ void Gecko_ClearAndResizeCounterResets(n
                                        uint32_t how_many);
 void Gecko_CopyStyleContentsFrom(nsStyleContent* content, const nsStyleContent* other);
 void Gecko_CopyCounterResetsFrom(nsStyleContent* content, const nsStyleContent* other);
 void Gecko_CopyCounterIncrementsFrom(nsStyleContent* content, const nsStyleContent* other);
 
 void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len,
                                    nsStyleImageLayers::LayerType layer_type);
 
-void Gecko_EnsureStyleAnimationArrayLength(void* array, size_t len);
-void Gecko_EnsureStyleTransitionArrayLength(void* array, size_t len);
+void Gecko_SetStyleAnimationArrayLength(void* array, size_t len);
+void Gecko_SetStyleTransitionArrayLength(void* array, size_t len);
 
 void Gecko_ClearWillChange(nsStyleDisplay* display, size_t length);
 void Gecko_AppendWillChange(nsStyleDisplay* display, nsAtom* atom);
 void Gecko_CopyWillChangeFrom(nsStyleDisplay* dest, nsStyleDisplay* src);
 
 // Searches from the beginning of |keyframes| for a Keyframe object with the
 // specified offset and timing function. If none is found, a new Keyframe object
 // with the specified |offset| and |timingFunction| will be prepended to
--- a/servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Rust helpers for Gecko's `nsStyleAutoArray`.
 
-use gecko_bindings::bindings::Gecko_EnsureStyleAnimationArrayLength;
-use gecko_bindings::bindings::Gecko_EnsureStyleTransitionArrayLength;
+use gecko_bindings::bindings::Gecko_SetStyleAnimationArrayLength;
+use gecko_bindings::bindings::Gecko_SetStyleTransitionArrayLength;
 use gecko_bindings::structs::{StyleAnimation, StyleTransition};
 use gecko_bindings::structs::nsStyleAutoArray;
 use std::iter::{once, Chain, Once, IntoIterator};
 use std::ops::{Index, IndexMut};
 use std::slice::{Iter, IterMut};
 
 impl<T> Index<usize> for nsStyleAutoArray<T> {
     type Output = T;
@@ -47,29 +47,29 @@ impl<T> nsStyleAutoArray<T> {
     /// Note that often structs containing autoarrays will have additional
     /// member fields that contain the length, which must be kept in sync.
     pub fn len(&self) -> usize {
         1 + self.mOtherElements.len()
     }
 }
 
 impl nsStyleAutoArray<StyleAnimation> {
-    /// Ensures that the array has length at least the given length.
-    pub fn ensure_len(&mut self, len: usize) {
+    /// Resize the array length to the given length.
+    pub fn set_len(&mut self, len: usize) {
         unsafe {
-            Gecko_EnsureStyleAnimationArrayLength(self as *mut nsStyleAutoArray<StyleAnimation> as *mut _, len);
+            Gecko_SetStyleAnimationArrayLength(self as *mut nsStyleAutoArray<StyleAnimation> as *mut _, len);
         }
     }
 }
 
 impl nsStyleAutoArray<StyleTransition> {
-    /// Ensures that the array has length at least the given length.
-    pub fn ensure_len(&mut self, len: usize) {
+    /// Resize the array length to the given length.
+    pub fn set_len(&mut self, len: usize) {
         unsafe {
-            Gecko_EnsureStyleTransitionArrayLength(self as *mut nsStyleAutoArray<StyleTransition> as *mut _, len);
+            Gecko_SetStyleTransitionArrayLength(self as *mut nsStyleAutoArray<StyleTransition> as *mut _, len);
         }
     }
 }
 
 impl<'a, T> IntoIterator for &'a mut nsStyleAutoArray<T> {
     type Item = &'a mut T;
     type IntoIter = Chain<Once<&'a mut T>, IterMut<'a, T>>;
     fn into_iter(self) -> Self::IntoIter {
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -2938,21 +2938,22 @@ fn static_assert() {
     }
 
     ${impl_simple_copy('_moz_min_font_size_ratio', 'mMinFontSizeRatio')}
 </%self:impl_trait>
 
 <%def name="impl_copy_animation_or_transition_value(type, ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn copy_${type}_${ident}_from(&mut self, other: &Self) {
-        self.gecko.m${type.capitalize()}s.ensure_len(other.gecko.m${type.capitalize()}s.len());
-
         let count = other.gecko.m${type.capitalize()}${gecko_ffi_name}Count;
         self.gecko.m${type.capitalize()}${gecko_ffi_name}Count = count;
 
+        let max = self.max_${type}_property_count();
+        self.gecko.m${type.capitalize()}s.set_len(max);
+
         let iter = self.gecko.m${type.capitalize()}s.iter_mut().take(count as usize).zip(
             other.gecko.m${type.capitalize()}s.iter()
         );
 
         for (ours, others) in iter {
             ours.m${gecko_ffi_name} = others.m${gecko_ffi_name};
         }
     }
@@ -2974,19 +2975,22 @@ fn static_assert() {
     #[allow(non_snake_case)]
     pub fn set_${type}_${ident}<I>(&mut self, v: I)
         where I: IntoIterator<Item = longhands::${type}_${ident}::computed_value::single_value::T>,
               I::IntoIter: ExactSizeIterator + Clone
     {
         let v = v.into_iter();
         debug_assert!(v.len() != 0);
         let input_len = v.len();
-        self.gecko.m${type.capitalize()}s.ensure_len(input_len);
 
         self.gecko.m${type.capitalize()}${gecko_ffi_name}Count = input_len as u32;
+
+        let max = self.max_${type}_property_count();
+        self.gecko.m${type.capitalize()}s.set_len(max);
+
         for (gecko, servo) in self.gecko.m${type.capitalize()}s.iter_mut().take(input_len as usize).zip(v) {
             gecko.m${gecko_ffi_name} = servo.seconds() * 1000.;
         }
     }
     #[allow(non_snake_case)]
     pub fn ${type}_${ident}_at(&self, index: usize)
         -> longhands::${type}_${ident}::computed_value::SingleComputedValue {
         use values::computed::Time;
@@ -2999,19 +3003,21 @@ fn static_assert() {
 <%def name="impl_animation_or_transition_timing_function(type)">
     pub fn set_${type}_timing_function<I>(&mut self, v: I)
         where I: IntoIterator<Item = longhands::${type}_timing_function::computed_value::single_value::T>,
               I::IntoIter: ExactSizeIterator + Clone
     {
         let v = v.into_iter();
         debug_assert!(v.len() != 0);
         let input_len = v.len();
-        self.gecko.m${type.capitalize()}s.ensure_len(input_len);
-
         self.gecko.m${type.capitalize()}TimingFunctionCount = input_len as u32;
+
+        let max = self.max_${type}_property_count();
+        self.gecko.m${type.capitalize()}s.set_len(max);
+
         for (gecko, servo) in self.gecko.m${type.capitalize()}s.iter_mut().take(input_len as usize).zip(v) {
             gecko.mTimingFunction = servo.into();
         }
     }
     ${impl_animation_or_transition_count(type, 'timing_function', 'TimingFunction')}
     ${impl_copy_animation_or_transition_value(type, 'timing_function', 'TimingFunction')}
     pub fn ${type}_timing_function_at(&self, index: usize)
         -> longhands::${type}_timing_function::computed_value::SingleComputedValue {
@@ -3055,20 +3061,21 @@ fn static_assert() {
     {
         use properties::longhands::animation_${ident}::single_value::computed_value::T as Keyword;
         use gecko_bindings::structs;
 
         let v = v.into_iter();
 
         debug_assert!(v.len() != 0);
         let input_len = v.len();
-        self.gecko.mAnimations.ensure_len(input_len);
-
         self.gecko.mAnimation${gecko_ffi_name}Count = input_len as u32;
 
+        let max = self.max_animation_property_count();
+        self.gecko.mAnimations.set_len(max);
+
         for (gecko, servo) in self.gecko.mAnimations.iter_mut().take(input_len as usize).zip(v) {
             let result = match servo {
                 % for value in keyword.gecko_values():
                     Keyword::${to_camel_case(value)} =>
                         structs::${keyword.gecko_constant(value)} ${keyword.maybe_cast(cast_type)},
                 % endfor
             };
             gecko.m${gecko_ffi_name} = result;
@@ -3297,27 +3304,36 @@ fn static_assert() {
     ${impl_transition_timing_function()}
 
     pub fn transition_combined_duration_at(&self, index: usize) -> f32 {
         // https://drafts.csswg.org/css-transitions/#transition-combined-duration
         self.gecko.mTransitions[index % self.gecko.mTransitionDurationCount as usize].mDuration.max(0.0)
             + self.gecko.mTransitions[index % self.gecko.mTransitionDelayCount as usize].mDelay
     }
 
+    fn max_transition_property_count(&self) -> usize {
+        *([ self.gecko.mTransitionPropertyCount,
+            self.gecko.mTransitionDelayCount,
+            self.gecko.mTransitionDurationCount,
+            self.gecko.mTransitionTimingFunctionCount,
+          ].iter().max().unwrap_or(&1)) as usize
+    }
+
     pub fn set_transition_property<I>(&mut self, v: I)
         where I: IntoIterator<Item = longhands::transition_property::computed_value::single_value::T>,
               I::IntoIter: ExactSizeIterator
     {
         use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_no_properties;
 
         let v = v.into_iter();
 
         if v.len() != 0 {
-            self.gecko.mTransitions.ensure_len(v.len());
             self.gecko.mTransitionPropertyCount = v.len() as u32;
+            let max = self.max_transition_property_count();
+            self.gecko.mTransitions.set_len(max);
             for (servo, gecko) in v.zip(self.gecko.mTransitions.iter_mut()) {
                 match servo {
                     TransitionProperty::Unsupported(ref ident) => unsafe {
                         Gecko_StyleTransition_SetUnsupportedProperty(gecko, ident.0.as_ptr())
                     },
                     _ => gecko.mProperty = servo.to_nscsspropertyid().unwrap(),
                 }
             }
@@ -3362,21 +3378,23 @@ fn static_assert() {
 
     pub fn transition_nscsspropertyid_at(&self, index: usize) -> nsCSSPropertyID {
         self.gecko.mTransitions[index].mProperty
     }
 
     pub fn copy_transition_property_from(&mut self, other: &Self) {
         use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_variable;
         use gecko_bindings::structs::nsCSSPropertyID::eCSSProperty_UNKNOWN;
-        self.gecko.mTransitions.ensure_len(other.gecko.mTransitions.len());
 
         let count = other.gecko.mTransitionPropertyCount;
         self.gecko.mTransitionPropertyCount = count;
 
+        let max = self.max_transition_property_count();
+        self.gecko.mTransitions.set_len(max);
+
         for (index, transition) in self.gecko.mTransitions.iter_mut().enumerate().take(count as usize) {
             transition.mProperty = other.gecko.mTransitions[index].mProperty;
             if transition.mProperty == eCSSProperty_UNKNOWN ||
                transition.mProperty == eCSSPropertyExtra_variable {
                 let atom = other.gecko.mTransitions[index].mUnknownProperty.mRawPtr;
                 debug_assert!(!atom.is_null());
                 unsafe { Gecko_StyleTransition_SetUnsupportedProperty(transition, atom) };
             }
@@ -3396,25 +3414,39 @@ fn static_assert() {
             && self.gecko.mAnimationDurationCount == other.gecko.mAnimationDurationCount
             && self.gecko.mAnimationFillModeCount == other.gecko.mAnimationFillModeCount
             && self.gecko.mAnimationIterationCountCount == other.gecko.mAnimationIterationCountCount
             && self.gecko.mAnimationPlayStateCount == other.gecko.mAnimationPlayStateCount
             && self.gecko.mAnimationTimingFunctionCount == other.gecko.mAnimationTimingFunctionCount
             && unsafe { bindings::Gecko_StyleAnimationsEquals(&self.gecko.mAnimations, &other.gecko.mAnimations) }
     }
 
+    fn max_animation_property_count(&self) -> usize {
+        *([ self.gecko.mAnimationNameCount,
+            self.gecko.mAnimationDelayCount,
+            self.gecko.mAnimationDirectionCount,
+            self.gecko.mAnimationDurationCount,
+            self.gecko.mAnimationFillModeCount,
+            self.gecko.mAnimationIterationCountCount,
+            self.gecko.mAnimationPlayStateCount,
+            self.gecko.mAnimationTimingFunctionCount,
+          ].iter().max().unwrap_or(&1)) as usize
+    }
+
     pub fn set_animation_name<I>(&mut self, v: I)
         where I: IntoIterator<Item = longhands::animation_name::computed_value::single_value::T>,
               I::IntoIter: ExactSizeIterator
     {
         let v = v.into_iter();
         debug_assert!(v.len() != 0);
-        self.gecko.mAnimations.ensure_len(v.len());
-
         self.gecko.mAnimationNameCount = v.len() as u32;
+
+        let max = self.max_animation_property_count();
+        self.gecko.mAnimations.set_len(max);
+
         for (servo, gecko) in v.zip(self.gecko.mAnimations.iter_mut()) {
             let atom = match servo.0 {
                 None => atom!(""),
                 Some(ref name) => name.as_atom().clone(),
             };
             unsafe { bindings::Gecko_SetAnimationName(gecko, atom.into_addrefed()); }
         }
     }
@@ -3457,19 +3489,20 @@ fn static_assert() {
     {
         use std::f32;
         use values::generics::box_::AnimationIterationCount;
 
         let v = v.into_iter();
 
         debug_assert_ne!(v.len(), 0);
         let input_len = v.len();
-        self.gecko.mAnimations.ensure_len(input_len);
-
         self.gecko.mAnimationIterationCountCount = input_len as u32;
+        let max = self.max_animation_property_count();
+        self.gecko.mAnimations.set_len(max);
+
         for (gecko, servo) in self.gecko.mAnimations.iter_mut().take(input_len as usize).zip(v) {
             match servo {
                 AnimationIterationCount::Number(n) => gecko.mIterationCount = n,
                 AnimationIterationCount::Infinite => gecko.mIterationCount = f32::INFINITY,
             }
         }
     }