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