text_typeset/font/
resolve.rs1use crate::font::registry::FontRegistry;
2use crate::types::FontFaceId;
3
4pub struct ResolvedFont {
6 pub font_face_id: FontFaceId,
7 pub size_px: f32,
8 pub face_index: u32,
9 pub swash_cache_key: swash::CacheKey,
10}
11
12pub fn resolve_font(
20 registry: &FontRegistry,
21 font_family: Option<&str>,
22 font_weight: Option<u32>,
23 font_bold: Option<bool>,
24 font_italic: Option<bool>,
25 font_point_size: Option<u32>,
26) -> Option<ResolvedFont> {
27 let weight = resolve_weight(font_weight, font_bold);
28 let italic = font_italic.unwrap_or(false);
29 let size_px = font_point_size
30 .map(|s| s as f32)
31 .unwrap_or(registry.default_size_px());
32
33 if let Some(family) = font_family
35 && let Some(face_id) = registry.query_font(family, weight, italic)
36 {
37 let entry = registry.get(face_id)?;
38 return Some(ResolvedFont {
39 font_face_id: face_id,
40 size_px,
41 face_index: entry.face_index,
42 swash_cache_key: entry.swash_cache_key,
43 });
44 }
45
46 let default_id = registry.default_font()?;
49 if (weight != 400 || italic)
50 && let Some(variant_id) = registry.query_variant(default_id, weight, italic)
51 {
52 let variant_entry = registry.get(variant_id)?;
53 return Some(ResolvedFont {
54 font_face_id: variant_id,
55 size_px,
56 face_index: variant_entry.face_index,
57 swash_cache_key: variant_entry.swash_cache_key,
58 });
59 }
60 let entry = registry.get(default_id)?;
61 Some(ResolvedFont {
62 font_face_id: default_id,
63 size_px,
64 face_index: entry.face_index,
65 swash_cache_key: entry.swash_cache_key,
66 })
67}
68
69pub fn font_has_glyph(registry: &FontRegistry, face_id: FontFaceId, ch: char) -> bool {
73 let entry = match registry.get(face_id) {
74 Some(e) => e,
75 None => return false,
76 };
77 let font_ref = match swash::FontRef::from_index(&entry.data, entry.face_index as usize) {
78 Some(f) => f,
79 None => return false,
80 };
81 font_ref.charmap().map(ch) != 0
82}
83
84pub fn find_fallback_font(
86 registry: &FontRegistry,
87 ch: char,
88 exclude: FontFaceId,
89) -> Option<FontFaceId> {
90 for (face_id, entry) in registry.all_entries() {
91 if face_id == exclude {
92 continue;
93 }
94 let font_ref = match swash::FontRef::from_index(&entry.data, entry.face_index as usize) {
95 Some(f) => f,
96 None => continue,
97 };
98 if font_ref.charmap().map(ch) != 0 {
99 return Some(face_id);
100 }
101 }
102 None
103}
104
105fn resolve_weight(font_weight: Option<u32>, font_bold: Option<bool>) -> u16 {
107 if let Some(w) = font_weight {
108 return w.min(1000) as u16;
109 }
110 if font_bold == Some(true) {
111 return 700;
112 }
113 400 }