mirror of
https://github.com/penpot/penpot.git
synced 2026-05-10 10:38:17 +00:00
♻️ Refactor GpuState and RenderState
* ♻️ Refactor GpuState * ♻️ Refactor RenderState * 🔧 Tweak some _build_env options
This commit is contained in:
parent
cccd7bc6de
commit
4e98dfb99f
@ -42,6 +42,8 @@ export EMCC_CFLAGS="--no-entry \
|
||||
-sEXPORTED_RUNTIME_METHODS=GL,UTF8ToString,stringToUTF8,HEAPU8,HEAP32,HEAPU32,HEAPF32 \
|
||||
-sENVIRONMENT=web \
|
||||
-sMODULARIZE=1 \
|
||||
-sDISABLE_EXCEPTION_CATCHING=1 \
|
||||
-sFILESYSTEM=0 \
|
||||
-sEXPORT_ES6=1";
|
||||
|
||||
export EM_CACHE="/tmp/emsdk_cache";
|
||||
|
||||
@ -22,6 +22,7 @@ use crate::state::TextEditorState;
|
||||
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;
|
||||
@ -39,6 +40,28 @@ pub fn get_text_editor_state() -> &'static mut TextEditorState {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@ -111,11 +134,30 @@ macro_rules! with_state_mut_current_shape {
|
||||
};
|
||||
}
|
||||
|
||||
/// 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<()> {
|
||||
let state_box = Box::new(State::try_new(width, height)?);
|
||||
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()));
|
||||
}
|
||||
@ -134,12 +176,10 @@ pub extern "C" fn set_browser(browser: u8) -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn clean_up() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
// Cancel the current animation frame if it exists so
|
||||
// it won't try to render without context
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.cancel_animation_frame();
|
||||
});
|
||||
// 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();
|
||||
unsafe { STATE = None }
|
||||
mem::free_bytes()?;
|
||||
Ok(())
|
||||
@ -148,11 +188,9 @@ pub extern "C" fn clean_up() -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_render_options(debug: u32, dpr: f32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.set_debug_flags(debug);
|
||||
render_state.set_dpr(dpr)?;
|
||||
});
|
||||
let render_state = get_render_state();
|
||||
render_state.set_debug_flags(debug);
|
||||
render_state.set_dpr(dpr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -161,61 +199,48 @@ pub extern "C" fn set_render_options(debug: u32, dpr: f32) -> Result<()> {
|
||||
pub extern "C" fn set_viewport_interest_area_threshold(
|
||||
viewport_interest_area_threshold: i32,
|
||||
) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.set_viewport_interest_area_threshold(viewport_interest_area_threshold);
|
||||
});
|
||||
let render_state = get_render_state();
|
||||
render_state.set_viewport_interest_area_threshold(viewport_interest_area_threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_max_blocking_time_ms(max_blocking_time_ms: i32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.set_max_blocking_time_ms(max_blocking_time_ms);
|
||||
});
|
||||
let render_state = get_render_state();
|
||||
render_state.set_max_blocking_time_ms(max_blocking_time_ms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_node_batch_threshold(node_batch_threshold: i32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.set_node_batch_threshold(node_batch_threshold);
|
||||
});
|
||||
let render_state = get_render_state();
|
||||
render_state.set_node_batch_threshold(node_batch_threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_blur_downscale_threshold(blur_downscale_threshold: f32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.set_blur_downscale_threshold(blur_downscale_threshold);
|
||||
});
|
||||
let render_state = get_render_state();
|
||||
render_state.set_blur_downscale_threshold(blur_downscale_threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_antialias_threshold(threshold: f32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.render_state_mut().set_antialias_threshold(threshold);
|
||||
});
|
||||
get_render_state().set_antialias_threshold(threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_max_atlas_texture_size(max_px: i32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state
|
||||
.render_state_mut()
|
||||
.surfaces
|
||||
.set_max_atlas_texture_size(max_px);
|
||||
});
|
||||
get_render_state()
|
||||
.surfaces
|
||||
.set_max_atlas_texture_size(max_px);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -241,7 +266,7 @@ pub extern "C" fn render(timestamp: i32) -> Result<()> {
|
||||
// interactive_transform; we do it once here, with the current
|
||||
// modifier set, so the cost is paid once per rAF rather than
|
||||
// once per pointer move.
|
||||
if state.render_state.options.is_interactive_transform() {
|
||||
if get_render_state().options.is_interactive_transform() {
|
||||
let ids = state.shapes.modifier_ids();
|
||||
if !ids.is_empty() {
|
||||
state.rebuild_modifier_tiles(ids)?;
|
||||
@ -311,9 +336,7 @@ pub extern "C" fn render_from_cache(_: i32) -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_preview_mode(enabled: bool) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.render_state.set_preview_mode(enabled);
|
||||
});
|
||||
get_render_state().set_preview_mode(enabled);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -356,9 +379,7 @@ pub extern "C" fn end_loading() -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn render_loading_overlay() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.render_state.render_loading_overlay();
|
||||
});
|
||||
get_render_state().render_loading_overlay();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -375,30 +396,24 @@ pub extern "C" fn process_animation_frame(timestamp: i32) -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn reset_canvas() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.render_state_mut().reset_canvas();
|
||||
});
|
||||
get_render_state().reset_canvas();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn resize_viewbox(width: i32, height: i32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.resize(width, height)?;
|
||||
});
|
||||
get_render_state().resize(width, height)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
performance::begin_measure!("set_view");
|
||||
let render_state = state.render_state_mut();
|
||||
render_state.set_view(zoom, x, y);
|
||||
performance::end_measure!("set_view");
|
||||
});
|
||||
performance::begin_measure!("set_view");
|
||||
let render_state = get_render_state();
|
||||
render_state.set_view(zoom, x, y);
|
||||
performance::end_measure!("set_view");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -408,15 +423,13 @@ static mut VIEW_INTERACTION_START: i32 = 0;
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_view_start() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
#[cfg(feature = "profile-macros")]
|
||||
unsafe {
|
||||
VIEW_INTERACTION_START = performance::get_time();
|
||||
}
|
||||
performance::begin_measure!("set_view_start");
|
||||
state.render_state.options.set_fast_mode(true);
|
||||
performance::end_measure!("set_view_start");
|
||||
});
|
||||
#[cfg(feature = "profile-macros")]
|
||||
unsafe {
|
||||
VIEW_INTERACTION_START = performance::get_time();
|
||||
}
|
||||
performance::begin_measure!("set_view_start");
|
||||
get_render_state().options.set_fast_mode(true);
|
||||
performance::end_measure!("set_view_start");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -430,32 +443,32 @@ pub extern "C" fn set_view_start() -> Result<()> {
|
||||
pub extern "C" fn set_view_end() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
performance::begin_measure!("set_view_end");
|
||||
state.render_state.options.set_fast_mode(false);
|
||||
state.render_state.cancel_animation_frame();
|
||||
let render_state = get_render_state();
|
||||
render_state.options.set_fast_mode(false);
|
||||
render_state.cancel_animation_frame();
|
||||
|
||||
let scale = state.render_state.get_scale();
|
||||
state
|
||||
.render_state
|
||||
let scale = render_state.get_scale();
|
||||
render_state
|
||||
.tile_viewbox
|
||||
.update(state.render_state.viewbox, scale);
|
||||
.update(render_state.viewbox, scale);
|
||||
|
||||
if state.render_state.options.is_profile_rebuild_tiles() {
|
||||
if render_state.options.is_profile_rebuild_tiles() {
|
||||
state.rebuild_tiles();
|
||||
} else if state.render_state.zoom_changed() {
|
||||
} else if render_state.zoom_changed() {
|
||||
// Zoom changed: tile sizes differ so all cached tile
|
||||
// textures are invalid (wrong scale). Rebuild the tile
|
||||
// index and clear the tile texture cache, but *preserve*
|
||||
// the cache canvas so render_from_cache can show a scaled
|
||||
// preview of the old content while new tiles render.
|
||||
state.render_state.rebuild_tile_index(&state.shapes);
|
||||
state.render_state.surfaces.invalidate_tile_cache();
|
||||
render_state.rebuild_tile_index(&state.shapes);
|
||||
render_state.surfaces.invalidate_tile_cache();
|
||||
} else {
|
||||
// Pure pan at the same zoom level: tile contents have not
|
||||
// changed — only the viewport position moved. Update the
|
||||
// tile index (which tiles are in the interest area) but
|
||||
// keep cached tile textures so the render can blit them
|
||||
// instead of re-drawing every visible tile from scratch.
|
||||
state.render_state.rebuild_tile_index(&state.shapes);
|
||||
render_state.rebuild_tile_index(&state.shapes);
|
||||
}
|
||||
performance::end_measure!("set_view_end");
|
||||
});
|
||||
@ -470,12 +483,11 @@ pub extern "C" fn set_view_end() -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_modifiers_start() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
performance::begin_measure!("set_modifiers_start");
|
||||
state.render_state.options.set_fast_mode(true);
|
||||
state.render_state.options.set_interactive_transform(true);
|
||||
performance::end_measure!("set_modifiers_start");
|
||||
});
|
||||
performance::begin_measure!("set_modifiers_start");
|
||||
let render_state = get_render_state();
|
||||
render_state.options.set_fast_mode(true);
|
||||
render_state.options.set_interactive_transform(true);
|
||||
performance::end_measure!("set_modifiers_start");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -486,13 +498,12 @@ pub extern "C" fn set_modifiers_start() -> Result<()> {
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_modifiers_end() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
performance::begin_measure!("set_modifiers_end");
|
||||
state.render_state.options.set_fast_mode(false);
|
||||
state.render_state.options.set_interactive_transform(false);
|
||||
state.render_state.cancel_animation_frame();
|
||||
performance::end_measure!("set_modifiers_end");
|
||||
});
|
||||
performance::begin_measure!("set_modifiers_end");
|
||||
let render_state = get_render_state();
|
||||
render_state.options.set_fast_mode(false);
|
||||
render_state.options.set_interactive_transform(false);
|
||||
render_state.cancel_animation_frame();
|
||||
performance::end_measure!("set_modifiers_end");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -808,11 +819,9 @@ pub extern "C" fn is_image_cached(
|
||||
d: u32,
|
||||
is_thumbnail: bool,
|
||||
) -> Result<bool> {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let result = state.render_state().has_image(&id, is_thumbnail);
|
||||
Ok(result)
|
||||
})
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let result = get_render_state().has_image(&id, is_thumbnail);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -961,15 +970,14 @@ pub extern "C" fn set_structure_modifiers() -> Result<()> {
|
||||
#[wasm_error]
|
||||
pub extern "C" fn clean_modifiers() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let render_state = get_render_state();
|
||||
let prev_modifier_ids = state.shapes.clean_all();
|
||||
// Skip the tile-cache cleanup during interactive transform: the
|
||||
// per-rAF `rebuild_modifier_tiles` in `render()` already evicts
|
||||
// the same tiles for the active modifier set, so the eviction
|
||||
// here is redundant and doubles the per-emission cost.
|
||||
if !prev_modifier_ids.is_empty() && !state.render_state.options.is_interactive_transform() {
|
||||
state
|
||||
.render_state
|
||||
.update_tiles_shapes(&prev_modifier_ids, &mut state.shapes)?;
|
||||
if !prev_modifier_ids.is_empty() && !render_state.options.is_interactive_transform() {
|
||||
render_state.update_tiles_shapes(&prev_modifier_ids, &mut state.shapes)?;
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
@ -995,7 +1003,7 @@ pub extern "C" fn set_modifiers() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.set_modifiers(modifiers);
|
||||
// TO CHECK
|
||||
if !state.render_state.options.is_interactive_transform() {
|
||||
if !get_render_state().options.is_interactive_transform() {
|
||||
state.rebuild_modifier_tiles(ids)?;
|
||||
}
|
||||
});
|
||||
@ -1061,9 +1069,7 @@ pub extern "C" fn render_shape_pixels(
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn render_stats() {
|
||||
with_state!(state, {
|
||||
state.render_state.print_stats();
|
||||
})
|
||||
get_render_state().print_stats();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
@ -2,7 +2,7 @@ mod debug;
|
||||
mod fills;
|
||||
pub mod filters;
|
||||
mod fonts;
|
||||
mod gpu_state;
|
||||
pub mod gpu_state;
|
||||
pub mod grid_layout;
|
||||
mod images;
|
||||
mod options;
|
||||
@ -17,13 +17,10 @@ use skia_safe::{self as skia, Matrix, RRect, Rect};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use gpu_state::GpuState;
|
||||
|
||||
use options::RenderOptions;
|
||||
pub use surfaces::{SurfaceId, Surfaces};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::performance;
|
||||
use crate::shapes::{
|
||||
all_with_ancestors, radius_to_sigma, Blur, BlurType, Corners, Fill, Shadow, Shape, SolidColor,
|
||||
Stroke, StrokeKind, TextContent, Type,
|
||||
@ -33,6 +30,7 @@ use crate::tiles::{self, PendingTiles, TileRect};
|
||||
use crate::uuid::Uuid;
|
||||
use crate::view::Viewbox;
|
||||
use crate::wapi;
|
||||
use crate::{get_gpu_state, performance};
|
||||
|
||||
pub use fonts::*;
|
||||
pub use images::*;
|
||||
@ -327,7 +325,6 @@ impl RenderStats {
|
||||
}
|
||||
|
||||
pub(crate) struct RenderState {
|
||||
gpu_state: GpuState,
|
||||
pub options: RenderOptions,
|
||||
stats: RenderStats,
|
||||
pub surfaces: Surfaces,
|
||||
@ -492,13 +489,11 @@ impl RenderState {
|
||||
|
||||
pub fn try_new(width: i32, height: i32) -> Result<RenderState> {
|
||||
// This needs to be done once per WebGL context.
|
||||
let mut gpu_state = GpuState::try_new()?;
|
||||
let sampling_options =
|
||||
skia::SamplingOptions::new(skia::FilterMode::Linear, skia::MipmapMode::Nearest);
|
||||
|
||||
let fonts = FontStore::try_new()?;
|
||||
let surfaces = Surfaces::try_new(
|
||||
&mut gpu_state,
|
||||
(width, height),
|
||||
sampling_options,
|
||||
tiles::get_tile_dimensions(),
|
||||
@ -511,15 +506,14 @@ impl RenderState {
|
||||
let tiles = tiles::TileHashMap::new();
|
||||
let options = RenderOptions::default();
|
||||
|
||||
Ok(RenderState {
|
||||
gpu_state: gpu_state.clone(),
|
||||
Ok(Self {
|
||||
options,
|
||||
stats: RenderStats::new(),
|
||||
surfaces,
|
||||
fonts,
|
||||
viewbox,
|
||||
cached_viewbox: Viewbox::new(0., 0.),
|
||||
images: ImageStore::new(gpu_state.context.clone()),
|
||||
images: ImageStore::new(),
|
||||
background_color: skia::Color::TRANSPARENT,
|
||||
render_request_id: None,
|
||||
render_in_progress: false,
|
||||
@ -801,8 +795,7 @@ impl RenderState {
|
||||
pub fn resize(&mut self, width: i32, height: i32) -> Result<()> {
|
||||
let dpr_width = (width as f32 * self.options.dpr).floor() as i32;
|
||||
let dpr_height = (height as f32 * self.options.dpr).floor() as i32;
|
||||
self.surfaces
|
||||
.resize(&mut self.gpu_state, dpr_width, dpr_height)?;
|
||||
self.surfaces.resize(dpr_width, dpr_height)?;
|
||||
self.viewbox.set_wh(width as f32, height as f32);
|
||||
self.tile_viewbox.update(self.viewbox, self.get_scale());
|
||||
|
||||
@ -810,8 +803,7 @@ impl RenderState {
|
||||
}
|
||||
|
||||
pub fn flush_and_submit(&mut self) {
|
||||
self.surfaces
|
||||
.flush_and_submit(&mut self.gpu_state, SurfaceId::Target);
|
||||
self.surfaces.flush_and_submit(SurfaceId::Target);
|
||||
}
|
||||
|
||||
pub fn reset_canvas(&mut self) {
|
||||
@ -890,7 +882,6 @@ impl RenderState {
|
||||
.as_ref()
|
||||
.ok_or(Error::CriticalError("Current tile not found".to_string()))?;
|
||||
self.surfaces.cache_current_tile_texture(
|
||||
&mut self.gpu_state,
|
||||
&self.tile_viewbox,
|
||||
¤t_tile,
|
||||
&tile_rect,
|
||||
@ -2203,13 +2194,12 @@ impl RenderState {
|
||||
// Clear export context so get_scale() returns to workspace zoom.
|
||||
self.export_context = None;
|
||||
|
||||
self.surfaces
|
||||
.flush_and_submit(&mut self.gpu_state, target_surface);
|
||||
self.surfaces.flush_and_submit(target_surface);
|
||||
|
||||
let image = self.surfaces.snapshot(target_surface);
|
||||
let data = image
|
||||
.encode(
|
||||
&mut self.gpu_state.context,
|
||||
Some(&mut get_gpu_state().context),
|
||||
skia::EncodedImageFormat::PNG,
|
||||
100,
|
||||
)
|
||||
@ -3590,8 +3580,7 @@ impl RenderState {
|
||||
}
|
||||
|
||||
pub fn remove_cached_tile(&mut self, tile: tiles::Tile) {
|
||||
self.surfaces
|
||||
.remove_cached_tile_surface(&mut self.gpu_state, tile);
|
||||
self.surfaces.remove_cached_tile_surface(tile);
|
||||
}
|
||||
|
||||
/// Rebuild the tile index (shape→tile mapping) for all top-level shapes.
|
||||
@ -3790,6 +3779,6 @@ impl RenderState {
|
||||
|
||||
impl Drop for RenderState {
|
||||
fn drop(&mut self) {
|
||||
self.gpu_state.context.free_gpu_resources();
|
||||
get_gpu_state().context.free_gpu_resources();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
use super::{tiles, RenderState, SurfaceId};
|
||||
use crate::with_state_mut;
|
||||
use crate::STATE;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use macros::wasm_error;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::get_render_state;
|
||||
|
||||
use skia_safe::{self as skia, Rect};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@ -227,9 +231,7 @@ pub fn console_debug_surface_rect(render_state: &mut RenderState, id: SurfaceId,
|
||||
#[wasm_error]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub extern "C" fn debug_cache_console() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
console_debug_surface(state.render_state_mut(), SurfaceId::Cache);
|
||||
});
|
||||
console_debug_surface(get_render_state(), SurfaceId::Cache);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -237,9 +239,7 @@ pub extern "C" fn debug_cache_console() -> Result<()> {
|
||||
#[wasm_error]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub extern "C" fn debug_cache_base64() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
console_debug_surface_base64(state.render_state_mut(), SurfaceId::Cache);
|
||||
});
|
||||
console_debug_surface_base64(get_render_state(), SurfaceId::Cache);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -247,9 +247,7 @@ pub extern "C" fn debug_cache_base64() -> Result<()> {
|
||||
#[wasm_error]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub extern "C" fn debug_atlas_console() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
console_debug_surface(state.render_state_mut(), SurfaceId::Atlas);
|
||||
});
|
||||
console_debug_surface(get_render_state(), SurfaceId::Atlas);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -257,8 +255,6 @@ pub extern "C" fn debug_atlas_console() -> Result<()> {
|
||||
#[wasm_error]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub extern "C" fn debug_atlas_base64() -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
console_debug_surface_base64(state.render_state_mut(), SurfaceId::Atlas);
|
||||
});
|
||||
console_debug_surface_base64(get_render_state(), SurfaceId::Atlas);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ impl GpuState {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(GpuState {
|
||||
Ok(Self {
|
||||
context,
|
||||
framebuffer_info,
|
||||
})
|
||||
|
||||
@ -3,6 +3,7 @@ use crate::shapes::ImageFill;
|
||||
use crate::uuid::Uuid;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::get_gpu_state;
|
||||
use skia_safe::gpu::{surfaces, Budgeted, DirectContext};
|
||||
use skia_safe::{self as skia, Codec, ISize};
|
||||
use std::collections::HashMap;
|
||||
@ -143,10 +144,12 @@ fn decode_image(context: &mut Box<DirectContext>, raw_data: &[u8]) -> Option<Ima
|
||||
}
|
||||
|
||||
impl ImageStore {
|
||||
pub fn new(context: DirectContext) -> Self {
|
||||
pub fn new() -> Self {
|
||||
let gpu_state = get_gpu_state();
|
||||
let context = &gpu_state.context;
|
||||
Self {
|
||||
images: HashMap::with_capacity(2048),
|
||||
context: Box::new(context),
|
||||
context: Box::new(context.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::error::{Error, Result};
|
||||
use crate::performance;
|
||||
use crate::shapes::Shape;
|
||||
use crate::view::Viewbox;
|
||||
use crate::{get_gpu_state, performance};
|
||||
|
||||
use skia_safe::{self as skia, IRect, Paint, RRect};
|
||||
|
||||
@ -101,11 +101,12 @@ pub struct Surfaces {
|
||||
#[allow(dead_code)]
|
||||
impl Surfaces {
|
||||
pub fn try_new(
|
||||
gpu_state: &mut GpuState,
|
||||
(width, height): (i32, i32),
|
||||
sampling_options: skia::SamplingOptions,
|
||||
tile_dims: skia::ISize,
|
||||
) -> Result<Self> {
|
||||
let gpu_state = get_gpu_state();
|
||||
|
||||
let extra_tile_dims = skia::ISize::new(
|
||||
tile_dims.width * TILE_SIZE_MULTIPLIER,
|
||||
tile_dims.height * TILE_SIZE_MULTIPLIER,
|
||||
@ -140,7 +141,7 @@ impl Surfaces {
|
||||
atlas.canvas().clear(skia::Color::TRANSPARENT);
|
||||
|
||||
let tiles = TileTextureCache::new();
|
||||
Ok(Surfaces {
|
||||
Ok(Self {
|
||||
target,
|
||||
filter,
|
||||
cache,
|
||||
@ -445,12 +446,9 @@ impl Surfaces {
|
||||
self.margins
|
||||
}
|
||||
|
||||
pub fn resize(
|
||||
&mut self,
|
||||
gpu_state: &mut GpuState,
|
||||
new_width: i32,
|
||||
new_height: i32,
|
||||
) -> Result<()> {
|
||||
pub fn resize(&mut self, new_width: i32, new_height: i32) -> Result<()> {
|
||||
let gpu_state = get_gpu_state();
|
||||
|
||||
self.reset_from_target(gpu_state.create_target_surface(new_width, new_height)?)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -547,7 +545,8 @@ impl Surfaces {
|
||||
self.dirty_surfaces = 0;
|
||||
}
|
||||
|
||||
pub fn flush_and_submit(&mut self, gpu_state: &mut GpuState, id: SurfaceId) {
|
||||
pub fn flush_and_submit(&mut self, id: SurfaceId) {
|
||||
let gpu_state = get_gpu_state();
|
||||
let surface = self.get_mut(id);
|
||||
gpu_state.context.flush_and_submit_surface(surface, None);
|
||||
}
|
||||
@ -946,13 +945,13 @@ impl Surfaces {
|
||||
|
||||
pub fn cache_current_tile_texture(
|
||||
&mut self,
|
||||
gpu_state: &mut GpuState,
|
||||
tile_viewbox: &TileViewbox,
|
||||
tile: &Tile,
|
||||
tile_rect: &skia::Rect,
|
||||
skip_cache_surface: bool,
|
||||
tile_doc_rect: skia::Rect,
|
||||
) {
|
||||
let gpu_state = get_gpu_state();
|
||||
let rect = IRect::from_xywh(
|
||||
self.margins.width,
|
||||
self.margins.height,
|
||||
@ -985,7 +984,8 @@ impl Surfaces {
|
||||
self.tiles.has(tile)
|
||||
}
|
||||
|
||||
pub fn remove_cached_tile_surface(&mut self, gpu_state: &mut GpuState, tile: Tile) {
|
||||
pub fn remove_cached_tile_surface(&mut self, tile: Tile) {
|
||||
let gpu_state = get_gpu_state();
|
||||
// Mark tile as invalid
|
||||
// Old content stays visible until new tile overwrites it atomically,
|
||||
// preventing flickering during tile re-renders.
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
use crate::get_render_state;
|
||||
use crate::shapes::text::TextContent;
|
||||
use skia_safe::{
|
||||
self as skia, textlayout::Paragraph as SkiaParagraph, FontMetrics, Point, Rect, TextBlob,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::{with_state_mut, STATE};
|
||||
|
||||
pub struct TextPaths(TextContent);
|
||||
|
||||
// Note: This class is not being currently used.
|
||||
@ -173,20 +172,18 @@ impl TextPaths {
|
||||
blob_offset_x: f32,
|
||||
blob_offset_y: f32,
|
||||
) -> Option<(skia::Path, skia::Rect)> {
|
||||
with_state_mut!(state, {
|
||||
let utf16_text = span_text.encode_utf16().collect::<Vec<u16>>();
|
||||
let text = unsafe { skia_safe::as_utf16_unchecked(&utf16_text) };
|
||||
let emoji_font = state.render_state.fonts().get_emoji_font(font.size());
|
||||
let use_font = emoji_font.as_ref().unwrap_or(font);
|
||||
let utf16_text = span_text.encode_utf16().collect::<Vec<u16>>();
|
||||
let text = unsafe { skia_safe::as_utf16_unchecked(&utf16_text) };
|
||||
let emoji_font = get_render_state().fonts().get_emoji_font(font.size());
|
||||
let use_font = emoji_font.as_ref().unwrap_or(font);
|
||||
|
||||
if let Some(mut text_blob) = TextBlob::from_text(text, use_font) {
|
||||
let path = SkiaParagraph::get_path(&mut text_blob);
|
||||
let d = Point::new(blob_offset_x, blob_offset_y);
|
||||
let offset_path = path.with_offset(d);
|
||||
let bounds = text_blob.bounds();
|
||||
return Some((offset_path, *bounds));
|
||||
}
|
||||
});
|
||||
if let Some(mut text_blob) = TextBlob::from_text(text, use_font) {
|
||||
let path = SkiaParagraph::get_path(&mut text_blob);
|
||||
let d = Point::new(blob_offset_x, blob_offset_y);
|
||||
let offset_path = path.with_offset(d);
|
||||
let bounds = text_blob.bounds();
|
||||
return Some((offset_path, *bounds));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,10 +7,9 @@ pub use shapes_pool::{ShapesPool, ShapesPoolMutRef, ShapesPoolRef};
|
||||
pub use text_editor::*;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::render::RenderState;
|
||||
use crate::shapes::{modifiers::grid_layout::grid_cell_data, Shape};
|
||||
use crate::tiles;
|
||||
use crate::shapes::{grid_layout::grid_cell_data, Shape};
|
||||
use crate::uuid::Uuid;
|
||||
use crate::{get_render_state, tiles};
|
||||
|
||||
/// This struct holds the state of the Rust application between JS calls.
|
||||
///
|
||||
@ -18,7 +17,6 @@ use crate::uuid::Uuid;
|
||||
/// Note that rust-skia data structures are not thread safe, so a state
|
||||
/// must not be shared between different Web Workers.
|
||||
pub(crate) struct State {
|
||||
pub render_state: RenderState,
|
||||
pub current_id: Option<Uuid>,
|
||||
pub current_browser: u8,
|
||||
pub shapes: ShapesPool,
|
||||
@ -28,16 +26,14 @@ pub(crate) struct State {
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn try_new(width: i32, height: i32) -> Result<Self> {
|
||||
Ok(State {
|
||||
render_state: RenderState::try_new(width, height)?,
|
||||
// text_editor_state: TextEditorState::new(),
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
current_id: None,
|
||||
current_browser: 0,
|
||||
shapes: ShapesPool::new(),
|
||||
saved_shapes: None,
|
||||
loading: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new temporary shapes pool.
|
||||
@ -64,30 +60,16 @@ impl State {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, width: i32, height: i32) -> Result<()> {
|
||||
self.render_state.resize(width, height)
|
||||
}
|
||||
|
||||
pub fn render_state_mut(&mut self) -> &mut RenderState {
|
||||
&mut self.render_state
|
||||
}
|
||||
|
||||
pub fn render_state(&self) -> &RenderState {
|
||||
&self.render_state
|
||||
}
|
||||
|
||||
pub fn render_from_cache(&mut self) {
|
||||
self.render_state.render_from_cache(&self.shapes);
|
||||
get_render_state().render_from_cache(&self.shapes);
|
||||
}
|
||||
|
||||
pub fn render_sync(&mut self, timestamp: i32) -> Result<()> {
|
||||
self.render_state
|
||||
.start_render_loop(None, &self.shapes, timestamp, true)
|
||||
get_render_state().start_render_loop(None, &self.shapes, timestamp, true)
|
||||
}
|
||||
|
||||
pub fn render_sync_shape(&mut self, id: &Uuid, timestamp: i32) -> Result<()> {
|
||||
self.render_state
|
||||
.start_render_loop(Some(id), &self.shapes, timestamp, true)
|
||||
get_render_state().start_render_loop(Some(id), &self.shapes, timestamp, true)
|
||||
}
|
||||
|
||||
pub fn render_shape_pixels(
|
||||
@ -96,36 +78,34 @@ impl State {
|
||||
scale: f32,
|
||||
timestamp: i32,
|
||||
) -> Result<(Vec<u8>, i32, i32)> {
|
||||
self.render_state
|
||||
.render_shape_pixels(id, &self.shapes, scale, timestamp)
|
||||
get_render_state().render_shape_pixels(id, &self.shapes, scale, timestamp)
|
||||
}
|
||||
|
||||
pub fn start_render_loop(&mut self, timestamp: i32) -> Result<()> {
|
||||
let render_state = get_render_state();
|
||||
// If zoom changed (e.g. interrupted zoom render followed by pan), the
|
||||
// tile index may be stale for the new viewport position. Rebuild the
|
||||
// index so shapes are mapped to the correct tiles. We use
|
||||
// rebuild_tile_index (NOT rebuild_tiles_shallow) to preserve the tile
|
||||
// texture cache — otherwise cached tiles with shadows/blur would be
|
||||
// cleared and re-rendered in fast mode without effects.
|
||||
if self.render_state.zoom_changed() {
|
||||
self.render_state.rebuild_tile_index(&self.shapes);
|
||||
if render_state.zoom_changed() {
|
||||
render_state.rebuild_tile_index(&self.shapes);
|
||||
}
|
||||
|
||||
self.render_state
|
||||
.start_render_loop(None, &self.shapes, timestamp, false)
|
||||
render_state.start_render_loop(None, &self.shapes, timestamp, false)
|
||||
}
|
||||
|
||||
pub fn process_animation_frame(&mut self, timestamp: i32) -> Result<()> {
|
||||
self.render_state
|
||||
.process_animation_frame(None, &self.shapes, timestamp)
|
||||
get_render_state().process_animation_frame(None, &self.shapes, timestamp)
|
||||
}
|
||||
|
||||
pub fn clear_focus_mode(&mut self) {
|
||||
self.render_state.clear_focus_mode();
|
||||
get_render_state().clear_focus_mode();
|
||||
}
|
||||
|
||||
pub fn set_focus_mode(&mut self, shapes: Vec<Uuid>) {
|
||||
self.render_state.set_focus_mode(shapes);
|
||||
get_render_state().set_focus_mode(shapes);
|
||||
}
|
||||
|
||||
pub fn init_shapes_pool(&mut self, capacity: usize) {
|
||||
@ -140,6 +120,8 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn delete_shape_children(&mut self, parent_id: Uuid, id: Uuid) {
|
||||
let render_state = get_render_state();
|
||||
|
||||
// We don't really do a self.shapes.remove so that redo/undo keep working
|
||||
let Some(shape) = self.shapes.get(&id) else {
|
||||
return;
|
||||
@ -155,16 +137,15 @@ impl State {
|
||||
//
|
||||
// Instead, remove the shape from *all* tiles where it was indexed, and
|
||||
// drop cached tiles for those entries.
|
||||
let indexed_tiles: Vec<tiles::Tile> = self
|
||||
.render_state
|
||||
let indexed_tiles: Vec<tiles::Tile> = render_state
|
||||
.tiles
|
||||
.get_tiles_of(shape.id)
|
||||
.map(|t| t.iter().copied().collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
for tile in indexed_tiles {
|
||||
self.render_state.remove_cached_tile(tile);
|
||||
self.render_state.tiles.remove_shape_at(tile, shape.id);
|
||||
render_state.remove_cached_tile(tile);
|
||||
render_state.tiles.remove_shape_at(tile, shape.id);
|
||||
}
|
||||
|
||||
if let Some(shape_to_delete) = self.shapes.get(&id) {
|
||||
@ -173,8 +154,8 @@ impl State {
|
||||
if let Some(shape_to_delete) = self.shapes.get_mut(&shape_id) {
|
||||
shape_to_delete.set_deleted(true);
|
||||
}
|
||||
if self.render_state.show_grid == Some(shape_id) {
|
||||
self.render_state.show_grid = None;
|
||||
if render_state.show_grid == Some(shape_id) {
|
||||
render_state.show_grid = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,7 +171,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn set_background_color(&mut self, color: skia::Color) {
|
||||
self.render_state.set_background_color(color);
|
||||
get_render_state().set_background_color(color);
|
||||
}
|
||||
|
||||
pub fn set_browser(&mut self, browser: u8) {
|
||||
@ -225,33 +206,32 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn rebuild_tiles_shallow(&mut self) {
|
||||
self.render_state.rebuild_tiles_shallow(&self.shapes);
|
||||
get_render_state().rebuild_tiles_shallow(&self.shapes);
|
||||
}
|
||||
|
||||
pub fn rebuild_tiles(&mut self) {
|
||||
self.render_state.rebuild_tiles_from(&self.shapes, None);
|
||||
get_render_state().rebuild_tiles_from(&self.shapes, None);
|
||||
}
|
||||
|
||||
pub fn rebuild_tiles_from(&mut self, base_id: Option<&Uuid>) {
|
||||
self.render_state.rebuild_tiles_from(&self.shapes, base_id);
|
||||
get_render_state().rebuild_tiles_from(&self.shapes, base_id);
|
||||
}
|
||||
|
||||
pub fn rebuild_touched_tiles(&mut self) {
|
||||
self.render_state.rebuild_touched_tiles(&self.shapes);
|
||||
get_render_state().rebuild_touched_tiles(&self.shapes);
|
||||
}
|
||||
|
||||
pub fn render_preview(&mut self, timestamp: i32) {
|
||||
let _ = self.render_state.render_preview(&self.shapes, timestamp);
|
||||
let _ = get_render_state().render_preview(&self.shapes, timestamp);
|
||||
}
|
||||
|
||||
pub fn rebuild_modifier_tiles(&mut self, ids: Vec<Uuid>) -> Result<()> {
|
||||
// Index-based storage is safe
|
||||
self.render_state
|
||||
.rebuild_modifier_tiles(&mut self.shapes, ids)
|
||||
get_render_state().rebuild_modifier_tiles(&mut self.shapes, ids)
|
||||
}
|
||||
|
||||
pub fn font_collection(&self) -> &FontCollection {
|
||||
self.render_state.fonts().font_collection()
|
||||
get_render_state().fonts().font_collection()
|
||||
}
|
||||
|
||||
pub fn get_grid_coords(&self, pos_x: f32, pos_y: f32) -> Option<(i32, i32)> {
|
||||
@ -284,16 +264,18 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn touch_current(&mut self) {
|
||||
let render_state = get_render_state();
|
||||
if !self.loading {
|
||||
if let Some(current_id) = self.current_id {
|
||||
self.render_state.mark_touched(current_id);
|
||||
render_state.mark_touched(current_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn touch_shape(&mut self, id: Uuid) {
|
||||
let render_state = get_render_state();
|
||||
if !self.loading {
|
||||
self.render_state.mark_touched(id);
|
||||
render_state.mark_touched(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::get_render_state;
|
||||
use crate::skia::textlayout::FontCollection;
|
||||
use crate::skia::Image;
|
||||
use crate::uuid::Uuid;
|
||||
@ -25,12 +26,12 @@ pub fn uuid_from_u32(id: [u32; 4]) -> Uuid {
|
||||
}
|
||||
|
||||
pub fn get_image(image_id: &Uuid) -> Option<&Image> {
|
||||
with_state_mut!(state, { state.render_state_mut().images.get(image_id) })
|
||||
get_render_state().images.get(image_id)
|
||||
}
|
||||
|
||||
// FIXME: move to a different place ?
|
||||
pub fn get_fallback_fonts() -> &'static HashSet<String> {
|
||||
with_state_mut!(state, { state.render_state().fonts().get_fallback() })
|
||||
get_render_state().fonts().get_fallback()
|
||||
}
|
||||
|
||||
pub fn get_font_collection() -> &'static FontCollection {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::error::{Error, Result};
|
||||
use crate::get_render_state;
|
||||
use crate::mem;
|
||||
use crate::shapes::Fill;
|
||||
use crate::state::State;
|
||||
@ -106,11 +107,7 @@ pub extern "C" fn store_image() -> Result<()> {
|
||||
let image_bytes = &bytes[IMAGE_HEADER_SIZE..];
|
||||
|
||||
with_state_mut!(state, {
|
||||
if let Err(msg) =
|
||||
state
|
||||
.render_state_mut()
|
||||
.add_image(ids.image_id, is_thumbnail, image_bytes)
|
||||
{
|
||||
if let Err(msg) = get_render_state().add_image(ids.image_id, is_thumbnail, image_bytes) {
|
||||
eprintln!("{}", msg);
|
||||
}
|
||||
touch_shapes_with_image(state, ids.image_id);
|
||||
@ -180,7 +177,7 @@ pub extern "C" fn store_image_from_texture() -> Result<()> {
|
||||
);
|
||||
|
||||
with_state_mut!(state, {
|
||||
if let Err(msg) = state.render_state_mut().add_image_from_gl_texture(
|
||||
if let Err(msg) = get_render_state().add_image_from_gl_texture(
|
||||
ids.image_id,
|
||||
is_thumbnail,
|
||||
texture_id,
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
use macros::{wasm_error, ToJs};
|
||||
|
||||
use crate::get_render_state;
|
||||
use crate::mem;
|
||||
use crate::shapes::{FontFamily, FontStyle};
|
||||
use crate::utils::uuid_from_u32_quartet;
|
||||
use crate::with_state_mut;
|
||||
use crate::STATE;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
@ -41,20 +40,16 @@ pub extern "C" fn store_font(
|
||||
is_emoji: bool,
|
||||
is_fallback: bool,
|
||||
) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let font_bytes = mem::bytes();
|
||||
let font_style = RawFontStyle::from(style);
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let font_bytes = mem::bytes();
|
||||
let font_style = RawFontStyle::from(style);
|
||||
|
||||
let family = FontFamily::new(id, weight, font_style.into());
|
||||
let _ =
|
||||
state
|
||||
.render_state_mut()
|
||||
.fonts_mut()
|
||||
.add(family, &font_bytes, is_emoji, is_fallback);
|
||||
let family = FontFamily::new(id, weight, font_style.into());
|
||||
let _ = get_render_state()
|
||||
.fonts_mut()
|
||||
.add(family, &font_bytes, is_emoji, is_fallback);
|
||||
|
||||
mem::free_bytes()?;
|
||||
});
|
||||
mem::free_bytes()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -68,12 +63,10 @@ pub extern "C" fn is_font_uploaded(
|
||||
style: u8,
|
||||
is_emoji: bool,
|
||||
) -> bool {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let font_style = RawFontStyle::from(style);
|
||||
let family = FontFamily::new(id, weight, font_style.into());
|
||||
let res = state.render_state().fonts().has_family(&family, is_emoji);
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let font_style = RawFontStyle::from(style);
|
||||
let family = FontFamily::new(id, weight, font_style.into());
|
||||
let res = get_render_state().fonts().has_family(&family, is_emoji);
|
||||
|
||||
res
|
||||
})
|
||||
res
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use macros::{wasm_error, ToJs};
|
||||
|
||||
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, with_state_mut, STATE};
|
||||
use crate::{uuid_from_u32_quartet, with_current_shape_mut, with_state, STATE};
|
||||
|
||||
use super::align;
|
||||
|
||||
@ -241,17 +242,13 @@ pub extern "C" fn set_grid_cells() -> Result<()> {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
state.render_state.show_grid = Some(id);
|
||||
});
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
get_render_state().show_grid = Some(id);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn hide_grid() {
|
||||
with_state_mut!(state, {
|
||||
state.render_state.show_grid = None;
|
||||
});
|
||||
get_render_state().show_grid = None;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@ -2,7 +2,6 @@ use macros::{wasm_error, ToJs};
|
||||
|
||||
use crate::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};
|
||||
@ -13,6 +12,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 skia_safe::Color;
|
||||
|
||||
@ -287,7 +287,7 @@ pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) {
|
||||
return;
|
||||
}
|
||||
|
||||
let view_matrix: Matrix = state.render_state.viewbox.get_matrix();
|
||||
let view_matrix: Matrix = get_render_state().viewbox.get_matrix();
|
||||
let point = Point::new(x, y);
|
||||
let Some(shape_id) = get_text_editor_state().active_shape_id else {
|
||||
return;
|
||||
@ -368,7 +368,7 @@ pub extern "C" fn text_editor_composition_end() -> Result<()> {
|
||||
get_text_editor_state().push_event(crate::state::TextEditorEvent::ContentChanged);
|
||||
get_text_editor_state().push_event(crate::state::TextEditorEvent::NeedsLayout);
|
||||
|
||||
state.render_state.mark_touched(shape_id);
|
||||
get_render_state().mark_touched(shape_id);
|
||||
|
||||
get_text_editor_state().composition.end();
|
||||
});
|
||||
@ -420,7 +420,7 @@ pub extern "C" fn text_editor_composition_update() -> Result<()> {
|
||||
get_text_editor_state().push_event(crate::state::TextEditorEvent::ContentChanged);
|
||||
get_text_editor_state().push_event(crate::state::TextEditorEvent::NeedsLayout);
|
||||
|
||||
state.render_state.mark_touched(shape_id);
|
||||
get_render_state().mark_touched(shape_id);
|
||||
});
|
||||
|
||||
crate::mem::free_bytes()?;
|
||||
@ -489,7 +489,7 @@ pub extern "C" fn text_editor_insert_text() -> Result<()> {
|
||||
get_text_editor_state().push_event(TextEditorEvent::ContentChanged);
|
||||
get_text_editor_state().push_event(TextEditorEvent::NeedsLayout);
|
||||
|
||||
state.render_state.mark_touched(shape_id);
|
||||
get_render_state().mark_touched(shape_id);
|
||||
});
|
||||
|
||||
crate::mem::free_bytes()?;
|
||||
@ -516,7 +516,7 @@ pub extern "C" fn text_editor_delete_backward(word_boundary: bool) {
|
||||
};
|
||||
|
||||
get_text_editor_state().delete_backward(text_content, word_boundary);
|
||||
state.render_state.mark_touched(shape_id);
|
||||
get_render_state().mark_touched(shape_id);
|
||||
});
|
||||
}
|
||||
|
||||
@ -540,7 +540,7 @@ pub extern "C" fn text_editor_delete_forward(word_boundary: bool) {
|
||||
};
|
||||
|
||||
get_text_editor_state().delete_forward(text_content, word_boundary);
|
||||
state.render_state.mark_touched(shape_id);
|
||||
get_render_state().mark_touched(shape_id);
|
||||
});
|
||||
}
|
||||
|
||||
@ -564,7 +564,7 @@ pub extern "C" fn text_editor_insert_paragraph() {
|
||||
};
|
||||
|
||||
get_text_editor_state().insert_paragraph(text_content);
|
||||
state.render_state.mark_touched(shape_id);
|
||||
get_render_state().mark_touched(shape_id);
|
||||
});
|
||||
}
|
||||
|
||||
@ -880,16 +880,16 @@ pub extern "C" fn text_editor_render_overlay() {
|
||||
return;
|
||||
};
|
||||
|
||||
let canvas = state.render_state.surfaces.canvas(SurfaceId::Target);
|
||||
let viewbox = state.render_state.viewbox;
|
||||
let canvas = get_render_state().surfaces.canvas(SurfaceId::Target);
|
||||
let viewbox = get_render_state().viewbox;
|
||||
text_editor_render::render_overlay(
|
||||
canvas,
|
||||
&viewbox,
|
||||
&state.render_state.options,
|
||||
&get_render_state().options,
|
||||
get_text_editor_state(),
|
||||
shape,
|
||||
);
|
||||
state.render_state.flush_and_submit();
|
||||
get_render_state().flush_and_submit();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user