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 super::bindings::cell::DomRefCell;
19use super::bindings::codegen::UnionTypes::StringOrArrayBufferViewOrArrayBuffer;
20use super::bindings::error::{Error, ErrorResult, Fallible};
21use super::bindings::refcounted::Trusted;
22use super::bindings::reflector::DomGlobal;
23use super::bindings::root::MutNullableDom;
24use super::types::FontFaceSet;
25use crate::dom::bindings::codegen::Bindings::FontFaceBinding::{
26 FontFaceDescriptors, FontFaceLoadStatus, FontFaceMethods,
27};
28use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
29use crate::dom::bindings::codegen::UnionTypes;
30use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
31use crate::dom::bindings::root::DomRoot;
32use crate::dom::bindings::str::DOMString;
33use crate::dom::globalscope::GlobalScope;
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 #[ignore_malloc_size_of = "Rc"]
66 font_status_promise: Rc<Promise>,
67}
68
69fn parse_font_face_descriptors(
75 global: &GlobalScope,
76 family_name: &DOMString,
77 sources: Option<&str>,
78 input_descriptors: &FontFaceDescriptors,
79) -> Fallible<FontFaceRule> {
80 let window = global.as_window(); let quirks_mode = window.Document().quirks_mode();
82 let url_data = UrlExtraData(window.get_url().get_arc());
83 let error_reporter = FontFaceErrorReporter {
84 not_encountered_error: Cell::new(true),
85 };
86 let parser_context = ParserContext::new(
87 Origin::Author,
88 &url_data,
89 Some(CssRuleType::FontFace),
90 ParsingMode::DEFAULT,
91 quirks_mode,
92 Default::default(),
93 Some(&error_reporter as &dyn ParseErrorReporter),
94 None,
95 );
96
97 let FontFaceDescriptors {
98 ascentOverride,
99 descentOverride,
100 display,
101 featureSettings,
102 lineGapOverride,
103 stretch,
104 style,
105 unicodeRange,
106 variationSettings,
107 weight,
108 } = input_descriptors;
109
110 let _ = variationSettings; let maybe_sources = sources.map_or_else(String::new, |sources| format!("src: {sources};"));
112 let font_face_rule = format!(
113 r"
114 ascent-override: {ascentOverride};
115 descent-override: {descentOverride};
116 font-display: {display};
117 font-family: {family_name};
118 font-feature-settings: {featureSettings};
119 font-stretch: {stretch};
120 font-style: {style};
121 font-weight: {weight};
122 line-gap-override: {lineGapOverride};
123 unicode-range: {unicodeRange};
124 {maybe_sources}
125 "
126 );
127
128 let location = cssparser::SourceLocation { line: 0, column: 0 };
130 let mut input = ParserInput::new(&font_face_rule);
131 let mut parser = Parser::new(&mut input);
132 let mut parsed_font_face_rule =
133 style::font_face::parse_font_face_block(&parser_context, &mut parser, location);
134
135 if let Some(ref mut sources) = parsed_font_face_rule.sources {
136 let supported_sources: Vec<_> = sources
137 .0
138 .iter()
139 .rev()
140 .filter(FontContext::is_supported_web_font_source)
141 .cloned()
142 .collect();
143 if supported_sources.is_empty() {
144 error_reporter.not_encountered_error.set(false);
145 } else {
146 sources.0 = supported_sources;
147 }
148 }
149
150 if error_reporter.not_encountered_error.get() {
151 Ok(parsed_font_face_rule)
152 } else {
153 Err(Error::Syntax)
154 }
155}
156
157fn serialize_parsed_descriptors(font_face_rule: &FontFaceRule) -> FontFaceDescriptors {
158 FontFaceDescriptors {
159 ascentOverride: font_face_rule.ascent_override.to_css_string().into(),
160 descentOverride: font_face_rule.descent_override.to_css_string().into(),
161 display: font_face_rule.display.to_css_string().into(),
162 featureSettings: font_face_rule.feature_settings.to_css_string().into(),
163 lineGapOverride: font_face_rule.line_gap_override.to_css_string().into(),
164 stretch: font_face_rule.stretch.to_css_string().into(),
165 style: font_face_rule.style.to_css_string().into(),
166 unicodeRange: font_face_rule.unicode_range.to_css_string().into(),
167 variationSettings: font_face_rule.variation_settings.to_css_string().into(),
168 weight: font_face_rule.weight.to_css_string().into(),
169 }
170}
171
172struct FontFaceErrorReporter {
173 not_encountered_error: Cell<bool>,
174}
175
176impl ParseErrorReporter for FontFaceErrorReporter {
177 fn report_error(
178 &self,
179 _url: &UrlExtraData,
180 _location: cssparser::SourceLocation,
181 _error: style::error_reporting::ContextualParseError,
182 ) {
183 self.not_encountered_error.set(false);
184 }
185}
186
187impl FontFace {
188 fn new_failed_font_face(global: &GlobalScope, can_gc: CanGc) -> Self {
191 let font_status_promise = Promise::new(global, can_gc);
192 font_status_promise.reject_error(Error::Syntax, can_gc);
195
196 Self {
199 reflector: Reflector::new(),
200 font_face_set: MutNullableDom::default(),
201 font_status_promise,
202 family_name: DomRefCell::default(),
203 urls: DomRefCell::default(),
204 descriptors: DomRefCell::new(FontFaceDescriptors {
205 ascentOverride: DOMString::new(),
206 descentOverride: DOMString::new(),
207 display: DOMString::new(),
208 featureSettings: DOMString::new(),
209 lineGapOverride: DOMString::new(),
210 stretch: DOMString::new(),
211 style: DOMString::new(),
212 unicodeRange: DOMString::new(),
213 variationSettings: DOMString::new(),
214 weight: DOMString::new(),
215 }),
216 status: Cell::new(FontFaceLoadStatus::Error),
217 template: RefCell::default(),
218 }
219 }
220
221 fn new_inherited(
223 global: &GlobalScope,
224 family_name: DOMString,
225 source: StringOrArrayBufferViewOrArrayBuffer,
226 descriptors: &FontFaceDescriptors,
227 can_gc: CanGc,
228 ) -> Self {
229 let StringOrArrayBufferViewOrArrayBuffer::String(ref source_string) = source else {
231 return Self::new_failed_font_face(global, can_gc);
232 };
233
234 let parse_result =
239 parse_font_face_descriptors(global, &family_name, Some(source_string), descriptors);
240
241 let Ok(ref parsed_font_face_rule) = parse_result else {
242 return Self::new_failed_font_face(global, can_gc);
247 };
248
249 let font_status_promise = Promise::new(global, can_gc);
251
252 let sources = parsed_font_face_rule
253 .sources
254 .clone()
255 .expect("Sources should be non-None after validation");
256
257 Self {
259 reflector: Reflector::new(),
260
261 status: Cell::new(FontFaceLoadStatus::Unloaded),
263
264 descriptors: DomRefCell::new(serialize_parsed_descriptors(parsed_font_face_rule)),
266
267 font_face_set: MutNullableDom::default(),
268 family_name: DomRefCell::new(family_name.clone()),
269 urls: DomRefCell::new(Some(sources)),
270 template: RefCell::default(),
271 font_status_promise,
272 }
273 }
274
275 pub(crate) fn new(
276 global: &GlobalScope,
277 proto: Option<HandleObject>,
278 font_family: DOMString,
279 source: StringOrArrayBufferViewOrArrayBuffer,
280 descriptors: &FontFaceDescriptors,
281 can_gc: CanGc,
282 ) -> DomRoot<Self> {
283 reflect_dom_object_with_proto(
284 Box::new(Self::new_inherited(
285 global,
286 font_family,
287 source,
288 descriptors,
289 can_gc,
290 )),
291 global,
292 proto,
293 can_gc,
294 )
295 }
296
297 pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
298 self.font_face_set.set(Some(font_face_set));
299 }
300
301 pub(super) fn loaded(&self) -> bool {
302 self.status.get() == FontFaceLoadStatus::Loaded
303 }
304
305 pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
306 self.template.borrow().clone()
307 }
308
309 fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
316 let global = self.global();
317 let parsed_font_face_rule = parse_font_face_descriptors(
318 &global,
319 &self.family_name.borrow(),
320 None,
321 &new_descriptors,
322 )?;
323
324 *self.descriptors.borrow_mut() = serialize_parsed_descriptors(&parsed_font_face_rule);
325 Ok(())
326 }
327}
328
329impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
330 fn Family(&self) -> DOMString {
332 self.family_name.borrow().clone()
333 }
334
335 fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
337 let descriptors = self.descriptors.borrow();
338 let global = self.global();
339 let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
340 *self.family_name.borrow_mut() = family_name;
341 Ok(())
342 }
343
344 fn Style(&self) -> DOMString {
346 self.descriptors.borrow().style.clone()
347 }
348
349 fn SetStyle(&self, value: DOMString) -> ErrorResult {
351 let mut new_descriptors = self.descriptors.borrow().clone();
352 new_descriptors.style = value;
353 self.validate_and_set_descriptors(new_descriptors)
354 }
355
356 fn Weight(&self) -> DOMString {
358 self.descriptors.borrow().weight.clone()
359 }
360
361 fn SetWeight(&self, value: DOMString) -> ErrorResult {
363 let mut new_descriptors = self.descriptors.borrow().clone();
364 new_descriptors.weight = value;
365 self.validate_and_set_descriptors(new_descriptors)
366 }
367
368 fn Stretch(&self) -> DOMString {
370 self.descriptors.borrow().stretch.clone()
371 }
372
373 fn SetStretch(&self, value: DOMString) -> ErrorResult {
375 let mut new_descriptors = self.descriptors.borrow().clone();
376 new_descriptors.stretch = value;
377 self.validate_and_set_descriptors(new_descriptors)
378 }
379
380 fn UnicodeRange(&self) -> DOMString {
382 self.descriptors.borrow().unicodeRange.clone()
383 }
384
385 fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
387 let mut new_descriptors = self.descriptors.borrow().clone();
388 new_descriptors.unicodeRange = value;
389 self.validate_and_set_descriptors(new_descriptors)
390 }
391
392 fn FeatureSettings(&self) -> DOMString {
394 self.descriptors.borrow().featureSettings.clone()
395 }
396
397 fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
399 let mut new_descriptors = self.descriptors.borrow().clone();
400 new_descriptors.featureSettings = value;
401 self.validate_and_set_descriptors(new_descriptors)
402 }
403
404 fn VariationSettings(&self) -> DOMString {
406 self.descriptors.borrow().variationSettings.clone()
407 }
408
409 fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
411 let mut new_descriptors = self.descriptors.borrow().clone();
412 new_descriptors.variationSettings = value;
413 self.validate_and_set_descriptors(new_descriptors)
414 }
415
416 fn Display(&self) -> DOMString {
418 self.descriptors.borrow().display.clone()
419 }
420
421 fn SetDisplay(&self, value: DOMString) -> ErrorResult {
423 let mut new_descriptors = self.descriptors.borrow().clone();
424 new_descriptors.display = value;
425 self.validate_and_set_descriptors(new_descriptors)
426 }
427
428 fn AscentOverride(&self) -> DOMString {
430 self.descriptors.borrow().ascentOverride.clone()
431 }
432
433 fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
435 let mut new_descriptors = self.descriptors.borrow().clone();
436 new_descriptors.ascentOverride = value;
437 self.validate_and_set_descriptors(new_descriptors)
438 }
439
440 fn DescentOverride(&self) -> DOMString {
442 self.descriptors.borrow().descentOverride.clone()
443 }
444
445 fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
447 let mut new_descriptors = self.descriptors.borrow().clone();
448 new_descriptors.descentOverride = value;
449 self.validate_and_set_descriptors(new_descriptors)
450 }
451
452 fn LineGapOverride(&self) -> DOMString {
454 self.descriptors.borrow().lineGapOverride.clone()
455 }
456
457 fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
459 let mut new_descriptors = self.descriptors.borrow().clone();
460 new_descriptors.lineGapOverride = value;
461 self.validate_and_set_descriptors(new_descriptors)
462 }
463
464 fn Status(&self) -> FontFaceLoadStatus {
466 self.status.get()
467 }
468
469 fn Load(&self) -> Rc<Promise> {
474 let Some(sources) = self.urls.borrow_mut().take() else {
475 return self.font_status_promise.clone();
479 };
480
481 debug_assert_eq!(self.status.get(), FontFaceLoadStatus::Unloaded);
485
486 let global = self.global();
487 let trusted = Trusted::new(self);
488 let task_source = global
489 .task_manager()
490 .font_loading_task_source()
491 .to_sendable();
492
493 let finished_callback = Box::new(
494 move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
495 let trusted = trusted.clone();
496
497 task_source.queue(task!(resolve_font_face_load_task: move || {
500 let font_face = trusted.root();
501
502 match load_result {
503 None => {
504 font_face.status.set(FontFaceLoadStatus::Error);
508 font_face.font_status_promise.reject_error(Error::Network, CanGc::note());
509 }
510 Some(template) => {
511 font_face.status.set(FontFaceLoadStatus::Loaded);
515 let old_template = font_face.template.borrow_mut().replace((family_name, template));
516 debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
517 font_face.font_status_promise.resolve_native(&font_face, CanGc::note());
518 }
519 }
520
521 if let Some(font_face_set) = font_face.font_face_set.get() {
522 font_face_set.handle_font_face_status_changed(&font_face);
528 }
529 }));
530 },
531 );
532
533 let parsed_font_face_rule = parse_font_face_descriptors(
536 &global,
537 &self.family_name.borrow(),
538 None,
539 &self.descriptors.borrow(),
540 )
541 .expect("Parsing shouldn't fail as descriptors are valid by construction");
542
543 global.as_window().font_context().load_web_font_for_script(
548 global.webview_id(),
549 sources,
550 (&parsed_font_face_rule).into(),
551 finished_callback,
552 );
553
554 self.status.set(FontFaceLoadStatus::Loading);
557 self.font_status_promise.clone()
558 }
559
560 fn Loaded(&self) -> Rc<Promise> {
562 self.font_status_promise.clone()
563 }
564
565 fn Constructor(
567 window: &Window,
568 proto: Option<HandleObject>,
569 can_gc: CanGc,
570 family: DOMString,
571 source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
572 descriptors: &FontFaceDescriptors,
573 ) -> DomRoot<FontFace> {
574 let global = window.as_global_scope();
575 FontFace::new(global, proto, family, source, descriptors, can_gc)
576 }
577}