mirror of
https://github.com/servo/servo.git
synced 2025-06-28 11:03:39 +01:00
style: Use cbindgen to back CSS transforms.
This avoids the expensive conversion, and cleans up a bunch. Further cleanup is possible, just not done yet to avoid growing the patch even more. Differential Revision: https://phabricator.services.mozilla.com/D30748
This commit is contained in:
parent
85752fa479
commit
3034d66eef
11 changed files with 59 additions and 356 deletions
|
@ -276,29 +276,6 @@ impl nsCSSValue {
|
||||||
}
|
}
|
||||||
debug_assert!(values.next().is_none(), "Values should have been exhausted");
|
debug_assert!(values.next().is_none(), "Values should have been exhausted");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a shared list
|
|
||||||
pub fn set_shared_list<I>(&mut self, values: I)
|
|
||||||
where
|
|
||||||
I: ExactSizeIterator<Item = nsCSSValue>,
|
|
||||||
{
|
|
||||||
debug_assert!(values.len() > 0, "Empty list is not supported");
|
|
||||||
unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) };
|
|
||||||
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList);
|
|
||||||
let list = unsafe {
|
|
||||||
self.mValue
|
|
||||||
.mSharedList
|
|
||||||
.as_ref()
|
|
||||||
.as_mut()
|
|
||||||
.expect("List pointer should be non-null")
|
|
||||||
.mHead
|
|
||||||
.as_mut()
|
|
||||||
};
|
|
||||||
debug_assert!(list.is_some(), "New created shared list shouldn't be null");
|
|
||||||
for (item, new_value) in list.unwrap().into_iter().zip(values) {
|
|
||||||
*item = new_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for nsCSSValue {
|
impl Drop for nsCSSValue {
|
||||||
|
|
|
@ -289,11 +289,6 @@ impl_threadsafe_refcount!(
|
||||||
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
|
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
|
||||||
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
||||||
);
|
);
|
||||||
impl_threadsafe_refcount!(
|
|
||||||
structs::nsCSSValueSharedList,
|
|
||||||
bindings::Gecko_AddRefCSSValueSharedListArbitraryThread,
|
|
||||||
bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread
|
|
||||||
);
|
|
||||||
impl_threadsafe_refcount!(
|
impl_threadsafe_refcount!(
|
||||||
structs::mozilla::css::URLValue,
|
structs::mozilla::css::URLValue,
|
||||||
bindings::Gecko_AddRefCSSURLValueArbitraryThread,
|
bindings::Gecko_AddRefCSSURLValueArbitraryThread,
|
||||||
|
|
|
@ -628,10 +628,6 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
if let Some(display) = builder.get_box_if_mutated() {
|
|
||||||
display.generate_combined_transform();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bg) = builder.get_background_if_mutated() {
|
if let Some(bg) = builder.get_background_if_mutated() {
|
||||||
bg.fill_arrays();
|
bg.fill_arrays();
|
||||||
}
|
}
|
||||||
|
|
|
@ -811,281 +811,6 @@ def set_gecko_property(ffi_name, expr):
|
||||||
}
|
}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%
|
|
||||||
transform_functions = [
|
|
||||||
("Matrix3D", "matrix3d", ["number"] * 16),
|
|
||||||
("Matrix", "matrix", ["number"] * 6),
|
|
||||||
("Translate", "translate", ["lp", "lp"]),
|
|
||||||
("Translate3D", "translate3d", ["lp", "lp", "length"]),
|
|
||||||
("TranslateX", "translatex", ["lp"]),
|
|
||||||
("TranslateY", "translatey", ["lp"]),
|
|
||||||
("TranslateZ", "translatez", ["length"]),
|
|
||||||
("Scale3D", "scale3d", ["number"] * 3),
|
|
||||||
("Scale", "scale", ["number", "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", "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)">
|
|
||||||
<%
|
|
||||||
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)",
|
|
||||||
"lp" : "%s.set_length_percentage(%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));",
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
crate::values::generics::transform::TransformOperation::${name}${pattern} => {
|
|
||||||
let len = ${len(items) + 1};
|
|
||||||
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):
|
|
||||||
% if item == "list":
|
|
||||||
debug_assert!(!${item}${index + 1}.0.is_empty());
|
|
||||||
% endif
|
|
||||||
${css_value_setters[item] % (
|
|
||||||
"(&mut *bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d))" % (index + 1),
|
|
||||||
item + str(index + 1)
|
|
||||||
)};
|
|
||||||
% 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))",
|
|
||||||
"lp" : "%s.get_length_percentage()",
|
|
||||||
"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"]
|
|
||||||
|
|
||||||
%>
|
|
||||||
structs::nsCSSKeyword::eCSSKeyword_${keyword} => {
|
|
||||||
crate::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] % (
|
|
||||||
"(&*bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d))" % (index + 1)
|
|
||||||
)
|
|
||||||
%>
|
|
||||||
${getter},
|
|
||||||
% endfor
|
|
||||||
${post_symbols}
|
|
||||||
},
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
|
||||||
fn set_single_transform_function(
|
|
||||||
servo_value: &values::computed::TransformOperation,
|
|
||||||
gecko_value: &mut structs::nsCSSValue /* output */
|
|
||||||
) {
|
|
||||||
use crate::values::computed::TransformOperation;
|
|
||||||
use crate::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 {
|
|
||||||
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 crate::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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output.set_move(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
|
||||||
fn clone_single_transform_function(
|
|
||||||
gecko_value: &structs::nsCSSValue
|
|
||||||
) -> values::computed::TransformOperation {
|
|
||||||
use crate::values::computed::{Length, Percentage, TransformOperation};
|
|
||||||
use crate::values::generics::transform::{Matrix, Matrix3D};
|
|
||||||
use crate::values::generics::transform::Transform;
|
|
||||||
|
|
||||||
let convert_shared_list_to_operations = |value: &structs::nsCSSValue|
|
|
||||||
-> Vec<TransformOperation> {
|
|
||||||
debug_assert_eq!(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))
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
match transform_function {
|
|
||||||
% for servo, gecko, format in transform_functions:
|
|
||||||
${computed_operation_arm(servo, gecko, format)}
|
|
||||||
% endfor
|
|
||||||
_ => panic!("unacceptable transform function"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_transform_from_list(
|
|
||||||
list: Option< &structs::root::nsCSSValueList>
|
|
||||||
) -> values::computed::Transform {
|
|
||||||
use crate::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 crate::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 crate::gecko_properties::clone_transform_from_list;
|
|
||||||
use crate::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>
|
||||||
|
@ -1191,7 +916,6 @@ 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,
|
|
||||||
"url::UrlOrNone": impl_css_url,
|
"url::UrlOrNone": impl_css_url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2511,17 +2235,11 @@ fn static_assert() {
|
||||||
animation-iteration-count animation-timing-function
|
animation-iteration-count animation-timing-function
|
||||||
clear transition-duration transition-delay
|
clear transition-duration transition-delay
|
||||||
transition-timing-function transition-property
|
transition-timing-function transition-property
|
||||||
transform-style
|
transform-style scroll-snap-points-x
|
||||||
rotate scroll-snap-points-x scroll-snap-points-y
|
scroll-snap-points-y scroll-snap-coordinate
|
||||||
scroll-snap-coordinate -moz-binding
|
-moz-binding offset-path shape-outside
|
||||||
offset-path shape-outside
|
-webkit-line-clamp""" %>
|
||||||
translate scale -webkit-line-clamp""" %>
|
|
||||||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||||
#[inline]
|
|
||||||
pub fn generate_combined_transform(&mut self) {
|
|
||||||
unsafe { bindings::Gecko_StyleDisplay_GenerateCombinedTransform(&mut *self.gecko) };
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
|
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
|
||||||
self.gecko.mDisplay = v;
|
self.gecko.mDisplay = v;
|
||||||
|
@ -2825,10 +2543,6 @@ fn static_assert() {
|
||||||
|
|
||||||
${impl_animation_timing_function()}
|
${impl_animation_timing_function()}
|
||||||
|
|
||||||
${impl_individual_transform('rotate', 'Rotate', 'mSpecifiedRotate')}
|
|
||||||
${impl_individual_transform('translate', 'Translate', 'mSpecifiedTranslate')}
|
|
||||||
${impl_individual_transform('scale', 'Scale', 'mSpecifiedScale')}
|
|
||||||
|
|
||||||
<% impl_shape_source("shape_outside", "mShapeOutside") %>
|
<% impl_shape_source("shape_outside", "mShapeOutside") %>
|
||||||
|
|
||||||
pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) {
|
pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) {
|
||||||
|
|
|
@ -352,7 +352,6 @@ ${helpers.predefined_type(
|
||||||
"generics::transform::Transform::none()",
|
"generics::transform::Transform::none()",
|
||||||
extra_prefixes=transform_extra_prefixes,
|
extra_prefixes=transform_extra_prefixes,
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
gecko_ffi_name="mSpecifiedTransform",
|
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \
|
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \
|
||||||
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
|
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
|
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
|
||||||
|
|
|
@ -81,7 +81,6 @@ ${helpers.predefined_type(
|
||||||
"Transform",
|
"Transform",
|
||||||
"generics::transform::Transform::none()",
|
"generics::transform::Transform::none()",
|
||||||
products="gecko",
|
products="gecko",
|
||||||
gecko_ffi_name="mSpecifiedWindowTransform",
|
|
||||||
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
spec="None (Nonstandard internal property)",
|
spec="None (Nonstandard internal property)",
|
||||||
|
|
|
@ -861,7 +861,7 @@ impl Animate for ComputedTransform {
|
||||||
// animation procedures so we treat it separately here rather than
|
// animation procedures so we treat it separately here rather than
|
||||||
// handling it in TransformOperation.
|
// handling it in TransformOperation.
|
||||||
if procedure == Procedure::Add {
|
if procedure == Procedure::Add {
|
||||||
let result = self.0.iter().chain(&other.0).cloned().collect::<Vec<_>>();
|
let result = self.0.iter().chain(&*other.0).cloned().collect();
|
||||||
return Ok(Transform(result));
|
return Ok(Transform(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,15 +898,15 @@ impl Animate for ComputedTransform {
|
||||||
},
|
},
|
||||||
Procedure::Interpolate { progress } => {
|
Procedure::Interpolate { progress } => {
|
||||||
result.push(TransformOperation::InterpolateMatrix {
|
result.push(TransformOperation::InterpolateMatrix {
|
||||||
from_list: Transform(this_remainder.to_vec()),
|
from_list: Transform(this_remainder.to_vec().into()),
|
||||||
to_list: Transform(other_remainder.to_vec()),
|
to_list: Transform(other_remainder.to_vec().into()),
|
||||||
progress: Percentage(progress as f32),
|
progress: Percentage(progress as f32),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
Procedure::Accumulate { count } => {
|
Procedure::Accumulate { count } => {
|
||||||
result.push(TransformOperation::AccumulateMatrix {
|
result.push(TransformOperation::AccumulateMatrix {
|
||||||
from_list: Transform(this_remainder.to_vec()),
|
from_list: Transform(this_remainder.to_vec().into()),
|
||||||
to_list: Transform(other_remainder.to_vec()),
|
to_list: Transform(other_remainder.to_vec().into()),
|
||||||
count: cmp::min(count, i32::max_value() as u64) as i32,
|
count: cmp::min(count, i32::max_value() as u64) as i32,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -927,8 +927,8 @@ impl Animate for ComputedTransform {
|
||||||
// matrix. Instead we need to wrap it in another ___Matrix type.
|
// matrix. Instead we need to wrap it in another ___Matrix type.
|
||||||
TransformOperation::AccumulateMatrix { .. } |
|
TransformOperation::AccumulateMatrix { .. } |
|
||||||
TransformOperation::InterpolateMatrix { .. } => {
|
TransformOperation::InterpolateMatrix { .. } => {
|
||||||
let transform_list = Transform(vec![transform.clone()]);
|
let transform_list = Transform(vec![transform.clone()].into());
|
||||||
let identity_list = Transform(vec![identity]);
|
let identity_list = Transform(vec![identity].into());
|
||||||
let (from_list, to_list) = if fill_right {
|
let (from_list, to_list) = if fill_right {
|
||||||
(transform_list, identity_list)
|
(transform_list, identity_list)
|
||||||
} else {
|
} else {
|
||||||
|
@ -970,7 +970,7 @@ impl Animate for ComputedTransform {
|
||||||
(None, None) => {},
|
(None, None) => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Transform(result))
|
Ok(Transform(result.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ use style_traits::{CssWriter, ToCss};
|
||||||
ToAnimatedZero,
|
ToAnimatedZero,
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Angle(CSSFloat);
|
pub struct Angle(CSSFloat);
|
||||||
|
|
||||||
impl ToCss for Angle {
|
impl ToCss for Angle {
|
||||||
|
|
|
@ -16,9 +16,9 @@ pub use crate::values::generics::transform::TransformStyle;
|
||||||
|
|
||||||
/// A single operation in a computed CSS `transform`
|
/// A single operation in a computed CSS `transform`
|
||||||
pub type TransformOperation =
|
pub type TransformOperation =
|
||||||
generic::TransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
|
generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
|
||||||
/// A computed CSS `transform`
|
/// A computed CSS `transform`
|
||||||
pub type Transform = generic::Transform<TransformOperation>;
|
pub type Transform = generic::GenericTransform<TransformOperation>;
|
||||||
|
|
||||||
/// The computed value of a CSS `<transform-origin>`
|
/// The computed value of a CSS `<transform-origin>`
|
||||||
pub type TransformOrigin =
|
pub type TransformOrigin =
|
||||||
|
@ -540,13 +540,13 @@ impl ToAnimatedZero for Transform {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|op| op.to_animated_zero())
|
.map(|op| op.to_animated_zero())
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<crate::OwnedSlice<_>, _>>()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A computed CSS `rotate`
|
/// A computed CSS `rotate`
|
||||||
pub type Rotate = generic::Rotate<Number, Angle>;
|
pub type Rotate = generic::GenericRotate<Number, Angle>;
|
||||||
|
|
||||||
impl Rotate {
|
impl Rotate {
|
||||||
/// Convert TransformOperation to Rotate.
|
/// Convert TransformOperation to Rotate.
|
||||||
|
@ -573,7 +573,7 @@ impl Rotate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A computed CSS `translate`
|
/// A computed CSS `translate`
|
||||||
pub type Translate = generic::Translate<LengthPercentage, Length>;
|
pub type Translate = generic::GenericTranslate<LengthPercentage, Length>;
|
||||||
|
|
||||||
impl Translate {
|
impl Translate {
|
||||||
/// Convert TransformOperation to Translate.
|
/// Convert TransformOperation to Translate.
|
||||||
|
@ -602,7 +602,7 @@ impl Translate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A computed CSS `scale`
|
/// A computed CSS `scale`
|
||||||
pub type Scale = generic::Scale<Number>;
|
pub type Scale = generic::GenericScale<Number>;
|
||||||
|
|
||||||
impl Scale {
|
impl Scale {
|
||||||
/// Convert TransformOperation to Scale.
|
/// Convert TransformOperation to Scale.
|
||||||
|
|
|
@ -30,8 +30,9 @@ use style_traits::{CssWriter, ToCss};
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[css(comma, function)]
|
#[css(comma, function = "matrix")]
|
||||||
pub struct Matrix<T> {
|
#[repr(C)]
|
||||||
|
pub struct GenericMatrix<T> {
|
||||||
pub a: T,
|
pub a: T,
|
||||||
pub b: T,
|
pub b: T,
|
||||||
pub c: T,
|
pub c: T,
|
||||||
|
@ -40,6 +41,8 @@ pub struct Matrix<T> {
|
||||||
pub f: T,
|
pub f: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericMatrix as Matrix;
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
#[css(comma, function = "matrix3d")]
|
#[css(comma, function = "matrix3d")]
|
||||||
|
@ -55,13 +58,16 @@ pub struct Matrix<T> {
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
pub struct Matrix3D<T> {
|
#[repr(C)]
|
||||||
|
pub struct GenericMatrix3D<T> {
|
||||||
pub m11: T, pub m12: T, pub m13: T, pub m14: T,
|
pub m11: T, pub m12: T, pub m13: T, pub m14: T,
|
||||||
pub m21: T, pub m22: T, pub m23: T, pub m24: T,
|
pub m21: T, pub m22: T, pub m23: T, pub m24: T,
|
||||||
pub m31: T, pub m32: T, pub m33: T, pub m34: T,
|
pub m31: T, pub m32: T, pub m33: T, pub m34: T,
|
||||||
pub m41: T, pub m42: T, pub m43: T, pub m44: T,
|
pub m41: T, pub m42: T, pub m43: T, pub m44: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericMatrix3D as Matrix3D;
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
|
impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -142,17 +148,19 @@ fn is_same<N: PartialEq>(x: &N, y: &N) -> bool {
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C, u8)]
|
||||||
/// A single operation in the list of a `transform` value
|
/// A single operation in the list of a `transform` value
|
||||||
pub enum TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
/// cbindgen:derive-tagged-enum-copy-constructor=true
|
||||||
|
pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
||||||
where
|
where
|
||||||
Angle: Zero,
|
Angle: Zero,
|
||||||
LengthPercentage: Zero,
|
LengthPercentage: Zero,
|
||||||
Number: PartialEq,
|
Number: PartialEq,
|
||||||
{
|
{
|
||||||
/// Represents a 2D 2x3 matrix.
|
/// Represents a 2D 2x3 matrix.
|
||||||
Matrix(Matrix<Number>),
|
Matrix(GenericMatrix<Number>),
|
||||||
/// Represents a 3D 4x4 matrix.
|
/// Represents a 3D 4x4 matrix.
|
||||||
Matrix3D(Matrix3D<Number>),
|
Matrix3D(GenericMatrix3D<Number>),
|
||||||
/// A 2D skew.
|
/// A 2D skew.
|
||||||
///
|
///
|
||||||
/// If the second angle is not provided it is assumed zero.
|
/// If the second angle is not provided it is assumed zero.
|
||||||
|
@ -232,20 +240,22 @@ where
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[css(comma, function = "interpolatematrix")]
|
#[css(comma, function = "interpolatematrix")]
|
||||||
InterpolateMatrix {
|
InterpolateMatrix {
|
||||||
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
from_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||||
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
to_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||||
progress: computed::Percentage,
|
progress: computed::Percentage,
|
||||||
},
|
},
|
||||||
/// A intermediate type for accumulation of mismatched transform lists.
|
/// A intermediate type for accumulation of mismatched transform lists.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[css(comma, function = "accumulatematrix")]
|
#[css(comma, function = "accumulatematrix")]
|
||||||
AccumulateMatrix {
|
AccumulateMatrix {
|
||||||
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
from_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||||
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
to_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||||
count: Integer,
|
count: Integer,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericTransformOperation as TransformOperation;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
Debug,
|
Debug,
|
||||||
|
@ -257,8 +267,11 @@ where
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C)]
|
||||||
/// A value of the `transform` property
|
/// A value of the `transform` property
|
||||||
pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>);
|
pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>);
|
||||||
|
|
||||||
|
pub use self::GenericTransform as Transform;
|
||||||
|
|
||||||
impl<Angle, Number, Length, Integer, LengthPercentage>
|
impl<Angle, Number, Length, Integer, LengthPercentage>
|
||||||
TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
||||||
|
@ -497,7 +510,7 @@ where
|
||||||
impl<T> Transform<T> {
|
impl<T> Transform<T> {
|
||||||
/// `none`
|
/// `none`
|
||||||
pub fn none() -> Self {
|
pub fn none() -> Self {
|
||||||
Transform(vec![])
|
Transform(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +542,7 @@ impl<T: ToMatrix> Transform<T> {
|
||||||
let mut transform = Transform3D::<f64>::identity();
|
let mut transform = Transform3D::<f64>::identity();
|
||||||
let mut contain_3d = false;
|
let mut contain_3d = false;
|
||||||
|
|
||||||
for operation in &self.0 {
|
for operation in &*self.0 {
|
||||||
let matrix = operation.to_3d_matrix(reference_box)?;
|
let matrix = operation.to_3d_matrix(reference_box)?;
|
||||||
contain_3d |= operation.is_3d();
|
contain_3d |= operation.is_3d();
|
||||||
transform = transform.pre_mul(&matrix);
|
transform = transform.pre_mul(&matrix);
|
||||||
|
@ -589,10 +602,11 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C, u8)]
|
||||||
/// A value of the `Rotate` property
|
/// A value of the `Rotate` property
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||||
pub enum Rotate<Number, Angle> {
|
pub enum GenericRotate<Number, Angle> {
|
||||||
/// 'none'
|
/// 'none'
|
||||||
None,
|
None,
|
||||||
/// '<angle>'
|
/// '<angle>'
|
||||||
|
@ -601,6 +615,8 @@ pub enum Rotate<Number, Angle> {
|
||||||
Rotate3D(Number, Number, Number, Angle),
|
Rotate3D(Number, Number, Number, Angle),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericRotate as Rotate;
|
||||||
|
|
||||||
/// A trait to check if the current 3D vector is parallel to the DirectionVector.
|
/// A trait to check if the current 3D vector is parallel to the DirectionVector.
|
||||||
/// This is especially for serialization on Rotate.
|
/// This is especially for serialization on Rotate.
|
||||||
pub trait IsParallelTo {
|
pub trait IsParallelTo {
|
||||||
|
@ -660,10 +676,11 @@ where
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C, u8)]
|
||||||
/// A value of the `Scale` property
|
/// A value of the `Scale` property
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||||
pub enum Scale<Number> {
|
pub enum GenericScale<Number> {
|
||||||
/// 'none'
|
/// 'none'
|
||||||
None,
|
None,
|
||||||
/// '<number>{1,2}'
|
/// '<number>{1,2}'
|
||||||
|
@ -672,6 +689,8 @@ pub enum Scale<Number> {
|
||||||
Scale3D(Number, Number, Number),
|
Scale3D(Number, Number, Number),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericScale as Scale;
|
||||||
|
|
||||||
impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
|
@ -710,6 +729,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(C, u8)]
|
||||||
/// A value of the `translate` property
|
/// A value of the `translate` property
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization:
|
/// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization:
|
||||||
|
@ -724,7 +744,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
||||||
/// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305
|
/// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||||
pub enum Translate<LengthPercentage, Length>
|
pub enum GenericTranslate<LengthPercentage, Length>
|
||||||
where
|
where
|
||||||
LengthPercentage: Zero,
|
LengthPercentage: Zero,
|
||||||
{
|
{
|
||||||
|
@ -739,6 +759,8 @@ where
|
||||||
Translate3D(LengthPercentage, LengthPercentage, Length),
|
Translate3D(LengthPercentage, LengthPercentage, Length),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericTranslate as Translate;
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl Transform {
|
||||||
.try(|input| input.expect_ident_matching("none"))
|
.try(|input| input.expect_ident_matching("none"))
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
return Ok(generic::Transform(Vec::new()));
|
return Ok(generic::Transform::none());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(generic::Transform(Space::parse(input, |input| {
|
Ok(generic::Transform(Space::parse(input, |input| {
|
||||||
|
@ -218,7 +218,7 @@ impl Transform {
|
||||||
.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone()))
|
.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})?))
|
})?.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue