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