1use std::rc::Rc;
6use std::sync::Arc;
7use std::sync::atomic::{AtomicBool, Ordering};
8
9use crossbeam_channel::Sender;
10use devtools_traits::ScriptToDevtoolsControlMsg;
11use dom_struct::dom_struct;
12use embedder_traits::ScriptToEmbedderChan;
13use js::context::JSContext;
14use net_traits::ResourceThreads;
15use net_traits::image_cache::ImageCache;
16use profile_traits::{mem, time};
17use script_traits::Painter;
18use servo_base::generic_channel::GenericCallback;
19use servo_base::id::PipelineId;
20use servo_constellation_traits::ScriptToConstellationSender;
21use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
22use storage_traits::StorageThreads;
23use stylo_atoms::Atom;
24
25use crate::dom::Window;
26use crate::dom::bindings::inheritance::Castable;
27use crate::dom::bindings::root::DomRoot;
28use crate::dom::bindings::trace::CustomTraceable;
29use crate::dom::bindings::utils::define_all_exposed_interfaces;
30use crate::dom::globalscope::GlobalScope;
31use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
32#[cfg(feature = "testbinding")]
33use crate::dom::testworkletglobalscope::TestWorkletGlobalScope;
34#[cfg(feature = "webgpu")]
35use crate::dom::webgpu::identityhub::IdentityHub;
36use crate::dom::worklet::WorkletExecutor;
37use crate::messaging::MainThreadScriptMsg;
38use crate::realms::enter_auto_realm;
39use crate::runtime::microtask::MicrotaskQueue;
40use crate::tasks::task::TaskCanceller;
41use crate::tasks::task_manager::TaskManager;
42
43#[dom_struct]
44pub(crate) struct WorkletGlobalScope {
46 globalscope: GlobalScope,
48 #[no_trace]
50 base_url: ServoUrl,
51 to_script_thread_sender: Sender<MainThreadScriptMsg>,
53 executor: WorkletExecutor,
55
56 #[no_trace]
57 pipeline_id: PipelineId,
59
60 #[no_trace]
61 origin: MutableOrigin,
62
63 #[conditional_malloc_size_of]
65 task_manager: Rc<TaskManager>,
66
67 #[conditional_malloc_size_of]
70 microtask_queue: Rc<MicrotaskQueue>,
71
72 #[conditional_malloc_size_of]
73 closing: Arc<AtomicBool>,
74}
75
76impl WorkletGlobalScope {
77 #[allow(clippy::too_many_arguments)]
79 pub(crate) fn new(
80 scope_type: WorkletGlobalScopeType,
81 pipeline_id: PipelineId,
82 base_url: ServoUrl,
83 inherited_secure_context: Option<bool>,
84 executor: WorkletExecutor,
85 init: &WorkletGlobalScopeInit,
86 cx: &mut JSContext,
87 closing: Arc<AtomicBool>,
88 microtask_queue: Rc<MicrotaskQueue>,
89 ) -> DomRoot<WorkletGlobalScope> {
90 let scope: DomRoot<WorkletGlobalScope> = match scope_type {
91 #[cfg(feature = "testbinding")]
92 WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
93 pipeline_id,
94 base_url,
95 inherited_secure_context,
96 executor,
97 init,
98 cx,
99 closing,
100 microtask_queue,
101 )),
102 WorkletGlobalScopeType::Paint => DomRoot::upcast(PaintWorkletGlobalScope::new(
103 cx,
104 pipeline_id,
105 base_url,
106 inherited_secure_context,
107 executor,
108 init,
109 closing,
110 microtask_queue,
111 )),
112 };
113
114 let mut realm = enter_auto_realm(cx, &*scope);
115 let mut realm = realm.current_realm();
116 define_all_exposed_interfaces(&mut realm, scope.upcast());
117
118 scope
119 }
120
121 pub(crate) fn new_inherited(
123 pipeline_id: PipelineId,
124 base_url: ServoUrl,
125 inherited_secure_context: Option<bool>,
126 executor: WorkletExecutor,
127 init: &WorkletGlobalScopeInit,
128 closing: Arc<AtomicBool>,
129 microtask_queue: Rc<MicrotaskQueue>,
130 ) -> Self {
131 let script_event_loop_sender = executor.event_loop_sender();
132
133 Self {
134 globalscope: GlobalScope::new_inherited(
135 init.devtools_chan.clone(),
136 init.mem_profiler_chan.clone(),
137 init.time_profiler_chan.clone(),
138 init.script_to_constellation_sender.clone(),
139 init.to_embedder_sender.clone(),
140 init.resource_threads.clone(),
141 init.storage_threads.clone(),
142 base_url.clone(),
143 None,
144 #[cfg(feature = "webgpu")]
145 init.gpu_id_hub.clone(),
146 inherited_secure_context,
147 false,
148 ),
149 base_url,
150 to_script_thread_sender: init.to_script_thread_sender.clone(),
151 executor,
152 pipeline_id,
153 task_manager: Rc::new(TaskManager::new(
154 Some(script_event_loop_sender),
155 pipeline_id,
156 Some(TaskCanceller {
157 cancelled: closing.clone(),
158 }),
159 )),
160 origin: MutableOrigin::new(ImmutableOrigin::new_opaque()),
161 microtask_queue,
162 closing,
163 }
164 }
165
166 pub(crate) fn origin(&self) -> MutableOrigin {
167 self.origin.clone()
168 }
169
170 pub(crate) fn pipeline_id(&self) -> PipelineId {
171 self.pipeline_id
172 }
173
174 pub(crate) fn register_paint_worklet(
176 &self,
177 name: Atom,
178 properties: Vec<Atom>,
179 painter: Box<dyn Painter>,
180 ) {
181 self.to_script_thread_sender
182 .send(MainThreadScriptMsg::RegisterPaintWorklet {
183 pipeline_id: self.globalscope.pipeline_id(),
184 name,
185 properties,
186 painter,
187 })
188 .expect("Worklet thread outlived script thread.");
189 }
190
191 pub(crate) fn base_url(&self) -> ServoUrl {
193 self.base_url.clone()
194 }
195
196 pub(crate) fn executor(&self) -> WorkletExecutor {
198 self.executor.clone()
199 }
200
201 pub(crate) fn task_manager(&self) -> Rc<TaskManager> {
202 self.task_manager.clone()
203 }
204
205 pub(crate) fn perform_a_microtask_checkpoint(&self, cx: &mut JSContext) {
206 if !self.closing.load(Ordering::SeqCst) {
207 self.microtask_queue
208 .checkpoint(cx, vec![DomRoot::from_ref(&self.globalscope)]);
209 }
210 }
211}
212
213impl From<&Window> for WorkletGlobalScopeInit {
214 fn from(window: &Window) -> Self {
215 let global_scope = window.as_global_scope();
216
217 WorkletGlobalScopeInit {
218 to_script_thread_sender: window.main_thread_script_chan().clone(),
219 resource_threads: global_scope.resource_threads().clone(),
220 storage_threads: global_scope.storage_threads().clone(),
221 mem_profiler_chan: global_scope.mem_profiler_chan().clone(),
222 time_profiler_chan: global_scope.time_profiler_chan().clone(),
223 devtools_chan: global_scope.devtools_chan().cloned(),
224 script_to_constellation_sender: global_scope.script_to_constellation_chan().sender,
225 to_embedder_sender: global_scope.script_to_embedder_chan().clone(),
226 image_cache: global_scope.image_cache(),
227 #[cfg(feature = "webgpu")]
228 gpu_id_hub: global_scope.wgpu_id_hub(),
229 }
230 }
231}
232
233#[derive(Clone)]
235pub(crate) struct WorkletGlobalScopeInit {
236 pub(crate) to_script_thread_sender: Sender<MainThreadScriptMsg>,
238 pub(crate) resource_threads: ResourceThreads,
240 pub(crate) storage_threads: StorageThreads,
242 pub(crate) mem_profiler_chan: mem::ProfilerChan,
244 pub(crate) time_profiler_chan: time::ProfilerChan,
246 pub(crate) devtools_chan: Option<GenericCallback<ScriptToDevtoolsControlMsg>>,
248 pub(crate) to_embedder_sender: ScriptToEmbedderChan,
250 pub(crate) image_cache: Arc<dyn ImageCache>,
252 #[cfg(feature = "webgpu")]
254 pub(crate) gpu_id_hub: Arc<IdentityHub>,
255 pub(crate) script_to_constellation_sender: ScriptToConstellationSender,
256}
257
258#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
260pub(crate) enum WorkletGlobalScopeType {
261 #[cfg(feature = "testbinding")]
263 Test,
264 Paint,
266}