1use std::sync::Arc;
6
7use app_units::Au;
8use fonts::{FontContext, FontDescriptor, FontFamilyDescriptor, FontSearchScope};
9use net_traits::image_cache::FontResolver;
10use resvg::usvg::{Font, FontFamily, FontStretch, FontStyle, fontdb};
11use style::computed_values::font_optical_sizing::T as FontOpticalSizing;
12use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps;
13use style::values::computed::font::{
14 FamilyName, FontFamilyNameSyntax, GenericFontFamily, SingleFontFamily,
15};
16use style::values::computed::{
17 FontStretch as ServoFontStretch, FontStyle as ServoFontStyle, FontSynthesis, FontWeight,
18};
19use webrender_api::FontVariation;
20
21pub struct SvgFontResolver {
22 pub context: Arc<FontContext>,
23}
24
25fn convert_font_descriptor(font: &Font) -> FontDescriptor {
26 let style = match font.style() {
27 FontStyle::Normal => ServoFontStyle::normal(),
28 FontStyle::Italic => ServoFontStyle::ITALIC,
29 FontStyle::Oblique => ServoFontStyle::OBLIQUE,
30 };
31
32 let stretch = match font.stretch() {
33 FontStretch::UltraCondensed => ServoFontStretch::ULTRA_CONDENSED,
34 FontStretch::ExtraCondensed => ServoFontStretch::EXTRA_CONDENSED,
35 FontStretch::Condensed => ServoFontStretch::CONDENSED,
36 FontStretch::SemiCondensed => ServoFontStretch::SEMI_CONDENSED,
37 FontStretch::Normal => ServoFontStretch::NORMAL,
38 FontStretch::SemiExpanded => ServoFontStretch::SEMI_EXPANDED,
39 FontStretch::Expanded => ServoFontStretch::EXPANDED,
40 FontStretch::ExtraExpanded => ServoFontStretch::EXTRA_EXPANDED,
41 FontStretch::UltraExpanded => ServoFontStretch::ULTRA_EXPANDED,
42 };
43
44 let variation_settings = font
45 .variations()
46 .iter()
47 .map(|variation| FontVariation {
48 tag: u32::from_be_bytes(variation.tag),
49 value: variation.value,
50 })
51 .collect();
52
53 FontDescriptor {
54 weight: FontWeight::from_float(font.weight() as f32),
55 stretch,
56 style,
57 variant: FontVariantCaps::Normal,
58 pt_size: Au::from_px(16),
59 variation_settings,
60 synthesis_weight: FontSynthesis::Auto,
61 optical_sizing: FontOpticalSizing::Auto,
62 }
63}
64
65fn convert_font_family(family: &FontFamily) -> SingleFontFamily {
66 match family {
67 FontFamily::Serif => SingleFontFamily::Generic(GenericFontFamily::Serif),
68 FontFamily::SansSerif => SingleFontFamily::Generic(GenericFontFamily::SansSerif),
69 FontFamily::Cursive => SingleFontFamily::Generic(GenericFontFamily::Cursive),
70 FontFamily::Fantasy => SingleFontFamily::Generic(GenericFontFamily::Fantasy),
71 FontFamily::Monospace => SingleFontFamily::Generic(GenericFontFamily::Monospace),
72 FontFamily::Named(name) => SingleFontFamily::FamilyName(FamilyName {
73 name: name.as_str().into(),
74 syntax: FontFamilyNameSyntax::Quoted,
75 }),
76 }
77}
78
79impl FontResolver for SvgFontResolver {
80 fn resolve(&self, font: &Font, database: &mut Arc<fontdb::Database>) -> Option<fontdb::ID> {
81 let font_descriptor = convert_font_descriptor(font);
82
83 for family in font.families() {
84 let family_descriptor =
85 FontFamilyDescriptor::new(convert_font_family(family), FontSearchScope::Any);
86 let Some(font_template) = self
87 .context
88 .matching_templates(&font_descriptor, &family_descriptor)
89 .into_iter()
90 .next()
91 else {
92 continue;
93 };
94 let Some(font) = self.context.font(font_template, &font_descriptor) else {
95 continue;
96 };
97 let Ok(data_and_index) = font.font_data_and_index() else {
98 continue;
99 };
100 let ids = Arc::make_mut(database).load_font_source(fontdb::Source::Binary(Arc::new(
101 data_and_index.data.clone(),
102 )));
103 if let Some(id) = ids.get(data_and_index.index as usize).copied() {
104 return Some(id);
105 }
106 }
107
108 None
109 }
110}