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::parser::ParserContext;
15use style::stylesheets::{CssRuleType, FontFaceRule, Origin, UrlExtraData};
16use style_traits::{ParsingMode, ToCss};
17
18use crate::dom::bindings::cell::DomRefCell;
19use crate::dom::bindings::codegen::Bindings::FontFaceBinding::{
20 FontFaceDescriptors, FontFaceLoadStatus, FontFaceMethods,
21};
22use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
23use crate::dom::bindings::codegen::UnionTypes;
24use crate::dom::bindings::codegen::UnionTypes::StringOrArrayBufferViewOrArrayBuffer;
25use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
26use crate::dom::bindings::refcounted::Trusted;
27use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
28use crate::dom::bindings::root::{DomRoot, MutNullableDom};
29use crate::dom::bindings::str::DOMString;
30use crate::dom::css::fontfaceset::FontFaceSet;
31use crate::dom::globalscope::GlobalScope;
32use crate::dom::promise::Promise;
33use crate::dom::window::Window;
34use crate::script_runtime::CanGc;
35
36#[dom_struct]
38pub struct FontFace {
39 reflector: Reflector,
40 status: Cell<FontFaceLoadStatus>,
41 family_name: DomRefCell<DOMString>,
42 descriptors: DomRefCell<FontFaceDescriptors>,
43
44 font_face_set: MutNullableDom<FontFaceSet>,
49
50 #[no_trace = "Does not contain managed objects"]
56 template: RefCell<Option<(LowercaseFontFamilyName, FontTemplate)>>,
57
58 #[no_trace = "Does not contain managed objects"]
59 urls: DomRefCell<Option<SourceList>>,
61
62 #[conditional_malloc_size_of]
64 font_status_promise: Rc<Promise>,
65}
66
67fn parse_font_face_descriptors(
73 global: &GlobalScope,
74 family_name: &DOMString,
75 sources: Option<&DOMString>,
76 input_descriptors: &FontFaceDescriptors,
77) -> Fallible<FontFaceRule> {
78 let window = global.as_window(); let quirks_mode = window.Document().quirks_mode();
80 let url_data = UrlExtraData(window.get_url().get_arc());
81 let error_reporter = FontFaceErrorReporter {
82 not_encountered_error: Cell::new(true),
83 };
84 let parser_context = ParserContext::new(
85 Origin::Author,
86 &url_data,
87 Some(CssRuleType::FontFace),
88 ParsingMode::DEFAULT,
89 quirks_mode,
90 Default::default(),
91 Some(&error_reporter as &dyn ParseErrorReporter),
92 None,
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 _ = variationSettings; let maybe_sources = sources.map_or_else(String::new, |sources| format!("src: {sources};"));
110 let font_face_rule = format!(
111 r"
112 ascent-override: {ascentOverride};
113 descent-override: {descentOverride};
114 font-display: {display};
115 font-family: {family_name};
116 font-feature-settings: {featureSettings};
117 font-stretch: {stretch};
118 font-style: {style};
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.sources {
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(font_face_rule: &FontFaceRule) -> FontFaceDescriptors {
156 FontFaceDescriptors {
157 ascentOverride: font_face_rule.ascent_override.to_css_string().into(),
158 descentOverride: font_face_rule.descent_override.to_css_string().into(),
159 display: font_face_rule.display.to_css_string().into(),
160 featureSettings: font_face_rule.feature_settings.to_css_string().into(),
161 lineGapOverride: font_face_rule.line_gap_override.to_css_string().into(),
162 stretch: font_face_rule.stretch.to_css_string().into(),
163 style: font_face_rule.style.to_css_string().into(),
164 unicodeRange: font_face_rule.unicode_range.to_css_string().into(),
165 variationSettings: font_face_rule.variation_settings.to_css_string().into(),
166 weight: font_face_rule.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: DomRefCell::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(
221 global: &GlobalScope,
222 family_name: DOMString,
223 source: StringOrArrayBufferViewOrArrayBuffer,
224 descriptors: &FontFaceDescriptors,
225 can_gc: CanGc,
226 ) -> Self {
227 let StringOrArrayBufferViewOrArrayBuffer::String(ref source_string) = source else {
229 return Self::new_failed_font_face(global, can_gc);
230 };
231
232 let parse_result =
237 parse_font_face_descriptors(global, &family_name, Some(source_string), descriptors);
238
239 let Ok(ref parsed_font_face_rule) = parse_result else {
240 return Self::new_failed_font_face(global, can_gc);
245 };
246
247 let font_status_promise = Promise::new(global, can_gc);
249
250 let sources = parsed_font_face_rule
251 .sources
252 .clone()
253 .expect("Sources should be non-None after validation");
254
255 Self {
257 reflector: Reflector::new(),
258
259 status: Cell::new(FontFaceLoadStatus::Unloaded),
261
262 descriptors: DomRefCell::new(serialize_parsed_descriptors(parsed_font_face_rule)),
264
265 font_face_set: MutNullableDom::default(),
266 family_name: DomRefCell::new(family_name.clone()),
267 urls: DomRefCell::new(Some(sources)),
268 template: RefCell::default(),
269 font_status_promise,
270 }
271 }
272
273 pub(crate) fn new(
274 global: &GlobalScope,
275 proto: Option<HandleObject>,
276 font_family: DOMString,
277 source: StringOrArrayBufferViewOrArrayBuffer,
278 descriptors: &FontFaceDescriptors,
279 can_gc: CanGc,
280 ) -> DomRoot<Self> {
281 reflect_dom_object_with_proto(
282 Box::new(Self::new_inherited(
283 global,
284 font_family,
285 source,
286 descriptors,
287 can_gc,
288 )),
289 global,
290 proto,
291 can_gc,
292 )
293 }
294
295 pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
296 self.font_face_set.set(Some(font_face_set));
297 }
298
299 pub(super) fn loaded(&self) -> bool {
300 self.status.get() == FontFaceLoadStatus::Loaded
301 }
302
303 pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
304 self.template.borrow().clone()
305 }
306
307 fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
314 let global = self.global();
315 let parsed_font_face_rule = parse_font_face_descriptors(
316 &global,
317 &self.family_name.borrow(),
318 None,
319 &new_descriptors,
320 )?;
321
322 *self.descriptors.borrow_mut() = serialize_parsed_descriptors(&parsed_font_face_rule);
323 Ok(())
324 }
325}
326
327impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
328 fn Family(&self) -> DOMString {
330 self.family_name.borrow().clone()
331 }
332
333 fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
335 let descriptors = self.descriptors.borrow();
336 let global = self.global();
337 let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
338 *self.family_name.borrow_mut() = family_name;
339 Ok(())
340 }
341
342 fn Style(&self) -> DOMString {
344 self.descriptors.borrow().style.clone()
345 }
346
347 fn SetStyle(&self, value: DOMString) -> ErrorResult {
349 let mut new_descriptors = self.descriptors.borrow().clone();
350 new_descriptors.style = value;
351 self.validate_and_set_descriptors(new_descriptors)
352 }
353
354 fn Weight(&self) -> DOMString {
356 self.descriptors.borrow().weight.clone()
357 }
358
359 fn SetWeight(&self, value: DOMString) -> ErrorResult {
361 let mut new_descriptors = self.descriptors.borrow().clone();
362 new_descriptors.weight = value;
363 self.validate_and_set_descriptors(new_descriptors)
364 }
365
366 fn Stretch(&self) -> DOMString {
368 self.descriptors.borrow().stretch.clone()
369 }
370
371 fn SetStretch(&self, value: DOMString) -> ErrorResult {
373 let mut new_descriptors = self.descriptors.borrow().clone();
374 new_descriptors.stretch = value;
375 self.validate_and_set_descriptors(new_descriptors)
376 }
377
378 fn UnicodeRange(&self) -> DOMString {
380 self.descriptors.borrow().unicodeRange.clone()
381 }
382
383 fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
385 let mut new_descriptors = self.descriptors.borrow().clone();
386 new_descriptors.unicodeRange = value;
387 self.validate_and_set_descriptors(new_descriptors)
388 }
389
390 fn FeatureSettings(&self) -> DOMString {
392 self.descriptors.borrow().featureSettings.clone()
393 }
394
395 fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
397 let mut new_descriptors = self.descriptors.borrow().clone();
398 new_descriptors.featureSettings = value;
399 self.validate_and_set_descriptors(new_descriptors)
400 }
401
402 fn VariationSettings(&self) -> DOMString {
404 self.descriptors.borrow().variationSettings.clone()
405 }
406
407 fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
409 let mut new_descriptors = self.descriptors.borrow().clone();
410 new_descriptors.variationSettings = value;
411 self.validate_and_set_descriptors(new_descriptors)
412 }
413
414 fn Display(&self) -> DOMString {
416 self.descriptors.borrow().display.clone()
417 }
418
419 fn SetDisplay(&self, value: DOMString) -> ErrorResult {
421 let mut new_descriptors = self.descriptors.borrow().clone();
422 new_descriptors.display = value;
423 self.validate_and_set_descriptors(new_descriptors)
424 }
425
426 fn AscentOverride(&self) -> DOMString {
428 self.descriptors.borrow().ascentOverride.clone()
429 }
430
431 fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
433 let mut new_descriptors = self.descriptors.borrow().clone();
434 new_descriptors.ascentOverride = value;
435 self.validate_and_set_descriptors(new_descriptors)
436 }
437
438 fn DescentOverride(&self) -> DOMString {
440 self.descriptors.borrow().descentOverride.clone()
441 }
442
443 fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
445 let mut new_descriptors = self.descriptors.borrow().clone();
446 new_descriptors.descentOverride = value;
447 self.validate_and_set_descriptors(new_descriptors)
448 }
449
450 fn LineGapOverride(&self) -> DOMString {
452 self.descriptors.borrow().lineGapOverride.clone()
453 }
454
455 fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
457 let mut new_descriptors = self.descriptors.borrow().clone();
458 new_descriptors.lineGapOverride = value;
459 self.validate_and_set_descriptors(new_descriptors)
460 }
461
462 fn Status(&self) -> FontFaceLoadStatus {
464 self.status.get()
465 }
466
467 fn Load(&self) -> Rc<Promise> {
472 let Some(sources) = self.urls.borrow_mut().take() else {
473 return self.font_status_promise.clone();
477 };
478
479 debug_assert_eq!(self.status.get(), FontFaceLoadStatus::Unloaded);
483
484 let global = self.global();
485 let trusted = Trusted::new(self);
486 let task_source = global
487 .task_manager()
488 .font_loading_task_source()
489 .to_sendable();
490
491 let finished_callback = Box::new(
492 move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
493 let trusted = trusted.clone();
494
495 task_source.queue(task!(resolve_font_face_load_task: move || {
498 let font_face = trusted.root();
499
500 match load_result {
501 None => {
502 font_face.status.set(FontFaceLoadStatus::Error);
506 font_face.font_status_promise.reject_error(Error::Network, CanGc::note());
507 }
508 Some(template) => {
509 font_face.status.set(FontFaceLoadStatus::Loaded);
513 let old_template = font_face.template.borrow_mut().replace((family_name, template));
514 debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
515 font_face.font_status_promise.resolve_native(&font_face, CanGc::note());
516 }
517 }
518
519 if let Some(font_face_set) = font_face.font_face_set.get() {
520 font_face_set.handle_font_face_status_changed(&font_face);
526 }
527 }));
528 },
529 );
530
531 let parsed_font_face_rule = parse_font_face_descriptors(
534 &global,
535 &self.family_name.borrow(),
536 None,
537 &self.descriptors.borrow(),
538 )
539 .expect("Parsing shouldn't fail as descriptors are valid by construction");
540
541 global.as_window().font_context().load_web_font_for_script(
546 global.webview_id(),
547 sources,
548 (&parsed_font_face_rule).into(),
549 finished_callback,
550 );
551
552 self.status.set(FontFaceLoadStatus::Loading);
555 self.font_status_promise.clone()
556 }
557
558 fn Loaded(&self) -> Rc<Promise> {
560 self.font_status_promise.clone()
561 }
562
563 fn Constructor(
565 window: &Window,
566 proto: Option<HandleObject>,
567 can_gc: CanGc,
568 family: DOMString,
569 source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
570 descriptors: &FontFaceDescriptors,
571 ) -> DomRoot<FontFace> {
572 let global = window.as_global_scope();
573 FontFace::new(global, proto, family, source, descriptors, can_gc)
574 }
575}