--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -3,18 +3,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Little helpers for `nsCSSValue`.
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;
use values::computed::{Angle, LengthOrPercentage};
use values::specified::url::SpecifiedUrl;
impl nsCSSValue {
/// Create a CSSValue with null unit, useful to be used as a return value.
@@ -220,29 +221,27 @@ impl nsCSSValue {
/// This is only supported on the main thread.
pub fn set_pair(&mut self, x: &nsCSSValue, y: &nsCSSValue) {
unsafe { bindings::Gecko_CSSValue_SetPair(self, x, y) }
}
/// Set to a list value
///
/// This is only supported on the main thread.
- pub fn set_list<I>(&mut self, mut values: I) where I: ExactSizeIterator<Item=nsCSSValue> {
+ pub fn set_list<I>(&mut self, values: I) where I: ExactSizeIterator<Item=nsCSSValue> {
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
///
/// This is only supported on the main thread.
pub fn set_pair_list<I>(&mut self, mut values: I)
where I: ExactSizeIterator<Item=(nsCSSValue, nsCSSValue)> {
debug_assert!(values.len() > 0, "Empty list is not supported");
@@ -263,16 +262,74 @@ impl nsCSSValue {
}
impl Drop for nsCSSValue {
fn drop(&mut self) {
unsafe { bindings::Gecko_CSSValue_Drop(self) };
}
}
+/// 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<Self::Item> {
+ 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<Self::Item> {
+ 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]
pub fn len(&self) -> usize {
self.mCount
}
#[inline]
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -2280,67 +2280,66 @@ fn static_assert() {
"angle" : "%s.set_angle(%s)",
"number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
}
%>
longhands::transform::computed_value::ComputedOperation::${name}(${pattern}) => {
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] % (
"bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d)" % (index + 1),
item + str(index + 1)
)};
% endfor
}
</%def>
+ 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<structs::root::nsCSSValueSharedList>) {
- use gecko_bindings::structs::nsCSSKeyword::*;
use gecko_bindings::sugar::refptr::RefPtr;
- use properties::longhands::transform::computed_value::ComputedMatrix;
- use properties::longhands::transform::computed_value::ComputedMatrixWithPercents;
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) };
}
pub fn set_transform(&mut self, other: longhands::transform::computed_value::T) {
let vec = if let Some(v) = other.0 {
v
} else {
unsafe {
@@ -2360,17 +2359,17 @@ fn static_assert() {
# %s is substituted with the call to GetArrayItem.
css_value_getters = {
"length" : "Au(bindings::Gecko_CSSValue_GetAbsoluteLength(%s))",
"lop" : "%s.get_lop()",
"angle" : "%s.get_angle()",
"number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
}
%>
- eCSSKeyword_${keyword} => {
+ structs::nsCSSKeyword::eCSSKeyword_${keyword} => {
ComputedOperation::${name}(
% if keyword == "matrix3d":
ComputedMatrix {
% endif
% for index, item in enumerate(items):
% if keyword == "matrix3d":
m${index / 4 + 1}${index % 4 + 1}:
% endif
@@ -2379,49 +2378,50 @@ fn static_assert() {
)},
% endfor
% if keyword == "matrix3d":
}
% endif
)
},
</%def>
- 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')}
${impl_transition_time_value('duration', 'Duration')}
${impl_transition_timing_function()}
pub fn transition_combined_duration_at(&self, index: usize) -> f32 {
// https://drafts.csswg.org/css-transitions/#transition-combined-duration