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 #[no_trace]
57 origin: MutableOrigin,
58}
59
60impl WorkletGlobalScope {
61 pub(crate) fn new(
63 scope_type: WorkletGlobalScopeType,
64 pipeline_id: PipelineId,
65 base_url: ServoUrl,
66 inherited_secure_context: Option<bool>,
67 executor: WorkletExecutor,
68 init: &WorkletGlobalScopeInit,
69 cx: &mut JSContext,
70 ) -> DomRoot<WorkletGlobalScope> {
71 let scope: DomRoot<WorkletGlobalScope> = match scope_type {
72 #[cfg(feature = "testbinding")]
73 WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
74 pipeline_id,
75 base_url,
76 inherited_secure_context,
77 executor,
78 init,
79 cx,
80 )),
81 WorkletGlobalScopeType::Paint => DomRoot::upcast(PaintWorkletGlobalScope::new(
82 pipeline_id,
83 base_url,
84 inherited_secure_context,
85 executor,
86 init,
87 cx,
88 )),
89 };
90
91 let mut realm = enter_auto_realm(cx, &*scope);
92 let mut realm = realm.current_realm();
93 define_all_exposed_interfaces(&mut realm, scope.upcast());
94
95 scope
96 }
97
98 pub(crate) fn new_inherited(
100 pipeline_id: PipelineId,
101 base_url: ServoUrl,
102 inherited_secure_context: Option<bool>,
103 executor: WorkletExecutor,
104 init: &WorkletGlobalScopeInit,
105 ) -> Self {
106 Self {
107 globalscope: GlobalScope::new_inherited(
108 init.devtools_chan.clone(),
109 init.mem_profiler_chan.clone(),
110 init.time_profiler_chan.clone(),
111 init.script_to_constellation_sender.clone(),
112 init.to_embedder_sender.clone(),
113 init.resource_threads.clone(),
114 init.storage_threads.clone(),
115 base_url.clone(),
116 None,
117 #[cfg(feature = "webgpu")]
118 init.gpu_id_hub.clone(),
119 inherited_secure_context,
120 false,
121 None, ),
123 base_url,
124 to_script_thread_sender: init.to_script_thread_sender.clone(),
125 executor,
126 pipeline_id,
127 origin: MutableOrigin::new(ImmutableOrigin::new_opaque()),
128 }
129 }
130
131 pub(crate) fn origin(&self) -> MutableOrigin {
132 self.origin.clone()
133 }
134
135 pub(crate) fn pipeline_id(&self) -> PipelineId {
136 self.pipeline_id
137 }
138
139 pub(crate) fn evaluate_js(
141 &self,
142 script: Cow<'_, str>,
143 cx: &mut JSContext,
144 ) -> Result<(), JavaScriptEvaluationError> {
145 let mut realm = enter_auto_realm(cx, self);
146 let cx = &mut realm.current_realm();
147
148 debug!("Evaluating Dom in a worklet.");
149 self.globalscope.evaluate_js_on_global(
150 cx,
151 script,
152 "",
153 Some(IntroductionType::WORKLET),
154 None,
155 )
156 }
157
158 pub(crate) fn register_paint_worklet(
160 &self,
161 name: Atom,
162 properties: Vec<Atom>,
163 painter: Box<dyn Painter>,
164 ) {
165 self.to_script_thread_sender
166 .send(MainThreadScriptMsg::RegisterPaintWorklet {
167 pipeline_id: self.globalscope.pipeline_id(),
168 name,
169 properties,
170 painter,
171 })
172 .expect("Worklet thread outlived script thread.");
173 }
174
175 pub(crate) fn base_url(&self) -> ServoUrl {
177 self.base_url.clone()
178 }
179
180 pub(crate) fn executor(&self) -> WorkletExecutor {
182 self.executor.clone()
183 }
184
185 pub(crate) fn perform_a_worklet_task(&self, cx: &mut JSContext, task: WorkletTask) {
187 match task {
188 #[cfg(feature = "testbinding")]
189 WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
190 Some(global) => global.perform_a_worklet_task(task),
191 None => warn!("This is not a test worklet."),
192 },
193 WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
194 Some(global) => global.perform_a_worklet_task(cx, task),
195 None => warn!("This is not a paint worklet."),
196 },
197 }
198 }
199}
200
201#[derive(Clone)]
203pub(crate) struct WorkletGlobalScopeInit {
204 pub(crate) to_script_thread_sender: Sender<MainThreadScriptMsg>,
206 pub(crate) resource_threads: ResourceThreads,
208 pub(crate) storage_threads: StorageThreads,
210 pub(crate) mem_profiler_chan: mem::ProfilerChan,
212 pub(crate) time_profiler_chan: time::ProfilerChan,
214 pub(crate) devtools_chan: Option<GenericCallback<ScriptToDevtoolsControlMsg>>,
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 pub(crate) script_to_constellation_sender: ScriptToConstellationSender,
224}
225
226#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
228pub(crate) enum WorkletGlobalScopeType {
229 #[cfg(feature = "testbinding")]
231 Test,
232 Paint,
234}
235
236pub(crate) enum WorkletTask {
238 #[cfg(feature = "testbinding")]
239 Test(TestWorkletTask),
240 Paint(PaintWorkletTask),
241}