1use 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 read_fonts::collections::int_set::Domain;
12use read_fonts::types::Tag;
13use serde::{Deserialize, Serialize};
14use style::computed_values::font_optical_sizing::T as FontOpticalSizing;
15use style::computed_values::font_stretch::T as FontStretch;
16use style::computed_values::font_style::T as FontStyle;
17use style::stylesheets::{DocumentStyleSheet, FontFaceRule};
18use style::values::computed::font::FontWeight;
19use webrender_api::FontVariation;
20
21use crate::{CSSFontFaceDescriptors, ComputedFontStyleDescriptor, FontDescriptor, FontIdentifier};
22
23#[derive(Clone, Debug, MallocSizeOf)]
25pub struct FontTemplateRef(#[conditional_malloc_size_of] Arc<AtomicRefCell<FontTemplate>>);
26
27impl FontTemplateRef {
28 pub fn new(template: FontTemplate) -> Self {
29 Self(Arc::new(AtomicRefCell::new(template)))
30 }
31}
32
33impl Deref for FontTemplateRef {
34 type Target = Arc<AtomicRefCell<FontTemplate>>;
35 fn deref(&self) -> &Self::Target {
36 &self.0
37 }
38}
39
40#[derive(Clone, Debug, Deserialize, Hash, MallocSizeOf, PartialEq, Serialize)]
45pub struct FontTemplateDescriptor {
46 pub weight: (FontWeight, FontWeight),
47 pub stretch: (FontStretch, FontStretch),
48 pub style: (FontStyle, FontStyle),
49 #[ignore_malloc_size_of = "MallocSizeOf does not yet support RangeInclusive"]
50 pub unicode_range: Option<Vec<RangeInclusive<u32>>>,
51}
52
53impl Default for FontTemplateDescriptor {
54 fn default() -> Self {
55 Self::new(FontWeight::normal(), FontStretch::NORMAL, FontStyle::NORMAL)
56 }
57}
58
59impl Eq for FontTemplateDescriptor {}
62
63impl FontTemplateDescriptor {
64 #[inline]
65 pub fn new(weight: FontWeight, stretch: FontStretch, style: FontStyle) -> Self {
66 Self {
67 weight: (weight, weight),
68 stretch: (stretch, stretch),
69 style: (style, style),
70 unicode_range: None,
71 }
72 }
73
74 pub fn is_variation_font(&self) -> bool {
75 self.weight.0 != self.weight.1 ||
76 self.stretch.0 != self.stretch.1 ||
77 self.style.0 != self.style.1
78 }
79
80 #[inline]
87 fn distance_from(&self, target: &FontDescriptor) -> f32 {
88 let stretch_distance = target.stretch.match_distance(&self.stretch);
89 let style_distance = target.style.match_distance(&self.style);
90 let weight_distance = target.weight.match_distance(&self.weight);
91
92 assert!((0.0..=2000.0).contains(&stretch_distance));
95 assert!((0.0..=500.0).contains(&style_distance));
96 assert!((0.0..=1600.0).contains(&weight_distance));
97
98 const STRETCH_FACTOR: f32 = 1.0e8;
107 const STYLE_FACTOR: f32 = 1.0e4;
108 const WEIGHT_FACTOR: f32 = 1.0e0;
109
110 stretch_distance * STRETCH_FACTOR +
111 style_distance * STYLE_FACTOR +
112 weight_distance * WEIGHT_FACTOR
113 }
114
115 fn matches(&self, descriptor_to_match: &FontDescriptor) -> bool {
116 self.weight.0 <= descriptor_to_match.weight &&
117 self.weight.1 >= descriptor_to_match.weight &&
118 self.style.0 <= descriptor_to_match.style &&
119 self.style.1 >= descriptor_to_match.style &&
120 self.stretch.0 <= descriptor_to_match.stretch &&
121 self.stretch.1 >= descriptor_to_match.stretch
122 }
123
124 pub fn override_values_with_css_font_template_descriptors(
125 &mut self,
126 css_font_template_descriptors: &CSSFontFaceDescriptors,
127 ) {
128 if let Some(weight) = css_font_template_descriptors.weight {
129 self.weight = weight;
130 }
131 self.style = match css_font_template_descriptors.style {
132 Some(ComputedFontStyleDescriptor::Italic) => (FontStyle::ITALIC, FontStyle::ITALIC),
133 Some(ComputedFontStyleDescriptor::Oblique(angle_1, angle_2)) => (
134 FontStyle::oblique(angle_1.to_float()),
135 FontStyle::oblique(angle_2.to_float()),
136 ),
137 None => self.style,
138 };
139 if let Some(stretch) = css_font_template_descriptors.stretch {
140 self.stretch = stretch;
141 }
142 if let Some(ref unicode_range) = css_font_template_descriptors.unicode_range {
143 self.unicode_range = Some(unicode_range.clone());
144 }
145 }
146}
147
148#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
152pub struct FontTemplate {
153 pub identifier: FontIdentifier,
154 pub descriptor: FontTemplateDescriptor,
155 #[serde(skip)]
162 pub stylesheet: Option<DocumentStyleSheet>,
163
164 #[serde(skip)]
167 pub font_face_rule: Option<FontFaceRule>,
168}
169
170impl Debug for FontTemplate {
171 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
172 self.identifier.fmt(f)
173 }
174}
175
176impl FontTemplate {
180 pub fn new(
182 identifier: FontIdentifier,
183 descriptor: FontTemplateDescriptor,
184 stylesheet: Option<DocumentStyleSheet>,
185 font_face_rule: Option<FontFaceRule>,
186 ) -> FontTemplate {
187 assert!(
188 (stylesheet.is_some() && font_face_rule.is_some()) ||
189 (stylesheet.is_none() && font_face_rule.is_none())
190 );
191 FontTemplate {
192 identifier,
193 descriptor,
194 stylesheet,
195 font_face_rule,
196 }
197 }
198
199 pub fn new_for_local_web_font(
203 local_template: FontTemplateRef,
204 css_font_template_descriptors: &CSSFontFaceDescriptors,
205 stylesheet: Option<DocumentStyleSheet>,
206 font_face_rule: Option<FontFaceRule>,
207 ) -> Result<FontTemplate, &'static str> {
208 let mut alias_template = local_template.borrow().clone();
209 alias_template
210 .descriptor
211 .override_values_with_css_font_template_descriptors(css_font_template_descriptors);
212 alias_template.stylesheet = stylesheet;
213 alias_template.font_face_rule = font_face_rule;
214 Ok(alias_template)
215 }
216
217 pub fn identifier(&self) -> &FontIdentifier {
218 &self.identifier
219 }
220
221 pub fn compute_variations(&self, descriptor: &FontDescriptor) -> Vec<FontVariation> {
223 let mut variations: Vec<FontVariation> = vec![];
225
226 let mut add_variation = |variation: FontVariation| {
227 if !variations
228 .iter()
229 .any(|existing_variation| existing_variation.tag == variation.tag)
230 {
231 variations.push(variation);
232 }
233 };
234
235 descriptor
239 .variation_settings
240 .iter()
241 .copied()
242 .for_each(&mut add_variation);
243
244 if let Some(font_face_rule) = &self.font_face_rule {
250 if let Some(variation_settings) = font_face_rule.variation_settings.as_ref() {
253 variation_settings
254 .0
255 .iter()
256 .map(|variation| FontVariation {
257 tag: variation.tag.0,
258 value: variation.value.get(),
259 })
260 .for_each(&mut add_variation);
261 }
262 }
263
264 if descriptor.weight != FontWeight::NORMAL {
268 add_variation(FontVariation {
269 tag: Tag::new(b"wght").to_u32(),
270 value: descriptor.weight.value(),
271 });
272 }
273
274 if descriptor.stretch != FontStretch::NORMAL {
275 add_variation(FontVariation {
276 tag: Tag::new(b"wdth").to_u32(),
277 value: descriptor.stretch.0.to_float(),
278 });
279 }
280
281 if descriptor.optical_sizing == FontOpticalSizing::Auto {
283 add_variation(FontVariation {
284 tag: Tag::new(b"opsz").to_u32(),
285 value: descriptor.pt_size.to_f32_px(),
286 });
287 }
288
289 variations
290 }
291}
292
293pub trait FontTemplateRefMethods {
294 fn descriptor(&self) -> FontTemplateDescriptor;
296 fn identifier(&self) -> FontIdentifier;
298 fn matches_font_descriptor(&self, descriptor_to_match: &FontDescriptor) -> bool;
300 fn descriptor_distance(&self, descriptor_to_match: &FontDescriptor) -> f32;
303 fn char_in_unicode_range(&self, character: char) -> bool;
306
307 fn font_face_rule(&self) -> Option<AtomicRef<'_, FontFaceRule>>;
309}
310
311impl FontTemplateRefMethods for FontTemplateRef {
312 fn descriptor(&self) -> FontTemplateDescriptor {
313 self.borrow().descriptor.clone()
314 }
315
316 fn identifier(&self) -> FontIdentifier {
317 self.borrow().identifier.clone()
318 }
319
320 fn matches_font_descriptor(&self, descriptor_to_match: &FontDescriptor) -> bool {
321 self.descriptor().matches(descriptor_to_match)
322 }
323
324 fn descriptor_distance(&self, descriptor_to_match: &FontDescriptor) -> f32 {
325 self.descriptor().distance_from(descriptor_to_match)
326 }
327
328 fn char_in_unicode_range(&self, character: char) -> bool {
329 let character = character as u32;
330 self.borrow()
331 .descriptor
332 .unicode_range
333 .as_ref()
334 .is_none_or(|ranges| ranges.iter().any(|range| range.contains(&character)))
335 }
336
337 fn font_face_rule(&self) -> Option<AtomicRef<'_, FontFaceRule>> {
338 AtomicRef::filter_map(self.borrow(), |template| template.font_face_rule.as_ref())
339 }
340}
341
342trait FontMatchDistanceMethod: Sized {
348 fn match_distance(&self, range: &(Self, Self)) -> f32;
349 fn to_float(&self) -> f32;
350}
351
352impl FontMatchDistanceMethod for FontStretch {
353 fn match_distance(&self, range: &(Self, Self)) -> f32 {
354 const REVERSE_DISTANCE: f32 = 1000.0;
356
357 let min_stretch = range.0;
358 let max_stretch = range.1;
359
360 if *self < min_stretch {
366 if *self > FontStretch::NORMAL {
367 return min_stretch.to_float() - self.to_float();
368 }
369 return (min_stretch.to_float() - self.to_float()) + REVERSE_DISTANCE;
370 }
371
372 if *self > max_stretch {
373 if *self <= FontStretch::NORMAL {
374 return self.to_float() - max_stretch.to_float();
375 }
376 return (self.to_float() - max_stretch.to_float()) + REVERSE_DISTANCE;
377 }
378 0.0
379 }
380
381 fn to_float(&self) -> f32 {
382 self.0.to_float()
383 }
384}
385
386impl FontMatchDistanceMethod for FontWeight {
387 fn match_distance(&self, range: &(Self, Self)) -> f32 {
399 const NOT_WITHIN_CENTRAL_RANGE: f32 = 100.0;
401 const REVERSE_DISTANCE: f32 = 600.0;
402
403 let min_weight = range.0;
404 let max_weight = range.1;
405
406 if *self >= min_weight && *self <= max_weight {
407 return 0.0;
409 }
410
411 if *self < FontWeight::NORMAL {
412 if max_weight < *self {
414 return self.to_float() - max_weight.to_float();
415 }
416
417 return (min_weight.to_float() - self.to_float()) + REVERSE_DISTANCE;
419 }
420
421 if *self > FontWeight::from_float(500.) {
422 if min_weight > *self {
424 return min_weight.to_float() - self.to_float();
425 }
426 return (self.to_float() - max_weight.to_float()) + REVERSE_DISTANCE;
428 }
429
430 if min_weight > *self {
432 if min_weight <= FontWeight::from_float(500.) {
433 return min_weight.to_float() - self.to_float();
435 }
436 return (min_weight.to_float() - self.to_float()) + REVERSE_DISTANCE;
438 }
439 (self.to_float() - max_weight.to_float()) + NOT_WITHIN_CENTRAL_RANGE
441 }
442
443 fn to_float(&self) -> f32 {
444 self.value()
445 }
446}
447
448impl FontMatchDistanceMethod for FontStyle {
449 fn match_distance(&self, range: &(Self, Self)) -> f32 {
450 let min_style = range.0;
452 if *self == min_style {
453 return 0.0; }
455
456 const REVERSE: f32 = 100.0;
459
460 const NEGATE: f32 = 200.0;
463
464 if *self == FontStyle::NORMAL {
465 if min_style.is_oblique() {
466 let min_angle = min_style.oblique_degrees();
468 if min_angle >= 0.0 {
469 return 1.0 + min_angle;
470 }
471 let max_style = range.1;
472 let max_angle = max_style.oblique_degrees();
473 if max_angle >= 0.0 {
474 return 1.0;
476 }
477 return NEGATE - max_angle;
479 }
480 assert!(min_style == FontStyle::ITALIC);
483 return REVERSE;
484 }
485
486 let default_oblique_angle = FontStyle::OBLIQUE.oblique_degrees();
487 if *self == FontStyle::ITALIC {
488 if min_style.is_oblique() {
489 let min_angle = min_style.oblique_degrees();
490 if min_angle >= default_oblique_angle {
491 return 1.0 + (min_angle - default_oblique_angle);
492 }
493 let max_style = range.1;
494 let max_angle = max_style.oblique_degrees();
495 if max_angle >= default_oblique_angle {
496 return 1.0;
497 }
498 if max_angle > 0.0 {
499 return REVERSE + (default_oblique_angle - max_angle);
501 }
502 return REVERSE + NEGATE + (default_oblique_angle - max_angle);
504 }
505 assert!(min_style == FontStyle::NORMAL);
507 return NEGATE;
508 }
509
510 let target_angle = self.oblique_degrees();
514 if target_angle >= default_oblique_angle {
515 if min_style.is_oblique() {
516 let min_angle = min_style.oblique_degrees();
517 if min_angle >= target_angle {
518 return min_angle - target_angle;
519 }
520 let max_style = range.1;
521 let max_angle = max_style.oblique_degrees();
522 if max_angle >= target_angle {
523 return 0.0;
524 }
525 if max_angle > 0.0 {
526 return REVERSE + (target_angle - max_angle);
527 }
528 return REVERSE + NEGATE + (target_angle - max_angle);
529 }
530 if min_style == FontStyle::ITALIC {
531 return REVERSE + NEGATE;
532 }
533 return REVERSE + NEGATE + 1.0;
534 }
535
536 if target_angle <= -default_oblique_angle {
537 if min_style.is_oblique() {
538 let max_style = range.1;
539 let max_angle = max_style.oblique_degrees();
540 if max_angle <= target_angle {
541 return target_angle - max_angle;
542 }
543 let min_angle = min_style.oblique_degrees();
544 if min_angle <= target_angle {
545 return 0.0;
546 }
547 if min_angle < 0.0 {
548 return REVERSE + (min_angle - target_angle);
549 }
550 return REVERSE + NEGATE + (min_angle - target_angle);
551 }
552 if min_style == FontStyle::ITALIC {
553 return REVERSE + NEGATE;
554 }
555 return REVERSE + NEGATE + 1.0;
556 }
557
558 if target_angle >= 0.0 {
559 if min_style.is_oblique() {
560 let min_angle = min_style.oblique_degrees();
561 if min_angle > target_angle {
562 return REVERSE + (min_angle - target_angle);
563 }
564 let max_style = range.1;
565 let max_angle = max_style.oblique_degrees();
566 if max_angle >= target_angle {
567 return 0.0;
568 }
569 if max_angle > 0.0 {
570 return target_angle - max_angle;
571 }
572 return REVERSE + NEGATE + (target_angle - max_angle);
573 }
574 if min_style == FontStyle::ITALIC {
575 return REVERSE + NEGATE - 2.0;
576 }
577 return REVERSE + NEGATE - 1.0;
578 }
579
580 if min_style.is_oblique() {
582 let max_style = range.1;
583 let max_angle = max_style.oblique_degrees();
584 if max_angle < target_angle {
585 return REVERSE + (target_angle - max_angle);
586 }
587 let min_angle = min_style.oblique_degrees();
588 if min_angle <= target_angle {
589 return 0.0;
590 }
591 if min_angle < 0.0 {
592 return min_angle - target_angle;
593 }
594 return REVERSE + NEGATE + (min_angle - target_angle);
595 }
596 if min_style == FontStyle::ITALIC {
597 return REVERSE + NEGATE - 2.0;
598 }
599 REVERSE + NEGATE - 1.0
600 }
601
602 fn to_float(&self) -> f32 {
603 unimplemented!("Don't know how to convert FontStyle to float.");
604 }
605}
606
607pub trait IsOblique {
608 fn is_oblique(&self) -> bool;
609}
610
611impl IsOblique for FontStyle {
612 fn is_oblique(&self) -> bool {
613 *self != FontStyle::NORMAL && *self != FontStyle::ITALIC
614 }
615}