script/dom/css/
fontfaceset.rs1use std::rc::Rc;
6
7use dom_struct::dom_struct;
8use fonts::FontContextWebFontMethods;
9use js::rust::HandleObject;
10use script_bindings::like::Setlike;
11
12use crate::dom::bindings::cell::DomRefCell;
13use crate::dom::bindings::codegen::Bindings::FontFaceSetBinding::FontFaceSetMethods;
14use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
15use crate::dom::bindings::refcounted::TrustedPromise;
16use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
17use crate::dom::bindings::root::{Dom, DomRoot};
18use crate::dom::bindings::str::DOMString;
19use crate::dom::eventtarget::EventTarget;
20use crate::dom::fontface::FontFace;
21use crate::dom::globalscope::GlobalScope;
22use crate::dom::promise::Promise;
23use crate::dom::window::Window;
24use crate::script_runtime::CanGc;
25
26#[dom_struct]
28pub(crate) struct FontFaceSet {
29 target: EventTarget,
30
31 #[conditional_malloc_size_of]
33 promise: Rc<Promise>,
34
35 set_entries: DomRefCell<Vec<Dom<FontFace>>>,
36}
37
38impl FontFaceSet {
39 fn new_inherited(global: &GlobalScope, can_gc: CanGc) -> Self {
40 FontFaceSet {
41 target: EventTarget::new_inherited(),
42 promise: Promise::new(global, can_gc),
43 set_entries: Default::default(),
44 }
45 }
46
47 pub(crate) fn new(
48 global: &GlobalScope,
49 proto: Option<HandleObject>,
50 can_gc: CanGc,
51 ) -> DomRoot<Self> {
52 reflect_dom_object_with_proto(
53 Box::new(FontFaceSet::new_inherited(global, can_gc)),
54 global,
55 proto,
56 can_gc,
57 )
58 }
59
60 pub(super) fn handle_font_face_status_changed(&self, font_face: &FontFace) {
61 if font_face.loaded() {
62 let Some(window) = DomRoot::downcast::<Window>(self.global()) else {
63 return;
64 };
65
66 let (family_name, template) = font_face
67 .template()
68 .expect("A loaded web font should have a template");
69 window
70 .font_context()
71 .add_template_to_font_context(family_name, template);
72 window.Document().dirty_all_nodes();
73 }
74 }
75
76 pub(crate) fn fulfill_ready_promise_if_needed(&self, can_gc: CanGc) -> bool {
78 if self.promise.is_fulfilled() {
79 return false;
80 }
81 self.promise.resolve_native(self, can_gc);
82 true
83 }
84
85 pub(crate) fn waiting_to_fullfill_promise(&self) -> bool {
86 !self.promise.is_fulfilled()
87 }
88
89 fn contains_face(&self, target: &FontFace) -> bool {
90 self.set_entries
91 .borrow()
92 .iter()
93 .any(|face| &**face == target)
94 }
95
96 fn delete_face(&self, target: &FontFace) -> bool {
98 let mut set_entries = self.set_entries.borrow_mut();
99 let Some(index) = set_entries.iter().position(|face| &**face == target) else {
100 return false;
101 };
102 set_entries.remove(index);
103 true
104 }
105}
106
107impl FontFaceSetMethods<crate::DomTypeHolder> for FontFaceSet {
108 fn Ready(&self) -> Rc<Promise> {
110 self.promise.clone()
111 }
112
113 fn Add(&self, font_face: &FontFace) -> DomRoot<FontFaceSet> {
115 if self.contains_face(font_face) {
118 return DomRoot::from_ref(self);
119 }
120
121 self.set_entries.borrow_mut().push(Dom::from_ref(font_face));
126 font_face.set_associated_font_face_set(self);
127
128 self.handle_font_face_status_changed(font_face);
132
133 DomRoot::from_ref(self)
135 }
136
137 fn Delete(&self, to_delete: &FontFace) -> bool {
139 self.delete_face(to_delete)
147 }
148
149 fn Clear(&self) {
151 self.set_entries.borrow_mut().clear();
154
155 }
158
159 fn Load(&self, _font: DOMString, _text: DOMString, can_gc: CanGc) -> Rc<Promise> {
161 let promise = Promise::new(&self.global(), can_gc);
164
165 let trusted = TrustedPromise::new(promise.clone());
171 self.global()
173 .task_manager()
174 .font_loading_task_source()
175 .queue(task!(resolve_font_face_set_load_task: move || {
176 let promise = trusted.root();
177
178 let matched_fonts = Vec::<&FontFace>::new();
184 promise.resolve_native(&matched_fonts, CanGc::note());
185 }));
186
187 promise
189 }
190
191 fn Size(&self) -> u32 {
193 self.set_entries.borrow().len() as u32
194 }
195}
196
197impl Setlike for FontFaceSet {
198 type Key = DomRoot<FontFace>;
199
200 #[inline(always)]
201 fn get_index(&self, index: u32) -> Option<Self::Key> {
202 self.set_entries
203 .borrow()
204 .get(index as usize)
205 .map(|face| face.as_rooted())
206 }
207
208 #[inline(always)]
209 fn size(&self) -> u32 {
210 self.set_entries.borrow().len() as u32
211 }
212
213 #[inline(always)]
214 fn add(&self, face: Self::Key) {
215 self.set_entries.borrow_mut().push(face.as_traced());
216 }
217
218 #[inline(always)]
219 fn has(&self, target: Self::Key) -> bool {
220 self.contains_face(&target)
221 }
222
223 #[inline(always)]
224 fn clear(&self) {
225 self.set_entries.borrow_mut().clear();
226 }
227
228 #[inline(always)]
229 fn delete(&self, to_delete: Self::Key) -> bool {
230 self.delete_face(&to_delete)
231 }
232}