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::Easing
| Type::Component(_)
| Type::PathElements
| Type::PathData
| Type::LayoutCache
| 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::LayoutCache
| Type::Model
| Type::PathElements => {
| Type::PathData => {
diag.push_error("Cannot debug this expression".into(), &node);
Expression::Invalid
}

View file

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

View file

@ -2297,7 +2297,7 @@ fn compile_expression(
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::CubicBezier(a, b, c, d)) => format!(
"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 } => {
if prop_name == "elements" {
// The `Path::elements` property is not in the NativeClasss
return &Type::PathElements;
return &Type::PathData;
}
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);
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,
}
}

View file

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

View file

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

View file

@ -166,7 +166,7 @@ pub fn lower_expression(
.map(|(s, e)| Some((s.clone(), lower_expression(e, ctx)?)))
.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::LinearGradient { angle, stops } => Some(llr_Expression::LinearGradient {
angle: Box::new(lower_expression(angle, ctx)?),
@ -873,12 +873,16 @@ fn compile_path(
.collect();
Some(llr_Expression::Cast {
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,
as_model: false,
}
.into(),
to: Type::PathElements,
to: Type::PathData,
})
}
crate::expression_tree::Path::Events(events) => {

View file

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

View file

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

View file

@ -118,7 +118,7 @@ pub struct PathQuadraticTo {
}
#[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.
pub enum PathElement {
/// The MoveTo variant sets the current position on the path.

View file

@ -102,7 +102,7 @@ pub enum Value {
Brush(Brush),
#[doc(hidden)]
/// The elements of a path
PathElements(PathData),
PathData(PathData),
#[doc(hidden)]
/// An easing curve
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::Struct(lhs) => matches!(other, Value::Struct(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::EnumerationValue(lhs_name, lhs_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::Struct(s) => write!(f, "Value::Struct({:?})", s),
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::EnumerationValue(n, v) => write!(f, "Value::EnumerationValue({:?}, {:?})", n, 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!(Struct => [Struct] );
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!(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)))
.collect(),
),
Expression::PathElements { elements } => {
Value::PathElements(convert_path(elements, local_context))
Expression::PathData(data) => {
Value::PathData(convert_path(data, local_context))
}
Expression::StoreLocalVariable { name, value } => {
let value = eval_expression(value, local_context);
@ -847,7 +847,7 @@ fn check_value_type(value: &Value, ty: &Type) -> bool {
Type::Model => {
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::Brush => matches!(value, Value::Brush(_)),
Type::Array(inner) => {
@ -1138,7 +1138,7 @@ pub fn default_value_for_type(ty: &Type) -> Value {
Type::Void | Type::Invalid => Value::Void,
Type::Model => Value::Void,
Type::UnitProduct(_) => Value::Number(0.),
Type::PathElements => Value::PathElements(Default::default()),
Type::PathData => Value::PathData(Default::default()),
Type::LayoutCache => Value::LayoutCache(Default::default()),
Type::InferredProperty
| Type::InferredCallback

View file

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