1use std::sync::Arc;
6
7use base::generic_channel::GenericSender;
8use base::id::PipelineId;
9use constellation_traits::{ScriptToConstellationChan, ScriptToConstellationMessage};
10use crossbeam_channel::Sender;
11use devtools_traits::ScriptToDevtoolsControlMsg;
12use dom_struct::dom_struct;
13use embedder_traits::{JavaScriptEvaluationError, ScriptToEmbedderChan};
14use ipc_channel::ipc::IpcSender;
15use js::jsval::UndefinedValue;
16use net_traits::ResourceThreads;
17use net_traits::image_cache::ImageCache;
18use profile_traits::{mem, time};
19use script_bindings::realms::InRealm;
20use script_traits::Painter;
21use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
22use storage_traits::StorageThreads;
23use stylo_atoms::Atom;
24
25use crate::dom::bindings::inheritance::Castable;
26use crate::dom::bindings::root::DomRoot;
27use crate::dom::bindings::trace::CustomTraceable;
28use crate::dom::bindings::utils::define_all_exposed_interfaces;
29use crate::dom::globalscope::GlobalScope;
30use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask};
31#[cfg(feature = "testbinding")]
32use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
33#[cfg(feature = "webgpu")]
34use crate::dom::webgpu::identityhub::IdentityHub;
35use crate::dom::worklet::WorkletExecutor;
36use crate::messaging::MainThreadScriptMsg;
37use crate::realms::enter_realm;
38use crate::script_module::ScriptFetchOptions;
39use crate::script_runtime::{CanGc, IntroductionType, JSContext};
40
41#[dom_struct]
42pub(crate) struct WorkletGlobalScope {
44 globalscope: GlobalScope,
46 #[no_trace]
48 base_url: ServoUrl,
49 to_script_thread_sender: Sender<MainThreadScriptMsg>,
51 executor: WorkletExecutor,
53}
54
55impl WorkletGlobalScope {
56 pub(crate) fn new(
58 scope_type: WorkletGlobalScopeType,
59 pipeline_id: PipelineId,
60 base_url: ServoUrl,
61 executor: WorkletExecutor,
62 init: &WorkletGlobalScopeInit,
63 ) -> DomRoot<WorkletGlobalScope> {
64 let scope: DomRoot<WorkletGlobalScope> = match scope_type {
65 #[cfg(feature = "testbinding")]
66 WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
67 pipeline_id,
68 base_url,
69 executor,
70 init,
71 )),
72 WorkletGlobalScopeType::Paint => DomRoot::upcast(PaintWorkletGlobalScope::new(
73 pipeline_id,
74 base_url,
75 executor,
76 init,
77 )),
78 };
79
80 let realm = enter_realm(&*scope);
81 define_all_exposed_interfaces(scope.upcast(), InRealm::entered(&realm), CanGc::note());
82
83 scope
84 }
85
86 pub(crate) fn new_inherited(
88 pipeline_id: PipelineId,
89 base_url: ServoUrl,
90 executor: WorkletExecutor,
91 init: &WorkletGlobalScopeInit,
92 ) -> Self {
93 let script_to_constellation_chan = ScriptToConstellationChan {
94 sender: init.to_constellation_sender.clone(),
95 pipeline_id,
96 };
97 Self {
98 globalscope: GlobalScope::new_inherited(
99 pipeline_id,
100 init.devtools_chan.clone(),
101 init.mem_profiler_chan.clone(),
102 init.time_profiler_chan.clone(),
103 script_to_constellation_chan,
104 init.to_embedder_sender.clone(),
105 init.resource_threads.clone(),
106 init.storage_threads.clone(),
107 MutableOrigin::new(ImmutableOrigin::new_opaque()),
108 base_url.clone(),
109 None,
110 Default::default(),
111 #[cfg(feature = "webgpu")]
112 init.gpu_id_hub.clone(),
113 init.inherited_secure_context,
114 false,
115 None, ),
117 base_url,
118 to_script_thread_sender: init.to_script_thread_sender.clone(),
119 executor,
120 }
121 }
122
123 pub(crate) fn get_cx() -> JSContext {
125 GlobalScope::get_cx()
126 }
127
128 pub(crate) fn evaluate_js(
130 &self,
131 script: &str,
132 can_gc: CanGc,
133 ) -> Result<(), JavaScriptEvaluationError> {
134 debug!("Evaluating Dom in a worklet.");
135 rooted!(in (*GlobalScope::get_cx()) let mut rval = UndefinedValue());
136 self.globalscope.evaluate_js_on_global_with_result(
137 script,
138 rval.handle_mut(),
139 ScriptFetchOptions::default_classic_script(&self.globalscope),
140 self.globalscope.api_base_url(),
141 can_gc,
142 Some(IntroductionType::WORKLET),
143 )
144 }
145
146 pub(crate) fn register_paint_worklet(
148 &self,
149 name: Atom,
150 properties: Vec<Atom>,
151 painter: Box<dyn Painter>,
152 ) {
153 self.to_script_thread_sender
154 .send(MainThreadScriptMsg::RegisterPaintWorklet {
155 pipeline_id: self.globalscope.pipeline_id(),
156 name,
157 properties,
158 painter,
159 })
160 .expect("Worklet thread outlived script thread.");
161 }
162
163 pub(crate) fn base_url(&self) -> ServoUrl {
165 self.base_url.clone()
166 }
167
168 pub(crate) fn executor(&self) -> WorkletExecutor {
170 self.executor.clone()
171 }
172
173 pub(crate) fn perform_a_worklet_task(&self, task: WorkletTask) {
175 match task {
176 #[cfg(feature = "testbinding")]
177 WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
178 Some(global) => global.perform_a_worklet_task(task),
179 None => warn!("This is not a test worklet."),
180 },
181 WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
182 Some(global) => global.perform_a_worklet_task(task),
183 None => warn!("This is not a paint worklet."),
184 },
185 }
186 }
187}
188
189#[derive(Clone)]
191pub(crate) struct WorkletGlobalScopeInit {
192 pub(crate) to_script_thread_sender: Sender<MainThreadScriptMsg>,
194 pub(crate) resource_threads: ResourceThreads,
196 pub(crate) storage_threads: StorageThreads,
198 pub(crate) mem_profiler_chan: mem::ProfilerChan,
200 pub(crate) time_profiler_chan: time::ProfilerChan,
202 pub(crate) devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
204 pub(crate) to_constellation_sender: GenericSender<(PipelineId, ScriptToConstellationMessage)>,
206 pub(crate) to_embedder_sender: ScriptToEmbedderChan,
208 pub(crate) image_cache: Arc<dyn ImageCache>,
210 #[cfg(feature = "webgpu")]
212 pub(crate) gpu_id_hub: Arc<IdentityHub>,
213 pub(crate) inherited_secure_context: Option<bool>,
215}
216
217#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
219pub(crate) enum WorkletGlobalScopeType {
220 #[cfg(feature = "testbinding")]
222 Test,
223 Paint,
225}
226
227pub(crate) enum WorkletTask {
229 #[cfg(feature = "testbinding")]
230 Test(TestWorkletTask),
231 Paint(PaintWorkletTask),
232}