1use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7
8use cssparser::{Parser, ParserInput};
9use dom_struct::dom_struct;
10use fonts::{FontContext, FontContextWebFontMethods, FontTemplate, LowercaseFontFamilyName};
11use js::rust::HandleObject;
12use style::error_reporting::ParseErrorReporter;
13use style::font_face::SourceList;
14use style::properties::font_face::Descriptors;
15use style::stylesheets::{CssRuleType, FontFaceRule, UrlExtraData};
16use style_traits::{ParsingMode, ToCss};
17
18use crate::css::parser_context_for_document_with_reporter;
19use crate::dom::bindings::cell::DomRefCell;
20use crate::dom::bindings::codegen::Bindings::FontFaceBinding::{
21 FontFaceDescriptors, FontFaceLoadStatus, FontFaceMethods,
22};
23use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
24use crate::dom::bindings::codegen::UnionTypes;
25use crate::dom::bindings::codegen::UnionTypes::StringOrArrayBufferViewOrArrayBuffer;
26use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
27use crate::dom::bindings::refcounted::Trusted;
28use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
29use crate::dom::bindings::root::{DomRoot, MutNullableDom};
30use crate::dom::bindings::str::DOMString;
31use crate::dom::css::fontfaceset::FontFaceSet;
32use crate::dom::globalscope::GlobalScope;
33use crate::dom::node::NodeTraits;
34use crate::dom::promise::Promise;
35use crate::dom::window::Window;
36use crate::script_runtime::CanGc;
37
38#[dom_struct]
40pub struct FontFace {
41 reflector: Reflector,
42 status: Cell<FontFaceLoadStatus>,
43 family_name: DomRefCell<DOMString>,
44 descriptors: DomRefCell<FontFaceDescriptors>,
45
46 font_face_set: MutNullableDom<FontFaceSet>,
51
52 #[no_trace = "Does not contain managed objects"]
58 template: RefCell<Option<(LowercaseFontFamilyName, FontTemplate)>>,
59
60 #[no_trace = "Does not contain managed objects"]
61 urls: DomRefCell<Option<SourceList>>,
63
64 #[conditional_malloc_size_of]
66 font_status_promise: Rc<Promise>,
67}
68
69fn parse_font_face_descriptors(
75 global: &GlobalScope,
76 family_name: &DOMString,
77 sources: Option<&DOMString>,
78 input_descriptors: &FontFaceDescriptors,
79) -> Fallible<FontFaceRule> {
80 let window = global.as_window(); let document = window.Document();
82 let url_data = UrlExtraData(document.owner_global().api_base_url().get_arc());
83 let error_reporter = FontFaceErrorReporter {
84 not_encountered_error: Cell::new(true),
85 };
86 let parser_context = parser_context_for_document_with_reporter(
87 &document,
88 CssRuleType::FontFace,
89 ParsingMode::DEFAULT,
90 &url_data,
91 &error_reporter,
92 );
93
94 let FontFaceDescriptors {
95 ascentOverride,
96 descentOverride,
97 display,
98 featureSettings,
99 lineGapOverride,
100 stretch,
101 style,
102 unicodeRange,
103 variationSettings,
104 weight,
105 } = input_descriptors;
106
107 let maybe_sources = sources.map_or_else(String::new, |sources| format!("src: {sources};"));
108 let font_face_rule = format!(
109 r"
110 ascent-override: {ascentOverride};
111 descent-override: {descentOverride};
112 font-display: {display};
113 font-family: {family_name};
114 font-feature-settings: {featureSettings};
115 font-stretch: {stretch};
116 font-style: {style};
117 font-variation-settings: {variationSettings};
118 font-weight: {weight};
119 line-gap-override: {lineGapOverride};
120 unicode-range: {unicodeRange};
121 {maybe_sources}
122 "
123 );
124
125 let location = cssparser::SourceLocation { line: 0, column: 0 };
127 let mut input = ParserInput::new(&font_face_rule);
128 let mut parser = Parser::new(&mut input);
129 let mut parsed_font_face_rule =
130 style::font_face::parse_font_face_block(&parser_context, &mut parser, location);
131
132 if let Some(ref mut sources) = parsed_font_face_rule.descriptors.src {
133 let supported_sources: Vec<_> = sources
134 .0
135 .iter()
136 .rev()
137 .filter(FontContext::is_supported_web_font_source)
138 .cloned()
139 .collect();
140 if supported_sources.is_empty() {
141 error_reporter.not_encountered_error.set(false);
142 } else {
143 sources.0 = supported_sources;
144 }
145 }
146
147 if error_reporter.not_encountered_error.get() {
148 Ok(parsed_font_face_rule)
149 } else {
150 Err(Error::Syntax(None))
151 }
152}
153
154fn serialize_parsed_descriptors(descriptors: &Descriptors) -> FontFaceDescriptors {
155 FontFaceDescriptors {
156 ascentOverride: descriptors.ascent_override.to_css_string().into(),
157 descentOverride: descriptors.descent_override.to_css_string().into(),
158 display: descriptors.font_display.to_css_string().into(),
159 featureSettings: descriptors.font_feature_settings.to_css_string().into(),
160 lineGapOverride: descriptors.line_gap_override.to_css_string().into(),
161 stretch: descriptors.font_stretch.to_css_string().into(),
162 style: descriptors.font_style.to_css_string().into(),
163 unicodeRange: descriptors.unicode_range.to_css_string().into(),
164 variationSettings: descriptors.font_variation_settings.to_css_string().into(),
165 weight: descriptors.font_weight.to_css_string().into(),
166 }
167}
168
169struct FontFaceErrorReporter {
170 not_encountered_error: Cell<bool>,
171}
172
173impl ParseErrorReporter for FontFaceErrorReporter {
174 fn report_error(
175 &self,
176 _url: &UrlExtraData,
177 _location: cssparser::SourceLocation,
178 _error: style::error_reporting::ContextualParseError,
179 ) {
180 self.not_encountered_error.set(false);
181 }
182}
183
184impl FontFace {
185 fn new_failed_font_face(global: &GlobalScope, can_gc: CanGc) -> Self {
188 let font_status_promise = Promise::new(global, can_gc);
189 font_status_promise.reject_error(Error::Syntax(None), can_gc);
192
193 Self {
196 reflector: Reflector::new(),
197 font_face_set: MutNullableDom::default(),
198 font_status_promise,
199 family_name: DomRefCell::default(),
200 urls: Default::default(),
201 descriptors: DomRefCell::new(FontFaceDescriptors {
202 ascentOverride: DOMString::new(),
203 descentOverride: DOMString::new(),
204 display: DOMString::new(),
205 featureSettings: DOMString::new(),
206 lineGapOverride: DOMString::new(),
207 stretch: DOMString::new(),
208 style: DOMString::new(),
209 unicodeRange: DOMString::new(),
210 variationSettings: DOMString::new(),
211 weight: DOMString::new(),
212 }),
213 status: Cell::new(FontFaceLoadStatus::Error),
214 template: RefCell::default(),
215 }
216 }
217
218 fn new_inherited(
223 global: &GlobalScope,
224 family_name: DOMString,
225 source: Option<&DOMString>,
226 descriptors: &FontFaceDescriptors,
227 can_gc: CanGc,
228 ) -> Self {
229 let parse_result = parse_font_face_descriptors(global, &family_name, source, descriptors);
234
235 let Ok(ref parsed_font_face_rule) = parse_result else {
236 return Self::new_failed_font_face(global, can_gc);
241 };
242
243 let font_status_promise = Promise::new(global, can_gc);
245
246 let sources = parsed_font_face_rule.descriptors.src.clone();
247
248 Self {
250 reflector: Reflector::new(),
251
252 status: Cell::new(FontFaceLoadStatus::Unloaded),
254
255 descriptors: DomRefCell::new(serialize_parsed_descriptors(
257 &parsed_font_face_rule.descriptors,
258 )),
259
260 font_face_set: MutNullableDom::default(),
261 family_name: DomRefCell::new(family_name),
262 urls: DomRefCell::new(sources),
263 template: RefCell::default(),
264 font_status_promise,
265 }
266 }
267
268 pub(crate) fn new(
270 global: &GlobalScope,
271 proto: Option<HandleObject>,
272 font_family: DOMString,
273 source: StringOrArrayBufferViewOrArrayBuffer,
274 descriptors: &FontFaceDescriptors,
275 can_gc: CanGc,
276 ) -> DomRoot<Self> {
277 let url_source = if let StringOrArrayBufferViewOrArrayBuffer::String(source) = &source {
278 Some(source)
279 } else {
280 None
281 };
282
283 let font_face_rule = reflect_dom_object_with_proto(
284 Box::new(Self::new_inherited(
285 global,
286 font_family,
287 url_source,
288 descriptors,
289 can_gc,
290 )),
291 global,
292 proto,
293 can_gc,
294 );
295
296 let font_face_bytes = match source {
301 StringOrArrayBufferViewOrArrayBuffer::String(_) => {
302 return font_face_rule;
303 },
304 StringOrArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
305 StringOrArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
306 };
307
308 let trusted_font_face_rule = Trusted::new(&*font_face_rule);
309 let trusted_global = Trusted::new(global);
310 global
311 .task_manager()
312 .font_loading_task_source()
313 .queue(task!(
314 load_font_from_arraybuffer: move || {
315 let font_face_rule = trusted_font_face_rule.root();
316 let global = trusted_global.root();
317
318 font_face_rule.load_from_data(&global, font_face_bytes);
319 }
320 ));
321
322 font_face_rule
323 }
324
325 fn load_from_data(&self, global: &GlobalScope, data: Vec<u8>) {
327 let parsed_font_face_rule = self.font_face_rule(global);
328
329 self.status.set(FontFaceLoadStatus::Loading);
331
332 if let Some(font_face_set) = self.font_face_set.get() {
334 font_face_set.handle_font_face_status_changed(self);
335 }
336
337 let result = global
341 .as_window()
342 .font_context()
343 .construct_web_font_from_data(&data, (&parsed_font_face_rule).into());
344
345 if let Some(template) = result {
346 self.font_status_promise
349 .resolve_native(&self, CanGc::note());
350 self.status.set(FontFaceLoadStatus::Loaded);
351 *self.template.borrow_mut() = Some(template);
352
353 if let Some(font_face_set) = self.font_face_set.get() {
355 font_face_set.handle_font_face_status_changed(self);
360 }
361 } else {
362 self.font_status_promise
365 .reject_error(Error::Syntax(None), CanGc::note());
366 self.status.set(FontFaceLoadStatus::Error);
367
368 if let Some(font_face_set) = self.font_face_set.get() {
370 font_face_set.handle_font_face_status_changed(self);
375 }
376 }
377 }
378
379 pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
380 self.font_face_set.set(Some(font_face_set));
381 }
382
383 pub(super) fn loaded(&self) -> bool {
384 self.status.get() == FontFaceLoadStatus::Loaded
385 }
386
387 pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
388 self.template.borrow().clone()
389 }
390
391 fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
398 let global = self.global();
399 let parsed_font_face_rule = parse_font_face_descriptors(
400 &global,
401 &self.family_name.borrow(),
402 None,
403 &new_descriptors,
404 )?;
405
406 *self.descriptors.borrow_mut() =
407 serialize_parsed_descriptors(&parsed_font_face_rule.descriptors);
408 Ok(())
409 }
410
411 fn font_face_rule(&self, global: &GlobalScope) -> FontFaceRule {
412 parse_font_face_descriptors(
415 global,
416 &self.family_name.borrow(),
417 None,
418 &self.descriptors.borrow(),
419 )
420 .expect("Parsing shouldn't fail as descriptors are valid by construction")
421 }
422}
423
424impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
425 fn Family(&self) -> DOMString {
427 self.family_name.borrow().clone()
428 }
429
430 fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
432 let descriptors = self.descriptors.borrow();
433 let global = self.global();
434 let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
435 *self.family_name.borrow_mut() = family_name;
436 Ok(())
437 }
438
439 fn Style(&self) -> DOMString {
441 self.descriptors.borrow().style.clone()
442 }
443
444 fn SetStyle(&self, value: DOMString) -> ErrorResult {
446 let mut new_descriptors = self.descriptors.borrow().clone();
447 new_descriptors.style = value;
448 self.validate_and_set_descriptors(new_descriptors)
449 }
450
451 fn Weight(&self) -> DOMString {
453 self.descriptors.borrow().weight.clone()
454 }
455
456 fn SetWeight(&self, value: DOMString) -> ErrorResult {
458 let mut new_descriptors = self.descriptors.borrow().clone();
459 new_descriptors.weight = value;
460 self.validate_and_set_descriptors(new_descriptors)
461 }
462
463 fn Stretch(&self) -> DOMString {
465 self.descriptors.borrow().stretch.clone()
466 }
467
468 fn SetStretch(&self, value: DOMString) -> ErrorResult {
470 let mut new_descriptors = self.descriptors.borrow().clone();
471 new_descriptors.stretch = value;
472 self.validate_and_set_descriptors(new_descriptors)
473 }
474
475 fn UnicodeRange(&self) -> DOMString {
477 self.descriptors.borrow().unicodeRange.clone()
478 }
479
480 fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
482 let mut new_descriptors = self.descriptors.borrow().clone();
483 new_descriptors.unicodeRange = value;
484 self.validate_and_set_descriptors(new_descriptors)
485 }
486
487 fn FeatureSettings(&self) -> DOMString {
489 self.descriptors.borrow().featureSettings.clone()
490 }
491
492 fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
494 let mut new_descriptors = self.descriptors.borrow().clone();
495 new_descriptors.featureSettings = value;
496 self.validate_and_set_descriptors(new_descriptors)
497 }
498
499 fn VariationSettings(&self) -> DOMString {
501 self.descriptors.borrow().variationSettings.clone()
502 }
503
504 fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
506 let mut new_descriptors = self.descriptors.borrow().clone();
507 new_descriptors.variationSettings = value;
508 self.validate_and_set_descriptors(new_descriptors)
509 }
510
511 fn Display(&self) -> DOMString {
513 self.descriptors.borrow().display.clone()
514 }
515
516 fn SetDisplay(&self, value: DOMString) -> ErrorResult {
518 let mut new_descriptors = self.descriptors.borrow().clone();
519 new_descriptors.display = value;
520 self.validate_and_set_descriptors(new_descriptors)
521 }
522
523 fn AscentOverride(&self) -> DOMString {
525 self.descriptors.borrow().ascentOverride.clone()
526 }
527
528 fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
530 let mut new_descriptors = self.descriptors.borrow().clone();
531 new_descriptors.ascentOverride = value;
532 self.validate_and_set_descriptors(new_descriptors)
533 }
534
535 fn DescentOverride(&self) -> DOMString {
537 self.descriptors.borrow().descentOverride.clone()
538 }
539
540 fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
542 let mut new_descriptors = self.descriptors.borrow().clone();
543 new_descriptors.descentOverride = value;
544 self.validate_and_set_descriptors(new_descriptors)
545 }
546
547 fn LineGapOverride(&self) -> DOMString {
549 self.descriptors.borrow().lineGapOverride.clone()
550 }
551
552 fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
554 let mut new_descriptors = self.descriptors.borrow().clone();
555 new_descriptors.lineGapOverride = value;
556 self.validate_and_set_descriptors(new_descriptors)
557 }
558
559 fn Status(&self) -> FontFaceLoadStatus {
561 self.status.get()
562 }
563
564 fn Load(&self) -> Rc<Promise> {
569 let Some(sources) = self.urls.borrow_mut().take() else {
570 return self.font_status_promise.clone();
574 };
575
576 debug_assert_eq!(self.status.get(), FontFaceLoadStatus::Unloaded);
580
581 let global = self.global();
582 let trusted = Trusted::new(self);
583 let task_source = global
584 .task_manager()
585 .font_loading_task_source()
586 .to_sendable();
587
588 let finished_callback = Box::new(
589 move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
590 let trusted = trusted.clone();
591
592 task_source.queue(task!(resolve_font_face_load_task: move || {
595 let font_face = trusted.root();
596
597 match load_result {
598 None => {
599 font_face.status.set(FontFaceLoadStatus::Error);
603 font_face.font_status_promise.reject_error(Error::Network(None), CanGc::note());
604 }
605 Some(template) => {
606 font_face.status.set(FontFaceLoadStatus::Loaded);
610 let old_template = font_face.template.borrow_mut().replace((family_name, template));
611 debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
612 font_face.font_status_promise.resolve_native(&font_face, CanGc::note());
613 }
614 }
615
616 if let Some(font_face_set) = font_face.font_face_set.get() {
617 font_face_set.handle_font_face_status_changed(&font_face);
623 }
624 }));
625 },
626 );
627
628 let parsed_font_face_rule = self.font_face_rule(&global);
631
632 let document_context = global.as_window().web_font_context();
634
635 global.as_window().font_context().load_web_font_for_script(
640 global.webview_id(),
641 sources,
642 (&parsed_font_face_rule).into(),
643 finished_callback,
644 &document_context,
645 );
646
647 self.status.set(FontFaceLoadStatus::Loading);
650 self.font_status_promise.clone()
651 }
652
653 fn Loaded(&self) -> Rc<Promise> {
655 self.font_status_promise.clone()
656 }
657
658 fn Constructor(
660 window: &Window,
661 proto: Option<HandleObject>,
662 can_gc: CanGc,
663 family: DOMString,
664 source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
665 descriptors: &FontFaceDescriptors,
666 ) -> DomRoot<FontFace> {
667 let global = window.as_global_scope();
668 FontFace::new(global, proto, family, source, descriptors, can_gc)
669 }
670}