Merge pull request #9389 from penpot/azazeln28-refactor-state

♻️ Refactor State into DesignState
This commit is contained in:
Alejandro Alonso 2026-05-12 12:15:05 +02:00 committed by GitHub
commit 086ed83847
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 233 additions and 252 deletions

138
render-wasm/src/globals.rs Normal file
View File

@ -0,0 +1,138 @@
use macros::wasm_error;
use crate::mem;
use crate::render::{gpu_state::GpuState, RenderState};
use crate::state::{State, TextEditorState};
static mut DESIGN_STATE: *mut State = std::ptr::null_mut();
/// Design State.
pub(crate) fn get_design_state() -> &'static mut State {
unsafe {
debug_assert!(!DESIGN_STATE.is_null(), "Design State is null");
&mut *DESIGN_STATE
}
}
/// GPU State.
static mut GPU_STATE: *mut GpuState = std::ptr::null_mut();
#[inline(always)]
pub(crate) fn get_gpu_state() -> &'static mut GpuState {
unsafe {
debug_assert!(!GPU_STATE.is_null(), "GPU State is null");
&mut *GPU_STATE
}
}
/// Render State.
static mut RENDER_STATE: *mut RenderState = std::ptr::null_mut();
#[inline(always)]
pub(crate) fn get_render_state() -> &'static mut RenderState {
unsafe {
debug_assert!(!RENDER_STATE.is_null(), "Render State is null");
&mut *RENDER_STATE
}
}
/// Text Editor State
static mut TEXT_EDITOR_STATE: *mut TextEditorState = std::ptr::null_mut();
#[inline(always)]
pub(crate) fn get_text_editor_state() -> &'static mut TextEditorState {
unsafe {
debug_assert!(!TEXT_EDITOR_STATE.is_null(), "Text Editor state is null");
&mut *TEXT_EDITOR_STATE
}
}
// FIXME: These with_state* macros should be using our CriticalError instead of expect.
// But to do that, we need to not use them at domain-level (i.e. in business logic), just
// in the context of the wasm call.
#[macro_export]
macro_rules! with_state {
($state:ident, $block:block) => {{
use $crate::globals::get_design_state;
let $state = get_design_state();
$block
}};
}
#[macro_export]
macro_rules! with_current_shape_mut {
($state:ident, |$shape:ident: &mut Shape| $block:block) => {
use $crate::globals::get_design_state;
let $state = get_design_state();
$state.touch_current();
if let Some($shape) = $state.current_shape_mut() {
$block
}
};
}
#[macro_export]
macro_rules! with_current_shape {
($state:ident, |$shape:ident: &Shape| $block:block) => {
use $crate::globals::get_design_state;
let $state = get_design_state();
if let Some($shape) = $state.current_shape() {
$block
}
};
}
/// Initializes GPUState.
fn gpu_init() {
unsafe {
let gpu_state = GpuState::try_new().expect("Cannot initialize GPU State");
GPU_STATE = Box::into_raw(Box::new(gpu_state));
}
}
/// Initializes RenderState.
fn render_init(width: i32, height: i32) {
unsafe {
let render_state =
RenderState::try_new(width, height).expect("Cannot intialize RenderState");
RENDER_STATE = Box::into_raw(Box::new(render_state));
}
}
/// Initializes DesignState.
fn design_init() {
unsafe {
let design_state = State::new();
DESIGN_STATE = Box::into_raw(Box::new(design_state));
}
}
fn text_editor_init() {
unsafe {
let text_editor_state = TextEditorState::new();
TEXT_EDITOR_STATE = Box::into_raw(Box::new(text_editor_state));
}
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn init(width: i32, height: i32) -> Result<()> {
gpu_init();
render_init(width, height);
text_editor_init();
design_init();
Ok(())
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn clean_up() -> Result<()> {
// Cancel the current animation frame if it exists so
// it won't try to render without context
let render_state = get_render_state();
render_state.cancel_animation_frame();
render_state.prepare_context_loss_cleanup();
unsafe { DESIGN_STATE = std::ptr::null_mut() }
mem::free_bytes()?;
Ok(())
}

View File

@ -1,6 +1,7 @@
#[cfg(target_arch = "wasm32")]
mod emscripten;
mod error;
mod globals;
mod math;
mod mem;
mod performance;
@ -18,181 +19,26 @@ use std::collections::HashMap;
#[allow(unused_imports)]
use crate::error::{Error, Result};
use crate::state::TextEditorState;
use globals::{get_design_state, get_gpu_state, get_render_state};
use macros::wasm_error;
use math::{Bounds, Matrix};
use mem::SerializableResult;
use render::{gpu_state::GpuState, RenderState};
use shapes::{StructureEntry, StructureEntryType, TransformEntry};
use skia_safe as skia;
use state::State;
use utils::uuid_from_u32_quartet;
use uuid::Uuid;
pub(crate) static mut STATE: Option<Box<State>> = None;
pub(crate) static mut TEXT_EDITOR_STATE: *mut TextEditorState = std::ptr::null_mut();
#[inline(always)]
pub fn get_text_editor_state() -> &'static mut TextEditorState {
unsafe {
debug_assert!(!TEXT_EDITOR_STATE.is_null(), "Text Editor state is null");
&mut *TEXT_EDITOR_STATE
}
}
/// GPU State.
static mut GPU_STATE: *mut GpuState = std::ptr::null_mut();
#[inline(always)]
pub(crate) fn get_gpu_state() -> &'static mut GpuState {
unsafe {
debug_assert!(!GPU_STATE.is_null(), "GPU State is null");
&mut *GPU_STATE
}
}
/// Render State.
static mut RENDER_STATE: *mut RenderState = std::ptr::null_mut();
#[inline(always)]
pub(crate) fn get_render_state() -> &'static mut RenderState {
unsafe {
debug_assert!(!RENDER_STATE.is_null(), "Render State is null");
&mut *RENDER_STATE
}
}
// FIXME: These with_state* macros should be using our CriticalError instead of expect.
// But to do that, we need to not use them at domain-level (i.e. in business logic), just
// in the context of the wasm call.
#[macro_export]
macro_rules! with_state_mut {
($state:ident, $block:block) => {{
let $state = unsafe {
#[allow(static_mut_refs)]
STATE.as_mut()
}
.expect("Got an invalid state pointer");
$block
}};
}
#[macro_export]
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_rules! with_current_shape_mut {
($state:ident, |$shape:ident: &mut Shape| $block:block) => {
let $state = unsafe {
#[allow(static_mut_refs)]
STATE.as_mut()
}
.expect("Got an invalid state pointer");
$state.touch_current();
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() {
$block
}
};
}
#[macro_export]
macro_rules! with_state_mut_current_shape {
($state:ident, |$shape:ident: &Shape| $block:block) => {
let $state = unsafe {
#[allow(static_mut_refs)]
STATE.as_mut()
}
.expect("Got an invalid state pointer");
if let Some($shape) = $state.current_shape() {
$block
}
};
}
/// Initializes GPU.
fn gpu_init() {
unsafe {
let gpu_state = GpuState::try_new().expect("Cannot initialize GPU State");
GPU_STATE = Box::into_raw(Box::new(gpu_state));
}
}
/// Initializes RenderState.
fn render_init(width: i32, height: i32) {
unsafe {
let render_state =
RenderState::try_new(width, height).expect("Cannot intialize RenderState");
RENDER_STATE = Box::into_raw(Box::new(render_state));
}
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn init(width: i32, height: i32) -> Result<()> {
gpu_init();
render_init(width, height);
unsafe {
let state_box = Box::new(State::new());
STATE = Some(state_box);
TEXT_EDITOR_STATE = Box::into_raw(Box::new(TextEditorState::new()));
}
Ok(())
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn set_browser(browser: u8) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.set_browser(browser);
});
Ok(())
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn clean_up() -> Result<()> {
// Cancel the current animation frame if it exists so
// it won't try to render without context
unsafe {
#[allow(static_mut_refs)]
if STATE.is_some() {
// Cancel the current animation frame if it exists so
// it won't try to render without context.
let render_state = get_render_state();
render_state.cancel_animation_frame();
render_state.prepare_context_loss_cleanup();
}
STATE = None;
}
mem::free_bytes()?;
Ok(())
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn set_render_options(debug: u32, dpr: f32) -> Result<()> {
@ -255,7 +101,7 @@ pub extern "C" fn set_max_atlas_texture_size(max_px: i32) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn set_canvas_background(raw_color: u32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
let color = skia::Color::new(raw_color);
state.set_background_color(color);
state.rebuild_tiles_shallow();
@ -267,7 +113,7 @@ pub extern "C" fn set_canvas_background(raw_color: u32) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn render(timestamp: i32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.rebuild_touched_tiles();
// Drain the throttled modifier-tile invalidation accumulated
// since the previous rAF. set_modifiers skips this work during
@ -290,7 +136,7 @@ pub extern "C" fn render(timestamp: i32) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn render_sync() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.rebuild_tiles();
state
.render_sync(0)
@ -302,7 +148,7 @@ pub extern "C" fn render_sync() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn render_sync_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
let id = uuid_from_u32_quartet(a, b, c, d);
state.use_shape(id);
@ -328,7 +174,7 @@ pub extern "C" fn render_sync_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()
#[no_mangle]
#[wasm_error]
pub extern "C" fn render_from_cache(_: i32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
// Don't cancel the animation frame — let the async render
// continue populating the tile HashMap in the background.
// process_animation_frame skips flush_and_submit in fast
@ -351,7 +197,7 @@ pub extern "C" fn set_preview_mode(enabled: bool) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn render_preview() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.render_preview(performance::get_time());
});
Ok(())
@ -361,7 +207,7 @@ pub extern "C" fn render_preview() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn begin_loading() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.loading = true;
});
Ok(())
@ -372,7 +218,7 @@ pub extern "C" fn begin_loading() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn end_loading() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.loading = false;
});
Ok(())
@ -394,7 +240,7 @@ pub extern "C" fn render_loading_overlay() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn process_animation_frame(timestamp: i32) -> Result<()> {
let result = with_state_mut!(state, { state.process_animation_frame(timestamp) });
let result = with_state!(state, { state.process_animation_frame(timestamp) });
if let Err(err) = result {
eprintln!("process_animation_frame error: {}", err);
}
@ -449,7 +295,7 @@ pub extern "C" fn set_view_start() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn set_view_end() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
performance::begin_measure!("set_view_end");
let render_state = get_render_state();
render_state.options.set_fast_mode(false);
@ -518,7 +364,7 @@ pub extern "C" fn set_modifiers_end() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn clear_focus_mode() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.clear_focus_mode();
});
Ok(())
@ -534,7 +380,7 @@ pub extern "C" fn set_focus_mode() -> Result<()> {
.map(|data| Uuid::try_from(data).map_err(|e| Error::RecoverableError(e.to_string())))
.collect::<Result<Vec<Uuid>>>()?;
with_state_mut!(state, {
with_state!(state, {
state.set_focus_mode(entries);
});
Ok(())
@ -543,7 +389,7 @@ pub extern "C" fn set_focus_mode() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn init_shapes_pool(capacity: usize) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
state.init_shapes_pool(capacity);
});
Ok(())
@ -552,7 +398,7 @@ pub extern "C" fn init_shapes_pool(capacity: usize) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
let id = uuid_from_u32_quartet(a, b, c, d);
state.use_shape(id);
});
@ -562,7 +408,7 @@ pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn touch_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
let shape_id = uuid_from_u32_quartet(a, b, c, d);
state.touch_shape(shape_id);
});
@ -572,7 +418,7 @@ pub extern "C" fn touch_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn set_parent(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
let id = uuid_from_u32_quartet(a, b, c, d);
state.set_parent_for_current_shape(id);
});
@ -658,7 +504,7 @@ fn set_children_set(entries: Vec<Uuid>) -> Result<()> {
}
});
with_state_mut!(state, {
with_state!(state, {
let Some(parent_id) = parent_id else {
return Err(Error::RecoverableError(
"set_children_set: Parent ID not found".to_string(),
@ -891,7 +737,7 @@ pub extern "C" fn get_selection_rect() -> Result<*mut u8> {
})
.collect();
let result_bound = with_state_mut!(state, {
let result_bound = with_state!(state, {
let bbs: Vec<_> = entries
.iter()
.flat_map(|id| state.shapes.get(id).map(|b| b.bounds()))
@ -938,7 +784,7 @@ pub extern "C" fn set_structure_modifiers() -> Result<()> {
})
.collect::<Result<Vec<_>>>()?;
with_state_mut!(state, {
with_state!(state, {
let mut structure = HashMap::new();
let mut scale_content = HashMap::new();
for entry in entries {
@ -977,7 +823,7 @@ pub extern "C" fn set_structure_modifiers() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn clean_modifiers() -> Result<()> {
with_state_mut!(state, {
with_state!(state, {
let render_state = get_render_state();
let prev_modifier_ids = state.shapes.clean_all();
// Skip the tile-cache cleanup during interactive transform: the
@ -1008,7 +854,7 @@ pub extern "C" fn set_modifiers() -> Result<()> {
ids.push(entry.id);
}
with_state_mut!(state, {
with_state!(state, {
state.set_modifiers(modifiers);
// TO CHECK
if !get_render_state().options.is_interactive_transform() {
@ -1021,28 +867,14 @@ pub extern "C" fn set_modifiers() -> Result<()> {
#[no_mangle]
#[wasm_error]
pub extern "C" fn start_temp_objects() -> Result<()> {
unsafe {
#[allow(static_mut_refs)]
let mut state = STATE.take().ok_or(Error::CriticalError(
"Got an invalid state pointer".to_string(),
))?;
state = Box::new(state.start_temp_objects()?);
STATE = Some(state);
}
get_design_state().start_temp_objects()?;
Ok(())
}
#[no_mangle]
#[wasm_error]
pub extern "C" fn end_temp_objects() -> Result<()> {
unsafe {
#[allow(static_mut_refs)]
let mut state = STATE.take().ok_or(Error::CriticalError(
"Got an invalid state pointer".to_string(),
))?;
state = Box::new(state.end_temp_objects()?);
STATE = Some(state);
}
get_design_state().end_temp_objects()?;
Ok(())
}
@ -1061,7 +893,7 @@ pub extern "C" fn render_shape_pixels(
return Err(Error::CriticalError("Scale is not finite".to_string()));
}
with_state_mut!(state, {
with_state!(state, {
let (data, width, height) =
state.render_shape_pixels(&id, scale, performance::get_time())?;

View File

@ -26,7 +26,6 @@ use crate::math::Point;
use crate::shapes::{self, merge_fills, Shape, VerticalAlign};
use crate::utils::{get_fallback_fonts, get_font_collection};
use crate::Uuid;
use crate::STATE;
// TODO: maybe move this to the wasm module?
pub type ParagraphBuilderGroup = Vec<ParagraphBuilder>;

View File

@ -38,26 +38,26 @@ impl State {
// Creates a new temporary shapes pool.
// Will panic if a previous temporary pool exists.
pub fn start_temp_objects(mut self) -> Result<Self> {
pub fn start_temp_objects(&mut self) -> Result<()> {
if self.saved_shapes.is_some() {
return Err(Error::CriticalError(
"Tried to start a temp objects while the previous have not been restored"
.to_string(),
));
}
self.saved_shapes = Some(self.shapes);
self.saved_shapes = Some(self.shapes.clone());
self.shapes = ShapesPool::new();
Ok(self)
Ok(())
}
// Disposes of the temporary shapes pool restoring the normal pool
// Will panic if a there is no temporary pool.
pub fn end_temp_objects(mut self) -> Result<Self> {
self.shapes = self.saved_shapes.ok_or(Error::CriticalError(
pub fn end_temp_objects(&mut self) -> Result<()> {
self.shapes = self.saved_shapes.clone().ok_or(Error::CriticalError(
"Tried to end temp objects but not content to be restored is present".to_string(),
))?;
self.saved_shapes = None;
Ok(self)
Ok(())
}
pub fn render_from_cache(&mut self) {

View File

@ -398,3 +398,19 @@ impl Default for ShapesPoolImpl {
Self::new()
}
}
impl Clone for ShapesPoolImpl {
fn clone(&self) -> Self {
ShapesPoolImpl {
shapes: self.shapes.clone(),
counter: self.counter,
uuid_to_idx: self.uuid_to_idx.clone(),
// The modified_shape_cache is a derived/computed cache; reset it on clone
// so it gets lazily rebuilt on demand rather than cloning OnceCell state.
modified_shape_cache: HashMap::default(),
modifiers: self.modifiers.clone(),
structure: self.structure.clone(),
scale_content: self.scale_content.clone(),
}
}
}

View File

@ -2,8 +2,7 @@ use crate::get_render_state;
use crate::skia::textlayout::FontCollection;
use crate::skia::Image;
use crate::uuid::Uuid;
use crate::with_state_mut;
use crate::STATE;
use crate::with_state;
use std::collections::HashSet;
pub fn uuid_from_u32_quartet(a: u32, b: u32, c: u32, d: u32) -> Uuid {
@ -35,7 +34,7 @@ pub fn get_fallback_fonts() -> &'static HashSet<String> {
}
pub fn get_font_collection() -> &'static FontCollection {
with_state_mut!(state, { state.font_collection() })
with_state!(state, { state.font_collection() })
}
#[derive(Debug, Clone, Copy)]

View File

@ -2,7 +2,7 @@ use macros::ToJs;
use skia_safe as skia;
use crate::shapes::BlendMode;
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
#[repr(u8)]

View File

@ -1,7 +1,7 @@
use macros::ToJs;
use crate::shapes::{Blur, BlurType};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
#[repr(u8)]

View File

@ -3,7 +3,6 @@ use macros::{wasm_error, ToJs};
use crate::mem;
use crate::shapes;
use crate::with_current_shape_mut;
use crate::STATE;
mod gradient;
mod image;

View File

@ -4,8 +4,7 @@ use crate::mem;
use crate::shapes::Fill;
use crate::state::State;
use crate::uuid::Uuid;
use crate::with_state_mut;
use crate::STATE;
use crate::with_state;
use crate::{shapes::ImageFill, utils::uuid_from_u32_quartet};
use macros::wasm_error;
@ -106,7 +105,7 @@ pub extern "C" fn store_image() -> Result<()> {
let image_bytes = &bytes[IMAGE_HEADER_SIZE..];
with_state_mut!(state, {
with_state!(state, {
if let Err(msg) = get_render_state().add_image(ids.image_id, is_thumbnail, image_bytes) {
eprintln!("{}", msg);
}
@ -176,7 +175,7 @@ pub extern "C" fn store_image_from_texture() -> Result<()> {
.map_err(|_| Error::CriticalError("Invalid bytes for height".to_string()))?,
);
with_state_mut!(state, {
with_state!(state, {
if let Err(msg) = get_render_state().add_image_from_gl_texture(
ids.image_id,
is_thumbnail,

View File

@ -1,5 +1,5 @@
use crate::shapes::Sizing;
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
use macros::ToJs;
mod align;

View File

@ -3,7 +3,7 @@ use macros::ToJs;
use crate::shapes::{
AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf, VerticalAlign,
};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]

View File

@ -1,7 +1,7 @@
use macros::ToJs;
use crate::shapes::{ConstraintH, ConstraintV};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]

View File

@ -1,5 +1,5 @@
use crate::shapes::{FlexDirection, WrapType};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
use macros::ToJs;
use super::align;

View File

@ -4,7 +4,7 @@ use crate::get_render_state;
use crate::mem;
use crate::shapes::{GridCell, GridDirection, GridTrack, GridTrackType};
use crate::uuid::Uuid;
use crate::{uuid_from_u32_quartet, with_current_shape_mut, with_state, STATE};
use crate::{uuid_from_u32_quartet, with_current_shape_mut, with_state};
use super::align;

View File

@ -6,7 +6,7 @@ use std::sync::{Mutex, OnceLock};
use crate::error::{Error, Result};
use crate::shapes::{stroke_to_path, Path, Segment, ToPath};
use crate::{mem, with_current_shape, with_current_shape_mut, STATE};
use crate::{mem, with_current_shape, with_current_shape_mut};
const RAW_SEGMENT_DATA_SIZE: usize = size_of::<RawSegmentData>();

View File

@ -5,7 +5,7 @@ use crate::math;
use crate::shapes::BoolType;
use crate::uuid::Uuid;
use crate::{mem, SerializableResult};
use crate::{with_current_shape_mut, with_state, STATE};
use crate::{with_current_shape_mut, with_state};
use std::mem::size_of;
#[allow(unused_imports)]

View File

@ -2,7 +2,7 @@ use macros::ToJs;
use skia_safe as skia;
use crate::shapes::{Shadow, ShadowStyle};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
#[repr(u8)]

View File

@ -4,7 +4,7 @@ use crate::utils::uuid_from_u32_quartet;
use crate::uuid::Uuid;
use crate::wasm::blend::RawBlendMode;
use crate::wasm::layouts::constraints::{RawConstraintH, RawConstraintV};
use crate::{with_state_mut, STATE};
use crate::with_state;
#[allow(unused_imports)]
use crate::error::{Error, Result};
@ -128,7 +128,7 @@ pub extern "C" fn set_shape_base_props() -> Result<()> {
let parent_id = raw.parent_id();
let shape_type = RawShapeType::from(raw.shape_type);
with_state_mut!(state, {
with_state!(state, {
state.use_shape(id);
state.set_parent_for_current_shape(parent_id);
state.touch_current();

View File

@ -3,7 +3,7 @@ mod base_props;
use macros::ToJs;
use crate::shapes::{Bool, Frame, Group, Path, Rect, SVGRaw, TextContent, Type};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(Debug, Clone, PartialEq, ToJs)]
#[repr(u8)]

View File

@ -3,7 +3,6 @@ use macros::ToJs;
use crate::mem;
use crate::shapes::{self, StrokeCap, StrokeStyle};
use crate::with_current_shape_mut;
use crate::STATE;
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]

View File

@ -1,7 +1,7 @@
use macros::ToJs;
use crate::shapes::{FillRule, StrokeLineCap, StrokeLineJoin, SvgAttrs};
use crate::{with_current_shape_mut, STATE};
use crate::with_current_shape_mut;
#[derive(PartialEq, ToJs)]
#[repr(u8)]

View File

@ -7,7 +7,7 @@ use crate::shapes::{
self, GrowType, Shape, TextAlign, TextDecoration, TextDirection, TextTransform, Type,
};
use crate::utils::{uuid_from_u32, uuid_from_u32_quartet};
use crate::{with_current_shape, with_current_shape_mut, with_state, with_state_mut, STATE};
use crate::{with_current_shape, with_current_shape_mut, with_state};
use crate::error::Error;
@ -386,7 +386,7 @@ pub extern "C" fn update_shape_text_layout() {
#[no_mangle]
pub extern "C" fn update_shape_text_layout_for(a: u32, b: u32, c: u32, d: u32) {
with_state_mut!(state, {
with_state!(state, {
let shape_id = uuid_from_u32_quartet(a, b, c, d);
if let Some(shape) = state.shapes.get_mut(&shape_id) {
update_text_layout(shape);

View File

@ -1,7 +1,8 @@
use macros::{wasm_error, ToJs};
use crate::get_text_editor_state;
use crate::globals::{get_render_state, get_text_editor_state};
use crate::math::{Matrix, Point, Rect};
use crate::mem;
use crate::render::text_editor as text_editor_render;
use crate::render::SurfaceId;
use crate::shapes::{Shape, TextAlign, TextContent, TextPositionWithAffinity, Type, VerticalAlign};
@ -12,8 +13,7 @@ use crate::wasm::fills::RawFillData;
use crate::wasm::text::{
helpers as text_helpers, RawTextAlign, RawTextDecoration, RawTextDirection, RawTextTransform,
};
use crate::{get_render_state, mem};
use crate::{with_state, with_state_mut, STATE};
use crate::with_state;
use skia_safe::Color;
#[derive(PartialEq, ToJs)]
@ -42,7 +42,7 @@ pub extern "C" fn text_editor_apply_theme(selection_color: u32, cursor_color: u3
#[no_mangle]
pub extern "C" fn text_editor_focus(a: u32, b: u32, c: u32, d: u32) -> bool {
with_state_mut!(state, {
with_state!(state, {
let shape_id = uuid_from_u32_quartet(a, b, c, d);
let Some(shape) = state.shapes.get(&shape_id) else {
@ -107,7 +107,7 @@ pub extern "C" fn text_editor_get_active_shape_id(buffer_ptr: *mut u32) {
#[no_mangle]
pub extern "C" fn text_editor_select_all() -> bool {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return false;
}
@ -129,7 +129,7 @@ pub extern "C" fn text_editor_select_all() -> bool {
#[no_mangle]
pub extern "C" fn text_editor_select_word_boundary(x: f32, y: f32) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -164,7 +164,7 @@ pub extern "C" fn text_editor_poll_event() -> u8 {
#[no_mangle]
pub extern "C" fn text_editor_pointer_down(x: f32, y: f32) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -188,7 +188,7 @@ pub extern "C" fn text_editor_pointer_down(x: f32, y: f32) {
#[no_mangle]
pub extern "C" fn text_editor_pointer_move(x: f32, y: f32) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -222,7 +222,7 @@ pub extern "C" fn text_editor_pointer_move(x: f32, y: f32) {
#[no_mangle]
pub extern "C" fn text_editor_pointer_up(x: f32, y: f32) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -249,7 +249,7 @@ pub extern "C" fn text_editor_pointer_up(x: f32, y: f32) {
#[no_mangle]
pub extern "C" fn text_editor_set_cursor_from_offset(x: f32, y: f32) {
with_state_mut!(state, {
with_state!(state, {
// We need this flag to prevent handling the click behavior
// just after a pointerup event.
if get_text_editor_state().is_click_event_skipped {
@ -282,7 +282,7 @@ pub extern "C" fn text_editor_set_cursor_from_offset(x: f32, y: f32) {
#[no_mangle]
pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -330,7 +330,7 @@ pub extern "C" fn text_editor_composition_end() -> Result<()> {
Err(_) => return Ok(()),
};
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return Ok(());
}
@ -386,7 +386,7 @@ pub extern "C" fn text_editor_composition_update() -> Result<()> {
Err(_) => return Ok(()),
};
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return Ok(());
}
@ -444,7 +444,7 @@ pub extern "C" fn text_editor_insert_text() -> Result<()> {
Err(_) => return Ok(()),
};
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return Ok(());
}
@ -498,7 +498,7 @@ pub extern "C" fn text_editor_insert_text() -> Result<()> {
#[no_mangle]
pub extern "C" fn text_editor_delete_backward(word_boundary: bool) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -522,7 +522,7 @@ pub extern "C" fn text_editor_delete_backward(word_boundary: bool) {
#[no_mangle]
pub extern "C" fn text_editor_delete_forward(word_boundary: bool) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -546,7 +546,7 @@ pub extern "C" fn text_editor_delete_forward(word_boundary: bool) {
#[no_mangle]
pub extern "C" fn text_editor_insert_paragraph() {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -578,7 +578,7 @@ pub extern "C" fn text_editor_move_cursor(
word_boundary: bool,
extend_selection: bool,
) {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
@ -610,7 +610,7 @@ pub extern "C" fn text_editor_move_cursor(
#[no_mangle]
pub extern "C" fn text_editor_get_cursor_rect() -> *mut u8 {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus || !get_text_editor_state().cursor_visible {
return std::ptr::null_mut();
}
@ -644,7 +644,7 @@ pub extern "C" fn text_editor_get_cursor_rect() -> *mut u8 {
#[no_mangle]
pub extern "C" fn text_editor_get_current_styles() -> *mut u8 {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return std::ptr::null_mut();
}
@ -812,7 +812,7 @@ pub extern "C" fn text_editor_get_current_styles() -> *mut u8 {
#[no_mangle]
pub extern "C" fn text_editor_get_selection_rects() -> *mut u8 {
with_state_mut!(state, {
with_state!(state, {
if !get_text_editor_state().has_focus {
return std::ptr::null_mut();
}
@ -858,7 +858,7 @@ pub extern "C" fn text_editor_update_blink(timestamp_ms: f32) {
#[no_mangle]
pub extern "C" fn text_editor_render_overlay() {
with_state_mut!(state, {
with_state!(state, {
let Some(shape_id) = get_text_editor_state().active_shape_id else {
return;
};

View File

@ -7,7 +7,7 @@ use skia_safe as skia;
use crate::mem;
use crate::shapes::{self, TransformEntry, TransformEntrySource};
use crate::utils::uuid_from_u32_quartet;
use crate::{with_state, STATE};
use crate::with_state;
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
#[repr(u8)]