mirror of
https://github.com/servo/servo.git
synced 2025-06-25 09:34:32 +01:00
Add general impl in gecko_properties for Transform value and add -moz-window-transform.
This commit is contained in:
parent
8b9bbfea75
commit
dfbf632fd6
4 changed files with 358 additions and 328 deletions
|
@ -979,6 +979,351 @@ def set_gecko_property(ffi_name, expr):
|
||||||
}
|
}
|
||||||
</%def>
|
</%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_logical(name, **kwargs)">
|
<%def name="impl_logical(name, **kwargs)">
|
||||||
${helpers.logical_setter(name)}
|
${helpers.logical_setter(name)}
|
||||||
</%def>
|
</%def>
|
||||||
|
@ -1131,6 +1476,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
||||||
"SVGOpacity": impl_svg_opacity,
|
"SVGOpacity": impl_svg_opacity,
|
||||||
"SVGPaint": impl_svg_paint,
|
"SVGPaint": impl_svg_paint,
|
||||||
"SVGWidth": impl_svg_length,
|
"SVGWidth": impl_svg_length,
|
||||||
|
"Transform": impl_transform,
|
||||||
"UrlOrNone": impl_css_url,
|
"UrlOrNone": impl_css_url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2699,7 +3045,7 @@ fn static_assert() {
|
||||||
transition-duration transition-delay
|
transition-duration transition-delay
|
||||||
transition-timing-function transition-property
|
transition-timing-function transition-property
|
||||||
page-break-before page-break-after
|
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
|
scroll-snap-type-x scroll-snap-type-y scroll-snap-coordinate
|
||||||
perspective-origin transform-origin -moz-binding will-change
|
perspective-origin transform-origin -moz-binding will-change
|
||||||
shape-outside contain touch-action""" %>
|
shape-outside contain touch-action""" %>
|
||||||
|
@ -2894,330 +3240,6 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
|
|
||||||
${impl_css_url('_moz_binding', 'mBinding.mPtr')}
|
${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: &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();
|
|
||||||
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: &[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()) {
|
|
||||||
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: "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 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| 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('delay', 'Delay')}
|
||||||
${impl_transition_time_value('duration', 'Duration')}
|
${impl_transition_time_value('duration', 'Duration')}
|
||||||
|
|
|
@ -571,6 +571,7 @@ ${helpers.predefined_type("transform", "Transform",
|
||||||
"generics::transform::Transform::none()",
|
"generics::transform::Transform::none()",
|
||||||
extra_prefixes="webkit",
|
extra_prefixes="webkit",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
|
gecko_ffi_name="mSpecifiedTransform",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||||
spec="https://drafts.csswg.org/css-transforms/#propdef-transform")}
|
spec="https://drafts.csswg.org/css-transforms/#propdef-transform")}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,13 @@ ${helpers.predefined_type("-moz-window-opacity", "Opacity", "1.0", products="gec
|
||||||
internal=True,
|
internal=True,
|
||||||
spec="None (Nonstandard internal property)")}
|
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:longhand name="-moz-force-broken-image-icon"
|
<%helpers:longhand name="-moz-force-broken-image-icon"
|
||||||
products="gecko"
|
products="gecko"
|
||||||
animation_value_type="discrete"
|
animation_value_type="discrete"
|
||||||
|
|
|
@ -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::{FFIArcHelpers, HasFFI, HasArcFFI};
|
||||||
use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
|
use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
|
||||||
use style::gecko_bindings::sugar::refptr::RefPtr;
|
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::invalidation::element::restyle_hints;
|
||||||
use style::media_queries::{Device, MediaList, parse_media_query_list};
|
use style::media_queries::{Device, MediaList, parse_media_query_list};
|
||||||
use style::parser::{Parse, ParserContext, self};
|
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()));
|
list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
style_structs::Box::convert_transform(&servo_list.0, list);
|
gecko_properties::convert_transform(&servo_list.0, list);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("The AnimationValue should be transform");
|
panic!("The AnimationValue should be transform");
|
||||||
|
@ -733,7 +733,7 @@ pub extern "C" fn Servo_AnimationValue_Transform(
|
||||||
list: *const nsCSSValueSharedList
|
list: *const nsCSSValueSharedList
|
||||||
) -> RawServoAnimationValueStrong {
|
) -> RawServoAnimationValueStrong {
|
||||||
let list = unsafe { (&*list).mHead.as_ref() };
|
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()
|
Arc::new(AnimationValue::Transform(transform)).into_strong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue