Skip to content

Commit 2b75bfb

Browse files
committed
Move font picking to the backend
1 parent 2376e76 commit 2b75bfb

File tree

29 files changed

+792
-374
lines changed

29 files changed

+792
-374
lines changed

editor/src/dispatcher.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
5151
NodeGraphMessageDiscriminant::RunDocumentGraph,
5252
))),
5353
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::SubmitActiveGraphRender),
54-
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
54+
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontDataLoad),
5555
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateUIScale),
5656
];
5757
/// Since we don't need to update the frontend multiple times per frame,
@@ -69,6 +69,7 @@ const FRONTEND_UPDATE_MESSAGES: &[MessageDiscriminant] = &[
6969
const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[
7070
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(EventMessageDiscriminant::AnimationFrame)),
7171
MessageDiscriminant::Animation(AnimationMessageDiscriminant::IncrementFrameCounter),
72+
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::AutoSaveAllDocuments),
7273
];
7374
// TODO: Find a way to combine these with the list above. We use strings for now since these are the standard variant names used by multiple messages. But having these also type-checked would be best.
7475
const DEBUG_MESSAGE_ENDING_BLOCK_LIST: &[&str] = &["PointerMove", "PointerOutsideViewport", "Overlays", "Draw", "CurrentTime", "Time"];
@@ -179,7 +180,7 @@ impl Dispatcher {
179180
}
180181
Message::Frontend(message) => {
181182
// Handle these messages immediately by returning early
182-
if let FrontendMessage::TriggerFontLoad { .. } = message {
183+
if let FrontendMessage::TriggerFontDataLoad { .. } | FrontendMessage::TriggerFontCatalogLoad = message {
183184
self.responses.push(message);
184185
self.cleanup_queues(false);
185186

@@ -359,8 +360,9 @@ impl Dispatcher {
359360
fn log_message(&self, message: &Message, queues: &[VecDeque<Message>], message_logging_verbosity: MessageLoggingVerbosity) {
360361
let discriminant = MessageDiscriminant::from(message);
361362
let is_blocked = DEBUG_MESSAGE_BLOCK_LIST.contains(&discriminant) || DEBUG_MESSAGE_ENDING_BLOCK_LIST.iter().any(|blocked_name| discriminant.local_name().ends_with(blocked_name));
363+
let is_empty_batched = if let Message::Batched { messages } = message { messages.is_empty() } else { false };
362364

363-
if !is_blocked {
365+
if !is_blocked && !is_empty_batched {
364366
match message_logging_verbosity {
365367
MessageLoggingVerbosity::Off => {}
366368
MessageLoggingVerbosity::Names => {

editor/src/messages/frontend/frontend_message.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,19 @@ pub enum FrontendMessage {
3939
#[serde(rename = "fontSize")]
4040
font_size: f64,
4141
color: Color,
42-
url: String,
42+
#[serde(rename = "fontData")]
43+
font_data: Vec<u8>,
4344
transform: [f64; 6],
4445
#[serde(rename = "maxWidth")]
4546
max_width: Option<f64>,
4647
#[serde(rename = "maxHeight")]
4748
max_height: Option<f64>,
4849
align: TextAlign,
4950
},
51+
DisplayEditableTextboxUpdateFontData {
52+
#[serde(rename = "fontData")]
53+
font_data: Vec<u8>,
54+
},
5055
DisplayEditableTextboxTransform {
5156
transform: [f64; 6],
5257
},
@@ -92,8 +97,10 @@ pub enum FrontendMessage {
9297
name: String,
9398
filename: String,
9499
},
95-
TriggerFontLoad {
100+
TriggerFontCatalogLoad,
101+
TriggerFontDataLoad {
96102
font: Font,
103+
url: String,
97104
},
98105
TriggerImport,
99106
TriggerPersistenceRemoveDocument {

editor/src/messages/layout/layout_message_handler.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
22
use crate::messages::layout::utility_types::widget_prelude::*;
33
use crate::messages::prelude::*;
44
use graphene_std::raster::color::Color;
5-
use graphene_std::text::Font;
65
use graphene_std::vector::style::{FillChoice, GradientStops};
76
use serde_json::Value;
87
use std::collections::HashMap;
@@ -48,7 +47,6 @@ impl MessageHandler<LayoutMessage, LayoutMessageContext<'_>> for LayoutMessageHa
4847
}
4948
LayoutMessage::WidgetValueUpdate { layout_target, widget_id, value } => {
5049
self.handle_widget_callback(layout_target, widget_id, value, WidgetValueAction::Update, responses);
51-
responses.add(LayoutMessage::ResendActiveWidget { layout_target, widget_id });
5250
}
5351
}
5452
}

editor/src/messages/layout/utility_types/layout_widget.rs

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -353,42 +353,7 @@ impl From<Vec<WidgetInstance>> for LayoutGroup {
353353
}
354354

355355
impl LayoutGroup {
356-
/// Applies a tooltip label to all widgets in this row or column without a tooltip.
357-
pub fn with_tooltip_label(self, label: impl Into<String>) -> Self {
358-
let (is_col, mut widgets) = match self {
359-
LayoutGroup::Column { widgets } => (true, widgets),
360-
LayoutGroup::Row { widgets } => (false, widgets),
361-
_ => unimplemented!(),
362-
};
363-
let label = label.into();
364-
for widget in &mut widgets {
365-
let val = match &mut widget.widget {
366-
Widget::CheckboxInput(x) => &mut x.tooltip_label,
367-
Widget::ColorInput(x) => &mut x.tooltip_label,
368-
Widget::CurveInput(x) => &mut x.tooltip_label,
369-
Widget::DropdownInput(x) => &mut x.tooltip_label,
370-
Widget::IconButton(x) => &mut x.tooltip_label,
371-
Widget::IconLabel(x) => &mut x.tooltip_label,
372-
Widget::ImageButton(x) => &mut x.tooltip_label,
373-
Widget::ImageLabel(x) => &mut x.tooltip_label,
374-
Widget::NumberInput(x) => &mut x.tooltip_label,
375-
Widget::ParameterExposeButton(x) => &mut x.tooltip_label,
376-
Widget::PopoverButton(x) => &mut x.tooltip_label,
377-
Widget::TextAreaInput(x) => &mut x.tooltip_label,
378-
Widget::TextButton(x) => &mut x.tooltip_label,
379-
Widget::TextInput(x) => &mut x.tooltip_label,
380-
Widget::TextLabel(x) => &mut x.tooltip_label,
381-
Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip_label,
382-
Widget::ReferencePointInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::ShortcutLabel(_) | Widget::WorkingColorsInput(_) | Widget::NodeCatalog(_) => continue,
383-
};
384-
if val.is_empty() {
385-
val.clone_from(&label);
386-
}
387-
}
388-
if is_col { Self::Column { widgets } } else { Self::Row { widgets } }
389-
}
390-
391-
/// Applies a tooltip description to all widgets in this row or column without a tooltip.
356+
/// Applies a tooltip description to all widgets without a tooltip in this row or column.
392357
pub fn with_tooltip_description(self, description: impl Into<String>) -> Self {
393358
let (is_col, mut widgets) = match self {
394359
LayoutGroup::Column { widgets } => (true, widgets),
@@ -407,14 +372,19 @@ impl LayoutGroup {
407372
Widget::ImageButton(x) => &mut x.tooltip_description,
408373
Widget::ImageLabel(x) => &mut x.tooltip_description,
409374
Widget::NumberInput(x) => &mut x.tooltip_description,
410-
Widget::ParameterExposeButton(x) => &mut x.tooltip_description,
411375
Widget::PopoverButton(x) => &mut x.tooltip_description,
412376
Widget::TextAreaInput(x) => &mut x.tooltip_description,
413377
Widget::TextButton(x) => &mut x.tooltip_description,
414378
Widget::TextInput(x) => &mut x.tooltip_description,
415379
Widget::TextLabel(x) => &mut x.tooltip_description,
416380
Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip_description,
417-
Widget::ReferencePointInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::ShortcutLabel(_) | Widget::WorkingColorsInput(_) | Widget::NodeCatalog(_) => continue,
381+
Widget::ReferencePointInput(_)
382+
| Widget::RadioInput(_)
383+
| Widget::Separator(_)
384+
| Widget::ShortcutLabel(_)
385+
| Widget::WorkingColorsInput(_)
386+
| Widget::NodeCatalog(_)
387+
| Widget::ParameterExposeButton(_) => continue,
418388
};
419389
if val.is_empty() {
420390
val.clone_from(&description);
@@ -834,10 +804,38 @@ impl DiffUpdate {
834804
(recursive_wrapper.0)(entry_sections, &recursive_wrapper)
835805
};
836806

807+
// Hash the menu list entry sections for caching purposes
808+
let hash_menu_list_entry_sections = |entry_sections: &MenuListEntrySections| {
809+
struct RecursiveHasher<'a> {
810+
hasher: DefaultHasher,
811+
hash_fn: &'a dyn Fn(&mut RecursiveHasher, &MenuListEntrySections),
812+
}
813+
let mut recursive_hasher = RecursiveHasher {
814+
hasher: DefaultHasher::new(),
815+
hash_fn: &|recursive_hasher, entry_sections| {
816+
for (index, entries) in entry_sections.iter().enumerate() {
817+
index.hash(&mut recursive_hasher.hasher);
818+
for entry in entries {
819+
entry.hash(&mut recursive_hasher.hasher);
820+
(recursive_hasher.hash_fn)(recursive_hasher, &entry.children);
821+
}
822+
}
823+
},
824+
};
825+
(recursive_hasher.hash_fn)(&mut recursive_hasher, entry_sections);
826+
recursive_hasher.hasher.finish()
827+
};
828+
837829
// Apply shortcut conversions to all widgets that have menu lists
838830
let convert_menu_lists = |widget_instance: &mut WidgetInstance| match &mut widget_instance.widget {
839-
Widget::DropdownInput(dropdown_input) => apply_action_shortcut_to_menu_lists(&mut dropdown_input.entries),
840-
Widget::TextButton(text_button) => apply_action_shortcut_to_menu_lists(&mut text_button.menu_list_children),
831+
Widget::DropdownInput(dropdown_input) => {
832+
apply_action_shortcut_to_menu_lists(&mut dropdown_input.entries);
833+
dropdown_input.entries_hash = hash_menu_list_entry_sections(&dropdown_input.entries);
834+
}
835+
Widget::TextButton(text_button) => {
836+
apply_action_shortcut_to_menu_lists(&mut text_button.menu_list_children);
837+
text_button.menu_list_children_hash = hash_menu_list_entry_sections(&text_button.menu_list_children);
838+
}
841839
_ => {}
842840
};
843841

editor/src/messages/layout/utility_types/widgets/button_widgets.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ pub struct TextButton {
144144
#[serde(rename = "menuListChildren")]
145145
pub menu_list_children: MenuListEntrySections,
146146

147+
#[serde(rename = "menuListChildrenHash")]
148+
#[widget_builder(skip)]
149+
pub menu_list_children_hash: u64,
150+
147151
// Callbacks
148152
#[serde(skip)]
149153
#[derivative(Debug = "ignore", PartialEq = "ignore")]

editor/src/messages/layout/utility_types/widgets/input_widgets.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ pub struct DropdownInput {
8080
#[widget_builder(constructor)]
8181
pub entries: MenuListEntrySections,
8282

83+
#[serde(rename = "entriesHash")]
84+
#[widget_builder(skip)]
85+
pub entries_hash: u64,
86+
8387
// This uses `u32` instead of `usize` since it will be serialized as a normal JS number (replace this with `usize` after switching to a Rust-based GUI)
8488
#[serde(rename = "selectedIndex")]
8589
pub selected_index: Option<u32>,
@@ -94,6 +98,9 @@ pub struct DropdownInput {
9498

9599
pub narrow: bool,
96100

101+
#[serde(rename = "virtualScrolling")]
102+
pub virtual_scrolling: bool,
103+
97104
#[serde(rename = "tooltipLabel")]
98105
pub tooltip_label: String,
99106

@@ -142,6 +149,10 @@ pub struct MenuListEntry {
142149

143150
pub children: MenuListEntrySections,
144151

152+
#[serde(rename = "childrenHash")]
153+
#[widget_builder(skip)]
154+
pub children_hash: u64,
155+
145156
// Callbacks
146157
#[serde(skip)]
147158
#[derivative(Debug = "ignore", PartialEq = "ignore")]
@@ -152,6 +163,15 @@ pub struct MenuListEntry {
152163
pub on_commit: WidgetCallback<()>,
153164
}
154165

166+
impl std::hash::Hash for MenuListEntry {
167+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168+
self.value.hash(state);
169+
self.label.hash(state);
170+
self.icon.hash(state);
171+
self.disabled.hash(state);
172+
}
173+
}
174+
155175
#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)]
156176
#[derivative(Debug, PartialEq, Default)]
157177
pub struct NumberInput {

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc
1919
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, PTZ};
2020
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate};
2121
use crate::messages::portfolio::document::utility_types::nodes::RawBuffer;
22-
use crate::messages::portfolio::utility_types::PanelType;
23-
use crate::messages::portfolio::utility_types::PersistentData;
22+
use crate::messages::portfolio::utility_types::{FontCatalog, PanelType, PersistentData};
2423
use crate::messages::prelude::*;
2524
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_fill, get_opacity};
2625
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
@@ -36,6 +35,7 @@ use graphene_std::raster::BlendMode;
3635
use graphene_std::raster_types::Raster;
3736
use graphene_std::subpath::Subpath;
3837
use graphene_std::table::Table;
38+
use graphene_std::text::Font;
3939
use graphene_std::vector::PointId;
4040
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
4141
use graphene_std::vector::misc::{dvec2_to_point, point_to_dvec2};
@@ -2171,17 +2171,24 @@ impl DocumentMessageHandler {
21712171
}
21722172

21732173
/// Loads all of the fonts in the document.
2174-
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>) {
2175-
let mut fonts = HashSet::new();
2176-
for (_node_id, node, _) in self.document_network().recursive_nodes() {
2174+
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>, font_catalog: &FontCatalog) {
2175+
let mut fonts_to_load = HashSet::new();
2176+
2177+
for (_, node, _) in self.document_network().recursive_nodes() {
21772178
for input in &node.inputs {
21782179
if let Some(TaggedValue::Font(font)) = input.as_value() {
2179-
fonts.insert(font.clone());
2180+
fonts_to_load.insert(font.clone());
21802181
}
21812182
}
21822183
}
2183-
for font in fonts {
2184-
responses.add_front(FrontendMessage::TriggerFontLoad { font });
2184+
2185+
for font in fonts_to_load {
2186+
if let Some(style) = font_catalog.find_font_style_in_catalog(&font) {
2187+
responses.add_front(FrontendMessage::TriggerFontDataLoad {
2188+
font: Font::new(font.font_family, style.to_named_style()),
2189+
url: style.url,
2190+
});
2191+
}
21852192
}
21862193
}
21872194

0 commit comments

Comments
 (0)