mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-07 15:55:00 +00:00
WIP Extract gtext
This commit is contained in:
parent
9f9a50e79a
commit
e5c6a645de
11 changed files with 77 additions and 40 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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 {
|
||||
|
|
28
node-graph/gtext/Cargo.toml
Normal file
28
node-graph/gtext/Cargo.toml
Normal 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"] }
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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::*;
|
|
@ -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>(
|
|
@ -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};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue