1use super::{FontStyle, FontWeight, FontWidth};
11use fontique::{
12 Attributes, Collection, FamilyId, GenericFamily, QueryFamily, QueryFont, QueryStatus, Script,
13 SourceCache,
14};
15use log::debug;
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18use std::collections::HashMap;
19use std::collections::hash_map::Entry;
20use std::hash::{BuildHasher, Hash};
21
22pub struct Resolver {
24 collection: Collection,
25 cache: SourceCache,
26 families: HashMap<FamilySelector, FamilySet>,
28}
29
30impl Resolver {
31 pub(crate) fn new() -> Self {
32 Resolver {
33 collection: Collection::new(Default::default()),
34 cache: SourceCache::new(Default::default()),
35 families: HashMap::new(),
36 }
37 }
38
39 pub fn font_family(&mut self, id: FamilyId) -> Option<&str> {
41 self.collection.family_name(id)
42 }
43
44 pub fn font_family_from_generic(&mut self, generic: GenericFamily) -> Option<&str> {
46 let id = self.collection.generic_families(generic).next()?;
47 self.collection.family_name(id)
48 }
49
50 pub fn select_families<I, F>(&mut self, families: I) -> FamilySelector
52 where
53 I: IntoIterator<Item = F>,
54 F: Into<FamilyName>,
55 {
56 let set = FamilySet(families.into_iter().map(|f| f.into()).collect());
57 let hash = self.families.hasher().hash_one(&set);
58 let sel = FamilySelector(hash | (1 << 63));
59
60 match self.families.entry(sel) {
61 Entry::Vacant(entry) => {
62 entry.insert(set);
63 }
64 Entry::Occupied(entry) => {
65 log::warn!(
67 "Resolver::select_families: hash collision for family selector {set:?} and {:?}",
68 entry.get()
69 );
70 }
72 }
73
74 sel
75 }
76
77 pub fn resolve_families(&self, selector: &FamilySelector) -> Vec<FamilyName> {
81 if let Some(gf) = selector.as_generic() {
82 vec![FamilyName::Generic(gf)]
83 } else if let Some(set) = self.families.get(selector) {
84 set.0.clone()
85 } else {
86 vec![]
87 }
88 }
89}
90
91#[derive(Clone, Debug, Eq, PartialEq, Hash)]
93#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
94pub enum FamilyName {
95 Named(String),
97 #[cfg_attr(feature = "serde", serde(with = "remote::GenericFamily"))]
99 Generic(GenericFamily),
100}
101
102impl From<GenericFamily> for FamilyName {
103 fn from(gf: GenericFamily) -> Self {
104 FamilyName::Generic(gf)
105 }
106}
107
108impl<'a> From<&'a FamilyName> for QueryFamily<'a> {
109 fn from(family: &'a FamilyName) -> Self {
110 match family {
111 FamilyName::Named(name) => QueryFamily::Named(name),
112 FamilyName::Generic(gf) => QueryFamily::Generic(*gf),
113 }
114 }
115}
116
117#[derive(Clone, Debug, PartialEq, Eq, Hash)]
118struct FamilySet(Vec<FamilyName>);
119
120#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
127pub struct FamilySelector(u64);
128
129impl FamilySelector {
130 pub const SERIF: FamilySelector = FamilySelector(0);
132
133 pub const SANS_SERIF: FamilySelector = FamilySelector(1);
135
136 pub const MONOSPACE: FamilySelector = FamilySelector(2);
138
139 pub const CURSIVE: FamilySelector = FamilySelector(3);
141
142 pub const SYSTEM_UI: FamilySelector = FamilySelector(5);
144
145 pub const EMOJI: FamilySelector = FamilySelector(10);
147
148 pub const MATH: FamilySelector = FamilySelector(11);
150
151 pub const FANG_SONG: FamilySelector = FamilySelector(12);
153
154 pub fn as_generic(self) -> Option<GenericFamily> {
156 match self.0 {
157 0 => Some(GenericFamily::Serif),
158 1 => Some(GenericFamily::SansSerif),
159 2 => Some(GenericFamily::Monospace),
160 3 => Some(GenericFamily::Cursive),
161 5 => Some(GenericFamily::SystemUi),
162 10 => Some(GenericFamily::Emoji),
163 11 => Some(GenericFamily::Math),
164 12 => Some(GenericFamily::FangSong),
165 _ => None,
166 }
167 }
168
169 pub fn generic_name(self) -> Option<&'static str> {
171 Some(match self.as_generic()? {
172 GenericFamily::Serif => "serif",
173 GenericFamily::SansSerif => "sans-serif",
174 GenericFamily::Monospace => "monospace",
175 GenericFamily::Cursive => "cursive",
176 GenericFamily::SystemUi => "system-ui",
177 GenericFamily::Emoji => "emoji",
178 GenericFamily::Math => "math",
179 GenericFamily::FangSong => "fangsong",
180 _ => return None,
181 })
182 }
183
184 pub fn parse_generic(name: &str) -> Option<Self> {
186 Some(match name.trim() {
187 "serif" => Self::SERIF,
188 "sans-serif" => Self::SANS_SERIF,
189 "monospace" => Self::MONOSPACE,
190 "cursive" => Self::CURSIVE,
191 "system-ui" => Self::SYSTEM_UI,
192 "emoji" => Self::EMOJI,
193 "math" => Self::MATH,
194 "fangsong" => Self::FANG_SONG,
195 _ => return None,
196 })
197 }
198}
199
200impl Default for FamilySelector {
202 fn default() -> Self {
203 FamilySelector::SYSTEM_UI
204 }
205}
206
207#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
215pub struct FontSelector {
216 pub family: FamilySelector,
218 pub weight: FontWeight,
220 pub width: FontWidth,
222 pub style: FontStyle,
224}
225
226impl FontSelector {
227 pub const EMOJI: Self = FontSelector {
229 family: FamilySelector::EMOJI,
230 weight: FontWeight::NORMAL,
231 width: FontWidth::NORMAL,
232 style: FontStyle::Normal,
233 };
234
235 #[inline]
240 pub fn new() -> Self {
241 FontSelector::default()
242 }
243
244 pub(crate) fn select<F>(&self, resolver: &mut Resolver, script: Script, add_face: F)
248 where
249 F: FnMut(&QueryFont) -> QueryStatus,
250 {
251 let mut query = resolver.collection.query(&mut resolver.cache);
252 if let Some(gf) = self.family.as_generic() {
253 debug!(
254 "select: Script::{:?}, GenericFamily::{:?}, {:?}, {:?}, {:?}",
255 &script, gf, &self.weight, &self.width, &self.style
256 );
257
258 query.set_families([gf]);
259 } else if let Some(set) = resolver.families.get(&self.family) {
260 debug!(
261 "select: Script::{:?}, {:?}, {:?}, {:?}, {:?}",
262 &script, set, &self.weight, &self.width, &self.style
263 );
264
265 query.set_families(set.0.iter());
266 }
267
268 query.set_attributes(Attributes {
269 width: self.width.into(),
270 style: self.style.into(),
271 weight: self.weight.into(),
272 });
273
274 query.set_fallbacks(script);
275
276 query.matches_with(add_face);
277 }
278
279 pub fn format_css(&self) -> Option<String> {
295 let family = self.family.generic_name()?;
296 let mut s = String::new();
297 if self.style != FontStyle::Normal {
298 s.push_str(&format!("{} ", self.style));
299 }
300 if self.weight != FontWeight::NORMAL {
301 s.push_str(&format!("{} ", self.weight));
302 }
303 if self.width != FontWidth::NORMAL {
304 s.push_str(&format!("{} ", self.width));
305 }
306 s.push_str(family);
307 Some(s)
308 }
309
310 pub fn parse_css(s: &str) -> Option<Self> {
317 let mut weight = FontWeight::NORMAL;
318 let mut width = FontWidth::NORMAL;
319 let mut style = FontStyle::Normal;
320 let mut last_is_oblique = false;
321 for part in s.split_ascii_whitespace() {
322 if last_is_oblique {
323 if part.ends_with("deg") {
325 style = FontStyle::parse(&format!("oblique {part}"))
326 .expect("failed to parse oblique angle");
327 }
328 last_is_oblique = false;
329 } else if let Some(v) = FontStyle::parse(part) {
330 style = v;
331 if style == FontStyle::Oblique(None) {
332 last_is_oblique = true;
333 }
334 } else if let Some(v) = FontWeight::parse(part) {
335 weight = v;
336 } else if let Some(v) = FontWidth::parse(part) {
337 width = v;
338 } else {
339 let family = FamilySelector::parse_generic(part)?;
340 return Some(FontSelector {
341 family,
342 weight,
343 width,
344 style,
345 });
346 }
347 }
348 None
349 }
350}
351
352impl From<FamilySelector> for FontSelector {
353 #[inline]
354 fn from(family: FamilySelector) -> Self {
355 FontSelector {
356 family,
357 ..Default::default()
358 }
359 }
360}
361
362#[cfg(feature = "serde")]
364mod remote {
365 use serde::{Deserialize, Serialize};
366
367 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
368 #[repr(u8)]
369 #[serde(remote = "fontique::GenericFamily")]
370 pub enum GenericFamily {
371 Serif = 0,
372 SansSerif = 1,
373 Monospace = 2,
374 Cursive = 3,
375 Fantasy = 4,
376 SystemUi = 5,
377 UiSerif = 6,
378 UiSansSerif = 7,
379 UiMonospace = 8,
380 UiRounded = 9,
381 Emoji = 10,
382 Math = 11,
383 FangSong = 12,
384 }
385}
386
387#[cfg(feature = "serde")]
388mod serde_impls {
389 use super::*;
390 use serde::{de, ser};
391 use std::fmt;
392
393 impl ser::Serialize for FamilySelector {
394 fn serialize<S: ser::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
395 if let Some(name) = self.generic_name() {
396 ser.serialize_str(name)
397 } else {
398 Err(ser::Error::custom(
399 "unable to serialize non-generic family selectors",
400 ))
401 }
402 }
403 }
404
405 impl<'de> de::Deserialize<'de> for FamilySelector {
406 fn deserialize<D: de::Deserializer<'de>>(de: D) -> Result<FamilySelector, D::Error> {
407 struct Visitor;
408 impl<'de> de::Visitor<'de> for Visitor {
409 type Value = FamilySelector;
410
411 fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
412 write!(fmt, "a generic family name")
413 }
414
415 fn visit_str<E: de::Error>(self, s: &str) -> Result<FamilySelector, E> {
416 FamilySelector::parse_generic(s)
418 .ok_or_else(|| de::Error::invalid_value(de::Unexpected::Str(s), &self))
419 }
420 }
421
422 de.deserialize_str(Visitor)
423 }
424 }
425
426 impl ser::Serialize for FontSelector {
427 fn serialize<S: ser::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
428 if let Some(s) = self.format_css() {
429 ser.serialize_str(&s)
430 } else {
431 Err(ser::Error::custom(
432 "unable to serialize non-generic family selectors",
433 ))
434 }
435 }
436 }
437
438 impl<'de> de::Deserialize<'de> for FontSelector {
439 fn deserialize<D: de::Deserializer<'de>>(de: D) -> Result<FontSelector, D::Error> {
440 struct Visitor;
441 impl<'de> de::Visitor<'de> for Visitor {
442 type Value = FontSelector;
443
444 fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
445 write!(fmt, "a CSS-style font selector")
446 }
447
448 fn visit_str<E: de::Error>(self, s: &str) -> Result<FontSelector, E> {
449 FontSelector::parse_css(s)
450 .ok_or_else(|| de::Error::invalid_value(de::Unexpected::Str(s), &self))
451 }
452 }
453
454 de.deserialize_str(Visitor)
455 }
456 }
457}