diff options
-rw-r--r-- | components/style/properties/gecko.mako.rs | 754 | ||||
-rw-r--r-- | components/style/properties/longhand/box.mako.rs | 44 | ||||
-rw-r--r-- | components/style/properties/longhand/ui.mako.rs | 17 | ||||
-rw-r--r-- | components/style/properties/shorthand/box.mako.rs | 5 | ||||
-rw-r--r-- | components/style/values/computed/mod.rs | 2 | ||||
-rw-r--r-- | components/style/values/generics/transform.rs | 7 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 2 | ||||
-rw-r--r-- | components/style/values/specified/transform.rs | 21 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 6 |
9 files changed, 457 insertions, 401 deletions
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 022507fdce0..6cd1b509b06 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -979,6 +979,400 @@ def set_gecko_property(ffi_name, expr): } </%def> +<% +transform_functions = [ + ("Matrix3D", "matrix3d", ["number"] * 16), + ("PrefixedMatrix3D", "matrix3d", ["number"] * 12 + ["lopon"] * 2 + + ["lon"] + ["number"]), + ("Matrix", "matrix", ["number"] * 6), + ("PrefixedMatrix", "matrix", ["number"] * 4 + ["lopon"] * 2), + ("Translate", "translate", ["lop", "optional_lop"]), + ("Translate3D", "translate3d", ["lop", "lop", "length"]), + ("TranslateX", "translatex", ["lop"]), + ("TranslateY", "translatey", ["lop"]), + ("TranslateZ", "translatez", ["length"]), + ("Scale3D", "scale3d", ["number"] * 3), + ("Scale", "scale", ["number", "optional_number"]), + ("ScaleX", "scalex", ["number"]), + ("ScaleY", "scaley", ["number"]), + ("ScaleZ", "scalez", ["number"]), + ("Rotate", "rotate", ["angle"]), + ("Rotate3D", "rotate3d", ["number"] * 3 + ["angle"]), + ("RotateX", "rotatex", ["angle"]), + ("RotateY", "rotatey", ["angle"]), + ("RotateZ", "rotatez", ["angle"]), + ("Skew", "skew", ["angle", "optional_angle"]), + ("SkewX", "skewx", ["angle"]), + ("SkewY", "skewy", ["angle"]), + ("Perspective", "perspective", ["length"]), + ("InterpolateMatrix", "interpolatematrix", ["list"] * 2 + ["percentage"]), + ("AccumulateMatrix", "accumulatematrix", ["list"] * 2 + ["integer_to_percentage"]) +] +%> + +<%def name="transform_function_arm(name, keyword, items)"> + <% + has_optional = items[-1].startswith("optional_") + pattern = None + if keyword == "matrix3d": + # m11: number1, m12: number2, .. + single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b) + in enumerate(items)] + pattern = "(Matrix3D { %s })" % ", ".join(single_patterns) + elif keyword == "matrix": + # a: number1, b: number2, .. + single_patterns = ["%s: %s" % (chr(ord('a') + a), b + str(a + 1)) for (a, b) + in enumerate(items)] + pattern = "(Matrix { %s })" % ", ".join(single_patterns) + elif keyword == "interpolatematrix": + pattern = " { from_list: ref list1, to_list: ref list2, progress: percentage3 }" + elif keyword == "accumulatematrix": + pattern = " { from_list: ref list1, to_list: ref list2, count: integer_to_percentage3 }" + else: + # Generate contents of pattern from items + pattern = "(%s)" % ", ".join([b + str(a+1) for (a,b) in enumerate(items)]) + + # First %s substituted with the call to GetArrayItem, the second + # %s substituted with the corresponding variable + css_value_setters = { + "length" : "bindings::Gecko_CSSValue_SetPixelLength(%s, %s.px())", + "percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s.0)", + # Note: This is an integer type, but we use it as a percentage value in Gecko, so + # need to cast it to f32. + "integer_to_percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s as f32)", + "lop" : "%s.set_lop(%s)", + "lopon" : "set_lopon(%s, %s)", + "lon" : "set_lon(%s, %s)", + "angle" : "%s.set_angle(%s)", + "number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)", + # Note: We use nsCSSValueSharedList here, instead of nsCSSValueList_heap + # because this function is not called on the main thread and + # nsCSSValueList_heap is not thread safe. + "list" : "%s.set_shared_list(%s.0.iter().map(&convert_to_ns_css_value));", + } + %> + ::values::generics::transform::TransformOperation::${name}${pattern} => { + % if has_optional: + let optional_present = ${items[-1] + str(len(items))}.is_some(); + let len = if optional_present { + ${len(items) + 1} + } else { + ${len(items)} + }; + % else: + let len = ${len(items) + 1}; + % endif + bindings::Gecko_CSSValue_SetFunction(gecko_value, len); + bindings::Gecko_CSSValue_SetKeyword( + bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0), + structs::nsCSSKeyword::eCSSKeyword_${keyword} + ); + % for index, item in enumerate(items): + <% replaced_item = item.replace("optional_", "") %> + % if item.startswith("optional"): + if let Some(${replaced_item + str(index + 1)}) = ${item + str(index + 1)} { + % endif + % if item == "list": + debug_assert!(!${item}${index + 1}.0.is_empty()); + % endif + ${css_value_setters[replaced_item] % ( + "bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d)" % (index + 1), + replaced_item + str(index + 1) + )}; + % if item.startswith("optional"): + } + % endif + % endfor + } +</%def> + +<%def name="computed_operation_arm(name, keyword, items)"> + <% + # %s is substituted with the call to GetArrayItem. + css_value_getters = { + "length" : "Length::new(bindings::Gecko_CSSValue_GetNumber(%s))", + "lop" : "%s.get_lop()", + "lopon" : "Either::Second(%s.get_lop())", + "lon" : "Either::First(%s.get_length())", + "angle" : "%s.get_angle()", + "number" : "bindings::Gecko_CSSValue_GetNumber(%s)", + "percentage" : "Percentage(bindings::Gecko_CSSValue_GetPercentage(%s))", + "integer_to_percentage" : "bindings::Gecko_CSSValue_GetPercentage(%s) as i32", + "list" : "Transform(convert_shared_list_to_operations(%s))", + } + pre_symbols = "(" + post_symbols = ")" + if keyword == "interpolatematrix" or keyword == "accumulatematrix": + # We generate this like: "TransformOperation::InterpolateMatrix {", so the space is + # between "InterpolateMatrix"/"AccumulateMatrix" and '{' + pre_symbols = " {" + post_symbols = "}" + elif keyword == "matrix3d": + pre_symbols = "(Matrix3D {" + post_symbols = "})" + elif keyword == "matrix": + pre_symbols = "(Matrix {" + post_symbols = "})" + field_names = None + if keyword == "interpolatematrix": + field_names = ["from_list", "to_list", "progress"] + elif keyword == "accumulatematrix": + field_names = ["from_list", "to_list", "count"] + + %> + <% + + guard = "" + if name == "Matrix3D" or name == "Matrix": + guard = "if !needs_prefix " + elif name == "PrefixedMatrix3D" or name == "PrefixedMatrix": + guard = "if needs_prefix " + + %> + structs::nsCSSKeyword::eCSSKeyword_${keyword} ${guard}=> { + ::values::generics::transform::TransformOperation::${name}${pre_symbols} + % for index, item in enumerate(items): + % if keyword == "matrix3d": + m${index / 4 + 1}${index % 4 + 1}: + % elif keyword == "matrix": + ${chr(ord('a') + index)}: + % elif keyword == "interpolatematrix" or keyword == "accumulatematrix": + ${field_names[index]}: + % endif + <% + getter = css_value_getters[item.replace("optional_", "")] % ( + "bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d)" % (index + 1) + ) + %> + % if item.startswith("optional_"): + if (**gecko_value.mValue.mArray.as_ref()).mCount == ${index + 1} { + None + } else { + Some(${getter}) + } + % else: + ${getter} + % endif +, + % endfor + ${post_symbols} + }, +</%def> + +fn set_single_transform_function( + servo_value: &values::computed::TransformOperation, + gecko_value: &mut structs::nsCSSValue /* output */ +) { + use values::computed::{Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrNumber}; + use values::computed::TransformOperation; + use values::generics::transform::{Matrix, Matrix3D}; + + let convert_to_ns_css_value = |item: &TransformOperation| -> structs::nsCSSValue { + let mut value = structs::nsCSSValue::null(); + set_single_transform_function(item, &mut value); + value + }; + + unsafe fn set_lopon(css: &mut structs::nsCSSValue, lopon: LengthOrPercentageOrNumber) { + let lop = match lopon { + Either::First(number) => LengthOrPercentage::Length(Length::new(number)), + Either::Second(lop) => lop, + }; + css.set_lop(lop); + } + + unsafe fn set_lon(css: &mut structs::nsCSSValue, lopon: LengthOrNumber) { + let length = match lopon { + Either::Second(number) => Length::new(number), + Either::First(l) => l, + }; + bindings::Gecko_CSSValue_SetPixelLength(css, length.px()) + } + + unsafe { + match *servo_value { + % for servo, gecko, format in transform_functions: + ${transform_function_arm(servo, gecko, format)} + % endfor + } + } +} + +pub fn convert_transform( + input: &[values::computed::TransformOperation], + output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList> +) { + use gecko_bindings::sugar::refptr::RefPtr; + + unsafe { output.clear() }; + + let list = unsafe { + RefPtr::from_addrefed(bindings::Gecko_NewCSSValueSharedList(input.len() as u32)) + }; + 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()) { + set_single_transform_function(servo, gecko); + } + } + unsafe { output.set_move(list) }; +} + +fn clone_single_transform_function( + gecko_value: &structs::nsCSSValue +) -> values::computed::TransformOperation { + use values::computed::{Length, Percentage, TransformOperation}; + use values::generics::transform::{Matrix, Matrix3D}; + use values::generics::transform::Transform; + + let convert_shared_list_to_operations = |value: &structs::nsCSSValue| + -> Vec<TransformOperation> { + debug_assert!(value.mUnit == structs::nsCSSUnit::eCSSUnit_SharedList); + let value_list = unsafe { + value.mValue.mSharedList.as_ref() + .as_mut().expect("List pointer should be non-null").mHead.as_ref() + }; + debug_assert!(value_list.is_some(), "An empty shared list is not allowed"); + value_list.unwrap().into_iter() + .map(|item| clone_single_transform_function(item)) + .collect() + }; + + let transform_function = unsafe { + bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0)) + }; + + let needs_prefix = if transform_function == structs::nsCSSKeyword::eCSSKeyword_matrix3d { + unsafe { + bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 13).mUnit + != structs::nsCSSUnit::eCSSUnit_Number || + bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 14).mUnit + != structs::nsCSSUnit::eCSSUnit_Number || + bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 15).mUnit + != structs::nsCSSUnit::eCSSUnit_Number + } + } else { + false + }; + + unsafe { + match transform_function { + % for servo, gecko, format in transform_functions: + ${computed_operation_arm(servo, gecko, format)} + % endfor + _ => panic!("{:?} is not an acceptable transform function", transform_function), + } + } +} + +pub fn clone_transform_from_list( + list: Option< &structs::root::nsCSSValueList> +) -> values::computed::Transform { + use values::generics::transform::Transform; + + let result = match list { + Some(list) => { + list.into_iter() + .filter_map(|value| { + // Handle none transform. + if value.is_none() { + None + } else { + Some(clone_single_transform_function(value)) + } + }) + .collect::<Vec<_>>() + }, + _ => vec![], + }; + Transform(result) +} + +<%def name="impl_transform(ident, gecko_ffi_name)"> + #[allow(non_snake_case)] + pub fn set_${ident}(&mut self, other: values::computed::Transform) { + use gecko_properties::convert_transform; + if other.0.is_empty() { + unsafe { + self.gecko.${gecko_ffi_name}.clear(); + } + return; + }; + convert_transform(&other.0, &mut self.gecko.${gecko_ffi_name}); + } + + #[allow(non_snake_case)] + pub fn copy_${ident}_from(&mut self, other: &Self) { + unsafe { self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name}); } + } + + #[allow(non_snake_case)] + pub fn reset_${ident}(&mut self, other: &Self) { + self.copy_${ident}_from(other) + } + + #[allow(non_snake_case)] + pub fn clone_${ident}(&self) -> values::computed::Transform { + use gecko_properties::clone_transform_from_list; + use values::generics::transform::Transform; + + if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() { + return Transform(vec!()); + } + let list = unsafe { (*self.gecko.${gecko_ffi_name}.to_safe().get()).mHead.as_ref() }; + clone_transform_from_list(list) + } +</%def> + +<%def name="impl_transform_origin(ident, gecko_ffi_name)"> + #[allow(non_snake_case)] + pub fn set_${ident}(&mut self, v: values::computed::TransformOrigin) { + self.gecko.${gecko_ffi_name}[0].set(v.horizontal); + self.gecko.${gecko_ffi_name}[1].set(v.vertical); + // transform-origin supports the third value for depth, while + // -moz-window-transform-origin doesn't. The following code is + // for handling this difference. Rust (incorrectly) generates + // an unsuppressible warning, but we know it's safe here. + // See rust-lang/rust#45850. Also if we can have more knowledge + // about the type here, we may want to check that the length is + // exactly either 2 or 3 in compile time. + if self.gecko.${gecko_ffi_name}.len() == 3 { + self.gecko.${gecko_ffi_name}[2].set(v.depth); + } + } + + #[allow(non_snake_case)] + pub fn copy_${ident}_from(&mut self, other: &Self) { + self.gecko.${gecko_ffi_name}[0].copy_from(&other.gecko.${gecko_ffi_name}[0]); + self.gecko.${gecko_ffi_name}[1].copy_from(&other.gecko.${gecko_ffi_name}[1]); + if self.gecko.${gecko_ffi_name}.len() == 3 { + self.gecko.${gecko_ffi_name}[2].copy_from(&other.gecko.${gecko_ffi_name}[2]); + } + } + + #[allow(non_snake_case)] + pub fn reset_${ident}(&mut self, other: &Self) { + self.copy_${ident}_from(other) + } + + #[allow(non_snake_case)] + pub fn clone_${ident}(&self) -> values::computed::TransformOrigin { + use values::computed::{Length, LengthOrPercentage, TransformOrigin}; + TransformOrigin { + horizontal: LengthOrPercentage::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}[0]) + .expect("clone for LengthOrPercentage failed"), + vertical: LengthOrPercentage::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}[1]) + .expect("clone for LengthOrPercentage failed"), + depth: if self.gecko.${gecko_ffi_name}.len() == 3 { + Length::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}[2]) + .expect("clone for Length failed") + } else { + Length::new(0.) + }, + } + } +</%def> + <%def name="impl_logical(name, **kwargs)"> ${helpers.logical_setter(name)} </%def> @@ -1131,6 +1525,8 @@ impl Clone for ${style_struct.gecko_struct_name} { "SVGOpacity": impl_svg_opacity, "SVGPaint": impl_svg_paint, "SVGWidth": impl_svg_length, + "Transform": impl_transform, + "TransformOrigin": impl_transform_origin, "UrlOrNone": impl_css_url, } @@ -2699,9 +3095,9 @@ fn static_assert() { transition-duration transition-delay transition-timing-function transition-property page-break-before page-break-after - scroll-snap-points-x scroll-snap-points-y transform + scroll-snap-points-x scroll-snap-points-y scroll-snap-type-x scroll-snap-type-y scroll-snap-coordinate - perspective-origin transform-origin -moz-binding will-change + perspective-origin -moz-binding will-change shape-outside contain touch-action""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> @@ -2894,331 +3290,6 @@ fn static_assert() { } ${impl_css_url('_moz_binding', 'mBinding.mPtr')} - <% - transform_functions = [ - ("Matrix3D", "matrix3d", ["number"] * 16), - ("PrefixedMatrix3D", "matrix3d", ["number"] * 12 + ["lopon"] * 2 - + ["lon"] + ["number"]), - ("Matrix", "matrix", ["number"] * 6), - ("PrefixedMatrix", "matrix", ["number"] * 4 + ["lopon"] * 2), - ("Translate", "translate", ["lop", "optional_lop"]), - ("Translate3D", "translate3d", ["lop", "lop", "length"]), - ("TranslateX", "translatex", ["lop"]), - ("TranslateY", "translatey", ["lop"]), - ("TranslateZ", "translatez", ["length"]), - ("Scale3D", "scale3d", ["number"] * 3), - ("Scale", "scale", ["number", "optional_number"]), - ("ScaleX", "scalex", ["number"]), - ("ScaleY", "scaley", ["number"]), - ("ScaleZ", "scalez", ["number"]), - ("Rotate", "rotate", ["angle"]), - ("Rotate3D", "rotate3d", ["number"] * 3 + ["angle"]), - ("RotateX", "rotatex", ["angle"]), - ("RotateY", "rotatey", ["angle"]), - ("RotateZ", "rotatez", ["angle"]), - ("Skew", "skew", ["angle", "optional_angle"]), - ("SkewX", "skewx", ["angle"]), - ("SkewY", "skewy", ["angle"]), - ("Perspective", "perspective", ["length"]), - ("InterpolateMatrix", "interpolatematrix", ["list"] * 2 + ["percentage"]), - ("AccumulateMatrix", "accumulatematrix", ["list"] * 2 + ["integer_to_percentage"]) - ] - %> - <%def name="transform_function_arm(name, keyword, items)"> - <% - has_optional = items[-1].startswith("optional_") - pattern = None - if keyword == "matrix3d": - # m11: number1, m12: number2, .. - single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b) - in enumerate(items)] - pattern = "(Matrix3D { %s })" % ", ".join(single_patterns) - elif keyword == "matrix": - # a: number1, b: number2, .. - single_patterns = ["%s: %s" % (chr(ord('a') + a), b + str(a + 1)) for (a, b) - in enumerate(items)] - pattern = "(Matrix { %s })" % ", ".join(single_patterns) - elif keyword == "interpolatematrix": - pattern = " { from_list: ref list1, to_list: ref list2, progress: percentage3 }" - elif keyword == "accumulatematrix": - pattern = " { from_list: ref list1, to_list: ref list2, count: integer_to_percentage3 }" - else: - # Generate contents of pattern from items - pattern = "(%s)" % ", ".join([b + str(a+1) for (a,b) in enumerate(items)]) - - # First %s substituted with the call to GetArrayItem, the second - # %s substituted with the corresponding variable - css_value_setters = { - "length" : "bindings::Gecko_CSSValue_SetPixelLength(%s, %s.px())", - "percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s.0)", - # Note: This is an integer type, but we use it as a percentage value in Gecko, so - # need to cast it to f32. - "integer_to_percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s as f32)", - "lop" : "%s.set_lop(%s)", - "lopon" : "set_lopon(%s, %s)", - "lon" : "set_lon(%s, %s)", - "angle" : "%s.set_angle(%s)", - "number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)", - # Note: We use nsCSSValueSharedList here, instead of nsCSSValueList_heap - # because this function is not called on the main thread and - # nsCSSValueList_heap is not thread safe. - "list" : "%s.set_shared_list(%s.0.iter().map(&convert_to_ns_css_value));", - } - %> - ::values::generics::transform::TransformOperation::${name}${pattern} => { - % if has_optional: - let optional_present = ${items[-1] + str(len(items))}.is_some(); - let len = if optional_present { - ${len(items) + 1} - } else { - ${len(items)} - }; - % else: - let len = ${len(items) + 1}; - % endif - bindings::Gecko_CSSValue_SetFunction(gecko_value, len); - bindings::Gecko_CSSValue_SetKeyword( - bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0), - structs::nsCSSKeyword::eCSSKeyword_${keyword} - ); - % for index, item in enumerate(items): - <% replaced_item = item.replace("optional_", "") %> - % if item.startswith("optional"): - if let Some(${replaced_item + str(index + 1)}) = ${item + str(index + 1)} { - % endif - % if item == "list": - debug_assert!(!${item}${index + 1}.0.is_empty()); - % endif - ${css_value_setters[replaced_item] % ( - "bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d)" % (index + 1), - replaced_item + str(index + 1) - )}; - % if item.startswith("optional"): - } - % endif - % 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::ComputedOperation; - use values::computed::{Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrNumber}; - use values::generics::transform::{Matrix, Matrix3D}; - - let convert_to_ns_css_value = |item: &ComputedOperation| -> structs::nsCSSValue { - let mut value = structs::nsCSSValue::null(); - Self::set_single_transform_function(item, &mut value); - value - }; - - unsafe fn set_lopon(css: &mut structs::nsCSSValue, lopon: LengthOrPercentageOrNumber) { - let lop = match lopon { - Either::First(number) => LengthOrPercentage::Length(Length::new(number)), - Either::Second(lop) => lop, - }; - css.set_lop(lop); - } - - unsafe fn set_lon(css: &mut structs::nsCSSValue, lopon: LengthOrNumber) { - let length = match lopon { - Either::Second(number) => Length::new(number), - Either::First(l) => l, - }; - bindings::Gecko_CSSValue_SetPixelLength(css, length.px()) - } - - unsafe { - match *servo_value { - % for servo, gecko, format in transform_functions: - ${transform_function_arm(servo, gecko, format)} - % endfor - } - } - } - pub fn convert_transform(input: &[longhands::transform::computed_value::ComputedOperation], - output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList>) { - use gecko_bindings::sugar::refptr::RefPtr; - - unsafe { output.clear() }; - - let list = unsafe { - RefPtr::from_addrefed(bindings::Gecko_NewCSSValueSharedList(input.len() as u32)) - }; - 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); - } - } - unsafe { output.set_move(list) }; - } - - pub fn set_transform(&mut self, other: longhands::transform::computed_value::T) { - if other.0.is_empty() { - unsafe { - self.gecko.mSpecifiedTransform.clear(); - } - return; - }; - Self::convert_transform(&other.0, &mut self.gecko.mSpecifiedTransform); - } - - pub fn copy_transform_from(&mut self, other: &Self) { - unsafe { self.gecko.mSpecifiedTransform.set(&other.gecko.mSpecifiedTransform); } - } - - pub fn reset_transform(&mut self, other: &Self) { - self.copy_transform_from(other) - } - - <%def name="computed_operation_arm(name, keyword, items)"> - <% - # %s is substituted with the call to GetArrayItem. - css_value_getters = { - "length" : "Length::new(bindings::Gecko_CSSValue_GetNumber(%s))", - "lop" : "%s.get_lop()", - "lopon" : "Either::Second(%s.get_lop())", - "lon" : "Either::First(%s.get_length())", - "angle" : "%s.get_angle()", - "number" : "bindings::Gecko_CSSValue_GetNumber(%s)", - "percentage" : "Percentage(bindings::Gecko_CSSValue_GetPercentage(%s))", - "integer_to_percentage" : "bindings::Gecko_CSSValue_GetPercentage(%s) as i32", - "list" : "Transform(convert_shared_list_to_operations(%s))", - } - pre_symbols = "(" - post_symbols = ")" - if keyword == "interpolatematrix" or keyword == "accumulatematrix": - # We generate this like: "ComputedOperation::InterpolateMatrix {", so the space is - # between "InterpolateMatrix"/"AccumulateMatrix" and '{' - pre_symbols = " {" - post_symbols = "}" - elif keyword == "matrix3d": - pre_symbols = "(Matrix3D {" - post_symbols = "})" - elif keyword == "matrix": - pre_symbols = "(Matrix {" - post_symbols = "})" - field_names = None - if keyword == "interpolatematrix": - field_names = ["from_list", "to_list", "progress"] - elif keyword == "accumulatematrix": - field_names = ["from_list", "to_list", "count"] - - %> - <% - - guard = "" - if name == "Matrix3D" or name == "Matrix": - guard = "if !needs_prefix " - elif name == "PrefixedMatrix3D" or name == "PrefixedMatrix": - guard = "if needs_prefix " - - %> - structs::nsCSSKeyword::eCSSKeyword_${keyword} ${guard}=> { - ::values::generics::transform::TransformOperation::${name}${pre_symbols} - % for index, item in enumerate(items): - % if keyword == "matrix3d": - m${index / 4 + 1}${index % 4 + 1}: - % elif keyword == "matrix": - ${chr(ord('a') + index)}: - % elif keyword == "interpolatematrix" or keyword == "accumulatematrix": - ${field_names[index]}: - % endif - <% - getter = css_value_getters[item.replace("optional_", "")] % ( - "bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d)" % (index + 1) - ) - %> - % if item.startswith("optional_"): - if (**gecko_value.mValue.mArray.as_ref()).mCount == ${index + 1} { - None - } else { - Some(${getter}) - } - % else: - ${getter} - % endif -, - % endfor - ${post_symbols} - }, - </%def> - fn clone_single_transform_function(gecko_value: &structs::nsCSSValue) - -> longhands::transform::computed_value::ComputedOperation { - use properties::longhands::transform::computed_value::ComputedOperation; - use values::computed::{Length, Percentage}; - use values::generics::transform::{Matrix, Matrix3D}; - use values::generics::transform::Transform; - - let convert_shared_list_to_operations = |value: &structs::nsCSSValue| - -> Vec<ComputedOperation> { - debug_assert!(value.mUnit == structs::nsCSSUnit::eCSSUnit_SharedList); - let value_list = unsafe { - value.mValue.mSharedList.as_ref() - .as_mut().expect("List pointer should be non-null").mHead.as_ref() - }; - debug_assert!(value_list.is_some(), "An empty shared list is not allowed"); - value_list.unwrap().into_iter() - .map(|item| Self::clone_single_transform_function(item)) - .collect() - }; - - let transform_function = unsafe { - bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0)) - }; - - let needs_prefix = if transform_function == structs::nsCSSKeyword::eCSSKeyword_matrix3d { - unsafe { - bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 13).mUnit - != structs::nsCSSUnit::eCSSUnit_Number || - bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 14).mUnit - != structs::nsCSSUnit::eCSSUnit_Number || - bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 15).mUnit - != structs::nsCSSUnit::eCSSUnit_Number - } - } else { - false - }; - - unsafe { - match transform_function { - % for servo, gecko, format in transform_functions: - ${computed_operation_arm(servo, gecko, format)} - % endfor - _ => panic!("{:?} is not an acceptable transform function", transform_function), - } - } - } - pub fn clone_transform(&self) -> longhands::transform::computed_value::T { - use values::generics::transform::Transform; - - if self.gecko.mSpecifiedTransform.mRawPtr.is_null() { - return Transform(vec!()); - } - let list = unsafe { (*self.gecko.mSpecifiedTransform.to_safe().get()).mHead.as_ref() }; - Self::clone_transform_from_list(list) - } - pub fn clone_transform_from_list(list: Option< &structs::root::nsCSSValueList>) - -> longhands::transform::computed_value::T { - use values::generics::transform::Transform; - - let result = match list { - Some(list) => { - list.into_iter() - .filter_map(|value| { - // Handle none transform. - if value.is_none() { - None - } else { - Some(Self::clone_single_transform_function(value)) - } - }) - .collect::<Vec<_>>() - }, - _ => vec![], - }; - Transform(result) - } ${impl_transition_time_value('delay', 'Delay')} ${impl_transition_time_value('duration', 'Duration')} @@ -3439,35 +3510,6 @@ fn static_assert() { } } - pub fn set_transform_origin(&mut self, v: longhands::transform_origin::computed_value::T) { - self.gecko.mTransformOrigin[0].set(v.horizontal); - self.gecko.mTransformOrigin[1].set(v.vertical); - self.gecko.mTransformOrigin[2].set(v.depth); - } - - pub fn copy_transform_origin_from(&mut self, other: &Self) { - self.gecko.mTransformOrigin[0].copy_from(&other.gecko.mTransformOrigin[0]); - self.gecko.mTransformOrigin[1].copy_from(&other.gecko.mTransformOrigin[1]); - self.gecko.mTransformOrigin[2].copy_from(&other.gecko.mTransformOrigin[2]); - } - - pub fn reset_transform_origin(&mut self, other: &Self) { - self.copy_transform_origin_from(other) - } - - pub fn clone_transform_origin(&self) -> longhands::transform_origin::computed_value::T { - use properties::longhands::transform_origin::computed_value::T; - use values::computed::{Length, LengthOrPercentage}; - T { - horizontal: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mTransformOrigin[0]) - .expect("clone for LengthOrPercentage failed"), - vertical: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mTransformOrigin[1]) - .expect("clone for LengthOrPercentage failed"), - depth: Length::from_gecko_style_coord(&self.gecko.mTransformOrigin[2]) - .expect("clone for Length failed"), - } - } - pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) { use gecko_bindings::bindings::{Gecko_AppendWillChange, Gecko_ClearWillChange}; use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_OPACITY; diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 4d13abedf06..f5f9d0753cd 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -567,42 +567,13 @@ ${helpers.predefined_type( allow_empty="NotInitial" )} -<%helpers:longhand name="transform" extra_prefixes="webkit" - animation_value_type="ComputedValue" - flags="CREATES_STACKING_CONTEXT FIXPOS_CB" - spec="https://drafts.csswg.org/css-transforms/#propdef-transform"> - use values::generics::transform::Transform; - - - pub mod computed_value { - pub use values::computed::transform::Transform as T; - pub use values::computed::transform::TransformOperation as ComputedOperation; - } - - pub use values::specified::transform::Transform as SpecifiedValue; - pub use values::specified::transform::TransformOperation as SpecifiedOperation; - - #[inline] - pub fn get_initial_value() -> computed_value::T { - Transform(vec![]) - } - - - /// Parses `transform` property. - #[inline] - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result<SpecifiedValue,ParseError<'i>> { - SpecifiedValue::parse_internal(context, input, false) - } - - /// Parses `-moz-transform` property. This prefixed property also accepts LengthOrPercentage - /// in the nondiagonal homogeneous components of matrix and matrix3d. - #[inline] - pub fn parse_prefixed<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result<SpecifiedValue,ParseError<'i>> { - SpecifiedValue::parse_internal(context, input, true) - } -</%helpers:longhand> +${helpers.predefined_type("transform", "Transform", + "generics::transform::Transform::none()", + extra_prefixes="webkit", + animation_value_type="ComputedValue", + gecko_ffi_name="mSpecifiedTransform", + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", + spec="https://drafts.csswg.org/css-transforms/#propdef-transform")} // CSSOM View Module // https://www.w3.org/TR/cssom-view-1/ @@ -713,6 +684,7 @@ ${helpers.predefined_type("transform-origin", "computed::TransformOrigin::initial_value()", animation_value_type="ComputedValue", extra_prefixes="moz webkit", + gecko_ffi_name="mTransformOrigin", boxed=True, spec="https://drafts.csswg.org/css-transforms/#transform-origin-property")} diff --git a/components/style/properties/longhand/ui.mako.rs b/components/style/properties/longhand/ui.mako.rs index 6152411155a..98093882e17 100644 --- a/components/style/properties/longhand/ui.mako.rs +++ b/components/style/properties/longhand/ui.mako.rs @@ -46,6 +46,23 @@ ${helpers.predefined_type("-moz-window-opacity", "Opacity", "1.0", products="gec internal=True, spec="None (Nonstandard internal property)")} +${helpers.predefined_type("-moz-window-transform", "Transform", + "generics::transform::Transform::none()", + products="gecko", gecko_ffi_name="mSpecifiedWindowTransform", + animation_value_type="ComputedValue", + internal=True, + spec="None (Nonstandard internal property)")} + +${helpers.predefined_type("-moz-window-transform-origin", + "TransformOrigin", + "computed::TransformOrigin::initial_value()", + animation_value_type="ComputedValue", + gecko_ffi_name="mWindowTransformOrigin", + products="gecko", + boxed=True, + internal=True, + spec="None (Nonstandard internal property)")} + <%helpers:longhand name="-moz-force-broken-image-icon" products="gecko" animation_value_type="discrete" diff --git a/components/style/properties/shorthand/box.mako.rs b/components/style/properties/shorthand/box.mako.rs index 94510e12c1f..4a058b5b7ab 100644 --- a/components/style/properties/shorthand/box.mako.rs +++ b/components/style/properties/shorthand/box.mako.rs @@ -363,12 +363,11 @@ macro_rules! try_parse_one { flags="SHORTHAND_ALIAS_PROPERTY" derive_serialize="True" spec="Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/transform"> - use properties::longhands::transform; - pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Longhands, ParseError<'i>> { + use values::specified::transform::Transform; Ok(expanded! { - transform: transform::parse_prefixed(context, input)?, + transform: Transform::parse_prefixed(context, input)?, }) } </%helpers:shorthand> diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 7c6f54f58ed..bf3bbf712c5 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -57,7 +57,7 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDash pub use self::table::XSpan; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing}; pub use self::time::Time; -pub use self::transform::{TimingFunction, TransformOrigin}; +pub use self::transform::{TimingFunction, Transform, TransformOperation, TransformOrigin}; #[cfg(feature = "gecko")] pub mod align; diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 45d19c8ab68..c4c41070065 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -450,3 +450,10 @@ impl<T: ToCss> ToCss for Transform<T> { Ok(()) } } + +impl<T> Transform<T> { + /// `none` + pub fn none() -> Self { + Transform(vec![]) + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 9a33019d98a..3827b638e4b 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -53,7 +53,7 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDash pub use self::table::XSpan; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing}; pub use self::time::Time; -pub use self::transform::{TimingFunction, TransformOrigin}; +pub use self::transform::{TimingFunction, Transform, TransformOrigin}; pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; #[cfg(feature = "gecko")] diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index e01a5d996c5..ca77bd7a723 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -39,7 +39,7 @@ pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComp impl Transform { /// Internal parse function for deciding if we wish to accept prefixed values or not // Allow unitless zero angle for rotate() and skew() to align with gecko - pub fn parse_internal<'i, 't>( + fn parse_internal<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, prefixed: bool, @@ -252,6 +252,25 @@ impl Transform { }) })?)) } + + /// Parses `-moz-transform` property. This prefixed property also accepts LengthOrPercentage + /// in the nondiagonal homogeneous components of matrix and matrix3d. + #[inline] + pub fn parse_prefixed<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + Transform::parse_internal(context, input, true) + } +} + +impl Parse for Transform { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result<Self, ParseError<'i>> { + Transform::parse_internal(context, input, false) + } } /// The specified value of a component of a CSS `<transform-origin>`. diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 07d05379628..04ff917fa1e 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -111,7 +111,7 @@ use style::gecko_bindings::structs::nsresult; use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasFFI, HasArcFFI}; use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; use style::gecko_bindings::sugar::refptr::RefPtr; -use style::gecko_properties::style_structs; +use style::gecko_properties; use style::invalidation::element::restyle_hints; use style::media_queries::{Device, MediaList, parse_media_query_list}; use style::parser::{Parse, ParserContext, self}; @@ -721,7 +721,7 @@ pub extern "C" fn Servo_AnimationValue_GetTransform( list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform())); } } else { - style_structs::Box::convert_transform(&servo_list.0, list); + gecko_properties::convert_transform(&servo_list.0, list); } } else { panic!("The AnimationValue should be transform"); @@ -733,7 +733,7 @@ pub extern "C" fn Servo_AnimationValue_Transform( list: *const nsCSSValueSharedList ) -> RawServoAnimationValueStrong { let list = unsafe { (&*list).mHead.as_ref() }; - let transform = style_structs::Box::clone_transform_from_list(list); + let transform = gecko_properties::clone_transform_from_list(list); Arc::new(AnimationValue::Transform(transform)).into_strong() } |