♻️ Refactor mutability modifiers in wasm

This commit is contained in:
alonso.torres 2025-07-01 12:46:50 +02:00
parent f0f01af55c
commit 3d374e8e97
12 changed files with 155 additions and 131 deletions

View file

@ -29,7 +29,7 @@ use uuid::Uuid;
pub(crate) static mut STATE: Option<Box<State>> = None; pub(crate) static mut STATE: Option<Box<State>> = None;
#[macro_export] #[macro_export]
macro_rules! with_state { macro_rules! with_state_mut {
($state:ident, $block:block) => {{ ($state:ident, $block:block) => {{
let $state = unsafe { let $state = unsafe {
#[allow(static_mut_refs)] #[allow(static_mut_refs)]
@ -40,14 +40,39 @@ macro_rules! with_state {
}}; }};
} }
macro_rules! with_state {
($state:ident, $block:block) => {{
let $state = unsafe {
#[allow(static_mut_refs)]
STATE.as_ref()
}
.expect("Got an invalid state pointer");
$block
}};
}
#[macro_export] #[macro_export]
macro_rules! with_current_shape { macro_rules! with_current_shape_mut {
($state:ident, |$shape:ident: &mut Shape| $block:block) => { ($state:ident, |$shape:ident: &mut Shape| $block:block) => {
let $state = unsafe { let $state = unsafe {
#[allow(static_mut_refs)] #[allow(static_mut_refs)]
STATE.as_mut() STATE.as_mut()
} }
.expect("Got an invalid state pointer"); .expect("Got an invalid state pointer");
if let Some($shape) = $state.current_shape_mut() {
$block
}
};
}
#[macro_export]
macro_rules! with_current_shape {
($state:ident, |$shape:ident: &Shape| $block:block) => {
let $state = unsafe {
#[allow(static_mut_refs)]
STATE.as_ref()
}
.expect("Got an invalid state pointer");
if let Some($shape) = $state.current_shape() { if let Some($shape) = $state.current_shape() {
$block $block
} }
@ -71,15 +96,15 @@ pub extern "C" fn clean_up() {
#[no_mangle] #[no_mangle]
pub extern "C" fn clear_drawing_cache() { pub extern "C" fn clear_drawing_cache() {
with_state!(state, { with_state_mut!(state, {
state.rebuild_tiles(); state.rebuild_tiles();
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_render_options(debug: u32, dpr: f32) { pub extern "C" fn set_render_options(debug: u32, dpr: f32) {
with_state!(state, { with_state_mut!(state, {
let render_state = state.render_state(); let render_state = state.render_state_mut();
render_state.set_debug_flags(debug); render_state.set_debug_flags(debug);
render_state.set_dpr(dpr); render_state.set_dpr(dpr);
}); });
@ -87,7 +112,7 @@ pub extern "C" fn set_render_options(debug: u32, dpr: f32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_canvas_background(raw_color: u32) { pub extern "C" fn set_canvas_background(raw_color: u32) {
with_state!(state, { with_state_mut!(state, {
let color = skia::Color::new(raw_color); let color = skia::Color::new(raw_color);
state.set_background_color(color); state.set_background_color(color);
}); });
@ -95,7 +120,7 @@ pub extern "C" fn set_canvas_background(raw_color: u32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn render(_: i32) { pub extern "C" fn render(_: i32) {
with_state!(state, { with_state_mut!(state, {
state state
.start_render_loop(performance::get_time()) .start_render_loop(performance::get_time())
.expect("Error rendering"); .expect("Error rendering");
@ -104,7 +129,7 @@ pub extern "C" fn render(_: i32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn render_from_cache(_: i32) { pub extern "C" fn render_from_cache(_: i32) {
with_state!(state, { with_state_mut!(state, {
state.render_from_cache(); state.render_from_cache();
}); });
} }
@ -112,7 +137,7 @@ pub extern "C" fn render_from_cache(_: i32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn process_animation_frame(timestamp: i32) { pub extern "C" fn process_animation_frame(timestamp: i32) {
let result = std::panic::catch_unwind(|| { let result = std::panic::catch_unwind(|| {
with_state!(state, { with_state_mut!(state, {
state state
.process_animation_frame(timestamp) .process_animation_frame(timestamp)
.expect("Error processing animation frame"); .expect("Error processing animation frame");
@ -133,24 +158,24 @@ pub extern "C" fn process_animation_frame(timestamp: i32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn reset_canvas() { pub extern "C" fn reset_canvas() {
with_state!(state, { with_state_mut!(state, {
state.render_state().reset_canvas(); state.render_state_mut().reset_canvas();
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn resize_viewbox(width: i32, height: i32) { pub extern "C" fn resize_viewbox(width: i32, height: i32) {
with_state!(state, { with_state_mut!(state, {
state.resize(width, height); state.resize(width, height);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) { pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) {
with_state!(state, { with_state_mut!(state, {
let render_state = state.render_state(); let render_state = state.render_state_mut();
render_state.viewbox.set_all(zoom, x, y); render_state.viewbox.set_all(zoom, x, y);
with_state!(state, { with_state_mut!(state, {
// We can have renders in progress // We can have renders in progress
state.render_state.cancel_animation_frame(); state.render_state.cancel_animation_frame();
if state.render_state.options.is_profile_rebuild_tiles() { if state.render_state.options.is_profile_rebuild_tiles() {
@ -164,7 +189,7 @@ pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn clear_focus_mode() { pub extern "C" fn clear_focus_mode() {
with_state!(state, { with_state_mut!(state, {
state.clear_focus_mode(); state.clear_focus_mode();
}); });
} }
@ -178,21 +203,21 @@ pub extern "C" fn set_focus_mode() {
.map(|data| Uuid::from_bytes(data.try_into().unwrap())) .map(|data| Uuid::from_bytes(data.try_into().unwrap()))
.collect(); .collect();
with_state!(state, { with_state_mut!(state, {
state.set_focus_mode(entries); state.set_focus_mode(entries);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn init_shapes_pool(capacity: usize) { pub extern "C" fn init_shapes_pool(capacity: usize) {
with_state!(state, { with_state_mut!(state, {
state.init_shapes_pool(capacity); state.init_shapes_pool(capacity);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) { pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) {
with_state!(state, { with_state_mut!(state, {
let id = uuid_from_u32_quartet(a, b, c, d); let id = uuid_from_u32_quartet(a, b, c, d);
state.use_shape(id); state.use_shape(id);
}); });
@ -200,7 +225,7 @@ pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_parent(a: u32, b: u32, c: u32, d: u32) { pub extern "C" fn set_parent(a: u32, b: u32, c: u32, d: u32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let id = uuid_from_u32_quartet(a, b, c, d); let id = uuid_from_u32_quartet(a, b, c, d);
shape.set_parent(id); shape.set_parent(id);
}); });
@ -208,56 +233,56 @@ pub extern "C" fn set_parent(a: u32, b: u32, c: u32, d: u32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_masked_group(masked: bool) { pub extern "C" fn set_shape_masked_group(masked: bool) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_masked(masked); shape.set_masked(masked);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_bool_type(raw_bool_type: u8) { pub extern "C" fn set_shape_bool_type(raw_bool_type: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_bool_type(BoolType::from(raw_bool_type)); shape.set_bool_type(BoolType::from(raw_bool_type));
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_type(shape_type: u8) { pub extern "C" fn set_shape_type(shape_type: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_shape_type(Type::from(shape_type)); shape.set_shape_type(Type::from(shape_type));
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_selrect(left: f32, top: f32, right: f32, bottom: f32) { pub extern "C" fn set_shape_selrect(left: f32, top: f32, right: f32, bottom: f32) {
with_state!(state, { with_state_mut!(state, {
state.set_selrect_for_current_shape(left, top, right, bottom); state.set_selrect_for_current_shape(left, top, right, bottom);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_clip_content(clip_content: bool) { pub extern "C" fn set_shape_clip_content(clip_content: bool) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_clip(clip_content); shape.set_clip(clip_content);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_rotation(rotation: f32) { pub extern "C" fn set_shape_rotation(rotation: f32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_rotation(rotation); shape.set_rotation(rotation);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_transform(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) { pub extern "C" fn set_shape_transform(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_transform(a, b, c, d, e, f); shape.set_transform(a, b, c, d, e, f);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn add_shape_child(a: u32, b: u32, c: u32, d: u32) { pub extern "C" fn add_shape_child(a: u32, b: u32, c: u32, d: u32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let id = uuid_from_u32_quartet(a, b, c, d); let id = uuid_from_u32_quartet(a, b, c, d);
shape.add_child(id); shape.add_child(id);
}); });
@ -274,12 +299,12 @@ pub extern "C" fn set_children() {
let mut deleted = IndexSet::new(); let mut deleted = IndexSet::new();
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
(_, deleted) = shape.compute_children_differences(&entries); (_, deleted) = shape.compute_children_differences(&entries);
shape.children = entries.clone(); shape.children = entries.clone();
}); });
with_state!(state, { with_state_mut!(state, {
for id in deleted { for id in deleted {
state.delete_shape(id); state.delete_shape(id);
} }
@ -301,18 +326,18 @@ pub extern "C" fn store_image(
c2: u32, c2: u32,
d2: u32, d2: u32,
) { ) {
with_state!(state, { with_state_mut!(state, {
let image_id = uuid_from_u32_quartet(a2, b2, c2, d2); let image_id = uuid_from_u32_quartet(a2, b2, c2, d2);
let image_bytes = mem::bytes(); let image_bytes = mem::bytes();
if let Err(msg) = state.render_state().add_image(image_id, &image_bytes) { if let Err(msg) = state.render_state_mut().add_image(image_id, &image_bytes) {
eprintln!("{}", msg); eprintln!("{}", msg);
} }
mem::free_bytes(); mem::free_bytes();
}); });
with_state!(state, { with_state_mut!(state, {
let shape_id = uuid_from_u32_quartet(a1, b1, c1, d1); let shape_id = uuid_from_u32_quartet(a1, b1, c1, d1);
state.update_tile_for_shape(shape_id); state.update_tile_for_shape(shape_id);
}); });
@ -320,7 +345,7 @@ pub extern "C" fn store_image(
#[no_mangle] #[no_mangle]
pub extern "C" fn is_image_cached(a: u32, b: u32, c: u32, d: u32) -> bool { pub extern "C" fn is_image_cached(a: u32, b: u32, c: u32, d: u32) -> bool {
with_state!(state, { with_state_mut!(state, {
let id = uuid_from_u32_quartet(a, b, c, d); let id = uuid_from_u32_quartet(a, b, c, d);
state.render_state().has_image(&id) state.render_state().has_image(&id)
}) })
@ -328,7 +353,7 @@ pub extern "C" fn is_image_cached(a: u32, b: u32, c: u32, d: u32) -> bool {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_svg_raw_content() { pub extern "C" fn set_shape_svg_raw_content() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let bytes = mem::bytes(); let bytes = mem::bytes();
let svg_raw_content = String::from_utf8(bytes) let svg_raw_content = String::from_utf8(bytes)
.unwrap() .unwrap()
@ -342,56 +367,56 @@ pub extern "C" fn set_shape_svg_raw_content() {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_blend_mode(mode: i32) { pub extern "C" fn set_shape_blend_mode(mode: i32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_blend_mode(render::BlendMode::from(mode)); shape.set_blend_mode(render::BlendMode::from(mode));
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_vertical_align(align: u8) { pub extern "C" fn set_shape_vertical_align(align: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_vertical_align(VerticalAlign::from(align)); shape.set_vertical_align(VerticalAlign::from(align));
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_opacity(opacity: f32) { pub extern "C" fn set_shape_opacity(opacity: f32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_opacity(opacity); shape.set_opacity(opacity);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_constraint_h(constraint: u8) { pub extern "C" fn set_shape_constraint_h(constraint: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_constraint_h(ConstraintH::from(constraint)); shape.set_constraint_h(ConstraintH::from(constraint));
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_constraint_v(constraint: u8) { pub extern "C" fn set_shape_constraint_v(constraint: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_constraint_v(ConstraintV::from(constraint)); shape.set_constraint_v(ConstraintV::from(constraint));
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_hidden(hidden: bool) { pub extern "C" fn set_shape_hidden(hidden: bool) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_hidden(hidden); shape.set_hidden(hidden);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) { pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_blur(blur_type, hidden, value); shape.set_blur(blur_type, hidden, value);
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_corners(r1: f32, r2: f32, r3: f32, r4: f32) { pub extern "C" fn set_shape_corners(r1: f32, r2: f32, r3: f32, r4: f32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_corners((r1, r2, r3, r4)); shape.set_corners((r1, r2, r3, r4));
}); });
} }
@ -427,7 +452,7 @@ pub extern "C" fn get_selection_rect() -> *mut u8 {
}) })
.collect(); .collect();
with_state!(state, { with_state_mut!(state, {
let bbs: Vec<_> = entries let bbs: Vec<_> = entries
.iter() .iter()
.flat_map(|id| { .flat_map(|id| {
@ -472,7 +497,7 @@ pub extern "C" fn set_structure_modifiers() {
.map(|data| StructureEntry::from_bytes(data.try_into().unwrap())) .map(|data| StructureEntry::from_bytes(data.try_into().unwrap()))
.collect(); .collect();
with_state!(state, { with_state_mut!(state, {
for entry in entries { for entry in entries {
match entry.entry_type { match entry.entry_type {
StructureEntryType::ScaleContent => { StructureEntryType::ScaleContent => {
@ -500,7 +525,7 @@ pub extern "C" fn set_structure_modifiers() {
#[no_mangle] #[no_mangle]
pub extern "C" fn clean_modifiers() { pub extern "C" fn clean_modifiers() {
with_state!(state, { with_state_mut!(state, {
state.structure.clear(); state.structure.clear();
state.scale_content.clear(); state.scale_content.clear();
state.modifiers.clear(); state.modifiers.clear();
@ -516,7 +541,7 @@ pub extern "C" fn set_modifiers() {
.map(|data| TransformEntry::from_bytes(data.try_into().unwrap())) .map(|data| TransformEntry::from_bytes(data.try_into().unwrap()))
.collect(); .collect();
with_state!(state, { with_state_mut!(state, {
for entry in entries { for entry in entries {
state.modifiers.insert(entry.id, entry.transform); state.modifiers.insert(entry.id, entry.transform);
} }
@ -534,7 +559,7 @@ pub extern "C" fn add_shape_shadow(
raw_style: u8, raw_style: u8,
hidden: bool, hidden: bool,
) { ) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let color = skia::Color::new(raw_color); let color = skia::Color::new(raw_color);
let style = shapes::ShadowStyle::from(raw_style); let style = shapes::ShadowStyle::from(raw_style);
let shadow = shapes::Shadow::new(color, blur, spread, (x, y), style, hidden); let shadow = shapes::Shadow::new(color, blur, spread, (x, y), style, hidden);
@ -544,14 +569,14 @@ pub extern "C" fn add_shape_shadow(
#[no_mangle] #[no_mangle]
pub extern "C" fn clear_shape_shadows() { pub extern "C" fn clear_shape_shadows() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.clear_shadows(); shape.clear_shadows();
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn update_shape_tiles() { pub extern "C" fn update_shape_tiles() {
with_state!(state, { with_state_mut!(state, {
state.update_tile_for_current_shape(); state.update_tile_for_current_shape();
}); });
} }
@ -578,7 +603,7 @@ pub extern "C" fn set_flex_layout_data(
let justify_content = shapes::JustifyContent::from_u8(justify_content); let justify_content = shapes::JustifyContent::from_u8(justify_content);
let wrap_type = shapes::WrapType::from_u8(wrap_type); let wrap_type = shapes::WrapType::from_u8(wrap_type);
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_flex_layout_data( shape.set_flex_layout_data(
dir, dir,
row_gap, row_gap,
@ -629,7 +654,7 @@ pub extern "C" fn set_layout_child_data(
None None
}; };
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_flex_layout_child_data( shape.set_flex_layout_child_data(
margin_top, margin_top,
margin_right, margin_right,
@ -668,7 +693,7 @@ pub extern "C" fn set_grid_layout_data(
let justify_items = shapes::JustifyItems::from_u8(justify_items); let justify_items = shapes::JustifyItems::from_u8(justify_items);
let justify_content = shapes::JustifyContent::from_u8(justify_content); let justify_content = shapes::JustifyContent::from_u8(justify_content);
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_grid_layout_data( shape.set_grid_layout_data(
dir, dir,
row_gap, row_gap,
@ -694,7 +719,7 @@ pub extern "C" fn set_grid_columns() {
.map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap())) .map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap()))
.collect(); .collect();
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_grid_columns(entries); shape.set_grid_columns(entries);
}); });
@ -710,7 +735,7 @@ pub extern "C" fn set_grid_rows() {
.map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap())) .map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap()))
.collect(); .collect();
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_grid_rows(entries); shape.set_grid_rows(entries);
}); });
@ -726,7 +751,7 @@ pub extern "C" fn set_grid_cells() {
.map(|data| shapes::RawGridCell::from_bytes(data.try_into().unwrap())) .map(|data| shapes::RawGridCell::from_bytes(data.try_into().unwrap()))
.collect(); .collect();
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.set_grid_cells(entries); shape.set_grid_cells(entries);
}); });
@ -735,7 +760,7 @@ pub extern "C" fn set_grid_cells() {
#[no_mangle] #[no_mangle]
pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) { pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) {
with_state!(state, { with_state_mut!(state, {
let id = uuid_from_u32_quartet(a, b, c, d); let id = uuid_from_u32_quartet(a, b, c, d);
state.render_state.show_grid = Some(id); state.render_state.show_grid = Some(id);
}); });
@ -743,7 +768,7 @@ pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn hide_grid() { pub extern "C" fn hide_grid() {
with_state!(state, { with_state_mut!(state, {
state.render_state.show_grid = None; state.render_state.show_grid = None;
}); });
} }

View file

@ -260,7 +260,7 @@ impl RenderState {
self.images.add(id, image_data) self.images.add(id, image_data)
} }
pub fn has_image(&mut self, id: &Uuid) -> bool { pub fn has_image(&self, id: &Uuid) -> bool {
self.images.contains(id) self.images.contains(id)
} }
@ -635,7 +635,7 @@ impl RenderState {
pub fn start_render_loop( pub fn start_render_loop(
&mut self, &mut self,
tree: &mut HashMap<Uuid, &mut Shape>, tree: &HashMap<Uuid, &mut Shape>,
modifiers: &HashMap<Uuid, Matrix>, modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>, scale_content: &HashMap<Uuid, f32>,
@ -690,7 +690,7 @@ impl RenderState {
pub fn process_animation_frame( pub fn process_animation_frame(
&mut self, &mut self,
tree: &mut HashMap<Uuid, &mut Shape>, tree: &HashMap<Uuid, &mut Shape>,
modifiers: &HashMap<Uuid, Matrix>, modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>, scale_content: &HashMap<Uuid, f32>,
@ -719,7 +719,7 @@ impl RenderState {
} }
#[inline] #[inline]
pub fn render_shape_enter(&mut self, element: &mut Shape, mask: bool) { pub fn render_shape_enter(&mut self, element: &Shape, mask: bool) {
// Masked groups needs two rendering passes, the first one rendering // Masked groups needs two rendering passes, the first one rendering
// the content and the second one rendering the mask so we need to do // the content and the second one rendering the mask so we need to do
// an extra save_layer to keep all the masked group separate from // an extra save_layer to keep all the masked group separate from
@ -765,7 +765,7 @@ impl RenderState {
} }
#[inline] #[inline]
pub fn render_shape_exit(&mut self, element: &mut Shape, visited_mask: bool) { pub fn render_shape_exit(&mut self, element: &Shape, visited_mask: bool) {
if visited_mask { if visited_mask {
// Because masked groups needs two rendering passes (first drawing // Because masked groups needs two rendering passes (first drawing
// the content and then drawing the mask), we need to do an // the content and then drawing the mask), we need to do an
@ -849,7 +849,7 @@ impl RenderState {
pub fn render_shape_tree_partial_uncached( pub fn render_shape_tree_partial_uncached(
&mut self, &mut self,
tree: &mut HashMap<Uuid, &mut Shape>, tree: &HashMap<Uuid, &mut Shape>,
modifiers: &HashMap<Uuid, Matrix>, modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>, scale_content: &HashMap<Uuid, f32>,
@ -867,7 +867,7 @@ impl RenderState {
} = node_render_state; } = node_render_state;
is_empty = false; is_empty = false;
let element = tree.get_mut(&node_id).ok_or( let element = tree.get(&node_id).ok_or(
"Error: Element with root_id {node_render_state.id} not found in the tree." "Error: Element with root_id {node_render_state.id} not found in the tree."
.to_string(), .to_string(),
)?; )?;
@ -962,7 +962,7 @@ impl RenderState {
pub fn render_shape_tree_partial( pub fn render_shape_tree_partial(
&mut self, &mut self,
tree: &mut HashMap<Uuid, &mut Shape>, tree: &HashMap<Uuid, &mut Shape>,
modifiers: &HashMap<Uuid, Matrix>, modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>, scale_content: &HashMap<Uuid, f32>,

View file

@ -14,7 +14,7 @@ pub fn render_overlay(
modifiers: &HashMap<Uuid, Matrix>, modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
) { ) {
let cells = grid_cell_data(shape.clone(), shapes, modifiers, structure, true); let cells = grid_cell_data(shape, shapes, modifiers, structure, true);
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);

View file

@ -601,7 +601,7 @@ pub fn create_cell_data<'a>(
} }
pub fn grid_cell_data<'a>( pub fn grid_cell_data<'a>(
shape: Shape, shape: &Shape,
shapes: &'a HashMap<Uuid, &mut Shape>, shapes: &'a HashMap<Uuid, &mut Shape>,
modifiers: &HashMap<Uuid, Matrix>, modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,

View file

@ -171,7 +171,7 @@ impl TextPaths {
blob_offset_x: f32, blob_offset_x: f32,
blob_offset_y: f32, blob_offset_y: f32,
) -> Option<(skia::Path, skia::Rect)> { ) -> Option<(skia::Path, skia::Rect)> {
with_state!(state, { with_state_mut!(state, {
let utf16_text = leaf_text.encode_utf16().collect::<Vec<u16>>(); let utf16_text = leaf_text.encode_utf16().collect::<Vec<u16>>();
let text = unsafe { skia_safe::as_utf16_unchecked(&utf16_text) }; let text = unsafe { skia_safe::as_utf16_unchecked(&utf16_text) };
let emoji_font = state.render_state.fonts().get_emoji_font(font.size()); let emoji_font = state.render_state.fonts().get_emoji_font(font.size());

View file

@ -106,10 +106,14 @@ impl<'a> State<'a> {
self.render_state.resize(width, height); self.render_state.resize(width, height);
} }
pub fn render_state(&'a mut self) -> &'a mut RenderState { pub fn render_state_mut(&'a mut self) -> &'a mut RenderState {
&mut self.render_state &mut self.render_state
} }
pub fn render_state(&'a self) -> &'a RenderState {
&self.render_state
}
pub fn render_from_cache(&mut self) { pub fn render_from_cache(&mut self) {
self.render_state self.render_state
.render_from_cache(&self.shapes, &self.modifiers, &self.structure); .render_from_cache(&self.shapes, &self.modifiers, &self.structure);
@ -117,7 +121,7 @@ impl<'a> State<'a> {
pub fn start_render_loop(&mut self, timestamp: i32) -> Result<(), String> { pub fn start_render_loop(&mut self, timestamp: i32) -> Result<(), String> {
self.render_state.start_render_loop( self.render_state.start_render_loop(
&mut self.shapes, &self.shapes,
&self.modifiers, &self.modifiers,
&self.structure, &self.structure,
&self.scale_content, &self.scale_content,
@ -128,7 +132,7 @@ impl<'a> State<'a> {
pub fn process_animation_frame(&mut self, timestamp: i32) -> Result<(), String> { pub fn process_animation_frame(&mut self, timestamp: i32) -> Result<(), String> {
self.render_state.process_animation_frame( self.render_state.process_animation_frame(
&mut self.shapes, &self.shapes,
&self.modifiers, &self.modifiers,
&self.structure, &self.structure,
&self.scale_content, &self.scale_content,
@ -172,45 +176,44 @@ impl<'a> State<'a> {
} }
} }
pub fn current_shape(&mut self) -> Option<&mut Shape> { pub fn current_shape_mut(&mut self) -> Option<&mut Shape> {
self.current_shape.as_deref_mut() self.current_shape.as_deref_mut()
} }
pub fn current_shape(&self) -> Option<&Shape> {
self.current_shape.as_deref()
}
pub fn set_background_color(&mut self, color: skia::Color) { pub fn set_background_color(&mut self, color: skia::Color) {
self.render_state.set_background_color(color); self.render_state.set_background_color(color);
} }
pub fn set_selrect_for_current_shape(&mut self, left: f32, top: f32, right: f32, bottom: f32) { pub fn set_selrect_for_current_shape(&mut self, left: f32, top: f32, right: f32, bottom: f32) {
match self.current_shape.as_mut() { let Some(shape) = self.current_shape.as_deref_mut() else {
Some(shape) => { panic!("Invalid current shape")
};
shape.set_selrect(left, top, right, bottom); shape.set_selrect(left, top, right, bottom);
// We don't need to update the tile for the root shape. // We don't need to update the tile for the root shape.
if !shape.id.is_nil() { if !shape.id.is_nil() {
self.render_state.update_tile_for(shape); self.render_state.update_tile_for(shape);
} }
} }
None => panic!("Invalid current shape"),
}
}
pub fn update_tile_for_shape(&mut self, shape_id: Uuid) { pub fn update_tile_for_shape(&mut self, shape_id: Uuid) {
if let Some(shape) = self.shapes.get_mut(&shape_id) { if let Some(shape) = self.shapes.get(&shape_id) {
self.render_state.update_tile_for(shape); self.render_state.update_tile_for(shape);
} }
} }
pub fn update_tile_for_current_shape(&mut self) { pub fn update_tile_for_current_shape(&mut self) {
match self.current_shape.as_mut() { let Some(shape) = self.current_shape.as_deref() else {
Some(shape) => { panic!("Invalid current shape")
// We don't need to update the tile for the root shape. };
// We can also have deleted the selected shape
if !shape.id.is_nil() && self.shapes.contains_key(&shape.id) { if !shape.id.is_nil() && self.shapes.contains_key(&shape.id) {
self.render_state.update_tile_for(shape); self.render_state.update_tile_for(shape);
} }
} }
None => panic!("Invalid current shape"),
}
}
pub fn rebuild_tiles_shallow(&mut self) { pub fn rebuild_tiles_shallow(&mut self) {
self.render_state self.render_state
@ -227,7 +230,7 @@ impl<'a> State<'a> {
.rebuild_modifier_tiles(&mut self.shapes, &self.modifiers); .rebuild_modifier_tiles(&mut self.shapes, &self.modifiers);
} }
pub fn get_grid_coords(&mut self, pos_x: f32, pos_y: f32) -> (i32, i32) { pub fn get_grid_coords(&self, pos_x: f32, pos_y: f32) -> (i32, i32) {
let Some(shape) = self.current_shape() else { let Some(shape) = self.current_shape() else {
return (-1, -1); return (-1, -1);
}; };
@ -235,13 +238,7 @@ impl<'a> State<'a> {
let bounds = shape.bounds(); let bounds = shape.bounds();
let position = Point::new(pos_x, pos_y); let position = Point::new(pos_x, pos_y);
let cells = grid_cell_data( let cells = grid_cell_data(shape, &self.shapes, &self.modifiers, &self.structure, true);
shape.clone(),
&self.shapes,
&self.modifiers,
&self.structure,
true,
);
for cell in cells { for cell in cells {
let points = &[ let points = &[

View file

@ -1,6 +1,6 @@
use crate::skia::Image; use crate::skia::Image;
use crate::uuid::Uuid; use crate::uuid::Uuid;
use crate::with_state; use crate::with_state_mut;
use crate::STATE; use crate::STATE;
use std::collections::HashSet; use std::collections::HashSet;
@ -24,10 +24,10 @@ pub fn uuid_from_u32(id: [u32; 4]) -> Uuid {
} }
pub fn get_image(image_id: &Uuid) -> Option<&Image> { pub fn get_image(image_id: &Uuid) -> Option<&Image> {
with_state!(state, { state.render_state().images.get(image_id) }) with_state_mut!(state, { state.render_state_mut().images.get(image_id) })
} }
// FIXME: move to a different place ? // FIXME: move to a different place ?
pub fn get_fallback_fonts() -> &'static HashSet<String> { pub fn get_fallback_fonts() -> &'static HashSet<String> {
with_state!(state, { state.render_state().fonts().get_fallback() }) with_state_mut!(state, { state.render_state().fonts().get_fallback() })
} }

View file

@ -4,7 +4,7 @@ mod solid;
use crate::mem; use crate::mem;
use crate::shapes; use crate::shapes;
use crate::with_current_shape; use crate::with_current_shape_mut;
use crate::STATE; use crate::STATE;
const RAW_FILL_DATA_SIZE: usize = std::mem::size_of::<RawFillData>(); const RAW_FILL_DATA_SIZE: usize = std::mem::size_of::<RawFillData>();
@ -65,7 +65,7 @@ pub fn parse_fills_from_bytes(buffer: &[u8], num_fills: usize) -> Vec<shapes::Fi
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_fills() { pub extern "C" fn set_shape_fills() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let bytes = mem::bytes(); let bytes = mem::bytes();
let fills = parse_fills_from_bytes(&bytes, bytes.len() / RAW_FILL_DATA_SIZE); let fills = parse_fills_from_bytes(&bytes, bytes.len() / RAW_FILL_DATA_SIZE);
shape.set_fills(fills); shape.set_fills(fills);
@ -74,7 +74,7 @@ pub extern "C" fn set_shape_fills() {
#[no_mangle] #[no_mangle]
pub extern "C" fn add_shape_fill() { pub extern "C" fn add_shape_fill() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let bytes = mem::bytes(); let bytes = mem::bytes();
let raw_fill = RawFillData::try_from(&bytes[..]).expect("Invalid fill data"); let raw_fill = RawFillData::try_from(&bytes[..]).expect("Invalid fill data");
shape.add_fill(raw_fill.into()); shape.add_fill(raw_fill.into());
@ -83,7 +83,7 @@ pub extern "C" fn add_shape_fill() {
#[no_mangle] #[no_mangle]
pub extern "C" fn clear_shape_fills() { pub extern "C" fn clear_shape_fills() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.clear_fills(); shape.clear_fills();
}); });
} }

View file

@ -1,6 +1,6 @@
use crate::mem; use crate::mem;
use crate::utils::uuid_from_u32_quartet; use crate::utils::uuid_from_u32_quartet;
use crate::with_state; use crate::with_state_mut;
use crate::STATE; use crate::STATE;
use crate::shapes::FontFamily; use crate::shapes::FontFamily;
@ -20,20 +20,21 @@ pub extern "C" fn store_font(
is_emoji: bool, is_emoji: bool,
is_fallback: bool, is_fallback: bool,
) { ) {
with_state!(state, { with_state_mut!(state, {
let id = uuid_from_u32_quartet(a2, b2, c2, d2); let id = uuid_from_u32_quartet(a2, b2, c2, d2);
let font_bytes = mem::bytes(); let font_bytes = mem::bytes();
let family = FontFamily::new(id, weight, style.into()); let family = FontFamily::new(id, weight, style.into());
let _ = state let _ =
.render_state() state
.render_state_mut()
.fonts_mut() .fonts_mut()
.add(family, &font_bytes, is_emoji, is_fallback); .add(family, &font_bytes, is_emoji, is_fallback);
mem::free_bytes(); mem::free_bytes();
}); });
with_state!(state, { with_state_mut!(state, {
let shape_id = uuid_from_u32_quartet(a1, b1, c1, d1); let shape_id = uuid_from_u32_quartet(a1, b1, c1, d1);
state.update_tile_for_shape(shape_id); state.update_tile_for_shape(shape_id);
}); });
@ -49,7 +50,7 @@ pub extern "C" fn is_font_uploaded(
style: u8, style: u8,
is_emoji: bool, is_emoji: bool,
) -> bool { ) -> bool {
with_state!(state, { with_state_mut!(state, {
let id = uuid_from_u32_quartet(a, b, c, d); let id = uuid_from_u32_quartet(a, b, c, d);
let family = FontFamily::new(id, weight, style.into()); let family = FontFamily::new(id, weight, style.into());
let res = state.render_state().fonts().has_family(&family, is_emoji); let res = state.render_state().fonts().has_family(&family, is_emoji);

View file

@ -1,5 +1,5 @@
use crate::shapes::{Path, Segment}; use crate::shapes::{Path, Segment};
use crate::{mem, with_current_shape, STATE}; use crate::{mem, with_current_shape_mut, STATE};
const RAW_SEGMENT_DATA_SIZE: usize = size_of::<RawSegmentData>(); const RAW_SEGMENT_DATA_SIZE: usize = size_of::<RawSegmentData>();
@ -79,7 +79,7 @@ impl From<Vec<RawSegmentData>> for Path {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_path_content() { pub extern "C" fn set_shape_path_content() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let bytes = mem::bytes(); let bytes = mem::bytes();
let segments = bytes let segments = bytes
@ -112,7 +112,7 @@ fn extract_string(start: &mut usize, bytes: &[u8]) -> String {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_path_attrs(num_attrs: u32) { pub extern "C" fn set_shape_path_attrs(num_attrs: u32) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let bytes = mem::bytes(); let bytes = mem::bytes();
let mut start = 0; let mut start = 0;
for _ in 0..num_attrs { for _ in 0..num_attrs {

View file

@ -1,11 +1,11 @@
use crate::mem; use crate::mem;
use crate::shapes; use crate::shapes;
use crate::with_current_shape; use crate::with_current_shape_mut;
use crate::STATE; use crate::STATE;
#[no_mangle] #[no_mangle]
pub extern "C" fn add_shape_center_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) { pub extern "C" fn add_shape_center_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.add_stroke(shapes::Stroke::new_center_stroke( shape.add_stroke(shapes::Stroke::new_center_stroke(
width, style, cap_start, cap_end, width, style, cap_start, cap_end,
)); ));
@ -14,7 +14,7 @@ pub extern "C" fn add_shape_center_stroke(width: f32, style: u8, cap_start: u8,
#[no_mangle] #[no_mangle]
pub extern "C" fn add_shape_inner_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) { pub extern "C" fn add_shape_inner_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.add_stroke(shapes::Stroke::new_inner_stroke( shape.add_stroke(shapes::Stroke::new_inner_stroke(
width, style, cap_start, cap_end, width, style, cap_start, cap_end,
)); ));
@ -23,7 +23,7 @@ pub extern "C" fn add_shape_inner_stroke(width: f32, style: u8, cap_start: u8, c
#[no_mangle] #[no_mangle]
pub extern "C" fn add_shape_outer_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) { pub extern "C" fn add_shape_outer_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.add_stroke(shapes::Stroke::new_outer_stroke( shape.add_stroke(shapes::Stroke::new_outer_stroke(
width, style, cap_start, cap_end, width, style, cap_start, cap_end,
)); ));
@ -32,7 +32,7 @@ pub extern "C" fn add_shape_outer_stroke(width: f32, style: u8, cap_start: u8, c
#[no_mangle] #[no_mangle]
pub extern "C" fn add_shape_stroke_fill() { pub extern "C" fn add_shape_stroke_fill() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let bytes = mem::bytes(); let bytes = mem::bytes();
let raw_fill = super::fills::RawFillData::try_from(&bytes[..]).expect("Invalid fill data"); let raw_fill = super::fills::RawFillData::try_from(&bytes[..]).expect("Invalid fill data");
shape shape
@ -43,7 +43,7 @@ pub extern "C" fn add_shape_stroke_fill() {
#[no_mangle] #[no_mangle]
pub extern "C" fn clear_shape_strokes() { pub extern "C" fn clear_shape_strokes() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.clear_strokes(); shape.clear_strokes();
}); });
} }

View file

@ -2,11 +2,11 @@ use crate::mem;
use crate::shapes::{auto_height, auto_width, max_width, GrowType, RawTextData, Type}; use crate::shapes::{auto_height, auto_width, max_width, GrowType, RawTextData, Type};
use crate::STATE; use crate::STATE;
use crate::{with_current_shape, with_state}; use crate::{with_current_shape, with_current_shape_mut, with_state_mut};
#[no_mangle] #[no_mangle]
pub extern "C" fn clear_shape_text() { pub extern "C" fn clear_shape_text() {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
shape.clear_text(); shape.clear_text();
}); });
} }
@ -14,7 +14,7 @@ pub extern "C" fn clear_shape_text() {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_text_content() { pub extern "C" fn set_shape_text_content() {
let bytes = mem::bytes(); let bytes = mem::bytes();
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
let raw_text_data = RawTextData::from(&bytes); let raw_text_data = RawTextData::from(&bytes);
shape shape
.add_paragraph(raw_text_data.paragraph) .add_paragraph(raw_text_data.paragraph)
@ -26,7 +26,7 @@ pub extern "C" fn set_shape_text_content() {
#[no_mangle] #[no_mangle]
pub extern "C" fn set_shape_grow_type(grow_type: u8) { pub extern "C" fn set_shape_grow_type(grow_type: u8) {
with_current_shape!(state, |shape: &mut Shape| { with_current_shape_mut!(state, |shape: &mut Shape| {
if let Type::Text(text_content) = &mut shape.shape_type { if let Type::Text(text_content) = &mut shape.shape_type {
text_content.set_grow_type(GrowType::from(grow_type)); text_content.set_grow_type(GrowType::from(grow_type));
} }
@ -36,14 +36,15 @@ pub extern "C" fn set_shape_grow_type(grow_type: u8) {
#[no_mangle] #[no_mangle]
pub extern "C" fn get_text_dimensions() -> *mut u8 { pub extern "C" fn get_text_dimensions() -> *mut u8 {
let font_col; let font_col;
with_state!(state, { with_state_mut!(state, {
font_col = state.render_state.fonts.font_collection(); font_col = state.render_state.fonts.font_collection();
}); });
let mut width = 0.01; let mut width = 0.01;
let mut height = 0.01; let mut height = 0.01;
let mut m_width = 0.01; let mut m_width = 0.01;
with_current_shape!(state, |shape: &mut Shape| {
with_current_shape!(state, |shape: &Shape| {
width = shape.selrect.width(); width = shape.selrect.width();
height = shape.selrect.height(); height = shape.selrect.height();