1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use core::cell::RefCell;
5
6use alloc::boxed::Box;
7use alloc::rc::Rc;
8use std::collections::HashMap;
9
10use crate::lengths::ScaleFactor;
11use i_slint_common::sharedfontdb::{self, fontdb};
12
13use super::super::PhysicalLength;
14use super::vectorfont::VectorFont;
15
16crate::thread_local! {
17 static FONTDUE_FONTS: RefCell<HashMap<fontdb::ID, Rc<fontdue::Font>>> = Default::default();
18}
19
20fn get_or_create_fontdue_font(fontdb: &fontdb::Database, id: fontdb::ID) -> Rc<fontdue::Font> {
21 FONTDUE_FONTS.with(|font_cache: &RefCell>>| {
22 font_cache&mut Rc
23 .borrow_mut()
24 .entry(id)
25 .or_insert_with(|| {
26 fontdbOption>
27 .with_face_data(id, |face_data: &[u8], font_index: u32| {
28 fontdueFont::Font::from_bytes(
29 face_data,
30 fontdue::FontSettings {
31 collection_index: font_index,
32 scale: 40.,
33 ..Default::default()
34 },
35 )
36 .expect(msg:"fatal: fontdue is unable to parse truetype font")
37 .into()
38 })
39 .unwrap()
40 })
41 .clone()
42 })
43}
44
45pub fn match_font(
46 request: &super::FontRequest,
47 scale_factor: super::ScaleFactor,
48) -> Option<VectorFont> {
49 request.family.as_ref().and_then(|family_str: &SharedString| {
50 let query: Query<'_> = request.to_fontdb_query();
51
52 let requested_pixel_size: PhysicalLength =
53 (request.pixel_size.unwrap_or(default:super::DEFAULT_FONT_SIZE).cast() * scale_factor).cast();
54
55 sharedfontdb::FONT_DB.with(|fonts: &RefCell| {
56 let borrowed_fontdb: Ref<'_, FontDatabase> = fonts.borrow();
57 borrowed_fontdb.query_with_family(query, family:Some(family_str)).map(|font_id: ID| {
58 let fontdue_font: Rc = get_or_create_fontdue_font(&borrowed_fontdb, font_id);
59 VectorFont::new(font_id, fontdue_font.clone(), requested_pixel_size)
60 })
61 })
62 })
63}
64
65pub fn fallbackfont(font_request: &super::FontRequest, scale_factor: ScaleFactor) -> VectorFont {
66 let requested_pixel_size: PhysicalLength =
67 (font_request.pixel_size.unwrap_or(default:super::DEFAULT_FONT_SIZE).cast() * scale_factor).cast();
68
69 sharedfontdb::FONT_DB.with_borrow(|fonts: &FontDatabase| {
70 let query: Query<'_> = font_request.to_fontdb_query();
71
72 let fallback_font_id: ID = fonts
73 .query_with_family(query, None)
74 .expect(msg:"fatal: query for fallback font returned empty font list");
75
76 let fontdue_font: Rc = get_or_create_fontdue_font(fontdb:fonts, fallback_font_id);
77 VectorFont::new(fallback_font_id, fontdue_font, requested_pixel_size)
78 })
79}
80
81pub fn register_font_from_memory(data: &'static [u8]) -> Result<(), Box<dyn std::error::Error>> {
82 sharedfontdb::FONT_DB.with_borrow_mut(|fonts: &mut FontDatabase| {
83 fonts.make_mut().load_font_source(fontdb::Source::Binary(std::sync::Arc::new(data)))
84 });
85 Ok(())
86}
87
88#[cfg(not(target_family = "wasm"))]
89pub fn register_font_from_path(path: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
90 let requested_path: PathBuf = path.canonicalize().unwrap_or_else(|_| path.into());
91 sharedfontdb::FONT_DB.with_borrow_mut(|fonts: &mut FontDatabase| {
92 for face_info in fonts.faces() {
93 match &face_info.source {
94 fontdb::Source::Binary(_) => {}
95 fontdb::Source::File(loaded_path: &PathBuf) | fontdb::Source::SharedFile(loaded_path: &PathBuf, ..) => {
96 if *loaded_path == requested_path {
97 return Ok(());
98 }
99 }
100 }
101 }
102
103 fonts.make_mut().load_font_file(requested_path).map_err(|e: Error| e.into())
104 })
105}
106