Skip to main content

i_slint_renderer_software/fonts/
systemfonts.rs

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 i_slint_common::sharedfontique::{self, HashedBlob, fontique};
11use i_slint_core::lengths::ScaleFactor;
12
13use super::super::PhysicalLength;
14use super::vectorfont::VectorFont;
15
16struct CachedFont {
17    fontdue_font: Rc<fontdue::Font>,
18}
19
20i_slint_core::thread_local! {
21    // fontdue fonts cached and indexed by fontique blob id (unique incremental) and true type collection index
22    static FONTDUE_FONTS: RefCell<HashMap<(HashedBlob, u32), CachedFont>> = Default::default();
23}
24
25pub fn get_or_create_fontdue_font_from_blob_and_index(
26    blob: &fontique::Blob<u8>,
27    index: u32,
28) -> Rc<fontdue::Font> {
29    FONTDUE_FONTS.with(|font_cache| {
30        font_cache
31            .borrow_mut()
32            .entry((blob.clone().into(), index))
33            .or_insert_with(move || CachedFont {
34                fontdue_font: fontdue::Font::from_bytes(
35                    blob.data(),
36                    fontdue::FontSettings {
37                        collection_index: index,
38                        scale: 40.,
39                        ..Default::default()
40                    },
41                )
42                .expect("fatal: fontdue is unable to parse truetype font")
43                .into(),
44            })
45            .fontdue_font
46            .clone()
47    })
48}
49
50fn get_or_create_fontdue_font(font: &fontique::QueryFont) -> Rc<fontdue::Font> {
51    get_or_create_fontdue_font_from_blob_and_index(&font.blob, font.index)
52}
53
54pub fn match_font(
55    request: &super::FontRequest,
56    scale_factor: super::ScaleFactor,
57) -> Option<VectorFont> {
58    if request.family.is_some() {
59        let requested_pixel_size: PhysicalLength =
60            (request.pixel_size.unwrap_or(super::DEFAULT_FONT_SIZE).cast() * scale_factor).cast();
61
62        if let Some(font) = request.query_fontique() {
63            let fontdue_font = get_or_create_fontdue_font(&font);
64            Some(VectorFont::new(font, fontdue_font, requested_pixel_size))
65        } else {
66            None
67        }
68    } else {
69        None
70    }
71}
72
73pub fn fallbackfont(font_request: &super::FontRequest, scale_factor: ScaleFactor) -> VectorFont {
74    let requested_pixel_size: PhysicalLength =
75        (font_request.pixel_size.unwrap_or(super::DEFAULT_FONT_SIZE).cast() * scale_factor).cast();
76
77    let font = font_request.query_fontique().unwrap();
78    let fontdue_font = get_or_create_fontdue_font(&font);
79    VectorFont::new(font, fontdue_font, requested_pixel_size)
80}
81
82pub fn register_font_from_memory(data: &'static [u8]) -> Result<(), Box<dyn std::error::Error>> {
83    sharedfontique::get_collection().register_fonts(data.to_vec().into(), None);
84    Ok(())
85}
86
87#[cfg(not(target_family = "wasm"))]
88pub fn register_font_from_path(path: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
89    let requested_path = path.canonicalize().unwrap_or_else(|_| path.into());
90    let contents = std::fs::read(requested_path)?;
91    sharedfontique::get_collection().register_fonts(contents.into(), None);
92    Ok(())
93}