1use std::cell::{Cell, Ref, RefCell};
6use std::rc::Rc;
7
8use cssparser::{Parser, ParserInput};
9use dom_struct::dom_struct;
10use fonts::{
11 FontContext, FontContextWebFontMethods, FontFaceRuleInfo, FontTemplate, LowercaseFontFamilyName,
12};
13use js::context::JSContext;
14use js::rust::HandleObject;
15use script_bindings::cell::DomRefCell;
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, 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;
41use crate::dom::window::Window;
42
43#[dom_struct]
45pub struct FontFace {
46 reflector: Reflector,
47 status: Cell<FontFaceLoadStatus>,
48 family_name: DomRefCell<DOMString>,
49 descriptors: DomRefCell<FontFaceDescriptors>,
50
51 font_face_set: MutNullableDom<FontFaceSet>,
56
57 #[no_trace = "Does not contain managed objects"]
63 template: RefCell<Option<(LowercaseFontFamilyName, FontTemplate)>>,
64
65 #[no_trace = "Does not contain managed objects"]
66 urls: DomRefCell<Option<SourceList>>,
68
69 #[conditional_malloc_size_of]
71 font_status_promise: Rc<Promise>,
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 ascentOverride,
108 descentOverride,
109 display,
110 featureSettings,
111 lineGapOverride,
112 stretch,
113 style,
114 unicodeRange,
115 variationSettings,
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: {ascentOverride};
123 descent-override: {descentOverride};
124 font-display: {display};
125 font-family: {family_name};
126 font-feature-settings: {featureSettings};
127 font-stretch: {stretch};
128 font-style: {style};
129 font-variation-settings: {variationSettings};
130 font-weight: {weight};
131 line-gap-override: {lineGapOverride};
132 unicode-range: {unicodeRange};
133 {maybe_sources}
134 "
135 );
136
137 let location = cssparser::SourceLocation { line: 0, column: 0 };
139 let mut input = ParserInput::new(&font_face_rule);
140 let mut parser = Parser::new(&mut input);
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
168fn serialize_parsed_descriptors(descriptors: &Descriptors) -> FontFaceDescriptors {
171 FontFaceDescriptors {
172 ascentOverride: descriptors.ascent_override.to_css_string().into(),
173 descentOverride: descriptors.descent_override.to_css_string().into(),
174 display: descriptors.font_display.to_css_string().into(),
175 featureSettings: descriptors.font_feature_settings.to_css_string().into(),
176 lineGapOverride: descriptors.line_gap_override.to_css_string().into(),
177 stretch: descriptors.font_stretch.to_css_string().into(),
178 style: descriptors.font_style.to_css_string().into(),
179 unicodeRange: descriptors.unicode_range.to_css_string().into(),
180 variationSettings: descriptors.font_variation_settings.to_css_string().into(),
181 weight: descriptors.font_weight.to_css_string().into(),
182 }
183}
184
185struct FontFaceErrorReporter {
186 not_encountered_error: Cell<bool>,
187}
188
189impl ParseErrorReporter for FontFaceErrorReporter {
190 fn report_error(
191 &self,
192 _url: &UrlExtraData,
193 _location: cssparser::SourceLocation,
194 _error: style::error_reporting::ContextualParseError,
195 ) {
196 self.not_encountered_error.set(false);
197 }
198}
199
200impl FontFace {
201 fn new_failed_font_face(
204 cx: &mut JSContext,
205 global: &GlobalScope,
206 proto: Option<HandleObject>,
207 ) -> DomRoot<Self> {
208 let font_status_promise = Promise::new(cx, global);
209 font_status_promise
212 .reject_error(cx, Error::Syntax(Some("Failed to parse font face".into())));
213
214 reflect_dom_object_with_proto(
217 cx,
218 Box::new(Self {
219 reflector: Reflector::new(),
220 font_face_set: MutNullableDom::default(),
221 font_status_promise,
222 family_name: DomRefCell::default(),
223 urls: Default::default(),
224 descriptors: DomRefCell::new(FontFaceDescriptors {
225 ascentOverride: DOMString::new(),
226 descentOverride: DOMString::new(),
227 display: DOMString::new(),
228 featureSettings: DOMString::new(),
229 lineGapOverride: DOMString::new(),
230 stretch: DOMString::new(),
231 style: DOMString::new(),
232 unicodeRange: DOMString::new(),
233 variationSettings: DOMString::new(),
234 weight: DOMString::new(),
235 }),
236 status: Cell::new(FontFaceLoadStatus::Error),
237 template: RefCell::default(),
238 css_font_face_rule: Default::default(),
239 }),
240 global,
241 proto,
242 )
243 }
244
245 fn new_inherited(
247 family_name: DOMString,
248 urls: Option<SourceList>,
249 descriptors: &Descriptors,
250 font_status_promise: Rc<Promise>,
251 ) -> Self {
252 Self {
253 reflector: Reflector::new(),
254
255 status: Cell::new(FontFaceLoadStatus::Unloaded),
257
258 descriptors: DomRefCell::new(serialize_parsed_descriptors(descriptors)),
260
261 font_face_set: MutNullableDom::default(),
262 family_name: DomRefCell::new(family_name),
263 urls: DomRefCell::new(urls),
264 template: RefCell::default(),
265 font_status_promise,
266 css_font_face_rule: Default::default(),
267 }
268 }
269
270 pub(crate) fn new(
272 cx: &mut JSContext,
273 global: &GlobalScope,
274 proto: Option<HandleObject>,
275 font_family: DOMString,
276 urls: Option<SourceList>,
277 descriptors: &Descriptors,
278 font_status_promise: Rc<Promise>,
279 ) -> DomRoot<Self> {
280 reflect_dom_object_with_proto(
281 cx,
282 Box::new(Self::new_inherited(
283 font_family,
284 urls,
285 descriptors,
286 font_status_promise,
287 )),
288 global,
289 proto,
290 )
291 }
292
293 pub(crate) fn new_inherited_for_web_font(
295 family_name: DOMString,
296 descriptors: FontFaceDescriptors,
297 src: Option<SourceList>,
298 font_status_promise: Rc<Promise>,
299 font_face_rule: ServoArc<FontFaceRuleInfo>,
300 ) -> Self {
301 Self {
302 reflector: Reflector::new(),
303 status: Cell::new(FontFaceLoadStatus::Loading),
304 descriptors: DomRefCell::new(descriptors),
305 font_face_set: MutNullableDom::default(),
306 family_name: DomRefCell::new(family_name),
307 urls: DomRefCell::new(src),
308 template: RefCell::default(),
309 font_status_promise,
310 css_font_face_rule: DomRefCell::new(Some(font_face_rule)),
311 }
312 }
313
314 pub(crate) fn new_for_web_font(
316 cx: &mut JSContext,
317 global: &GlobalScope,
318 font_face_rule: ServoArc<FontFaceRuleInfo>,
319 ) -> Option<DomRoot<Self>> {
320 let Some(family_name) = font_face_rule
321 .descriptors
322 .font_family
323 .as_ref()
324 .map(|name| DOMString::from(&*name.name))
325 else {
326 return None;
328 };
329
330 let descriptors = serialize_parsed_descriptors(&font_face_rule.descriptors);
335
336 let font_status_promise = Promise::new(cx, global);
337 Some(reflect_dom_object_with_proto(
338 cx,
339 Box::new(Self::new_inherited_for_web_font(
340 family_name,
341 descriptors,
342 font_face_rule.descriptors.src.clone(),
343 font_status_promise,
344 font_face_rule,
345 )),
346 global,
347 None,
348 ))
349 }
350
351 pub(crate) fn disconnect_from_css(&self) {
355 *self.css_font_face_rule.borrow_mut() = None;
356 }
357
358 pub(crate) fn is_css_connected(&self) -> bool {
360 self.css_font_face_rule().is_some()
361 }
362
363 pub(crate) fn css_font_face_rule(&self) -> Ref<'_, Option<ServoArc<FontFaceRuleInfo>>> {
364 self.css_font_face_rule.borrow()
365 }
366
367 pub(crate) fn is_connected_to_font_face_rule(
372 &self,
373 target_rule: &ServoArc<FontFaceRuleInfo>,
374 ) -> bool {
375 self.css_font_face_rule()
376 .as_ref()
377 .is_some_and(|connected_rule| ServoArc::ptr_eq(connected_rule, target_rule))
378 }
379
380 fn load_from_data(&self, cx: &mut JSContext, global: &GlobalScope, data: Vec<u8>) {
382 self.status.set(FontFaceLoadStatus::Loading);
384
385 if let Some(font_face_set) = self.font_face_set.get() {
387 font_face_set.handle_font_face_status_changed(cx, self);
388 }
389
390 let parsed_font_face_rule = self.font_face_rule(global);
394 let result = parsed_font_face_rule
395 .ok()
396 .and_then(|parsed_font_face_rule| {
397 global
398 .as_window()
399 .font_context()
400 .construct_web_font_from_data(&data, (&parsed_font_face_rule).into())
401 });
402
403 if let Some(template) = result {
404 self.font_status_promise.resolve_native(cx, &self);
407 self.status.set(FontFaceLoadStatus::Loaded);
408 *self.template.borrow_mut() = Some(template);
409
410 if let Some(font_face_set) = self.font_face_set.get() {
412 font_face_set.handle_font_face_status_changed(cx, self);
417 }
418 } else {
419 self.font_status_promise
422 .reject_error(cx, Error::Syntax(Some("Failed to parse font data".into())));
423 self.status.set(FontFaceLoadStatus::Error);
424
425 if let Some(font_face_set) = self.font_face_set.get() {
427 font_face_set.handle_font_face_status_changed(cx, self);
432 }
433 }
434 }
435
436 pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
437 self.font_face_set.set(Some(font_face_set));
438 }
439
440 pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
441 self.template.borrow().clone()
442 }
443
444 fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
451 let global = self.global();
452 let parsed_font_face_rule = parse_font_face_descriptors(
453 &global,
454 &self.family_name.borrow(),
455 None,
456 &new_descriptors,
457 )?;
458
459 *self.descriptors.borrow_mut() =
460 serialize_parsed_descriptors(&parsed_font_face_rule.descriptors);
461 Ok(())
462 }
463
464 fn font_face_rule(&self, global: &GlobalScope) -> Fallible<FontFaceRule> {
465 parse_font_face_descriptors(
468 global,
469 &self.family_name.borrow(),
470 None,
471 &self.descriptors.borrow(),
472 )
473 }
474}
475
476impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
477 fn Family(&self) -> DOMString {
479 self.family_name.borrow().clone()
480 }
481
482 fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
484 let descriptors = self.descriptors.borrow();
485 let global = self.global();
486 let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
487 *self.family_name.borrow_mut() = family_name;
488 Ok(())
489 }
490
491 fn Style(&self) -> DOMString {
493 self.descriptors.borrow().style.clone()
494 }
495
496 fn SetStyle(&self, value: DOMString) -> ErrorResult {
498 let mut new_descriptors = self.descriptors.borrow().clone();
499 new_descriptors.style = value;
500 self.validate_and_set_descriptors(new_descriptors)
501 }
502
503 fn Weight(&self) -> DOMString {
505 self.descriptors.borrow().weight.clone()
506 }
507
508 fn SetWeight(&self, value: DOMString) -> ErrorResult {
510 let mut new_descriptors = self.descriptors.borrow().clone();
511 new_descriptors.weight = value;
512 self.validate_and_set_descriptors(new_descriptors)
513 }
514
515 fn Stretch(&self) -> DOMString {
517 self.descriptors.borrow().stretch.clone()
518 }
519
520 fn SetStretch(&self, value: DOMString) -> ErrorResult {
522 let mut new_descriptors = self.descriptors.borrow().clone();
523 new_descriptors.stretch = value;
524 self.validate_and_set_descriptors(new_descriptors)
525 }
526
527 fn UnicodeRange(&self) -> DOMString {
529 self.descriptors.borrow().unicodeRange.clone()
530 }
531
532 fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
534 let mut new_descriptors = self.descriptors.borrow().clone();
535 new_descriptors.unicodeRange = value;
536 self.validate_and_set_descriptors(new_descriptors)
537 }
538
539 fn FeatureSettings(&self) -> DOMString {
541 self.descriptors.borrow().featureSettings.clone()
542 }
543
544 fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
546 let mut new_descriptors = self.descriptors.borrow().clone();
547 new_descriptors.featureSettings = value;
548 self.validate_and_set_descriptors(new_descriptors)
549 }
550
551 fn VariationSettings(&self) -> DOMString {
553 self.descriptors.borrow().variationSettings.clone()
554 }
555
556 fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
558 let mut new_descriptors = self.descriptors.borrow().clone();
559 new_descriptors.variationSettings = value;
560 self.validate_and_set_descriptors(new_descriptors)
561 }
562
563 fn Display(&self) -> DOMString {
565 self.descriptors.borrow().display.clone()
566 }
567
568 fn SetDisplay(&self, value: DOMString) -> ErrorResult {
570 let mut new_descriptors = self.descriptors.borrow().clone();
571 new_descriptors.display = value;
572 self.validate_and_set_descriptors(new_descriptors)
573 }
574
575 fn AscentOverride(&self) -> DOMString {
577 self.descriptors.borrow().ascentOverride.clone()
578 }
579
580 fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
582 let mut new_descriptors = self.descriptors.borrow().clone();
583 new_descriptors.ascentOverride = value;
584 self.validate_and_set_descriptors(new_descriptors)
585 }
586
587 fn DescentOverride(&self) -> DOMString {
589 self.descriptors.borrow().descentOverride.clone()
590 }
591
592 fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
594 let mut new_descriptors = self.descriptors.borrow().clone();
595 new_descriptors.descentOverride = value;
596 self.validate_and_set_descriptors(new_descriptors)
597 }
598
599 fn LineGapOverride(&self) -> DOMString {
601 self.descriptors.borrow().lineGapOverride.clone()
602 }
603
604 fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
606 let mut new_descriptors = self.descriptors.borrow().clone();
607 new_descriptors.lineGapOverride = value;
608 self.validate_and_set_descriptors(new_descriptors)
609 }
610
611 fn Status(&self) -> FontFaceLoadStatus {
613 self.status.get()
614 }
615
616 fn Load(&self, cx: &mut JSContext) -> Rc<Promise> {
621 let Some(sources) = self.urls.borrow_mut().take() else {
625 return self.font_status_promise.clone();
626 };
627 if self.status.get() != FontFaceLoadStatus::Unloaded {
628 return self.font_status_promise.clone();
629 }
630
631 let global = self.global();
632 let trusted = Trusted::new(self);
633 let task_source = global
634 .task_manager()
635 .font_loading_task_source()
636 .to_sendable();
637
638 let finished_callback = Box::new(
639 move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
640 let trusted = trusted.clone();
641
642 task_source.queue(task!(resolve_font_face_load_task: move |cx| {
645 let font_face = trusted.root();
646
647 match load_result {
648 None => {
649 font_face.status.set(FontFaceLoadStatus::Error);
653 font_face.font_status_promise.reject_error(cx, Error::Network(Some("Failed to load font data".into())));
654 }
655 Some(template) => {
656 font_face.status.set(FontFaceLoadStatus::Loaded);
660 let old_template = font_face.template.borrow_mut().replace((family_name, template));
661 debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
662 font_face.font_status_promise.resolve_native(cx, &font_face);
663 }
664 }
665
666 if let Some(font_face_set) = font_face.font_face_set.get() {
667 font_face_set.handle_font_face_status_changed(cx, &font_face);
673 }
674 }));
675 },
676 );
677
678 let parsed_font_face_rule = self
681 .font_face_rule(&global)
682 .expect("Parsing shouldn't fail as descriptors are valid by construction");
683
684 let document_context = global.as_window().web_font_context(cx.no_gc());
686
687 global.as_window().font_context().load_web_font_for_script(
692 global.webview_id(),
693 sources,
694 (&parsed_font_face_rule).into(),
695 finished_callback,
696 &document_context,
697 );
698
699 self.status.set(FontFaceLoadStatus::Loading);
702
703 if let Some(font_face_set) = self.font_face_set.get() {
707 font_face_set.handle_font_face_status_changed(cx, self);
708 }
709
710 self.font_status_promise.clone()
711 }
712
713 fn Loaded(&self) -> Rc<Promise> {
715 self.font_status_promise.clone()
716 }
717
718 fn Constructor(
720 cx: &mut JSContext,
721 window: &Window,
722 proto: Option<HandleObject>,
723 family: DOMString,
724 source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
725 descriptors: &FontFaceDescriptors,
726 ) -> DomRoot<FontFace> {
727 let url_source = if let StringOrArrayBufferViewOrArrayBuffer::String(source) = &source {
729 Some(source)
730 } else {
731 None
732 };
733 let global = window.as_global_scope();
740 let parse_result = parse_font_face_descriptors(global, &family, url_source, descriptors);
741
742 let Ok(ref parsed_font_face_rule) = parse_result else {
743 return Self::new_failed_font_face(cx, global, proto);
748 };
749
750 let font_status_promise = Promise::new(cx, global);
752
753 let sources = parsed_font_face_rule.descriptors.src.clone();
754 let font_face = FontFace::new(
756 cx,
757 global,
758 proto,
759 family,
760 sources,
761 &parsed_font_face_rule.descriptors,
762 font_status_promise,
763 );
764
765 if font_face.Status() == FontFaceLoadStatus::Error {
768 return font_face;
769 }
770
771 let font_face_bytes = match &source {
776 StringOrArrayBufferViewOrArrayBuffer::String(_) => {
777 return font_face;
779 },
780 StringOrArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => {
781 get_buffer_source_copy(view.into())
782 },
783 StringOrArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => {
784 get_buffer_source_copy(buffer.into())
785 },
786 };
787 let trusted_font_face = Trusted::new(&*font_face);
788 let trusted_global = Trusted::new(global);
789 global
790 .task_manager()
791 .font_loading_task_source()
792 .queue(task!(
793 load_font_from_arraybuffer: move |cx| {
794 let font_face = trusted_font_face.root();
795 let global = trusted_global.root();
796
797 font_face.load_from_data(cx, &global, font_face_bytes);
798 }
799 ));
800
801 font_face
803 }
804}