1use std::collections::{HashMap, HashSet};
6use std::default::Default;
7use std::hash::{Hash, Hasher};
8use std::ops::Deref;
9use std::sync::Arc;
10use std::sync::atomic::{AtomicBool, Ordering};
11
12use app_units::Au;
13use base::id::{PainterId, WebViewId};
14use compositing_traits::CrossProcessCompositorApi;
15use fonts_traits::{
16 CSSFontFaceDescriptors, FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef,
17 FontTemplateRefMethods, StylesheetWebFontLoadFinishedCallback,
18};
19use log::{debug, trace};
20use malloc_size_of_derive::MallocSizeOf;
21use net_traits::request::{Destination, Referrer, RequestBuilder};
22use net_traits::{CoreResourceThread, FetchResponseMsg, ResourceThreads, fetch_async};
23use parking_lot::{Mutex, RwLock};
24use rustc_hash::FxHashSet;
25use servo_arc::Arc as ServoArc;
26use servo_config::pref;
27use servo_url::{ImmutableOrigin, ServoUrl};
28use style::Atom;
29use style::computed_values::font_variant_caps::T as FontVariantCaps;
30use style::font_face::{
31 FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source, SourceList, UrlSource,
32};
33use style::media_queries::Device;
34use style::properties::style_structs::Font as FontStyleStruct;
35use style::shared_lock::SharedRwLockReadGuard;
36use style::stylesheets::{
37 CssRule, CustomMediaMap, DocumentStyleSheet, FontFaceRule, StylesheetInDocument,
38};
39use style::values::computed::font::{FamilyName, FontFamilyNameSyntax, SingleFontFamily};
40use url::Url;
41use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation};
42
43use crate::font::{Font, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope};
44use crate::font_store::CrossThreadFontStore;
45use crate::platform::font::PlatformFont;
46use crate::{FontData, LowercaseFontFamilyName, PlatformFontMethods, SystemFontServiceProxy};
47
48static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; #[derive(Eq, Hash, MallocSizeOf, PartialEq)]
51pub(crate) struct FontParameters {
52 pub(crate) font_key: FontKey,
53 pub(crate) pt_size: Au,
54 pub(crate) variations: Vec<FontVariation>,
55 pub(crate) flags: FontInstanceFlags,
56}
57
58#[derive(MallocSizeOf)]
59struct FontGroupRef(#[conditional_malloc_size_of] Arc<RwLock<FontGroup>>);
60
61impl Deref for FontGroupRef {
62 type Target = Arc<RwLock<FontGroup>>;
63 fn deref(&self) -> &Self::Target {
64 &self.0
65 }
66}
67
68#[derive(MallocSizeOf)]
73pub struct FontContext {
74 #[conditional_malloc_size_of]
75 system_font_service_proxy: Arc<SystemFontServiceProxy>,
76
77 resource_threads: Mutex<CoreResourceThread>,
78
79 compositor_api: Mutex<CrossProcessCompositorApi>,
81
82 fonts: RwLock<HashMap<FontCacheKey, Option<FontRef>>>,
85
86 resolved_font_groups: RwLock<HashMap<FontGroupCacheKey, FontGroupRef>>,
90
91 web_fonts: CrossThreadFontStore,
92
93 webrender_font_keys: RwLock<HashMap<FontIdentifier, FontKey>>,
96
97 webrender_font_instance_keys: RwLock<HashMap<FontParameters, FontInstanceKey>>,
100
101 font_data: RwLock<HashMap<FontIdentifier, FontData>>,
104
105 have_removed_web_fonts: AtomicBool,
106}
107
108impl FontContext {
109 pub fn new(
110 system_font_service_proxy: Arc<SystemFontServiceProxy>,
111 compositor_api: CrossProcessCompositorApi,
112 resource_threads: ResourceThreads,
113 ) -> Self {
114 #[allow(clippy::default_constructed_unit_structs)]
115 Self {
116 system_font_service_proxy,
117 resource_threads: Mutex::new(resource_threads.core_thread),
118 compositor_api: Mutex::new(compositor_api),
119 fonts: Default::default(),
120 resolved_font_groups: Default::default(),
121 web_fonts: Default::default(),
122 webrender_font_keys: RwLock::default(),
123 webrender_font_instance_keys: RwLock::default(),
124 have_removed_web_fonts: AtomicBool::new(false),
125 font_data: RwLock::default(),
126 }
127 }
128
129 pub fn web_fonts_still_loading(&self) -> usize {
130 self.web_fonts.read().number_of_fonts_still_loading()
131 }
132
133 fn get_font_data(&self, identifier: &FontIdentifier) -> Option<FontData> {
134 match identifier {
135 FontIdentifier::Web(_) => self.font_data.read().get(identifier).cloned(),
136 FontIdentifier::Local(_) => None,
137 }
138 }
139
140 pub fn font_group(&self, style: ServoArc<FontStyleStruct>) -> Arc<RwLock<FontGroup>> {
144 let font_size = style.font_size.computed_size().into();
145 self.font_group_with_size(style, font_size)
146 }
147
148 pub fn font_group_with_size(
151 &self,
152 style: ServoArc<FontStyleStruct>,
153 size: Au,
154 ) -> Arc<RwLock<FontGroup>> {
155 let cache_key = FontGroupCacheKey { size, style };
156 if let Some(font_group) = self.resolved_font_groups.read().get(&cache_key) {
157 return font_group.0.clone();
158 }
159
160 let mut descriptor = FontDescriptor::from(&*cache_key.style);
161 descriptor.pt_size = size;
162
163 let font_group = Arc::new(RwLock::new(FontGroup::new(&cache_key.style, descriptor)));
164 self.resolved_font_groups
165 .write()
166 .insert(cache_key, FontGroupRef(font_group.clone()));
167 font_group
168 }
169
170 pub fn font(
173 &self,
174 font_template: FontTemplateRef,
175 font_descriptor: &FontDescriptor,
176 ) -> Option<FontRef> {
177 self.get_font_maybe_synthesizing_small_caps(
178 font_template,
179 font_descriptor,
180 true, )
182 }
183
184 fn get_font_maybe_synthesizing_small_caps(
185 &self,
186 font_template: FontTemplateRef,
187 font_descriptor: &FontDescriptor,
188 synthesize_small_caps: bool,
189 ) -> Option<FontRef> {
190 let synthesized_small_caps_font =
194 if font_descriptor.variant == FontVariantCaps::SmallCaps && synthesize_small_caps {
195 let mut small_caps_descriptor = font_descriptor.clone();
196 small_caps_descriptor.pt_size =
197 font_descriptor.pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR);
198 self.get_font_maybe_synthesizing_small_caps(
199 font_template.clone(),
200 &small_caps_descriptor,
201 false, )
203 } else {
204 None
205 };
206
207 let cache_key = FontCacheKey {
208 font_identifier: font_template.identifier(),
209 font_descriptor: font_descriptor.clone(),
210 };
211
212 if let Some(font) = self.fonts.read().get(&cache_key).cloned() {
213 return font;
214 }
215
216 debug!(
217 "FontContext::font cache miss for font_template={:?} font_descriptor={:?}",
218 font_template, font_descriptor
219 );
220
221 let font = self
224 .create_font(
225 font_template,
226 font_descriptor.to_owned(),
227 synthesized_small_caps_font,
228 )
229 .ok();
230 self.fonts.write().insert(cache_key, font.clone());
231 font
232 }
233
234 fn matching_web_font_templates(
235 &self,
236 descriptor_to_match: &FontDescriptor,
237 family_descriptor: &FontFamilyDescriptor,
238 ) -> Option<Vec<FontTemplateRef>> {
239 if family_descriptor.scope != FontSearchScope::Any {
240 return None;
241 }
242
243 let SingleFontFamily::FamilyName(ref family_name) = family_descriptor.family else {
245 return None;
246 };
247
248 self.web_fonts
249 .read()
250 .families
251 .get(&family_name.name.clone().into())
252 .map(|templates| templates.find_for_descriptor(Some(descriptor_to_match)))
253 }
254
255 pub fn matching_templates(
258 &self,
259 descriptor_to_match: &FontDescriptor,
260 family_descriptor: &FontFamilyDescriptor,
261 ) -> Vec<FontTemplateRef> {
262 self.matching_web_font_templates(descriptor_to_match, family_descriptor)
263 .unwrap_or_else(|| {
264 self.system_font_service_proxy.find_matching_font_templates(
265 Some(descriptor_to_match),
266 &family_descriptor.family,
267 )
268 })
269 }
270
271 #[servo_tracing::instrument(skip_all)]
274 fn create_font(
275 &self,
276 font_template: FontTemplateRef,
277 font_descriptor: FontDescriptor,
278 synthesized_small_caps: Option<FontRef>,
279 ) -> Result<FontRef, &'static str> {
280 Ok(FontRef(Arc::new(Font::new(
281 font_template.clone(),
282 font_descriptor,
283 self.get_font_data(&font_template.identifier()),
284 synthesized_small_caps,
285 )?)))
286 }
287
288 pub(crate) fn create_font_instance_key(
289 &self,
290 font: &Font,
291 painter_id: PainterId,
292 ) -> FontInstanceKey {
293 match font.template.identifier() {
294 FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance(
295 font.template.identifier(),
296 font.descriptor.pt_size,
297 font.webrender_font_instance_flags(),
298 font.variations().to_owned(),
299 painter_id,
300 ),
301 FontIdentifier::Web(_) => self.create_web_font_instance(
302 font.template.clone(),
303 font.descriptor.pt_size,
304 font.webrender_font_instance_flags(),
305 font.variations().to_owned(),
306 painter_id,
307 ),
308 }
309 }
310
311 fn create_web_font_instance(
312 &self,
313 font_template: FontTemplateRef,
314 pt_size: Au,
315 flags: FontInstanceFlags,
316 variations: Vec<FontVariation>,
317 painter_id: PainterId,
318 ) -> FontInstanceKey {
319 let identifier = font_template.identifier().clone();
320 let font_data = self
321 .get_font_data(&identifier)
322 .expect("Web font should have associated font data");
323 let font_key = *self
324 .webrender_font_keys
325 .write()
326 .entry(identifier.clone())
327 .or_insert_with(|| {
328 let font_key = self.system_font_service_proxy.generate_font_key(painter_id);
329 self.compositor_api.lock().add_font(
330 font_key,
331 font_data.as_ipc_shared_memory(),
332 identifier.index(),
333 );
334 font_key
335 });
336
337 let entry_key = FontParameters {
338 font_key,
339 pt_size,
340 variations: variations.clone(),
341 flags,
342 };
343 *self
344 .webrender_font_instance_keys
345 .write()
346 .entry(entry_key)
347 .or_insert_with(|| {
348 let font_instance_key = self
349 .system_font_service_proxy
350 .generate_font_instance_key(painter_id);
351 self.compositor_api.lock().add_font_instance(
352 font_instance_key,
353 font_key,
354 pt_size.to_f32_px(),
355 flags,
356 variations,
357 );
358 font_instance_key
359 })
360 }
361
362 fn invalidate_font_groups_after_web_font_load(&self) {
363 self.resolved_font_groups.write().clear();
364 }
365
366 pub fn is_supported_web_font_source(source: &&Source) -> bool {
367 let url_source = match &source {
368 Source::Url(url_source) => url_source,
369 Source::Local(_) => return true,
370 };
371 let format_hint = match url_source.format_hint {
372 Some(ref format_hint) => format_hint,
373 None => return true,
374 };
375
376 if matches!(
377 format_hint,
378 FontFaceSourceFormat::Keyword(
379 FontFaceSourceFormatKeyword::Truetype |
380 FontFaceSourceFormatKeyword::Opentype |
381 FontFaceSourceFormatKeyword::Woff |
382 FontFaceSourceFormatKeyword::Woff2
383 )
384 ) {
385 return true;
386 }
387
388 if let FontFaceSourceFormat::String(string) = format_hint {
389 if string == "truetype" || string == "opentype" || string == "woff" || string == "woff2"
390 {
391 return true;
392 }
393
394 return pref!(layout_variable_fonts_enabled) &&
395 (string == "truetype-variations" ||
396 string == "opentype-variations" ||
397 string == "woff-variations" ||
398 string == "woff2-variations");
399 }
400
401 false
402 }
403}
404
405pub(crate) struct WebFontDownloadState {
406 webview_id: Option<WebViewId>,
407 css_font_face_descriptors: CSSFontFaceDescriptors,
408 remaining_sources: Vec<Source>,
409 core_resource_thread: CoreResourceThread,
410 local_fonts: HashMap<Atom, Option<FontTemplateRef>>,
411 font_context: Arc<FontContext>,
412 initiator: WebFontLoadInitiator,
413}
414
415impl WebFontDownloadState {
416 fn new(
417 webview_id: Option<WebViewId>,
418 font_context: Arc<FontContext>,
419 css_font_face_descriptors: CSSFontFaceDescriptors,
420 initiator: WebFontLoadInitiator,
421 sources: Vec<Source>,
422 local_fonts: HashMap<Atom, Option<FontTemplateRef>>,
423 ) -> WebFontDownloadState {
424 match initiator {
425 WebFontLoadInitiator::Stylesheet(ref stylesheet, _) => {
426 font_context
427 .web_fonts
428 .write()
429 .handle_web_font_load_started_for_stylesheet(stylesheet);
430 },
431 WebFontLoadInitiator::Script(_) => {
432 font_context
433 .web_fonts
434 .write()
435 .handle_web_font_load_started_for_script();
436 },
437 };
438 let core_resource_thread = font_context.resource_threads.lock().clone();
439 WebFontDownloadState {
440 webview_id,
441 css_font_face_descriptors,
442 remaining_sources: sources,
443 core_resource_thread,
444 local_fonts,
445 font_context,
446 initiator,
447 }
448 }
449
450 fn handle_web_font_load_success(self, new_template: FontTemplate) {
451 let family_name = self.css_font_face_descriptors.family_name.clone();
452 match self.initiator {
453 WebFontLoadInitiator::Stylesheet(ref stylesheet, ref callback) => {
454 let not_cancelled = self
455 .font_context
456 .web_fonts
457 .write()
458 .handle_web_font_loaded_for_stylesheet(stylesheet, family_name, new_template);
459 self.font_context
460 .invalidate_font_groups_after_web_font_load();
461 callback(not_cancelled);
462 },
463 WebFontLoadInitiator::Script(callback) => {
464 self.font_context
465 .web_fonts
466 .write()
467 .handle_web_font_load_finished_for_script();
468 callback(family_name, Some(new_template));
469 },
470 }
471 }
472
473 fn handle_web_font_load_failure(self) {
474 let family_name = self.css_font_face_descriptors.family_name.clone();
475 match self.initiator {
476 WebFontLoadInitiator::Stylesheet(ref stylesheet, ref callback) => {
477 self.font_context
478 .web_fonts
479 .write()
480 .handle_web_font_load_failed_for_stylesheet(stylesheet);
481 callback(false);
482 },
483 WebFontLoadInitiator::Script(callback) => {
484 self.font_context
485 .web_fonts
486 .write()
487 .handle_web_font_load_finished_for_script();
488 callback(family_name, None);
489 },
490 }
491 }
492
493 fn font_load_cancelled(&self) -> bool {
494 match self.initiator {
495 WebFontLoadInitiator::Stylesheet(ref stylesheet, _) => self
496 .font_context
497 .web_fonts
498 .read()
499 .font_load_cancelled_for_stylesheet(stylesheet),
500 WebFontLoadInitiator::Script(_) => false,
501 }
502 }
503}
504
505pub trait FontContextWebFontMethods {
506 fn add_all_web_fonts_from_stylesheet(
507 &self,
508 webview_id: WebViewId,
509 stylesheet: &DocumentStyleSheet,
510 guard: &SharedRwLockReadGuard,
511 device: &Device,
512 finished_callback: StylesheetWebFontLoadFinishedCallback,
513 ) -> usize;
514 fn load_web_font_for_script(
515 &self,
516 webview_id: Option<WebViewId>,
517 source_list: SourceList,
518 descriptors: CSSFontFaceDescriptors,
519 finished_callback: ScriptWebFontLoadFinishedCallback,
520 );
521 fn add_template_to_font_context(
522 &self,
523 family_name: LowercaseFontFamilyName,
524 font_template: FontTemplate,
525 );
526 fn remove_all_web_fonts_from_stylesheet(&self, stylesheet: &DocumentStyleSheet);
527 fn collect_unused_webrender_resources(&self, all: bool)
528 -> (Vec<FontKey>, Vec<FontInstanceKey>);
529}
530
531impl FontContextWebFontMethods for Arc<FontContext> {
532 fn add_all_web_fonts_from_stylesheet(
533 &self,
534 webview_id: WebViewId,
535 stylesheet: &DocumentStyleSheet,
536 guard: &SharedRwLockReadGuard,
537 device: &Device,
538 finished_callback: StylesheetWebFontLoadFinishedCallback,
539 ) -> usize {
540 let mut number_loading = 0;
541 let custom_media = &CustomMediaMap::default();
542 for rule in stylesheet
543 .contents(guard)
544 .effective_rules(device, custom_media, guard)
545 {
546 let CssRule::FontFace(ref lock) = *rule else {
547 continue;
548 };
549
550 let rule: &FontFaceRule = lock.read_with(guard);
551 let Some(font_face) = rule.font_face() else {
552 continue;
553 };
554
555 let css_font_face_descriptors = rule.into();
556 let completion_handler =
557 WebFontLoadInitiator::Stylesheet(stylesheet.clone(), finished_callback.clone());
558
559 number_loading += 1;
560 self.start_loading_one_web_font(
561 Some(webview_id),
562 font_face.sources(),
563 css_font_face_descriptors,
564 completion_handler,
565 );
566 }
567
568 number_loading
569 }
570
571 fn remove_all_web_fonts_from_stylesheet(&self, stylesheet: &DocumentStyleSheet) {
572 let mut web_fonts = self.web_fonts.write();
573 let mut fonts = self.fonts.write();
574 let mut font_groups = self.resolved_font_groups.write();
575
576 web_fonts.handle_stylesheet_removed(stylesheet);
578
579 let mut removed_any = false;
580 for family in web_fonts.families.values_mut() {
581 removed_any |= family.remove_templates_for_stylesheet(stylesheet);
582 }
583 if !removed_any {
584 return;
585 };
586
587 fonts.retain(|_, font| match font {
588 Some(font) => font.template.borrow().stylesheet.as_ref() != Some(stylesheet),
589 _ => true,
590 });
591
592 font_groups.clear();
595
596 self.have_removed_web_fonts.store(true, Ordering::Relaxed);
598 }
599
600 fn collect_unused_webrender_resources(
601 &self,
602 all: bool,
603 ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
604 if all {
605 let mut webrender_font_keys = self.webrender_font_keys.write();
606 let mut webrender_font_instance_keys = self.webrender_font_instance_keys.write();
607 self.have_removed_web_fonts.store(false, Ordering::Relaxed);
608 return (
609 webrender_font_keys.drain().map(|(_, key)| key).collect(),
610 webrender_font_instance_keys
611 .drain()
612 .map(|(_, key)| key)
613 .collect(),
614 );
615 }
616
617 if !self.have_removed_web_fonts.load(Ordering::Relaxed) {
618 return (Vec::new(), Vec::new());
619 }
620
621 let web_fonts = self.web_fonts.write();
623 let mut font_data = self.font_data.write();
624 let _fonts = self.fonts.write();
625 let _font_groups = self.resolved_font_groups.write();
626 let mut webrender_font_keys = self.webrender_font_keys.write();
627 let mut webrender_font_instance_keys = self.webrender_font_instance_keys.write();
628
629 let mut unused_identifiers: HashSet<FontIdentifier> =
630 webrender_font_keys.keys().cloned().collect();
631 for templates in web_fonts.families.values() {
632 templates.for_all_identifiers(|identifier| {
633 unused_identifiers.remove(identifier);
634 });
635 }
636
637 font_data.retain(|font_identifier, _| !unused_identifiers.contains(font_identifier));
638
639 self.have_removed_web_fonts.store(false, Ordering::Relaxed);
640
641 let mut removed_keys: FxHashSet<FontKey> = FxHashSet::default();
642 webrender_font_keys.retain(|identifier, font_key| {
643 if unused_identifiers.contains(identifier) {
644 removed_keys.insert(*font_key);
645 false
646 } else {
647 true
648 }
649 });
650
651 let mut removed_instance_keys: HashSet<FontInstanceKey> = HashSet::new();
652 webrender_font_instance_keys.retain(|font_param, instance_key| {
653 if removed_keys.contains(&font_param.font_key) {
654 removed_instance_keys.insert(*instance_key);
655 false
656 } else {
657 true
658 }
659 });
660
661 (
662 removed_keys.into_iter().collect(),
663 removed_instance_keys.into_iter().collect(),
664 )
665 }
666
667 fn load_web_font_for_script(
668 &self,
669 webview_id: Option<WebViewId>,
670 sources: SourceList,
671 descriptors: CSSFontFaceDescriptors,
672 finished_callback: ScriptWebFontLoadFinishedCallback,
673 ) {
674 let completion_handler = WebFontLoadInitiator::Script(finished_callback);
675 self.start_loading_one_web_font(webview_id, &sources, descriptors, completion_handler);
676 }
677
678 fn add_template_to_font_context(
679 &self,
680 family_name: LowercaseFontFamilyName,
681 new_template: FontTemplate,
682 ) {
683 self.web_fonts
684 .write()
685 .add_new_template(family_name, new_template);
686 self.invalidate_font_groups_after_web_font_load();
687 }
688}
689
690impl FontContext {
691 fn start_loading_one_web_font(
692 self: &Arc<FontContext>,
693 webview_id: Option<WebViewId>,
694 source_list: &SourceList,
695 css_font_face_descriptors: CSSFontFaceDescriptors,
696 completion_handler: WebFontLoadInitiator,
697 ) {
698 let sources: Vec<Source> = source_list
699 .0
700 .iter()
701 .rev()
702 .filter(Self::is_supported_web_font_source)
703 .cloned()
704 .collect();
705
706 let mut local_fonts = HashMap::new();
714 for source in sources.iter() {
715 if let Source::Local(family_name) = source {
716 local_fonts
717 .entry(family_name.name.clone())
718 .or_insert_with(|| {
719 let family = SingleFontFamily::FamilyName(FamilyName {
720 name: family_name.name.clone(),
721 syntax: FontFamilyNameSyntax::Quoted,
722 });
723 self.system_font_service_proxy
724 .find_matching_font_templates(None, &family)
725 .first()
726 .cloned()
727 });
728 }
729 }
730
731 self.process_next_web_font_source(WebFontDownloadState::new(
732 webview_id,
733 self.clone(),
734 css_font_face_descriptors,
735 completion_handler,
736 sources,
737 local_fonts,
738 ));
739 }
740
741 fn process_next_web_font_source(self: &Arc<FontContext>, mut state: WebFontDownloadState) {
742 let Some(source) = state.remaining_sources.pop() else {
743 state.handle_web_font_load_failure();
744 return;
745 };
746
747 let this = self.clone();
748 let web_font_family_name = state.css_font_face_descriptors.family_name.clone();
749 match source {
750 Source::Url(url_source) => {
751 RemoteWebFontDownloader::download(url_source, this, web_font_family_name, state)
752 },
753 Source::Local(ref local_family_name) => {
754 if let Some(new_template) = state
755 .local_fonts
756 .get(&local_family_name.name)
757 .cloned()
758 .flatten()
759 .and_then(|local_template| {
760 let template = FontTemplate::new_for_local_web_font(
761 local_template.clone(),
762 &state.css_font_face_descriptors,
763 state.initiator.stylesheet().cloned(),
764 )
765 .ok()?;
766 Some(template)
767 })
768 {
769 state.handle_web_font_load_success(new_template);
770 } else {
771 this.process_next_web_font_source(state);
772 }
773 },
774 }
775 }
776}
777
778pub(crate) type ScriptWebFontLoadFinishedCallback =
779 Box<dyn FnOnce(LowercaseFontFamilyName, Option<FontTemplate>) + Send>;
780
781pub(crate) enum WebFontLoadInitiator {
782 Stylesheet(DocumentStyleSheet, StylesheetWebFontLoadFinishedCallback),
783 Script(ScriptWebFontLoadFinishedCallback),
784}
785
786impl WebFontLoadInitiator {
787 pub(crate) fn stylesheet(&self) -> Option<&DocumentStyleSheet> {
788 match self {
789 Self::Stylesheet(stylesheet, _) => Some(stylesheet),
790 Self::Script(_) => None,
791 }
792 }
793}
794
795struct RemoteWebFontDownloader {
796 state: Option<WebFontDownloadState>,
797 url: ServoArc<Url>,
798 web_font_family_name: LowercaseFontFamilyName,
799 response_valid: bool,
800 response_data: Vec<u8>,
801}
802
803enum DownloaderResponseResult {
804 InProcess,
805 Finished,
806 Failure,
807}
808
809impl RemoteWebFontDownloader {
810 fn download(
811 url_source: UrlSource,
812 font_context: Arc<FontContext>,
813 web_font_family_name: LowercaseFontFamilyName,
814 state: WebFontDownloadState,
815 ) {
816 let url = match url_source.url.url() {
818 Some(url) => url.clone(),
819 None => return,
820 };
821
822 let request =
824 RequestBuilder::new(state.webview_id, url.clone().into(), Referrer::NoReferrer)
825 .policy_container(Default::default())
827 .origin(ImmutableOrigin::new(url.origin()))
829 .destination(Destination::Font);
830
831 let core_resource_thread_clone = state.core_resource_thread.clone();
832
833 debug!("Loading @font-face {} from {}", web_font_family_name, url);
834 let mut downloader = Self {
835 url,
836 web_font_family_name,
837 response_valid: false,
838 response_data: Vec::new(),
839 state: Some(state),
840 };
841
842 fetch_async(
843 &core_resource_thread_clone,
844 request,
845 None,
846 Box::new(move |response_message| {
847 match downloader.handle_web_font_fetch_message(response_message) {
848 DownloaderResponseResult::InProcess => {},
849 DownloaderResponseResult::Finished => {
850 if !downloader.process_downloaded_font_and_signal_completion() {
851 font_context.process_next_web_font_source(downloader.take_state())
852 }
853 },
854 DownloaderResponseResult::Failure => {
855 font_context.process_next_web_font_source(downloader.take_state())
856 },
857 }
858 }),
859 )
860 }
861
862 fn take_state(&mut self) -> WebFontDownloadState {
863 self.state
864 .take()
865 .expect("must be non-None until download either succeeds or fails")
866 }
867
868 fn process_downloaded_font_and_signal_completion(&mut self) -> bool {
871 let state = self
872 .state
873 .as_ref()
874 .expect("must be non-None until processing is completed");
875 if state.font_load_cancelled() {
876 self.take_state().handle_web_font_load_failure();
877 return true;
879 }
880
881 let font_data = std::mem::take(&mut self.response_data);
882 trace!(
883 "Downloaded @font-face {} ({} bytes)",
884 self.web_font_family_name,
885 font_data.len()
886 );
887
888 let font_data = match fontsan::process(&font_data) {
889 Ok(bytes) => FontData::from_bytes(&bytes),
890 Err(error) => {
891 debug!(
892 "Sanitiser rejected web font: family={} url={:?} with {error:?}",
893 self.web_font_family_name, self.url,
894 );
895 return false;
896 },
897 };
898
899 let url: ServoUrl = self.url.clone().into();
900 let identifier = FontIdentifier::Web(url.clone());
901 let Ok(handle) = PlatformFont::new_from_data(identifier, &font_data, None, &[], false)
902 else {
903 return false;
904 };
905 let state = self.take_state();
906
907 let mut descriptor = handle.descriptor();
908 descriptor
909 .override_values_with_css_font_template_descriptors(&state.css_font_face_descriptors);
910
911 let new_template = FontTemplate::new(
912 FontIdentifier::Web(url),
913 descriptor,
914 state.initiator.stylesheet().cloned(),
915 );
916
917 state
918 .font_context
919 .font_data
920 .write()
921 .insert(new_template.identifier.clone(), font_data);
922
923 state.handle_web_font_load_success(new_template);
924
925 true
928 }
929
930 fn handle_web_font_fetch_message(
931 &mut self,
932 response_message: FetchResponseMsg,
933 ) -> DownloaderResponseResult {
934 match response_message {
935 FetchResponseMsg::ProcessRequestBody(..) |
936 FetchResponseMsg::ProcessRequestEOF(..) |
937 FetchResponseMsg::ProcessCspViolations(..) => DownloaderResponseResult::InProcess,
938 FetchResponseMsg::ProcessResponse(_, meta_result) => {
939 trace!(
940 "@font-face {} metadata ok={:?}",
941 self.web_font_family_name,
942 meta_result.is_ok()
943 );
944 self.response_valid = meta_result.is_ok();
945 DownloaderResponseResult::InProcess
946 },
947 FetchResponseMsg::ProcessResponseChunk(_, new_bytes) => {
948 trace!(
949 "@font-face {} chunk={:?}",
950 self.web_font_family_name, new_bytes
951 );
952 if self.response_valid {
953 self.response_data.extend(new_bytes.0)
954 }
955 DownloaderResponseResult::InProcess
956 },
957 FetchResponseMsg::ProcessResponseEOF(_, response) => {
958 trace!(
959 "@font-face {} EOF={:?}",
960 self.web_font_family_name, response
961 );
962 if response.is_err() || !self.response_valid {
963 return DownloaderResponseResult::Failure;
964 }
965 DownloaderResponseResult::Finished
966 },
967 }
968 }
969}
970
971#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
972struct FontCacheKey {
973 font_identifier: FontIdentifier,
974 font_descriptor: FontDescriptor,
975}
976
977#[derive(Debug, MallocSizeOf)]
978struct FontGroupCacheKey {
979 #[ignore_malloc_size_of = "This is also stored as part of styling."]
980 style: ServoArc<FontStyleStruct>,
981 size: Au,
982}
983
984impl PartialEq for FontGroupCacheKey {
985 fn eq(&self, other: &FontGroupCacheKey) -> bool {
986 self.style == other.style && self.size == other.size
987 }
988}
989
990impl Eq for FontGroupCacheKey {}
991
992impl Hash for FontGroupCacheKey {
993 fn hash<H>(&self, hasher: &mut H)
994 where
995 H: Hasher,
996 {
997 self.style.hash.hash(hasher)
998 }
999}