1use std::cell::{Cell, Ref, RefCell};
6
7use cssparser::Parser;
8use dom_struct::dom_struct;
9use fonts::{
10 FontContext, FontContextWebFontMethods, FontFaceRuleInfo, FontTemplate, LowercaseFontFamilyName,
11};
12use js::context::JSContext;
13use js::rust::HandleObject;
14use script_bindings::cell::DomRefCell;
15use script_bindings::domstring::TracedDOMString;
16use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto};
17use servo_arc::Arc as ServoArc;
18use style::error_reporting::ParseErrorReporter;
19use style::font_face::SourceList;
20use style::properties::font_face::Descriptors;
21use style::stylesheets::{CssRuleType, FontFaceRule, UrlExtraData};
22use style_traits::{ParsingMode, ToCss};
23
24use crate::css::css::parser_context_for_document_with_reporter;
25use crate::dom::bindings::buffer_source::get_buffer_source_copy;
26use crate::dom::bindings::codegen::Bindings::FontFaceBinding::{
27 FontFaceDescriptors as FontFaceInputDescriptors, FontFaceLoadStatus, FontFaceMethods,
28};
29use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
30use crate::dom::bindings::codegen::UnionTypes;
31use crate::dom::bindings::codegen::UnionTypes::StringOrArrayBufferViewOrArrayBuffer;
32use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
33use crate::dom::bindings::refcounted::Trusted;
34use crate::dom::bindings::reflector::DomGlobal;
35use crate::dom::bindings::root::{DomRoot, MutNullableDom};
36use crate::dom::bindings::str::DOMString;
37use crate::dom::css::fontfaceset::FontFaceSet;
38use crate::dom::globalscope::GlobalScope;
39use crate::dom::node::NodeTraits;
40use crate::dom::promise::{Promise, RootedPromise, TracedPromise};
41use crate::dom::window::Window;
42
43#[dom_struct]
45pub struct FontFace {
46 reflector: Reflector,
47 status: Cell<FontFaceLoadStatus>,
48 family_name: DomRefCell<TracedDOMString>,
49
50 #[no_trace = "Does not contain managed objects"]
51 descriptors: DomRefCell<FontFaceDescriptors>,
52
53 font_face_set: MutNullableDom<FontFaceSet>,
58
59 #[no_trace = "Does not contain managed objects"]
65 template: RefCell<Option<(LowercaseFontFamilyName, FontTemplate)>>,
66
67 #[no_trace = "Does not contain managed objects"]
68 urls: DomRefCell<Option<SourceList>>,
70
71 font_status_promise: TracedPromise,
73
74 #[no_trace]
78 #[conditional_malloc_size_of]
79 css_font_face_rule: DomRefCell<Option<ServoArc<FontFaceRuleInfo>>>,
80}
81
82fn parse_font_face_descriptors(
88 global: &GlobalScope,
89 family_name: &TracedDOMString,
90 sources: Option<&DOMString>,
91 input_descriptors: &FontFaceDescriptors,
92) -> Fallible<FontFaceRule> {
93 let window = global.as_window(); let document = window.Document();
95 let url_data = UrlExtraData(document.owner_global().api_base_url().get_arc());
96 let error_reporter = FontFaceErrorReporter {
97 not_encountered_error: Cell::new(true),
98 };
99 let parser_context = parser_context_for_document_with_reporter(
100 &document,
101 CssRuleType::FontFace,
102 ParsingMode::DEFAULT,
103 &url_data,
104 &error_reporter,
105 );
106
107 let FontFaceDescriptors {
108 ascent_override,
109 descent_override,
110 display,
111 feature_settings,
112 line_gap_override,
113 width,
114 style,
115 unicode_range,
116 variation_settings,
117 weight,
118 } = input_descriptors;
119
120 let maybe_sources = sources.map_or_else(String::new, |sources| format!("src: {sources};"));
121 let font_face_rule = format!(
122 r"
123 ascent-override: {ascent_override};
124 descent-override: {descent_override};
125 font-display: {display};
126 font-family: {family_name};
127 font-feature-settings: {feature_settings};
128 font-style: {style};
129 font-variation-settings: {variation_settings};
130 font-weight: {weight};
131 font-width: {width};
132 line-gap-override: {line_gap_override};
133 unicode-range: {unicode_range};
134 {maybe_sources}
135 "
136 );
137
138 let location = cssparser::SourceLocation { line: 0, column: 0 };
140 let mut parser = Parser::new(&font_face_rule);
141 let mut parsed_font_face_rule =
142 style::font_face::parse_font_face_block(&parser_context, &mut parser, location);
143
144 if let Some(ref mut sources) = parsed_font_face_rule.descriptors.src {
145 let supported_sources: Vec<_> = sources
146 .0
147 .iter()
148 .rev()
149 .filter(FontContext::is_supported_web_font_source)
150 .cloned()
151 .collect();
152 if supported_sources.is_empty() {
153 error_reporter.not_encountered_error.set(false);
154 } else {
155 sources.0 = supported_sources;
156 }
157 }
158
159 if error_reporter.not_encountered_error.get() {
160 Ok(parsed_font_face_rule)
161 } else {
162 Err(Error::Syntax(Some(
163 "Failed to parse `@font-face` descriptors".into(),
164 )))
165 }
166}
167
168#[derive(Clone, MallocSizeOf)]
169pub(crate) struct FontFaceDescriptors {
170 ascent_override: DOMString,
171 descent_override: DOMString,
172 display: DOMString,
173 feature_settings: DOMString,
174 line_gap_override: DOMString,
175 style: DOMString,
176 unicode_range: DOMString,
177 variation_settings: DOMString,
178 weight: DOMString,
179 width: DOMString,
180}
181
182impl From<&FontFaceInputDescriptors> for FontFaceDescriptors {
183 fn from(descriptors: &FontFaceInputDescriptors) -> Self {
184 Self {
185 ascent_override: descriptors.ascentOverride.clone(),
186 descent_override: descriptors.descentOverride.clone(),
187 display: descriptors.display.clone(),
188 feature_settings: descriptors.featureSettings.clone(),
189 line_gap_override: descriptors.lineGapOverride.clone(),
190 style: descriptors.style.clone(),
191 unicode_range: descriptors.unicodeRange.clone(),
192 variation_settings: descriptors.variationSettings.clone(),
193 weight: descriptors.weight.clone(),
194 width: descriptors
195 .width
196 .clone()
197 .unwrap_or(descriptors.stretch.clone()),
198 }
199 }
200}
201
202fn serialize_parsed_descriptors(descriptors: &Descriptors) -> FontFaceDescriptors {
205 FontFaceDescriptors {
206 ascent_override: descriptors.ascent_override.to_css_string().into(),
207 descent_override: descriptors.descent_override.to_css_string().into(),
208 display: descriptors.font_display.to_css_string().into(),
209 feature_settings: descriptors.font_feature_settings.to_css_string().into(),
210 line_gap_override: descriptors.line_gap_override.to_css_string().into(),
211 style: descriptors.font_style.to_css_string().into(),
212 unicode_range: descriptors.unicode_range.to_css_string().into(),
213 variation_settings: descriptors.font_variation_settings.to_css_string().into(),
214 weight: descriptors.font_weight.to_css_string().into(),
215 width: descriptors.font_width.to_css_string().into(),
216 }
217}
218
219struct FontFaceErrorReporter {
220 not_encountered_error: Cell<bool>,
221}
222
223impl ParseErrorReporter for FontFaceErrorReporter {
224 fn report_error(
225 &self,
226 _url: &UrlExtraData,
227 _location: cssparser::SourceLocation,
228 _error: style::error_reporting::ContextualParseError,
229 ) {
230 self.not_encountered_error.set(false);
231 }
232}
233
234impl FontFace {
235 fn new_failed_font_face(
238 cx: &mut JSContext,
239 global: &GlobalScope,
240 proto: Option<HandleObject>,
241 ) -> DomRoot<Self> {
242 let font_status_promise = Promise::new(cx, global);
243 font_status_promise
246 .reject_error(cx, Error::Syntax(Some("Failed to parse font face".into())));
247
248 reflect_dom_object_with_proto(
251 cx,
252 Box::new(Self {
253 reflector: Reflector::new(),
254 font_face_set: MutNullableDom::default(),
255 font_status_promise: font_status_promise.to_traced(),
256 family_name: DomRefCell::default(),
257 urls: Default::default(),
258 descriptors: DomRefCell::new(FontFaceDescriptors {
259 ascent_override: DOMString::new(),
260 descent_override: DOMString::new(),
261 display: DOMString::new(),
262 feature_settings: DOMString::new(),
263 line_gap_override: DOMString::new(),
264 style: DOMString::new(),
265 unicode_range: DOMString::new(),
266 variation_settings: DOMString::new(),
267 weight: DOMString::new(),
268 width: DOMString::new(),
269 }),
270 status: Cell::new(FontFaceLoadStatus::Error),
271 template: RefCell::default(),
272 css_font_face_rule: Default::default(),
273 }),
274 global,
275 proto,
276 )
277 }
278
279 fn new_inherited(
281 family_name: DOMString,
282 urls: Option<SourceList>,
283 descriptors: &Descriptors,
284 font_status_promise: &RootedPromise,
285 ) -> Self {
286 Self {
287 reflector: Reflector::new(),
288
289 status: Cell::new(FontFaceLoadStatus::Unloaded),
291
292 descriptors: DomRefCell::new(serialize_parsed_descriptors(descriptors)),
294
295 font_face_set: MutNullableDom::default(),
296 family_name: DomRefCell::new(family_name.traced()),
297 urls: DomRefCell::new(urls),
298 template: RefCell::default(),
299 font_status_promise: font_status_promise.to_traced(),
300 css_font_face_rule: Default::default(),
301 }
302 }
303
304 pub(crate) fn new(
306 cx: &mut JSContext,
307 global: &GlobalScope,
308 proto: Option<HandleObject>,
309 font_family: DOMString,
310 urls: Option<SourceList>,
311 descriptors: &Descriptors,
312 font_status_promise: &RootedPromise,
313 ) -> DomRoot<Self> {
314 reflect_dom_object_with_proto(
315 cx,
316 Box::new(Self::new_inherited(
317 font_family,
318 urls,
319 descriptors,
320 font_status_promise,
321 )),
322 global,
323 proto,
324 )
325 }
326
327 pub(crate) fn new_inherited_for_web_font(
329 family_name: DOMString,
330 descriptors: FontFaceDescriptors,
331 src: Option<SourceList>,
332 font_status_promise: &RootedPromise,
333 font_face_rule: ServoArc<FontFaceRuleInfo>,
334 ) -> Self {
335 Self {
336 reflector: Reflector::new(),
337 status: Cell::new(FontFaceLoadStatus::Loading),
338 descriptors: DomRefCell::new(descriptors),
339 font_face_set: MutNullableDom::default(),
340 family_name: DomRefCell::new(family_name.traced()),
341 urls: DomRefCell::new(src),
342 template: RefCell::default(),
343 font_status_promise: font_status_promise.to_traced(),
344 css_font_face_rule: DomRefCell::new(Some(font_face_rule)),
345 }
346 }
347
348 pub(crate) fn new_for_web_font(
350 cx: &mut JSContext,
351 global: &GlobalScope,
352 font_face_rule: ServoArc<FontFaceRuleInfo>,
353 ) -> Option<DomRoot<Self>> {
354 let Some(family_name) = font_face_rule
355 .descriptors
356 .font_family
357 .as_ref()
358 .map(|name| TracedDOMString::from(name.name.clone()).root())
359 else {
360 return None;
362 };
363
364 let descriptors = serialize_parsed_descriptors(&font_face_rule.descriptors);
369
370 let font_status_promise = Promise::new(cx, global);
371 Some(reflect_dom_object_with_proto(
372 cx,
373 Box::new(Self::new_inherited_for_web_font(
374 family_name,
375 descriptors,
376 font_face_rule.descriptors.src.clone(),
377 &font_status_promise,
378 font_face_rule,
379 )),
380 global,
381 None,
382 ))
383 }
384
385 pub(crate) fn disconnect_from_css(&self) {
389 *self.css_font_face_rule.borrow_mut() = None;
390 }
391
392 pub(crate) fn is_css_connected(&self) -> bool {
394 self.css_font_face_rule().is_some()
395 }
396
397 pub(crate) fn css_font_face_rule(&self) -> Ref<'_, Option<ServoArc<FontFaceRuleInfo>>> {
398 self.css_font_face_rule.borrow()
399 }
400
401 pub(crate) fn is_connected_to_font_face_rule(
406 &self,
407 target_rule: &ServoArc<FontFaceRuleInfo>,
408 ) -> bool {
409 self.css_font_face_rule()
410 .as_ref()
411 .is_some_and(|connected_rule| ServoArc::ptr_eq(connected_rule, target_rule))
412 }
413
414 fn load_from_data(&self, cx: &mut JSContext, global: &GlobalScope, data: Vec<u8>) {
416 self.status.set(FontFaceLoadStatus::Loading);
418
419 if let Some(font_face_set) = self.font_face_set.get() {
421 font_face_set.handle_font_face_status_changed(cx, self);
422 }
423
424 let parsed_font_face_rule = self.font_face_rule(global);
428 let result = parsed_font_face_rule
429 .ok()
430 .and_then(|parsed_font_face_rule| {
431 global
432 .as_window()
433 .font_context()
434 .construct_web_font_from_data(&data, (&parsed_font_face_rule).into())
435 });
436
437 if let Some(template) = result {
438 self.font_status_promise.resolve_native(cx, &self);
441 self.status.set(FontFaceLoadStatus::Loaded);
442 *self.template.borrow_mut() = Some(template);
443
444 if let Some(font_face_set) = self.font_face_set.get() {
446 font_face_set.handle_font_face_status_changed(cx, self);
451 }
452 } else {
453 self.font_status_promise
456 .reject_error(cx, Error::Syntax(Some("Failed to parse font data".into())));
457 self.status.set(FontFaceLoadStatus::Error);
458
459 if let Some(font_face_set) = self.font_face_set.get() {
461 font_face_set.handle_font_face_status_changed(cx, self);
466 }
467 }
468 }
469
470 pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
471 self.font_face_set.set(Some(font_face_set));
472 }
473
474 pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
475 self.template.borrow().clone()
476 }
477
478 fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
485 let global = self.global();
486 let parsed_font_face_rule = parse_font_face_descriptors(
487 &global,
488 &self.family_name.borrow(),
489 None,
490 &new_descriptors,
491 )?;
492
493 *self.descriptors.borrow_mut() =
494 serialize_parsed_descriptors(&parsed_font_face_rule.descriptors);
495 Ok(())
496 }
497
498 fn font_face_rule(&self, global: &GlobalScope) -> Fallible<FontFaceRule> {
499 parse_font_face_descriptors(
502 global,
503 &self.family_name.borrow(),
504 None,
505 &self.descriptors.borrow(),
506 )
507 }
508}
509
510impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
511 fn Family(&self) -> DOMString {
513 self.family_name.borrow().clone().root()
514 }
515
516 fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
518 let descriptors = self.descriptors.borrow();
519 let global = self.global();
520 let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
521 *self.family_name.borrow_mut() = family_name.traced();
522 Ok(())
523 }
524
525 fn Style(&self) -> DOMString {
527 self.descriptors.borrow().style.clone()
528 }
529
530 fn SetStyle(&self, value: DOMString) -> ErrorResult {
532 let mut new_descriptors = self.descriptors.borrow().clone();
533 new_descriptors.style = value;
534 self.validate_and_set_descriptors(new_descriptors)
535 }
536
537 fn Weight(&self) -> DOMString {
539 self.descriptors.borrow().weight.clone()
540 }
541
542 fn SetWeight(&self, value: DOMString) -> ErrorResult {
544 let mut new_descriptors = self.descriptors.borrow().clone();
545 new_descriptors.weight = value;
546 self.validate_and_set_descriptors(new_descriptors)
547 }
548
549 fn Width(&self) -> DOMString {
551 self.descriptors.borrow().width.clone()
552 }
553
554 fn SetWidth(&self, value: DOMString) -> ErrorResult {
556 let mut new_descriptors = self.descriptors.borrow().clone();
557 new_descriptors.width = value;
558 self.validate_and_set_descriptors(new_descriptors)
559 }
560
561 fn UnicodeRange(&self) -> DOMString {
563 self.descriptors.borrow().unicode_range.clone()
564 }
565
566 fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
568 let mut new_descriptors = self.descriptors.borrow().clone();
569 new_descriptors.unicode_range = value;
570 self.validate_and_set_descriptors(new_descriptors)
571 }
572
573 fn FeatureSettings(&self) -> DOMString {
575 self.descriptors.borrow().feature_settings.clone()
576 }
577
578 fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
580 let mut new_descriptors = self.descriptors.borrow().clone();
581 new_descriptors.feature_settings = value;
582 self.validate_and_set_descriptors(new_descriptors)
583 }
584
585 fn VariationSettings(&self) -> DOMString {
587 self.descriptors.borrow().variation_settings.clone()
588 }
589
590 fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
592 let mut new_descriptors = self.descriptors.borrow().clone();
593 new_descriptors.variation_settings = value;
594 self.validate_and_set_descriptors(new_descriptors)
595 }
596
597 fn Display(&self) -> DOMString {
599 self.descriptors.borrow().display.clone()
600 }
601
602 fn SetDisplay(&self, value: DOMString) -> ErrorResult {
604 let mut new_descriptors = self.descriptors.borrow().clone();
605 new_descriptors.display = value;
606 self.validate_and_set_descriptors(new_descriptors)
607 }
608
609 fn AscentOverride(&self) -> DOMString {
611 self.descriptors.borrow().ascent_override.clone()
612 }
613
614 fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
616 let mut new_descriptors = self.descriptors.borrow().clone();
617 new_descriptors.ascent_override = value;
618 self.validate_and_set_descriptors(new_descriptors)
619 }
620
621 fn DescentOverride(&self) -> DOMString {
623 self.descriptors.borrow().descent_override.clone()
624 }
625
626 fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
628 let mut new_descriptors = self.descriptors.borrow().clone();
629 new_descriptors.descent_override = value;
630 self.validate_and_set_descriptors(new_descriptors)
631 }
632
633 fn LineGapOverride(&self) -> DOMString {
635 self.descriptors.borrow().line_gap_override.clone()
636 }
637
638 fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
640 let mut new_descriptors = self.descriptors.borrow().clone();
641 new_descriptors.line_gap_override = value;
642 self.validate_and_set_descriptors(new_descriptors)
643 }
644
645 fn Status(&self) -> FontFaceLoadStatus {
647 self.status.get()
648 }
649
650 fn Load(&self, cx: &mut JSContext) -> RootedPromise {
655 let Some(sources) = self.urls.safe_borrow_mut(cx.no_gc()).take() else {
659 return self.font_status_promise.root(cx);
660 };
661 if self.status.get() != FontFaceLoadStatus::Unloaded {
662 return self.font_status_promise.root(cx);
663 }
664
665 let global = self.global();
666 let trusted = Trusted::new(self);
667 let task_source = global
668 .task_manager()
669 .font_loading_task_source()
670 .to_sendable();
671
672 let finished_callback = Box::new(
673 move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
674 let trusted = trusted.clone();
675
676 task_source.queue(task!(resolve_font_face_load_task: move |cx| {
679 let font_face = trusted.root();
680
681 match load_result {
682 None => {
683 font_face.status.set(FontFaceLoadStatus::Error);
687 font_face.font_status_promise.reject_error(cx, Error::Network(Some("Failed to load font data".into())));
688 }
689 Some(template) => {
690 font_face.status.set(FontFaceLoadStatus::Loaded);
694 let old_template = font_face.template.borrow_mut().replace((family_name, template));
695 debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
696 font_face.font_status_promise.resolve_native(cx, &font_face);
697 }
698 }
699
700 if let Some(font_face_set) = font_face.font_face_set.get() {
701 font_face_set.handle_font_face_status_changed(cx, &font_face);
707 }
708 }));
709 },
710 );
711
712 let parsed_font_face_rule = self
715 .font_face_rule(&global)
716 .expect("Parsing shouldn't fail as descriptors are valid by construction");
717
718 let document_context = global.as_window().web_font_context(cx.no_gc());
720
721 global.as_window().font_context().load_web_font_for_script(
726 global.webview_id(),
727 sources,
728 (&parsed_font_face_rule).into(),
729 finished_callback,
730 &document_context,
731 );
732
733 self.status.set(FontFaceLoadStatus::Loading);
736
737 if let Some(font_face_set) = self.font_face_set.get() {
741 font_face_set.handle_font_face_status_changed(cx, self);
742 }
743
744 self.font_status_promise.root(cx)
745 }
746
747 fn Loaded(&self, cx: &JSContext) -> RootedPromise {
749 self.font_status_promise.root(cx)
750 }
751
752 fn Constructor(
754 cx: &mut JSContext,
755 window: &Window,
756 proto: Option<HandleObject>,
757 family: DOMString,
758 source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
759 descriptors: &FontFaceInputDescriptors,
760 ) -> DomRoot<FontFace> {
761 let url_source = if let StringOrArrayBufferViewOrArrayBuffer::String(source) = &source {
763 Some(source)
764 } else {
765 None
766 };
767 let global = window.as_global_scope();
774 let parse_result =
775 parse_font_face_descriptors(global, &family, url_source, &descriptors.into());
776
777 let Ok(ref parsed_font_face_rule) = parse_result else {
778 return Self::new_failed_font_face(cx, global, proto);
783 };
784
785 let font_status_promise = Promise::new(cx, global);
787
788 let sources = parsed_font_face_rule.descriptors.src.clone();
789 let font_face = FontFace::new(
791 cx,
792 global,
793 proto,
794 family,
795 sources,
796 &parsed_font_face_rule.descriptors,
797 &font_status_promise,
798 );
799
800 if font_face.Status() == FontFaceLoadStatus::Error {
803 return font_face;
804 }
805
806 let font_face_bytes = match &source {
811 StringOrArrayBufferViewOrArrayBuffer::String(_) => {
812 return font_face;
814 },
815 StringOrArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => {
816 get_buffer_source_copy(view.into())
817 },
818 StringOrArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => {
819 get_buffer_source_copy(buffer.into())
820 },
821 };
822 let trusted_font_face = Trusted::new(&*font_face);
823 let trusted_global = Trusted::new(global);
824 global
825 .task_manager()
826 .font_loading_task_source()
827 .queue(task!(
828 load_font_from_arraybuffer: move |cx| {
829 let font_face = trusted_font_face.root();
830 let global = trusted_global.root();
831
832 font_face.load_from_data(cx, &global, font_face_bytes);
833 }
834 ));
835
836 font_face
838 }
839}