1use std::sync::Arc;
6use std::sync::atomic::AtomicBool;
7use std::thread::{self, JoinHandle};
8
9use base::generic_channel::{GenericReceiver, RoutedReceiver};
10use base::id::{BrowsingContextId, PipelineId, ScriptEventLoopId, WebViewId};
11use constellation_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
12use crossbeam_channel::{Receiver, Sender, unbounded};
13use devtools_traits::DevtoolScriptControlMsg;
14use dom_struct::dom_struct;
15use fonts::FontContext;
16use js::jsapi::{Heap, JSContext, JSObject};
17use js::jsval::UndefinedValue;
18use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
19use net_traits::image_cache::ImageCache;
20use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer};
21use net_traits::request::{
22 CredentialsMode, Destination, InsecureRequestsPolicy, Origin, ParserMetadata,
23 PreloadedResources, Referrer, RequestBuilder, RequestClient, RequestMode,
24};
25use servo_url::{ImmutableOrigin, ServoUrl};
26use style::thread_state::{self, ThreadState};
27
28use crate::devtools;
29use crate::dom::abstractworker::{MessageData, SimpleWorkerErrorHandler, WorkerScriptMsg};
30use crate::dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
31use crate::dom::bindings::cell::DomRefCell;
32use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
33use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
34use crate::dom::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
35use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
36use crate::dom::bindings::error::{ErrorInfo, ErrorResult};
37use crate::dom::bindings::inheritance::Castable;
38use crate::dom::bindings::refcounted::Trusted;
39use crate::dom::bindings::reflector::DomGlobal;
40use crate::dom::bindings::root::DomRoot;
41use crate::dom::bindings::str::DOMString;
42use crate::dom::bindings::structuredclone;
43use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
44use crate::dom::csp::Violation;
45use crate::dom::errorevent::ErrorEvent;
46use crate::dom::event::{Event, EventBubbles, EventCancelable};
47use crate::dom::eventtarget::EventTarget;
48use crate::dom::globalscope::GlobalScope;
49use crate::dom::messageevent::MessageEvent;
50use crate::dom::types::DebuggerGlobalScope;
51#[cfg(feature = "webgpu")]
52use crate::dom::webgpu::identityhub::IdentityHub;
53use crate::dom::worker::{TrustedWorkerAddress, Worker};
54use crate::dom::workerglobalscope::{ScriptFetchContext, WorkerGlobalScope};
55use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
56use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
57use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
58use crate::script_runtime::{CanGc, JSContext as SafeJSContext, Runtime, ThreadSafeJSContext};
59use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
60use crate::task_source::{SendableTaskSource, TaskSourceName};
61
62pub(crate) struct AutoWorkerReset<'a> {
67 workerscope: &'a DedicatedWorkerGlobalScope,
68 old_worker: Option<TrustedWorkerAddress>,
69}
70
71impl<'a> AutoWorkerReset<'a> {
72 pub(crate) fn new(
73 workerscope: &'a DedicatedWorkerGlobalScope,
74 worker: TrustedWorkerAddress,
75 ) -> AutoWorkerReset<'a> {
76 let old_worker = workerscope.replace_worker(Some(worker));
77 AutoWorkerReset {
78 workerscope,
79 old_worker,
80 }
81 }
82}
83
84impl Drop for AutoWorkerReset<'_> {
85 fn drop(&mut self) {
86 self.workerscope
87 .replace_worker(std::mem::take(&mut self.old_worker));
88 }
89}
90
91pub(crate) enum DedicatedWorkerControlMsg {
93 Exit,
95}
96
97pub(crate) enum DedicatedWorkerScriptMsg {
98 CommonWorker(TrustedWorkerAddress, WorkerScriptMsg),
100 WakeUp,
102}
103
104pub(crate) enum MixedMessage {
105 Worker(DedicatedWorkerScriptMsg),
106 Devtools(DevtoolScriptControlMsg),
107 Control(DedicatedWorkerControlMsg),
108 Timer,
109}
110
111impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
112 fn task_source_name(&self) -> Option<&TaskSourceName> {
113 let common_worker_msg = match self {
114 DedicatedWorkerScriptMsg::CommonWorker(_, common_worker_msg) => common_worker_msg,
115 _ => return None,
116 };
117 let script_msg = match common_worker_msg {
118 WorkerScriptMsg::Common(script_msg) => script_msg,
119 _ => return None,
120 };
121 match script_msg {
122 CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => {
123 Some(source_name)
124 },
125 _ => None,
126 }
127 }
128
129 fn pipeline_id(&self) -> Option<PipelineId> {
130 None
133 }
134
135 fn into_queued_task(self) -> Option<QueuedTask> {
136 let (worker, common_worker_msg) = match self {
137 DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => {
138 (worker, common_worker_msg)
139 },
140 _ => return None,
141 };
142 let script_msg = match common_worker_msg {
143 WorkerScriptMsg::Common(script_msg) => script_msg,
144 _ => return None,
145 };
146 let (category, boxed, pipeline_id, task_source) = match script_msg {
147 CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
148 (category, boxed, pipeline_id, task_source)
149 },
150 _ => return None,
151 };
152 Some((Some(worker), category, boxed, pipeline_id, task_source))
153 }
154
155 fn from_queued_task(queued_task: QueuedTask) -> Self {
156 let (worker, category, boxed, pipeline_id, task_source) = queued_task;
157 let script_msg = CommonScriptMsg::Task(category, boxed, pipeline_id, task_source);
158 DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
159 }
160
161 fn inactive_msg() -> Self {
162 panic!("Workers should never receive messages marked as inactive");
164 }
165
166 fn wake_up_msg() -> Self {
167 DedicatedWorkerScriptMsg::WakeUp
168 }
169
170 fn is_wake_up(&self) -> bool {
171 matches!(self, DedicatedWorkerScriptMsg::WakeUp)
172 }
173}
174
175unsafe_no_jsmanaged_fields!(TaskQueue<DedicatedWorkerScriptMsg>);
176
177#[dom_struct]
179pub(crate) struct DedicatedWorkerGlobalScope {
180 workerglobalscope: WorkerGlobalScope,
181 #[no_trace]
183 webview_id: WebViewId,
184 #[ignore_malloc_size_of = "Defined in std"]
185 task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
186 own_sender: Sender<DedicatedWorkerScriptMsg>,
187 worker: DomRefCell<Option<TrustedWorkerAddress>>,
188 parent_event_loop_sender: ScriptEventLoopSender,
190 #[ignore_malloc_size_of = "ImageCache"]
191 #[no_trace]
192 image_cache: Arc<dyn ImageCache>,
193 #[no_trace]
194 browsing_context: Option<BrowsingContextId>,
195 #[ignore_malloc_size_of = "Channels are hard"]
198 #[no_trace]
199 control_receiver: Receiver<DedicatedWorkerControlMsg>,
200 #[no_trace]
201 queued_worker_tasks: DomRefCell<Vec<MessageData>>,
202}
203
204impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
205 type WorkerMsg = DedicatedWorkerScriptMsg;
206 type ControlMsg = DedicatedWorkerControlMsg;
207 type Event = MixedMessage;
208
209 fn task_queue(&self) -> &TaskQueue<DedicatedWorkerScriptMsg> {
210 &self.task_queue
211 }
212
213 fn handle_event(&self, event: MixedMessage, cx: &mut js::context::JSContext) -> bool {
214 self.handle_mixed_message(event, cx)
215 }
216
217 fn handle_worker_post_event(
218 &self,
219 worker: &TrustedWorkerAddress,
220 ) -> Option<AutoWorkerReset<'_>> {
221 let ar = AutoWorkerReset::new(self, worker.clone());
222 Some(ar)
223 }
224
225 fn from_control_msg(msg: DedicatedWorkerControlMsg) -> MixedMessage {
226 MixedMessage::Control(msg)
227 }
228
229 fn from_worker_msg(msg: DedicatedWorkerScriptMsg) -> MixedMessage {
230 MixedMessage::Worker(msg)
231 }
232
233 fn from_devtools_msg(msg: DevtoolScriptControlMsg) -> MixedMessage {
234 MixedMessage::Devtools(msg)
235 }
236
237 fn from_timer_msg() -> MixedMessage {
238 MixedMessage::Timer
239 }
240
241 fn control_receiver(&self) -> &Receiver<DedicatedWorkerControlMsg> {
242 &self.control_receiver
243 }
244}
245
246impl DedicatedWorkerGlobalScope {
247 #[allow(clippy::too_many_arguments)]
248 fn new_inherited(
249 init: WorkerGlobalScopeInit,
250 webview_id: WebViewId,
251 worker_name: DOMString,
252 worker_type: WorkerType,
253 worker_url: ServoUrl,
254 from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
255 runtime: Runtime,
256 parent_event_loop_sender: ScriptEventLoopSender,
257 own_sender: Sender<DedicatedWorkerScriptMsg>,
258 receiver: Receiver<DedicatedWorkerScriptMsg>,
259 closing: Arc<AtomicBool>,
260 image_cache: Arc<dyn ImageCache>,
261 browsing_context: Option<BrowsingContextId>,
262 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
263 control_receiver: Receiver<DedicatedWorkerControlMsg>,
264 insecure_requests_policy: InsecureRequestsPolicy,
265 font_context: Option<Arc<FontContext>>,
266 ) -> DedicatedWorkerGlobalScope {
267 DedicatedWorkerGlobalScope {
268 workerglobalscope: WorkerGlobalScope::new_inherited(
269 init,
270 worker_name,
271 worker_type,
272 worker_url,
273 runtime,
274 from_devtools_receiver,
275 closing,
276 #[cfg(feature = "webgpu")]
277 gpu_id_hub,
278 insecure_requests_policy,
279 font_context,
280 ),
281 webview_id,
282 task_queue: TaskQueue::new(receiver, own_sender.clone()),
283 own_sender,
284 parent_event_loop_sender,
285 worker: DomRefCell::new(None),
286 image_cache,
287 browsing_context,
288 control_receiver,
289 queued_worker_tasks: Default::default(),
290 }
291 }
292
293 #[expect(clippy::too_many_arguments)]
294 pub(crate) fn new(
295 init: WorkerGlobalScopeInit,
296 webview_id: WebViewId,
297 worker_name: DOMString,
298 worker_type: WorkerType,
299 worker_url: ServoUrl,
300 from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
301 runtime: Runtime,
302 parent_event_loop_sender: ScriptEventLoopSender,
303 own_sender: Sender<DedicatedWorkerScriptMsg>,
304 receiver: Receiver<DedicatedWorkerScriptMsg>,
305 closing: Arc<AtomicBool>,
306 image_cache: Arc<dyn ImageCache>,
307 browsing_context: Option<BrowsingContextId>,
308 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
309 control_receiver: Receiver<DedicatedWorkerControlMsg>,
310 insecure_requests_policy: InsecureRequestsPolicy,
311 font_context: Option<Arc<FontContext>>,
312 ) -> DomRoot<DedicatedWorkerGlobalScope> {
313 let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
314 init,
315 webview_id,
316 worker_name,
317 worker_type,
318 worker_url,
319 from_devtools_receiver,
320 runtime,
321 parent_event_loop_sender,
322 own_sender,
323 receiver,
324 closing,
325 image_cache,
326 browsing_context,
327 #[cfg(feature = "webgpu")]
328 gpu_id_hub,
329 control_receiver,
330 insecure_requests_policy,
331 font_context,
332 ));
333 DedicatedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(
334 GlobalScope::get_cx(),
335 scope,
336 )
337 }
338
339 #[expect(unsafe_code)]
341 #[allow(clippy::too_many_arguments)]
342 pub(crate) fn run_worker_scope(
343 mut init: WorkerGlobalScopeInit,
344 webview_id: WebViewId,
345 worker_url: ServoUrl,
346 from_devtools_receiver: GenericReceiver<DevtoolScriptControlMsg>,
347 worker: TrustedWorkerAddress,
348 parent_event_loop_sender: ScriptEventLoopSender,
349 own_sender: Sender<DedicatedWorkerScriptMsg>,
350 receiver: Receiver<DedicatedWorkerScriptMsg>,
351 worker_load_origin: WorkerScriptLoadOrigin,
352 worker_name: String,
353 worker_type: WorkerType,
354 closing: Arc<AtomicBool>,
355 image_cache: Arc<dyn ImageCache>,
356 browsing_context: Option<BrowsingContextId>,
357 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
358 control_receiver: Receiver<DedicatedWorkerControlMsg>,
359 context_sender: Sender<ThreadSafeJSContext>,
360 insecure_requests_policy: InsecureRequestsPolicy,
361 policy_container: PolicyContainer,
362 font_context: Option<Arc<FontContext>>,
363 ) -> JoinHandle<()> {
364 let event_loop_id = ScriptEventLoopId::installed()
365 .expect("Should always be in a ScriptThread or in a dedicated worker");
366 let current_global = GlobalScope::current().expect("No current global object");
367 let origin = current_global.origin().immutable().clone();
368 let referrer = current_global.get_referrer();
369 let parent = current_global.runtime_handle();
370 let current_global_https_state = current_global.get_https_state();
371 let current_global_ancestor_trustworthy = current_global.has_trustworthy_ancestor_origin();
372 let is_secure_context = current_global.is_secure_context();
373 let is_nested_browsing_context = current_global.is_nested_browsing_context();
374
375 thread::Builder::new()
376 .name(format!("WW:{}", worker_url.debug_compact()))
377 .spawn(move || {
378 thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
379 ScriptEventLoopId::install(event_loop_id);
380
381 let WorkerScriptLoadOrigin {
382 referrer_url,
383 referrer_policy,
384 pipeline_id,
385 } = worker_load_origin;
386
387 let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
388
389 let request_client = RequestClient {
390 preloaded_resources: PreloadedResources::default(),
391 policy_container: RequestPolicyContainer::PolicyContainer(
392 policy_container.clone(),
393 ),
394 origin: Origin::Origin(origin.clone()),
395 is_nested_browsing_context,
396 insecure_requests_policy,
397 };
398
399 let request = RequestBuilder::new(Some(webview_id), worker_url.clone(), referrer)
400 .destination(Destination::Worker)
401 .mode(RequestMode::SameOrigin)
402 .credentials_mode(CredentialsMode::CredentialsSameOrigin)
403 .parser_metadata(ParserMetadata::NotParserInserted)
404 .use_url_credentials(true)
405 .pipeline_id(Some(pipeline_id))
406 .referrer_policy(referrer_policy)
407 .insecure_requests_policy(insecure_requests_policy)
408 .has_trustworthy_ancestor_origin(current_global_ancestor_trustworthy)
409 .policy_container(policy_container.clone())
410 .origin(origin)
411 .client(request_client);
412
413 let event_loop_sender = ScriptEventLoopSender::DedicatedWorker {
414 sender: own_sender.clone(),
415 main_thread_worker: worker.clone(),
416 };
417
418 let runtime = unsafe {
419 Runtime::new_with_parent(Some(parent), Some(event_loop_sender.clone()))
420 };
421 let mut cx = unsafe { runtime.cx() };
425 let cx = &mut cx;
426 let debugger_global = DebuggerGlobalScope::new(
427 pipeline_id,
428 init.to_devtools_sender.clone(),
429 init.from_devtools_sender
430 .clone()
431 .expect("Guaranteed by Worker::Constructor"),
432 init.mem_profiler_chan.clone(),
433 init.time_profiler_chan.clone(),
434 init.script_to_constellation_chan.clone(),
435 init.script_to_embedder_chan.clone(),
436 init.resource_threads.clone(),
437 init.storage_threads.clone(),
438 #[cfg(feature = "webgpu")]
439 gpu_id_hub.clone(),
440 cx,
441 );
442 debugger_global.execute(CanGc::from_cx(cx));
443
444 let context_for_interrupt = runtime.thread_safe_js_context();
445 let _ = context_sender.send(context_for_interrupt);
446
447 let devtools_mpsc_port = from_devtools_receiver.route_preserving_errors();
448
449 if worker_url.scheme() == "data" {
457 if is_secure_context {
459 init.origin = ImmutableOrigin::new_opaque_data_url_worker();
460 } else {
461 init.origin = ImmutableOrigin::new_opaque();
462 }
463 }
464
465 let worker_id = init.worker_id;
466 let global = DedicatedWorkerGlobalScope::new(
467 init,
468 webview_id,
469 DOMString::from_string(worker_name),
470 worker_type,
471 worker_url,
472 devtools_mpsc_port,
473 runtime,
474 parent_event_loop_sender,
475 own_sender,
476 receiver,
477 closing,
478 image_cache,
479 browsing_context,
480 #[cfg(feature = "webgpu")]
481 gpu_id_hub,
482 control_receiver,
483 insecure_requests_policy,
484 font_context,
485 );
486 debugger_global.fire_add_debuggee(
487 CanGc::from_cx(cx),
488 global.upcast(),
489 pipeline_id,
490 Some(worker_id),
491 );
492 let scope = global.upcast::<WorkerGlobalScope>();
493 let global_scope = global.upcast::<GlobalScope>();
494
495 global_scope.set_https_state(current_global_https_state);
496 let request = request.https_state(global_scope.get_https_state());
497
498 let task_source = SendableTaskSource {
499 sender: event_loop_sender.clone(),
500 pipeline_id,
501 name: TaskSourceName::Networking,
502 canceller: Default::default(),
503 };
504 let context = ScriptFetchContext::new(
505 Trusted::new(scope),
506 request.url.clone(),
507 worker.clone(),
508 policy_container,
509 );
510 global_scope.fetch(request, context, task_source);
511
512 let reporter_name = format!("dedicated-worker-reporter-{}", worker_id);
513 scope
514 .upcast::<GlobalScope>()
515 .mem_profiler_chan()
516 .run_with_memory_reporting(
517 || {
518 while !scope.is_closing() {
524 run_worker_event_loop(&*global, Some(&worker), cx);
525 }
526 },
527 reporter_name,
528 event_loop_sender,
529 CommonScriptMsg::CollectReports,
530 );
531 scope.clear_js_runtime();
532 })
533 .expect("Thread spawning failed")
534 }
535
536 pub(crate) fn webview_id(&self) -> WebViewId {
537 self.webview_id
538 }
539
540 fn replace_worker(
545 &self,
546 new_worker: Option<TrustedWorkerAddress>,
547 ) -> Option<TrustedWorkerAddress> {
548 let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker);
549
550 self.upcast::<GlobalScope>()
556 .task_manager()
557 .set_sender(self.event_loop_sender());
558
559 old_worker
560 }
561
562 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
563 self.image_cache.clone()
564 }
565
566 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
567 Some(ScriptEventLoopSender::DedicatedWorker {
568 sender: self.own_sender.clone(),
569 main_thread_worker: self.worker.borrow().clone()?,
570 })
571 }
572
573 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
574 let (sender, receiver) = unbounded();
575 let main_thread_worker = self.worker.borrow().as_ref().unwrap().clone();
576 (
577 ScriptEventLoopSender::DedicatedWorker {
578 sender,
579 main_thread_worker,
580 },
581 ScriptEventLoopReceiver::DedicatedWorker(receiver),
582 )
583 }
584
585 pub(crate) fn fire_queued_messages(&self, can_gc: CanGc) {
586 let queue: Vec<_> = self.queued_worker_tasks.borrow_mut().drain(..).collect();
587 for msg in queue {
588 if self.upcast::<WorkerGlobalScope>().is_closing() {
589 return;
590 }
591 self.dispatch_message_event(msg, can_gc);
592 }
593 }
594
595 fn dispatch_message_event(&self, msg: MessageData, can_gc: CanGc) {
596 let scope = self.upcast::<WorkerGlobalScope>();
597 let target = self.upcast();
598 let _ac = enter_realm(self);
599 rooted!(in(*scope.get_cx()) let mut message = UndefinedValue());
600 if let Ok(ports) =
601 structuredclone::read(scope.upcast(), *msg.data, message.handle_mut(), can_gc)
602 {
603 MessageEvent::dispatch_jsval(
604 target,
605 scope.upcast(),
606 message.handle(),
607 Some(&msg.origin.ascii_serialization()),
608 None,
609 ports,
610 can_gc,
611 );
612 } else {
613 MessageEvent::dispatch_error(target, scope.upcast(), can_gc);
614 }
615 }
616
617 fn handle_script_event(&self, msg: WorkerScriptMsg, cx: &mut js::context::JSContext) {
618 match msg {
619 WorkerScriptMsg::DOMMessage(message_data) => {
620 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
621 self.dispatch_message_event(message_data, CanGc::from_cx(cx));
622 } else {
623 self.queued_worker_tasks.borrow_mut().push(message_data);
624 }
625 },
626 WorkerScriptMsg::Common(msg) => {
627 self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
628 },
629 }
630 }
631
632 fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut js::context::JSContext) -> bool {
633 if self.upcast::<WorkerGlobalScope>().is_closing() {
634 return false;
635 }
636 match msg {
638 MixedMessage::Devtools(msg) => match msg {
639 DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
640 devtools::handle_evaluate_js(self.upcast(), string, sender, CanGc::from_cx(cx))
641 },
642 DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
643 devtools::handle_wants_live_notifications(self.upcast(), bool_val)
644 },
645 _ => debug!("got an unusable devtools control message inside the worker!"),
646 },
647 MixedMessage::Worker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
648 let _ar = AutoWorkerReset::new(self, linked_worker);
649 self.handle_script_event(msg, cx);
650 },
651 MixedMessage::Worker(DedicatedWorkerScriptMsg::WakeUp) => {},
652 MixedMessage::Control(DedicatedWorkerControlMsg::Exit) => {
653 return false;
654 },
655 MixedMessage::Timer => {},
656 }
657 true
658 }
659
660 pub(crate) fn forward_error_to_worker_object(&self, error_info: ErrorInfo) {
662 let worker = self.worker.borrow().as_ref().unwrap().clone();
664 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
665 let task = Box::new(task!(forward_error_to_worker_object: move || {
666 let worker = worker.root();
667 let global = worker.global();
668
669 let event = ErrorEvent::new(
672 &global,
673 atom!("error"),
674 EventBubbles::DoesNotBubble,
675 EventCancelable::Cancelable,
676 error_info.message.as_str().into(),
677 error_info.filename.as_str().into(),
678 error_info.lineno,
679 error_info.column,
680 HandleValue::null(),
681 CanGc::note(),
682 );
683
684 if event.upcast::<Event>().fire(worker.upcast::<EventTarget>(), CanGc::note()) {
686 global.report_an_error(error_info, HandleValue::null(), CanGc::note());
687 }
688 }));
689 self.parent_event_loop_sender
690 .send(CommonScriptMsg::Task(
691 WorkerEvent,
692 task,
693 Some(pipeline_id),
694 TaskSourceName::DOMManipulation,
695 ))
696 .unwrap();
697 }
698
699 fn post_message_impl(
701 &self,
702 cx: SafeJSContext,
703 message: HandleValue,
704 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
705 ) -> ErrorResult {
706 let data = structuredclone::write(cx, message, Some(transfer))?;
707 let worker = self.worker.borrow().as_ref().unwrap().clone();
708 let global_scope = self.upcast::<GlobalScope>();
709 let pipeline_id = global_scope.pipeline_id();
710 let task = Box::new(task!(post_worker_message: move || {
711 Worker::handle_message(worker, data, CanGc::note());
712 }));
713 self.parent_event_loop_sender
714 .send(CommonScriptMsg::Task(
715 WorkerEvent,
716 task,
717 Some(pipeline_id),
718 TaskSourceName::DOMManipulation,
719 ))
720 .expect("Sending to parent failed");
721 Ok(())
722 }
723
724 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
725 self.browsing_context
726 }
727
728 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
729 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
730 self.parent_event_loop_sender
731 .send(CommonScriptMsg::ReportCspViolations(
732 pipeline_id,
733 violations,
734 ))
735 .expect("Sending to parent failed");
736 }
737
738 pub(crate) fn forward_simple_error_at_worker(&self, worker: TrustedWorkerAddress) {
739 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
740 self.parent_event_loop_sender
741 .send(CommonScriptMsg::Task(
742 WorkerEvent,
743 Box::new(SimpleWorkerErrorHandler::new(worker)),
744 Some(pipeline_id),
745 TaskSourceName::DOMManipulation,
746 ))
747 .expect("Sending to parent failed");
748 }
749}
750
751#[expect(unsafe_code)]
752pub(crate) unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
753 let in_realm_proof = AlreadyInRealm::assert_for_cx(unsafe { SafeJSContext::from_ptr(cx) });
754 let global = unsafe { GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)) };
755
756 let Some(worker) = global.downcast::<WorkerGlobalScope>() else {
758 assert!(global.is::<DebuggerGlobalScope>());
759 return false;
760 };
761
762 assert!(worker.is::<DedicatedWorkerGlobalScope>());
764 !worker.is_closing()
765}
766
767impl DedicatedWorkerGlobalScopeMethods<crate::DomTypeHolder> for DedicatedWorkerGlobalScope {
768 fn Name(&self) -> DOMString {
770 self.workerglobalscope.worker_name()
771 }
772
773 fn PostMessage(
775 &self,
776 cx: SafeJSContext,
777 message: HandleValue,
778 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
779 ) -> ErrorResult {
780 self.post_message_impl(cx, message, transfer)
781 }
782
783 fn PostMessage_(
785 &self,
786 cx: SafeJSContext,
787 message: HandleValue,
788 options: RootedTraceableBox<StructuredSerializeOptions>,
789 ) -> ErrorResult {
790 let mut rooted = CustomAutoRooter::new(
791 options
792 .transfer
793 .iter()
794 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
795 .collect(),
796 );
797 let guard = CustomAutoRooterGuard::new(*cx, &mut rooted);
798 self.post_message_impl(cx, message, guard)
799 }
800
801 fn Close(&self) {
803 self.upcast::<WorkerGlobalScope>().close();
805 }
806
807 event_handler!(message, GetOnmessage, SetOnmessage);
809
810 event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
812}