servo: Merge #19106 - Implement -moz-window-transform{,-origin} internal properties (from upsuper:window-transform); r=emilio

This fixes [bug 1374178](https://bugzilla.mozilla.org/show_bug.cgi?id=1374178).

Note that the impl of `-moz-window-transform-origin` doesn't exactly match how it is implemented in Gecko. Specifically, that property doesn't accept depth value in Gecko, but it does in this impl. The depth value is simply dropped during conversion. This is because I don't think it's worth adding code for handling this internal property to make it as restrictive.

Source-Repo: https://github.com/servo/servo
Source-Revision: 4decea188feb87b880fd2b0663b86d262a346a18

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 5655ab7551b2b151417086b9370df0a55897206f
This commit is contained in:
Xidorn Quan 2017-11-06 17:46:51 -06:00
Родитель ee666a4026
Коммит a02700faf7
9 изменённых файлов: 453 добавлений и 402 удалений

Просмотреть файл

@ -978,6 +978,395 @@ 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)">
<% has_depth = ident == "transform" %>
#[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);
% if has_depth:
self.gecko.${gecko_ffi_name}[2].set(v.depth);
% endif
}
#[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 has_depth:
self.gecko.${gecko_ffi_name}[2].copy_from(&other.gecko.${gecko_ffi_name}[2]);
% endif
}
#[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"),
% if has_depth:
depth: Length::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}[2])
.expect("clone for Length failed"),
% else:
depth: Length::new(0.)
% endif
}
}
</%def>
<%def name="impl_logical(name, **kwargs)">
${helpers.logical_setter(name)}
</%def>
@ -1130,6 +1519,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,
}
@ -2698,9 +3089,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}">
@ -2893,331 +3284,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')}
@ -3438,35 +3504,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;

Просмотреть файл

@ -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")}

Просмотреть файл

@ -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"

Просмотреть файл

@ -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>

Просмотреть файл

@ -56,7 +56,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;

Просмотреть файл

@ -450,3 +450,10 @@ impl<T: ToCss> ToCss for Transform<T> {
Ok(())
}
}
impl<T> Transform<T> {
/// `none`
pub fn none() -> Self {
Transform(vec![])
}
}

Просмотреть файл

@ -52,7 +52,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")]

Просмотреть файл

@ -37,9 +37,9 @@ pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComp
impl Transform {
/// Internal parse function for deciding if we wish to accept prefixed values or not
// 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>`.

Просмотреть файл

@ -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()
}