mirror of
https://github.com/penpot/penpot.git
synced 2025-05-14 06:06:40 +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
|
@ -194,10 +194,8 @@
|
||||||
ptr (h/call internal-module "_alloc_bytes" size)
|
ptr (h/call internal-module "_alloc_bytes" size)
|
||||||
heap (gobj/get ^js internal-module "HEAPU8")
|
heap (gobj/get ^js internal-module "HEAPU8")
|
||||||
mem (js/Uint8Array. (.-buffer heap) ptr size)]
|
mem (js/Uint8Array. (.-buffer heap) ptr size)]
|
||||||
(.set mem (js/Uint8Array. buffer)
|
(.set mem (js/Uint8Array. buffer))
|
||||||
(h/call internal-module "_set_shape_path_content" (count content))
|
(h/call internal-module "_set_shape_path_content")))
|
||||||
(js/console.log mem)
|
|
||||||
(js/console.log buffer))))
|
|
||||||
|
|
||||||
(defn- translate-blend-mode
|
(defn- translate-blend-mode
|
||||||
[blend-mode]
|
[blend-mode]
|
||||||
|
|
|
@ -7,6 +7,7 @@ mod state;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod view;
|
mod view;
|
||||||
|
|
||||||
|
use shapes::RawPathData;
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
@ -271,20 +272,18 @@ pub extern "C" fn set_shape_hidden(hidden: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[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");
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||||
|
|
||||||
if let Some(shape) = state.current_shape() {
|
if let Some(shape) = state.current_shape() {
|
||||||
let len = n_segments as usize;
|
let bytes = mem::bytes();
|
||||||
|
let raw_segments = bytes
|
||||||
unsafe {
|
.chunks(size_of::<shapes::RawPathData>())
|
||||||
let buffer = Vec::<shapes::RawPathData>::from_raw_parts(
|
.map(|data| shapes::RawPathData {
|
||||||
mem::buffer_ptr() as *mut shapes::RawPathData,
|
data: data.try_into().unwrap(),
|
||||||
len,
|
})
|
||||||
len,
|
.collect();
|
||||||
);
|
shape.set_path_segments(raw_segments).unwrap();
|
||||||
mem::free_bytes();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
|
|
||||||
pub type Rect = skia::Rect;
|
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");
|
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();
|
let ptr = buffer.as_mut_ptr();
|
||||||
|
|
||||||
unsafe { BUFFERU8 = Some(buffer) };
|
unsafe { BUFFERU8 = Some(buffer) };
|
||||||
|
@ -23,3 +23,8 @@ pub fn buffer_ptr() -> *mut u8 {
|
||||||
let buffer = unsafe { BUFFERU8.as_mut() }.expect("uninitializied buffer");
|
let buffer = unsafe { BUFFERU8.as_mut() }.expect("uninitializied buffer");
|
||||||
buffer.as_mut_ptr()
|
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 images::*;
|
||||||
pub use paths::*;
|
pub use paths::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Rect,
|
Rect,
|
||||||
|
Path(Path),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Color = skia::Color;
|
pub type Color = skia::Color;
|
||||||
|
@ -110,6 +111,12 @@ impl Shape {
|
||||||
Ok(())
|
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) {
|
pub fn set_blend_mode(&mut self, mode: BlendMode) {
|
||||||
self.blend_mode = mode;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct RawPathData {
|
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