Bug 1420928 - Shrink array for StyleAnimation and StyleTransition if possible. r?boris
MozReview-Commit-ID: 6wFdsx7NyOk
--- 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,
}
}
}