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