Skip to main content

ferroui_fonts_inter/
inter_font_collection.rs

1use ferroui_base::media::fonts::{EmbeddedFontCollection, FontCollectionBase, FontCollectionBaseImpl};
2use ferroui_base::utilities::Uri;
3
4/// The font collection of the embedded Inter family, with the key
5/// `fonts:Inter`.
6pub struct InterFontCollection {
7    base: EmbeddedFontCollection,
8}
9
10impl InterFontCollection {
11    /// Creates the collection and loads the embedded fonts into it.
12    pub fn new() -> Self {
13        crate::assets::register();
14        Self {
15            base: EmbeddedFontCollection::new(
16                Uri::absolute("fonts:Inter").expect("a valid key"),
17                Uri::absolute(&format!("ferres://{}/Assets", crate::ASSEMBLY_NAME)).expect("a valid source"),
18            ),
19        }
20    }
21}
22
23impl Default for InterFontCollection {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl FontCollectionBaseImpl for InterFontCollection {
30    fn base(this: &Self) -> &FontCollectionBase {
31        EmbeddedFontCollection::base(&this.base)
32    }
33
34    fn key(this: &Self) -> Uri {
35        EmbeddedFontCollection::key(&this.base)
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use ferroui_base::media::fonts::IFontCollection;
43    use ferroui_base::media::{FontFamily, FontManager, FontWeight, Typeface};
44    use ferroui_base::platform::{IAssetLoader, IFontManagerImpl, StandardAssetLoader};
45    use ferroui_base::reactive::IDisposable;
46    use ferroui_base::FerroLocator;
47    use std::rc::Rc;
48
49    /// A locator scope with the Skia font manager and the asset loader that
50    /// serves the embedded assets.
51    fn start() -> Rc<dyn IDisposable> {
52        let scope = FerroLocator::enter_scope();
53        let locator = FerroLocator::current_mutable();
54        let font_manager: Rc<dyn IFontManagerImpl> = Rc::new(ferroui_skia::FontManagerImpl::new());
55        locator.bind::<dyn IFontManagerImpl>().to_constant(font_manager);
56        let asset_loader: Rc<dyn IAssetLoader> = Rc::new(StandardAssetLoader::new(None));
57        locator.bind::<dyn IAssetLoader>().to_constant(asset_loader);
58        scope
59    }
60
61    #[test]
62    fn the_collection_is_keyed_as_the_inter_fonts() {
63        let scope = start();
64
65        let collection = InterFontCollection::new();
66
67        assert_eq!("fonts:Inter", IFontCollection::key(&collection).original_string());
68        scope.dispose();
69    }
70
71    #[test]
72    fn the_collection_holds_the_families_of_the_six_font_files() {
73        let scope = start();
74
75        let collection = InterFontCollection::new();
76
77        // The regular and the bold face share the family name; the other weights carry theirs in
78        // the name, with "Inter" as their typographic family.
79        let mut names: Vec<String> = (0..IFontCollection::count(&collection))
80            .map(|index| IFontCollection::get(&collection, index).name().to_string())
81            .collect();
82        names.sort();
83        assert_eq!(vec!["Inter", "Inter Light", "Inter Medium", "Inter SemiBold", "Inter Thin"], names);
84
85        let typefaces = collection.try_get_family_typefaces("Inter").expect("the family is present");
86        let weights: Vec<i32> = typefaces.iter().map(|typeface| typeface.weight().0).collect();
87        assert!(weights.contains(&FontWeight::Normal.0), "{weights:?}");
88        assert!(weights.contains(&FontWeight::Bold.0), "{weights:?}");
89        scope.dispose();
90    }
91
92    #[test]
93    fn the_collection_can_be_added_to_the_font_manager() {
94        let scope = start();
95
96        FontManager::current().add_font_collection(Rc::new(InterFontCollection::new()));
97
98        let typeface = Typeface::new(FontFamily::parse("fonts:Inter#Inter").unwrap());
99        let glyph_typeface =
100            FontManager::current().try_get_glyph_typeface(&typeface).expect("the family resolves through its key");
101        assert_eq!("Inter", glyph_typeface.family_name());
102        scope.dispose();
103    }
104}