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