1use std::{
2 collections::HashMap,
3 hash::{Hash, Hasher},
4 io::{Read, Write},
5};
6
7use byteorder_lite::{LittleEndian, ReadBytesExt, WriteBytesExt};
8use flate2::bufread::ZlibDecoder;
9
10use crate::{
11 gpu::{
12 GPU,
13 GPUInner,
14 texture::{Texture, TextureBuilder, TextureError, TextureFormat, TextureUsage},
15 },
16 math::{Point2, Vector2},
17 utils::ArcRef,
18};
19
20
21pub fn new() -> FontManager {
25 FontManager::new()
26}
27
28pub fn load_font(path: &str, glyph: Option<&[(u32, u32)]>, size: f32) -> Result<Font, FontError> {
29 let font_info = system::get_font_info(std::path::Path::new(path));
30
31 if font_info.is_none() {
32 return Err(FontError::InvalidFontData(format!(
33 "Failed to load font from path: {}",
34 path
35 )));
36 }
37
38 let font_info = font_info.unwrap();
39 Font::new(font_info, size, glyph.unwrap_or(&[(0x20, 0x7E)]))
40}
41
42mod system;
43
44#[derive(Clone, Copy, Debug)]
45pub struct FontStyle(u8);
46
47bitflags::bitflags! {
48 impl FontStyle: u8 {
49 const BOLD = 0b00000001;
51 const ITALIC = 0b00000010;
53 }
54}
55
56#[derive(Clone, Debug)]
57pub struct FontInfo {
58 pub name: String,
59 pub path: std::path::PathBuf,
60 pub style: FontStyle,
61}
62
63#[derive(Clone, Debug)]
64pub struct FontInner {
65 pub info: FontInfo,
66 pub glyphs: HashMap<u32, Glyph>,
67 pub texture_buffer: Vec<u8>,
68 pub texture_width: u32,
69 pub texture_height: u32,
70 pub ascender: f32,
71 pub descender: f32,
72 pub line_height: f32,
73 pub space_width: f32,
74}
75
76#[derive(Clone, Debug)]
77pub struct Font {
78 pub(crate) inner: ArcRef<FontInner>,
79}
80
81const FONT_CACHE_MAGIC: [u8; 5] = *b"eFONT";
82const MAX_ATLAS_SIZE: usize = 2048; fn power_of_two(n: usize) -> usize {
85 let mut power = 1;
86 while power < n {
87 power *= 2;
88 }
89 power
90}
91
92#[derive(Clone, Debug)]
93pub enum FontBakeFormat {
94 GrayScale,
95 Rgba,
96}
97
98pub enum FontError {
99 InvalidFontData(String),
100 GlyphNotFound(u32),
101 IoError(std::io::Error),
102 InvalidSize(f32),
103 PackFailed(String),
104 FontError(String),
105}
106
107impl std::fmt::Debug for FontError {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 match self {
110 FontError::InvalidFontData(msg) => write!(f, "Invalid font data: {}", msg),
111 FontError::GlyphNotFound(codepoint) => write!(f, "Glyph not found for codepoint: {}", codepoint),
112 FontError::IoError(err) => write!(f, "IO error: {}", err),
113 FontError::InvalidSize(size) => write!(f, "Invalid size: {}", size),
114 FontError::PackFailed(msg) => write!(f, "Pack failed: {}", msg),
115 FontError::FontError(msg) => write!(f, "Font error: {}", msg),
116 }
117 }
118}
119
120impl Font {
121 pub(crate) fn new(info: FontInfo, size: f32, glyph_range: &[(u32, u32)]) -> Result<Self, FontError> {
122 let data = std::fs::read(&info.path).expect("Failed to read font file");
123 let font = fontdue::Font::from_bytes(data, fontdue::FontSettings::default())
124 .expect("Failed to parse font file");
125
126 let line_metrics = font.horizontal_line_metrics(size);
127 let pixel_gap = 2usize; if line_metrics.is_none() {
138 return Err(FontError::FontError(format!(
139 "Failed to get line metrics for font: {}",
140 info.path.display()
141 )));
142 }
143
144 let line_metrics = line_metrics.unwrap();
145
146 let ascender = line_metrics.ascent;
147 let descender = line_metrics.descent;
148 let line_height = line_metrics.ascent - line_metrics.descent + line_metrics.line_gap;
149 let space_metrics = font.metrics(' ', size);
150
151 let tex_width = {
154 let mut total_area = 0;
155
156 for &(start, end) in glyph_range {
157 for codepoint in start..=end {
158 let codepoint_char = std::char::from_u32(codepoint).unwrap_or_default();
159 let metrics = font.metrics(codepoint_char, size);
160
161 total_area += ((metrics.width + pixel_gap) * (metrics.height + pixel_gap)) as usize;
162 }
163 }
164
165 power_of_two((total_area as f32).sqrt().ceil() as usize) as i32
166 };
167
168 if tex_width > MAX_ATLAS_SIZE as i32 {
169 return Err(FontError::InvalidSize(tex_width as f32));
174 }
175
176 let rect_config = rect_packer::Config {
177 width: tex_width,
178 height: tex_width,
179 border_padding: 0,
180 rectangle_padding: pixel_gap as i32,
181 };
182
183 let mut packer = rect_packer::Packer::new(rect_config);
184 let mut raw_glyphs = Vec::new();
185 let mut max_size = Point2::new(0, 0);
186
187 for &(start, end) in glyph_range {
188 for codepoint in start..=end {
189 let codepoint_char = std::char::from_u32(codepoint).unwrap_or_default();
190 let (metrics, bitmap) = font.rasterize(codepoint_char, size);
191 if bitmap.is_empty() {
192 continue;
193 }
194
195 if let Some(rect) = packer.pack(metrics.width as i32, metrics.height as i32, false) {
196 raw_glyphs.push(
197 (rect, codepoint, metrics, bitmap)
198 );
199
200 max_size.x = max_size.x.max(rect.x + rect.width);
201 max_size.y = max_size.y.max(rect.y + rect.height);
202 } else {
203 return Err(FontError::PackFailed(format!(
213 "Failed to pack glyph: {} ({}x{}) with atlas size {}x{}",
214 codepoint_char, metrics.width, metrics.height, tex_width, tex_width
215 )));
216 }
217 }
218 }
219
220 let mut texture_buffer = vec![0; (max_size.x * max_size.y) as usize];
221 let mut glyphs = HashMap::new();
222
223 for (rect, codepoint, metrics, bitmap) in raw_glyphs {
224 let advance = metrics.advance_width as f32;
225 let glyph_width = metrics.width as usize;
226 let glyph_height = metrics.height as usize;
227
228 for j in 0..glyph_height {
229 for i in 0..glyph_width {
230 let src_index = j * glyph_width + i;
231 let dest_x = rect.x as usize + i;
232 let dest_y = rect.y as usize + j;
233 let dest_index = dest_y * max_size.x as usize + dest_x;
234
235 if dest_index < texture_buffer.len() && src_index < bitmap.len() {
236 texture_buffer[dest_index] = bitmap[src_index];
237 }
238 }
239 }
240
241 let start_offset = Vector2::new(rect.x as f32, rect.y as f32);
242 let end_offset = Vector2::new(
243 rect.x + glyph_width as i32,
244 rect.y + glyph_height as i32,
245 );
246
247 let glyph = Glyph {
248 codepoint,
249 advance,
250 atlas_start_offset: start_offset,
251 atlas_end_offset: end_offset,
252
253 width: glyph_width as f32,
254 height: glyph_height as f32,
255 bearing_x: metrics.xmin as f32,
256 bearing_y: metrics.ymin as f32,
257 advance_x: metrics.advance_width as f32,
258 advance_y: metrics.advance_height as f32,
259 ascender: -metrics.bounds.ymin.max(0.0) as f32,
260 descender: (metrics.bounds.ymin + metrics.bounds.height) as f32,
261 };
262
263 glyphs.insert(codepoint, glyph);
264 }
265
266 let inner = FontInner {
267 info,
268 glyphs,
269 texture_buffer,
270 texture_width: max_size.x as u32,
271 texture_height: max_size.y as u32,
272 ascender,
273 descender,
274 line_height,
275 space_width: space_metrics.advance_width as f32,
276 };
277
278 let inner = ArcRef::new(inner);
279
280 Ok(Font {
281 inner,
282 })
283 }
284
285 pub fn line_height(&self) -> f32 {
286 self.inner.borrow().line_height
287 }
288
289 pub fn ascender(&self) -> f32 {
290 self.inner.borrow().ascender
291 }
292
293 pub fn descender(&self) -> f32 {
294 self.inner.borrow().descender
295 }
296
297 pub fn space_width(&self) -> f32 {
298 self.inner.borrow().space_width
299 }
300
301 pub fn texture_size(&self) -> Point2 {
302 let inner = self.inner.borrow();
303 Point2::new(inner.texture_width as i32, inner.texture_height as i32)
304 }
305
306 pub fn calculate_text_size(&self, text: &str, max_bounds: Option<Vector2>) -> Vector2 {
307 let inner = self.inner.borrow();
308
309 let mut width = 0.0f32;
310 let mut height = inner.line_height;
311
312 let mut pen_x = 0.0;
313
314 for c in text.chars() {
315 let codepoint = c as u32;
316 if codepoint == '\n' as u32 {
317 width = width.max(pen_x);
318 pen_x = 0.0;
319 height += inner.line_height;
320 continue;
321 }
322
323 if codepoint == ' ' as u32 {
324 pen_x += inner.space_width;
325 continue;
326 }
327
328 if let Some(glyph) = inner.glyphs.get(&codepoint) {
329 if max_bounds.is_some() {
330 let max_bounds = max_bounds.unwrap();
331
332 if pen_x + glyph.advance_x > max_bounds.x {
333 width = width.max(pen_x);
334 pen_x = 0.0;
335 height += inner.line_height;
336 }
337 }
338
339 pen_x += glyph.advance_x;
340 }
341 }
342
343 width = width.max(pen_x);
344
345 Vector2::new(width, height)
346 }
347
348 pub fn create_baked_text_raw(
352 &self,
353 text: &str,
354 format: FontBakeFormat,
355 max_bounds: Option<Vector2>,
356 ) -> Result<(Vec<u8>, u32, u32), String> {
357 let inner = self.inner.borrow();
358
359 let mut pen = Vector2::new(0.0, 0.0);
360
361 let mut min_x = f32::MAX;
363 let mut min_y = f32::MAX;
364 let mut max_x = f32::MIN;
365 let mut max_y = f32::MIN;
366
367 for c in text.chars() {
370 let codepoint = c as u32;
371 if codepoint == '\n' as u32 {
372 pen.x = 0.0;
373 pen.y += inner.line_height as f32;
374 continue;
375 }
376
377 if codepoint == ' ' as u32 {
378 pen.x += inner.space_width;
379 continue;
380 }
381
382 if let Some(glyph) = inner.glyphs.get(&codepoint) {
383 let x0 = pen.x + glyph.bearing_x;
384 let y0 = pen.y + inner.ascender - (glyph.height + glyph.bearing_y);
385 let x1 = x0 + glyph.width;
386 let y1 = y0 + glyph.height;
387
388 if max_bounds.is_some() {
389 let max_bounds = max_bounds.unwrap();
390 if pen.x + glyph.advance_x > max_bounds.x {
391 pen.x = 0.0;
392 pen.y += inner.line_height as f32;
393 }
394 }
395
396 min_x = min_x.min(x0);
397 min_y = min_y.min(y0);
398 max_x = max_x.max(x1);
399 max_y = max_y.max(y1);
400
401 pen.x += glyph.advance_x;
402 }
403 }
404
405 if min_x == f32::MAX || min_y == f32::MAX {
407 return Err("No glyphs found".to_string());
408 }
409
410 let width = (max_x - min_x).ceil().max(1.0) as usize;
411 let height = (max_y - min_y).ceil().max(1.0) as usize;
412 let mut buffer = vec![0; width * height];
413
414 let mut pen2 = Vector2::new(0.0, 0.0);
415
416 for c in text.chars() {
417 let codepoint = c as u32;
418 if codepoint == '\n' as u32 {
419 pen2.x = 0.0;
420 pen2.y += inner.line_height as f32;
421 continue;
422 }
423
424 if codepoint == ' ' as u32 {
425 pen2.x += inner.space_width;
426 continue;
427 }
428
429 if max_bounds.is_some() {
430 let max_bounds = max_bounds.unwrap();
431 if pen2.x + inner.space_width > max_bounds.x {
432 pen2.x = 0.0;
433 pen2.y += inner.line_height as f32;
434 }
435 }
436
437 if let Some(glyph) = inner.glyphs.get(&codepoint) {
438 let x0 = pen2.x + glyph.bearing_x - min_x;
439 let y0 = pen2.y + inner.ascender - (glyph.height + glyph.bearing_y) - min_y;
440
441 let atlas_offset_x = glyph.atlas_start_offset.x as usize;
442 let atlas_offset_y = glyph.atlas_start_offset.y as usize;
443 let atlas_width = inner.texture_width as usize;
444 let atlas_height = inner.texture_height as usize;
445
446 for y in 0..glyph.height as usize {
447 let src_start = (atlas_offset_y + y) * atlas_width + atlas_offset_x;
448 let dest_start = (y0 as usize + y) * width + x0 as usize;
449
450 for x in 0..glyph.width as usize {
451 let src_index = src_start + x;
452 let dest_index = dest_start + x;
453
454 if src_index < atlas_width * atlas_height && dest_index < buffer.len() {
455 buffer[dest_index] = inner.texture_buffer[src_index];
456 }
457 }
458 }
459
460 pen2.x += glyph.advance_x;
461 }
462 }
463
464 match format {
465 FontBakeFormat::GrayScale => Ok((buffer, width as u32, height as u32)),
466 FontBakeFormat::Rgba => {
467 let mut rgba_buffer = Vec::with_capacity(width * height * 4);
468 for byte in buffer.iter() {
469 let is_transparent = *byte == 0;
470
471 rgba_buffer.push(*byte);
472 rgba_buffer.push(*byte);
473 rgba_buffer.push(*byte);
474 rgba_buffer.push(if is_transparent { 0 } else { 255 });
475 }
476
477 Ok((rgba_buffer, width as u32, height as u32))
478 }
479 }
480 }
481
482 pub(crate) fn new_cached(path: &str) -> Result<Self, std::io::Error> {
483 let data = std::fs::read(path)?;
484 let mut reader = std::io::Cursor::new(data);
485
486 let mut magic = [0; 5];
487 reader.read_exact(&mut magic)?;
488 if magic != FONT_CACHE_MAGIC {
489 return Err(std::io::Error::new(
490 std::io::ErrorKind::InvalidData,
491 "Invalid font cache file",
492 ));
493 }
494
495 let compressed_size = reader.read_u32::<LittleEndian>()?;
496 let uncompressed_size = reader.read_u32::<LittleEndian>()?;
497
498 let mut compressed_data = vec![0; compressed_size as usize];
499 reader.read_exact(&mut compressed_data)?;
500
501 let mut decoder = ZlibDecoder::new(&compressed_data[..]);
502 let mut decompressed_data = Vec::with_capacity(uncompressed_size as usize);
503 decoder.read_to_end(&mut decompressed_data)?;
504
505 let mut reader = std::io::Cursor::new(decompressed_data);
506
507 let font_family_name_len = reader.read_u32::<LittleEndian>()?;
508 let mut font_family_name = vec![0; font_family_name_len as usize];
509 reader.read_exact(&mut font_family_name)?;
510 let font_family_name = String::from_utf8(font_family_name).map_err(|_| {
511 std::io::Error::new(
512 std::io::ErrorKind::InvalidData,
513 "Invalid UTF-8 in font family name",
514 )
515 })?;
516 let font_style = reader.read_u8()?;
517 let font_style = FontStyle::from_bits(font_style).ok_or_else(|| {
518 std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid font style")
519 })?;
520
521 let info = FontInfo {
522 name: font_family_name,
523 path: std::path::PathBuf::from(path),
524 style: font_style,
525 };
526
527 let num_glyphs = reader.read_u32::<LittleEndian>()?;
528 let mut glyphs = HashMap::new();
529 for _ in 0..num_glyphs {
530 let codepoint = reader.read_u32::<LittleEndian>()?;
531 let advance = reader.read_f32::<LittleEndian>()?;
532 let atlas_start_offset = Vector2::new(
533 reader.read_f32::<LittleEndian>()?,
534 reader.read_f32::<LittleEndian>()?,
535 );
536 let atlas_end_offset = Vector2::new(
537 reader.read_f32::<LittleEndian>()?,
538 reader.read_f32::<LittleEndian>()?,
539 );
540 let width = reader.read_f32::<LittleEndian>()?;
541 let height = reader.read_f32::<LittleEndian>()?;
542 let bearing_x = reader.read_f32::<LittleEndian>()?;
543 let bearing_y = reader.read_f32::<LittleEndian>()?;
544 let advance_x = reader.read_f32::<LittleEndian>()?;
545 let advance_y = reader.read_f32::<LittleEndian>()?;
546 let ascender = reader.read_f32::<LittleEndian>()?;
547 let descender = reader.read_f32::<LittleEndian>()?;
548
549 let glyph = Glyph {
550 codepoint,
551 advance,
552 atlas_start_offset,
553 atlas_end_offset,
554 width,
555 height,
556 bearing_x,
557 bearing_y,
558 advance_x,
559 advance_y,
560 ascender,
561 descender,
562 };
563
564 glyphs.insert(codepoint, glyph);
565 }
566
567 let texture_buffer_width = reader.read_u32::<LittleEndian>()?;
568 let texture_buffer_height = reader.read_u32::<LittleEndian>()?;
569
570 if texture_buffer_width > MAX_ATLAS_SIZE as u32
571 || texture_buffer_height > MAX_ATLAS_SIZE as u32
572 {
573 return Err(std::io::Error::new(
574 std::io::ErrorKind::InvalidData,
575 "Invalid texture buffer size",
576 ));
577 }
578
579 let mut texture_buffer = vec![0; (texture_buffer_width * texture_buffer_height) as usize];
580 reader.read_exact(&mut texture_buffer)?;
581
582 let ascender = reader.read_f32::<LittleEndian>()?;
583 let descender = reader.read_f32::<LittleEndian>()?;
584 let line_height = reader.read_f32::<LittleEndian>()?;
585 let space_width = reader.read_f32::<LittleEndian>()?;
586
587 let inner = FontInner {
588 info,
589 glyphs,
590 texture_buffer,
591 texture_width: texture_buffer_width,
592 texture_height: texture_buffer_height,
593 ascender,
594 descender,
595 line_height,
596 space_width,
597 };
598
599 let inner = ArcRef::new(inner);
600
601 Ok(Font {
602 inner: ArcRef::clone(&inner),
603 })
604 }
605
606 pub fn save_font_cache(&self, path: &str) -> Result<(), std::io::Error> {
610 let mut writer = std::fs::File::create(path)?;
611 writer.write_all(&FONT_CACHE_MAGIC)?;
612
613 let inner = self.inner.borrow();
614
615 let mut writer2 = std::io::Cursor::new(Vec::<u8>::new());
616
617 writer2.write_u32::<LittleEndian>(inner.info.name.len() as u32)?;
618 writer2.write_all(inner.info.name.as_bytes())?;
619 writer2.write_u8(inner.info.style.bits())?;
620
621 writer2.write_u32::<LittleEndian>(inner.glyphs.len() as u32)?;
622 for (_index, glyph) in inner.glyphs.iter() {
623 writer2.write_u32::<LittleEndian>(glyph.codepoint)?;
624 writer2.write_f32::<LittleEndian>(glyph.advance)?;
625 writer2.write_f32::<LittleEndian>(glyph.atlas_start_offset.x)?;
626 writer2.write_f32::<LittleEndian>(glyph.atlas_start_offset.y)?;
627 writer2.write_f32::<LittleEndian>(glyph.atlas_end_offset.x)?;
628 writer2.write_f32::<LittleEndian>(glyph.atlas_end_offset.y)?;
629 writer2.write_f32::<LittleEndian>(glyph.width)?;
630 writer2.write_f32::<LittleEndian>(glyph.height)?;
631 writer2.write_f32::<LittleEndian>(glyph.bearing_x)?;
632 writer2.write_f32::<LittleEndian>(glyph.bearing_y)?;
633 writer2.write_f32::<LittleEndian>(glyph.advance_x)?;
634 writer2.write_f32::<LittleEndian>(glyph.advance_y)?;
635 writer2.write_f32::<LittleEndian>(glyph.ascender)?;
636 writer2.write_f32::<LittleEndian>(glyph.descender)?;
637 }
638
639 writer2.write_u32::<LittleEndian>(inner.texture_width)?;
640 writer2.write_u32::<LittleEndian>(inner.texture_height)?;
641 writer2.write_all(&inner.texture_buffer)?;
642
643 writer2.write_f32::<LittleEndian>(inner.ascender)?;
644 writer2.write_f32::<LittleEndian>(inner.descender)?;
645 writer2.write_f32::<LittleEndian>(inner.line_height)?;
646 writer2.write_f32::<LittleEndian>(inner.space_width)?;
647
648 let uncompressed_data: Vec<u8> = writer2.into_inner();
649 let uncompressed_size = uncompressed_data.len() as u32;
650
651 let mut compressed_data =
652 flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
653 compressed_data.write_all(&uncompressed_data)?;
654
655 let compressed_data = compressed_data.finish()?;
656
657 writer.write_u32::<LittleEndian>(compressed_data.len() as u32)?;
658 writer.write_u32::<LittleEndian>(uncompressed_size as u32)?;
659 writer.write_all(&compressed_data)?;
660
661 Ok(())
662 }
663
664 pub fn get_image_data(&self) -> (Vec<u8>, u32, u32) {
666 let inner = self.inner.borrow();
667 (
668 inner.texture_buffer.clone(),
669 inner.texture_width,
670 inner.texture_height,
671 )
672 }
673
674 pub fn get_glyph(&self, codepoint: u32) -> Result<Glyph, FontError> {
676 let inner = self.inner.borrow();
677
678 inner
679 .glyphs
680 .get(&codepoint)
681 .cloned()
682 .ok_or(FontError::GlyphNotFound(codepoint))
683 }
684
685 pub fn create_baked_text(
689 &self,
690 gpu: &mut GPU,
691 text: &str,
692 max_bounds: Option<Vector2>,
693 ) -> Result<Texture, TextureError> {
694 let (image_data, width, height) = self.create_baked_text_raw(text, FontBakeFormat::Rgba, max_bounds)
695 .map_err(|_| TextureError::InvalidTextureData)?;
696
697 let format = {
698 let gpu_inner = gpu.inner.borrow();
699
700 if gpu_inner.is_srgb() {
701 TextureFormat::Bgra8UnormSrgb
702 } else {
703 TextureFormat::Bgra8Unorm
704 }
705 };
706
707 let texture = gpu
708 .create_texture()
709 .set_raw_image(&image_data, Point2::new(width as i32, height as i32), format)
710 .set_usage(TextureUsage::Sampler)
711 .build()?;
712
713 Ok(texture)
714 }
715
716 pub fn create_texture(&self, gpu: &mut GPU) -> Result<Texture, TextureError> {
718 let gpu_inner = &gpu.inner;
719
720 self.create_texture_inner(&gpu_inner)
721 }
722
723 pub(crate) fn create_texture_inner(
724 &self,
725 gpu: &ArcRef<GPUInner>,
726 ) -> Result<Texture, TextureError> {
727 let (image_data, width, height) = self.get_image_data();
728
729 let format = {
730 let gpu_inner = gpu.borrow();
731
732 if gpu_inner.is_srgb() {
733 TextureFormat::Bgra8UnormSrgb
734 } else {
735 TextureFormat::Bgra8Unorm
736 }
737 };
738
739 let image_data = {
740 let mut data = Vec::with_capacity(image_data.len() * 4);
741 for &pixel in &image_data {
742 let is_transparent_pixel = pixel == 0;
743 data.push(pixel);
744 data.push(pixel);
745 data.push(pixel);
746 data.push(if is_transparent_pixel { 0 } else { 255 });
747 }
748
749 data
750 };
751
752 let texture = TextureBuilder::new(ArcRef::clone(gpu))
753 .set_raw_image(
754 &image_data,
755 Point2::new(width as i32, height as i32),
756 format,
757 )
758 .set_usage(TextureUsage::Sampler)
759 .build()?;
760
761 Ok(texture)
762 }
763}
764
765#[derive(Clone, Debug)]
766pub struct Glyph {
767 pub codepoint: u32,
768 pub advance: f32,
769 pub atlas_start_offset: Vector2,
770 pub atlas_end_offset: Vector2,
771
772 pub width: f32,
774 pub height: f32,
775 pub bearing_x: f32,
776 pub bearing_y: f32,
777 pub advance_x: f32,
778 pub advance_y: f32,
779 pub ascender: f32,
780 pub descender: f32,
781}
782
783impl Eq for Glyph {}
784
785impl PartialEq for Glyph {
786 fn eq(&self, other: &Self) -> bool {
787 self.codepoint == other.codepoint
788 }
789}
790
791#[derive(Clone, Debug)]
792pub struct FontManager {
793 fonts: Vec<FontInfo>,
794 cached_font: HashMap<u64, Font>,
795}
796
797const DEFAULT_GLYPH_RANGE: [(u32, u32); 1] = [(0x20, 0x7E)]; impl FontManager {
800 pub fn new() -> Self {
805 let fonts = system::search_system_font();
806 FontManager {
807 fonts,
808 cached_font: HashMap::new(),
809 }
810 }
811
812 pub fn load_font(
817 &mut self,
818 font_name: &str,
819 glyph_range: Option<&[(u32, u32)]>,
820 size: f32,
821 ) -> Result<Font, FontError> {
822 let glyph_range = glyph_range.unwrap_or(&DEFAULT_GLYPH_RANGE);
823
824 let hashed_name = {
825 let mut hasher = std::collections::hash_map::DefaultHasher::new();
826 font_name.hash(&mut hasher);
827 for (start, end) in glyph_range {
828 start.hash(&mut hasher);
829 end.hash(&mut hasher);
830 }
831 size.to_bits().hash(&mut hasher);
832 hasher.finish()
833 };
834
835 if self.cached_font.contains_key(&hashed_name) {
836 return Ok(self.cached_font.get(&hashed_name).unwrap().clone());
837 }
838
839 if std::path::Path::new(font_name).exists() {
840 let path = std::path::Path::new(font_name);
841
842 let font_info = system::get_font_info(path);
843 if font_info.is_none() {
844 return Err(FontError::InvalidFontData(format!(
845 "Failed to load font from path: {}",
846 font_name
847 )));
848 }
849
850 let font_info = font_info.unwrap();
851 let font = Font::new(font_info, size, glyph_range);
852 if font.is_err() {
853 return Err(font.err().unwrap());
854 }
855
856 let font = font.unwrap();
857 self.cached_font.insert(hashed_name, font.clone());
858
859 return Ok(font);
860 } else {
861 for font in &self.fonts {
862 if font.name == font_name {
863 let font = Font::new(font.clone(), size, glyph_range);
864
865 if font.is_err() {
866 return Err(font.err().unwrap());
867 }
868
869 let font = font.unwrap();
870 self.cached_font.insert(hashed_name, font.clone());
871
872 return Ok(font);
873 }
874 }
875 }
876
877 Err(FontError::InvalidFontData(format!(
878 "Font not found: {}",
879 font_name
880 )))
881 }
882
883 pub fn load_font_cached(&mut self, path: &str) -> Option<Font> {
888 let hash_id = {
889 let mut hasher = std::collections::hash_map::DefaultHasher::new();
890 path.hash(&mut hasher);
891 hasher.finish()
892 };
893
894 if self.cached_font.contains_key(&hash_id) {
895 return self.cached_font.get(&hash_id).cloned();
896 }
897
898 match Font::new_cached(path) {
899 Ok(font) => {
900 self.cached_font.insert(hash_id, font.clone());
901 Some(font)
902 }
903 Err(_) => None,
904 }
905 }
906}