Simplify compiled path data structure

Use two arrays, one for events and one for coordinates. That simplifies
the code generator and the generated code, and it also provides for
a more compact memory representation.
This commit is contained in:
Simon Hausmann 2020-07-10 10:17:02 +02:00
parent 264b1f650f
commit 4b6e549b96
7 changed files with 254 additions and 313 deletions

View file

@ -8,12 +8,8 @@ namespace sixtyfps {
using internal::types::PathArcTo; using internal::types::PathArcTo;
using internal::types::PathElement; using internal::types::PathElement;
using internal::types::PathEvent; using internal::types::PathEvent;
using internal::types::PathEventBegin;
using internal::types::PathEventCubic;
using internal::types::PathEventEnd;
using internal::types::PathEventLine;
using internal::types::PathEventQuadratic;
using internal::types::PathLineTo; using internal::types::PathLineTo;
using internal::types::Point;
struct PathElements struct PathElements
{ {
@ -26,8 +22,9 @@ public:
{ {
} }
PathElements(const PathEvent *firstEvent, size_t count) PathElements(const PathEvent *firstEvent, size_t event_count, const Point *firstCoordinate,
: data(Data::PathEvents(events_from_array(firstEvent, count))) size_t coordinate_count)
: data(events_from_array(firstEvent, event_count, firstCoordinate, coordinate_count))
{ {
} }
@ -40,11 +37,16 @@ private:
return tmp; return tmp;
} }
static SharedArray<PathEvent> events_from_array(const PathEvent *firstEvent, size_t count) static internal::types::PathElements events_from_array(const PathEvent *firstEvent,
size_t event_count,
const Point *firstCoordinate,
size_t coordinate_count)
{ {
SharedArray<PathEvent> tmp; SharedArray<PathEvent> events;
sixtyfps_new_path_events(&tmp, firstEvent, count); SharedArray<Point> coordinates;
return tmp; sixtyfps_new_path_events(&events, &coordinates, firstEvent, event_count, firstCoordinate,
coordinate_count);
return Data::PathEvents(events, coordinates);
} }
using Data = internal::types::PathElements; using Data = internal::types::PathElements;

View file

@ -1,10 +1,7 @@
use core::cell::RefCell; use core::cell::RefCell;
use neon::prelude::*; use neon::prelude::*;
use sixtyfps_compilerlib::typeregister::Type; use sixtyfps_compilerlib::typeregister::Type;
use sixtyfps_corelib::abi::datastructures::{ use sixtyfps_corelib::abi::datastructures::{PathArcTo, PathElement, PathLineTo, Resource};
PathArcTo, PathElement, PathEvent, PathEventBegin, PathEventCubic, PathEventEnd, PathEventLine,
PathEventQuadratic, PathLineTo, Resource,
};
use sixtyfps_corelib::{ComponentRefPin, EvaluationContext}; use sixtyfps_corelib::{ComponentRefPin, EvaluationContext};
use std::rc::Rc; use std::rc::Rc;
@ -235,79 +232,7 @@ fn to_js_value<'cx>(
} }
js_array.as_value(cx) js_array.as_value(cx)
} else { } else {
let events_iter = elements.events_iter().unwrap(); todo!()
let js_array = JsArray::new(cx, events_iter.len() as _);
for (i, event) in events_iter.enumerate() {
let element_object = JsObject::new(cx);
match event {
PathEvent::Begin(PathEventBegin { x, y }) => {
set_string_property(cx, &element_object, "type", "event_begin")?;
set_float_property(cx, &element_object, "x", *x)?;
set_float_property(cx, &element_object, "y", *y)?;
}
PathEvent::Line(PathEventLine { from_x, from_y, to_x, to_y }) => {
set_string_property(cx, &element_object, "type", "event_line")?;
set_float_property(cx, &element_object, "from_x", *from_x)?;
set_float_property(cx, &element_object, "from_y", *from_y)?;
set_float_property(cx, &element_object, "to_x", *to_x)?;
set_float_property(cx, &element_object, "to_y", *to_y)?;
}
PathEvent::Quadratic(PathEventQuadratic {
from_x,
from_y,
control_x,
control_y,
to_x,
to_y,
}) => {
set_string_property(cx, &element_object, "type", "event_quadratic")?;
set_float_property(cx, &element_object, "from_x", *from_x)?;
set_float_property(cx, &element_object, "from_y", *from_y)?;
set_float_property(cx, &element_object, "control_x", *control_x)?;
set_float_property(cx, &element_object, "control_y", *control_y)?;
set_float_property(cx, &element_object, "to_x", *to_x)?;
set_float_property(cx, &element_object, "to_y", *to_y)?;
}
PathEvent::Cubic(PathEventCubic {
from_x,
from_y,
control1_x,
control1_y,
control2_x,
control2_y,
to_x,
to_y,
}) => {
set_string_property(cx, &element_object, "type", "event_cubic")?;
set_float_property(cx, &element_object, "from_x", *from_x)?;
set_float_property(cx, &element_object, "from_y", *from_y)?;
set_float_property(cx, &element_object, "control1_x", *control1_x)?;
set_float_property(cx, &element_object, "control1_y", *control1_y)?;
set_float_property(cx, &element_object, "control2_x", *control2_x)?;
set_float_property(cx, &element_object, "control2_y", *control2_y)?;
set_float_property(cx, &element_object, "to_x", *to_x)?;
set_float_property(cx, &element_object, "to_y", *to_y)?;
}
PathEvent::End(PathEventEnd {
first_x,
first_y,
last_x,
last_y,
close,
}) => {
set_string_property(cx, &element_object, "type", "event_end")?;
set_float_property(cx, &element_object, "first_x", *first_x)?;
set_float_property(cx, &element_object, "first_y", *first_y)?;
set_float_property(cx, &element_object, "last_x", *last_x)?;
set_float_property(cx, &element_object, "last_y", *last_y)?;
set_bool_property(cx, &element_object, "close", *close)?;
}
}
js_array.set(cx, i as u32, element_object)?;
}
js_array.as_value(cx)
} }
} }
}) })

View file

@ -931,23 +931,6 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
res res
} }
fn new_path_event(event_name: &str, fields: &[(&str, String)]) -> String {
let fields_initialization: Vec<String> = fields
.iter()
.map(|(prop, initializer)| format!("var.{} = {};", prop, initializer))
.collect();
format!(
r#"[&](){{
{} var{{}};
{}
return var;
}}()"#,
event_name,
fields_initialization.join("\n")
)
}
fn compile_path(path: &crate::expression_tree::Path, component: &Rc<Component>) -> String { fn compile_path(path: &crate::expression_tree::Path, component: &Rc<Component>) -> String {
match path { match path {
crate::expression_tree::Path::Elements(elements) => { crate::expression_tree::Path::Elements(elements) => {
@ -980,89 +963,73 @@ fn compile_path(path: &crate::expression_tree::Path, component: &Rc<Component>)
) )
} }
crate::expression_tree::Path::Events(events) => { crate::expression_tree::Path::Events(events) => {
let converted_elements: Vec<String> = compile_path_events(events); let (converted_events, converted_coordinates) = compile_path_events(events);
format!( format!(
r#"[&](){{ r#"[&](){{
sixtyfps::PathEvent events[{}] = {{ sixtyfps::PathEvent events[{}] = {{
{} {}
}}; }};
return sixtyfps::PathElements(&events[0], std::size(events)); sixtyfps::Point coordinates[{}] = {{
{}
}};
return sixtyfps::PathElements(&events[0], std::size(events), &coordinates[0], std::size(coordinates));
}}()"#, }}()"#,
converted_elements.len(), converted_events.len(),
converted_elements.join(",") converted_events.join(","),
converted_coordinates.len(),
converted_coordinates.join(",")
) )
} }
} }
} }
fn compile_path_events(events: &crate::expression_tree::PathEvents) -> Vec<String> { fn compile_path_events(events: &crate::expression_tree::PathEvents) -> (Vec<String>, Vec<String>) {
use lyon::path::Event; use lyon::path::Event;
events let mut coordinates = Vec::new();
let events = events
.iter() .iter()
.map(|event| match event { .map(|event| match event {
Event::Begin { at } => format!( Event::Begin { at } => {
"sixtyfps::PathEvent::Begin({})", coordinates.push(at);
new_path_event( "sixtyfps::PathEvent::Begin"
"sixtyfps::PathEventBegin", }
&[("x", at.x.to_string()), ("y", at.y.to_string())] Event::Line { from, to } => {
) coordinates.push(from);
), coordinates.push(to);
Event::Line { from, to } => format!( "sixtyfps::PathEvent::Line"
"sixtyfps::PathEvent::Line({})", }
new_path_event( Event::Quadratic { from, ctrl, to } => {
"sixtyfps::PathEventLine", coordinates.push(from);
&[ coordinates.push(ctrl);
("from_x", from.x.to_string()), coordinates.push(to);
("from_y", from.y.to_string()), "sixtyfps::PathEvent::Quadratic"
("to_x", to.x.to_string()), }
("to_y", to.y.to_string()) Event::Cubic { from, ctrl1, ctrl2, to } => {
] coordinates.push(from);
) coordinates.push(ctrl1);
), coordinates.push(ctrl2);
Event::Quadratic { from, ctrl, to } => format!( coordinates.push(to);
"sixtyfps::PathEvent::Quadratic({})", "sixtyfps::PathEvent::Cubic"
new_path_event( }
"sixtyfps::PathEventQuadratic", Event::End { last, first, close } => {
&[ debug_assert_eq!(coordinates.first(), Some(&first));
("from_x", from.x.to_string()), debug_assert_eq!(coordinates.last(), Some(&last));
("from_y", from.y.to_string()), if *close {
("control_x", ctrl.x.to_string()), "sixtyfps::PathEvent::EndClosed"
("control_y", ctrl.y.to_string()), } else {
("to_x", to.x.to_string()), "sixtyfps::PathEvent::EndOpen"
("to_y", to.y.to_string()) }
] }
) })
), .map(String::from)
Event::Cubic { from, ctrl1, ctrl2, to } => format!( .collect();
"sixtyfps::PathEvent::Cubic({})",
new_path_event( let coordinates = coordinates
"sixtyfps::PathEventCubic", .into_iter()
&[ .map(|pt| format!("sixtyfps::Point{{{}, {}}}", pt.x, pt.y))
("from_x", from.x.to_string()), .collect();
("from_y", from.y.to_string()),
("control1_x", ctrl1.x.to_string()), (events, coordinates)
("control1_y", ctrl1.y.to_string()),
("control2_x", ctrl2.x.to_string()),
("control2_y", ctrl2.y.to_string()),
("to_x", to.x.to_string()),
("to_y", to.y.to_string())
]
)
),
Event::End { last, first, close } => format!(
"sixtyfps::PathEvent::End({})",
new_path_event(
"sixtyfps::PathEventEnd",
&[
("first_x", first.x.to_string()),
("first_y", first.y.to_string()),
("last_x", last.x.to_string()),
("last_y", last.y.to_string()),
("close", close.to_string())
]
)
),
})
.collect()
} }

View file

@ -791,52 +791,56 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
fn compile_path_events(events: &crate::expression_tree::PathEvents) -> TokenStream { fn compile_path_events(events: &crate::expression_tree::PathEvents) -> TokenStream {
use lyon::path::Event; use lyon::path::Event;
let mut coordinates = Vec::new();
let converted_events: Vec<proc_macro2::TokenStream> = events let converted_events: Vec<proc_macro2::TokenStream> = events
.iter() .iter()
.map(|event| match event { .map(|event| match event {
Event::Begin { at } => { Event::Begin { at } => {
let x = at.x; coordinates.push(at);
let y = at.y; quote!(sixtyfps::re_exports::PathEvent::Begin)
quote!(sixtyfps::re_exports::PathEvent::Begin(sixtyfps::re_exports::PathEventBegin{x: #x, y: #y}))
} }
Event::Line { from, to } => { Event::Line { from, to } => {
let from_x = from.x; coordinates.push(from);
let from_y = from.y; coordinates.push(to);
let to_x = to.x; quote!(sixtyfps::re_exports::PathEvent::Line)
let to_y = to.y;
quote!(sixtyfps::re_exports::PathEvent::Line(sixtyfps::re_exports::PathEventLine{from_x: #from_x, from_y: #from_y, to_x: #to_x, to_y: #to_y}))
} }
Event::Quadratic { from, ctrl, to } => { Event::Quadratic { from, ctrl, to } => {
let from_x = from.x; coordinates.push(from);
let from_y = from.y; coordinates.push(ctrl);
let control_x = ctrl.x; coordinates.push(to);
let control_y = ctrl.y; quote!(sixtyfps::re_exports::PathEvent::Quadratic)
let to_x = to.x;
let to_y = to.y;
quote!(sixtyfps::re_exports::PathEvent::Quadratic(sixtyfps::re_exports::PathEventQuadratic{from_x: #from_x, from_y: #from_y, control_x: #control_x, control_y: #control_y, to_x: #to_x, to_y: #to_y}))
} }
Event::Cubic { from, ctrl1, ctrl2, to } => { Event::Cubic { from, ctrl1, ctrl2, to } => {
let from_x = from.x; coordinates.push(from);
let from_y = from.y; coordinates.push(ctrl1);
let control1_x = ctrl1.x; coordinates.push(ctrl2);
let control1_y = ctrl1.y; coordinates.push(to);
let control2_x = ctrl2.x; quote!(sixtyfps::re_exports::PathEvent::Cubic)
let control2_y = ctrl2.y;
let to_x = to.x;
let to_y = to.y;
quote!(sixtyfps::re_exports::PathEvent::Cubic(sixtyfps::re_exports::PathEventCubic{from_x: #from_x, from_y: #from_y, control1_x: #control1_x, control1_y: #control1_y, control2_x: #control2_x, control2_y: #control2_y, to_x: #to_x, to_y: #to_y}))
} }
Event::End { last, first, close } => { Event::End { last, first, close } => {
let first_x = first.x; debug_assert_eq!(coordinates.first(), Some(&first));
let first_y = first.y; debug_assert_eq!(coordinates.last(), Some(&last));
let last_x = last.x; if *close {
let last_y = last.y; quote!(sixtyfps::re_exports::PathEvent::EndClosed)
quote!(sixtyfps::re_exports::PathEvent::End(sixtyfps::re_exports::PathEventEnd{first_x: #first_x, first_y: #first_y, last_x: #last_x, last_y: #last_y, close: #close})) } else {
quote!(sixtyfps::re_exports::PathEvent::EndOpen)
}
} }
}) })
.collect(); .collect();
quote!(sixtyfps::re_exports::SharedArray::<sixtyfps::re_exports::PathEvent>::from(&[#(#converted_events),*])) let coordinates: Vec<TokenStream> = coordinates
.into_iter()
.map(|pt| {
let x = pt.x;
let y = pt.y;
quote!(sixtyfps::re_exports::Point::new(#x, #y))
})
.collect();
quote!(sixtyfps::re_exports::SharedArray::<sixtyfps::re_exports::PathEvent>::from(&[#(#converted_events),*]),
sixtyfps::re_exports::SharedArray::<sixtyfps::re_exports::Point>::from(&[#(#coordinates),*]))
} }
fn compile_path(path: &Path, component: &Rc<Component>) -> TokenStream { fn compile_path(path: &Path, component: &Rc<Component>) -> TokenStream {

View file

@ -426,86 +426,67 @@ pub struct PathEventEnd {
/// generated at compile time from a higher-level description, such as SVG commands. /// generated at compile time from a higher-level description, such as SVG commands.
pub enum PathEvent { pub enum PathEvent {
/// The beginning of the path. /// The beginning of the path.
Begin(PathEventBegin), Begin,
/// A straight line on the path. /// A straight line on the path.
Line(PathEventLine), Line,
/// A quadratic bezier curve on the path. /// A quadratic bezier curve on the path.
Quadratic(PathEventQuadratic), Quadratic,
/// A cubic bezier curve on the path. /// A cubic bezier curve on the path.
Cubic(PathEventCubic), Cubic,
/// The end of the path. /// The end of the path that remains open.
End(PathEventEnd), EndOpen,
/// The end of a path that is closed.
EndClosed,
} }
impl From<&PathEvent> for lyon::path::Event<lyon::math::Point, lyon::math::Point> { struct ToLyonPathEventIterator<'a> {
fn from(event: &PathEvent) -> Self { events_it: std::slice::Iter<'a, PathEvent>,
use lyon::math::Point; coordinates_it: std::slice::Iter<'a, Point>,
use lyon::path::Event; first: Option<&'a Point>,
match event { last: Option<&'a Point>,
PathEvent::Begin(begin) => Event::Begin { at: Point::new(begin.x, begin.y) },
PathEvent::Line(line) => Event::Line {
from: Point::new(line.from_x, line.from_y),
to: Point::new(line.to_x, line.to_y),
},
PathEvent::Quadratic(curve) => Event::Quadratic {
from: Point::new(curve.from_x, curve.from_y),
ctrl: Point::new(curve.control_x, curve.control_y),
to: Point::new(curve.to_x, curve.to_y),
},
PathEvent::Cubic(curve) => Event::Cubic {
from: Point::new(curve.from_x, curve.from_y),
ctrl1: Point::new(curve.control1_x, curve.control1_y),
ctrl2: Point::new(curve.control2_x, curve.control2_y),
to: Point::new(curve.to_x, curve.to_y),
},
PathEvent::End(end) => Event::End {
first: Point::new(end.first_x, end.first_y),
last: Point::new(end.last_x, end.last_y),
close: end.close,
},
} }
impl<'a> Iterator for ToLyonPathEventIterator<'a> {
type Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>;
fn next(&mut self) -> Option<Self::Item> {
use lyon::path::Event;
self.events_it.next().map(|event| match event {
PathEvent::Begin => Event::Begin { at: self.coordinates_it.next().unwrap().clone() },
PathEvent::Line => Event::Line {
from: self.coordinates_it.next().unwrap().clone(),
to: self.coordinates_it.next().unwrap().clone(),
},
PathEvent::Quadratic => Event::Quadratic {
from: self.coordinates_it.next().unwrap().clone(),
ctrl: self.coordinates_it.next().unwrap().clone(),
to: self.coordinates_it.next().unwrap().clone(),
},
PathEvent::Cubic => Event::Cubic {
from: self.coordinates_it.next().unwrap().clone(),
ctrl1: self.coordinates_it.next().unwrap().clone(),
ctrl2: self.coordinates_it.next().unwrap().clone(),
to: self.coordinates_it.next().unwrap().clone(),
},
PathEvent::EndOpen => Event::End {
first: self.first.unwrap().clone(),
last: self.last.unwrap().clone(),
close: false,
},
PathEvent::EndClosed => Event::End {
first: self.first.unwrap().clone(),
last: self.last.unwrap().clone(),
close: true,
},
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.events_it.size_hint()
} }
} }
impl From<&lyon::path::Event<lyon::math::Point, lyon::math::Point>> for PathEvent { impl<'a> ExactSizeIterator for ToLyonPathEventIterator<'a> {}
fn from(event: &lyon::path::Event<lyon::math::Point, lyon::math::Point>) -> Self {
use lyon::path::Event;
match event {
Event::Begin { at } => PathEvent::Begin(PathEventBegin { x: at.x, y: at.y }),
Event::Line { from, to } => PathEvent::Line(PathEventLine {
from_x: from.x,
from_y: from.y,
to_x: to.x,
to_y: to.y,
}),
Event::Quadratic { from, ctrl, to } => PathEvent::Quadratic(PathEventQuadratic {
from_x: from.x,
from_y: from.y,
control_x: ctrl.x,
control_y: ctrl.y,
to_x: to.x,
to_y: to.y,
}),
Event::Cubic { from, ctrl1, ctrl2, to } => PathEvent::Cubic(PathEventCubic {
from_x: from.x,
from_y: from.y,
control1_x: ctrl1.x,
control1_y: ctrl1.y,
control2_x: ctrl2.x,
control2_y: ctrl2.y,
to_x: to.x,
to_y: to.y,
}),
Event::End { last, first, close } => PathEvent::End(PathEventEnd {
first_x: first.x,
first_y: first.y,
last_x: last.x,
last_y: last.y,
close: *close,
}),
}
}
}
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -518,7 +499,7 @@ pub enum PathElements {
/// SharedElements is used to make PathElements from shared arrays of elements. /// SharedElements is used to make PathElements from shared arrays of elements.
SharedElements(crate::SharedArray<PathElement>), SharedElements(crate::SharedArray<PathElement>),
/// PathEvents describe the elements of the path as a series of low-level events. /// PathEvents describe the elements of the path as a series of low-level events.
PathEvents(crate::SharedArray<PathEvent>), PathEvents(crate::SharedArray<PathEvent>, crate::SharedArray<Point>),
} }
impl Default for PathElements { impl Default for PathElements {
@ -540,9 +521,14 @@ impl PathElements {
} }
/// Returns an iterator over all events if the elements are represented as low-level events. /// Returns an iterator over all events if the elements are represented as low-level events.
pub fn events_iter(&self) -> Option<std::slice::Iter<PathEvent>> { fn events_iter(&self) -> Option<ToLyonPathEventIterator> {
match self { match &self {
PathElements::PathEvents(events) => Some(events.as_slice().iter()), PathElements::PathEvents(events, coordinates) => Some(ToLyonPathEventIterator {
events_it: events.iter(),
coordinates_it: coordinates.iter(),
first: coordinates.first(),
last: coordinates.last(),
}),
_ => None, _ => None,
} }
} }
@ -615,12 +601,18 @@ pub unsafe extern "C" fn sixtyfps_new_path_elements(
#[no_mangle] #[no_mangle]
/// This function is used for the low-level C++ interface to allocate the backing vector for a shared path event array. /// This function is used for the low-level C++ interface to allocate the backing vector for a shared path event array.
pub unsafe extern "C" fn sixtyfps_new_path_events( pub unsafe extern "C" fn sixtyfps_new_path_events(
out: *mut c_void, out_events: *mut c_void,
out_coordinates: *mut c_void,
first_event: *const PathEvent, first_event: *const PathEvent,
count: usize, event_count: usize,
first_coordinate: *const Point,
coordinate_count: usize,
) { ) {
let arr = crate::SharedArray::from(std::slice::from_raw_parts(first_event, count)); let events = crate::SharedArray::from(std::slice::from_raw_parts(first_event, event_count));
core::ptr::write(out as *mut crate::SharedArray<PathEvent>, arr.clone()); core::ptr::write(out_events as *mut crate::SharedArray<PathEvent>, events.clone());
let coordinates =
crate::SharedArray::from(std::slice::from_raw_parts(first_coordinate, coordinate_count));
core::ptr::write(out_coordinates as *mut crate::SharedArray<Point>, coordinates.clone());
} }
/// Each item return a RenderingPrimitive to the backend with information about what to draw. /// Each item return a RenderingPrimitive to the backend with information about what to draw.

View file

@ -11,4 +11,5 @@ path = "lib.rs"
sixtyfps_corelib = { path = "../corelib", features = ["rtti"] } sixtyfps_corelib = { path = "../corelib", features = ["rtti"] }
vtable = { path="../../helper_crates/vtable" } vtable = { path="../../helper_crates/vtable" }
sixtyfps_compilerlib = { path = "../../sixtyfps_compiler", features = ["display-diagnostics"] } sixtyfps_compilerlib = { path = "../../sixtyfps_compiler", features = ["display-diagnostics"] }
lyon = { version = "0.15.8" }

View file

@ -6,8 +6,9 @@ use sixtyfps_compilerlib::expression_tree::{
use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type}; use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type};
use sixtyfps_corelib as corelib; use sixtyfps_corelib as corelib;
use sixtyfps_corelib::{ use sixtyfps_corelib::{
abi::datastructures::ItemRef, abi::primitives::PropertyAnimation, Color, EvaluationContext, abi::datastructures::ItemRef, abi::datastructures::PathElement,
PathElements, Resource, SharedString, abi::primitives::PropertyAnimation, Color, EvaluationContext, PathElements, Resource,
SharedArray, SharedString,
}; };
use std::{collections::HashMap, rc::Rc}; use std::{collections::HashMap, rc::Rc};
@ -363,26 +364,71 @@ pub fn new_struct_with_bindings<
element element
} }
fn convert_from_lyon_path<'a>(
it: impl IntoIterator<Item = &'a lyon::path::Event<lyon::math::Point, lyon::math::Point>>,
) -> PathElements {
use lyon::path::Event;
use sixtyfps_corelib::abi::datastructures::PathEvent;
let mut coordinates = Vec::new();
let events = it
.into_iter()
.map(|event| match event {
Event::Begin { at } => {
coordinates.push(at);
PathEvent::Begin
}
Event::Line { from, to } => {
coordinates.push(from);
coordinates.push(to);
PathEvent::Line
}
Event::Quadratic { from, ctrl, to } => {
coordinates.push(from);
coordinates.push(ctrl);
coordinates.push(to);
PathEvent::Quadratic
}
Event::Cubic { from, ctrl1, ctrl2, to } => {
coordinates.push(from);
coordinates.push(ctrl1);
coordinates.push(ctrl2);
coordinates.push(to);
PathEvent::Cubic
}
Event::End { last, first, close } => {
debug_assert_eq!(coordinates.first(), Some(&first));
debug_assert_eq!(coordinates.last(), Some(&last));
if *close {
PathEvent::EndClosed
} else {
PathEvent::EndOpen
}
}
})
.collect::<Vec<_>>();
PathElements::PathEvents(
SharedArray::from(&events),
SharedArray::from_iter(coordinates.into_iter().cloned()),
)
}
pub fn convert_path( pub fn convert_path(
path: &ExprPath, path: &ExprPath,
component_type: &crate::ComponentDescription, component_type: &crate::ComponentDescription,
eval_context: &corelib::EvaluationContext, eval_context: &corelib::EvaluationContext,
) -> sixtyfps_corelib::abi::datastructures::PathElements { ) -> PathElements {
match path { match path {
ExprPath::Elements(elements) => { ExprPath::Elements(elements) => {
PathElements::SharedElements(sixtyfps_corelib::SharedArray::< PathElements::SharedElements(SharedArray::<PathElement>::from_iter(
sixtyfps_corelib::abi::datastructures::PathElement,
>::from_iter(
elements elements
.iter() .iter()
.map(|element| convert_path_element(element, component_type, eval_context)), .map(|element| convert_path_element(element, component_type, eval_context)),
)) ))
} }
ExprPath::Events(events) => PathElements::PathEvents(sixtyfps_corelib::SharedArray::< ExprPath::Events(events) => convert_from_lyon_path(events.iter()),
sixtyfps_corelib::abi::datastructures::PathEvent,
>::from_iter(
events.iter().map(|event| event.into()),
)),
} }
} }
@ -390,15 +436,19 @@ fn convert_path_element(
expr_element: &ExprPathElement, expr_element: &ExprPathElement,
component_type: &crate::ComponentDescription, component_type: &crate::ComponentDescription,
eval_context: &corelib::EvaluationContext, eval_context: &corelib::EvaluationContext,
) -> sixtyfps_corelib::abi::datastructures::PathElement { ) -> PathElement {
match expr_element.element_type.class_name.as_str() { match expr_element.element_type.class_name.as_str() {
"LineTo" => sixtyfps_corelib::abi::datastructures::PathElement::LineTo( "LineTo" => PathElement::LineTo(new_struct_with_bindings(
new_struct_with_bindings(&expr_element.bindings, component_type, eval_context), &expr_element.bindings,
), component_type,
"ArcTo" => sixtyfps_corelib::abi::datastructures::PathElement::ArcTo( eval_context,
new_struct_with_bindings(&expr_element.bindings, component_type, eval_context), )),
), "ArcTo" => PathElement::ArcTo(new_struct_with_bindings(
"Close" => sixtyfps_corelib::abi::datastructures::PathElement::Close, &expr_element.bindings,
component_type,
eval_context,
)),
"Close" => PathElement::Close,
_ => panic!( _ => panic!(
"Cannot create unsupported path element {}", "Cannot create unsupported path element {}",
expr_element.element_type.class_name expr_element.element_type.class_name