diff --git a/components/style/gecko_bindings/sugar/ns_css_value.rs b/components/style/gecko_bindings/sugar/ns_css_value.rs index 0f91fc4f27a..3a2cf439711 100644 --- a/components/style/gecko_bindings/sugar/ns_css_value.rs +++ b/components/style/gecko_bindings/sugar/ns_css_value.rs @@ -8,8 +8,9 @@ use app_units::Au; use gecko_bindings::bindings; use gecko_bindings::structs; use gecko_bindings::structs::{nsCSSValue, nsCSSUnit}; -use gecko_bindings::structs::{nsCSSValue_Array, nscolor}; +use gecko_bindings::structs::{nsCSSValue_Array, nsCSSValueList, nscolor}; use gecko_string_cache::Atom; +use std::marker::PhantomData; use std::mem; use std::ops::{Index, IndexMut}; use std::slice; @@ -225,19 +226,17 @@ impl nsCSSValue { /// Set to a list value /// /// This is only supported on the main thread. - pub fn set_list(&mut self, mut values: I) where I: ExactSizeIterator { + pub fn set_list(&mut self, values: I) where I: ExactSizeIterator { debug_assert!(values.len() > 0, "Empty list is not supported"); unsafe { bindings::Gecko_CSSValue_SetList(self, values.len() as u32); } debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_List); - let mut item_ptr = &mut unsafe { + let list: &mut structs::nsCSSValueList = &mut unsafe { self.mValue.mList.as_ref() // &*nsCSSValueList_heap .as_mut().expect("List pointer should be non-null") - }._base as *mut structs::nsCSSValueList; - while let Some(item) = unsafe { item_ptr.as_mut() } { - item.mValue = values.next().expect("Values shouldn't have been exhausted"); - item_ptr = item.mNext; + }._base; + for (item, new_value) in list.into_iter().zip(values) { + *item = new_value; } - debug_assert!(values.next().is_none(), "Values should have been exhausted"); } /// Set to a pair list value @@ -268,6 +267,64 @@ impl Drop for nsCSSValue { } } +/// Iterator of nsCSSValueList. +#[allow(non_camel_case_types)] +pub struct nsCSSValueListIterator<'a> { + current: Option<&'a nsCSSValueList>, +} + +impl<'a> Iterator for nsCSSValueListIterator<'a> { + type Item = &'a nsCSSValue; + fn next(&mut self) -> Option { + match self.current { + Some(item) => { + self.current = unsafe { item.mNext.as_ref() }; + Some(&item.mValue) + }, + None => None + } + } +} + +impl<'a> IntoIterator for &'a nsCSSValueList { + type Item = &'a nsCSSValue; + type IntoIter = nsCSSValueListIterator<'a>; + + fn into_iter(self) -> Self::IntoIter { + nsCSSValueListIterator { current: Some(self) } + } +} + +/// Mutable Iterator of nsCSSValueList. +#[allow(non_camel_case_types)] +pub struct nsCSSValueListMutIterator<'a> { + current: *mut nsCSSValueList, + phantom: PhantomData<&'a mut nsCSSValue>, +} + +impl<'a> Iterator for nsCSSValueListMutIterator<'a> { + type Item = &'a mut nsCSSValue; + fn next(&mut self) -> Option { + match unsafe { self.current.as_mut() } { + Some(item) => { + self.current = item.mNext; + Some(&mut item.mValue) + }, + None => None + } + } +} + +impl<'a> IntoIterator for &'a mut nsCSSValueList { + type Item = &'a mut nsCSSValue; + type IntoIter = nsCSSValueListMutIterator<'a>; + + fn into_iter(self) -> Self::IntoIter { + nsCSSValueListMutIterator { current: self as *mut nsCSSValueList, + phantom: PhantomData } + } +} + impl nsCSSValue_Array { /// Return the length of this `nsCSSValue::Array` #[inline] diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 50b354c7dbd..9f9b5443a0a 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2307,7 +2307,7 @@ fn static_assert() { bindings::Gecko_CSSValue_SetFunction(gecko_value, ${len(items) + 1}); bindings::Gecko_CSSValue_SetKeyword( bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0), - eCSSKeyword_${keyword} + structs::nsCSSKeyword::eCSSKeyword_${keyword} ); % for index, item in enumerate(items): ${css_value_setters[item] % ( @@ -2317,47 +2317,46 @@ fn static_assert() { % endfor } - pub fn convert_transform(input: &[longhands::transform::computed_value::ComputedOperation], - output: &mut structs::root::RefPtr) { - use gecko_bindings::structs::nsCSSKeyword::*; - use gecko_bindings::sugar::refptr::RefPtr; + fn set_single_transform_function(servo_value: &longhands::transform::computed_value::ComputedOperation, + gecko_value: &mut structs::nsCSSValue /* output */) { use properties::longhands::transform::computed_value::ComputedMatrix; use properties::longhands::transform::computed_value::ComputedMatrixWithPercents; + unsafe { + match *servo_value { + ${transform_function_arm("Matrix", "matrix3d", ["number"] * 16)} + ${transform_function_arm("MatrixWithPercents", "matrix3d", ["number"] * 12 + ["lop"] * 2 + + ["length"] + ["number"])} + ${transform_function_arm("Skew", "skew", ["angle"] * 2)} + ${transform_function_arm("Translate", "translate3d", ["lop", "lop", "length"])} + ${transform_function_arm("Scale", "scale3d", ["number"] * 3)} + ${transform_function_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])} + ${transform_function_arm("Perspective", "perspective", ["length"])} + _ => { + // TODO: Convert ComputedOperation::InterpolateMatrix into + // eCSSKeyword_interpolatematrix, and convert + // ComputedOperation::AccumulateMatrix into + // eCSSKeyword_accumulatematrix in the patch series. + gecko_value.mUnit = structs::nsCSSUnit::eCSSUnit_None; + } + } + } + } + pub fn convert_transform(input: &[longhands::transform::computed_value::ComputedOperation], + output: &mut structs::root::RefPtr) { + use gecko_bindings::sugar::refptr::RefPtr; + unsafe { output.clear() }; let list = unsafe { RefPtr::from_addrefed(bindings::Gecko_NewCSSValueSharedList(input.len() as u32)) }; - - let mut cur = list.mHead; - let mut iter = input.into_iter(); - while !cur.is_null() { - let gecko_value = unsafe { &mut (*cur).mValue }; - let servo = iter.next().expect("Gecko_NewCSSValueSharedList should create a shared \ - value list of the same length as the transform vector"); - unsafe { - match *servo { - ${transform_function_arm("Matrix", "matrix3d", ["number"] * 16)} - ${transform_function_arm("MatrixWithPercents", "matrix3d", ["number"] * 12 + ["lop"] * 2 - + ["length"] + ["number"])} - ${transform_function_arm("Skew", "skew", ["angle"] * 2)} - ${transform_function_arm("Translate", "translate3d", ["lop", "lop", "length"])} - ${transform_function_arm("Scale", "scale3d", ["number"] * 3)} - ${transform_function_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])} - ${transform_function_arm("Perspective", "perspective", ["length"])} - _ => { - // TODO: Convert ComputedOperation::InterpolateMatrix into - // eCSSKeyword_interpolatematrix, and convert - // ComputedOperation::AccumulateMatrix into - // eCSSKeyword_accumulatematrix in the patch series. - gecko_value.mUnit = structs::nsCSSUnit::eCSSUnit_None; - } - } - cur = (*cur).mNext; + let value_list = unsafe { list.mHead.as_mut() }; + if let Some(value_list) = value_list { + for (gecko, servo) in value_list.into_iter().zip(input.into_iter()) { + Self::set_single_transform_function(servo, gecko); } } - debug_assert!(iter.next().is_none()); unsafe { output.set_move(list) }; } @@ -2387,7 +2386,7 @@ fn static_assert() { "number" : "bindings::Gecko_CSSValue_GetNumber(%s)", } %> - eCSSKeyword_${keyword} => { + structs::nsCSSKeyword::eCSSKeyword_${keyword} => { ComputedOperation::${name}( % if keyword == "matrix3d": ComputedMatrix { @@ -2406,39 +2405,40 @@ fn static_assert() { ) }, - pub fn clone_transform(&self) -> longhands::transform::computed_value::T { - use app_units::Au; - use gecko_bindings::structs::nsCSSKeyword::*; - use properties::longhands::transform::computed_value; + fn clone_single_transform_function(gecko_value: &structs::nsCSSValue) + -> longhands::transform::computed_value::ComputedOperation { use properties::longhands::transform::computed_value::ComputedMatrix; use properties::longhands::transform::computed_value::ComputedOperation; + let transform_function = unsafe { + bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0)) + }; + + unsafe { + match transform_function { + ${computed_operation_arm("Matrix", "matrix3d", ["number"] * 16)} + ${computed_operation_arm("Skew", "skew", ["angle"] * 2)} + ${computed_operation_arm("Translate", "translate3d", ["lop", "lop", "length"])} + ${computed_operation_arm("Scale", "scale3d", ["number"] * 3)} + ${computed_operation_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])} + ${computed_operation_arm("Perspective", "perspective", ["length"])} + _ => panic!("We shouldn't set any other transform function types"), + } + } + } + pub fn clone_transform(&self) -> longhands::transform::computed_value::T { + use properties::longhands::transform::computed_value; + if self.gecko.mSpecifiedTransform.mRawPtr.is_null() { return computed_value::T(None); } - - let mut result = vec![]; - let mut cur = unsafe { (*self.gecko.mSpecifiedTransform.to_safe().get()).mHead }; - while !cur.is_null() { - let gecko_value = unsafe { &(*cur).mValue }; - let transform_function = unsafe { - bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0)) - }; - let servo = unsafe { - match transform_function { - ${computed_operation_arm("Matrix", "matrix3d", ["number"] * 16)} - ${computed_operation_arm("Skew", "skew", ["angle"] * 2)} - ${computed_operation_arm("Translate", "translate3d", ["lop", "lop", "length"])} - ${computed_operation_arm("Scale", "scale3d", ["number"] * 3)} - ${computed_operation_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])} - ${computed_operation_arm("Perspective", "perspective", ["length"])} - _ => panic!("We shouldn't set any other transform function types"), - } - }; - result.push(servo); - unsafe { cur = (&*cur).mNext }; - } - computed_value::T(Some(result)) + let list = unsafe { (*self.gecko.mSpecifiedTransform.to_safe().get()).mHead.as_ref() }; + let result = list.map(|list| { + list.into_iter() + .map(|value| Self::clone_single_transform_function(value)) + .collect() + }); + computed_value::T(result) } ${impl_transition_time_value('delay', 'Delay')}