1use std::collections::hash_map::Entry;
6use std::collections::{HashMap, HashSet};
7use std::default::Default;
8use std::hash::{Hash, Hasher};
9use std::iter;
10use std::sync::Arc;
11use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
12
13use app_units::Au;
14use content_security_policy::Violation;
15use fonts_traits::{
16 CSSFontFaceDescriptors, FontDescriptor, FontFaceRuleInfo, FontIdentifier, FontTemplate,
17 FontTemplateRef, FontTemplateRefMethods, StylesheetWebFontLoadFinishedCallback,
18 WebFontLoadEvent, WebFontSetDifference,
19};
20use log::{debug, trace};
21use malloc_size_of::MallocSizeOf;
22use malloc_size_of_derive::MallocSizeOf;
23use net_traits::blob_url_store::UrlWithBlobClaim;
24use net_traits::policy_container::PolicyContainer;
25use net_traits::request::{
26 CredentialsMode, Destination, Referrer, RequestBuilder, RequestClient, RequestMode,
27 ServiceWorkersMode,
28};
29use net_traits::{
30 CoreResourceThread, FetchResponseMsg, ResourceFetchTiming, ResourceThreads, fetch_async,
31};
32use paint_api::CrossProcessPaintApi;
33use parking_lot::{Mutex, RwLock};
34use rustc_hash::{FxHashMap, FxHashSet};
35use servo_arc::Arc as ServoArc;
36use servo_base::id::{PainterId, WebViewId};
37use servo_config::pref;
38use servo_url::ServoUrl;
39use style::Atom;
40use style::computed_values::font_variant_caps::T as FontVariantCaps;
41use style::font_face::{
42 FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source, SourceList, UrlSource,
43};
44use style::properties::generated::font_face::Descriptors as FontFaceRuleDescriptors;
45use style::properties::style_structs::Font as FontStyleStruct;
46use style::shared_lock::StylesheetGuards;
47use style::stylesheets::{FontFaceRule, LockedFontFaceRule, Origin};
48use style::stylist::Stylist;
49use style::values::computed::FontVariantAlternates;
50use style::values::computed::font::{FamilyName, FontFamilyNameSyntax, SingleFontFamily};
51use style::values::specified::font::VariantAlternates;
52use url::Url;
53use uuid::Uuid;
54use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation};
55
56use crate::font::{Font, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope};
57use crate::font_feature_values::{
58 AlternateKindRequiringResolution, FontFeatureValue, FontFeatureValueMap,
59 ResolvedFontVariantAlternates,
60};
61use crate::font_store::{CrossThreadFontStore, FontStore};
62use crate::platform::font::PlatformFont;
63use crate::{FontData, LowercaseFontFamilyName, PlatformFontMethods, SystemFontServiceProxy};
64
65static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; #[derive(Eq, Hash, MallocSizeOf, PartialEq)]
68pub(crate) struct FontParameters {
69 pub(crate) font_key: FontKey,
70 pub(crate) pt_size: Au,
71 pub(crate) variations: Vec<FontVariation>,
72 pub(crate) flags: FontInstanceFlags,
73}
74
75pub type FontGroupRef = Arc<FontGroup>;
76
77#[derive(MallocSizeOf)]
82pub struct FontContext {
83 #[conditional_malloc_size_of]
84 system_font_service_proxy: Arc<SystemFontServiceProxy>,
85
86 resource_threads: Mutex<CoreResourceThread>,
87
88 paint_api: Mutex<CrossProcessPaintApi>,
90
91 fonts: RwLock<HashMap<FontCacheKey, Option<FontRef>>>,
94
95 #[conditional_malloc_size_of]
99 resolved_font_groups: RwLock<HashMap<FontGroupCacheKey, FontGroupRef>>,
100
101 web_fonts: CrossThreadFontStore,
102
103 webrender_font_keys: RwLock<HashMap<FontIdentifier, FontKey>>,
106
107 webrender_font_instance_keys: RwLock<HashMap<FontParameters, FontInstanceKey>>,
110
111 font_data: RwLock<HashMap<FontIdentifier, FontData>>,
114
115 have_removed_web_fonts: AtomicBool,
116
117 currently_downloading_fonts: Mutex<HashMap<ServoUrl, Vec<WebFontDownloadState>>>,
120
121 known_font_face_rules: Mutex<KnownFontFaceRules>,
125
126 font_feature_value_map: RwLock<Option<FontFeatureValueMap>>,
128
129 number_of_loading_web_fonts: AtomicUsize,
131}
132
133pub trait CspViolationHandler: Send + std::fmt::Debug + MallocSizeOf {
137 fn process_violations(&self, violations: Vec<Violation>);
138 fn clone(&self) -> Box<dyn CspViolationHandler>;
139}
140
141pub trait NetworkTimingHandler: Send + std::fmt::Debug + MallocSizeOf {
144 fn submit_timing(&self, url: ServoUrl, response: ResourceFetchTiming);
145 fn clone(&self) -> Box<dyn NetworkTimingHandler>;
146}
147
148#[derive(Debug, MallocSizeOf)]
150pub struct WebFontDocumentContext {
151 pub policy_container: PolicyContainer,
152 pub request_client: RequestClient,
153 pub document_url: ServoUrl,
154 pub csp_handler: Box<dyn CspViolationHandler>,
155 pub network_timing_handler: Box<dyn NetworkTimingHandler>,
156}
157
158impl Clone for WebFontDocumentContext {
159 fn clone(&self) -> WebFontDocumentContext {
160 Self {
161 policy_container: self.policy_container.clone(),
162 request_client: self.request_client.clone(),
163 document_url: self.document_url.clone(),
164 csp_handler: self.csp_handler.clone(),
165 network_timing_handler: self.network_timing_handler.clone(),
166 }
167 }
168}
169
170impl FontContext {
171 pub fn new(
172 system_font_service_proxy: Arc<SystemFontServiceProxy>,
173 paint_api: CrossProcessPaintApi,
174 resource_threads: ResourceThreads,
175 ) -> Self {
176 Self {
177 system_font_service_proxy,
178 resource_threads: Mutex::new(resource_threads.core_thread),
179 paint_api: Mutex::new(paint_api),
180 fonts: Default::default(),
181 resolved_font_groups: Default::default(),
182 web_fonts: Default::default(),
183 webrender_font_keys: RwLock::default(),
184 webrender_font_instance_keys: RwLock::default(),
185 have_removed_web_fonts: AtomicBool::new(false),
186 font_data: RwLock::default(),
187 currently_downloading_fonts: Default::default(),
188 known_font_face_rules: Default::default(),
189 font_feature_value_map: Default::default(),
190 number_of_loading_web_fonts: Default::default(),
191 }
192 }
193
194 pub fn web_fonts_still_loading(&self) -> usize {
195 self.number_of_loading_web_fonts.load(Ordering::SeqCst)
196 }
197
198 fn get_font_data(&self, identifier: &FontIdentifier) -> Option<FontData> {
199 match identifier {
200 FontIdentifier::Web(_) | FontIdentifier::ArrayBuffer(_) => {
201 self.font_data.read().get(identifier).cloned()
202 },
203 FontIdentifier::Local(_) => None,
204 }
205 }
206
207 pub fn font_group(&self, style: ServoArc<FontStyleStruct>) -> FontGroupRef {
211 let font_size = style.font_size.computed_size().into();
212 self.font_group_with_size(style, font_size)
213 }
214
215 pub fn font_group_with_size(
218 &self,
219 style: ServoArc<FontStyleStruct>,
220 size: Au,
221 ) -> Arc<FontGroup> {
222 let cache_key = FontGroupCacheKey { size, style };
223 if let Some(font_group) = self.resolved_font_groups.read().get(&cache_key) {
224 return font_group.clone();
225 }
226
227 let mut descriptor = FontDescriptor::from(&*cache_key.style);
228 descriptor.pt_size = size;
229
230 let font_group = Arc::new(FontGroup::new(&cache_key.style, descriptor));
231 self.resolved_font_groups
232 .write()
233 .insert(cache_key, font_group.clone());
234 font_group
235 }
236
237 pub fn font(
240 &self,
241 font_template: FontTemplateRef,
242 font_descriptor: &FontDescriptor,
243 ) -> Option<FontRef> {
244 self.get_font_maybe_synthesizing_small_caps(
245 font_template,
246 font_descriptor,
247 true, )
249 }
250
251 fn get_font_maybe_synthesizing_small_caps(
252 &self,
253 font_template: FontTemplateRef,
254 font_descriptor: &FontDescriptor,
255 synthesize_small_caps: bool,
256 ) -> Option<FontRef> {
257 let synthesized_small_caps_font =
261 if font_descriptor.variant == FontVariantCaps::SmallCaps && synthesize_small_caps {
262 let mut small_caps_descriptor = font_descriptor.clone();
263 small_caps_descriptor.pt_size =
264 font_descriptor.pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR);
265 self.get_font_maybe_synthesizing_small_caps(
266 font_template.clone(),
267 &small_caps_descriptor,
268 false, )
270 } else {
271 None
272 };
273
274 let cache_key = FontCacheKey {
275 font_identifier: font_template.identifier().to_owned(),
276 font_descriptor: font_descriptor.clone(),
277 };
278
279 if let Some(font) = self.fonts.read().get(&cache_key).cloned() {
280 return font;
281 }
282
283 debug!(
284 "FontContext::font cache miss for font_template={:?} font_descriptor={:?}",
285 font_template, font_descriptor
286 );
287
288 let mut fonts = self.fonts.write();
293 if let Some(font) = fonts.get(&cache_key).cloned() {
294 return font;
295 }
296
297 let font = self
300 .create_font(
301 font_template,
302 font_descriptor.to_owned(),
303 synthesized_small_caps_font,
304 )
305 .ok();
306 fonts.insert(cache_key, font.clone());
307 font
308 }
309
310 fn matching_web_font_templates(
311 &self,
312 descriptor_to_match: &FontDescriptor,
313 family_descriptor: &FontFamilyDescriptor,
314 ) -> Option<Vec<FontTemplateRef>> {
315 if family_descriptor.scope != FontSearchScope::Any {
316 return None;
317 }
318
319 let SingleFontFamily::FamilyName(ref family_name) = family_descriptor.family else {
321 return None;
322 };
323
324 self.web_fonts
325 .read()
326 .families
327 .get(&family_name.name.clone().into())
328 .map(|templates| {
329 let mut matching_templates =
330 templates.find_for_descriptor(Some(descriptor_to_match));
331 matching_templates.sort_unstable_by_key(|template| {
332 template
333 .font_face_rule()
334 .map(|rule| rule.cascade_index.load(Ordering::SeqCst))
335 .unwrap_or(usize::MAX)
336 });
337 matching_templates
338 })
339 }
340
341 pub fn matching_templates(
344 &self,
345 descriptor_to_match: &FontDescriptor,
346 family_descriptor: &FontFamilyDescriptor,
347 ) -> Vec<FontTemplateRef> {
348 self.matching_web_font_templates(descriptor_to_match, family_descriptor)
349 .unwrap_or_else(|| {
350 self.system_font_service_proxy.find_matching_font_templates(
351 Some(descriptor_to_match),
352 &family_descriptor.family,
353 )
354 })
355 }
356
357 #[servo_tracing::instrument(skip_all)]
360 fn create_font(
361 &self,
362 font_template: FontTemplateRef,
363 font_descriptor: FontDescriptor,
364 synthesized_small_caps: Option<FontRef>,
365 ) -> Result<FontRef, &'static str> {
366 Ok(FontRef(Arc::new(Font::new(
367 font_template.clone(),
368 font_descriptor,
369 self.get_font_data(&font_template.identifier()),
370 synthesized_small_caps,
371 )?)))
372 }
373
374 pub(crate) fn create_font_instance_key(
375 &self,
376 font: &Font,
377 painter_id: PainterId,
378 ) -> FontInstanceKey {
379 let font_template_identifier = font.template.identifier();
380 match &*font_template_identifier {
381 FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance(
382 font.template.identifier().to_owned(),
383 font.descriptor.pt_size,
384 font.webrender_font_instance_flags(),
385 font.variations().to_owned(),
386 painter_id,
387 ),
388 FontIdentifier::Web(_) | FontIdentifier::ArrayBuffer(_) => self
389 .create_web_font_instance(
390 font.template.clone(),
391 font.descriptor.pt_size,
392 font.webrender_font_instance_flags(),
393 font.variations().to_owned(),
394 painter_id,
395 ),
396 }
397 }
398
399 fn create_web_font_instance(
400 &self,
401 font_template: FontTemplateRef,
402 pt_size: Au,
403 flags: FontInstanceFlags,
404 variations: Vec<FontVariation>,
405 painter_id: PainterId,
406 ) -> FontInstanceKey {
407 let identifier = font_template.identifier();
408 let font_data = self
409 .get_font_data(&identifier)
410 .expect("Web font should have associated font data");
411 let font_key = *self
412 .webrender_font_keys
413 .write()
414 .entry(identifier.clone())
415 .or_insert_with(|| {
416 let font_key = self.system_font_service_proxy.generate_font_key(painter_id);
417 self.paint_api.lock().add_font(
418 font_key,
419 font_data.as_ipc_shared_memory(),
420 identifier.index(),
421 );
422 font_key
423 });
424
425 let entry_key = FontParameters {
426 font_key,
427 pt_size,
428 variations: variations.clone(),
429 flags,
430 };
431 *self
432 .webrender_font_instance_keys
433 .write()
434 .entry(entry_key)
435 .or_insert_with(|| {
436 let font_instance_key = self
437 .system_font_service_proxy
438 .generate_font_instance_key(painter_id);
439 self.paint_api.lock().add_font_instance(
440 font_instance_key,
441 font_key,
442 pt_size.to_f32_px(),
443 flags,
444 variations,
445 );
446 font_instance_key
447 })
448 }
449
450 fn invalidate_font_groups_after_web_font_load(&self) {
451 self.resolved_font_groups.write().clear();
452 }
453
454 pub fn is_supported_web_font_source(source: &&Source) -> bool {
455 let url_source = match &source {
456 Source::Url(url_source) => url_source,
457 Source::Local(_) => return true,
458 };
459 let format_hint = match url_source.format_hint {
460 Some(ref format_hint) => format_hint,
461 None => return true,
462 };
463
464 if matches!(
465 format_hint,
466 FontFaceSourceFormat::Keyword(
467 FontFaceSourceFormatKeyword::Truetype |
468 FontFaceSourceFormatKeyword::Opentype |
469 FontFaceSourceFormatKeyword::Woff |
470 FontFaceSourceFormatKeyword::Woff2
471 )
472 ) {
473 return true;
474 }
475
476 if let FontFaceSourceFormat::String(string) = format_hint {
477 if string == "truetype" || string == "opentype" || string == "woff" || string == "woff2"
478 {
479 return true;
480 }
481
482 return pref!(layout_variable_fonts_enabled) &&
483 (string == "truetype-variations" ||
484 string == "opentype-variations" ||
485 string == "woff-variations" ||
486 string == "woff2-variations");
487 }
488
489 false
490 }
491
492 fn is_local_or_unknown_url_font(
493 &self,
494 family_name: &LowercaseFontFamilyName,
495 source: &Source,
496 ) -> bool {
497 match source {
498 Source::Url(url) => !url
499 .url
500 .url()
501 .cloned()
502 .map(ServoUrl::from)
503 .map(FontIdentifier::Web)
504 .filter(|font_identifier| self.font_data.read().contains_key(font_identifier))
505 .is_some_and(|font_identifier| {
506 self.web_fonts
507 .read()
508 .families
509 .get(family_name)
510 .is_some_and(|templates| {
511 templates
512 .templates
513 .iter()
514 .any(|template| template.borrow().identifier == font_identifier)
515 })
516 }),
517 Source::Local(_) => true,
518 }
519 }
520
521 pub(crate) fn handle_web_font_request_started(
526 &self,
527 url: ServoUrl,
528 state: WebFontDownloadState,
529 ) -> bool {
530 let mut downloading_fonts = self.currently_downloading_fonts.lock();
531 let entry = downloading_fonts.entry(url);
532
533 let needs_new_fetch_request = matches!(entry, Entry::Vacant(_));
535
536 entry.or_default().push(state);
537
538 needs_new_fetch_request
539 }
540
541 pub(crate) fn handle_web_font_request_succeeded(
547 &self,
548 font_data: FontData,
549 url: ServoUrl,
550 ) -> bool {
551 let Some(download_states) = self.currently_downloading_fonts.lock().remove(&url) else {
552 return false;
554 };
555 debug_assert!(
556 !download_states.is_empty(),
557 "Should have removed this entry"
558 );
559
560 let identifier = FontIdentifier::Web(url);
561 let Ok(handle) = PlatformFont::new_from_data(identifier.clone(), &font_data, None, false)
562 else {
563 return false;
564 };
565
566 self.font_data.write().insert(identifier.clone(), font_data);
567 let descriptor = handle.descriptor();
568 for download_state in download_states {
569 let mut descriptor = descriptor.clone();
570 descriptor.override_values_with_css_font_template_descriptors(
571 &download_state.css_font_face_descriptors,
572 );
573
574 let new_template = FontTemplate::new(
575 identifier.clone(),
576 descriptor,
577 download_state.initiator.font_face_rule().cloned(),
578 );
579
580 download_state.handle_web_font_load_success(new_template);
581 }
582
583 true
584 }
585
586 pub fn decrement_count_of_loading_fonts_by_one(&self) {
588 self.number_of_loading_web_fonts
589 .fetch_sub(1, Ordering::SeqCst);
590 }
591
592 pub(crate) fn is_font_active(&self, web_font: &ServoArc<FontFaceRuleInfo>) -> bool {
596 self.known_font_face_rules
597 .lock()
598 .contents
599 .values()
600 .flat_map(|bucket| bucket.iter())
601 .any(|known_web_font| ServoArc::ptr_eq(&known_web_font.font_face_rule_entry, web_font))
602 }
603}
604
605#[derive(MallocSizeOf)]
608pub(crate) struct WebFontDownloadState {
609 webview_id: Option<WebViewId>,
610 css_font_face_descriptors: CSSFontFaceDescriptors,
611 remaining_sources: Vec<Source>,
612 local_fonts: FxHashMap<Atom, Option<FontTemplateRef>>,
613 #[conditional_malloc_size_of]
614 pub(crate) font_context: Arc<FontContext>,
615 initiator: WebFontLoadInitiator,
616 document_context: WebFontDocumentContext,
617}
618
619impl WebFontDownloadState {
620 fn new(
621 webview_id: Option<WebViewId>,
622 font_context: Arc<FontContext>,
623 css_font_face_descriptors: CSSFontFaceDescriptors,
624 initiator: WebFontLoadInitiator,
625 sources: Vec<Source>,
626 local_fonts: FxHashMap<Atom, Option<FontTemplateRef>>,
627 document_context: WebFontDocumentContext,
628 ) -> WebFontDownloadState {
629 WebFontDownloadState {
630 webview_id,
631 css_font_face_descriptors,
632 remaining_sources: sources,
633 local_fonts,
634 font_context,
635 initiator,
636 document_context,
637 }
638 }
639
640 pub(crate) fn handle_web_font_load_success(self, new_template: FontTemplate) {
641 let family_name = self.css_font_face_descriptors.family_name.clone();
642 match self.initiator {
643 WebFontLoadInitiator::Stylesheet(initiator) => {
644 if !self.font_context.is_font_active(&initiator.font_face_rule) {
645 if self
647 .font_context
648 .number_of_loading_web_fonts
649 .fetch_sub(1, Ordering::SeqCst) ==
650 1
651 {
652 (initiator.callback)(WebFontLoadEvent::UnblockedFontReadyPromise);
655 }
656 return;
657 }
658
659 self.font_context
660 .web_fonts
661 .write()
662 .add_new_template(family_name, new_template);
663 self.font_context
664 .invalidate_font_groups_after_web_font_load();
665
666 (initiator.callback)(WebFontLoadEvent::LoadedSuccessfully);
670 },
671 WebFontLoadInitiator::Script(callback) => {
672 self.font_context.decrement_count_of_loading_fonts_by_one();
673 callback(family_name, Some(new_template));
674 },
675 }
676 }
677
678 pub(crate) fn handle_web_font_load_failure(self) {
680 let family_name = self.css_font_face_descriptors.family_name.clone();
681 match self.initiator {
682 WebFontLoadInitiator::Stylesheet(initiator) => {
683 if self
684 .font_context
685 .number_of_loading_web_fonts
686 .fetch_sub(1, Ordering::SeqCst) ==
687 1
688 {
689 (initiator.callback)(WebFontLoadEvent::UnblockedFontReadyPromise);
692 }
693 },
694 WebFontLoadInitiator::Script(callback) => {
695 self.font_context.decrement_count_of_loading_fonts_by_one();
696 callback(family_name, None);
697 },
698 }
699 }
700}
701
702pub trait FontContextWebFontMethods {
703 fn rebuild_font_face_set(
704 &self,
705 webview_id: WebViewId,
706 stylist: &Stylist,
707 guards: &StylesheetGuards<'_>,
708 callback: StylesheetWebFontLoadFinishedCallback,
709 document_context: &WebFontDocumentContext,
710 ) -> WebFontSetDifference;
711 fn load_single_font_face_rule(
712 &self,
713 webview_id: WebViewId,
714 font_face_rule: ServoArc<FontFaceRuleInfo>,
715 callback: StylesheetWebFontLoadFinishedCallback,
716 document_context: &WebFontDocumentContext,
717 );
718 fn load_web_font_for_script(
719 &self,
720 webview_id: Option<WebViewId>,
721 sources: SourceList,
722 descriptors: CSSFontFaceDescriptors,
723 finished_callback: ScriptWebFontLoadFinishedCallback,
724 document_context: &WebFontDocumentContext,
725 );
726 fn handle_web_font_request_failed(&self, url: ServoUrl);
727}
728
729impl FontContextWebFontMethods for Arc<FontContext> {
730 fn load_single_font_face_rule(
731 &self,
732 webview_id: WebViewId,
733 font_face_rule: ServoArc<FontFaceRuleInfo>,
734 callback: StylesheetWebFontLoadFinishedCallback,
735 document_context: &WebFontDocumentContext,
736 ) {
737 let Some(sources) = font_face_rule.descriptors.src.as_ref() else {
738 return;
739 };
740
741 let css_font_face_descriptors = CSSFontFaceDescriptors::from(&font_face_rule.descriptors);
742
743 let initiator = FontFaceRuleInitiator {
744 font_face_rule: font_face_rule.clone(),
745 callback: callback.clone(),
746 };
747
748 self.start_loading_one_web_font(
749 Some(webview_id),
750 sources,
751 css_font_face_descriptors,
752 WebFontLoadInitiator::Stylesheet(Box::new(initiator)),
753 document_context,
754 );
755 }
756 fn rebuild_font_face_set(
757 &self,
758 webview_id: WebViewId,
759 stylist: &Stylist,
760 guards: &StylesheetGuards<'_>,
761 callback: StylesheetWebFontLoadFinishedCallback,
762 document_context: &WebFontDocumentContext,
763 ) -> WebFontSetDifference {
764 let difference = self
765 .known_font_face_rules
766 .lock()
767 .diff_old_and_new_font_face_rules(stylist, guards);
768
769 for added_rule in &difference.added_font_faces {
770 self.load_single_font_face_rule(
771 webview_id,
772 added_rule.clone(),
773 callback.clone(),
774 document_context,
775 );
776 }
777 for removed_rule in &difference.removed_font_faces {
778 self.remove_single_font_face_rule(removed_rule, &mut self.web_fonts.write());
779 }
780
781 if !difference.removed_font_faces.is_empty() || difference.cascade_index_of_any_rule_changed
782 {
783 self.resolved_font_groups.write().clear();
785 }
786
787 if !difference.removed_font_faces.is_empty() {
788 self.have_removed_web_fonts.store(true, Ordering::Relaxed);
790 }
791
792 difference
793 }
794
795 fn load_web_font_for_script(
796 &self,
797 webview_id: Option<WebViewId>,
798 sources: SourceList,
799 descriptors: CSSFontFaceDescriptors,
800 finished_callback: ScriptWebFontLoadFinishedCallback,
801 document_context: &WebFontDocumentContext,
802 ) {
803 let completion_handler = WebFontLoadInitiator::Script(finished_callback);
804 self.start_loading_one_web_font(
805 webview_id,
806 &sources,
807 descriptors,
808 completion_handler,
809 document_context,
810 );
811 }
812
813 fn handle_web_font_request_failed(&self, url: ServoUrl) {
815 let Some(subscribers) = self.currently_downloading_fonts.lock().remove(&url) else {
816 return;
817 };
818
819 for subscriber in subscribers {
820 if let WebFontLoadInitiator::Stylesheet(stylesheet_initiator) = &subscriber.initiator &&
822 !self.is_font_active(&stylesheet_initiator.font_face_rule)
823 {
824 if self
826 .number_of_loading_web_fonts
827 .fetch_sub(1, Ordering::SeqCst) ==
828 1
829 {
830 (stylesheet_initiator.callback)(WebFontLoadEvent::UnblockedFontReadyPromise);
833 }
834 continue;
835 }
836
837 self.process_next_web_font_source(subscriber);
838 }
839 }
840}
841
842impl FontContext {
843 pub fn collect_unused_webrender_resources(
844 &self,
845 all: bool,
846 ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
847 if all {
848 let mut webrender_font_keys = self.webrender_font_keys.write();
849 let mut webrender_font_instance_keys = self.webrender_font_instance_keys.write();
850 self.have_removed_web_fonts.store(false, Ordering::Relaxed);
851 return (
852 webrender_font_keys.drain().map(|(_, key)| key).collect(),
853 webrender_font_instance_keys
854 .drain()
855 .map(|(_, key)| key)
856 .collect(),
857 );
858 }
859
860 if !self.have_removed_web_fonts.load(Ordering::Relaxed) {
861 return (Vec::new(), Vec::new());
862 }
863
864 let web_fonts = self.web_fonts.write();
866 let mut font_data = self.font_data.write();
867 let _fonts = self.fonts.write();
868 let _font_groups = self.resolved_font_groups.write();
869 let mut webrender_font_keys = self.webrender_font_keys.write();
870 let mut webrender_font_instance_keys = self.webrender_font_instance_keys.write();
871
872 let mut unused_identifiers: HashSet<FontIdentifier> =
873 webrender_font_keys.keys().cloned().collect();
874 for templates in web_fonts.families.values() {
875 templates.for_all_identifiers(|identifier| {
876 unused_identifiers.remove(identifier);
877 });
878 }
879
880 font_data.retain(|font_identifier, _| !unused_identifiers.contains(font_identifier));
881
882 self.have_removed_web_fonts.store(false, Ordering::Relaxed);
883
884 let mut removed_keys: FxHashSet<FontKey> = FxHashSet::default();
885 webrender_font_keys.retain(|identifier, font_key| {
886 if unused_identifiers.contains(identifier) {
887 removed_keys.insert(*font_key);
888 false
889 } else {
890 true
891 }
892 });
893
894 let mut removed_instance_keys: HashSet<FontInstanceKey> = HashSet::new();
895 webrender_font_instance_keys.retain(|font_param, instance_key| {
896 if removed_keys.contains(&font_param.font_key) {
897 removed_instance_keys.insert(*instance_key);
898 false
899 } else {
900 true
901 }
902 });
903
904 (
905 removed_keys.into_iter().collect(),
906 removed_instance_keys.into_iter().collect(),
907 )
908 }
909
910 fn remove_single_font_face_rule(
912 &self,
913 font_face_rule: &ServoArc<FontFaceRuleInfo>,
914 font_store: &mut FontStore,
915 ) -> bool {
916 let Some(family) = font_face_rule.descriptors.font_family.as_ref() else {
917 return false;
918 };
919
920 let lowercase_family_name: LowercaseFontFamilyName = family.name.clone().into();
921 let Some(known_family) = font_store.families.get_mut(&lowercase_family_name) else {
922 return false;
923 };
924 if !known_family.remove_template_for_font_face_rule(font_face_rule) {
925 return false;
926 }
927 self.fonts.write().retain(|_, font| match font {
928 Some(font) => !font
929 .template
930 .borrow()
931 .is_defined_by_font_face_rule(font_face_rule),
932 _ => true,
933 });
934
935 true
936 }
937
938 pub fn add_template_to_font_context(
939 &self,
940 family_name: LowercaseFontFamilyName,
941 new_template: FontTemplate,
942 ) {
943 self.web_fonts
944 .write()
945 .add_new_template(family_name, new_template);
946 self.invalidate_font_groups_after_web_font_load();
947 }
948
949 pub fn construct_web_font_from_data(
950 &self,
951 data: &[u8],
952 descriptors: CSSFontFaceDescriptors,
953 ) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
954 let bytes = fontsan::process(data)
955 .inspect_err(|error| {
956 debug!(
957 "Sanitiser rejected FontFace font: family={} with {error:?}",
958 descriptors.family_name,
959 );
960 })
961 .ok()?;
962 let font_data = FontData::from_bytes(&bytes);
963
964 let identifier = FontIdentifier::ArrayBuffer(Uuid::new_v4());
965 let handle =
966 PlatformFont::new_from_data(identifier.clone(), &font_data, None, false).ok()?;
967
968 let new_template = FontTemplate::new(identifier.clone(), handle.descriptor(), None);
969
970 self.font_data.write().insert(identifier, font_data);
971
972 Some((descriptors.family_name, new_template))
973 }
974
975 fn start_loading_one_web_font(
976 self: &Arc<FontContext>,
977 webview_id: Option<WebViewId>,
978 source_list: &SourceList,
979 css_font_face_descriptors: CSSFontFaceDescriptors,
980 completion_handler: WebFontLoadInitiator,
981 document_context: &WebFontDocumentContext,
982 ) {
983 self.number_of_loading_web_fonts
984 .fetch_add(1, Ordering::SeqCst);
985
986 let sources: Vec<Source> = source_list
987 .0
988 .iter()
989 .rev()
990 .filter(Self::is_supported_web_font_source)
991 .filter(|source| {
992 self.is_local_or_unknown_url_font(&css_font_face_descriptors.family_name, source)
993 })
994 .cloned()
995 .collect();
996
997 let sources_transformed = sources
1005 .iter()
1006 .filter_map(|source| {
1007 if let Source::Local(family_name) = source {
1008 Some(family_name)
1009 } else {
1010 None
1011 }
1012 })
1013 .map(|family_name| {
1014 let family = SingleFontFamily::FamilyName(FamilyName {
1015 name: family_name.name.clone(),
1016 syntax: FontFamilyNameSyntax::Quoted,
1017 });
1018 let matching_font_templates = self
1019 .system_font_service_proxy
1020 .find_matching_font_templates(None, &family);
1021 let value = matching_font_templates.first();
1022 (family_name.name.clone(), value.cloned())
1023 });
1024
1025 let local_fonts = FxHashMap::from_iter(sources_transformed);
1026
1027 self.process_next_web_font_source(WebFontDownloadState::new(
1028 webview_id,
1029 self.clone(),
1030 css_font_face_descriptors,
1031 completion_handler,
1032 sources,
1033 local_fonts,
1034 document_context.clone(),
1035 ));
1036 }
1037
1038 pub(crate) fn process_next_web_font_source(
1039 self: &Arc<FontContext>,
1040 mut state: WebFontDownloadState,
1041 ) {
1042 let Some(source) = state.remaining_sources.pop() else {
1043 state.handle_web_font_load_failure();
1044 return;
1045 };
1046
1047 let this = self.clone();
1048 let web_font_family_name = state.css_font_face_descriptors.family_name.clone();
1049 match source {
1050 Source::Url(url_source) => {
1051 RemoteWebFontDownloader::download(url_source, this, web_font_family_name, state)
1052 },
1053 Source::Local(ref local_family_name) => {
1054 if let Some(new_template) = state
1055 .local_fonts
1056 .get(&local_family_name.name)
1057 .cloned()
1058 .flatten()
1059 .and_then(|local_template| {
1060 let template = FontTemplate::new_for_local_web_font(
1061 local_template,
1062 &state.css_font_face_descriptors,
1063 state.initiator.font_face_rule().cloned(),
1064 )
1065 .ok()?;
1066 Some(template)
1067 })
1068 {
1069 state.handle_web_font_load_success(new_template);
1070 } else {
1071 this.process_next_web_font_source(state);
1072 }
1073 },
1074 }
1075 }
1076
1077 pub fn resolve_font_variant_alternate_identifiers_for(
1079 &self,
1080 font: &FontRef,
1081 alternates: &FontVariantAlternates,
1082 stylist: &Stylist,
1083 ) -> ResolvedFontVariantAlternates {
1084 let mut resolved_alternates = ResolvedFontVariantAlternates::default();
1085 if alternates.is_empty() {
1086 return resolved_alternates;
1087 }
1088 let Some(family_name) = font.family_name() else {
1089 return resolved_alternates;
1090 };
1091
1092 for alternate in alternates.iter() {
1093 match alternate {
1094 VariantAlternates::Stylistic(stylistic) => {
1095 let Some(FontFeatureValue::Single(value)) = self
1096 .look_up_font_feature_alternate_name(
1097 family_name.clone(),
1098 AlternateKindRequiringResolution::Stylistic,
1099 stylistic.0.clone(),
1100 stylist,
1101 )
1102 else {
1103 continue;
1104 };
1105
1106 resolved_alternates.stylistic = Some(value);
1107 },
1108 VariantAlternates::Styleset(styleset_list) => {
1109 for styleset in styleset_list.iter() {
1110 let Some(FontFeatureValue::Vector(value)) = self
1111 .look_up_font_feature_alternate_name(
1112 family_name.clone(),
1113 AlternateKindRequiringResolution::Styleset,
1114 styleset.0.clone(),
1115 stylist,
1116 )
1117 else {
1118 continue;
1119 };
1120
1121 resolved_alternates.styleset.extend(value.0.iter());
1122 }
1123 },
1124 VariantAlternates::CharacterVariant(character_variant_list) => {
1125 for character_variant in character_variant_list.iter() {
1126 let Some(FontFeatureValue::Pair(value)) = self
1127 .look_up_font_feature_alternate_name(
1128 family_name.clone(),
1129 AlternateKindRequiringResolution::CharacterVariant,
1130 character_variant.0.clone(),
1131 stylist,
1132 )
1133 else {
1134 continue;
1135 };
1136
1137 resolved_alternates.character_variant.push(value);
1138 }
1139 },
1140 VariantAlternates::Swash(swash) => {
1141 let Some(FontFeatureValue::Single(value)) = self
1142 .look_up_font_feature_alternate_name(
1143 family_name.clone(),
1144 AlternateKindRequiringResolution::Swash,
1145 swash.0.clone(),
1146 stylist,
1147 )
1148 else {
1149 continue;
1150 };
1151
1152 resolved_alternates.swash = Some(value);
1153 },
1154 VariantAlternates::Ornaments(ornaments) => {
1155 let Some(FontFeatureValue::Single(value)) = self
1156 .look_up_font_feature_alternate_name(
1157 family_name.clone(),
1158 AlternateKindRequiringResolution::Ornaments,
1159 ornaments.0.clone(),
1160 stylist,
1161 )
1162 else {
1163 continue;
1164 };
1165
1166 resolved_alternates.ornaments = Some(value);
1167 },
1168 VariantAlternates::Annotation(annotation) => {
1169 let Some(FontFeatureValue::Single(value)) = self
1170 .look_up_font_feature_alternate_name(
1171 family_name.clone(),
1172 AlternateKindRequiringResolution::Annotation,
1173 annotation.0.clone(),
1174 stylist,
1175 )
1176 else {
1177 continue;
1178 };
1179
1180 resolved_alternates.annotation = Some(value);
1181 },
1182 VariantAlternates::HistoricalForms => {
1183 resolved_alternates.historical_forms = true;
1184 },
1185 }
1186 }
1187
1188 resolved_alternates
1189 }
1190
1191 fn look_up_font_feature_alternate_name(
1197 &self,
1198 family_name: Atom,
1199 kind: AlternateKindRequiringResolution,
1200 name: Atom,
1201 stylist: &Stylist,
1202 ) -> Option<FontFeatureValue> {
1203 let read_guard = self.font_feature_value_map.read();
1205 if let Some(map) = &*read_guard {
1206 map.lookup(family_name, kind, name)
1208 } else {
1209 drop(read_guard);
1211 let mut write_guard = self.font_feature_value_map.write();
1212 if let Some(map) = &*write_guard {
1213 return map.lookup(family_name, kind, name);
1216 }
1217
1218 log::debug!("Initializing @font-feature-values map");
1219 let mut map = FontFeatureValueMap::default();
1220 stylist
1221 .iter_extra_data_origins_rev()
1222 .flat_map(|(extra_data, _)| extra_data.font_feature_values.iter())
1223 .for_each(|(rule, _)| map.add_rule(rule));
1224 let map = &*write_guard.insert(map);
1225 map.lookup(family_name, kind, name)
1227 }
1228 }
1229
1230 pub fn invalidate_font_feature_values_map(&self) {
1231 self.font_feature_value_map.write().take();
1232 }
1233}
1234
1235pub(crate) type ScriptWebFontLoadFinishedCallback =
1236 Box<dyn FnOnce(LowercaseFontFamilyName, Option<FontTemplate>) + Send>;
1237
1238#[derive(MallocSizeOf)]
1239pub(crate) struct FontFaceRuleInitiator {
1240 #[conditional_malloc_size_of]
1241 font_face_rule: ServoArc<FontFaceRuleInfo>,
1242 #[ignore_malloc_size_of = "dyn Fn"]
1243 callback: StylesheetWebFontLoadFinishedCallback,
1244}
1245
1246#[derive(MallocSizeOf)]
1247pub(crate) enum WebFontLoadInitiator {
1248 Stylesheet(Box<FontFaceRuleInitiator>),
1249 Script(#[ignore_malloc_size_of = "dyn Fn"] ScriptWebFontLoadFinishedCallback),
1250}
1251
1252impl WebFontLoadInitiator {
1253 pub(crate) fn font_face_rule(&self) -> Option<&ServoArc<FontFaceRuleInfo>> {
1254 match self {
1255 Self::Stylesheet(initiator) => Some(&initiator.font_face_rule),
1256 Self::Script(_) => None,
1257 }
1258 }
1259}
1260
1261struct RemoteWebFontDownloader {
1262 url: ServoArc<Url>,
1264 web_font_family_name: LowercaseFontFamilyName,
1265 response_valid: bool,
1266 response_data: Vec<u8>,
1268 document_context: WebFontDocumentContext,
1269 font_context: Arc<FontContext>,
1270}
1271
1272enum DownloaderResponseResult {
1273 InProcess,
1274 Finished,
1275 Failure,
1276}
1277
1278impl RemoteWebFontDownloader {
1279 fn download(
1280 url_source: UrlSource,
1281 font_context: Arc<FontContext>,
1282 web_font_family_name: LowercaseFontFamilyName,
1283 state: WebFontDownloadState,
1284 ) {
1285 let url = match url_source.url.url() {
1287 Some(url) => url.clone(),
1288 None => return,
1289 };
1290
1291 let webview_id = state.webview_id;
1292 let document_context = state.document_context.clone();
1293 if !font_context.handle_web_font_request_started(url.clone().into(), state) {
1294 return;
1297 }
1298
1299 let request = RequestBuilder::new(
1300 webview_id,
1301 UrlWithBlobClaim::from_url_without_having_claimed_blob(url.clone().into()),
1302 Referrer::ReferrerUrl(document_context.document_url.clone()),
1303 )
1304 .destination(Destination::Font)
1305 .mode(RequestMode::CorsMode)
1306 .credentials_mode(CredentialsMode::CredentialsSameOrigin)
1307 .service_workers_mode(ServiceWorkersMode::All)
1308 .policy_container(document_context.policy_container.clone())
1309 .client(document_context.request_client.clone());
1310
1311 let core_resource_thread_clone = font_context.resource_threads.lock().clone();
1312
1313 debug!("Loading @font-face {} from {}", web_font_family_name, url);
1314 let mut downloader = Self {
1315 url,
1316 web_font_family_name,
1317 response_valid: false,
1318 response_data: Vec::new(),
1319 document_context,
1320 font_context: font_context.clone(),
1321 };
1322
1323 fetch_async(
1324 &core_resource_thread_clone,
1325 request,
1326 None,
1327 Box::new(move |response_message| {
1328 match downloader.handle_web_font_fetch_message(response_message) {
1329 DownloaderResponseResult::InProcess => {},
1330 DownloaderResponseResult::Finished => {
1331 downloader.process_downloaded_font_and_signal_completion()
1332 },
1333 DownloaderResponseResult::Failure => {
1334 font_context.handle_web_font_request_failed(downloader.url.clone().into());
1335 },
1336 }
1337 }),
1338 )
1339 }
1340
1341 fn process_downloaded_font_and_signal_completion(&mut self) {
1344 let font_data = std::mem::take(&mut self.response_data);
1345 trace!(
1346 "Downloaded @font-face {} ({} bytes)",
1347 self.web_font_family_name,
1348 font_data.len()
1349 );
1350
1351 let font_data = match fontsan::process(&font_data) {
1352 Ok(bytes) => FontData::from_vec(bytes),
1353 Err(error) => {
1354 debug!(
1355 "Sanitiser rejected web font url={:?} with {error:?}",
1356 self.url.as_str(),
1357 );
1358 return self
1359 .font_context
1360 .handle_web_font_request_failed(self.url.clone().into());
1361 },
1362 };
1363
1364 let url: ServoUrl = self.url.clone().into();
1365 self.font_context
1366 .handle_web_font_request_succeeded(font_data, url);
1367 }
1368
1369 fn handle_web_font_fetch_message(
1370 &mut self,
1371 response_message: FetchResponseMsg,
1372 ) -> DownloaderResponseResult {
1373 match response_message {
1374 FetchResponseMsg::ProcessRequestBody(..) => DownloaderResponseResult::InProcess,
1375 FetchResponseMsg::ProcessCspViolations(_request_id, violations) => {
1376 self.document_context
1377 .csp_handler
1378 .process_violations(violations);
1379 DownloaderResponseResult::InProcess
1380 },
1381 FetchResponseMsg::ProcessResponse(_, meta_result) => {
1382 trace!(
1383 "@font-face {} metadata ok={:?}",
1384 self.web_font_family_name,
1385 meta_result.is_ok()
1386 );
1387 self.response_valid = meta_result.is_ok();
1388 DownloaderResponseResult::InProcess
1389 },
1390 FetchResponseMsg::ProcessResponseChunk(_, new_bytes) => {
1391 trace!(
1392 "@font-face {} chunk={:?}",
1393 self.web_font_family_name, new_bytes
1394 );
1395 if self.response_valid {
1396 self.response_data.extend(new_bytes)
1397 }
1398 DownloaderResponseResult::InProcess
1399 },
1400 FetchResponseMsg::ProcessResponseEOF(_, response, timing) => {
1401 trace!(
1402 "@font-face {} EOF={:?}",
1403 self.web_font_family_name, response
1404 );
1405 if response.is_err() || !self.response_valid {
1406 return DownloaderResponseResult::Failure;
1407 }
1408 self.document_context
1409 .network_timing_handler
1410 .submit_timing(ServoUrl::from_url(self.url.as_ref().clone()), timing);
1411 DownloaderResponseResult::Finished
1412 },
1413 FetchResponseMsg::ProcessContentLength(_request_id, size) => {
1414 self.response_data
1415 .reserve(size.saturating_sub(self.response_data.len()));
1416 DownloaderResponseResult::InProcess
1417 },
1418 }
1419 }
1420}
1421
1422#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
1423struct FontCacheKey {
1424 font_identifier: FontIdentifier,
1425 font_descriptor: FontDescriptor,
1426}
1427
1428#[derive(Debug, MallocSizeOf)]
1429struct FontGroupCacheKey {
1430 #[ignore_malloc_size_of = "This is also stored as part of styling."]
1431 style: ServoArc<FontStyleStruct>,
1432 size: Au,
1433}
1434
1435impl PartialEq for FontGroupCacheKey {
1436 fn eq(&self, other: &FontGroupCacheKey) -> bool {
1437 self.style == other.style && self.size == other.size
1438 }
1439}
1440
1441impl Eq for FontGroupCacheKey {}
1442
1443impl Hash for FontGroupCacheKey {
1444 fn hash<H>(&self, hasher: &mut H)
1445 where
1446 H: Hasher,
1447 {
1448 self.style.hash.hash(hasher)
1449 }
1450}
1451
1452#[derive(Default, MallocSizeOf)]
1453struct KnownFontFaceRules {
1454 generation: bool,
1459 contents: HashMap<Atom, Vec<KnownFontFaceRule>>,
1462}
1463
1464#[derive(MallocSizeOf)]
1465struct KnownFontFaceRule {
1466 #[conditional_malloc_size_of]
1467 font_face_rule_entry: ServoArc<FontFaceRuleInfo>,
1468 generation: bool,
1469}
1470
1471#[derive(Clone, MallocSizeOf)]
1472struct FontFaceRuleWithOrigin {
1473 #[conditional_malloc_size_of]
1474 rule: ServoArc<LockedFontFaceRule>,
1475 origin: Origin,
1476}
1477
1478impl FontFaceRuleWithOrigin {
1479 fn new(rule: ServoArc<LockedFontFaceRule>, origin: Origin) -> Self {
1480 Self { rule, origin }
1481 }
1482
1483 fn read_with<'a>(&'a self, guards: &'a StylesheetGuards) -> &'a FontFaceRule {
1484 match self.origin {
1485 Origin::Author => self.rule.read_with(guards.author),
1486 Origin::UserAgent | Origin::User => self.rule.read_with(guards.ua_or_user),
1487 }
1488 }
1489}
1490
1491impl KnownFontFaceRules {
1492 fn diff_old_and_new_font_face_rules(
1496 &mut self,
1497 stylist: &Stylist,
1498 guards: &StylesheetGuards<'_>,
1499 ) -> WebFontSetDifference {
1500 let mut difference = WebFontSetDifference::default();
1501 self.generation = !self.generation;
1502
1503 let font_face_rules_in_cascade_order = stylist
1504 .iter_extra_data_origins()
1505 .flat_map(|(extra_data, origin)| {
1506 extra_data.font_faces.iter().rev().zip(iter::repeat(origin))
1507 })
1508 .map(|((rule, _layer), origin)| FontFaceRuleWithOrigin::new(rule.clone(), origin));
1509
1510 let mut number_of_unchanged_rules = 0;
1512 let number_of_previously_known_rules: usize = self
1513 .contents
1514 .values()
1515 .map(|fonts_from_family| fonts_from_family.len())
1516 .sum();
1517 for (cascade_index, rule_with_origin) in font_face_rules_in_cascade_order.enumerate() {
1518 let borrowed_rule = rule_with_origin.read_with(guards);
1519
1520 let Some(font_family) = borrowed_rule.descriptors.font_family.as_ref() else {
1521 continue;
1526 };
1527 if borrowed_rule.descriptors.src.is_none() {
1528 continue;
1530 }
1531
1532 let known_font_faces_for_family =
1533 self.contents.entry(font_family.name.clone()).or_default();
1534
1535 let mut conflicting_declaration_with_higher_priority_exists = false;
1536 let mut index_of_existing_entry_for_this_rule = None;
1537 for (index, known_font_face) in known_font_faces_for_family.iter().enumerate() {
1538 if ServoArc::ptr_eq(
1540 &known_font_face.font_face_rule_entry.rule,
1541 &rule_with_origin.rule,
1542 ) {
1543 index_of_existing_entry_for_this_rule = Some(index);
1544 }
1545
1546 if conflicting_declaration_with_higher_priority_exists {
1548 continue;
1550 }
1551 if known_font_face.generation != self.generation {
1552 continue;
1555 }
1556 if font_face_rules_conflict(
1557 &known_font_face.font_face_rule_entry.descriptors,
1558 &borrowed_rule.descriptors,
1559 ) {
1560 conflicting_declaration_with_higher_priority_exists = true;
1561 }
1562 }
1563
1564 if let Some(index_of_existing_entry_for_this_rule) =
1565 index_of_existing_entry_for_this_rule
1566 {
1567 if conflicting_declaration_with_higher_priority_exists {
1571 let stale_rule =
1572 known_font_faces_for_family.remove(index_of_existing_entry_for_this_rule);
1573 difference
1574 .removed_font_faces
1575 .push(stale_rule.font_face_rule_entry);
1576 } else {
1577 number_of_unchanged_rules += 1;
1578
1579 let previous_cascade_index_of_this_rule = known_font_faces_for_family
1580 [index_of_existing_entry_for_this_rule]
1581 .font_face_rule_entry
1582 .cascade_index
1583 .swap(cascade_index, Ordering::SeqCst);
1584 difference.cascade_index_of_any_rule_changed |=
1585 previous_cascade_index_of_this_rule != cascade_index;
1586 known_font_faces_for_family[index_of_existing_entry_for_this_rule].generation =
1587 self.generation;
1588 }
1589 } else if conflicting_declaration_with_higher_priority_exists {
1590 continue;
1593 } else {
1594 let font_face_rule_entry = ServoArc::new(FontFaceRuleInfo {
1596 cascade_index: AtomicUsize::new(cascade_index),
1597 descriptors: borrowed_rule.descriptors.clone(),
1598 rule: rule_with_origin.rule,
1599 });
1600 difference
1601 .added_font_faces
1602 .push(font_face_rule_entry.clone());
1603 known_font_faces_for_family.push(KnownFontFaceRule {
1604 font_face_rule_entry,
1605 generation: self.generation,
1606 });
1607 }
1608 }
1609
1610 if number_of_unchanged_rules == number_of_previously_known_rules {
1611 return difference;
1615 }
1616
1617 self.contents.retain(|_, known_font_faces_for_family| {
1619 known_font_faces_for_family
1620 .extract_if(.., |rule| rule.generation != self.generation)
1621 .for_each(|removed_rule| {
1622 difference
1623 .removed_font_faces
1624 .push(removed_rule.font_face_rule_entry);
1625 });
1626
1627 !known_font_faces_for_family.is_empty()
1628 });
1629
1630 difference
1631 }
1632}
1633
1634fn font_face_rules_conflict(
1641 first_rule: &FontFaceRuleDescriptors,
1642 second_rule: &FontFaceRuleDescriptors,
1643) -> bool {
1644 first_rule.font_stretch == second_rule.font_stretch &&
1645 first_rule.font_style == second_rule.font_style &&
1646 first_rule.font_weight == second_rule.font_weight &&
1647 first_rule.unicode_range == second_rule.unicode_range
1648}