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