1use std::borrow::Cow;
6use std::sync::Arc;
7
8use base::generic_channel::{GenericCallback, GenericSender};
9use base::id::{PipelineId, WebViewId};
10use constellation_traits::{ScriptToConstellationChan, ScriptToConstellationMessage};
11use crossbeam_channel::Sender;
12use devtools_traits::ScriptToDevtoolsControlMsg;
13use dom_struct::dom_struct;
14use embedder_traits::{JavaScriptEvaluationError, ScriptToEmbedderChan};
15use net_traits::ResourceThreads;
16use net_traits::image_cache::ImageCache;
17use profile_traits::{mem, time};
18use script_traits::Painter;
19use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
20use storage_traits::StorageThreads;
21use stylo_atoms::Atom;
22
23use crate::dom::bindings::inheritance::Castable;
24use crate::dom::bindings::root::DomRoot;
25use crate::dom::bindings::trace::CustomTraceable;
26use crate::dom::bindings::utils::define_all_exposed_interfaces;
27use crate::dom::globalscope::GlobalScope;
28use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask};
29#[cfg(feature = "testbinding")]
30use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
31#[cfg(feature = "webgpu")]
32use crate::dom::webgpu::identityhub::IdentityHub;
33use crate::dom::worklet::WorkletExecutor;
34use crate::messaging::MainThreadScriptMsg;
35use crate::realms::enter_auto_realm;
36use crate::script_runtime::{IntroductionType, JSContext};
37
38#[dom_struct]
39pub(crate) struct WorkletGlobalScope {
41 globalscope: GlobalScope,
43 #[no_trace]
45 base_url: ServoUrl,
46 to_script_thread_sender: Sender<MainThreadScriptMsg>,
48 executor: WorkletExecutor,
50}
51
52impl WorkletGlobalScope {
53 #[expect(clippy::too_many_arguments)]
54 pub(crate) fn new(
56 scope_type: WorkletGlobalScopeType,
57 webview_id: WebViewId,
58 pipeline_id: PipelineId,
59 base_url: ServoUrl,
60 inherited_secure_context: Option<bool>,
61 executor: WorkletExecutor,
62 init: &WorkletGlobalScopeInit,
63 cx: &mut js::context::JSContext,
64 ) -> DomRoot<WorkletGlobalScope> {
65 let scope: DomRoot<WorkletGlobalScope> = match scope_type {
66 #[cfg(feature = "testbinding")]
67 WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
68 webview_id,
69 pipeline_id,
70 base_url,
71 inherited_secure_context,
72 executor,
73 init,
74 cx,
75 )),
76 WorkletGlobalScopeType::Paint => DomRoot::upcast(PaintWorkletGlobalScope::new(
77 webview_id,
78 pipeline_id,
79 base_url,
80 inherited_secure_context,
81 executor,
82 init,
83 cx,
84 )),
85 };
86
87 let mut realm = enter_auto_realm(cx, &*scope);
88 let mut realm = realm.current_realm();
89 define_all_exposed_interfaces(&mut realm, scope.upcast());
90
91 scope
92 }
93
94 pub(crate) fn new_inherited(
96 webview_id: WebViewId,
97 pipeline_id: PipelineId,
98 base_url: ServoUrl,
99 inherited_secure_context: Option<bool>,
100 executor: WorkletExecutor,
101 init: &WorkletGlobalScopeInit,
102 ) -> Self {
103 let script_to_constellation_chan = ScriptToConstellationChan {
104 sender: init.to_constellation_sender.clone(),
105 webview_id,
106 pipeline_id,
107 };
108 Self {
109 globalscope: GlobalScope::new_inherited(
110 pipeline_id,
111 init.devtools_chan.clone(),
112 init.mem_profiler_chan.clone(),
113 init.time_profiler_chan.clone(),
114 script_to_constellation_chan,
115 init.to_embedder_sender.clone(),
116 init.resource_threads.clone(),
117 init.storage_threads.clone(),
118 MutableOrigin::new(ImmutableOrigin::new_opaque()),
119 base_url.clone(),
120 None,
121 #[cfg(feature = "webgpu")]
122 init.gpu_id_hub.clone(),
123 inherited_secure_context,
124 false,
125 None, ),
127 base_url,
128 to_script_thread_sender: init.to_script_thread_sender.clone(),
129 executor,
130 }
131 }
132
133 pub(crate) fn get_cx() -> JSContext {
135 GlobalScope::get_cx()
136 }
137
138 pub(crate) fn evaluate_js(
140 &self,
141 script: Cow<'_, str>,
142 cx: &mut js::context::JSContext,
143 ) -> Result<(), JavaScriptEvaluationError> {
144 let mut realm = enter_auto_realm(cx, self);
145 let cx = &mut realm.current_realm();
146
147 debug!("Evaluating Dom in a worklet.");
148 self.globalscope.evaluate_js_on_global(
149 cx,
150 script,
151 "",
152 Some(IntroductionType::WORKLET),
153 None,
154 )
155 }
156
157 pub(crate) fn register_paint_worklet(
159 &self,
160 name: Atom,
161 properties: Vec<Atom>,
162 painter: Box<dyn Painter>,
163 ) {
164 self.to_script_thread_sender
165 .send(MainThreadScriptMsg::RegisterPaintWorklet {
166 pipeline_id: self.globalscope.pipeline_id(),
167 name,
168 properties,
169 painter,
170 })
171 .expect("Worklet thread outlived script thread.");
172 }
173
174 pub(crate) fn base_url(&self) -> ServoUrl {
176 self.base_url.clone()
177 }
178
179 pub(crate) fn executor(&self) -> WorkletExecutor {
181 self.executor.clone()
182 }
183
184 pub(crate) fn perform_a_worklet_task(&self, task: WorkletTask) {
186 match task {
187 #[cfg(feature = "testbinding")]
188 WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
189 Some(global) => global.perform_a_worklet_task(task),
190 None => warn!("This is not a test worklet."),
191 },
192 WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
193 Some(global) => global.perform_a_worklet_task(task),
194 None => warn!("This is not a paint worklet."),
195 },
196 }
197 }
198}
199
200#[derive(Clone)]
202pub(crate) struct WorkletGlobalScopeInit {
203 pub(crate) to_script_thread_sender: Sender<MainThreadScriptMsg>,
205 pub(crate) resource_threads: ResourceThreads,
207 pub(crate) storage_threads: StorageThreads,
209 pub(crate) mem_profiler_chan: mem::ProfilerChan,
211 pub(crate) time_profiler_chan: time::ProfilerChan,
213 pub(crate) devtools_chan: Option<GenericCallback<ScriptToDevtoolsControlMsg>>,
215 pub(crate) to_constellation_sender:
217 GenericSender<(WebViewId, PipelineId, ScriptToConstellationMessage)>,
218 pub(crate) to_embedder_sender: ScriptToEmbedderChan,
220 pub(crate) image_cache: Arc<dyn ImageCache>,
222 #[cfg(feature = "webgpu")]
224 pub(crate) gpu_id_hub: Arc<IdentityHub>,
225}
226
227#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
229pub(crate) enum WorkletGlobalScopeType {
230 #[cfg(feature = "testbinding")]
232 Test,
233 Paint,
235}
236
237pub(crate) enum WorkletTask {
239 #[cfg(feature = "testbinding")]
240 Test(TestWorkletTask),
241 Paint(PaintWorkletTask),
242}