orbtk_render/raqote/
font.rs1use crate::utils::{Color, Rectangle};
2
3#[derive(Debug, Clone)]
4pub struct Font {
5 inner: rusttype::Font<'static>,
6}
7
8impl Font {
9 pub fn from_bytes(bytes: &'static [u8]) -> Result<Self, rusttype::Error> {
10 rusttype::Font::from_bytes(bytes).map(|font| Font { inner: font })
11 }
12
13 pub fn measure_text(&self, text: &str, size: f64) -> (f64, f64) {
14 let scale = rusttype::Scale::uniform(size as f32);
15 let v_metrics = self.inner.v_metrics(scale);
16 let offset = rusttype::point(0.0, v_metrics.ascent);
17
18 let pixel_height = size.ceil();
19
20 let glyphs: Vec<rusttype::PositionedGlyph> =
22 self.inner.layout(text, scale, offset).collect();
23
24 let width = glyphs
25 .iter()
26 .rev()
27 .map(|g| g.position().x as f32 + g.unpositioned().h_metrics().advance_width)
28 .next()
29 .unwrap_or(0.0)
30 .ceil() as f64;
31
32 (width, pixel_height)
33 }
34
35 pub fn render_text(
36 &self,
37 text: &str,
38 data: &mut [u32],
39 width: f64,
40 config: (f64, Color, f32),
42 position: (f64, f64),
43 ) {
44 self.render_text_clipped(
45 text,
46 data,
47 width,
48 config,
49 position,
50 Rectangle::new((0.0, 0.0), (width, std::f64::MAX)),
51 );
52 }
53
54 pub fn render_text_clipped(
55 &self,
56 text: &str,
57 data: &mut [u32],
58 width: f64,
59 config: (f64, Color, f32),
61 position: (f64, f64),
62 clip: Rectangle,
63 ) {
64 let scale = rusttype::Scale::uniform(config.0 as f32);
65
66 let v_metrics = self.inner.v_metrics(scale);
71 let offset = rusttype::point(0.0, v_metrics.ascent);
72
73 let glyphs: Vec<rusttype::PositionedGlyph> =
75 self.inner.layout(text, scale, offset).collect();
76
77 let pixel_width = glyphs
78 .iter()
79 .rev()
80 .map(|g| g.position().x as f32 + g.unpositioned().h_metrics().advance_width)
81 .next()
82 .unwrap_or(0.0)
83 .ceil() as i32;
84
85 let pixel_height = config.0.ceil() as i32;
86
87 for g in glyphs.iter() {
88 if let Some(bb) = g.pixel_bounding_box() {
89 g.draw(|off_x, off_y, v| {
90 let off_x = off_x as i32 + bb.min.x;
91 let off_y = off_y as i32 + bb.min.y;
92
93 if off_x >= 0
94 && off_x < pixel_width
95 && off_y >= 0
96 && off_y < pixel_height
97 && position.0 + off_x as f64 >= clip.x()
98 && position.0 + off_x as f64 <= clip.x() + clip.width()
99 && position.1 + off_y as f64 >= clip.y()
100 && position.1 + off_y as f64 <= clip.y() + clip.height()
101 {
102 let alpha = (config.2 * v * 255.0) as u32;
104 let new = (alpha << 24) | (config.1.data & 0x00FF_FFFF);
105
106 let index = ((position.1 as i32 + off_y) * width as i32
107 + position.0 as i32
108 + off_x) as usize;
109 if index >= data.len() {
110 return;
111 }
112 let old = &mut data[index];
113 if alpha >= 255 {
114 *old = new;
115 } else if alpha > 0 {
116 let n_alpha = 255 - alpha;
117 let rb = ((n_alpha * (*old & 0x00FF_00FF))
118 + (alpha * (new & 0x00FF_00FF)))
119 >> 8;
120 let ag = (n_alpha * ((*old & 0xFF00_FF00) >> 8))
121 + (alpha * (0x0100_0000 | ((new & 0x0000_FF00) >> 8)));
122
123 *old = (rb & 0x00FF_00FF) | (ag & 0xFF00_FF00);
124 }
125 }
126 });
127 }
128 }
129 }
130}