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