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