Add the ability to load application fonts by path

The viewer command line tool also gains the ability to specify them via `--app-font=/path/to/font.ttf` , which can be specified multiple times.
This commit is contained in:
Simon Hausmann 2021-02-17 14:16:02 +01:00
parent 09ea6572e4
commit 45fe6c3e8d
7 changed files with 84 additions and 0 deletions

View file

@ -178,6 +178,15 @@ pub fn register_application_font_from_memory(
sixtyfps_rendering_backend_default::backend().register_application_font_from_memory(data) sixtyfps_rendering_backend_default::backend().register_application_font_from_memory(data)
} }
/// This function can be used to register a custom TrueType font with SixtyFPS,
/// for use with the `font-family` property. The provided path must refer to a valid TrueType
/// font.
pub fn register_application_font_from_path<P: AsRef<std::path::Path>>(
path: P,
) -> Result<(), Box<dyn std::error::Error>> {
sixtyfps_rendering_backend_default::backend().register_application_font_from_path(path.as_ref())
}
// FIXME: this should not be in this namespace // FIXME: this should not be in this namespace
// but the name is `sixtyfps::StateInfo` in builtin.60 // but the name is `sixtyfps::StateInfo` in builtin.60
#[doc(hidden)] #[doc(hidden)]

View file

@ -11,6 +11,8 @@ LICENSE END */
The backend is the abstraction for crates that need to do the actual drawing and event loop The backend is the abstraction for crates that need to do the actual drawing and event loop
*/ */
use std::path::Path;
use crate::window::ComponentWindow; use crate::window::ComponentWindow;
/// Interface implemented by backends /// Interface implemented by backends
@ -30,6 +32,14 @@ pub trait Backend: Send + Sync {
data: &'static [u8], data: &'static [u8],
) -> Result<(), Box<dyn std::error::Error>>; ) -> Result<(), Box<dyn std::error::Error>>;
/// This function can be used to register a custom TrueType font with SixtyFPS,
/// for use with the `font-family` property. The provided path must refer to a valid TrueType
/// font.
fn register_application_font_from_path(
&'static self,
path: &Path,
) -> Result<(), Box<dyn std::error::Error>>;
fn set_clipboard_text(&'static self, text: String); fn set_clipboard_text(&'static self, text: String);
fn clipboard_text(&'static self) -> Option<String>; fn clipboard_text(&'static self) -> Option<String>;
} }

View file

@ -213,3 +213,9 @@ pub async fn load(
pub fn run_event_loop() { pub fn run_event_loop() {
sixtyfps_rendering_backend_default::backend().run_event_loop(); sixtyfps_rendering_backend_default::backend().run_event_loop();
} }
pub fn register_application_font_from_path<P: AsRef<std::path::Path>>(
path: P,
) -> Result<(), Box<dyn std::error::Error>> {
sixtyfps_rendering_backend_default::backend().register_application_font_from_path(path.as_ref())
}

View file

@ -33,6 +33,17 @@ pub fn register_application_font_from_memory(
Ok(()) Ok(())
} }
pub fn register_application_font_from_path(
path: &std::path::Path,
) -> Result<(), Box<dyn std::error::Error>> {
// Should use FontDb::load_font_file but that requires the `fs` feature, for which I can't figure
// out how to exclude it from the wasm build. It's inclusion implies mmap, which doesn't compile
// with wasm.
let data = std::fs::read(path)?;
APPLICATION_FONTS.with(|fontdb| fontdb.borrow_mut().load_font_data(data));
Ok(())
}
pub(crate) fn try_load_app_font( pub(crate) fn try_load_app_font(
canvas: &CanvasRc, canvas: &CanvasRc,
request: &FontRequest, request: &FontRequest,

View file

@ -1438,6 +1438,13 @@ impl sixtyfps_corelib::backend::Backend for Backend {
self::register_application_font_from_memory(data) self::register_application_font_from_memory(data)
} }
fn register_application_font_from_path(
&'static self,
path: &std::path::Path,
) -> Result<(), Box<dyn std::error::Error>> {
self::register_application_font_from_path(path)
}
fn set_clipboard_text(&'static self, text: String) { fn set_clipboard_text(&'static self, text: String) {
use copypasta::ClipboardProvider; use copypasta::ClipboardProvider;
CLIPBOARD.with(|clipboard| clipboard.borrow_mut().set_contents(text).ok()); CLIPBOARD.with(|clipboard| clipboard.borrow_mut().set_contents(text).ok());

View file

@ -98,6 +98,17 @@ pub const HAS_NATIVE_STYLE: bool = cfg!(not(no_qt));
/// False if the backend was compiled without Qt so it wouldn't do anything /// False if the backend was compiled without Qt so it wouldn't do anything
pub const IS_AVAILABLE: bool = cfg!(not(no_qt)); pub const IS_AVAILABLE: bool = cfg!(not(no_qt));
#[cfg(unix)]
fn path_to_bytes<'a>(path: &'a std::path::Path) -> &'a [u8] {
use std::os::unix::ffi::OsStrExt;
path.as_os_str().as_bytes()
}
#[cfg(not(unix))]
fn path_to_bytes<'a>(path: &'a std::path::Path) -> &'a [u8] {
path.to_string_lossy().to_string().as_bytes()
}
pub struct Backend; pub struct Backend;
impl sixtyfps_corelib::backend::Backend for Backend { impl sixtyfps_corelib::backend::Backend for Backend {
fn create_window(&'static self) -> ComponentWindow { fn create_window(&'static self) -> ComponentWindow {
@ -138,6 +149,22 @@ impl sixtyfps_corelib::backend::Backend for Backend {
Ok(()) Ok(())
} }
fn register_application_font_from_path(
&'static self,
_path: &std::path::Path,
) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(not(no_qt))]
{
use cpp::cpp;
let encoded_path: qttypes::QByteArray = path_to_bytes(_path).into();
cpp! {unsafe [encoded_path as "QByteArray"] {
ensure_initialized();
QFontDatabase::addApplicationFont(QFile::decodeName(encoded_path));
} }
};
Ok(())
}
fn set_clipboard_text(&'static self, _text: String) { fn set_clipboard_text(&'static self, _text: String) {
#[cfg(not(no_qt))] #[cfg(not(no_qt))]
{ {

View file

@ -20,12 +20,26 @@ struct Cli {
/// The style name (empty, or 'qt') /// The style name (empty, or 'qt')
#[structopt(long, name = "style name", default_value)] #[structopt(long, name = "style name", default_value)]
style: String, style: String,
/// An optional application font
#[structopt(long, name = "application font")]
app_font: Option<Vec<String>>,
} }
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
let args = Cli::from_args(); let args = Cli::from_args();
let source = std::fs::read_to_string(&args.path)?; let source = std::fs::read_to_string(&args.path)?;
args.app_font.map(|fonts| {
fonts.iter().for_each(|font_path| {
if let Err(app_font_err) =
sixtyfps_interpreter::register_application_font_from_path(&font_path)
{
eprintln!("Error loading app font {}: {}", font_path, app_font_err);
}
});
});
let mut compiler_config = sixtyfps_compilerlib::CompilerConfiguration::new( let mut compiler_config = sixtyfps_compilerlib::CompilerConfiguration::new(
sixtyfps_compilerlib::generator::OutputFormat::Interpreter, sixtyfps_compilerlib::generator::OutputFormat::Interpreter,
); );