WIP Extract gtext

This commit is contained in:
Firestar99 2025-06-30 18:50:57 +02:00
parent 9f9a50e79a
commit e5c6a645de
11 changed files with 77 additions and 40 deletions

17
Cargo.lock generated
View file

@ -2313,6 +2313,7 @@ dependencies = [
"graphene-path-bool",
"graphene-raster-nodes",
"graphene-svg-renderer",
"graphene-text",
"image",
"log",
"ndarray",
@ -2344,6 +2345,22 @@ dependencies = [
"vello",
]
[[package]]
name = "graphene-text"
version = "0.1.0"
dependencies = [
"bezier-rs",
"dyn-any",
"glam",
"graphene-application-io",
"graphene-core",
"kurbo",
"node-macro",
"rustybuzz 0.20.1",
"serde",
"specta",
]
[[package]]
name = "graphite-desktop"
version = "0.1.0"

View file

@ -15,6 +15,7 @@ members = [
"node-graph/graphene-cli",
"node-graph/graster-nodes",
"node-graph/gsvg-renderer",
"node-graph/gtext",
"node-graph/interpreted-executor",
"node-graph/node-macro",
"node-graph/preprocessor",
@ -37,6 +38,7 @@ default-members = [
"node-graph/graphene-cli",
"node-graph/graster-nodes",
"node-graph/gsvg-renderer",
"node-graph/gtext",
"node-graph/interpreted-executor",
"node-graph/node-macro",
]
@ -59,6 +61,7 @@ graph-craft = { path = "node-graph/graph-craft" }
graphene-raster-nodes = { path = "node-graph/graster-nodes" }
graphene-std = { path = "node-graph/gstd" }
graphene-svg-renderer = { path = "node-graph/gsvg-renderer" }
graphene-text = { path = "node-graph/gtext" }
interpreted-executor = { path = "node-graph/interpreted-executor" }
node-macro = { path = "node-graph/node-macro" }
wgpu-executor = { path = "node-graph/wgpu-executor" }

View file

@ -1,14 +1,14 @@
use dyn_any::{DynAny, StaticType, StaticTypeSized};
use glam::{DAffine2, UVec2};
use graphene_core::text::FontCache;
use graphene_core::transform::Footprint;
use graphene_core::vector::style::ViewMode;
use std::any::Any;
use std::fmt::Debug;
use std::future::Future;
use std::hash::{Hash, Hasher};
use std::pin::Pin;
use std::ptr::addr_of;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
@ -254,7 +254,7 @@ impl GetEditorPreferences for DummyPreferences {
pub struct EditorApi<Io> {
/// Font data (for rendering text) made available to the graph through the [`WasmEditorApi`].
pub font_cache: FontCache,
pub font_cache: Mutex<Option<Box<dyn Any>>>,
/// Gives access to APIs like a rendering surface (native window handle or HTML5 canvas) and WGPU (which becomes WebGPU on web).
pub application_io: Option<Arc<Io>>,
pub node_graph_message_sender: Box<dyn NodeGraphUpdateSender + Send + Sync>,
@ -262,12 +262,10 @@ pub struct EditorApi<Io> {
pub editor_preferences: Box<dyn GetEditorPreferences + Send + Sync>,
}
impl<Io> Eq for EditorApi<Io> {}
impl<Io: Default> Default for EditorApi<Io> {
fn default() -> Self {
Self {
font_cache: FontCache::default(),
font_cache: Mutex::new(None),
application_io: None,
node_graph_message_sender: Box::new(Logger),
editor_preferences: Box::new(DummyPreferences),
@ -275,30 +273,6 @@ impl<Io: Default> Default for EditorApi<Io> {
}
}
impl<Io> Hash for EditorApi<Io> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.font_cache.hash(state);
self.application_io.as_ref().map_or(0, |io| io.as_ref() as *const _ as usize).hash(state);
(self.node_graph_message_sender.as_ref() as *const dyn NodeGraphUpdateSender).hash(state);
(self.editor_preferences.as_ref() as *const dyn GetEditorPreferences).hash(state);
}
}
impl<Io> PartialEq for EditorApi<Io> {
fn eq(&self, other: &Self) -> bool {
self.font_cache == other.font_cache
&& self.application_io.as_ref().map_or(0, |io| addr_of!(io) as usize) == other.application_io.as_ref().map_or(0, |io| addr_of!(io) as usize)
&& std::ptr::eq(self.node_graph_message_sender.as_ref() as *const _, other.node_graph_message_sender.as_ref() as *const _)
&& std::ptr::eq(self.editor_preferences.as_ref() as *const _, other.editor_preferences.as_ref() as *const _)
}
}
impl<T> Debug for EditorApi<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EditorApi").field("font_cache", &self.font_cache).finish()
}
}
unsafe impl<T: StaticTypeSized> StaticType for EditorApi<T> {
type Static = EditorApi<T::Static>;
}

View file

@ -20,7 +20,6 @@ pub mod raster;
pub mod raster_types;
pub mod registry;
pub mod structural;
pub mod text;
pub mod transform;
pub mod uuid;
pub mod value;

View file

@ -35,6 +35,7 @@ graphene-application-io = { workspace = true }
graphene-element-nodes = { workspace = true }
graphene-raster-nodes = { workspace = true }
graphene-brush = { workspace = true }
graphene-text = { workspace = true }
# Workspace dependencies
fastnoise-lite = { workspace = true }

View file

@ -1,6 +1,5 @@
pub mod any;
pub mod http;
pub mod text;
#[cfg(feature = "wasm")]
pub mod wasm_application_io;
@ -13,6 +12,7 @@ pub use graphene_element_nodes::animation;
pub use graphene_math_nodes as math_nodes;
pub use graphene_path_bool as path_bool;
pub use graphene_raster_nodes as raster_nodes;
pub use graphene_text as text;
/// stop gap solutions until all paths have been replaced with their absolute ones
pub mod renderer {

View file

@ -0,0 +1,28 @@
[package]
name = "graphene-text"
version = "0.1.0"
edition = "2024"
description = "graphene text nodes"
authors = ["Graphite Authors <contact@graphite.rs>"]
license = "MIT OR Apache-2.0"
[features]
default = ["serde"]
serde = ["dep:serde"]
[dependencies]
# Local dependencies
dyn-any = { workspace = true }
bezier-rs = { workspace = true }
graphene-core = { workspace = true }
graphene-application-io = { workspace = true }
node-macro = { workspace = true }
# Workspace dependencies
kurbo = { workspace = true }
glam = { workspace = true }
specta = { workspace = true }
rustybuzz = { workspace = true }
# Optional workspace dependencies
serde = { workspace = true, optional = true, features = ["derive"] }

View file

@ -1,4 +1,6 @@
use dyn_any::DynAny;
use graphene_application_io::EditorApi;
use graphene_core::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
use std::collections::HashMap;
/// A font type (storing font family and font style and an optional preview URL)
@ -16,7 +18,7 @@ impl Font {
}
impl Default for Font {
fn default() -> Self {
Self::new(crate::consts::DEFAULT_FONT_FAMILY.into(), crate::consts::DEFAULT_FONT_STYLE.into())
Self::new(DEFAULT_FONT_FAMILY.into(), DEFAULT_FONT_STYLE.into())
}
}
/// A cache of all loaded font data and preview urls along with the default font (send from `init_app` in `editor_api.rs`)
@ -33,9 +35,7 @@ impl FontCache {
if self.font_file_data.contains_key(font) {
Some(font)
} else {
self.font_file_data
.keys()
.find(|font| font.font_family == crate::consts::DEFAULT_FONT_FAMILY && font.font_style == crate::consts::DEFAULT_FONT_STYLE)
self.font_file_data.keys().find(|font| font.font_family == DEFAULT_FONT_FAMILY && font.font_style == DEFAULT_FONT_STYLE)
}
}
@ -78,3 +78,17 @@ fn migrate_font_style<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Resu
use serde::Deserialize;
String::deserialize(deserializer).map(|name| if name == "Normal (400)" { "Regular (400)".to_string() } else { name })
}
pub trait EditorApiFontCacheExt {
fn get_font_cache(&self) -> &FontCache;
}
impl<Io> EditorApiFontCacheExt for EditorApi<Io> {
fn get_font_cache(&self) -> &FontCache {
let mut guard = self.font_cache.lock().unwrap();
if *guard == None {
*guard = Some(Box::new(FontCache::default()));
}
*guard.as_ref().unwrap().downcast_ref().unwrap();
}
}

View file

@ -1,5 +1,7 @@
mod font_cache;
mod text_node;
mod to_path;
pub use font_cache::*;
pub use text_node::*;
pub use to_path::*;

View file

@ -1,7 +1,6 @@
use crate::vector::{VectorData, VectorDataTable};
use graph_craft::wasm_application_io::WasmEditorApi;
use crate::{Font, TypesettingConfig, load_face, to_path};
use graphene_core::Ctx;
pub use graphene_core::text::*;
use graphene_core::vector::{VectorData, VectorDataTable};
#[node_macro::node(category(""))]
fn text<'i: 'n>(

View file

@ -1,6 +1,6 @@
use crate::vector::PointId;
use bezier_rs::{ManipulatorGroup, Subpath};
use glam::DVec2;
use graphene_core::vector::PointId;
use rustybuzz::ttf_parser::{GlyphId, OutlineBuilder};
use rustybuzz::{GlyphBuffer, UnicodeBuffer};