fonts_traits/
font_template.rs1use std::fmt::{Debug, Error, Formatter};
6use std::ops::{Deref, RangeInclusive};
7use std::sync::Arc;
8
9use atomic_refcell::{AtomicRef, AtomicRefCell};
10use malloc_size_of_derive::MallocSizeOf;
11use serde::{Deserialize, Serialize};
12use servo_arc::Arc as ServoArc;
13use style::computed_values::font_stretch::T as FontStretch;
14use style::computed_values::font_style::T as FontStyle;
15use style::font_face::{ComputedFontStretchRange, ComputedFontStyleRange, ComputedFontWeightRange};
16use style::values::computed::font::FontWeight;
17
18use crate::{CSSFontFaceDescriptors, FontDescriptor, FontFaceRuleInfo, FontIdentifier};
19
20#[derive(Clone, Debug, MallocSizeOf)]
22pub struct FontTemplateRef(#[conditional_malloc_size_of] Arc<AtomicRefCell<FontTemplate>>);
23
24impl FontTemplateRef {
25 pub fn new(template: FontTemplate) -> Self {
26 Self(Arc::new(AtomicRefCell::new(template)))
27 }
28}
29
30impl Deref for FontTemplateRef {
31 type Target = Arc<AtomicRefCell<FontTemplate>>;
32 fn deref(&self) -> &Self::Target {
33 &self.0
34 }
35}
36
37#[derive(Clone, Debug, Deserialize, Hash, MallocSizeOf, PartialEq, Serialize)]
42pub struct FontTemplateDescriptor {
43 pub weight: ComputedFontWeightRange,
44 pub stretch: ComputedFontStretchRange,
45 pub style: ComputedFontStyleRange,
46 pub unicode_range: Option<Vec<RangeInclusive<u32>>>,
47}
48
49impl Default for FontTemplateDescriptor {
50 fn default() -> Self {
51 Self::new(FontWeight::normal(), FontStretch::NORMAL, FontStyle::NORMAL)
52 }
53}
54
55impl FontTemplateDescriptor {
56 #[inline]
57 pub fn new(weight: FontWeight, stretch: FontStretch, style: FontStyle) -> Self {
58 Self {
59 weight: ComputedFontWeightRange(weight, weight),
60 stretch: ComputedFontStretchRange(stretch, stretch),
61 style: ComputedFontStyleRange(style, style),
62 unicode_range: None,
63 }
64 }
65
66 pub fn is_variation_font(&self) -> bool {
67 self.weight.0 != self.weight.1 ||
68 self.stretch.0 != self.stretch.1 ||
69 self.style.0 != self.style.1
70 }
71
72 #[inline]
79 fn distance_from(&self, target: &FontDescriptor) -> f32 {
80 let stretch_distance = target.stretch.match_distance(&self.stretch);
81 let style_distance = target.style.match_distance(&self.style);
82 let weight_distance = target.weight.match_distance(&self.weight);
83
84 assert!((0.0..=2000.0).contains(&stretch_distance));
87 assert!((0.0..=500.0).contains(&style_distance));
88 assert!((0.0..=1600.0).contains(&weight_distance));
89
90 const STRETCH_FACTOR: f32 = 1.0e8;
99 const STYLE_FACTOR: f32 = 1.0e4;
100 const WEIGHT_FACTOR: f32 = 1.0e0;
101
102 stretch_distance * STRETCH_FACTOR +
103 style_distance * STYLE_FACTOR +
104 weight_distance * WEIGHT_FACTOR
105 }
106
107 fn matches(&self, descriptor_to_match: &FontDescriptor) -> bool {
108 self.weight.0 <= descriptor_to_match.weight &&
109 self.weight.1 >= descriptor_to_match.weight &&
110 self.style.0 <= descriptor_to_match.style &&
111 self.style.1 >= descriptor_to_match.style &&
112 self.stretch.0 <= descriptor_to_match.stretch &&
113 self.stretch.1 >= descriptor_to_match.stretch
114 }
115
116 pub fn override_values_with_css_font_template_descriptors(
117 &mut self,
118 css_font_template_descriptors: &CSSFontFaceDescriptors,
119 ) {
120 if let Some(ref weight) = css_font_template_descriptors.weight {
121 self.weight = weight.clone();
122 }
123 if let Some(ref style) = css_font_template_descriptors.style {
124 self.style = style.clone();
125 }
126 if let Some(ref stretch) = css_font_template_descriptors.stretch {
127 self.stretch = stretch.clone();
128 }
129 if let Some(ref unicode_range) = css_font_template_descriptors.unicode_range {
130 self.unicode_range = Some(unicode_range.clone());
131 }
132 }
133}
134
135#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
139pub struct FontTemplate {
140 pub identifier: FontIdentifier,
141 pub descriptor: FontTemplateDescriptor,
142
143 #[serde(skip)]
146 #[conditional_malloc_size_of]
147 pub font_face_rule: Option<ServoArc<FontFaceRuleInfo>>,
148}
149
150impl Debug for FontTemplate {
151 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
152 self.identifier.fmt(f)
153 }
154}
155
156impl FontTemplate {
160 pub fn new(
162 identifier: FontIdentifier,
163 descriptor: FontTemplateDescriptor,
164 font_face_rule: Option<ServoArc<FontFaceRuleInfo>>,
165 ) -> FontTemplate {
166 FontTemplate {
167 identifier,
168 descriptor,
169 font_face_rule,
170 }
171 }
172
173 pub fn new_for_local_web_font(
177 local_template: FontTemplateRef,
178 css_font_template_descriptors: &CSSFontFaceDescriptors,
179 font_face_rule: Option<ServoArc<FontFaceRuleInfo>>,
180 ) -> Result<FontTemplate, &'static str> {
181 let mut alias_template = local_template.borrow().clone();
182 alias_template
183 .descriptor
184 .override_values_with_css_font_template_descriptors(css_font_template_descriptors);
185 alias_template.font_face_rule = font_face_rule;
186 Ok(alias_template)
187 }
188
189 pub fn identifier(&self) -> &FontIdentifier {
190 &self.identifier
191 }
192
193 pub fn is_defined_by_font_face_rule(&self, rule: &ServoArc<FontFaceRuleInfo>) -> bool {
194 self.font_face_rule
195 .as_ref()
196 .is_some_and(|defining_rule| ServoArc::ptr_eq(rule, defining_rule))
197 }
198}
199
200pub trait FontTemplateRefMethods {
201 fn descriptor(&self) -> AtomicRef<'_, FontTemplateDescriptor>;
203 fn identifier(&self) -> AtomicRef<'_, FontIdentifier>;
205 fn matches_font_descriptor(&self, descriptor_to_match: &FontDescriptor) -> bool;
207 fn descriptor_distance(&self, descriptor_to_match: &FontDescriptor) -> f32;
210 fn char_in_unicode_range(&self, character: char) -> bool;
213
214 fn font_face_rule(&self) -> Option<AtomicRef<'_, ServoArc<FontFaceRuleInfo>>>;
216}
217
218impl FontTemplateRefMethods for FontTemplateRef {
219 fn descriptor(&self) -> AtomicRef<'_, FontTemplateDescriptor> {
220 AtomicRef::map(self.borrow(), |font_template_ref| {
221 &font_template_ref.descriptor
222 })
223 }
224
225 fn identifier(&self) -> AtomicRef<'_, FontIdentifier> {
226 AtomicRef::map(self.borrow(), |font_template_ref| {
227 &font_template_ref.identifier
228 })
229 }
230
231 fn matches_font_descriptor(&self, descriptor_to_match: &FontDescriptor) -> bool {
232 self.descriptor().matches(descriptor_to_match)
233 }
234
235 fn descriptor_distance(&self, descriptor_to_match: &FontDescriptor) -> f32 {
236 self.descriptor().distance_from(descriptor_to_match)
237 }
238
239 fn char_in_unicode_range(&self, character: char) -> bool {
240 let character = character as u32;
241 self.borrow()
242 .descriptor
243 .unicode_range
244 .as_ref()
245 .is_none_or(|ranges| ranges.iter().any(|range| range.contains(&character)))
246 }
247
248 fn font_face_rule(&self) -> Option<AtomicRef<'_, ServoArc<FontFaceRuleInfo>>> {
249 AtomicRef::filter_map(self.borrow(), |template| template.font_face_rule.as_ref())
250 }
251}
252
253trait FontMatchDistanceMethod<T>: Sized {
259 fn match_distance(&self, range: &T) -> f32;
260 fn to_float(&self) -> f32;
261}
262
263impl FontMatchDistanceMethod<ComputedFontStretchRange> for FontStretch {
264 fn match_distance(&self, range: &ComputedFontStretchRange) -> f32 {
265 const REVERSE_DISTANCE: f32 = 1000.0;
267
268 let min_stretch = range.0;
269 let max_stretch = range.1;
270
271 if *self < min_stretch {
277 if *self > FontStretch::NORMAL {
278 return min_stretch.to_float() - self.to_float();
279 }
280 return (min_stretch.to_float() - self.to_float()) + REVERSE_DISTANCE;
281 }
282
283 if *self > max_stretch {
284 if *self <= FontStretch::NORMAL {
285 return self.to_float() - max_stretch.to_float();
286 }
287 return (self.to_float() - max_stretch.to_float()) + REVERSE_DISTANCE;
288 }
289 0.0
290 }
291
292 fn to_float(&self) -> f32 {
293 self.0.to_float()
294 }
295}
296
297impl FontMatchDistanceMethod<ComputedFontWeightRange> for FontWeight {
298 fn match_distance(&self, range: &ComputedFontWeightRange) -> f32 {
310 const NOT_WITHIN_CENTRAL_RANGE: f32 = 100.0;
312 const REVERSE_DISTANCE: f32 = 600.0;
313
314 let min_weight = range.0;
315 let max_weight = range.1;
316
317 if *self >= min_weight && *self <= max_weight {
318 return 0.0;
320 }
321
322 if *self < FontWeight::NORMAL {
323 if max_weight < *self {
325 return self.to_float() - max_weight.to_float();
326 }
327
328 return (min_weight.to_float() - self.to_float()) + REVERSE_DISTANCE;
330 }
331
332 if *self > FontWeight::from_float(500.) {
333 if min_weight > *self {
335 return min_weight.to_float() - self.to_float();
336 }
337 return (self.to_float() - max_weight.to_float()) + REVERSE_DISTANCE;
339 }
340
341 if min_weight > *self {
343 if min_weight <= FontWeight::from_float(500.) {
344 return min_weight.to_float() - self.to_float();
346 }
347 return (min_weight.to_float() - self.to_float()) + REVERSE_DISTANCE;
349 }
350 (self.to_float() - max_weight.to_float()) + NOT_WITHIN_CENTRAL_RANGE
352 }
353
354 fn to_float(&self) -> f32 {
355 self.value()
356 }
357}
358
359impl FontMatchDistanceMethod<ComputedFontStyleRange> for FontStyle {
360 fn match_distance(&self, range: &ComputedFontStyleRange) -> f32 {
361 let min_style = range.0;
363 if *self == min_style {
364 return 0.0; }
366
367 const REVERSE: f32 = 100.0;
370
371 const NEGATE: f32 = 200.0;
374
375 if *self == FontStyle::NORMAL {
376 if min_style.is_oblique() {
377 let min_angle = min_style.oblique_degrees();
379 if min_angle >= 0.0 {
380 return 1.0 + min_angle;
381 }
382 let max_style = range.1;
383 let max_angle = max_style.oblique_degrees();
384 if max_angle >= 0.0 {
385 return 1.0;
387 }
388 return NEGATE - max_angle;
390 }
391 assert!(min_style == FontStyle::ITALIC);
394 return REVERSE;
395 }
396
397 let default_oblique_angle = FontStyle::OBLIQUE.oblique_degrees();
398 if *self == FontStyle::ITALIC {
399 if min_style.is_oblique() {
400 let min_angle = min_style.oblique_degrees();
401 if min_angle >= default_oblique_angle {
402 return 1.0 + (min_angle - default_oblique_angle);
403 }
404 let max_style = range.1;
405 let max_angle = max_style.oblique_degrees();
406 if max_angle >= default_oblique_angle {
407 return 1.0;
408 }
409 if max_angle > 0.0 {
410 return REVERSE + (default_oblique_angle - max_angle);
412 }
413 return REVERSE + NEGATE + (default_oblique_angle - max_angle);
415 }
416 assert!(min_style == FontStyle::NORMAL);
418 return NEGATE;
419 }
420
421 let target_angle = self.oblique_degrees();
425 if target_angle >= default_oblique_angle {
426 if min_style.is_oblique() {
427 let min_angle = min_style.oblique_degrees();
428 if min_angle >= target_angle {
429 return min_angle - target_angle;
430 }
431 let max_style = range.1;
432 let max_angle = max_style.oblique_degrees();
433 if max_angle >= target_angle {
434 return 0.0;
435 }
436 if max_angle > 0.0 {
437 return REVERSE + (target_angle - max_angle);
438 }
439 return REVERSE + NEGATE + (target_angle - max_angle);
440 }
441 if min_style == FontStyle::ITALIC {
442 return REVERSE + NEGATE;
443 }
444 return REVERSE + NEGATE + 1.0;
445 }
446
447 if target_angle <= -default_oblique_angle {
448 if min_style.is_oblique() {
449 let max_style = range.1;
450 let max_angle = max_style.oblique_degrees();
451 if max_angle <= target_angle {
452 return target_angle - max_angle;
453 }
454 let min_angle = min_style.oblique_degrees();
455 if min_angle <= target_angle {
456 return 0.0;
457 }
458 if min_angle < 0.0 {
459 return REVERSE + (min_angle - target_angle);
460 }
461 return REVERSE + NEGATE + (min_angle - target_angle);
462 }
463 if min_style == FontStyle::ITALIC {
464 return REVERSE + NEGATE;
465 }
466 return REVERSE + NEGATE + 1.0;
467 }
468
469 if target_angle >= 0.0 {
470 if min_style.is_oblique() {
471 let min_angle = min_style.oblique_degrees();
472 if min_angle > target_angle {
473 return REVERSE + (min_angle - target_angle);
474 }
475 let max_style = range.1;
476 let max_angle = max_style.oblique_degrees();
477 if max_angle >= target_angle {
478 return 0.0;
479 }
480 if max_angle > 0.0 {
481 return target_angle - max_angle;
482 }
483 return REVERSE + NEGATE + (target_angle - max_angle);
484 }
485 if min_style == FontStyle::ITALIC {
486 return REVERSE + NEGATE - 2.0;
487 }
488 return REVERSE + NEGATE - 1.0;
489 }
490
491 if min_style.is_oblique() {
493 let max_style = range.1;
494 let max_angle = max_style.oblique_degrees();
495 if max_angle < target_angle {
496 return REVERSE + (target_angle - max_angle);
497 }
498 let min_angle = min_style.oblique_degrees();
499 if min_angle <= target_angle {
500 return 0.0;
501 }
502 if min_angle < 0.0 {
503 return min_angle - target_angle;
504 }
505 return REVERSE + NEGATE + (min_angle - target_angle);
506 }
507 if min_style == FontStyle::ITALIC {
508 return REVERSE + NEGATE - 2.0;
509 }
510 REVERSE + NEGATE - 1.0
511 }
512
513 fn to_float(&self) -> f32 {
514 unimplemented!("Don't know how to convert FontStyle to float.");
515 }
516}
517
518pub trait IsOblique {
519 fn is_oblique(&self) -> bool;
520}
521
522impl IsOblique for FontStyle {
523 fn is_oblique(&self) -> bool {
524 *self != FontStyle::NORMAL && *self != FontStyle::ITALIC
525 }
526}