si_img/
font.rs

1use crate::TextOptions;
2use ab_glyph::{Font, FontVec, OutlinedGlyph};
3use wasm_bindgen::prelude::*;
4
5/// Represents a font used for text rendering.
6#[wasm_bindgen]
7pub struct SiFont {
8    pub(crate) font: FontVec,
9}
10
11#[wasm_bindgen]
12impl SiFont {
13    /// Creates a new SiFont from a vector of font data.
14    #[wasm_bindgen(constructor)]
15    pub fn new(vec: Vec<u8>) -> Self {
16        Self::from_vec(vec)
17    }
18
19    /// Creates a new SiFont from a vector of font data.
20    #[wasm_bindgen]
21    pub fn from_vec(vec: Vec<u8>) -> SiFont {
22        let font = FontVec::try_from_vec(vec).unwrap();
23        SiFont { font }
24    }
25
26    /// Creates a new SiFont from font data fetched from a network URL asynchronously.
27    ///
28    /// # Arguments
29    ///
30    /// * `url` - The URL from which to fetch the font data.
31    #[wasm_bindgen]
32    #[cfg(feature = "async")]
33    pub async fn from_network_async(url: &str) -> Result<SiFont, JsValue> {
34        let font_data: Vec<u8> = reqwest::get(url)
35            .await
36            .expect("Could not fetch font")
37            .bytes()
38            .await
39            .expect("Could not extract font")
40            .into();
41        let font = FontVec::try_from_vec(font_data).unwrap();
42        Ok(SiFont { font })
43    }
44
45    /// Placeholder method for when async feature is not enabled.
46    #[cfg(not(feature = "async"))]
47    pub fn from_network_async(_url: &str) {
48        panic!("async feature not enabled")
49    }
50
51    /// Creates a new SiFont from font data fetched from a network URL synchronously.
52    ///
53    /// # Arguments
54    ///
55    /// * `src` - The URL from which to fetch the font data.
56    #[cfg(feature = "blocking")]
57    pub fn from_network(src: &str) -> SiFont {
58        // Load font data from either URL or provided bytes.
59        let font_data: Vec<u8> = reqwest::blocking::get(src)
60            .expect("Could not fetch font")
61            .bytes()
62            .expect("Could not extract font")
63            .into();
64        let font = FontVec::try_from_vec(font_data).unwrap();
65        SiFont { font }
66    }
67
68    /// Placeholder method for when blocking feature is not enabled.
69    #[cfg(not(feature = "blocking"))]
70    pub fn from_network(url: &str) {
71        panic!("blocking feature not enabled")
72    }
73
74    pub(crate) fn layout(
75        &self,
76        text: &str,
77        scale: f32,
78        position: Position,
79        options: &TextOptions,
80    ) -> Vec<OutlinedGlyph> {
81        let mut res: Vec<OutlinedGlyph> = Vec::new();
82        let mut tmp_x: f32 = position.0;
83        for char in text.chars() {
84            if char.is_whitespace() {
85                tmp_x += options.space_width;
86            }
87            if let Some(glyph) = self.font.outline_glyph(
88                self.font
89                    .glyph_id(char)
90                    .with_scale_and_position(scale, ab_glyph::point(tmp_x, position.1)),
91            ) {
92                let bb = glyph.px_bounds();
93                res.push(glyph);
94                tmp_x += bb.width() + options.letter_spacing;
95                // tmp_y += bb.height();
96            }
97        }
98        res
99    }
100}
101
102pub type Position = (f32, f32);