Skip to main content

script/
svg_font.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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}