Session::apply_prefs set the shared text engine's missing-glyph protection through photocraft_text::shared(), which blocks until the system font scan that launch starts in the background is done. It runs on the UI thread at launch and on every preferences change, so the first frame waited for the rest of the scan: 248–257 ms on this machine (release, launch order replayed), more with many fonts installed. set_shared_missing_glyph_protection applies it at once when the engine is built, and otherwise from one helper thread once the scan finishes. Both read the newest setting under the engine's lock, so a late change is never overwritten by an older one. Measured the same way: 0.1 ms. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
parent
5cff9ebed2
commit
233b6c63f0
|
|
@ -1509,9 +1509,8 @@ impl Session {
|
|||
st.history.trim(&st.doc);
|
||||
}
|
||||
photocraft_compose::set_effect_cache_budget(budget << 20);
|
||||
if let Ok(mut engine) = photocraft_text::shared().lock() {
|
||||
engine.fonts.set_missing_glyph_protection(self.prefs().type_.missing_glyph_protection());
|
||||
}
|
||||
// Without waiting for the system font scan: this runs on the UI thread at launch.
|
||||
photocraft_text::set_shared_missing_glyph_protection(self.prefs().type_.missing_glyph_protection());
|
||||
crate::plugin_cmds::sync_prefs(self);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,43 @@ pub fn try_shared() -> Option<&'static std::sync::Mutex<TextEngine>> {
|
|||
SHARED.try_get(new_shared, uses_system_fonts())
|
||||
}
|
||||
|
||||
/// Preferences › Type › Enable Missing Glyph Protection for [`shared`]: 0 = not set yet,
|
||||
/// 1 = off, 2 = on. Read under the engine's lock, so the newest setting always wins.
|
||||
static WANT_GLYPH_PROTECTION: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
|
||||
/// A thread is already waiting for the font scan to apply [`WANT_GLYPH_PROTECTION`].
|
||||
static GLYPH_PROTECTION_WAITING: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
fn apply_glyph_protection(engine: &std::sync::Mutex<TextEngine>) {
|
||||
let mut e = engine.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
match WANT_GLYPH_PROTECTION.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
1 => e.fonts.set_missing_glyph_protection(false),
|
||||
2 => e.fonts.set_missing_glyph_protection(true),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets [`shared`]'s missing-glyph protection without waiting for the system font scan (#4519):
|
||||
/// applied now when the engine is built, otherwise by a helper thread once the scan finishes.
|
||||
/// Called from the UI thread at launch and on every preferences change, where [`shared`] would
|
||||
/// block until the scan is done.
|
||||
pub fn set_shared_missing_glyph_protection(on: bool) {
|
||||
WANT_GLYPH_PROTECTION.store(if on { 2 } else { 1 }, std::sync::atomic::Ordering::SeqCst);
|
||||
if let Some(engine) = try_shared() {
|
||||
apply_glyph_protection(engine);
|
||||
return;
|
||||
}
|
||||
if GLYPH_PROTECTION_WAITING.swap(true, std::sync::atomic::Ordering::SeqCst) {
|
||||
// The waiting thread reads the newest setting when it applies it.
|
||||
return;
|
||||
}
|
||||
let spawned = std::thread::Builder::new().name("photocraft-glyph-protection".into()).spawn(|| apply_glyph_protection(shared()));
|
||||
if spawned.is_err() {
|
||||
// No thread: apply it here, as before.
|
||||
GLYPH_PROTECTION_WAITING.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||
apply_glyph_protection(shared());
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts building [`shared`] (the system font scan) on a background thread, so the Type tool's
|
||||
/// font menus don't stall the UI when they first draw. Call once at startup; calling again does
|
||||
/// nothing.
|
||||
|
|
|
|||
|
|
@ -1838,6 +1838,21 @@ fn missing_glyph_protection_can_turn_the_fallback_stack_off() {
|
|||
assert!(db.fallback_stack().any(|f| f == "Cairo"), "turning it back on restores the coverage fonts");
|
||||
}
|
||||
|
||||
/// The shared engine's missing-glyph protection follows the setting without waiting for the
|
||||
/// system font scan (#4519). Under test the shared engine has no scan, so it applies at once;
|
||||
/// the newest setting wins.
|
||||
#[test]
|
||||
fn shared_missing_glyph_protection_follows_the_setting() {
|
||||
let read = || crate::shared().lock().unwrap_or_else(std::sync::PoisonError::into_inner).fonts.missing_glyph_protection();
|
||||
crate::set_shared_missing_glyph_protection(false);
|
||||
assert!(!read());
|
||||
crate::set_shared_missing_glyph_protection(true);
|
||||
crate::set_shared_missing_glyph_protection(false);
|
||||
assert!(!read(), "the newest setting wins");
|
||||
crate::set_shared_missing_glyph_protection(true);
|
||||
assert!(read());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn translate_tysh_moves_only_the_translation() {
|
||||
let mut t = point("Hello!", 26.0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue