mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 15:51:37 -05:00
Merge pull request #5403 from penpot/ladybenko-wasm-save-buffer-pointer
Wasm save buffer pointer
This commit is contained in:
commit
7c7ede9d0c
7 changed files with 118 additions and 89 deletions
|
@ -132,7 +132,6 @@
|
|||
(aget buffer 1)
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)
|
||||
image-ptr
|
||||
image-size)
|
||||
true))))))
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
mod debug;
|
||||
mod math;
|
||||
pub mod mem;
|
||||
mod mem;
|
||||
mod render;
|
||||
mod shapes;
|
||||
mod state;
|
||||
|
@ -9,7 +9,6 @@ mod view;
|
|||
|
||||
use skia_safe as skia;
|
||||
|
||||
use crate::shapes::Image;
|
||||
use crate::state::State;
|
||||
use crate::utils::uuid_from_u32_quartet;
|
||||
|
||||
|
@ -177,66 +176,46 @@ pub extern "C" fn add_shape_linear_fill(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawStopData {
|
||||
color: [u8; 4],
|
||||
offset: u8,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_fill_stops(ptr: *mut RawStopData, n_stops: i32) {
|
||||
pub extern "C" fn add_shape_fill_stops(ptr: *mut shapes::RawStopData, n_stops: u32) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
|
||||
if let Some(shape) = state.current_shape() {
|
||||
let len = n_stops as usize;
|
||||
|
||||
unsafe {
|
||||
let buf = Vec::<RawStopData>::from_raw_parts(ptr, n_stops as usize, n_stops as usize);
|
||||
for raw_stop in buf.iter() {
|
||||
let color = skia::Color::from_argb(
|
||||
raw_stop.color[3],
|
||||
raw_stop.color[0],
|
||||
raw_stop.color[1],
|
||||
raw_stop.color[2],
|
||||
);
|
||||
shape
|
||||
.add_gradient_stop(color, (raw_stop.offset as f32) / 100.)
|
||||
.expect("got no fill or an invalid one");
|
||||
}
|
||||
mem::free(
|
||||
ptr as *mut u8,
|
||||
n_stops as usize * std::mem::size_of::<RawStopData>(),
|
||||
);
|
||||
let buffer = Vec::<shapes::RawStopData>::from_raw_parts(ptr, len, len);
|
||||
shape
|
||||
.add_gradient_stops(buffer)
|
||||
.expect("could not add gradient stops");
|
||||
mem::free_bytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn store_image(a: u32, b: u32, c: u32, d: u32, ptr: *mut u8, size: u32) {
|
||||
if ptr.is_null() || size == 0 {
|
||||
panic!("Invalid data, null pointer or zero size");
|
||||
}
|
||||
pub extern "C" fn store_image(a: u32, b: u32, c: u32, d: u32, size: u32) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
let render_state = state.render_state();
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
|
||||
unsafe {
|
||||
let image_bytes = Vec::<u8>::from_raw_parts(ptr, size as usize, size as usize);
|
||||
let image_data = skia::Data::new_copy(&*image_bytes);
|
||||
match Image::from_encoded(image_data) {
|
||||
Some(image) => {
|
||||
render_state.images.insert(id.to_string(), image);
|
||||
}
|
||||
None => {
|
||||
eprintln!("Error on image decoding");
|
||||
let image_bytes =
|
||||
Vec::<u8>::from_raw_parts(mem::buffer_ptr(), size as usize, size as usize);
|
||||
match state.render_state().add_image(id, &image_bytes) {
|
||||
Err(msg) => {
|
||||
eprintln!("{}", msg);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
mem::free(ptr as *mut u8, size as usize * std::mem::size_of::<u8>());
|
||||
mem::free_bytes();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn is_image_cached(a: u32, b: u32, c: u32, d: u32) -> bool {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
let render_state = state.render_state();
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
render_state.images.contains_key(&id.to_string())
|
||||
state.render_state().has_image(&id)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -246,8 +225,8 @@ pub extern "C" fn add_shape_image_fill(
|
|||
c: u32,
|
||||
d: u32,
|
||||
alpha: f32,
|
||||
width: f32,
|
||||
height: f32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
|
@ -255,8 +234,7 @@ pub extern "C" fn add_shape_image_fill(
|
|||
shape.add_fill(shapes::Fill::new_image_fill(
|
||||
id,
|
||||
(alpha * 0xff as f32).floor() as u8,
|
||||
height,
|
||||
width,
|
||||
(width, height),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
static mut BUFFERU8: Option<Box<Vec<u8>>> = None;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn alloc_bytes(len: usize) -> *mut u8 {
|
||||
// create a new mutable buffer with capacity `len`
|
||||
let mut buf: Vec<u8> = Vec::with_capacity(len);
|
||||
let ptr = buf.as_mut_ptr();
|
||||
// take ownership of the memory block and ensure the its destructor is not
|
||||
// called when the object goes out of scope at the end of the function
|
||||
std::mem::forget(buf);
|
||||
// TODO: Figure out how to deal with Result<T> from Emscripten
|
||||
if unsafe { BUFFERU8.is_some() } {
|
||||
panic!("Bytes already allocated");
|
||||
}
|
||||
|
||||
let mut buffer = Box::new(Vec::<u8>::with_capacity(len));
|
||||
let ptr = buffer.as_mut_ptr();
|
||||
|
||||
unsafe { BUFFERU8 = Some(buffer) };
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub fn free(ptr: *mut u8, len: usize) {
|
||||
unsafe {
|
||||
let buf = Vec::<u8>::from_raw_parts(ptr, len, len);
|
||||
std::mem::forget(buf);
|
||||
}
|
||||
pub fn free_bytes() {
|
||||
let buffer = unsafe { BUFFERU8.take() }.expect("uninitialized buffer");
|
||||
std::mem::drop(buffer);
|
||||
}
|
||||
|
||||
pub fn buffer_ptr() -> *mut u8 {
|
||||
let buffer = unsafe { BUFFERU8.as_mut() }.expect("uninitializied buffer");
|
||||
buffer.as_mut_ptr()
|
||||
}
|
||||
|
|
|
@ -5,9 +5,8 @@ use std::collections::HashMap;
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::debug;
|
||||
use crate::shapes::Fill;
|
||||
use crate::shapes::Shape;
|
||||
use crate::shapes::{draw_image_in_container, Image};
|
||||
use crate::math::Rect;
|
||||
use crate::shapes::{draw_image_in_container, Fill, Image, Shape};
|
||||
use crate::view::Viewbox;
|
||||
|
||||
struct GpuState {
|
||||
|
@ -98,7 +97,7 @@ pub(crate) struct RenderState {
|
|||
pub cached_surface_image: Option<CachedSurfaceImage>,
|
||||
options: RenderOptions,
|
||||
pub viewbox: Viewbox,
|
||||
pub images: HashMap<String, Image>,
|
||||
images: HashMap<Uuid, Image>,
|
||||
}
|
||||
|
||||
impl RenderState {
|
||||
|
@ -125,6 +124,18 @@ impl RenderState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_image(&mut self, id: Uuid, image_data: &[u8]) -> Result<(), String> {
|
||||
let image_data = skia::Data::new_copy(image_data);
|
||||
let image = Image::from_encoded(image_data).ok_or("Error decoding image data")?;
|
||||
|
||||
self.images.insert(id, image);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn has_image(&mut self, id: &Uuid) -> bool {
|
||||
self.images.contains_key(id)
|
||||
}
|
||||
|
||||
pub fn set_debug_flags(&mut self, debug: u32) {
|
||||
self.options.debug_flags = debug;
|
||||
}
|
||||
|
@ -213,22 +224,7 @@ impl RenderState {
|
|||
self.drawing_surface.canvas().concat(&matrix);
|
||||
|
||||
for fill in shape.fills().rev() {
|
||||
if let Fill::Image(image_fill) = fill {
|
||||
let image = self.images.get(&image_fill.id.to_string());
|
||||
if let Some(image) = image {
|
||||
draw_image_in_container(
|
||||
&self.drawing_surface.canvas(),
|
||||
&image,
|
||||
(image_fill.width, image_fill.height),
|
||||
shape.selrect,
|
||||
&fill.to_paint(&shape.selrect),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.drawing_surface
|
||||
.canvas()
|
||||
.draw_rect(shape.selrect, &fill.to_paint(&shape.selrect));
|
||||
}
|
||||
self.render_fill(fill, shape.selrect);
|
||||
}
|
||||
|
||||
let mut paint = skia::Paint::default();
|
||||
|
@ -285,6 +281,25 @@ impl RenderState {
|
|||
self.flush();
|
||||
}
|
||||
|
||||
fn render_fill(&mut self, fill: &Fill, selrect: Rect) {
|
||||
if let Fill::Image(image_fill) = fill {
|
||||
let image = self.images.get(&image_fill.id());
|
||||
if let Some(image) = image {
|
||||
draw_image_in_container(
|
||||
&self.drawing_surface.canvas(),
|
||||
&image,
|
||||
image_fill.size(),
|
||||
selrect,
|
||||
&fill.to_paint(&selrect),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.drawing_surface
|
||||
.canvas()
|
||||
.draw_rect(selrect, &fill.to_paint(&selrect));
|
||||
}
|
||||
}
|
||||
|
||||
fn render_all_from_cache(&mut self) -> Result<(), String> {
|
||||
self.reset_canvas();
|
||||
|
||||
|
|
|
@ -92,14 +92,16 @@ impl Shape {
|
|||
self.fills.clear();
|
||||
}
|
||||
|
||||
pub fn add_gradient_stop(&mut self, color: skia::Color, offset: f32) -> Result<(), String> {
|
||||
pub fn add_gradient_stops(&mut self, buffer: Vec<RawStopData>) -> Result<(), String> {
|
||||
let fill = self.fills.last_mut().ok_or("Shape has no fills")?;
|
||||
let gradient = match fill {
|
||||
Fill::LinearGradient(g) => Ok(g),
|
||||
_ => Err("Active fill is not a gradient"),
|
||||
}?;
|
||||
|
||||
gradient.add_stop(color, offset);
|
||||
for stop in buffer.into_iter() {
|
||||
gradient.add_stop(stop.color(), stop.offset());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -4,6 +4,23 @@ use super::Color;
|
|||
use crate::math;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct RawStopData {
|
||||
color: [u8; 4],
|
||||
offset: u8,
|
||||
}
|
||||
|
||||
impl RawStopData {
|
||||
pub fn color(&self) -> skia::Color {
|
||||
skia::Color::from_argb(self.color[3], self.color[0], self.color[1], self.color[2])
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> f32 {
|
||||
self.offset as f32 / 100.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Gradient {
|
||||
colors: Vec<Color>,
|
||||
|
@ -43,10 +60,20 @@ impl Gradient {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ImageFill {
|
||||
pub id: Uuid,
|
||||
pub alpha: u8,
|
||||
pub height: f32,
|
||||
pub width: f32,
|
||||
id: Uuid,
|
||||
opacity: u8,
|
||||
height: i32,
|
||||
width: i32,
|
||||
}
|
||||
|
||||
impl ImageFill {
|
||||
pub fn size(&self) -> (i32, i32) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> Uuid {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -67,10 +94,10 @@ impl Fill {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn new_image_fill(id: Uuid, alpha: u8, height: f32, width: f32) -> Self {
|
||||
pub fn new_image_fill(id: Uuid, opacity: u8, (width, height): (i32, i32)) -> Self {
|
||||
Self::Image(ImageFill {
|
||||
id,
|
||||
alpha,
|
||||
opacity,
|
||||
height,
|
||||
width,
|
||||
})
|
||||
|
@ -99,7 +126,7 @@ impl Fill {
|
|||
p.set_style(skia::PaintStyle::Fill);
|
||||
p.set_anti_alias(true);
|
||||
p.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
p.set_alpha(image_fill.alpha);
|
||||
p.set_alpha(image_fill.opacity);
|
||||
p
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ pub type Image = skia::Image;
|
|||
pub fn draw_image_in_container(
|
||||
canvas: &skia::Canvas,
|
||||
image: &Image,
|
||||
size: (f32, f32),
|
||||
size: (i32, i32),
|
||||
container: skia::Rect,
|
||||
paint: &skia::Paint,
|
||||
) {
|
||||
let width = size.0;
|
||||
let height = size.1;
|
||||
let width = size.0 as f32;
|
||||
let height = size.1 as f32;
|
||||
let image_aspect_ratio = width / height;
|
||||
|
||||
// Container size
|
||||
|
|
Loading…
Add table
Reference in a new issue