1use std::{collections::HashMap, fmt, io::Read};
2use owned_ttf_parser::{AsFaceRef, GlyphId, OutlineBuilder, OwnedFace, Rect};
3use swash::{CacheKey, FontRef};
4
5use crate::atlas::{allocation::Allocation, Atlas};
6
7#[derive(Debug)]
8pub struct Glyph {
9 pub curves: Vec<f32>,
10 pub allocation: Allocation,
11 pub bbox: Rect,
12 pub descent: i16,
13 pub y_offset: i16,
14 pub left_side_bearing: i16,
15}
16
17pub struct Font {
18 data: Vec<u8>,
19 pub face: OwnedFace,
20 pub offset: u32,
21 pub key: CacheKey,
22 pub glyph_cache: HashMap<GlyphId, Glyph>,
23}
24
25type Result<T> = std::result::Result<T, LoadingError>;
26
27#[derive(Debug)]
28pub enum LoadingError {
29 FileNotFound,
30 InvalidFile,
31}
32
33impl fmt::Display for LoadingError {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 match *self {
36 LoadingError::FileNotFound =>
37 write!(f, "TTF Font file not found"),
38 LoadingError::InvalidFile =>
39 write!(f, "TTF Font file provided is invalid"),
40 }
41 }
42}
43
44impl Font {
45 pub fn from_file(
46 device: &wgpu::Device,
47 encoder: &mut wgpu::CommandEncoder,
48 queue: &wgpu::Queue,
49 path: &str,
50 index: usize,
51 cache_preset: &str,
52 atlas: &mut Atlas
53 ) -> Result<Font> {
54 let data = std::fs::read(path).or(Err(LoadingError::FileNotFound))?;
56 let font = FontRef::from_index(&data, index).ok_or(LoadingError::InvalidFile)?;
60 let (offset, key) = (font.offset, font.key);
61
62 let face = OwnedFace::from_vec(data.clone(), index as u32).or(Err(LoadingError::InvalidFile))?;
64
65 let glyph_cache = create_glyph_cache(device, encoder, queue, &face, cache_preset, atlas);
67
68 Ok(Self { data, face, offset, key, glyph_cache })
69 }
70
71 pub fn as_ref(&self) -> FontRef {
73 FontRef {
74 data: &self.data,
75 offset: self.offset,
76 key: self.key,
77 }
78 }
79}
80
81
82fn create_glyph_cache(
83 device: &wgpu::Device,
84 encoder: &mut wgpu::CommandEncoder,
85 queue: &wgpu::Queue,
86 face: &OwnedFace,
87 cache_preset: &str,
88 atlas: &mut Atlas
89) -> HashMap<GlyphId, Glyph> {
90 let mut glyph_cache = HashMap::new();
91
92 let face = face.as_face_ref();
93
94 let ascender = face.ascender();
95
96 for code_point in cache_preset.chars() {
97 if let Some(glyph_id) = face.glyph_index(code_point) {
98 if let Some(bbox) = face.glyph_bounding_box(glyph_id) {
99 let height = bbox.height();
100 let left_side_bearing = bbox.x_min;
101
102 let (descent, distance_from_baseline) = if bbox.y_min <= 0 {
103 (bbox.y_min, 0)
104 } else {
105 (0, bbox.y_min)
106 };
107
108 let total_height = height + descent + distance_from_baseline;
109 let y_offset = ascender - distance_from_baseline - height;
110
111 let mut builder = BezierBuilder::new(total_height as f32);
112
113 face.outline_glyph(glyph_id, &mut builder);
114
115 let curves_count = builder.curves.len() as u32;
116
117 let bytes = unsafe {
118 std::slice::from_raw_parts(builder.curves.as_ptr() as *const u8, builder.curves.len() * 4)
119 };
120
121 if let Some(allocation) = atlas.upload(curves_count, bytes, device, encoder, queue) {
122 let glyph = Glyph {
123 curves: builder.curves,
124 allocation,
125 bbox,
126 descent: descent,
127 y_offset: y_offset,
128 left_side_bearing,
129 };
130
131 glyph_cache.insert(glyph_id, glyph);
132 }
133 }
134 }
135 }
136
137 glyph_cache
138}
139
140struct BezierBuilder {
141 last_position: [f32; 2],
142 pub curves: Vec<f32>,
143 total_height: f32,
144}
145
146impl BezierBuilder {
147 pub fn new(total_height: f32) -> Self {
148 Self {
149 last_position: [0., 0.],
150 curves: Vec::new(),
151 total_height,
152 }
153 }
154}
155
156impl OutlineBuilder for BezierBuilder {
157 fn move_to(&mut self, x: f32, y: f32) {
158 self.last_position = [x, self.total_height - y];
159 }
160
161 fn line_to(&mut self, x: f32, y: f32) {
162 let [x0, y0] = self.last_position;
163 self.curves.extend_from_slice(&[x0, y0, x, self.total_height - y, x, self.total_height - y, 0., 0.]);
164 self.last_position = [x, self.total_height - y];
165 }
166
167 fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
168 let [x0, y0] = self.last_position;
169 self.curves.extend_from_slice(&[x0, y0, x1, self.total_height - y1, x, self.total_height - y, 0., 0.]);
170 self.last_position = [x, self.total_height - y];
171 }
172
173 fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
174 self.curves.extend_from_slice(&[x1, self.total_height - y1, x2, self.total_height - y2, x, self.total_height - y, 0., 0.]);
175 self.last_position = [x, self.total_height - y];
176 }
177
178 fn close(&mut self) {
179
180 }
181}