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