1use std::borrow::Cow;
6use std::sync::Arc;
7
8use base::generic_channel::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 ipc_channel::ipc::IpcSender;
16use js::jsval::UndefinedValue;
17use net_traits::ResourceThreads;
18use net_traits::image_cache::ImageCache;
19use profile_traits::{mem, time};
20use script_bindings::realms::InRealm;
21use script_traits::Painter;
22use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
23use storage_traits::StorageThreads;
24use stylo_atoms::Atom;
25
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, PaintWorkletTask};
32#[cfg(feature = "testbinding")]
33use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
34#[cfg(feature = "webgpu")]
35use crate::dom::webgpu::identityhub::IdentityHub;
36use crate::dom::worklet::WorkletExecutor;
37use crate::messaging::MainThreadScriptMsg;
38use crate::realms::enter_realm;
39use crate::script_module::ScriptFetchOptions;
40use crate::script_runtime::{CanGc, IntroductionType, JSContext};
41
42#[dom_struct]
43pub(crate) struct WorkletGlobalScope {
45 globalscope: GlobalScope,
47 #[no_trace]
49 base_url: ServoUrl,
50 to_script_thread_sender: Sender<MainThreadScriptMsg>,
52 executor: WorkletExecutor,
54}
55
56impl WorkletGlobalScope {
57 pub(crate) fn new(
59 scope_type: WorkletGlobalScopeType,
60 webview_id: WebViewId,
61 pipeline_id: PipelineId,
62 base_url: ServoUrl,
63 inherited_secure_context: Option<bool>,
64 executor: WorkletExecutor,
65 init: &WorkletGlobalScopeInit,
66 ) -> DomRoot<WorkletGlobalScope> {
67 let scope: DomRoot<WorkletGlobalScope> = match scope_type {
68 #[cfg(feature = "testbinding")]
69 WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
70 webview_id,
71 pipeline_id,
72 base_url,
73 inherited_secure_context,
74 executor,
75 init,
76 )),
77 WorkletGlobalScopeType::Paint => DomRoot::upcast(PaintWorkletGlobalScope::new(
78 webview_id,
79 pipeline_id,
80 base_url,
81 inherited_secure_context,
82 executor,
83 init,
84 )),
85 };
86
87 let realm = enter_realm(&*scope);
88 define_all_exposed_interfaces(scope.upcast(), InRealm::entered(&realm), CanGc::note());
89
90 scope
91 }
92
93 pub(crate) fn new_inherited(
95 webview_id: WebViewId,
96 pipeline_id: PipelineId,
97 base_url: ServoUrl,
98 inherited_secure_context: Option<bool>,
99 executor: WorkletExecutor,
100 init: &WorkletGlobalScopeInit,
101 ) -> Self {
102 let script_to_constellation_chan = ScriptToConstellationChan {
103 sender: init.to_constellation_sender.clone(),
104 webview_id,
105 pipeline_id,
106 };
107 Self {
108 globalscope: GlobalScope::new_inherited(
109 pipeline_id,
110 init.devtools_chan.clone(),
111 init.mem_profiler_chan.clone(),
112 init.time_profiler_chan.clone(),
113 script_to_constellation_chan,
114 init.to_embedder_sender.clone(),
115 init.resource_threads.clone(),
116 init.storage_threads.clone(),
117 MutableOrigin::new(ImmutableOrigin::new_opaque()),
118 base_url.clone(),
119 None,
120 #[cfg(feature = "webgpu")]
121 init.gpu_id_hub.clone(),
122 inherited_secure_context,
123 false,
124 None, ),
126 base_url,
127 to_script_thread_sender: init.to_script_thread_sender.clone(),
128 executor,
129 }
130 }
131
132 pub(crate) fn get_cx() -> JSContext {
134 GlobalScope::get_cx()
135 }
136
137 pub(crate) fn evaluate_js(
139 &self,
140 script: Cow<'_, str>,
141 can_gc: CanGc,
142 ) -> Result<(), JavaScriptEvaluationError> {
143 debug!("Evaluating Dom in a worklet.");
144 rooted!(in (*GlobalScope::get_cx()) let mut rval = UndefinedValue());
145 self.globalscope.evaluate_js_on_global_with_result(
146 script,
147 rval.handle_mut(),
148 ScriptFetchOptions::default_classic_script(&self.globalscope),
149 self.globalscope.api_base_url(),
150 can_gc,
151 Some(IntroductionType::WORKLET),
152 )
153 }
154
155 pub(crate) fn register_paint_worklet(
157 &self,
158 name: Atom,
159 properties: Vec<Atom>,
160 painter: Box<dyn Painter>,
161 ) {
162 self.to_script_thread_sender
163 .send(MainThreadScriptMsg::RegisterPaintWorklet {
164 pipeline_id: self.globalscope.pipeline_id(),
165 name,
166 properties,
167 painter,
168 })
169 .expect("Worklet thread outlived script thread.");
170 }
171
172 pub(crate) fn base_url(&self) -> ServoUrl {
174 self.base_url.clone()
175 }
176
177 pub(crate) fn executor(&self) -> WorkletExecutor {
179 self.executor.clone()
180 }
181
182 pub(crate) fn perform_a_worklet_task(&self, task: WorkletTask) {
184 match task {
185 #[cfg(feature = "testbinding")]
186 WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
187 Some(global) => global.perform_a_worklet_task(task),
188 None => warn!("This is not a test worklet."),
189 },
190 WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
191 Some(global) => global.perform_a_worklet_task(task),
192 None => warn!("This is not a paint worklet."),
193 },
194 }
195 }
196}
197
198#[derive(Clone)]
200pub(crate) struct WorkletGlobalScopeInit {
201 pub(crate) to_script_thread_sender: Sender<MainThreadScriptMsg>,
203 pub(crate) resource_threads: ResourceThreads,
205 pub(crate) storage_threads: StorageThreads,
207 pub(crate) mem_profiler_chan: mem::ProfilerChan,
209 pub(crate) time_profiler_chan: time::ProfilerChan,
211 pub(crate) devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
213 pub(crate) to_constellation_sender:
215 GenericSender<(WebViewId, PipelineId, ScriptToConstellationMessage)>,
216 pub(crate) to_embedder_sender: ScriptToEmbedderChan,
218 pub(crate) image_cache: Arc<dyn ImageCache>,
220 #[cfg(feature = "webgpu")]
222 pub(crate) gpu_id_hub: Arc<IdentityHub>,
223}
224
225#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
227pub(crate) enum WorkletGlobalScopeType {
228 #[cfg(feature = "testbinding")]
230 Test,
231 Paint,
233}
234
235pub(crate) enum WorkletTask {
237 #[cfg(feature = "testbinding")]
238 Test(TestWorkletTask),
239 Paint(PaintWorkletTask),
240}