ferroui_base/media/fonts/
system_font_collection.rs1use std::rc::Rc;
2
3use crate::media::fonts::font_collection_base::equals_ordinal_ignore_case;
4use crate::media::fonts::{FontCollectionBase, FontCollectionBaseImpl, FontCollectionKey};
5use crate::media::{
6 FontFamily, FontManager, FontSimulations, FontStretch, FontStyle, FontWeight, GlyphTypeface, Typeface,
7};
8use crate::platform::IFontManagerImpl;
9use crate::utilities::{CultureInfo, Uri};
10
11pub struct SystemFontCollection {
14 base: FontCollectionBase,
15 platform_impl: Rc<dyn IFontManagerImpl>,
16}
17
18impl SystemFontCollection {
19 pub fn new(platform_impl: Rc<dyn IFontManagerImpl>) -> Self {
20 let collection = Self { base: FontCollectionBase::new(), platform_impl };
21
22 for family_name in collection.platform_impl.get_installed_font_family_names(false) {
23 if !family_name.is_empty() {
24 collection.base.add_font_family(FontFamily::new(&family_name));
25 }
26 }
27
28 collection
29 }
30}
31
32impl FontCollectionBaseImpl for SystemFontCollection {
33 fn base(this: &Self) -> &FontCollectionBase {
34 &this.base
35 }
36
37 fn key(_this: &Self) -> Uri {
38 FontManager::system_fonts_key()
39 }
40
41 fn try_get_glyph_typeface(
42 this: &Self,
43 family_name: &str,
44 style: FontStyle,
45 weight: FontWeight,
46 stretch: FontStretch,
47 ) -> Option<Rc<GlyphTypeface>> {
48 let (typeface, family_name) =
49 Typeface::from_name_with_style(family_name, style, weight, stretch).normalize();
50 let family_name = family_name.as_str();
51 let key = FontCollectionKey::from(&typeface);
52
53 if let Some(glyph_typeface) = FontCollectionBase::try_get_glyph_typeface_by_key(this, family_name, key, false)
55 {
56 return Some(glyph_typeface);
57 }
58
59 if let Some(glyph_typefaces) = this.base.glyph_typeface_cache().try_get_value(family_name) {
61 if let Some(glyph_typeface) = glyph_typefaces.borrow().get(&key) {
62 return glyph_typeface.clone();
63 }
64 }
65
66 let Some(platform_typeface) = this.platform_impl.try_create_glyph_typeface(family_name, style, weight, stretch)
68 else {
69 FontCollectionBase::try_add_glyph_typeface_by_name(this, family_name, key, None);
71
72 return None;
73 };
74
75 if key != FontCollectionKey::from(&*platform_typeface) {
77 if let Some(glyph_typeface) =
78 FontCollectionBase::try_get_glyph_typeface_by_key(this, family_name, key, true)
79 {
80 return Some(glyph_typeface);
81 }
82 }
83
84 let platform_family_name = platform_typeface.family_name();
85
86 let glyph_typeface = GlyphTypeface::try_create(platform_typeface, FontSimulations::None)?;
87
88 FontCollectionBase::try_add_glyph_typeface_by_name(
90 this,
91 &platform_family_name,
92 key,
93 Some(glyph_typeface.clone()),
94 );
95
96 if !equals_ordinal_ignore_case(family_name, &platform_family_name) {
98 FontCollectionBase::try_add_glyph_typeface_by_name(this, family_name, key, Some(glyph_typeface.clone()));
99 }
100
101 if !FontCollectionBase::try_add_glyph_typeface(this, &glyph_typeface) {
103 return this
106 .base
107 .glyph_typeface_cache()
108 .try_get_value(family_name)
109 .and_then(|existing_map| existing_map.borrow().get(&key).cloned().flatten());
110 }
111
112 FontCollectionBase::try_get_glyph_typeface_by_key(this, family_name, key, false)
114 }
115
116 fn try_get_family_typefaces(this: &Self, family_name: &str) -> Option<Vec<Typeface>> {
117 this.platform_impl.try_get_family_typefaces(family_name)
118 }
119
120 fn try_match_character(
121 this: &Self,
122 codepoint: i32,
123 style: FontStyle,
124 weight: FontWeight,
125 stretch: FontStretch,
126 family_name: Option<&str>,
127 culture: Option<&CultureInfo>,
128 ) -> Option<Typeface> {
129 FontCollectionBase::try_match_character(this, codepoint, style, weight, stretch, family_name, culture)
133 }
134
135 fn try_match_character_from_platform(
136 this: &Self,
137 codepoint: i32,
138 key: FontCollectionKey,
139 family_name: Option<&str>,
140 culture: Option<&CultureInfo>,
141 ) -> Option<Rc<GlyphTypeface>> {
142 let platform_typeface =
143 this.platform_impl.try_match_character(codepoint, key.style, key.weight, key.stretch, family_name, culture)?;
144
145 let platform_key = FontCollectionKey::from(&*platform_typeface);
146 let platform_family_name = platform_typeface.family_name();
147
148 if let Some(glyph_typefaces) = this.base.glyph_typeface_cache().try_get_value(&platform_family_name) {
150 if let Some(Some(existing)) = glyph_typefaces.borrow().get(&platform_key) {
151 return Some(existing.clone());
152 }
153 }
154
155 let glyph_typeface = GlyphTypeface::try_create(platform_typeface, FontSimulations::None)?;
156
157 FontCollectionBase::try_add_glyph_typeface_by_name(
160 this,
161 &platform_family_name,
162 platform_key,
163 Some(glyph_typeface.clone()),
164 );
165 FontCollectionBase::try_add_glyph_typeface_with_key(this, &glyph_typeface, platform_key);
166
167 Some(glyph_typeface)
168 }
169}