fonts_traits/
font_descriptor.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::ops::{Deref, RangeInclusive};
6
7use malloc_size_of_derive::MallocSizeOf;
8use serde::{Deserialize, Serialize};
9use style::computed_values::font_variant_caps;
10use style::font_face::{FontFaceRuleData, FontStyle as FontFaceStyle};
11use style::properties::style_structs::Font as FontStyleStruct;
12use style::values::computed::font::{FixedPoint, FontStyleFixedPoint};
13use style::values::computed::{Au, FontStretch, FontStyle, FontWeight};
14use style::values::specified::FontStretch as SpecifiedFontStretch;
15use webrender_api::FontVariation;
16
17/// `FontDescriptor` describes the parameters of a `Font`. It represents rendering a given font
18/// template at a particular size, with a particular font-variant-caps applied, etc. This contrasts
19/// with `FontTemplateDescriptor` in that the latter represents only the parameters inherent in the
20/// font data (weight, stretch, etc.).
21#[derive(Clone, Debug, Deserialize, Hash, MallocSizeOf, PartialEq, Serialize)]
22pub struct FontDescriptor {
23    pub weight: FontWeight,
24    pub stretch: FontStretch,
25    pub style: FontStyle,
26    pub variant: font_variant_caps::T,
27    pub pt_size: Au,
28    pub variation_settings: Vec<FontVariation>,
29}
30
31impl Eq for FontDescriptor {}
32
33impl<'a> From<&'a FontStyleStruct> for FontDescriptor {
34    fn from(style: &'a FontStyleStruct) -> Self {
35        let variation_settings = style
36            .clone_font_variation_settings()
37            .0
38            .into_iter()
39            .map(|setting| FontVariation {
40                tag: setting.tag.0,
41                value: setting.value,
42            })
43            .collect();
44        FontDescriptor {
45            weight: style.font_weight,
46            stretch: style.font_stretch,
47            style: style.font_style,
48            variant: style.font_variant_caps,
49            pt_size: Au::from_f32_px(style.font_size.computed_size().px()),
50            variation_settings,
51        }
52    }
53}
54
55/// A version of `FontStyle` from Stylo that is serializable. Normally this is not
56/// because the specified version of `FontStyle` contains floats.
57#[derive(Clone, Debug, Deserialize, Serialize)]
58pub enum ComputedFontStyleDescriptor {
59    Italic,
60    Oblique(FontStyleFixedPoint, FontStyleFixedPoint),
61}
62
63/// This data structure represents the various optional descriptors that can be
64/// applied to a `@font-face` rule in CSS. These are used to create a [`FontTemplate`]
65/// from the given font data used as the source of the `@font-face` rule. If values
66/// like weight, stretch, and style are not specified they are initialized based
67/// on the contents of the font itself.
68#[derive(Clone, Debug, Default, Deserialize, Serialize)]
69pub struct CSSFontFaceDescriptors {
70    pub family_name: LowercaseFontFamilyName,
71    pub weight: Option<(FontWeight, FontWeight)>,
72    pub stretch: Option<(FontStretch, FontStretch)>,
73    pub style: Option<ComputedFontStyleDescriptor>,
74    pub unicode_range: Option<Vec<RangeInclusive<u32>>>,
75}
76
77impl CSSFontFaceDescriptors {
78    pub fn new(family_name: &str) -> Self {
79        CSSFontFaceDescriptors {
80            family_name: family_name.into(),
81            ..Default::default()
82        }
83    }
84}
85
86impl From<&FontFaceRuleData> for CSSFontFaceDescriptors {
87    fn from(rule_data: &FontFaceRuleData) -> Self {
88        let family_name = rule_data
89            .family
90            .as_ref()
91            .expect("Expected rule to contain a font family.")
92            .name
93            .clone();
94        let weight = rule_data
95            .weight
96            .as_ref()
97            .map(|weight_range| (weight_range.0.compute(), weight_range.1.compute()));
98
99        let stretch_to_computed = |specified: SpecifiedFontStretch| match specified {
100            SpecifiedFontStretch::Stretch(percentage) => {
101                FontStretch::from_percentage(percentage.compute().0)
102            },
103            SpecifiedFontStretch::Keyword(keyword) => keyword.compute(),
104            SpecifiedFontStretch::System(_) => FontStretch::NORMAL,
105        };
106        let stretch = rule_data.stretch.as_ref().map(|stretch_range| {
107            (
108                stretch_to_computed(stretch_range.0),
109                stretch_to_computed(stretch_range.1),
110            )
111        });
112
113        fn style_to_computed(specified: &FontFaceStyle) -> ComputedFontStyleDescriptor {
114            match specified {
115                FontFaceStyle::Italic => ComputedFontStyleDescriptor::Italic,
116                FontFaceStyle::Oblique(angle_a, angle_b) => ComputedFontStyleDescriptor::Oblique(
117                    FixedPoint::from_float(angle_a.degrees()),
118                    FixedPoint::from_float(angle_b.degrees()),
119                ),
120            }
121        }
122        let style = rule_data.style.as_ref().map(style_to_computed);
123        let unicode_range = rule_data
124            .unicode_range
125            .as_ref()
126            .map(|ranges| ranges.iter().map(|range| range.start..=range.end).collect());
127
128        CSSFontFaceDescriptors {
129            family_name: family_name.into(),
130            weight,
131            stretch,
132            style,
133            unicode_range,
134        }
135    }
136}
137
138#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
139pub struct LowercaseFontFamilyName {
140    inner: String,
141}
142
143impl<T: AsRef<str>> From<T> for LowercaseFontFamilyName {
144    fn from(value: T) -> Self {
145        LowercaseFontFamilyName {
146            inner: value.as_ref().to_lowercase(),
147        }
148    }
149}
150
151impl Deref for LowercaseFontFamilyName {
152    type Target = str;
153
154    #[inline]
155    fn deref(&self) -> &str {
156        &self.inner
157    }
158}
159
160impl std::fmt::Display for LowercaseFontFamilyName {
161    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
162        self.inner.fmt(f)
163    }
164}