Skip to main content

cranpose_render_common/
text_fonts.rs

1//! The typefaces a renderer hands the app it draws, which the app's text
2//! lays out with.
3
4use std::sync::Arc;
5
6use cranpose_text::{FontFamilyResolver, Typeface};
7
8/// The bytes of the embedded default font.
9#[cfg(feature = "embedded-default-font")]
10pub const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../assets/NotoSansMerged.ttf");
11
12/// The embedded default font, or `None` in a build without the
13/// `embedded-default-font` feature.
14pub fn default_typeface() -> Option<Typeface> {
15    #[cfg(feature = "embedded-default-font")]
16    {
17        Typeface::from_bytes(DEFAULT_FONT_BYTES).ok()
18    }
19    #[cfg(not(feature = "embedded-default-font"))]
20    {
21        None
22    }
23}
24
25/// The typefaces an app's text lays out and draws with: the app's own, then
26/// the faces installed while it runs.
27#[derive(Clone, Default)]
28pub struct TextFonts {
29    typefaces: Arc<[Typeface]>,
30    /// How many of `typefaces`, at its end, are installed faces.
31    #[cfg(feature = "installed-fonts")]
32    installed: usize,
33}
34
35impl TextFonts {
36    /// The typefaces `typefaces`, the first preferred.
37    pub fn new(typefaces: Vec<Typeface>) -> Self {
38        Self {
39            typefaces: Arc::from(typefaces),
40            #[cfg(feature = "installed-fonts")]
41            installed: 0,
42        }
43    }
44
45    /// Parses each of `fonts` and keeps those that parse; with none that
46    /// parses, the embedded default font when the build has it.
47    pub fn from_fonts_or_default(fonts: &[&'static [u8]]) -> Self {
48        let mut typefaces: Vec<Typeface> = fonts
49            .iter()
50            .filter_map(|bytes| Typeface::from_bytes(*bytes).ok())
51            .collect();
52        if typefaces.is_empty() {
53            typefaces.extend(default_typeface());
54        }
55        Self::new(typefaces)
56    }
57
58    /// The typefaces, the first preferred.
59    pub fn typefaces(&self) -> &[Typeface] {
60        &self.typefaces
61    }
62
63    /// The resolver text lays out with over these typefaces.
64    pub fn resolver(&self) -> FontFamilyResolver {
65        FontFamilyResolver::new(self.typefaces.iter().cloned())
66    }
67
68    /// These fonts with the faces installed through
69    /// [`install_font_file`](crate::installed_fonts::install_font_file) after
70    /// their own, or `None` while no face was installed since they were made.
71    #[cfg(feature = "installed-fonts")]
72    pub fn with_installed_faces(&self) -> Option<Self> {
73        if crate::installed_fonts::installed_font_generation() == self.installed {
74            return None;
75        }
76        let installed = crate::installed_fonts::installed_faces();
77        let own = &self.typefaces[..self.typefaces.len() - self.installed];
78        let mut typefaces = Vec::with_capacity(own.len() + installed.len());
79        typefaces.extend_from_slice(own);
80        typefaces.extend_from_slice(&installed);
81        Some(Self {
82            typefaces: Arc::from(typefaces),
83            installed: installed.len(),
84        })
85    }
86}