Fix build of Paths with path elements with rust/llr

A `Path` with `MoveTo`/`LineTo`/etc. sub-elements now maps to an Expression::PathData of type
Type::PathData.

The llr lowering creates an Array of Type::PathElement, which is casted to PathData.

This only covers the element case. The compiled path events are still todo.
This commit is contained in:
Simon Hausmann 2022-01-06 17:40:41 +01:00 committed by Olivier Goffart
parent d1298a9353
commit 9e61d4168b
14 changed files with 55 additions and 41 deletions

View file

@ -230,7 +230,7 @@ fn to_eval_value<'cx>(
| Type::Callback { .. } | Type::Callback { .. }
| Type::Easing | Type::Easing
| Type::Component(_) | Type::Component(_)
| Type::PathElements | Type::PathData
| Type::LayoutCache | Type::LayoutCache
| Type::ElementReference => cx.throw_error("Cannot convert to a Sixtyfps property value"), | Type::ElementReference => cx.throw_error("Cannot convert to a Sixtyfps property value"),
} }

View file

@ -182,7 +182,7 @@ fn to_debug_string(
| Type::ElementReference | Type::ElementReference
| Type::LayoutCache | Type::LayoutCache
| Type::Model | Type::Model
| Type::PathElements => { | Type::PathData => {
diag.push_error("Cannot debug this expression".into(), &node); diag.push_error("Cannot debug this expression".into(), &node);
Expression::Invalid Expression::Invalid
} }

View file

@ -431,9 +431,7 @@ pub enum Expression {
values: HashMap<String, Expression>, values: HashMap<String, Expression>,
}, },
PathElements { PathData(Path),
elements: Path,
},
EasingCurve(EasingCurve), EasingCurve(EasingCurve),
@ -585,7 +583,7 @@ impl Expression {
Expression::UnaryOp { sub, .. } => sub.ty(), Expression::UnaryOp { sub, .. } => sub.ty(),
Expression::Array { element_ty, .. } => Type::Array(Box::new(element_ty.clone())), Expression::Array { element_ty, .. } => Type::Array(Box::new(element_ty.clone())),
Expression::Struct { ty, .. } => ty.clone(), Expression::Struct { ty, .. } => ty.clone(),
Expression::PathElements { .. } => Type::PathElements, Expression::PathData { .. } => Type::PathData,
Expression::StoreLocalVariable { .. } => Type::Void, Expression::StoreLocalVariable { .. } => Type::Void,
Expression::ReadLocalVariable { ty, .. } => ty.clone(), Expression::ReadLocalVariable { ty, .. } => ty.clone(),
Expression::EasingCurve(_) => Type::Easing, Expression::EasingCurve(_) => Type::Easing,
@ -653,8 +651,8 @@ impl Expression {
visitor(x); visitor(x);
} }
} }
Expression::PathElements { elements } => { Expression::PathData(data) => {
if let Path::Elements(elements) = elements { if let Path::Elements(elements) = data {
for element in elements { for element in elements {
element.bindings.values().for_each(|binding| visitor(&binding.borrow())) element.bindings.values().for_each(|binding| visitor(&binding.borrow()))
} }
@ -735,8 +733,8 @@ impl Expression {
visitor(x); visitor(x);
} }
} }
Expression::PathElements { elements } => { Expression::PathData(data) => {
if let Path::Elements(elements) = elements { if let Path::Elements(elements) = data {
for element in elements { for element in elements {
element element
.bindings .bindings
@ -811,8 +809,8 @@ impl Expression {
Expression::UnaryOp { sub, .. } => sub.is_constant(), Expression::UnaryOp { sub, .. } => sub.is_constant(),
Expression::Array { values, .. } => values.iter().all(Expression::is_constant), Expression::Array { values, .. } => values.iter().all(Expression::is_constant),
Expression::Struct { values, .. } => values.iter().all(|(_, v)| v.is_constant()), Expression::Struct { values, .. } => values.iter().all(|(_, v)| v.is_constant()),
Expression::PathElements { elements } => { Expression::PathData(data) => {
if let Path::Elements(elements) = elements { if let Path::Elements(elements) = data {
elements elements
.iter() .iter()
.all(|element| element.bindings.values().all(|v| v.borrow().is_constant())) .all(|element| element.bindings.values().all(|v| v.borrow().is_constant()))
@ -1024,7 +1022,7 @@ impl Expression {
}, },
Type::Bool => Expression::BoolLiteral(false), Type::Bool => Expression::BoolLiteral(false),
Type::Model => Expression::Invalid, Type::Model => Expression::Invalid,
Type::PathElements => Expression::PathElements { elements: Path::Elements(vec![]) }, Type::PathData => Expression::PathData(Path::Elements(vec![])),
Type::Array(element_ty) => { Type::Array(element_ty) => {
Expression::Array { element_ty: (**element_ty).clone(), values: vec![] } Expression::Array { element_ty: (**element_ty).clone(), values: vec![] }
} }
@ -1319,7 +1317,7 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
} }
write!(f, " }}") write!(f, " }}")
} }
Expression::PathElements { elements } => write!(f, "{:?}", elements), Expression::PathData(data) => write!(f, "{:?}", data),
Expression::EasingCurve(e) => write!(f, "{:?}", e), Expression::EasingCurve(e) => write!(f, "{:?}", e),
Expression::LinearGradient { angle, stops } => { Expression::LinearGradient { angle, stops } => {
write!(f, "@linear-gradient(")?; write!(f, "@linear-gradient(")?;

View file

@ -2297,7 +2297,7 @@ fn compile_expression(
panic!("Expression::Object is not a Type::Object") panic!("Expression::Object is not a Type::Object")
} }
} }
Expression::PathElements { elements } => compile_path(elements, component), Expression::PathData(data) => compile_path(data, component),
Expression::EasingCurve(EasingCurve::Linear) => "sixtyfps::cbindgen_private::EasingCurve()".into(), Expression::EasingCurve(EasingCurve::Linear) => "sixtyfps::cbindgen_private::EasingCurve()".into(),
Expression::EasingCurve(EasingCurve::CubicBezier(a, b, c, d)) => format!( Expression::EasingCurve(EasingCurve::CubicBezier(a, b, c, d)) => format!(
"sixtyfps::cbindgen_private::EasingCurve(sixtyfps::cbindgen_private::EasingCurve::Tag::CubicBezier, {}, {}, {}, {})", "sixtyfps::cbindgen_private::EasingCurve(sixtyfps::cbindgen_private::EasingCurve::Tag::CubicBezier, {}, {}, {}, {})",

View file

@ -1343,7 +1343,7 @@ impl<'a> llr::EvaluationContext for EvaluationContext<'a> {
llr::PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => { llr::PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => {
if prop_name == "elements" { if prop_name == "elements" {
// The `Path::elements` property is not in the NativeClasss // The `Path::elements` property is not in the NativeClasss
return &Type::PathElements; return &Type::PathData;
} }
let mut sub_component = self.current_sub_component.unwrap(); let mut sub_component = self.current_sub_component.unwrap();
@ -1413,6 +1413,22 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
let id = struct_name_to_tokens(n); let id = struct_name_to_tokens(n);
quote!({ let obj = #f; #id { #(#fields),*} }) quote!({ let obj = #f; #id { #(#fields),*} })
} }
(Type::Array(..), Type::PathData)
if matches!(
from.as_ref(),
Expression::Array { element_ty: Type::Struct { .. }, .. }
) =>
{
let path_elements = match from.as_ref() {
Expression::Array { element_ty: _, values, as_model: _ } => values
.iter()
.map(|path_elem_expr| compile_expression(path_elem_expr, ctx)),
_ => {
unreachable!()
}
};
quote!(sixtyfps::re_exports::PathData::Elements(sixtyfps::re_exports::SharedVector::<_>::from_slice(&[#((#path_elements).into()),*])))
}
_ => f, _ => f,
} }
} }

View file

@ -49,7 +49,7 @@ pub enum Type {
Image, Image,
Bool, Bool,
Model, Model,
PathElements, PathData, // Either a vector of path elements or a two vectors of events and coordinates
Easing, Easing,
Brush, Brush,
/// This is usually a model /// This is usually a model
@ -103,7 +103,7 @@ impl core::cmp::PartialEq for Type {
Type::Image => matches!(other, Type::Image), Type::Image => matches!(other, Type::Image),
Type::Bool => matches!(other, Type::Bool), Type::Bool => matches!(other, Type::Bool),
Type::Model => matches!(other, Type::Model), Type::Model => matches!(other, Type::Model),
Type::PathElements => matches!(other, Type::PathElements), Type::PathData => matches!(other, Type::PathData),
Type::Easing => matches!(other, Type::Easing), Type::Easing => matches!(other, Type::Easing),
Type::Brush => matches!(other, Type::Brush), Type::Brush => matches!(other, Type::Brush),
Type::Array(a) => matches!(other, Type::Array(b) if a == b), Type::Array(a) => matches!(other, Type::Array(b) if a == b),
@ -177,7 +177,7 @@ impl Display for Type {
write!(f, "}}") write!(f, "}}")
} }
Type::PathElements => write!(f, "pathelements"), Type::PathData => write!(f, "pathdata"),
Type::Easing => write!(f, "easing"), Type::Easing => write!(f, "easing"),
Type::Brush => write!(f, "brush"), Type::Brush => write!(f, "brush"),
Type::Enumeration(enumeration) => write!(f, "enum {}", enumeration.name), Type::Enumeration(enumeration) => write!(f, "enum {}", enumeration.name),
@ -484,7 +484,7 @@ impl Type {
Type::Image => None, Type::Image => None,
Type::Bool => None, Type::Bool => None,
Type::Model => None, Type::Model => None,
Type::PathElements => None, Type::PathData => None,
Type::Easing => None, Type::Easing => None,
Type::Brush => None, Type::Brush => None,
Type::Array(_) => None, Type::Array(_) => None,

View file

@ -190,7 +190,7 @@ impl Expression {
}, },
Type::Bool => Expression::BoolLiteral(false), Type::Bool => Expression::BoolLiteral(false),
Type::Model => return None, Type::Model => return None,
Type::PathElements => Expression::PathEvents(Default::default()), Type::PathData => Expression::PathEvents(Default::default()),
Type::Array(element_ty) => Expression::Array { Type::Array(element_ty) => Expression::Array {
element_ty: (**element_ty).clone(), element_ty: (**element_ty).clone(),
values: vec![], values: vec![],

View file

@ -166,7 +166,7 @@ pub fn lower_expression(
.map(|(s, e)| Some((s.clone(), lower_expression(e, ctx)?))) .map(|(s, e)| Some((s.clone(), lower_expression(e, ctx)?)))
.collect::<Option<_>>()?, .collect::<Option<_>>()?,
}), }),
tree_Expression::PathElements { elements } => compile_path(elements, ctx), tree_Expression::PathData(data) => compile_path(data, ctx),
tree_Expression::EasingCurve(x) => Some(llr_Expression::EasingCurve(x.clone())), tree_Expression::EasingCurve(x) => Some(llr_Expression::EasingCurve(x.clone())),
tree_Expression::LinearGradient { angle, stops } => Some(llr_Expression::LinearGradient { tree_Expression::LinearGradient { angle, stops } => Some(llr_Expression::LinearGradient {
angle: Box::new(lower_expression(angle, ctx)?), angle: Box::new(lower_expression(angle, ctx)?),
@ -873,12 +873,16 @@ fn compile_path(
.collect(); .collect();
Some(llr_Expression::Cast { Some(llr_Expression::Cast {
from: llr_Expression::Array { from: llr_Expression::Array {
element_ty: Type::PathElements, element_ty: Type::Struct {
fields: Default::default(),
name: Some("PathElement".to_owned()),
node: None,
},
values: converted_elements, values: converted_elements,
as_model: false, as_model: false,
} }
.into(), .into(),
to: Type::PathElements, to: Type::PathData,
}) })
} }
crate::expression_tree::Path::Events(events) => { crate::expression_tree::Path::Events(events) => {

View file

@ -115,9 +115,7 @@ pub fn compile_paths(
crate::expression_tree::Path::Elements(path_data) crate::expression_tree::Path::Elements(path_data)
}; };
elem.bindings.insert( elem.bindings
"elements".into(), .insert("elements".into(), RefCell::new(Expression::PathData(path_data).into()));
RefCell::new(Expression::PathElements { elements: path_data }.into()),
);
}); });
} }

View file

@ -596,9 +596,7 @@ fn lower_path_layout(layout_element: &ElementRc, diag: &mut BuildDiagnostics) {
.remove("elements") .remove("elements")
.map(RefCell::into_inner) .map(RefCell::into_inner)
{ {
Some(BindingExpression { expression: Expression::PathElements { elements }, .. }) => { Some(BindingExpression { expression: Expression::PathData(data), .. }) => data,
elements
}
_ => { _ => {
diag.push_error("Internal error: elements binding in PathLayout does not contain path elements expression".into(), &*layout_element.borrow()); diag.push_error("Internal error: elements binding in PathLayout does not contain path elements expression".into(), &*layout_element.borrow());
return; return;

View file

@ -118,7 +118,7 @@ pub struct PathQuadraticTo {
} }
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, derive_more::From)]
/// PathElement describes a single element on a path, such as move-to, line-to, etc. /// PathElement describes a single element on a path, such as move-to, line-to, etc.
pub enum PathElement { pub enum PathElement {
/// The MoveTo variant sets the current position on the path. /// The MoveTo variant sets the current position on the path.

View file

@ -102,7 +102,7 @@ pub enum Value {
Brush(Brush), Brush(Brush),
#[doc(hidden)] #[doc(hidden)]
/// The elements of a path /// The elements of a path
PathElements(PathData), PathData(PathData),
#[doc(hidden)] #[doc(hidden)]
/// An easing curve /// An easing curve
EasingCurve(sixtyfps_corelib::animations::EasingCurve), EasingCurve(sixtyfps_corelib::animations::EasingCurve),
@ -150,7 +150,7 @@ impl PartialEq for Value {
Value::Model(lhs) => matches!(other, Value::Model(rhs) if Rc::ptr_eq(lhs, rhs)), Value::Model(lhs) => matches!(other, Value::Model(rhs) if Rc::ptr_eq(lhs, rhs)),
Value::Struct(lhs) => matches!(other, Value::Struct(rhs) if lhs == rhs), Value::Struct(lhs) => matches!(other, Value::Struct(rhs) if lhs == rhs),
Value::Brush(lhs) => matches!(other, Value::Brush(rhs) if lhs == rhs), Value::Brush(lhs) => matches!(other, Value::Brush(rhs) if lhs == rhs),
Value::PathElements(lhs) => matches!(other, Value::PathElements(rhs) if lhs == rhs), Value::PathData(lhs) => matches!(other, Value::PathData(rhs) if lhs == rhs),
Value::EasingCurve(lhs) => matches!(other, Value::EasingCurve(rhs) if lhs == rhs), Value::EasingCurve(lhs) => matches!(other, Value::EasingCurve(rhs) if lhs == rhs),
Value::EnumerationValue(lhs_name, lhs_value) => { Value::EnumerationValue(lhs_name, lhs_value) => {
matches!(other, Value::EnumerationValue(rhs_name, rhs_value) if lhs_name == rhs_name && lhs_value == rhs_value) matches!(other, Value::EnumerationValue(rhs_name, rhs_value) if lhs_name == rhs_name && lhs_value == rhs_value)
@ -172,7 +172,7 @@ impl std::fmt::Debug for Value {
Value::Model(_) => write!(f, "Value::Model(<model object>)"), Value::Model(_) => write!(f, "Value::Model(<model object>)"),
Value::Struct(s) => write!(f, "Value::Struct({:?})", s), Value::Struct(s) => write!(f, "Value::Struct({:?})", s),
Value::Brush(b) => write!(f, "Value::Brush({:?})", b), Value::Brush(b) => write!(f, "Value::Brush({:?})", b),
Value::PathElements(e) => write!(f, "Value::PathElements({:?})", e), Value::PathData(e) => write!(f, "Value::PathElements({:?})", e),
Value::EasingCurve(c) => write!(f, "Value::EasingCurve({:?})", c), Value::EasingCurve(c) => write!(f, "Value::EasingCurve({:?})", c),
Value::EnumerationValue(n, v) => write!(f, "Value::EnumerationValue({:?}, {:?})", n, v), Value::EnumerationValue(n, v) => write!(f, "Value::EnumerationValue({:?}, {:?})", n, v),
Value::LayoutCache(v) => write!(f, "Value::LayoutCache({:?})", v), Value::LayoutCache(v) => write!(f, "Value::LayoutCache({:?})", v),
@ -215,7 +215,7 @@ declare_value_conversion!(Bool => [bool] );
declare_value_conversion!(Image => [Image] ); declare_value_conversion!(Image => [Image] );
declare_value_conversion!(Struct => [Struct] ); declare_value_conversion!(Struct => [Struct] );
declare_value_conversion!(Brush => [Brush] ); declare_value_conversion!(Brush => [Brush] );
declare_value_conversion!(PathElements => [PathData]); declare_value_conversion!(PathData => [PathData]);
declare_value_conversion!(EasingCurve => [sixtyfps_corelib::animations::EasingCurve]); declare_value_conversion!(EasingCurve => [sixtyfps_corelib::animations::EasingCurve]);
declare_value_conversion!(LayoutCache => [SharedVector<f32>] ); declare_value_conversion!(LayoutCache => [SharedVector<f32>] );

View file

@ -561,8 +561,8 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
.map(|(k, v)| (k.clone(), eval_expression(v, local_context))) .map(|(k, v)| (k.clone(), eval_expression(v, local_context)))
.collect(), .collect(),
), ),
Expression::PathElements { elements } => { Expression::PathData(data) => {
Value::PathElements(convert_path(elements, local_context)) Value::PathData(convert_path(data, local_context))
} }
Expression::StoreLocalVariable { name, value } => { Expression::StoreLocalVariable { name, value } => {
let value = eval_expression(value, local_context); let value = eval_expression(value, local_context);
@ -847,7 +847,7 @@ fn check_value_type(value: &Value, ty: &Type) -> bool {
Type::Model => { Type::Model => {
matches!(value, Value::Model(_) | Value::Bool(_) | Value::Number(_) | Value::Array(_)) matches!(value, Value::Model(_) | Value::Bool(_) | Value::Number(_) | Value::Array(_))
} }
Type::PathElements => matches!(value, Value::PathElements(_)), Type::PathData => matches!(value, Value::PathData(_)),
Type::Easing => matches!(value, Value::EasingCurve(_)), Type::Easing => matches!(value, Value::EasingCurve(_)),
Type::Brush => matches!(value, Value::Brush(_)), Type::Brush => matches!(value, Value::Brush(_)),
Type::Array(inner) => { Type::Array(inner) => {
@ -1138,7 +1138,7 @@ pub fn default_value_for_type(ty: &Type) -> Value {
Type::Void | Type::Invalid => Value::Void, Type::Void | Type::Invalid => Value::Void,
Type::Model => Value::Void, Type::Model => Value::Void,
Type::UnitProduct(_) => Value::Number(0.), Type::UnitProduct(_) => Value::Number(0.),
Type::PathElements => Value::PathElements(Default::default()), Type::PathData => Value::PathData(Default::default()),
Type::LayoutCache => Value::LayoutCache(Default::default()), Type::LayoutCache => Value::LayoutCache(Default::default()),
Type::InferredProperty Type::InferredProperty
| Type::InferredCallback | Type::InferredCallback

View file

@ -145,7 +145,7 @@ pub(crate) fn solve_layout(
x: 0., x: 0.,
y: 0., y: 0.,
elements: &eval::eval_expression( elements: &eval::eval_expression(
&Expression::PathElements { elements: path_layout.path.clone() }, &Expression::PathData(path_layout.path.clone()),
local_context, local_context,
) )
.try_into() .try_into()