1use std::collections::HashMap;
6use std::ops::Deref;
7use std::sync::Arc;
8
9use fonts_traits::{
10 FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, FontTemplateRefMethods,
11 IsOblique, LowercaseFontFamilyName,
12};
13use log::warn;
14use malloc_size_of_derive::MallocSizeOf;
15use parking_lot::RwLock;
16use style::properties::generated::font_face::Descriptors as FontFaceRuleDescriptors;
17use style::values::computed::{FontStyle, FontWeight};
18
19#[derive(Default, MallocSizeOf)]
20pub(crate) struct FontStore {
21 pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>,
22}
23
24#[derive(Default, MallocSizeOf)]
25pub(crate) struct CrossThreadFontStore(#[conditional_malloc_size_of] Arc<RwLock<FontStore>>);
26
27impl Deref for CrossThreadFontStore {
28 type Target = Arc<RwLock<FontStore>>;
29 fn deref(&self) -> &Self::Target {
30 &self.0
31 }
32}
33
34impl FontStore {
35 pub(crate) fn clear(&mut self) {
36 self.families.clear();
37 }
38
39 pub(crate) fn add_new_template(
40 &mut self,
41 family_name: LowercaseFontFamilyName,
42 new_template: FontTemplate,
43 ) {
44 self.families
45 .entry(family_name)
46 .or_default()
47 .add_template(new_template);
48 }
49}
50
51#[derive(Clone, Debug, Default, MallocSizeOf)]
59struct SimpleFamily {
60 regular: Option<FontTemplateRef>,
61 bold: Option<FontTemplateRef>,
62 italic: Option<FontTemplateRef>,
63 bold_italic: Option<FontTemplateRef>,
64}
65
66impl SimpleFamily {
67 fn find_for_descriptor(&self, descriptor_to_match: &FontDescriptor) -> Option<FontTemplateRef> {
69 let want_bold = descriptor_to_match.weight > FontWeight::PREFER_BOLD_THRESHOLD;
70 let want_italic = descriptor_to_match.style != FontStyle::NORMAL;
71
72 let preference = match (want_bold, want_italic) {
75 (true, true) => [&self.bold_italic, &self.italic, &self.bold, &self.regular],
76 (true, false) => [&self.bold, &self.regular, &self.bold_italic, &self.italic],
77 (false, true) => [&self.italic, &self.bold_italic, &self.regular, &self.bold],
78 (false, false) => [&self.regular, &self.bold, &self.italic, &self.bold_italic],
79 };
80 preference.iter().find_map(|template| (*template).clone())
81 }
82
83 fn remove_templates_for_font_face_rule(&mut self, font_face_rule: &FontFaceRuleDescriptors) {
84 let remove_if_template_matches = |template: &mut Option<FontTemplateRef>| {
85 if template.as_ref().is_some_and(|template| {
86 template
87 .borrow()
88 .is_defined_by_font_face_rule(font_face_rule)
89 }) {
90 *template = None;
91 }
92 };
93 remove_if_template_matches(&mut self.regular);
94 remove_if_template_matches(&mut self.bold);
95 remove_if_template_matches(&mut self.italic);
96 remove_if_template_matches(&mut self.bold_italic);
97 }
98
99 pub(crate) fn for_all_identifiers(&self, mut callback: impl FnMut(&FontIdentifier)) {
100 let mut call_if_not_none = |template: &Option<FontTemplateRef>| {
101 if let Some(template) = template {
102 callback(&template.identifier())
103 }
104 };
105 call_if_not_none(&self.regular);
106 call_if_not_none(&self.bold);
107 call_if_not_none(&self.italic);
108 call_if_not_none(&self.bold_italic);
109 }
110}
111#[derive(Clone, Debug, MallocSizeOf)]
113pub struct FontTemplates {
114 pub(crate) templates: Vec<FontTemplateRef>,
115 simple_family: Option<SimpleFamily>,
116}
117
118impl Default for FontTemplates {
119 fn default() -> Self {
120 Self {
121 templates: Default::default(),
122 simple_family: Some(SimpleFamily::default()),
123 }
124 }
125}
126
127impl FontTemplates {
128 pub fn find_for_descriptor(
130 &self,
131 descriptor_to_match: Option<&FontDescriptor>,
132 ) -> Vec<FontTemplateRef> {
133 let Some(descriptor_to_match) = descriptor_to_match else {
134 return self.templates.clone();
135 };
136
137 if self.templates.len() == 1 {
138 return vec![self.templates[0].clone()];
139 }
140
141 if let Some(template) = self
142 .simple_family
143 .as_ref()
144 .and_then(|simple_family| simple_family.find_for_descriptor(descriptor_to_match))
145 {
146 return vec![template];
147 }
148
149 let mut best_templates = Vec::new();
150 let mut best_distance = f32::MAX;
151 for template in self.templates.iter() {
152 let distance = template.descriptor_distance(descriptor_to_match);
153 if distance < best_distance {
154 best_templates = vec![template.clone()];
155 best_distance = distance
156 } else if distance == best_distance {
157 best_templates.push(template.clone());
158 }
159 }
160
161 if !best_templates.is_empty() {
162 return best_templates;
163 }
164
165 if let Some(template) = self.templates.first() {
169 return vec![template.clone()];
170 }
171
172 Vec::new()
173 }
174
175 pub fn add_template(&mut self, new_template: FontTemplate) {
176 for existing_template in &self.templates {
177 let existing_template = existing_template.borrow();
178 if *existing_template.identifier() == new_template.identifier &&
179 existing_template.descriptor == new_template.descriptor
180 {
181 return;
182 }
183 }
184
185 let new_template = FontTemplateRef::new(new_template);
186 self.templates.push(new_template.clone());
187 self.update_simple_family(new_template);
188 }
189
190 fn update_simple_family(&mut self, added_template: FontTemplateRef) {
191 let Some(simple_family) = self.simple_family.as_mut() else {
194 return;
195 };
196
197 if self.templates.len() > 4 {
198 self.simple_family = None;
199 return;
200 }
201
202 if added_template.descriptor().is_variation_font() {
204 self.simple_family = None;
205 return;
206 }
207
208 let Some(first) = self.templates.first() else {
209 warn!("Called before adding any templates.");
210 return;
211 };
212
213 let stretch = added_template.descriptor().stretch.0;
216 let style = added_template.descriptor().style.0;
217 if first.descriptor().stretch.0 != stretch || style.is_oblique() {
218 self.simple_family = None;
219 return;
220 }
221
222 let weight = added_template.descriptor().weight.0;
223 let supports_bold = weight >= FontWeight::BOLD_THRESHOLD;
224 let is_italic = style == FontStyle::ITALIC;
225 let slot = match (supports_bold, is_italic) {
226 (true, true) => &mut simple_family.bold_italic,
227 (true, false) => &mut simple_family.bold,
228 (false, true) => &mut simple_family.italic,
229 (false, false) => &mut simple_family.regular,
230 };
231
232 if slot.is_some() {
235 self.simple_family = None;
236 return;
237 }
238
239 slot.replace(added_template);
240 }
241
242 pub(crate) fn remove_template_for_font_face_rule(
244 &mut self,
245 removed_rule: &FontFaceRuleDescriptors,
246 ) -> bool {
247 let old_length = self.templates.len();
248 self.templates
249 .retain(|template| !template.borrow().is_defined_by_font_face_rule(removed_rule));
250
251 if let Some(simple_family) = self.simple_family.as_mut() {
252 simple_family.remove_templates_for_font_face_rule(removed_rule);
253 }
254
255 self.templates.len() != old_length
256 }
257
258 pub(crate) fn for_all_identifiers(&self, mut callback: impl FnMut(&FontIdentifier)) {
259 for template in self.templates.iter() {
260 callback(&template.borrow().identifier);
261 }
262 if let Some(ref simple_family) = self.simple_family {
263 simple_family.for_all_identifiers(callback)
264 }
265 }
266}