Skip to content

Commit 7254350

Browse files
Migrate fonts to be stored as resources (#4165)
* Good start * Impl * allow responses.add(async { Message::NoOp }); * Fix * Cache font blob in text node * Refactor font handling to use Font struct direcly * Fix fmt * Embedd Font Resources by default * Review * Review * Cache font info based on ResourceHash
1 parent 5a4e0bf commit 7254350

46 files changed

Lines changed: 838 additions & 703 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

editor/src/dispatcher.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
6565
))),
6666
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::SubmitActiveGraphRender),
6767
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::SubmitEyedropperPreviewRender),
68-
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontDataLoad),
6968
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateUIScale),
7069
];
7170
/// Since we don't need to update the frontend multiple times per frame,
@@ -80,6 +79,8 @@ const FRONTEND_UPDATE_MESSAGES: &[MessageDiscriminant] = &[
8079
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::RenderScrollbars)),
8180
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure),
8281
];
82+
// FrontendMessages that should be sent immediately
83+
const IMMEDIATE_FRONTEND_MESSAGES: &[FrontendMessageDiscriminant] = &[FrontendMessageDiscriminant::TriggerResolveResource, FrontendMessageDiscriminant::TriggerFontCatalogLoad];
8384
const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[
8485
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(EventMessageDiscriminant::AnimationFrame)),
8586
MessageDiscriminant::Animation(AnimationMessageDiscriminant::IncrementFrameCounter),
@@ -205,16 +206,13 @@ impl Dispatcher {
205206
self.message_handlers.dialog_message_handler.process_message(message, &mut queue, context);
206207
}
207208
Message::Frontend(message) => {
208-
// Handle these messages immediately by returning early
209-
if let FrontendMessage::TriggerFontDataLoad { .. } | FrontendMessage::TriggerFontCatalogLoad = message {
210-
self.responses.push(message);
211-
self.cleanup_queues(false);
209+
let decreminant = message.to_discriminant();
210+
self.responses.push(message);
212211

213-
// Return early to avoid running the code after the match block
212+
// Handle these message immediately by returning early
213+
if IMMEDIATE_FRONTEND_MESSAGES.contains(&decreminant) {
214+
self.cleanup_queues(false);
214215
return;
215-
} else {
216-
// `FrontendMessage`s are saved and will be sent to the frontend after the message queue is done being processed
217-
self.responses.push(message);
218216
}
219217
}
220218
Message::InputPreprocessor(message) => {
@@ -325,7 +323,7 @@ impl Dispatcher {
325323
document_id,
326324
document,
327325
input: &self.message_handlers.input_preprocessor_message_handler,
328-
cached_data: &self.message_handlers.portfolio_message_handler.cached_data,
326+
fonts: &self.message_handlers.portfolio_message_handler.fonts,
329327
node_graph: &self.message_handlers.portfolio_message_handler.executor,
330328
preferences: &self.message_handlers.preferences_message_handler,
331329
viewport: &self.message_handlers.viewport_message_handler,

editor/src/messages/frontend/frontend_message.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use crate::messages::portfolio::document::utility_types::wires::{WirePath, WireP
1212
use crate::messages::portfolio::utility_types::WorkspacePanelLayout;
1313
use crate::messages::prelude::*;
1414
use crate::messages::tool::tool_messages::eyedropper_tool::PrimarySecondary;
15+
use graph_craft::application_io::resource::ResourceId;
1516
use graph_craft::document::NodeId;
1617
use graphene_std::color::SRGBA8;
1718
use graphene_std::raster::Image;
18-
use graphene_std::text::Font;
1919
use graphene_std::vector::style::FillChoiceUI;
2020
use std::path::PathBuf;
2121

@@ -112,8 +112,11 @@ pub enum FrontendMessage {
112112
filename: String,
113113
},
114114
TriggerFontCatalogLoad,
115-
TriggerFontDataLoad {
116-
font: Font,
115+
TriggerResolveResource {
116+
#[serde(rename = "documentId")]
117+
document_id: DocumentId,
118+
#[serde(rename = "resourceId")]
119+
resource_id: ResourceId,
117120
url: String,
118121
},
119122
TriggerPersistenceReadState,

editor/src/messages/future/future_message_handler.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@ impl IntoFuture for MessageFuture {
4343
}
4444
}
4545

46+
impl From<MessageFuture> for Message {
47+
fn from(future: MessageFuture) -> Self {
48+
FutureMessage::Await { future }.into()
49+
}
50+
}
51+
52+
impl<T> From<T> for Message
53+
where
54+
T: Future<Output = Message> + Send + 'static,
55+
{
56+
fn from(future: T) -> Self {
57+
MessageFuture::new(future).into()
58+
}
59+
}
60+
4661
/// Platform-specific async-task executor.
4762
/// Runs `future`, sends the resolved message on `results`, then calls `wake`.
4863
pub trait MessageSpawner: Send + Sync {

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::messages::portfolio::document::properties_panel::properties_panel_mes
2121
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
2222
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, PTZ};
2323
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate, OutputConnector};
24-
use crate::messages::portfolio::utility_types::{CachedData, PanelType};
24+
use crate::messages::portfolio::utility_types::PanelType;
2525
use crate::messages::prelude::*;
2626
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_fill, get_opacity};
2727
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
@@ -52,7 +52,6 @@ use std::time::Duration;
5252
pub struct DocumentMessageContext<'a> {
5353
pub document_id: DocumentId,
5454
pub ipp: &'a InputPreprocessorMessageHandler,
55-
pub cached_data: &'a CachedData,
5655
pub executor: &'a mut NodeGraphExecutor,
5756
pub current_tool: &'a ToolType,
5857
pub preferences: &'a PreferencesMessageHandler,
@@ -61,6 +60,7 @@ pub struct DocumentMessageContext<'a> {
6160
pub properties_panel_open: bool,
6261
pub viewport: &'a ViewportMessageHandler,
6362
pub resource_storage: &'a ResourceStorageMessageHandler,
63+
pub fonts: &'a FontsMessageHandler,
6464
}
6565

6666
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ExtractField)]
@@ -198,7 +198,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
198198
let DocumentMessageContext {
199199
document_id,
200200
ipp,
201-
cached_data,
202201
executor,
203202
viewport,
204203
current_tool,
@@ -207,6 +206,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
207206
layers_panel_open,
208207
properties_panel_open,
209208
resource_storage,
209+
fonts,
210210
} = context;
211211

212212
match message {
@@ -233,11 +233,12 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
233233
}
234234
DocumentMessage::PropertiesPanel(message) => {
235235
let context = PropertiesPanelMessageContext {
236+
executor,
236237
network_interface: &mut self.network_interface,
238+
resources: &self.resources,
237239
selection_network_path: &self.selection_network_path,
238240
document_name: self.name.as_str(),
239-
executor,
240-
cached_data,
241+
fonts,
241242
properties_panel_open,
242243
};
243244
self.properties_panel_message_handler.process_message(message, responses, context);
@@ -282,7 +283,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
282283
graph_operation_message_handler.process_message(message, responses, context);
283284
}
284285
DocumentMessage::Resource(message) => {
285-
let context = ResourceMessageContext {};
286+
let context = ResourceMessageContext { document_id, fonts };
286287
self.resources.process_message(message, responses, context);
287288
}
288289
DocumentMessage::AlignSelectedLayers { axis, aggregate } => {
@@ -933,21 +934,19 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
933934
let mut document = self.clone();
934935
let resources_load_handle = resource_storage.resources();
935936

936-
responses.add(FutureMessage::Await {
937-
future: MessageFuture::new(async move {
938-
document.resources.garbage_collect(document.used_resources(false).as_ref());
939-
document.resources.embed_resources(resources_load_handle).await;
937+
responses.add(async move {
938+
document.resources.collect_garbage(document.used_resources(false).as_ref());
939+
document.resources.embed_resources(resources_load_handle).await;
940940

941-
let content = document.serialize_document().into_bytes().into();
941+
let content = document.serialize_document().into_bytes().into();
942942

943-
Message::Frontend(FrontendMessage::TriggerSaveDocument {
944-
document_id,
945-
name,
946-
path,
947-
folder,
948-
content,
949-
})
950-
}),
943+
Message::Frontend(FrontendMessage::TriggerSaveDocument {
944+
document_id,
945+
name,
946+
path,
947+
folder,
948+
content,
949+
})
951950
});
952951
}
953952
DocumentMessage::SavedDocument { path } => {
@@ -2658,23 +2657,6 @@ impl DocumentMessageHandler {
26582657
}
26592658
}
26602659

2661-
/// Loads all of the fonts in the document.
2662-
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>) {
2663-
let mut fonts_to_load = HashSet::new();
2664-
2665-
for (_, node, _) in self.document_network().recursive_nodes() {
2666-
for input in &node.inputs {
2667-
if let Some(TaggedValue::Font(font)) = input.as_value() {
2668-
fonts_to_load.insert(font.clone());
2669-
}
2670-
}
2671-
}
2672-
2673-
for font in fonts_to_load {
2674-
responses.add(PortfolioMessage::LoadFontData { font });
2675-
}
2676-
}
2677-
26782660
pub fn update_document_widgets(&self, responses: &mut VecDeque<Message>, animation_is_playing: bool, time: Duration) {
26792661
let mut snapping_state = self.snapping_state.clone();
26802662
let mut snapping_state2 = self.snapping_state.clone();
@@ -3470,7 +3452,7 @@ impl DocumentMessageHandler {
34703452

34713453
pub fn garbage_collect_resources(&mut self) {
34723454
let used_resources = self.used_resources(true);
3473-
self.resources.garbage_collect(&used_resources);
3455+
self.resources.collect_garbage(&used_resources);
34743456
}
34753457

34763458
pub fn used_resources(&self, include_history: bool) -> Box<[ResourceId]> {

editor/src/messages/portfolio/document/graph_operation/utility_types.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,13 @@ impl<'a> ModifyInputsContext<'a> {
249249
}
250250

251251
pub fn insert_text(&mut self, text: String, font: Font, typesetting: TypesettingConfig, layer: LayerNodeIdentifier) {
252+
let font_resource_id = ResourceId::new();
252253
let text = resolve_proto_node_type(graphene_std::text::text::IDENTIFIER)
253254
.expect("Text node does not exist")
254255
.node_template_input_override([
255-
Some(NodeInput::scope("editor-api")),
256+
Some(NodeInput::value(TaggedValue::None, false)),
256257
Some(NodeInput::value(TaggedValue::String(text), false)),
257-
Some(NodeInput::value(TaggedValue::Font(font), false)),
258+
Some(NodeInput::value(TaggedValue::Resource(font_resource_id), false)),
258259
Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)),
259260
Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)),
260261
Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)),
@@ -264,6 +265,7 @@ impl<'a> ModifyInputsContext<'a> {
264265
Some(NodeInput::value(TaggedValue::F64(typesetting.max_height.unwrap_or(100.)), false)),
265266
Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)),
266267
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
268+
Some(NodeInput::value(TaggedValue::Bool(false), false)),
267269
]);
268270
let transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)
269271
.expect("Transform node does not exist")
@@ -276,6 +278,8 @@ impl<'a> ModifyInputsContext<'a> {
276278
self.network_interface.insert_node(text_id, text, &[]);
277279
self.network_interface.move_node_to_chain_start(&text_id, layer, &[], self.import);
278280

281+
self.responses.add(DocumentMessage::Resource(ResourceMessage::AddFont { resource_id: font_resource_id, font }));
282+
279283
let transform_id = NodeId::new();
280284
self.network_interface.insert_node(transform_id, transform, &[]);
281285
self.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::{
88
DocumentNodeMetadata, DocumentNodePersistentMetadata, InputMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate, NodeTypePersistentMetadata,
99
Vec2InputSettings, WidgetOverride,
1010
};
11-
use crate::messages::portfolio::utility_types::CachedData;
12-
use crate::messages::prelude::Message;
11+
use crate::messages::prelude::{FontsMessageHandler, Message, ResourceMessageHandler};
1312
use crate::node_graph_executor::NodeGraphExecutor;
1413
use glam::DVec2;
1514
use graph_craft::ProtoNodeIdentifier;
@@ -28,10 +27,11 @@ use serde_json::Value;
2827
use std::collections::{HashMap, VecDeque};
2928

3029
pub struct NodePropertiesContext<'a> {
31-
pub cached_data: &'a CachedData,
3230
pub responses: &'a mut VecDeque<Message>,
3331
pub executor: &'a mut NodeGraphExecutor,
3432
pub network_interface: &'a mut NodeNetworkInterface,
33+
pub resources: &'a ResourceMessageHandler,
34+
pub fonts: &'a FontsMessageHandler,
3535
pub selection_network_path: &'a [NodeId],
3636
pub document_name: &'a str,
3737
}

0 commit comments

Comments
 (0)