diff --git a/desktop/src/app.rs b/desktop/src/app.rs index 0d4db144d..c1436e641 100644 --- a/desktop/src/app.rs +++ b/desktop/src/app.rs @@ -49,12 +49,16 @@ impl App { .build(&event_loop)?; let window = Rc::new(window); - let mut gui = GuiController::new(window.clone(), &event_loop, &opt)?; + let mut font_database = fontdb::Database::default(); + font_database.load_system_fonts(); + + let mut gui = GuiController::new(window.clone(), &event_loop, &opt, &font_database)?; let mut player = PlayerController::new( event_loop.create_proxy(), window.clone(), gui.descriptors().clone(), + font_database, ); if let Some(movie_url) = movie_url { diff --git a/desktop/src/backends/ui.rs b/desktop/src/backends/ui.rs index c65025489..18f281c1a 100644 --- a/desktop/src/backends/ui.rs +++ b/desktop/src/backends/ui.rs @@ -1,6 +1,7 @@ use anyhow::{Context, Error}; use arboard::Clipboard; use chrono::{DateTime, Utc}; +use fontdb::Family; use rfd::{ AsyncFileDialog, FileHandle, MessageButtons, MessageDialog, MessageDialogResult, MessageLevel, }; @@ -120,12 +121,17 @@ pub struct DesktopUiBackend { language: LanguageIdentifier, preferred_cursor: MouseCursor, open_url_mode: OpenURLMode, + font_database: Rc, /// Is a dialog currently open dialog_open: bool, } impl DesktopUiBackend { - pub fn new(window: Rc, open_url_mode: OpenURLMode) -> Result { + pub fn new( + window: Rc, + open_url_mode: OpenURLMode, + font_database: Rc, + ) -> Result { let preferred_language = get_locale(); let language = preferred_language .and_then(|l| l.parse().ok()) @@ -138,6 +144,7 @@ impl DesktopUiBackend { preferred_cursor: MouseCursor::Arrow, open_url_mode, dialog_open: false, + font_database, }) } @@ -249,11 +256,52 @@ impl UiBackend for DesktopUiBackend { fn load_device_font( &self, - _name: &str, - _is_bold: bool, - _is_italic: bool, - _register: &mut dyn FnMut(FontDefinition), + name: &str, + is_bold: bool, + is_italic: bool, + register: &mut dyn FnMut(FontDefinition), ) { + let query = fontdb::Query { + families: &[Family::Name(name)], + weight: if is_bold { + fontdb::Weight::BOLD + } else { + fontdb::Weight::NORMAL + }, + style: if is_italic { + fontdb::Style::Italic + } else { + fontdb::Style::Normal + }, + ..Default::default() + }; + + // It'd be nice if we can get the full list of candidates... Feature request? + if let Some(id) = self.font_database.query(&query) { + if let Some(face) = self.font_database.face(id) { + tracing::info!("Loading device font \"{}\" for \"{name}\" (italic: {is_italic}, bold: {is_bold})", face.post_script_name); + + match &face.source { + fontdb::Source::File(path) => match std::fs::read(path) { + Ok(bytes) => register(FontDefinition::FontFile { + name: name.to_owned(), + is_bold, + is_italic, + data: bytes, + }), + Err(e) => error!("Couldn't read font file at {path:?}: {e}"), + }, + fontdb::Source::Binary(bin) | fontdb::Source::SharedFile(_, bin) => { + register(FontDefinition::FontFile { + name: name.to_owned(), + is_bold, + is_italic, + data: bin.as_ref().as_ref().to_vec(), + }) + } + }; + } + } } // Unused on desktop diff --git a/desktop/src/gui/controller.rs b/desktop/src/gui/controller.rs index cb2a98c7d..d371d8931 100644 --- a/desktop/src/gui/controller.rs +++ b/desktop/src/gui/controller.rs @@ -45,6 +45,7 @@ impl GuiController { window: Rc, event_loop: &EventLoop, opt: &Opt, + font_database: &Database, ) -> anyhow::Result { let backend: wgpu::Backends = opt.graphics.into(); if wgpu::Backends::SECONDARY.contains(backend) { @@ -104,7 +105,8 @@ impl GuiController { let egui_renderer = egui_wgpu::Renderer::new(&descriptors.device, surface_format, None, 1); let event_loop = event_loop.create_proxy(); let gui = RuffleGui::new(event_loop, opt.movie_url.clone(), PlayerOptions::from(opt)); - let system_fonts = load_system_fonts(gui.locale.to_owned()).unwrap_or_default(); + let system_fonts = + load_system_fonts(font_database, gui.locale.to_owned()).unwrap_or_default(); egui_ctx.set_fonts(system_fonts); egui_extras::install_image_loaders(&egui_ctx); @@ -330,10 +332,10 @@ impl GuiController { } // try to load known unicode supporting fonts to draw cjk characters in egui -fn load_system_fonts(locale: LanguageIdentifier) -> anyhow::Result { - let mut font_database = Database::default(); - font_database.load_system_fonts(); - +fn load_system_fonts( + font_database: &Database, + locale: LanguageIdentifier, +) -> anyhow::Result { let mut families = Vec::new(); if let Some(windows_font) = match locale.language.as_str() { "ja" => Some(Family::Name("MS UI Gothic")), diff --git a/desktop/src/player.rs b/desktop/src/player.rs index 53ebe3f49..7ad0c0ce5 100644 --- a/desktop/src/player.rs +++ b/desktop/src/player.rs @@ -97,6 +97,7 @@ impl ActivePlayer { window: Rc, descriptors: Arc, movie_view: MovieView, + font_database: Rc, ) -> Self { let mut builder = PlayerBuilder::new(); @@ -152,7 +153,7 @@ impl ActivePlayer { window: window.clone(), })) .with_ui( - DesktopUiBackend::new(window.clone(), opt.open_url_mode) + DesktopUiBackend::new(window.clone(), opt.open_url_mode, font_database) .expect("Couldn't create ui backend"), ) .with_autoplay(true) @@ -207,6 +208,7 @@ pub struct PlayerController { event_loop: EventLoopProxy, window: Rc, descriptors: Arc, + font_database: Rc, } impl PlayerController { @@ -214,12 +216,14 @@ impl PlayerController { event_loop: EventLoopProxy, window: Rc, descriptors: Arc, + font_database: fontdb::Database, ) -> Self { Self { player: None, event_loop, window, descriptors, + font_database: Rc::new(font_database), } } @@ -231,6 +235,7 @@ impl PlayerController { self.window.clone(), self.descriptors.clone(), movie_view, + self.font_database.clone(), )); }