mirror of
https://github.com/penpot/penpot.git
synced 2026-05-14 20:43:55 +00:00
Merge pull request #9389 from penpot/azazeln28-refactor-state
♻️ Refactor State into DesignState
This commit is contained in:
commit
086ed83847
138
render-wasm/src/globals.rs
Normal file
138
render-wasm/src/globals.rs
Normal 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(())
|
||||
}
|
||||
@ -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())?;
|
||||
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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>();
|
||||
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user