mirror of
https://github.com/penpot/penpot.git
synced 2025-05-23 13:06:14 +02:00
🎉 Deserialize shape data in wasm
This commit is contained in:
parent
22b01c63b5
commit
0bfcc1f854
6 changed files with 140 additions and 18 deletions
|
@ -7,6 +7,7 @@ mod state;
|
|||
mod utils;
|
||||
mod view;
|
||||
|
||||
use shapes::RawPathData;
|
||||
use skia_safe as skia;
|
||||
|
||||
use crate::state::State;
|
||||
|
@ -271,20 +272,18 @@ pub extern "C" fn set_shape_hidden(hidden: bool) {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_path_content(n_segments: u32) {
|
||||
pub extern "C" fn set_shape_path_content() {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
|
||||
if let Some(shape) = state.current_shape() {
|
||||
let len = n_segments as usize;
|
||||
|
||||
unsafe {
|
||||
let buffer = Vec::<shapes::RawPathData>::from_raw_parts(
|
||||
mem::buffer_ptr() as *mut shapes::RawPathData,
|
||||
len,
|
||||
len,
|
||||
);
|
||||
mem::free_bytes();
|
||||
}
|
||||
let bytes = mem::bytes();
|
||||
let raw_segments = bytes
|
||||
.chunks(size_of::<shapes::RawPathData>())
|
||||
.map(|data| shapes::RawPathData {
|
||||
data: data.try_into().unwrap(),
|
||||
})
|
||||
.collect();
|
||||
shape.set_path_segments(raw_segments).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use skia_safe as skia;
|
||||
|
||||
pub type Rect = skia::Rect;
|
||||
pub type Point = (f32, f32);
|
||||
|
|
|
@ -7,7 +7,7 @@ pub extern "C" fn alloc_bytes(len: usize) -> *mut u8 {
|
|||
panic!("Bytes already allocated");
|
||||
}
|
||||
|
||||
let mut buffer = Box::new(Vec::<u8>::with_capacity(len));
|
||||
let mut buffer = Box::new(vec![0u8; len]);
|
||||
let ptr = buffer.as_mut_ptr();
|
||||
|
||||
unsafe { BUFFERU8 = Some(buffer) };
|
||||
|
@ -23,3 +23,8 @@ pub fn buffer_ptr() -> *mut u8 {
|
|||
let buffer = unsafe { BUFFERU8.as_mut() }.expect("uninitializied buffer");
|
||||
buffer.as_mut_ptr()
|
||||
}
|
||||
|
||||
pub fn bytes() -> Vec<u8> {
|
||||
let buffer = unsafe { BUFFERU8.take() }.expect("uninitialized buffer");
|
||||
*buffer
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ pub use fills::*;
|
|||
pub use images::*;
|
||||
pub use paths::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Kind {
|
||||
Rect,
|
||||
Path(Path),
|
||||
}
|
||||
|
||||
pub type Color = skia::Color;
|
||||
|
@ -110,6 +111,12 @@ impl Shape {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_path_segments(&mut self, buffer: Vec<RawPathData>) -> Result<(), String> {
|
||||
let p = Path::try_from(buffer)?;
|
||||
self.kind = Kind::Path(p);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_blend_mode(&mut self, mode: BlendMode) {
|
||||
self.blend_mode = mode;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,116 @@
|
|||
use skia_safe as skia;
|
||||
use std::array::TryFromSliceError;
|
||||
|
||||
use crate::math::Point;
|
||||
|
||||
fn stringify_slice_err(_: TryFromSliceError) -> String {
|
||||
format!("Error deserializing path")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawPathData {
|
||||
data: [u8; 28],
|
||||
pub data: [u8; 28],
|
||||
}
|
||||
|
||||
impl RawPathData {
|
||||
fn command(&self) -> Result<u16, String> {
|
||||
let cmd = u16::from_be_bytes(self.data[0..2].try_into().map_err(stringify_slice_err)?);
|
||||
Ok(cmd)
|
||||
}
|
||||
|
||||
fn xy(&self) -> Result<Point, String> {
|
||||
let x = f32::from_be_bytes(self.data[20..24].try_into().map_err(stringify_slice_err)?);
|
||||
let y = f32::from_be_bytes(self.data[24..].try_into().map_err(stringify_slice_err)?);
|
||||
Ok((x, y))
|
||||
}
|
||||
|
||||
fn c1(&self) -> Result<Point, String> {
|
||||
let c1_x = f32::from_be_bytes(self.data[4..8].try_into().map_err(stringify_slice_err)?);
|
||||
let c1_y = f32::from_be_bytes(self.data[8..12].try_into().map_err(stringify_slice_err)?);
|
||||
|
||||
Ok((c1_x, c1_y))
|
||||
}
|
||||
|
||||
fn c2(&self) -> Result<Point, String> {
|
||||
let c2_x = f32::from_be_bytes(self.data[12..16].try_into().map_err(stringify_slice_err)?);
|
||||
let c2_y = f32::from_be_bytes(self.data[16..20].try_into().map_err(stringify_slice_err)?);
|
||||
|
||||
Ok((c2_x, c2_y))
|
||||
}
|
||||
}
|
||||
|
||||
const MOVE_TO: u16 = 1;
|
||||
const LINE_TO: u16 = 2;
|
||||
const CURVE_TO: u16 = 3;
|
||||
const CLOSE: u16 = 4;
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
enum Segment {
|
||||
MoveTo(Point),
|
||||
LineTo(Point),
|
||||
CurveTo((Point, Point, Point)),
|
||||
Close,
|
||||
}
|
||||
|
||||
impl TryFrom<RawPathData> for Segment {
|
||||
type Error = String;
|
||||
fn try_from(value: RawPathData) -> Result<Self, Self::Error> {
|
||||
let cmd = value.command()?;
|
||||
match cmd {
|
||||
MOVE_TO => Ok(Segment::MoveTo(value.xy()?)),
|
||||
LINE_TO => Ok(Segment::LineTo(value.xy()?)),
|
||||
CURVE_TO => Ok(Segment::CurveTo((value.c1()?, value.c2()?, value.xy()?))),
|
||||
CLOSE => Ok(Segment::Close),
|
||||
_ => Err(format!(
|
||||
"Error deserializing path. Unknown command/flags: {:#010x}",
|
||||
cmd
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Path {
|
||||
segments: Vec<Segment>,
|
||||
skia_path: skia::Path,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<RawPathData>> for Path {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: Vec<RawPathData>) -> Result<Self, Self::Error> {
|
||||
let segments = value
|
||||
.into_iter()
|
||||
.map(|raw| Segment::try_from(raw))
|
||||
.collect::<Result<Vec<Segment>, String>>()?;
|
||||
|
||||
let mut skia_path = skia::Path::new();
|
||||
for segment in segments.iter() {
|
||||
match *segment {
|
||||
Segment::MoveTo(xy) => {
|
||||
skia_path.move_to(xy);
|
||||
}
|
||||
Segment::LineTo(xy) => {
|
||||
skia_path.line_to(xy);
|
||||
}
|
||||
Segment::CurveTo((c1, c2, xy)) => {
|
||||
skia_path.cubic_to(c1, c2, xy);
|
||||
}
|
||||
Segment::Close => {
|
||||
skia_path.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Path {
|
||||
segments,
|
||||
skia_path,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn to_skia_path(&self) -> skia::Path {
|
||||
self.skia_path.snapshot()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue