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