1use cosmic_text::{Attrs, fontdb};
2use std::sync::{Arc, RwLock};
3
4pub struct FontDatabase {
6 inner: fontdb::Database,
7}
8
9impl FontDatabase {
10 pub fn new() -> Self {
12 let mut db = fontdb::Database::new();
13 db.load_system_fonts();
14 Self { inner: db }
15 }
16
17 pub fn empty() -> Self {
19 Self {
20 inner: fontdb::Database::new(),
21 }
22 }
23
24 pub fn load_font_data(&mut self, data: Vec<u8>) {
26 self.inner
27 .load_font_source(fontdb::Source::Binary(Arc::new(data)));
28 }
29
30 pub fn load_font_file(&mut self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
32 self.inner.load_font_file(path)?;
33 Ok(())
34 }
35
36 pub fn load_fonts_dir(&mut self, path: impl AsRef<std::path::Path>) {
38 self.inner.load_fonts_dir(path);
39 }
40
41 pub fn has_family(&self, family: &str) -> bool {
44 self.inner
45 .faces()
46 .any(|face| face.families.iter().any(|(f, _)| f == family))
47 }
48
49 pub fn list_families(&self) -> Vec<String> {
51 let mut families = std::collections::HashSet::new();
52 for face in self.inner.faces() {
53 for (family, _) in &face.families {
54 families.insert(family.clone());
55 }
56 }
57 let mut families: Vec<String> = families.into_iter().collect();
58 families.sort();
59 families
60 }
61
62 pub fn len(&self) -> usize {
64 self.inner.len()
65 }
66
67 pub fn is_empty(&self) -> bool {
69 self.len() == 0
70 }
71}
72
73impl Default for FontDatabase {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79pub struct FontSystem {
81 inner: Arc<RwLock<cosmic_text::FontSystem>>,
82}
83
84impl FontSystem {
85 pub fn new(db: FontDatabase) -> Self {
87 let cosmic_font_system = cosmic_text::FontSystem::new_with_locale_and_db(
88 sys_locale::get_locale().unwrap_or_else(|| String::from("en-US")),
89 db.inner,
90 );
91 Self {
92 inner: Arc::new(RwLock::new(cosmic_font_system)),
93 }
94 }
95
96 pub fn with_system_fonts() -> Self {
98 Self::new(FontDatabase::new())
99 }
100
101 pub(crate) fn inner(&self) -> Arc<RwLock<cosmic_text::FontSystem>> {
102 self.inner.clone()
103 }
104}
105
106impl Default for FontSystem {
107 fn default() -> Self {
108 Self::with_system_fonts()
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum FontWeight {
115 Thin,
116 ExtraLight,
117 Light,
118 Normal,
119 Medium,
120 SemiBold,
121 Bold,
122 ExtraBold,
123 Black,
124}
125
126impl FontWeight {
127 pub(crate) fn to_cosmic(self) -> cosmic_text::Weight {
128 match self {
129 FontWeight::Thin => cosmic_text::Weight::THIN,
130 FontWeight::ExtraLight => cosmic_text::Weight::EXTRA_LIGHT,
131 FontWeight::Light => cosmic_text::Weight::LIGHT,
132 FontWeight::Normal => cosmic_text::Weight::NORMAL,
133 FontWeight::Medium => cosmic_text::Weight::MEDIUM,
134 FontWeight::SemiBold => cosmic_text::Weight::SEMIBOLD,
135 FontWeight::Bold => cosmic_text::Weight::BOLD,
136 FontWeight::ExtraBold => cosmic_text::Weight::EXTRA_BOLD,
137 FontWeight::Black => cosmic_text::Weight::BLACK,
138 }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub enum FontStyle {
145 Normal,
146 Italic,
147 Oblique,
148}
149
150impl FontStyle {
151 pub(crate) fn to_cosmic(self) -> cosmic_text::Style {
152 match self {
153 FontStyle::Normal => cosmic_text::Style::Normal,
154 FontStyle::Italic => cosmic_text::Style::Italic,
155 FontStyle::Oblique => cosmic_text::Style::Oblique,
156 }
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum FontStretch {
163 UltraCondensed,
164 ExtraCondensed,
165 Condensed,
166 SemiCondensed,
167 Normal,
168 SemiExpanded,
169 Expanded,
170 ExtraExpanded,
171 UltraExpanded,
172}
173
174impl FontStretch {
175 pub(crate) fn to_cosmic(self) -> cosmic_text::Stretch {
176 match self {
177 FontStretch::UltraCondensed => cosmic_text::Stretch::UltraCondensed,
178 FontStretch::ExtraCondensed => cosmic_text::Stretch::ExtraCondensed,
179 FontStretch::Condensed => cosmic_text::Stretch::Condensed,
180 FontStretch::SemiCondensed => cosmic_text::Stretch::SemiCondensed,
181 FontStretch::Normal => cosmic_text::Stretch::Normal,
182 FontStretch::SemiExpanded => cosmic_text::Stretch::SemiExpanded,
183 FontStretch::Expanded => cosmic_text::Stretch::Expanded,
184 FontStretch::ExtraExpanded => cosmic_text::Stretch::ExtraExpanded,
185 FontStretch::UltraExpanded => cosmic_text::Stretch::UltraExpanded,
186 }
187 }
188}
189
190#[derive(Debug, Clone)]
192pub struct FontAttributes {
193 pub family: String,
194 pub weight: FontWeight,
195 pub style: FontStyle,
196 pub stretch: FontStretch,
197}
198
199impl FontAttributes {
200 pub fn new(family: impl Into<String>) -> Self {
207 Self {
208 family: family.into(),
209 weight: FontWeight::Normal,
210 style: FontStyle::Normal,
211 stretch: FontStretch::Normal,
212 }
213 }
214
215 pub fn sans_serif() -> Self {
217 Self::new("sans-serif")
218 }
219
220 pub fn serif() -> Self {
222 Self::new("serif")
223 }
224
225 pub fn monospace() -> Self {
227 Self::new("monospace")
228 }
229
230 pub fn weight(mut self, weight: FontWeight) -> Self {
231 self.weight = weight;
232 self
233 }
234
235 pub fn style(mut self, style: FontStyle) -> Self {
236 self.style = style;
237 self
238 }
239
240 pub fn stretch(mut self, stretch: FontStretch) -> Self {
241 self.stretch = stretch;
242 self
243 }
244
245 pub(crate) fn to_cosmic(&self) -> Attrs<'_> {
246 Attrs::new()
247 .family(cosmic_text::Family::Name(&self.family))
248 .weight(self.weight.to_cosmic())
249 .style(self.style.to_cosmic())
250 .stretch(self.stretch.to_cosmic())
251 }
252}
253
254impl Default for FontAttributes {
255 fn default() -> Self {
256 Self {
257 family: String::from("sans-serif"),
258 weight: FontWeight::Normal,
259 style: FontStyle::Normal,
260 stretch: FontStretch::Normal,
261 }
262 }
263}