1use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7
8use cssparser::{Parser, ParserInput};
9use dom_struct::dom_struct;
10use fonts::{
11 FontContext, FontContextWebFontMethods, FontFaceRuleWithOrigin, FontTemplate,
12 LowercaseFontFamilyName,
13};
14use js::context::JSContext;
15use js::rust::HandleObject;
16use script_bindings::cell::DomRefCell;
17use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto};
18use style::error_reporting::ParseErrorReporter;
19use style::font_face::SourceList;
20use style::properties::font_face::Descriptors;
21use style::shared_lock::StylesheetGuards;
22use style::stylesheets::{CssRuleType, FontFaceRule, UrlExtraData};
23use style_traits::{ParsingMode, ToCss};
24
25use crate::css::parser_context_for_document_with_reporter;
26use crate::dom::bindings::buffer_source::get_buffer_source_copy;
27use crate::dom::bindings::codegen::Bindings::FontFaceBinding::{
28 FontFaceDescriptors, FontFaceLoadStatus, FontFaceMethods,
29};
30use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
31use crate::dom::bindings::codegen::UnionTypes;
32use crate::dom::bindings::codegen::UnionTypes::StringOrArrayBufferViewOrArrayBuffer;
33use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
34use crate::dom::bindings::refcounted::Trusted;
35use crate::dom::bindings::reflector::DomGlobal;
36use crate::dom::bindings::root::{DomRoot, MutNullableDom};
37use crate::dom::bindings::str::DOMString;
38use crate::dom::css::fontfaceset::FontFaceSet;
39use crate::dom::globalscope::GlobalScope;
40use crate::dom::node::NodeTraits;
41use crate::dom::promise::Promise;
42use crate::dom::window::Window;
43
44#[dom_struct]
46pub struct FontFace {
47 reflector: Reflector,
48 status: Cell<FontFaceLoadStatus>,
49 family_name: DomRefCell<DOMString>,
50 descriptors: DomRefCell<FontFaceDescriptors>,
51
52 font_face_set: MutNullableDom<FontFaceSet>,
57
58 #[no_trace = "Does not contain managed objects"]
64 template: RefCell<Option<(LowercaseFontFamilyName, FontTemplate)>>,
65
66 #[no_trace = "Does not contain managed objects"]
67 urls: DomRefCell<Option<SourceList>>,
69
70 #[conditional_malloc_size_of]
72 font_status_promise: Rc<Promise>,
73
74 #[no_trace]
78 css_font_face_rule: DomRefCell<Option<FontFaceRuleWithOrigin>>,
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(None))
163 }
164}
165
166fn serialize_parsed_descriptors(descriptors: &Descriptors) -> FontFaceDescriptors {
169 FontFaceDescriptors {
170 ascentOverride: descriptors.ascent_override.to_css_string().into(),
171 descentOverride: descriptors.descent_override.to_css_string().into(),
172 display: descriptors.font_display.to_css_string().into(),
173 featureSettings: descriptors.font_feature_settings.to_css_string().into(),
174 lineGapOverride: descriptors.line_gap_override.to_css_string().into(),
175 stretch: descriptors.font_stretch.to_css_string().into(),
176 style: descriptors.font_style.to_css_string().into(),
177 unicodeRange: descriptors.unicode_range.to_css_string().into(),
178 variationSettings: descriptors.font_variation_settings.to_css_string().into(),
179 weight: descriptors.font_weight.to_css_string().into(),
180 }
181}
182
183struct FontFaceErrorReporter {
184 not_encountered_error: Cell<bool>,
185}
186
187impl ParseErrorReporter for FontFaceErrorReporter {
188 fn report_error(
189 &self,
190 _url: &UrlExtraData,
191 _location: cssparser::SourceLocation,
192 _error: style::error_reporting::ContextualParseError,
193 ) {
194 self.not_encountered_error.set(false);
195 }
196}
197
198impl FontFace {
199 fn new_failed_font_face(
202 cx: &mut JSContext,
203 global: &GlobalScope,
204 proto: Option<HandleObject>,
205 ) -> DomRoot<Self> {
206 let font_status_promise = Promise::new(cx, global);
207 font_status_promise.reject_error(cx, Error::Syntax(None));
210
211 reflect_dom_object_with_proto(
214 cx,
215 Box::new(Self {
216 reflector: Reflector::new(),
217 font_face_set: MutNullableDom::default(),
218 font_status_promise,
219 family_name: DomRefCell::default(),
220 urls: Default::default(),
221 descriptors: DomRefCell::new(FontFaceDescriptors {
222 ascentOverride: DOMString::new(),
223 descentOverride: DOMString::new(),
224 display: DOMString::new(),
225 featureSettings: DOMString::new(),
226 lineGapOverride: DOMString::new(),
227 stretch: DOMString::new(),
228 style: DOMString::new(),
229 unicodeRange: DOMString::new(),
230 variationSettings: DOMString::new(),
231 weight: DOMString::new(),
232 }),
233 status: Cell::new(FontFaceLoadStatus::Error),
234 template: RefCell::default(),
235 css_font_face_rule: Default::default(),
236 }),
237 global,
238 proto,
239 )
240 }
241
242 fn new_inherited(
244 family_name: DOMString,
245 urls: Option<SourceList>,
246 descriptors: &Descriptors,
247 font_status_promise: Rc<Promise>,
248 ) -> Self {
249 Self {
250 reflector: Reflector::new(),
251
252 status: Cell::new(FontFaceLoadStatus::Unloaded),
254
255 descriptors: DomRefCell::new(serialize_parsed_descriptors(descriptors)),
257
258 font_face_set: MutNullableDom::default(),
259 family_name: DomRefCell::new(family_name),
260 urls: DomRefCell::new(urls),
261 template: RefCell::default(),
262 font_status_promise,
263 css_font_face_rule: Default::default(),
264 }
265 }
266
267 pub(crate) fn new(
269 cx: &mut JSContext,
270 global: &GlobalScope,
271 proto: Option<HandleObject>,
272 font_family: DOMString,
273 urls: Option<SourceList>,
274 descriptors: &Descriptors,
275 font_status_promise: Rc<Promise>,
276 ) -> DomRoot<Self> {
277 reflect_dom_object_with_proto(
278 cx,
279 Box::new(Self::new_inherited(
280 font_family,
281 urls,
282 descriptors,
283 font_status_promise,
284 )),
285 global,
286 proto,
287 )
288 }
289
290 pub(crate) fn new_inherited_for_web_font(
292 family_name: DOMString,
293 descriptors: FontFaceDescriptors,
294 src: Option<SourceList>,
295 font_status_promise: Rc<Promise>,
296 font_face_rule: FontFaceRuleWithOrigin,
297 ) -> Self {
298 Self {
299 reflector: Reflector::new(),
300 status: Cell::new(FontFaceLoadStatus::Loading),
301 descriptors: DomRefCell::new(descriptors),
302 font_face_set: MutNullableDom::default(),
303 family_name: DomRefCell::new(family_name),
304 urls: DomRefCell::new(src),
305 template: RefCell::default(),
306 font_status_promise,
307 css_font_face_rule: DomRefCell::new(Some(font_face_rule)),
308 }
309 }
310
311 pub(crate) fn new_for_web_font(
313 cx: &mut JSContext,
314 global: &GlobalScope,
315 font_face_rule: FontFaceRuleWithOrigin,
316 guards: &StylesheetGuards,
317 ) -> Option<DomRoot<Self>> {
318 let new_web_font_ref = font_face_rule.read_with(guards);
319 let Some(family_name) = new_web_font_ref
320 .descriptors
321 .font_family
322 .as_ref()
323 .map(|name| DOMString::from(&*name.name))
324 else {
325 return None;
327 };
328
329 let descriptors = serialize_parsed_descriptors(&new_web_font_ref.descriptors);
334
335 let font_status_promise = Promise::new(cx, global);
336 Some(reflect_dom_object_with_proto(
337 cx,
338 Box::new(Self::new_inherited_for_web_font(
339 family_name,
340 descriptors,
341 new_web_font_ref.descriptors.src.clone(),
342 font_status_promise,
343 font_face_rule,
344 )),
345 global,
346 None,
347 ))
348 }
349
350 pub(crate) fn disconnect_from_css(&self) {
354 *self.css_font_face_rule.borrow_mut() = None;
355 }
356
357 pub(crate) fn is_css_connected(&self) -> bool {
359 self.css_font_face_rule.borrow().is_some()
360 }
361
362 pub(crate) fn is_connected_to_font_face_rule(
367 &self,
368 target_rule: &FontFaceRuleWithOrigin,
369 ) -> bool {
370 self.css_font_face_rule
371 .borrow()
372 .as_ref()
373 .is_some_and(|connected_rule| {
374 FontFaceRuleWithOrigin::ptr_eq(connected_rule, target_rule)
375 })
376 }
377
378 fn load_from_data(&self, cx: &mut JSContext, global: &GlobalScope, data: Vec<u8>) {
380 self.status.set(FontFaceLoadStatus::Loading);
382
383 if let Some(font_face_set) = self.font_face_set.get() {
385 font_face_set.handle_font_face_status_changed(cx, self);
386 }
387
388 let parsed_font_face_rule = self.font_face_rule(global);
392 let result = parsed_font_face_rule
393 .ok()
394 .and_then(|parsed_font_face_rule| {
395 global
396 .as_window()
397 .font_context()
398 .construct_web_font_from_data(&data, (&parsed_font_face_rule).into())
399 });
400
401 if let Some(template) = result {
402 self.font_status_promise.resolve_native(cx, &self);
405 self.status.set(FontFaceLoadStatus::Loaded);
406 *self.template.borrow_mut() = Some(template);
407
408 if let Some(font_face_set) = self.font_face_set.get() {
410 font_face_set.handle_font_face_status_changed(cx, self);
415 }
416 } else {
417 self.font_status_promise
420 .reject_error(cx, Error::Syntax(None));
421 self.status.set(FontFaceLoadStatus::Error);
422
423 if let Some(font_face_set) = self.font_face_set.get() {
425 font_face_set.handle_font_face_status_changed(cx, self);
430 }
431 }
432 }
433
434 pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
435 self.font_face_set.set(Some(font_face_set));
436 }
437
438 pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
439 self.template.borrow().clone()
440 }
441
442 fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
449 let global = self.global();
450 let parsed_font_face_rule = parse_font_face_descriptors(
451 &global,
452 &self.family_name.borrow(),
453 None,
454 &new_descriptors,
455 )?;
456
457 *self.descriptors.borrow_mut() =
458 serialize_parsed_descriptors(&parsed_font_face_rule.descriptors);
459 Ok(())
460 }
461
462 fn font_face_rule(&self, global: &GlobalScope) -> Fallible<FontFaceRule> {
463 parse_font_face_descriptors(
466 global,
467 &self.family_name.borrow(),
468 None,
469 &self.descriptors.borrow(),
470 )
471 }
472}
473
474impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
475 fn Family(&self) -> DOMString {
477 self.family_name.borrow().clone()
478 }
479
480 fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
482 let descriptors = self.descriptors.borrow();
483 let global = self.global();
484 let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
485 *self.family_name.borrow_mut() = family_name;
486 Ok(())
487 }
488
489 fn Style(&self) -> DOMString {
491 self.descriptors.borrow().style.clone()
492 }
493
494 fn SetStyle(&self, value: DOMString) -> ErrorResult {
496 let mut new_descriptors = self.descriptors.borrow().clone();
497 new_descriptors.style = value;
498 self.validate_and_set_descriptors(new_descriptors)
499 }
500
501 fn Weight(&self) -> DOMString {
503 self.descriptors.borrow().weight.clone()
504 }
505
506 fn SetWeight(&self, value: DOMString) -> ErrorResult {
508 let mut new_descriptors = self.descriptors.borrow().clone();
509 new_descriptors.weight = value;
510 self.validate_and_set_descriptors(new_descriptors)
511 }
512
513 fn Stretch(&self) -> DOMString {
515 self.descriptors.borrow().stretch.clone()
516 }
517
518 fn SetStretch(&self, value: DOMString) -> ErrorResult {
520 let mut new_descriptors = self.descriptors.borrow().clone();
521 new_descriptors.stretch = value;
522 self.validate_and_set_descriptors(new_descriptors)
523 }
524
525 fn UnicodeRange(&self) -> DOMString {
527 self.descriptors.borrow().unicodeRange.clone()
528 }
529
530 fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
532 let mut new_descriptors = self.descriptors.borrow().clone();
533 new_descriptors.unicodeRange = value;
534 self.validate_and_set_descriptors(new_descriptors)
535 }
536
537 fn FeatureSettings(&self) -> DOMString {
539 self.descriptors.borrow().featureSettings.clone()
540 }
541
542 fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
544 let mut new_descriptors = self.descriptors.borrow().clone();
545 new_descriptors.featureSettings = value;
546 self.validate_and_set_descriptors(new_descriptors)
547 }
548
549 fn VariationSettings(&self) -> DOMString {
551 self.descriptors.borrow().variationSettings.clone()
552 }
553
554 fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
556 let mut new_descriptors = self.descriptors.borrow().clone();
557 new_descriptors.variationSettings = value;
558 self.validate_and_set_descriptors(new_descriptors)
559 }
560
561 fn Display(&self) -> DOMString {
563 self.descriptors.borrow().display.clone()
564 }
565
566 fn SetDisplay(&self, value: DOMString) -> ErrorResult {
568 let mut new_descriptors = self.descriptors.borrow().clone();
569 new_descriptors.display = value;
570 self.validate_and_set_descriptors(new_descriptors)
571 }
572
573 fn AscentOverride(&self) -> DOMString {
575 self.descriptors.borrow().ascentOverride.clone()
576 }
577
578 fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
580 let mut new_descriptors = self.descriptors.borrow().clone();
581 new_descriptors.ascentOverride = value;
582 self.validate_and_set_descriptors(new_descriptors)
583 }
584
585 fn DescentOverride(&self) -> DOMString {
587 self.descriptors.borrow().descentOverride.clone()
588 }
589
590 fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
592 let mut new_descriptors = self.descriptors.borrow().clone();
593 new_descriptors.descentOverride = value;
594 self.validate_and_set_descriptors(new_descriptors)
595 }
596
597 fn LineGapOverride(&self) -> DOMString {
599 self.descriptors.borrow().lineGapOverride.clone()
600 }
601
602 fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
604 let mut new_descriptors = self.descriptors.borrow().clone();
605 new_descriptors.lineGapOverride = value;
606 self.validate_and_set_descriptors(new_descriptors)
607 }
608
609 fn Status(&self) -> FontFaceLoadStatus {
611 self.status.get()
612 }
613
614 fn Load(&self, cx: &mut JSContext) -> Rc<Promise> {
619 let Some(sources) = self.urls.borrow_mut().take() else {
623 return self.font_status_promise.clone();
624 };
625 if self.status.get() != FontFaceLoadStatus::Unloaded {
626 return self.font_status_promise.clone();
627 }
628
629 let global = self.global();
630 let trusted = Trusted::new(self);
631 let task_source = global
632 .task_manager()
633 .font_loading_task_source()
634 .to_sendable();
635
636 let finished_callback = Box::new(
637 move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
638 let trusted = trusted.clone();
639
640 task_source.queue(task!(resolve_font_face_load_task: move |cx| {
643 let font_face = trusted.root();
644
645 match load_result {
646 None => {
647 font_face.status.set(FontFaceLoadStatus::Error);
651 font_face.font_status_promise.reject_error(cx, Error::Network(None));
652 }
653 Some(template) => {
654 font_face.status.set(FontFaceLoadStatus::Loaded);
658 let old_template = font_face.template.borrow_mut().replace((family_name, template));
659 debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
660 font_face.font_status_promise.resolve_native(cx, &font_face);
661 }
662 }
663
664 if let Some(font_face_set) = font_face.font_face_set.get() {
665 font_face_set.handle_font_face_status_changed(cx, &font_face);
671 }
672 }));
673 },
674 );
675
676 let parsed_font_face_rule = self
679 .font_face_rule(&global)
680 .expect("Parsing shouldn't fail as descriptors are valid by construction");
681
682 let document_context = global.as_window().web_font_context(cx.no_gc());
684
685 global.as_window().font_context().load_web_font_for_script(
690 global.webview_id(),
691 sources,
692 (&parsed_font_face_rule).into(),
693 finished_callback,
694 &document_context,
695 );
696
697 self.status.set(FontFaceLoadStatus::Loading);
700
701 if let Some(font_face_set) = self.font_face_set.get() {
705 font_face_set.handle_font_face_status_changed(cx, self);
706 }
707
708 self.font_status_promise.clone()
709 }
710
711 fn Loaded(&self) -> Rc<Promise> {
713 self.font_status_promise.clone()
714 }
715
716 fn Constructor(
718 cx: &mut JSContext,
719 window: &Window,
720 proto: Option<HandleObject>,
721 family: DOMString,
722 source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
723 descriptors: &FontFaceDescriptors,
724 ) -> DomRoot<FontFace> {
725 let url_source = if let StringOrArrayBufferViewOrArrayBuffer::String(source) = &source {
727 Some(source)
728 } else {
729 None
730 };
731 let global = window.as_global_scope();
738 let parse_result = parse_font_face_descriptors(global, &family, url_source, descriptors);
739
740 let Ok(ref parsed_font_face_rule) = parse_result else {
741 return Self::new_failed_font_face(cx, global, proto);
746 };
747
748 let font_status_promise = Promise::new(cx, global);
750
751 let sources = parsed_font_face_rule.descriptors.src.clone();
752 let font_face = FontFace::new(
754 cx,
755 global,
756 proto,
757 family,
758 sources,
759 &parsed_font_face_rule.descriptors,
760 font_status_promise,
761 );
762
763 if font_face.Status() == FontFaceLoadStatus::Error {
766 return font_face;
767 }
768
769 let font_face_bytes = match &source {
774 StringOrArrayBufferViewOrArrayBuffer::String(_) => {
775 return font_face;
777 },
778 StringOrArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => {
779 get_buffer_source_copy(view.into())
780 },
781 StringOrArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => {
782 get_buffer_source_copy(buffer.into())
783 },
784 };
785 let trusted_font_face = Trusted::new(&*font_face);
786 let trusted_global = Trusted::new(global);
787 global
788 .task_manager()
789 .font_loading_task_source()
790 .queue(task!(
791 load_font_from_arraybuffer: move |cx| {
792 let font_face = trusted_font_face.root();
793 let global = trusted_global.root();
794
795 font_face.load_from_data(cx, &global, font_face_bytes);
796 }
797 ));
798
799 font_face
801 }
802}