Skip to main content

fonts/
font_feature_values.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::collections::HashMap;
6
7use malloc_size_of_derive::MallocSizeOf;
8use style::Atom;
9use style::stylesheets::FontFeatureValuesRule;
10use style::stylesheets::font_feature_values_rule::{PairValues, SingleValue, VectorValues};
11
12/// A key for looking up identifiers inside a [FontFeatureValueMap].
13#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
14struct HashKey {
15    /// The name of the font that the feature name is defined for
16    family_name: Atom,
17    kind: AlternateKindRequiringResolution,
18    /// The name of the feature.
19    name: Atom,
20}
21
22/// Different kinds of values that identifiers inside `font-variant-alternates` can resolve to.
23#[derive(Clone, Debug, MallocSizeOf)]
24pub(crate) enum FontFeatureValue {
25    Single(SingleValue),
26    Pair(PairValues),
27    Vector(VectorValues),
28}
29
30/// Stores accumulated data of all active [`@font-feature-value`] rules.
31///
32/// [`@font-feature-value`]: https://drafts.csswg.org/css-fonts/#font-feature-values
33#[derive(Debug, Default, MallocSizeOf)]
34pub(crate) struct FontFeatureValueMap {
35    map: HashMap<HashKey, FontFeatureValue>,
36}
37
38/// Enumerates the different variant kinds of [`font-variant-alternates`] which take a
39/// one or more identifiers.
40///
41/// [`font-variant-alternates`]: https://drafts.csswg.org/css-fonts/#font-variant-alternates-prop
42#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
43pub enum AlternateKindRequiringResolution {
44    /// <https://drafts.csswg.org/css-fonts/#stylistic>
45    Stylistic,
46    /// <https://drafts.csswg.org/css-fonts/#styleset>
47    Styleset,
48    /// <https://drafts.csswg.org/css-fonts/#character-variant>
49    CharacterVariant,
50    /// <https://drafts.csswg.org/css-fonts/#swash>
51    Swash,
52    /// <https://drafts.csswg.org/css-fonts/#ornaments>
53    Annotation,
54    /// <https://drafts.csswg.org/css-fonts/#annotation>
55    Ornaments,
56}
57
58impl FontFeatureValueMap {
59    /// Looks up a single identifier in the map.
60    pub(crate) fn lookup(
61        &self,
62        family_name: Atom,
63        kind: AlternateKindRequiringResolution,
64        name: Atom,
65    ) -> Option<FontFeatureValue> {
66        let key = HashKey {
67            family_name,
68            kind,
69            name,
70        };
71
72        let value = self.map.get(&key).cloned();
73        log::debug!(
74            "@font-feature-values lookup for {:?} {:?} {:?} -> {value:?}",
75            key.family_name,
76            key.kind,
77            key.name
78        );
79        value
80    }
81
82    /// Adds the values from a new `@font-feature-values` rule to the map.
83    ///
84    /// Conflicting entries are overwritten, so it is the callers responsibility to add the rules
85    /// in ascending cascade order.
86    pub(crate) fn add_rule(&mut self, rule: &FontFeatureValuesRule) {
87        self.map.reserve(rule.family_names.len() * rule.len());
88        for family_name in &rule.family_names {
89            for swash in &rule.swash {
90                let key = HashKey {
91                    family_name: family_name.name.clone(),
92                    kind: AlternateKindRequiringResolution::Swash,
93                    name: swash.name.clone(),
94                };
95                self.map
96                    .insert(key, FontFeatureValue::Single(swash.value.clone()));
97            }
98
99            for annotation in &rule.annotation {
100                let key = HashKey {
101                    family_name: family_name.name.clone(),
102                    kind: AlternateKindRequiringResolution::Annotation,
103                    name: annotation.name.clone(),
104                };
105                self.map
106                    .insert(key, FontFeatureValue::Single(annotation.value.clone()));
107            }
108
109            for ornament in &rule.ornaments {
110                let key = HashKey {
111                    family_name: family_name.name.clone(),
112                    kind: AlternateKindRequiringResolution::Ornaments,
113                    name: ornament.name.clone(),
114                };
115                self.map
116                    .insert(key, FontFeatureValue::Single(ornament.value.clone()));
117            }
118
119            for stylistic in &rule.stylistic {
120                let key = HashKey {
121                    family_name: family_name.name.clone(),
122                    kind: AlternateKindRequiringResolution::Stylistic,
123                    name: stylistic.name.clone(),
124                };
125                self.map
126                    .insert(key, FontFeatureValue::Single(stylistic.value.clone()));
127            }
128
129            for styleset in &rule.styleset {
130                let key = HashKey {
131                    family_name: family_name.name.clone(),
132                    kind: AlternateKindRequiringResolution::Styleset,
133                    name: styleset.name.clone(),
134                };
135                self.map
136                    .insert(key, FontFeatureValue::Vector(styleset.value.clone()));
137            }
138
139            for character_variant in &rule.character_variant {
140                let key = HashKey {
141                    family_name: family_name.name.clone(),
142                    kind: AlternateKindRequiringResolution::CharacterVariant,
143                    name: character_variant.name.clone(),
144                };
145                self.map
146                    .insert(key, FontFeatureValue::Pair(character_variant.value.clone()));
147            }
148        }
149    }
150}
151
152/// Stores the value of the [`font-variant-alternates`] property, with identifiers
153/// resolved to font-specific values.
154///
155/// [`font-variant-alternates`]: https://drafts.csswg.org/css-fonts/#font-variant-alternates-prop
156#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)]
157pub struct ResolvedFontVariantAlternates {
158    /// <https://drafts.csswg.org/css-fonts/#valdef-font-variant-alternates-historical-forms>
159    pub historical_forms: bool,
160    /// <https://drafts.csswg.org/css-fonts/#stylistic>
161    pub stylistic: Option<SingleValue>,
162    /// <https://drafts.csswg.org/css-fonts/#styleset>
163    pub styleset: Vec<u32>,
164    /// <https://drafts.csswg.org/css-fonts/#character-variant>
165    pub character_variant: Vec<PairValues>,
166    /// <https://drafts.csswg.org/css-fonts/#swash>
167    pub swash: Option<SingleValue>,
168    /// <https://drafts.csswg.org/css-fonts/#ornaments>
169    pub ornaments: Option<SingleValue>,
170    /// <https://drafts.csswg.org/css-fonts/#annotation>
171    pub annotation: Option<SingleValue>,
172}