aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/properties/gecko.mako.rs754
-rw-r--r--components/style/properties/longhand/box.mako.rs44
-rw-r--r--components/style/properties/longhand/ui.mako.rs17
-rw-r--r--components/style/properties/shorthand/box.mako.rs5
-rw-r--r--components/style/values/computed/mod.rs2
-rw-r--r--components/style/values/generics/transform.rs7
-rw-r--r--components/style/values/specified/mod.rs2
-rw-r--r--components/style/values/specified/transform.rs21
-rw-r--r--ports/geckolib/glue.rs6
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()
}