Skip to main content

firefly_rust/graphics/
font.rs

1use crate::*;
2
3/// Owned version of [`Font`].
4///
5/// Can be loaded as [`FileBuf`] from ROM with [`load_file_buf`]
6/// and then cast using [`Into::into`].
7#[cfg(feature = "alloc")]
8pub struct FontBuf {
9    pub(crate) raw: alloc::boxed::Box<[u8]>,
10}
11
12#[cfg(feature = "alloc")]
13impl Font for FontBuf {
14    unsafe fn as_bytes(&self) -> &[u8] {
15        &self.raw
16    }
17}
18
19#[cfg(feature = "alloc")]
20impl From<FileBuf> for FontBuf {
21    fn from(value: FileBuf) -> Self {
22        Self { raw: value.raw }
23    }
24}
25
26/// Borrowed version of [`Font`].
27pub struct FontRef<'a> {
28    raw: &'a [u8],
29}
30
31impl Font for FontRef<'_> {
32    unsafe fn as_bytes(&self) -> &[u8] {
33        self.raw
34    }
35}
36
37impl<'a> From<FileRef<'a>> for FontRef<'a> {
38    fn from(value: FileRef<'a>) -> Self {
39        Self { raw: value.raw }
40    }
41}
42
43/// A loaded font file.
44pub trait Font {
45    /// Get the raw font file representation.
46    ///
47    /// # Safety
48    ///
49    /// Don't use it. The internal font representation might change
50    /// in the future and so should not be relied upon.
51    unsafe fn as_bytes(&self) -> &[u8];
52
53    /// Check if the font encoding is ASCII.
54    #[must_use]
55    fn is_ascii(&self) -> bool {
56        let raw = unsafe { self.as_bytes() };
57        raw[1] == 0
58    }
59
60    /// Calculate width (in pixels) of the given ASCII text.
61    ///
62    /// This function does not account for newlines.
63    #[must_use]
64    fn line_width_ascii(&self, t: &str) -> u32 {
65        t.len() as u32 * u32::from(self.char_width())
66    }
67
68    /// Calculate width (in pixels) of the given UTF-8 text.
69    ///
70    /// This function does not account for newlines.
71    #[must_use]
72    fn line_width_utf8(&self, t: &str) -> u32 {
73        t.chars().count() as u32 * u32::from(self.char_width())
74    }
75
76    /// The width (in pixels) of one glyph bounding box.
77    #[must_use]
78    fn char_width(&self) -> u8 {
79        let raw = unsafe { self.as_bytes() };
80        raw[2]
81    }
82
83    /// The height (in pixels) of one glyph (one line) bounding box.
84    #[must_use]
85    fn char_height(&self) -> u8 {
86        let raw = unsafe { self.as_bytes() };
87        raw[3]
88    }
89
90    /// Offset from the top of the glyph bounding box to the baseline.
91    #[must_use]
92    fn baseline(&self) -> u8 {
93        let raw = unsafe { self.as_bytes() };
94        raw[4]
95    }
96}