1use std::borrow::Cow;
6use std::cell::{Cell, OnceCell, Ref};
7use std::collections::hash_map::Entry;
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::ffi::CStr;
10use std::ops::Index;
11use std::rc::Rc;
12use std::sync::Arc;
13use std::sync::atomic::{AtomicBool, Ordering};
14use std::thread::JoinHandle;
15use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
16use std::{mem, ptr};
17
18use base::IpcSend;
19use base::id::{
20 BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId,
21 ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId,
22};
23use constellation_traits::{
24 BlobData, BlobImpl, BroadcastChannelMsg, FileBlob, MessagePortImpl, MessagePortMsg,
25 PortMessageTask, ScriptToConstellationChan, ScriptToConstellationMessage,
26};
27use content_security_policy::CspList;
28use content_security_policy::sandboxing_directive::SandboxingFlagSet;
29use crossbeam_channel::Sender;
30use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
31use dom_struct::dom_struct;
32use embedder_traits::{EmbedderMsg, JavaScriptEvaluationError, ScriptToEmbedderChan};
33use fonts::FontContext;
34use indexmap::IndexSet;
35use ipc_channel::ipc::{self, IpcSender};
36use ipc_channel::router::ROUTER;
37use js::glue::{IsWrapper, UnwrapObjectDynamic};
38use js::jsapi::{
39 Compile1, CurrentGlobalOrNull, DelazificationOption, GetNonCCWObjectGlobal, HandleObject, Heap,
40 InstantiateGlobalStencil, InstantiateOptions, JSContext, JSObject, JSScript, SetScriptPrivate,
41};
42use js::jsval::{PrivateValue, UndefinedValue};
43use js::panic::maybe_resume_unwind;
44use js::realm::CurrentRealm;
45use js::rust::wrappers::{JS_ExecuteScript, JS_GetScriptPrivate};
46use js::rust::{
47 CompileOptionsWrapper, CustomAutoRooter, CustomAutoRooterGuard, HandleValue,
48 MutableHandleValue, ParentRuntime, Runtime, get_object_class, transform_str_to_source_text,
49};
50use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
51use net_traits::blob_url_store::{BlobBuf, get_blob_origin};
52use net_traits::filemanager_thread::{
53 FileManagerResult, FileManagerThreadMsg, ReadFileProgress, RelativePos,
54};
55use net_traits::image_cache::ImageCache;
56use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer};
57use net_traits::request::{
58 InsecureRequestsPolicy, Origin as RequestOrigin, Referrer, RequestBuilder, RequestClient,
59};
60use net_traits::response::HttpsState;
61use net_traits::{
62 CoreResourceMsg, CoreResourceThread, ReferrerPolicy, ResourceThreads, fetch_async,
63};
64use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time};
65use rustc_hash::{FxBuildHasher, FxHashMap};
66use script_bindings::interfaces::GlobalScopeHelpers;
67use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
68use storage_traits::StorageThreads;
69use strum::VariantArray;
70use timers::{TimerEventRequest, TimerId};
71use uuid::Uuid;
72#[cfg(feature = "webgpu")]
73use webgpu_traits::{DeviceLostReason, WebGPUDevice};
74
75use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
76#[cfg(feature = "webgpu")]
77use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
78use super::bindings::error::Fallible;
79use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox};
80use super::serviceworkerglobalscope::ServiceWorkerGlobalScope;
81use super::transformstream::CrossRealmTransform;
82use crate::dom::bindings::cell::{DomRefCell, RefMut};
83use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
84use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods;
85use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
86use crate::dom::bindings::codegen::Bindings::NotificationBinding::NotificationPermissionCallback;
87use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
88 PermissionName, PermissionState,
89};
90use crate::dom::bindings::codegen::Bindings::ReportingObserverBinding::Report;
91use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
92use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
93use crate::dom::bindings::conversions::{root_from_object, root_from_object_static};
94use crate::dom::bindings::error::{
95 Error, ErrorInfo, report_pending_exception, take_and_report_pending_exception_for_api,
96};
97use crate::dom::bindings::frozenarray::CachedFrozenArray;
98use crate::dom::bindings::inheritance::Castable;
99use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
100use crate::dom::bindings::reflector::{DomGlobal, DomObject};
101use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
102use crate::dom::bindings::settings_stack::{AutoEntryScript, entry_global, incumbent_global};
103use crate::dom::bindings::str::DOMString;
104use crate::dom::bindings::structuredclone;
105use crate::dom::bindings::trace::CustomTraceable;
106use crate::dom::bindings::weakref::{DOMTracker, WeakRef};
107use crate::dom::blob::Blob;
108use crate::dom::broadcastchannel::BroadcastChannel;
109use crate::dom::crypto::Crypto;
110use crate::dom::dedicatedworkerglobalscope::{
111 DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
112};
113use crate::dom::errorevent::ErrorEvent;
114use crate::dom::event::{Event, EventBubbles, EventCancelable};
115use crate::dom::eventsource::EventSource;
116use crate::dom::eventtarget::EventTarget;
117use crate::dom::file::File;
118use crate::dom::html::htmlscriptelement::{ScriptId, SourceCode};
119use crate::dom::htmlscriptelement::ScriptOrigin;
120use crate::dom::messageport::MessagePort;
121use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
122use crate::dom::performance::performance::Performance;
123use crate::dom::performance::performanceentry::EntryType;
124use crate::dom::promise::Promise;
125use crate::dom::readablestream::{CrossRealmTransformReadable, ReadableStream};
126use crate::dom::reportingobserver::ReportingObserver;
127use crate::dom::serviceworker::ServiceWorker;
128use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
129use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
130use crate::dom::types::{AbortSignal, CookieStore, DebuggerGlobalScope, MessageEvent};
131use crate::dom::underlyingsourcecontainer::UnderlyingSourceType;
132#[cfg(feature = "webgpu")]
133use crate::dom::webgpu::gpudevice::GPUDevice;
134#[cfg(feature = "webgpu")]
135use crate::dom::webgpu::identityhub::IdentityHub;
136use crate::dom::window::Window;
137use crate::dom::workerglobalscope::WorkerGlobalScope;
138use crate::dom::workletglobalscope::WorkletGlobalScope;
139use crate::dom::writablestream::CrossRealmTransformWritable;
140use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
141use crate::microtask::Microtask;
142use crate::network_listener::{FetchResponseListener, NetworkListener};
143use crate::realms::{InRealm, enter_realm};
144use crate::script_module::{
145 DynamicModuleList, ImportMap, ModuleScript, ModuleTree, ResolvedModule, ScriptFetchOptions,
146};
147use crate::script_runtime::{CanGc, JSContext as SafeJSContext, ThreadSafeJSContext};
148use crate::script_thread::{ScriptThread, with_script_thread};
149use crate::task_manager::TaskManager;
150use crate::task_source::SendableTaskSource;
151use crate::timers::{
152 IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback,
153 TimerEventId, TimerSource,
154};
155use crate::unminify::unminified_path;
156
157#[derive(JSTraceable, MallocSizeOf)]
158pub(crate) struct AutoCloseWorker {
159 #[conditional_malloc_size_of]
161 closing: Arc<AtomicBool>,
162 #[ignore_malloc_size_of = "JoinHandle"]
164 join_handle: Option<JoinHandle<()>>,
165 #[no_trace]
168 control_sender: Sender<DedicatedWorkerControlMsg>,
169 #[ignore_malloc_size_of = "mozjs"]
171 #[no_trace]
172 context: ThreadSafeJSContext,
173}
174
175impl Drop for AutoCloseWorker {
176 fn drop(&mut self) {
178 self.closing.store(true, Ordering::SeqCst);
180
181 if self
182 .control_sender
183 .send(DedicatedWorkerControlMsg::Exit)
184 .is_err()
185 {
186 warn!("Couldn't send an exit message to a dedicated worker.");
187 }
188
189 self.context.request_interrupt_callback();
190
191 if self
194 .join_handle
195 .take()
196 .expect("No handle to join on worker.")
197 .join()
198 .is_err()
199 {
200 warn!("Failed to join on dedicated worker thread.");
201 }
202 }
203}
204
205#[dom_struct]
206pub(crate) struct GlobalScope {
207 eventtarget: EventTarget,
208 crypto: MutNullableDom<Crypto>,
209
210 task_manager: OnceCell<TaskManager>,
212
213 message_port_state: DomRefCell<MessagePortState>,
215
216 broadcast_channel_state: DomRefCell<BroadcastChannelState>,
218
219 blob_state: DomRefCell<HashMapTracedValues<BlobId, BlobInfo, FxBuildHasher>>,
221
222 registration_map: DomRefCell<
224 HashMapTracedValues<
225 ServiceWorkerRegistrationId,
226 Dom<ServiceWorkerRegistration>,
227 FxBuildHasher,
228 >,
229 >,
230
231 cookie_store: MutNullableDom<CookieStore>,
233
234 worker_map: DomRefCell<HashMapTracedValues<ServiceWorkerId, Dom<ServiceWorker>, FxBuildHasher>>,
236
237 #[no_trace]
239 pipeline_id: PipelineId,
240
241 devtools_wants_updates: Cell<bool>,
244
245 console_timers: DomRefCell<HashMap<DOMString, Instant>>,
247
248 #[ignore_malloc_size_of = "mozjs"]
251 module_map: DomRefCell<HashMapTracedValues<ServoUrl, Rc<ModuleTree>>>,
252
253 #[ignore_malloc_size_of = "mozjs"]
254 inline_module_map: DomRefCell<FxHashMap<ScriptId, Rc<ModuleTree>>>,
255
256 #[no_trace]
258 devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
259
260 #[ignore_malloc_size_of = "channels are hard"]
262 #[no_trace]
263 mem_profiler_chan: profile_mem::ProfilerChan,
264
265 #[ignore_malloc_size_of = "channels are hard"]
267 #[no_trace]
268 time_profiler_chan: profile_time::ProfilerChan,
269
270 #[ignore_malloc_size_of = "channels are hard"]
272 #[no_trace]
273 script_to_constellation_chan: ScriptToConstellationChan,
274
275 #[ignore_malloc_size_of = "channels are hard"]
277 #[no_trace]
278 script_to_embedder_chan: ScriptToEmbedderChan,
279
280 in_error_reporting_mode: Cell<bool>,
282
283 #[no_trace]
286 resource_threads: ResourceThreads,
287
288 #[no_trace]
291 storage_threads: StorageThreads,
292
293 timers: OnceCell<OneshotTimers>,
296
297 #[no_trace]
299 origin: MutableOrigin,
300
301 #[no_trace]
303 creation_url: ServoUrl,
304
305 #[no_trace]
307 top_level_creation_url: Option<ServoUrl>,
308
309 permission_state_invocation_results: DomRefCell<HashMap<PermissionName, PermissionState>>,
311
312 list_auto_close_worker: DomRefCell<Vec<AutoCloseWorker>>,
314
315 event_source_tracker: DOMTracker<EventSource>,
317
318 abort_signal_dependents: DomRefCell<IndexSet<Dom<AbortSignal>>>,
321
322 #[ignore_malloc_size_of = "mozjs"]
331 #[allow(clippy::vec_box)]
334 uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
335
336 #[ignore_malloc_size_of = "mozjs"]
342 #[allow(clippy::vec_box)]
345 consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
346
347 #[ignore_malloc_size_of = "defined in wgpu"]
349 #[no_trace]
350 #[cfg(feature = "webgpu")]
351 gpu_id_hub: Arc<IdentityHub>,
352
353 #[cfg(feature = "webgpu")]
355 gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>, FxBuildHasher>>,
356
357 #[ignore_malloc_size_of = "mozjs"]
359 frozen_supported_performance_entry_types: CachedFrozenArray,
360
361 #[no_trace]
363 https_state: Cell<HttpsState>,
364
365 console_group_stack: DomRefCell<Vec<DOMString>>,
367
368 console_count_map: DomRefCell<HashMap<DOMString, usize>>,
372
373 dynamic_modules: DomRefCell<DynamicModuleList>,
375
376 inherited_secure_context: Option<bool>,
378
379 unminified_js_dir: Option<String>,
382
383 #[ignore_malloc_size_of = "callbacks are hard"]
388 byte_length_queuing_strategy_size_function: OnceCell<Rc<Function>>,
389
390 #[ignore_malloc_size_of = "callbacks are hard"]
395 count_queuing_strategy_size_function: OnceCell<Rc<Function>>,
396
397 #[ignore_malloc_size_of = "callbacks are hard"]
398 notification_permission_request_callback_map:
399 DomRefCell<HashMap<String, Rc<NotificationPermissionCallback>>>,
400
401 import_map: DomRefCell<ImportMap>,
406
407 resolved_module_set: DomRefCell<HashSet<ResolvedModule>>,
409
410 #[conditional_malloc_size_of]
414 #[no_trace]
415 font_context: Option<Arc<FontContext>>,
416}
417
418struct MessageListener {
420 task_source: SendableTaskSource,
421 context: Trusted<GlobalScope>,
422}
423
424struct BroadcastListener {
426 task_source: SendableTaskSource,
427 context: Trusted<GlobalScope>,
428}
429
430type FileListenerCallback = Box<dyn Fn(Rc<Promise>, Fallible<Vec<u8>>) + Send>;
431
432struct FileListener {
434 state: Option<FileListenerState>,
438 task_source: SendableTaskSource,
439}
440
441enum FileListenerTarget {
442 Promise(TrustedPromise, FileListenerCallback),
443 Stream(Trusted<ReadableStream>),
444}
445
446enum FileListenerState {
447 Empty(FileListenerTarget),
448 Receiving(Vec<u8>, FileListenerTarget),
449}
450
451#[derive(JSTraceable, MallocSizeOf)]
452pub(crate) enum BlobTracker {
454 File(WeakRef<File>),
456 Blob(WeakRef<Blob>),
458}
459
460#[derive(JSTraceable, MallocSizeOf)]
461pub(crate) struct BlobInfo {
463 tracker: BlobTracker,
465 #[no_trace]
467 blob_impl: BlobImpl,
468 has_url: bool,
471}
472
473enum BlobResult {
477 Bytes(Vec<u8>),
478 File(Uuid, usize),
479}
480
481#[derive(JSTraceable, MallocSizeOf)]
483#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
484pub(crate) struct ManagedMessagePort {
485 dom_port: Dom<MessagePort>,
487 #[no_trace]
492 port_impl: Option<MessagePortImpl>,
493 pending: bool,
497 explicitly_closed: bool,
500 cross_realm_transform: Option<CrossRealmTransform>,
503}
504
505#[derive(JSTraceable, MallocSizeOf)]
507#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
508pub(crate) enum BroadcastChannelState {
509 Managed(
514 #[no_trace] BroadcastChannelRouterId,
515 HashMap<DOMString, VecDeque<Dom<BroadcastChannel>>>,
517 ),
518 UnManaged,
520}
521
522#[derive(JSTraceable, MallocSizeOf)]
524#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
525pub(crate) enum MessagePortState {
526 Managed(
528 #[no_trace] MessagePortRouterId,
529 HashMapTracedValues<MessagePortId, ManagedMessagePort, FxBuildHasher>,
530 ),
531 UnManaged,
533}
534
535impl BroadcastListener {
536 fn handle(&self, event: BroadcastChannelMsg) {
539 let context = self.context.clone();
540
541 self.task_source
547 .queue(task!(broadcast_message_event: move || {
548 let global = context.root();
549 global.broadcast_message_event(event, None);
552 }));
553 }
554}
555
556impl MessageListener {
557 fn notify(&self, msg: MessagePortMsg) {
561 match msg {
562 MessagePortMsg::CompleteTransfer(ports) => {
563 let context = self.context.clone();
564 self.task_source.queue(
565 task!(process_complete_transfer: move || {
566 let global = context.root();
567
568 let router_id = match global.port_router_id() {
569 Some(router_id) => router_id,
570 None => {
571 let _ = global.script_to_constellation_chan().send(
574 ScriptToConstellationMessage::MessagePortTransferResult(None, vec![], ports),
575 );
576 return;
577 }
578 };
579
580 let mut succeeded = vec![];
581 let mut failed = FxHashMap::default();
582
583 for (id, info) in ports.into_iter() {
584 if global.is_managing_port(&id) {
585 succeeded.push(id);
586 global.complete_port_transfer(
587 id,
588 info.port_message_queue,
589 info.disentangled,
590 CanGc::note()
591 );
592 } else {
593 failed.insert(id, info);
594 }
595 }
596 let _ = global.script_to_constellation_chan().send(
597 ScriptToConstellationMessage::MessagePortTransferResult(Some(router_id), succeeded, failed),
598 );
599 })
600 );
601 },
602 MessagePortMsg::CompletePendingTransfer(port_id, info) => {
603 let context = self.context.clone();
604 self.task_source.queue(task!(complete_pending: move || {
605 let global = context.root();
606 global.complete_port_transfer(port_id, info.port_message_queue, info.disentangled, CanGc::note());
607 }));
608 },
609 MessagePortMsg::CompleteDisentanglement(port_id) => {
610 let context = self.context.clone();
611 self.task_source
612 .queue(task!(try_complete_disentanglement: move || {
613 let global = context.root();
614 global.try_complete_disentanglement(port_id, CanGc::note());
615 }));
616 },
617 MessagePortMsg::NewTask(port_id, task) => {
618 let context = self.context.clone();
619 self.task_source.queue(task!(process_new_task: move || {
620 let global = context.root();
621 global.route_task_to_port(port_id, task, CanGc::note());
622 }));
623 },
624 }
625 }
626}
627
628fn stream_handle_incoming(stream: &ReadableStream, bytes: Fallible<Vec<u8>>, can_gc: CanGc) {
630 match bytes {
631 Ok(b) => {
632 stream.enqueue_native(b, can_gc);
633 },
634 Err(e) => {
635 stream.error_native(e, can_gc);
636 },
637 }
638}
639
640fn stream_handle_eof(stream: &ReadableStream, can_gc: CanGc) {
642 stream.controller_close_native(can_gc);
643}
644
645impl FileListener {
646 fn handle(&mut self, msg: FileManagerResult<ReadFileProgress>) {
647 match msg {
648 Ok(ReadFileProgress::Meta(blob_buf)) => match self.state.take() {
649 Some(FileListenerState::Empty(target)) => {
650 let bytes = if let FileListenerTarget::Stream(ref trusted_stream) = target {
651 let trusted = trusted_stream.clone();
652
653 let task = task!(enqueue_stream_chunk: move || {
654 let stream = trusted.root();
655 stream_handle_incoming(&stream, Ok(blob_buf.bytes), CanGc::note());
656 });
657 self.task_source.queue(task);
658
659 Vec::with_capacity(0)
660 } else {
661 blob_buf.bytes
662 };
663
664 self.state = Some(FileListenerState::Receiving(bytes, target));
665 },
666 _ => panic!(
667 "Unexpected FileListenerState when receiving ReadFileProgress::Meta msg."
668 ),
669 },
670 Ok(ReadFileProgress::Partial(mut bytes_in)) => match self.state.take() {
671 Some(FileListenerState::Receiving(mut bytes, target)) => {
672 if let FileListenerTarget::Stream(ref trusted_stream) = target {
673 let trusted = trusted_stream.clone();
674
675 let task = task!(enqueue_stream_chunk: move || {
676 let stream = trusted.root();
677 stream_handle_incoming(&stream, Ok(bytes_in), CanGc::note());
678 });
679
680 self.task_source.queue(task);
681 } else {
682 bytes.append(&mut bytes_in);
683 };
684
685 self.state = Some(FileListenerState::Receiving(bytes, target));
686 },
687 _ => panic!(
688 "Unexpected FileListenerState when receiving ReadFileProgress::Partial msg."
689 ),
690 },
691 Ok(ReadFileProgress::EOF) => match self.state.take() {
692 Some(FileListenerState::Receiving(bytes, target)) => match target {
693 FileListenerTarget::Promise(trusted_promise, callback) => {
694 let task = task!(resolve_promise: move || {
695 let promise = trusted_promise.root();
696 let _ac = enter_realm(&*promise.global());
697 callback(promise, Ok(bytes));
698 });
699
700 self.task_source.queue(task);
701 },
702 FileListenerTarget::Stream(trusted_stream) => {
703 let trusted = trusted_stream.clone();
704
705 let task = task!(enqueue_stream_chunk: move || {
706 let stream = trusted.root();
707 stream_handle_eof(&stream, CanGc::note());
708 });
709
710 self.task_source.queue(task);
711 },
712 },
713 _ => {
714 panic!("Unexpected FileListenerState when receiving ReadFileProgress::EOF msg.")
715 },
716 },
717 Err(_) => match self.state.take() {
718 Some(FileListenerState::Receiving(_, target)) |
719 Some(FileListenerState::Empty(target)) => {
720 let error = Err(Error::Network(None));
721
722 match target {
723 FileListenerTarget::Promise(trusted_promise, callback) => {
724 self.task_source.queue(task!(reject_promise: move || {
725 let promise = trusted_promise.root();
726 let _ac = enter_realm(&*promise.global());
727 callback(promise, error);
728 }));
729 },
730 FileListenerTarget::Stream(trusted_stream) => {
731 self.task_source.queue(task!(error_stream: move || {
732 let stream = trusted_stream.root();
733 stream_handle_incoming(&stream, error, CanGc::note());
734 }));
735 },
736 }
737 },
738 _ => panic!("Unexpected FileListenerState when receiving Err msg."),
739 },
740 }
741 }
742}
743
744impl GlobalScope {
745 pub(crate) fn webview_id(&self) -> Option<WebViewId> {
749 if let Some(window) = self.downcast::<Window>() {
750 return Some(window.webview_id());
751 }
752 self.downcast::<DedicatedWorkerGlobalScope>()
756 .map(DedicatedWorkerGlobalScope::webview_id)
757 }
758
759 #[allow(clippy::too_many_arguments)]
760 pub(crate) fn new_inherited(
761 pipeline_id: PipelineId,
762 devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
763 mem_profiler_chan: profile_mem::ProfilerChan,
764 time_profiler_chan: profile_time::ProfilerChan,
765 script_to_constellation_chan: ScriptToConstellationChan,
766 script_to_embedder_chan: ScriptToEmbedderChan,
767 resource_threads: ResourceThreads,
768 storage_threads: StorageThreads,
769 origin: MutableOrigin,
770 creation_url: ServoUrl,
771 top_level_creation_url: Option<ServoUrl>,
772 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
773 inherited_secure_context: Option<bool>,
774 unminify_js: bool,
775 font_context: Option<Arc<FontContext>>,
776 ) -> Self {
777 Self {
778 task_manager: Default::default(),
779 message_port_state: DomRefCell::new(MessagePortState::UnManaged),
780 broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged),
781 blob_state: Default::default(),
782 eventtarget: EventTarget::new_inherited(),
783 crypto: Default::default(),
784 registration_map: DomRefCell::new(HashMapTracedValues::new_fx()),
785 cookie_store: Default::default(),
786 worker_map: DomRefCell::new(HashMapTracedValues::new_fx()),
787 pipeline_id,
788 devtools_wants_updates: Default::default(),
789 console_timers: DomRefCell::new(Default::default()),
790 module_map: DomRefCell::new(Default::default()),
791 inline_module_map: DomRefCell::new(Default::default()),
792 devtools_chan,
793 mem_profiler_chan,
794 time_profiler_chan,
795 script_to_constellation_chan,
796 script_to_embedder_chan,
797 in_error_reporting_mode: Default::default(),
798 resource_threads,
799 storage_threads,
800 timers: OnceCell::default(),
801 origin,
802 creation_url,
803 top_level_creation_url,
804 permission_state_invocation_results: Default::default(),
805 list_auto_close_worker: Default::default(),
806 event_source_tracker: DOMTracker::new(),
807 abort_signal_dependents: Default::default(),
808 uncaught_rejections: Default::default(),
809 consumed_rejections: Default::default(),
810 #[cfg(feature = "webgpu")]
811 gpu_id_hub,
812 #[cfg(feature = "webgpu")]
813 gpu_devices: DomRefCell::new(HashMapTracedValues::new_fx()),
814 frozen_supported_performance_entry_types: CachedFrozenArray::new(),
815 https_state: Cell::new(HttpsState::None),
816 console_group_stack: DomRefCell::new(Vec::new()),
817 console_count_map: Default::default(),
818 dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
819 inherited_secure_context,
820 unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
821 byte_length_queuing_strategy_size_function: OnceCell::new(),
822 count_queuing_strategy_size_function: OnceCell::new(),
823 notification_permission_request_callback_map: Default::default(),
824 import_map: Default::default(),
825 resolved_module_set: Default::default(),
826 font_context,
827 }
828 }
829
830 fn port_router_id(&self) -> Option<MessagePortRouterId> {
832 if let MessagePortState::Managed(id, _message_ports) = &*self.message_port_state.borrow() {
833 Some(*id)
834 } else {
835 None
836 }
837 }
838
839 fn is_managing_port(&self, port_id: &MessagePortId) -> bool {
841 if let MessagePortState::Managed(_router_id, message_ports) =
842 &*self.message_port_state.borrow()
843 {
844 return message_ports.contains_key(port_id);
845 }
846 false
847 }
848
849 fn timers(&self) -> &OneshotTimers {
850 self.timers.get_or_init(|| OneshotTimers::new(self))
851 }
852
853 pub(crate) fn font_context(&self) -> Option<&Arc<FontContext>> {
854 self.font_context.as_ref()
855 }
856
857 #[allow(clippy::too_many_arguments)]
859 pub(crate) fn get_serviceworker_registration(
860 &self,
861 script_url: &ServoUrl,
862 scope: &ServoUrl,
863 registration_id: ServiceWorkerRegistrationId,
864 installing_worker: Option<ServiceWorkerId>,
865 _waiting_worker: Option<ServiceWorkerId>,
866 _active_worker: Option<ServiceWorkerId>,
867 can_gc: CanGc,
868 ) -> DomRoot<ServiceWorkerRegistration> {
869 let mut registrations = self.registration_map.borrow_mut();
871
872 if let Some(registration) = registrations.get(®istration_id) {
873 return DomRoot::from_ref(&**registration);
875 }
876
877 let new_registration =
879 ServiceWorkerRegistration::new(self, scope.clone(), registration_id, can_gc);
880
881 if let Some(worker_id) = installing_worker {
883 let worker = self.get_serviceworker(script_url, scope, worker_id, can_gc);
884 new_registration.set_installing(&worker);
885 }
886
887 registrations.insert(registration_id, Dom::from_ref(&*new_registration));
893
894 new_registration
896 }
897
898 pub(crate) fn get_serviceworker(
900 &self,
901 script_url: &ServoUrl,
902 scope: &ServoUrl,
903 worker_id: ServiceWorkerId,
904 can_gc: CanGc,
905 ) -> DomRoot<ServiceWorker> {
906 let mut workers = self.worker_map.borrow_mut();
908
909 if let Some(worker) = workers.get(&worker_id) {
910 DomRoot::from_ref(&**worker)
912 } else {
913 let new_worker =
916 ServiceWorker::new(self, script_url.clone(), scope.clone(), worker_id, can_gc);
917
918 workers.insert(worker_id, Dom::from_ref(&*new_worker));
920
921 new_worker
923 }
924 }
925
926 fn complete_port_transfer(
928 &self,
929 port_id: MessagePortId,
930 tasks: VecDeque<PortMessageTask>,
931 disentangled: bool,
932 can_gc: CanGc,
933 ) {
934 let should_start = if let MessagePortState::Managed(_id, message_ports) =
935 &mut *self.message_port_state.borrow_mut()
936 {
937 match message_ports.get_mut(&port_id) {
938 None => {
939 panic!("complete_port_transfer called for an unknown port.");
940 },
941 Some(managed_port) => {
942 if managed_port.pending {
943 panic!("CompleteTransfer msg received for a pending port.");
944 }
945 if let Some(port_impl) = managed_port.port_impl.as_mut() {
946 port_impl.complete_transfer(tasks);
947 if disentangled {
948 port_impl.disentangle();
949 managed_port.dom_port.disentangle();
950 }
951 port_impl.enabled()
952 } else {
953 panic!("managed-port has no port-impl.");
954 }
955 },
956 }
957 } else {
958 panic!("complete_port_transfer called for an unknown port.");
959 };
960 if should_start {
961 self.start_message_port(&port_id, can_gc);
962 }
963 }
964
965 fn try_complete_disentanglement(&self, port_id: MessagePortId, can_gc: CanGc) {
968 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
969 &mut *self.message_port_state.borrow_mut()
970 {
971 if let Some(managed_port) = message_ports.get_mut(&port_id) {
972 if managed_port.pending {
973 unreachable!("CompleteDisentanglement msg received for a pending port.");
974 }
975 let port_impl = managed_port
976 .port_impl
977 .as_mut()
978 .expect("managed-port has no port-impl.");
979 port_impl.disentangle();
980 managed_port.dom_port.as_rooted()
981 } else {
982 return;
986 }
987 } else {
988 return;
989 };
990
991 dom_port.upcast().fire_event(atom!("close"), can_gc);
993
994 let res = self.script_to_constellation_chan().send(
995 ScriptToConstellationMessage::DisentanglePorts(port_id, None),
996 );
997 if res.is_err() {
998 warn!("Sending DisentanglePorts failed");
999 }
1000 }
1001
1002 pub(crate) fn perform_a_dom_garbage_collection_checkpoint(&self) {
1004 self.perform_a_message_port_garbage_collection_checkpoint();
1005 self.perform_a_blob_garbage_collection_checkpoint();
1006 self.perform_a_broadcast_channel_garbage_collection_checkpoint();
1007 self.perform_an_abort_signal_garbage_collection_checkpoint();
1008 }
1009
1010 pub(crate) fn remove_web_messaging_and_dedicated_workers_infra(&self) {
1013 self.remove_message_ports_router();
1014 self.remove_broadcast_channel_router();
1015
1016 self.list_auto_close_worker
1020 .borrow_mut()
1021 .drain(0..)
1022 .for_each(drop);
1023 }
1024
1025 fn remove_message_ports_router(&self) {
1028 if let MessagePortState::Managed(router_id, _message_ports) =
1029 &*self.message_port_state.borrow()
1030 {
1031 let _ = self.script_to_constellation_chan().send(
1032 ScriptToConstellationMessage::RemoveMessagePortRouter(*router_id),
1033 );
1034 }
1035 *self.message_port_state.borrow_mut() = MessagePortState::UnManaged;
1036 }
1037
1038 fn remove_broadcast_channel_router(&self) {
1041 if let BroadcastChannelState::Managed(router_id, _channels) =
1042 &*self.broadcast_channel_state.borrow()
1043 {
1044 let _ = self.script_to_constellation_chan().send(
1045 ScriptToConstellationMessage::RemoveBroadcastChannelRouter(
1046 *router_id,
1047 self.origin().immutable().clone(),
1048 ),
1049 );
1050 }
1051 *self.broadcast_channel_state.borrow_mut() = BroadcastChannelState::UnManaged;
1052 }
1053
1054 pub(crate) fn disentangle_port(&self, port: &MessagePort, can_gc: CanGc) {
1056 let initiator_port = port.message_port_id();
1057 let Some(other_port) = port.disentangle() else {
1059 return;
1063 };
1064
1065 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
1068 &mut *self.message_port_state.borrow_mut()
1069 {
1070 let mut dom_port = None;
1071 for port_id in &[initiator_port, &other_port] {
1072 match message_ports.get_mut(port_id) {
1073 None => {
1074 continue;
1075 },
1076 Some(managed_port) => {
1077 let port_impl = managed_port
1078 .port_impl
1079 .as_mut()
1080 .expect("managed-port has no port-impl.");
1081 managed_port.dom_port.disentangle();
1082 port_impl.disentangle();
1083
1084 if **port_id == other_port {
1085 dom_port = Some(managed_port.dom_port.as_rooted())
1086 }
1087 },
1088 }
1089 }
1090 dom_port
1091 } else {
1092 panic!("disentangle_port called on a global not managing any ports.");
1093 };
1094
1095 if let Some(dom_port) = dom_port {
1098 dom_port.upcast().fire_event(atom!("close"), can_gc);
1099 }
1100
1101 let chan = self.script_to_constellation_chan().clone();
1102 let initiator_port = *initiator_port;
1103 self.task_manager()
1104 .port_message_queue()
1105 .queue(task!(post_message: move || {
1106 let res = chan.send(ScriptToConstellationMessage::DisentanglePorts(initiator_port, Some(other_port)));
1109 if res.is_err() {
1110 warn!("Sending DisentanglePorts failed");
1111 }
1112 }));
1113 }
1114
1115 pub(crate) fn entangle_ports(&self, port1: MessagePortId, port2: MessagePortId) {
1117 if let MessagePortState::Managed(_id, message_ports) =
1118 &mut *self.message_port_state.borrow_mut()
1119 {
1120 for (port_id, entangled_id) in &[(port1, port2), (port2, port1)] {
1121 match message_ports.get_mut(port_id) {
1122 None => {
1123 return warn!("entangled_ports called on a global not managing the port.");
1124 },
1125 Some(managed_port) => {
1126 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1127 managed_port.dom_port.entangle(*entangled_id);
1128 port_impl.entangle(*entangled_id);
1129 } else {
1130 panic!("managed-port has no port-impl.");
1131 }
1132 },
1133 }
1134 }
1135 } else {
1136 panic!("entangled_ports called on a global not managing any ports.");
1137 }
1138
1139 let _ = self
1140 .script_to_constellation_chan()
1141 .send(ScriptToConstellationMessage::EntanglePorts(port1, port2));
1142 }
1143
1144 pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl {
1146 if let MessagePortState::Managed(_id, message_ports) =
1147 &mut *self.message_port_state.borrow_mut()
1148 {
1149 let mut port_impl = message_ports
1150 .remove(port_id)
1151 .map(|ref mut managed_port| {
1152 managed_port
1153 .port_impl
1154 .take()
1155 .expect("Managed port doesn't have a port-impl.")
1156 })
1157 .expect("mark_port_as_transferred called on a global not managing the port.");
1158 port_impl.set_has_been_shipped();
1159 let _ = self
1160 .script_to_constellation_chan()
1161 .send(ScriptToConstellationMessage::MessagePortShipped(*port_id));
1162 port_impl
1163 } else {
1164 panic!("mark_port_as_transferred called on a global not managing any ports.");
1165 }
1166 }
1167
1168 pub(crate) fn start_message_port(&self, port_id: &MessagePortId, can_gc: CanGc) {
1170 let (message_buffer, dom_port) = if let MessagePortState::Managed(_id, message_ports) =
1171 &mut *self.message_port_state.borrow_mut()
1172 {
1173 let (message_buffer, dom_port) = match message_ports.get_mut(port_id) {
1174 None => panic!("start_message_port called on a unknown port."),
1175 Some(managed_port) => {
1176 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1177 (port_impl.start(), managed_port.dom_port.as_rooted())
1178 } else {
1179 panic!("managed-port has no port-impl.");
1180 }
1181 },
1182 };
1183 (message_buffer, dom_port)
1184 } else {
1185 return warn!("start_message_port called on a global not managing any ports.");
1186 };
1187 if let Some(message_buffer) = message_buffer {
1188 for task in message_buffer {
1189 self.route_task_to_port(*port_id, task, CanGc::note());
1190 }
1191 if dom_port.disentangled() {
1192 dom_port.upcast().fire_event(atom!("close"), can_gc);
1195
1196 let res = self.script_to_constellation_chan().send(
1197 ScriptToConstellationMessage::DisentanglePorts(*port_id, None),
1198 );
1199 if res.is_err() {
1200 warn!("Sending DisentanglePorts failed");
1201 }
1202 }
1203 }
1204 }
1205
1206 pub(crate) fn close_message_port(&self, port_id: &MessagePortId) {
1208 if let MessagePortState::Managed(_id, message_ports) =
1209 &mut *self.message_port_state.borrow_mut()
1210 {
1211 match message_ports.get_mut(port_id) {
1212 None => panic!("close_message_port called on an unknown port."),
1213 Some(managed_port) => {
1214 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1215 port_impl.close();
1216 managed_port.explicitly_closed = true;
1217 } else {
1218 panic!("managed-port has no port-impl.");
1219 }
1220 },
1221 };
1222 } else {
1223 warn!("close_message_port called on a global not managing any ports.")
1224 }
1225 }
1226
1227 pub(crate) fn post_messageport_msg(&self, port_id: MessagePortId, task: PortMessageTask) {
1230 if let MessagePortState::Managed(_id, message_ports) =
1231 &mut *self.message_port_state.borrow_mut()
1232 {
1233 let entangled_port = match message_ports.get_mut(&port_id) {
1234 None => panic!("post_messageport_msg called on an unknown port."),
1235 Some(managed_port) => {
1236 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1237 port_impl.entangled_port_id()
1238 } else {
1239 panic!("managed-port has no port-impl.");
1240 }
1241 },
1242 };
1243 if let Some(entangled_id) = entangled_port {
1244 let this = Trusted::new(self);
1246 self.task_manager()
1247 .port_message_queue()
1248 .queue(task!(post_message: move || {
1249 let global = this.root();
1250 global.route_task_to_port(entangled_id, task, CanGc::note());
1253 }));
1254 }
1255 } else {
1256 warn!("post_messageport_msg called on a global not managing any ports.");
1257 }
1258 }
1259
1260 fn re_route_port_task(&self, port_id: MessagePortId, task: PortMessageTask) {
1263 let _ = self.script_to_constellation_chan().send(
1264 ScriptToConstellationMessage::RerouteMessagePort(port_id, task),
1265 );
1266 }
1267
1268 pub(crate) fn schedule_broadcast(&self, msg: BroadcastChannelMsg, channel_id: &Uuid) {
1271 self.broadcast_message_event(msg.clone(), Some(channel_id));
1273
1274 if let BroadcastChannelState::Managed(router_id, _) =
1275 &*self.broadcast_channel_state.borrow()
1276 {
1277 let _ = self.script_to_constellation_chan().send(
1282 ScriptToConstellationMessage::ScheduleBroadcast(*router_id, msg),
1283 );
1284 } else {
1285 panic!("Attemps to broadcast a message via global not managing any channels.");
1286 }
1287 }
1288
1289 pub(crate) fn broadcast_message_event(
1292 &self,
1293 event: BroadcastChannelMsg,
1294 channel_id: Option<&Uuid>,
1295 ) {
1296 if let BroadcastChannelState::Managed(_, channels) = &*self.broadcast_channel_state.borrow()
1297 {
1298 let BroadcastChannelMsg {
1299 data,
1300 origin,
1301 channel_name,
1302 } = event;
1303
1304 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
1308 if worker.is_closing() {
1309 return;
1310 }
1311 }
1312
1313 if let Some(window) = self.downcast::<Window>() {
1315 if !window.Document().is_fully_active() {
1316 return;
1317 }
1318 }
1319
1320 let channel_name = DOMString::from_string(channel_name);
1322
1323 if let Some(channels) = channels.get(&channel_name) {
1324 channels
1325 .iter()
1326 .filter(|channel| {
1327 if let Some(id) = channel_id {
1330 channel.id() != id
1331 } else {
1332 true
1333 }
1334 })
1335 .map(|channel| DomRoot::from_ref(&**channel))
1336 .for_each(|channel| {
1339 let data = data.clone_for_broadcast();
1340 let origin = origin.clone();
1341
1342 let channel = Trusted::new(&*channel);
1345 let global = Trusted::new(self);
1346 self.task_manager().dom_manipulation_task_source().queue(
1347 task!(process_pending_port_messages: move || {
1348 let destination = channel.root();
1349 let global = global.root();
1350
1351 if destination.closed() {
1353 return;
1354 }
1355
1356 rooted!(in(*GlobalScope::get_cx()) let mut message = UndefinedValue());
1357
1358 if let Ok(ports) = structuredclone::read(&global, data, message.handle_mut(), CanGc::note()) {
1360 MessageEvent::dispatch_jsval(
1362 destination.upcast(),
1363 &global,
1364 message.handle(),
1365 Some(&origin.ascii_serialization()),
1366 None,
1367 ports,
1368 CanGc::note()
1369 );
1370 } else {
1371 MessageEvent::dispatch_error(destination.upcast(), &global, CanGc::note());
1373 }
1374 })
1375 );
1376 });
1377 }
1378 }
1379 }
1380
1381 pub(crate) fn note_cross_realm_transform_readable(
1385 &self,
1386 cross_realm_transform_readable: &CrossRealmTransformReadable,
1387 port_id: &MessagePortId,
1388 ) {
1389 let MessagePortState::Managed(_id, message_ports) =
1390 &mut *self.message_port_state.borrow_mut()
1391 else {
1392 unreachable!(
1393 "Cross realm transform readable must be called on a global managing ports"
1394 );
1395 };
1396
1397 let Some(managed_port) = message_ports.get_mut(port_id) else {
1398 unreachable!("Cross realm transform readable must match a managed port");
1399 };
1400
1401 managed_port.cross_realm_transform = Some(CrossRealmTransform::Readable(
1402 cross_realm_transform_readable.clone(),
1403 ));
1404 }
1405
1406 pub(crate) fn note_cross_realm_transform_writable(
1410 &self,
1411 cross_realm_transform_writable: &CrossRealmTransformWritable,
1412 port_id: &MessagePortId,
1413 ) {
1414 let MessagePortState::Managed(_id, message_ports) =
1415 &mut *self.message_port_state.borrow_mut()
1416 else {
1417 unreachable!(
1418 "Cross realm transform writable must be called on a global managing ports"
1419 );
1420 };
1421
1422 let Some(managed_port) = message_ports.get_mut(port_id) else {
1423 unreachable!("Cross realm transform writable must match a managed port");
1424 };
1425
1426 managed_port.cross_realm_transform = Some(CrossRealmTransform::Writable(
1427 cross_realm_transform_writable.clone(),
1428 ));
1429 }
1430
1431 pub(crate) fn route_task_to_port(
1434 &self,
1435 port_id: MessagePortId,
1436 task: PortMessageTask,
1437 can_gc: CanGc,
1438 ) {
1439 let cx = GlobalScope::get_cx();
1440 rooted!(in(*cx) let mut cross_realm_transform = None);
1441
1442 let should_dispatch = if let MessagePortState::Managed(_id, message_ports) =
1443 &mut *self.message_port_state.borrow_mut()
1444 {
1445 if !message_ports.contains_key(&port_id) {
1446 self.re_route_port_task(port_id, task);
1447 return;
1448 }
1449 match message_ports.get_mut(&port_id) {
1450 None => panic!("route_task_to_port called for an unknown port."),
1451 Some(managed_port) => {
1452 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1455 let to_dispatch = port_impl.handle_incoming(task).map(|to_dispatch| {
1456 (DomRoot::from_ref(&*managed_port.dom_port), to_dispatch)
1457 });
1458 cross_realm_transform.set(managed_port.cross_realm_transform.clone());
1459 to_dispatch
1460 } else {
1461 panic!("managed-port has no port-impl.");
1462 }
1463 },
1464 }
1465 } else {
1466 self.re_route_port_task(port_id, task);
1467 return;
1468 };
1469
1470 if let Some((dom_port, PortMessageTask { origin, data })) = should_dispatch {
1475 let message_event_target = dom_port.upcast();
1477
1478 rooted!(in(*cx) let mut message_clone = UndefinedValue());
1484
1485 let realm = enter_realm(self);
1486 let comp = InRealm::Entered(&realm);
1487
1488 let _aes = AutoEntryScript::new(self);
1492
1493 if let Ok(ports) = structuredclone::read(self, data, message_clone.handle_mut(), can_gc)
1499 {
1500 if let Some(transform) = cross_realm_transform.as_ref() {
1502 match transform {
1503 CrossRealmTransform::Readable(readable) => {
1506 readable.handle_message(
1507 cx,
1508 self,
1509 &dom_port,
1510 message_clone.handle(),
1511 comp,
1512 can_gc,
1513 );
1514 },
1515 CrossRealmTransform::Writable(writable) => {
1518 writable.handle_message(cx, self, message_clone.handle(), comp, can_gc);
1519 },
1520 }
1521 } else {
1522 MessageEvent::dispatch_jsval(
1527 message_event_target,
1528 self,
1529 message_clone.handle(),
1530 Some(&origin.ascii_serialization()),
1531 None,
1532 ports,
1533 can_gc,
1534 );
1535 }
1536 } else if let Some(transform) = cross_realm_transform.as_ref() {
1537 match transform {
1538 CrossRealmTransform::Readable(readable) => {
1541 readable.handle_error(cx, self, &dom_port, comp, can_gc);
1542 },
1543 CrossRealmTransform::Writable(writable) => {
1546 writable.handle_error(cx, self, &dom_port, comp, can_gc);
1547 },
1548 }
1549 } else {
1550 MessageEvent::dispatch_error(message_event_target, self, can_gc);
1554 }
1555 }
1556 }
1557
1558 pub(crate) fn maybe_add_pending_ports(&self) {
1561 if let MessagePortState::Managed(router_id, message_ports) =
1562 &mut *self.message_port_state.borrow_mut()
1563 {
1564 let to_be_added: Vec<MessagePortId> = message_ports
1565 .iter()
1566 .filter_map(|(id, managed_port)| {
1567 if managed_port.pending {
1568 Some(*id)
1569 } else {
1570 None
1571 }
1572 })
1573 .collect();
1574 for id in to_be_added.iter() {
1575 let managed_port = message_ports
1576 .get_mut(id)
1577 .expect("Collected port-id to match an entry");
1578 if !managed_port.pending {
1579 panic!("Only pending ports should be found in to_be_added")
1580 }
1581 managed_port.pending = false;
1582 }
1583 let _ = self.script_to_constellation_chan().send(
1584 ScriptToConstellationMessage::CompleteMessagePortTransfer(*router_id, to_be_added),
1585 );
1586 } else {
1587 warn!("maybe_add_pending_ports called on a global not managing any ports.");
1588 }
1589 }
1590
1591 pub(crate) fn perform_a_message_port_garbage_collection_checkpoint(&self) {
1593 let is_empty = if let MessagePortState::Managed(_id, message_ports) =
1594 &mut *self.message_port_state.borrow_mut()
1595 {
1596 let to_be_removed: Vec<MessagePortId> = message_ports
1597 .iter()
1598 .filter_map(|(id, managed_port)| {
1599 if managed_port.explicitly_closed {
1600 Some(*id)
1601 } else {
1602 None
1603 }
1604 })
1605 .collect();
1606 for id in to_be_removed {
1607 message_ports.remove(&id);
1608 }
1609 message_ports.is_empty()
1613 } else {
1614 false
1615 };
1616 if is_empty {
1617 self.remove_message_ports_router();
1618 }
1619 }
1620
1621 pub(crate) fn perform_a_broadcast_channel_garbage_collection_checkpoint(&self) {
1625 let is_empty = if let BroadcastChannelState::Managed(router_id, channels) =
1626 &mut *self.broadcast_channel_state.borrow_mut()
1627 {
1628 channels.retain(|name, ref mut channels| {
1629 channels.retain(|chan| !chan.closed());
1630 if channels.is_empty() {
1631 let _ = self.script_to_constellation_chan().send(
1632 ScriptToConstellationMessage::RemoveBroadcastChannelNameInRouter(
1633 *router_id,
1634 name.to_string(),
1635 self.origin().immutable().clone(),
1636 ),
1637 );
1638 false
1639 } else {
1640 true
1641 }
1642 });
1643 channels.is_empty()
1644 } else {
1645 false
1646 };
1647 if is_empty {
1648 self.remove_broadcast_channel_router();
1649 }
1650 }
1651
1652 pub(crate) fn register_dependent_abort_signal(&self, signal: &AbortSignal) {
1655 self.abort_signal_dependents
1656 .borrow_mut()
1657 .insert(Dom::from_ref(signal));
1658 }
1659
1660 pub(crate) fn perform_an_abort_signal_garbage_collection_checkpoint(&self) {
1662 let mut set = self.abort_signal_dependents.borrow_mut();
1663
1664 set.retain(|dom_signal| dom_signal.must_keep_alive_for_gc());
1665 }
1666
1667 pub(crate) fn track_broadcast_channel(&self, dom_channel: &BroadcastChannel) {
1669 let mut current_state = self.broadcast_channel_state.borrow_mut();
1670
1671 if let BroadcastChannelState::UnManaged = &*current_state {
1672 let (broadcast_control_sender, broadcast_control_receiver) =
1674 ipc::channel().expect("ipc channel failure");
1675 let context = Trusted::new(self);
1676 let listener = BroadcastListener {
1677 task_source: self.task_manager().dom_manipulation_task_source().into(),
1678 context,
1679 };
1680 ROUTER.add_typed_route(
1681 broadcast_control_receiver,
1682 Box::new(move |message| match message {
1683 Ok(msg) => listener.handle(msg),
1684 Err(err) => warn!("Error receiving a BroadcastChannelMsg: {:?}", err),
1685 }),
1686 );
1687 let router_id = BroadcastChannelRouterId::new();
1688 *current_state = BroadcastChannelState::Managed(router_id, HashMap::new());
1689 let _ = self.script_to_constellation_chan().send(
1690 ScriptToConstellationMessage::NewBroadcastChannelRouter(
1691 router_id,
1692 broadcast_control_sender,
1693 self.origin().immutable().clone(),
1694 ),
1695 );
1696 }
1697
1698 if let BroadcastChannelState::Managed(router_id, channels) = &mut *current_state {
1699 let entry = channels.entry(dom_channel.Name()).or_insert_with(|| {
1700 let _ = self.script_to_constellation_chan().send(
1701 ScriptToConstellationMessage::NewBroadcastChannelNameInRouter(
1702 *router_id,
1703 dom_channel.Name().to_string(),
1704 self.origin().immutable().clone(),
1705 ),
1706 );
1707 VecDeque::new()
1708 });
1709 entry.push_back(Dom::from_ref(dom_channel));
1710 } else {
1711 panic!("track_broadcast_channel should have first switched the state to managed.");
1712 }
1713 }
1714
1715 pub(crate) fn track_message_port(
1717 &self,
1718 dom_port: &MessagePort,
1719 port_impl: Option<MessagePortImpl>,
1720 ) {
1721 let mut current_state = self.message_port_state.borrow_mut();
1722
1723 if let MessagePortState::UnManaged = &*current_state {
1724 let (port_control_sender, port_control_receiver) =
1726 ipc::channel().expect("ipc channel failure");
1727 let context = Trusted::new(self);
1728 let listener = MessageListener {
1729 task_source: self.task_manager().port_message_queue().into(),
1730 context,
1731 };
1732 ROUTER.add_typed_route(
1733 port_control_receiver,
1734 Box::new(move |message| match message {
1735 Ok(msg) => listener.notify(msg),
1736 Err(err) => warn!("Error receiving a MessagePortMsg: {:?}", err),
1737 }),
1738 );
1739 let router_id = MessagePortRouterId::new();
1740 *current_state = MessagePortState::Managed(router_id, HashMapTracedValues::new_fx());
1741 let _ = self.script_to_constellation_chan().send(
1742 ScriptToConstellationMessage::NewMessagePortRouter(router_id, port_control_sender),
1743 );
1744 }
1745
1746 if let MessagePortState::Managed(router_id, message_ports) = &mut *current_state {
1747 if let Some(port_impl) = port_impl {
1748 message_ports.insert(
1752 *dom_port.message_port_id(),
1753 ManagedMessagePort {
1754 port_impl: Some(port_impl),
1755 dom_port: Dom::from_ref(dom_port),
1756 pending: true,
1757 explicitly_closed: false,
1758 cross_realm_transform: None,
1759 },
1760 );
1761
1762 let this = Trusted::new(self);
1765 self.task_manager().port_message_queue().queue(
1766 task!(process_pending_port_messages: move || {
1767 let target_global = this.root();
1768 target_global.maybe_add_pending_ports();
1769 }),
1770 );
1771 } else {
1772 let port_impl = MessagePortImpl::new(*dom_port.message_port_id());
1774 message_ports.insert(
1775 *dom_port.message_port_id(),
1776 ManagedMessagePort {
1777 port_impl: Some(port_impl),
1778 dom_port: Dom::from_ref(dom_port),
1779 pending: false,
1780 explicitly_closed: false,
1781 cross_realm_transform: None,
1782 },
1783 );
1784 let _ = self.script_to_constellation_chan().send(
1785 ScriptToConstellationMessage::NewMessagePort(
1786 *router_id,
1787 *dom_port.message_port_id(),
1788 ),
1789 );
1790 };
1791 } else {
1792 panic!("track_message_port should have first switched the state to managed.");
1793 }
1794 }
1795
1796 pub(crate) fn serialize_blob(&self, blob_id: &BlobId) -> BlobImpl {
1800 let bytes = self
1804 .get_blob_bytes(blob_id)
1805 .expect("Could not read bytes from blob as part of serialization steps.");
1806 let type_string = self.get_blob_type_string(blob_id);
1807
1808 BlobImpl::new_from_bytes(bytes, type_string)
1810 }
1811
1812 fn track_blob_info(&self, blob_info: BlobInfo, blob_id: BlobId) {
1813 self.blob_state.borrow_mut().insert(blob_id, blob_info);
1814 }
1815
1816 pub(crate) fn track_blob(&self, dom_blob: &Blob, blob_impl: BlobImpl) {
1818 let blob_id = blob_impl.blob_id();
1819
1820 let blob_info = BlobInfo {
1821 blob_impl,
1822 tracker: BlobTracker::Blob(WeakRef::new(dom_blob)),
1823 has_url: false,
1824 };
1825
1826 self.track_blob_info(blob_info, blob_id);
1827 }
1828
1829 pub(crate) fn track_file(&self, file: &File, blob_impl: BlobImpl) {
1831 let blob_id = blob_impl.blob_id();
1832
1833 let blob_info = BlobInfo {
1834 blob_impl,
1835 tracker: BlobTracker::File(WeakRef::new(file)),
1836 has_url: false,
1837 };
1838
1839 self.track_blob_info(blob_info, blob_id);
1840 }
1841
1842 fn perform_a_blob_garbage_collection_checkpoint(&self) {
1846 let mut blob_state = self.blob_state.borrow_mut();
1847 blob_state.0.retain(|_id, blob_info| {
1848 let garbage_collected = match &blob_info.tracker {
1849 BlobTracker::File(weak) => weak.root().is_none(),
1850 BlobTracker::Blob(weak) => weak.root().is_none(),
1851 };
1852 if garbage_collected && !blob_info.has_url {
1853 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1854 self.decrement_file_ref(f.get_id());
1855 }
1856 false
1857 } else {
1858 true
1859 }
1860 });
1861 }
1862
1863 pub(crate) fn clean_up_all_file_resources(&self) {
1866 self.blob_state
1867 .borrow_mut()
1868 .drain()
1869 .for_each(|(_id, blob_info)| {
1870 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1871 self.decrement_file_ref(f.get_id());
1872 }
1873 });
1874 }
1875
1876 fn decrement_file_ref(&self, id: Uuid) {
1877 let origin = get_blob_origin(&self.get_url());
1878
1879 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
1880
1881 let msg = FileManagerThreadMsg::DecRef(id, origin, tx);
1882 self.send_to_file_manager(msg);
1883 let _ = rx.recv();
1884 }
1885
1886 pub(crate) fn get_blob_bytes(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1889 let parent = {
1890 match *self.get_blob_data(blob_id) {
1891 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1892 _ => None,
1893 }
1894 };
1895
1896 match parent {
1897 Some((parent_id, rel_pos)) => self.get_blob_bytes_non_sliced(&parent_id).map(|v| {
1898 let range = rel_pos.to_abs_range(v.len());
1899 v.index(range).to_vec()
1900 }),
1901 None => self.get_blob_bytes_non_sliced(blob_id),
1902 }
1903 }
1904
1905 pub(crate) fn get_blob_data<'a>(&'a self, blob_id: &BlobId) -> Ref<'a, BlobData> {
1910 Ref::map(self.blob_state.borrow(), |blob_state| {
1911 blob_state
1912 .get(blob_id)
1913 .expect("get_blob_impl called for a unknown blob")
1914 .blob_impl
1915 .blob_data()
1916 })
1917 }
1918
1919 fn get_blob_bytes_non_sliced(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1921 match *self.get_blob_data(blob_id) {
1922 BlobData::File(ref f) => {
1923 let (buffer, is_new_buffer) = match f.get_cache() {
1924 Some(bytes) => (bytes, false),
1925 None => {
1926 let bytes = self.read_file(f.get_id())?;
1927 (bytes, true)
1928 },
1929 };
1930
1931 if is_new_buffer {
1933 f.cache_bytes(buffer.clone());
1934 }
1935
1936 Ok(buffer)
1937 },
1938 BlobData::Memory(ref s) => Ok(s.clone()),
1939 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1940 }
1941 }
1942
1943 fn get_blob_bytes_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1950 let parent = {
1951 match *self.get_blob_data(blob_id) {
1952 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1953 _ => None,
1954 }
1955 };
1956
1957 match parent {
1958 Some((parent_id, rel_pos)) => {
1959 match self.get_blob_bytes_non_sliced_or_file_id(&parent_id) {
1960 BlobResult::Bytes(bytes) => {
1961 let range = rel_pos.to_abs_range(bytes.len());
1962 BlobResult::Bytes(bytes.index(range).to_vec())
1963 },
1964 res => res,
1965 }
1966 },
1967 None => self.get_blob_bytes_non_sliced_or_file_id(blob_id),
1968 }
1969 }
1970
1971 fn get_blob_bytes_non_sliced_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1977 match *self.get_blob_data(blob_id) {
1978 BlobData::File(ref f) => match f.get_cache() {
1979 Some(bytes) => BlobResult::Bytes(bytes.clone()),
1980 None => BlobResult::File(f.get_id(), f.get_size() as usize),
1981 },
1982 BlobData::Memory(ref s) => BlobResult::Bytes(s.clone()),
1983 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1984 }
1985 }
1986
1987 pub(crate) fn get_blob_type_string(&self, blob_id: &BlobId) -> String {
1989 let blob_state = self.blob_state.borrow();
1990 let blob_info = blob_state
1991 .get(blob_id)
1992 .expect("get_blob_type_string called for a unknown blob.");
1993 blob_info.blob_impl.type_string()
1994 }
1995
1996 pub(crate) fn get_blob_size(&self, blob_id: &BlobId) -> u64 {
1998 let parent = {
1999 match *self.get_blob_data(blob_id) {
2000 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
2001 _ => None,
2002 }
2003 };
2004 match parent {
2005 Some((parent_id, rel_pos)) => {
2006 let parent_size = match *self.get_blob_data(&parent_id) {
2007 BlobData::File(ref f) => f.get_size(),
2008 BlobData::Memory(ref v) => v.len() as u64,
2009 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
2010 };
2011 rel_pos.to_abs_range(parent_size as usize).len() as u64
2012 },
2013 None => match *self.get_blob_data(blob_id) {
2014 BlobData::File(ref f) => f.get_size(),
2015 BlobData::Memory(ref v) => v.len() as u64,
2016 BlobData::Sliced(_, _) => {
2017 panic!("It was previously checked that this blob does not have a parent.")
2018 },
2019 },
2020 }
2021 }
2022
2023 pub(crate) fn get_blob_url_id(&self, blob_id: &BlobId) -> Uuid {
2024 let mut blob_state = self.blob_state.borrow_mut();
2025 let parent = {
2026 let blob_info = blob_state
2027 .get_mut(blob_id)
2028 .expect("get_blob_url_id called for a unknown blob.");
2029
2030 blob_info.has_url = true;
2032
2033 match blob_info.blob_impl.blob_data() {
2034 BlobData::Sliced(parent, rel_pos) => Some((*parent, *rel_pos)),
2035 _ => None,
2036 }
2037 };
2038 match parent {
2039 Some((parent_id, rel_pos)) => {
2040 let parent_info = blob_state
2041 .get_mut(&parent_id)
2042 .expect("Parent of blob whose url is requested is unknown.");
2043 let parent_file_id = self.promote(parent_info, false);
2044 let parent_size = match parent_info.blob_impl.blob_data() {
2045 BlobData::File(f) => f.get_size(),
2046 BlobData::Memory(v) => v.len() as u64,
2047 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
2048 };
2049 let parent_size = rel_pos.to_abs_range(parent_size as usize).len() as u64;
2050 let blob_info = blob_state
2051 .get_mut(blob_id)
2052 .expect("Blob whose url is requested is unknown.");
2053 self.create_sliced_url_id(blob_info, &parent_file_id, &rel_pos, parent_size)
2054 },
2055 None => {
2056 let blob_info = blob_state
2057 .get_mut(blob_id)
2058 .expect("Blob whose url is requested is unknown.");
2059 self.promote(blob_info, true)
2060 },
2061 }
2062 }
2063
2064 fn create_sliced_url_id(
2066 &self,
2067 blob_info: &mut BlobInfo,
2068 parent_file_id: &Uuid,
2069 rel_pos: &RelativePos,
2070 parent_len: u64,
2071 ) -> Uuid {
2072 let origin = get_blob_origin(&self.get_url());
2073
2074 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2075 let msg =
2076 FileManagerThreadMsg::AddSlicedURLEntry(*parent_file_id, *rel_pos, tx, origin.clone());
2077 self.send_to_file_manager(msg);
2078 match rx.recv().expect("File manager thread is down.") {
2079 Ok(new_id) => {
2080 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
2081 new_id,
2082 None,
2083 None,
2084 rel_pos.to_abs_range(parent_len as usize).len() as u64,
2085 ));
2086
2087 new_id
2089 },
2090 Err(_) => {
2091 Uuid::new_v4()
2093 },
2094 }
2095 }
2096
2097 pub(crate) fn promote(&self, blob_info: &mut BlobInfo, set_valid: bool) -> Uuid {
2103 let mut bytes = vec![];
2104 let global_url = self.get_url();
2105
2106 match blob_info.blob_impl.blob_data_mut() {
2107 BlobData::Sliced(_, _) => {
2108 panic!("Sliced blobs should use create_sliced_url_id instead of promote.");
2109 },
2110 BlobData::File(f) => {
2111 if set_valid {
2112 let origin = get_blob_origin(&global_url);
2113 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2114
2115 let msg = FileManagerThreadMsg::ActivateBlobURL(f.get_id(), tx, origin.clone());
2116 self.send_to_file_manager(msg);
2117
2118 match rx.recv().unwrap() {
2119 Ok(_) => return f.get_id(),
2120 Err(_) => return Uuid::new_v4(),
2122 }
2123 } else {
2124 return f.get_id();
2126 }
2127 },
2128 BlobData::Memory(bytes_in) => mem::swap(bytes_in, &mut bytes),
2129 };
2130
2131 let origin = get_blob_origin(&global_url);
2132
2133 let blob_buf = BlobBuf {
2134 filename: None,
2135 type_string: blob_info.blob_impl.type_string(),
2136 size: bytes.len() as u64,
2137 bytes: bytes.to_vec(),
2138 };
2139
2140 let id = Uuid::new_v4();
2141 let msg = FileManagerThreadMsg::PromoteMemory(id, blob_buf, set_valid, origin.clone());
2142 self.send_to_file_manager(msg);
2143
2144 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
2145 id,
2146 None,
2147 Some(bytes.to_vec()),
2148 bytes.len() as u64,
2149 ));
2150
2151 id
2152 }
2153
2154 fn send_to_file_manager(&self, msg: FileManagerThreadMsg) {
2155 let resource_threads = self.resource_threads();
2156 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
2157 }
2158
2159 fn read_file(&self, id: Uuid) -> Result<Vec<u8>, ()> {
2160 let recv = self.send_msg(id);
2161 GlobalScope::read_msg(recv)
2162 }
2163
2164 pub(crate) fn get_blob_stream(
2166 &self,
2167 blob_id: &BlobId,
2168 can_gc: CanGc,
2169 ) -> Fallible<DomRoot<ReadableStream>> {
2170 let (file_id, size) = match self.get_blob_bytes_or_file_id(blob_id) {
2171 BlobResult::Bytes(bytes) => {
2172 return ReadableStream::new_from_bytes(self, bytes, can_gc);
2174 },
2175 BlobResult::File(id, size) => (id, size),
2176 };
2177
2178 let stream = ReadableStream::new_with_external_underlying_source(
2179 self,
2180 UnderlyingSourceType::Blob(size),
2181 can_gc,
2182 )?;
2183
2184 let recv = self.send_msg(file_id);
2185
2186 let trusted_stream = Trusted::new(&*stream.clone());
2187 let mut file_listener = FileListener {
2188 state: Some(FileListenerState::Empty(FileListenerTarget::Stream(
2189 trusted_stream,
2190 ))),
2191 task_source: self.task_manager().file_reading_task_source().into(),
2192 };
2193
2194 ROUTER.add_typed_route(
2195 recv.to_ipc_receiver(),
2196 Box::new(move |msg| {
2197 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
2198 }),
2199 );
2200
2201 Ok(stream)
2202 }
2203
2204 pub(crate) fn read_file_async(
2205 &self,
2206 id: Uuid,
2207 promise: Rc<Promise>,
2208 callback: FileListenerCallback,
2209 ) {
2210 let recv = self.send_msg(id);
2211
2212 let trusted_promise = TrustedPromise::new(promise);
2213 let mut file_listener = FileListener {
2214 state: Some(FileListenerState::Empty(FileListenerTarget::Promise(
2215 trusted_promise,
2216 callback,
2217 ))),
2218 task_source: self.task_manager().file_reading_task_source().into(),
2219 };
2220
2221 ROUTER.add_typed_route(
2222 recv.to_ipc_receiver(),
2223 Box::new(move |msg| {
2224 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
2225 }),
2226 );
2227 }
2228
2229 fn send_msg(&self, id: Uuid) -> profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>> {
2230 let resource_threads = self.resource_threads();
2231 let (chan, recv) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2232 let origin = get_blob_origin(&self.get_url());
2233 let msg = FileManagerThreadMsg::ReadFile(chan, id, origin);
2234 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
2235 recv
2236 }
2237
2238 fn read_msg(
2239 receiver: profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>>,
2240 ) -> Result<Vec<u8>, ()> {
2241 let mut bytes = vec![];
2242
2243 loop {
2244 match receiver.recv().unwrap() {
2245 Ok(ReadFileProgress::Meta(mut blob_buf)) => {
2246 bytes.append(&mut blob_buf.bytes);
2247 },
2248 Ok(ReadFileProgress::Partial(mut bytes_in)) => {
2249 bytes.append(&mut bytes_in);
2250 },
2251 Ok(ReadFileProgress::EOF) => {
2252 return Ok(bytes);
2253 },
2254 Err(_) => return Err(()),
2255 }
2256 }
2257 }
2258
2259 pub(crate) fn permission_state_invocation_results(
2260 &self,
2261 ) -> &DomRefCell<HashMap<PermissionName, PermissionState>> {
2262 &self.permission_state_invocation_results
2263 }
2264
2265 pub(crate) fn track_worker(
2266 &self,
2267 closing: Arc<AtomicBool>,
2268 join_handle: JoinHandle<()>,
2269 control_sender: Sender<DedicatedWorkerControlMsg>,
2270 context: ThreadSafeJSContext,
2271 ) {
2272 self.list_auto_close_worker
2273 .borrow_mut()
2274 .push(AutoCloseWorker {
2275 closing,
2276 join_handle: Some(join_handle),
2277 control_sender,
2278 context,
2279 });
2280 }
2281
2282 pub(crate) fn track_event_source(&self, event_source: &EventSource) {
2283 self.event_source_tracker.track(event_source);
2284 }
2285
2286 pub(crate) fn close_event_sources(&self) -> bool {
2287 let mut canceled_any_fetch = false;
2288 self.event_source_tracker
2289 .for_each(
2290 |event_source: DomRoot<EventSource>| match event_source.ReadyState() {
2291 2 => {},
2292 _ => {
2293 event_source.cancel();
2294 canceled_any_fetch = true;
2295 },
2296 },
2297 );
2298 canceled_any_fetch
2299 }
2300
2301 #[expect(unsafe_code)]
2304 pub(crate) fn from_reflector<T: DomObject>(reflector: &T, _realm: InRealm) -> DomRoot<Self> {
2305 unsafe { GlobalScope::from_object(*reflector.reflector().get_jsobject()) }
2306 }
2307
2308 #[expect(unsafe_code)]
2310 pub(crate) unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
2311 assert!(!obj.is_null());
2312 let global = unsafe { GetNonCCWObjectGlobal(obj) };
2313 unsafe { global_scope_from_global_static(global) }
2314 }
2315
2316 #[expect(unsafe_code)]
2318 pub(crate) unsafe fn from_context(cx: *mut JSContext, _realm: InRealm) -> DomRoot<Self> {
2319 let global = unsafe { CurrentGlobalOrNull(cx) };
2320 assert!(!global.is_null());
2321 unsafe { global_scope_from_global(global, cx) }
2322 }
2323
2324 #[expect(unsafe_code)]
2328 pub(crate) fn from_current_realm(realm: &'_ CurrentRealm) -> DomRoot<Self> {
2329 let global = realm.global();
2330 unsafe { global_scope_from_global(global.get(), realm.raw_cx_no_gc()) }
2331 }
2332
2333 #[expect(unsafe_code)]
2335 pub(crate) fn from_safe_context(cx: SafeJSContext, realm: InRealm) -> DomRoot<Self> {
2336 unsafe { Self::from_context(*cx, realm) }
2337 }
2338
2339 #[expect(unsafe_code)]
2342 pub(crate) unsafe fn from_object_maybe_wrapped(
2343 mut obj: *mut JSObject,
2344 cx: *mut JSContext,
2345 ) -> DomRoot<Self> {
2346 unsafe {
2347 if IsWrapper(obj) {
2348 obj = UnwrapObjectDynamic(obj, cx, false);
2349 assert!(!obj.is_null());
2350 }
2351 GlobalScope::from_object(obj)
2352 }
2353 }
2354
2355 pub(crate) fn add_uncaught_rejection(&self, rejection: HandleObject) {
2356 self.uncaught_rejections
2357 .borrow_mut()
2358 .push(Heap::boxed(rejection.get()));
2359 }
2360
2361 pub(crate) fn remove_uncaught_rejection(&self, rejection: HandleObject) {
2362 let mut uncaught_rejections = self.uncaught_rejections.borrow_mut();
2363
2364 if let Some(index) = uncaught_rejections
2365 .iter()
2366 .position(|promise| *promise == Heap::boxed(rejection.get()))
2367 {
2368 uncaught_rejections.remove(index);
2369 }
2370 }
2371
2372 #[allow(clippy::vec_box)]
2375 pub(crate) fn get_uncaught_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2376 &self.uncaught_rejections
2377 }
2378
2379 pub(crate) fn add_consumed_rejection(&self, rejection: HandleObject) {
2380 self.consumed_rejections
2381 .borrow_mut()
2382 .push(Heap::boxed(rejection.get()));
2383 }
2384
2385 pub(crate) fn remove_consumed_rejection(&self, rejection: HandleObject) {
2386 let mut consumed_rejections = self.consumed_rejections.borrow_mut();
2387
2388 if let Some(index) = consumed_rejections
2389 .iter()
2390 .position(|promise| *promise == Heap::boxed(rejection.get()))
2391 {
2392 consumed_rejections.remove(index);
2393 }
2394 }
2395
2396 #[allow(clippy::vec_box)]
2399 pub(crate) fn get_consumed_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2400 &self.consumed_rejections
2401 }
2402
2403 pub(crate) fn set_module_map(&self, url: ServoUrl, module: ModuleTree) {
2404 self.module_map.borrow_mut().insert(url, Rc::new(module));
2405 }
2406
2407 pub(crate) fn get_module_map(
2408 &self,
2409 ) -> &DomRefCell<HashMapTracedValues<ServoUrl, Rc<ModuleTree>>> {
2410 &self.module_map
2411 }
2412
2413 pub(crate) fn set_inline_module_map(&self, script_id: ScriptId, module: ModuleTree) {
2414 self.inline_module_map
2415 .borrow_mut()
2416 .insert(script_id, Rc::new(module));
2417 }
2418
2419 pub(crate) fn get_inline_module_map(&self) -> &DomRefCell<FxHashMap<ScriptId, Rc<ModuleTree>>> {
2420 &self.inline_module_map
2421 }
2422
2423 #[expect(unsafe_code)]
2424 pub(crate) fn get_cx() -> SafeJSContext {
2425 let cx = Runtime::get()
2426 .expect("Can't obtain context after runtime shutdown")
2427 .as_ptr();
2428 unsafe { SafeJSContext::from_ptr(cx) }
2429 }
2430
2431 pub(crate) fn crypto(&self, can_gc: CanGc) -> DomRoot<Crypto> {
2432 self.crypto.or_init(|| Crypto::new(self, can_gc))
2433 }
2434
2435 pub(crate) fn cookie_store(&self, can_gc: CanGc) -> DomRoot<CookieStore> {
2436 self.cookie_store.or_init(|| CookieStore::new(self, can_gc))
2437 }
2438
2439 pub(crate) fn live_devtools_updates(&self) -> bool {
2440 self.devtools_wants_updates.get()
2441 }
2442
2443 pub(crate) fn set_devtools_wants_updates(&self, value: bool) {
2444 self.devtools_wants_updates.set(value);
2445 }
2446
2447 pub(crate) fn time(&self, label: DOMString) -> Result<(), ()> {
2448 let mut timers = self.console_timers.borrow_mut();
2449 if timers.len() >= 10000 {
2450 return Err(());
2451 }
2452 match timers.entry(label) {
2453 Entry::Vacant(entry) => {
2454 entry.insert(Instant::now());
2455 Ok(())
2456 },
2457 Entry::Occupied(_) => Err(()),
2458 }
2459 }
2460
2461 pub(crate) fn time_log(&self, label: &DOMString) -> Result<u64, ()> {
2465 self.console_timers
2466 .borrow()
2467 .get(label)
2468 .ok_or(())
2469 .map(|&start| (Instant::now() - start).as_millis() as u64)
2470 }
2471
2472 pub(crate) fn time_end(&self, label: &DOMString) -> Result<u64, ()> {
2477 self.console_timers
2478 .borrow_mut()
2479 .remove(label)
2480 .ok_or(())
2481 .map(|start| (Instant::now() - start).as_millis() as u64)
2482 }
2483
2484 pub(crate) fn devtools_chan(&self) -> Option<&IpcSender<ScriptToDevtoolsControlMsg>> {
2487 self.devtools_chan.as_ref()
2488 }
2489
2490 pub(crate) fn issue_page_warning(&self, warning: &str) {
2491 if let Some(ref chan) = self.devtools_chan {
2492 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2493 self.pipeline_id,
2494 PageError {
2495 type_: "PageError".to_string(),
2496 error_message: warning.to_string(),
2497 source_name: self.get_url().to_string(),
2498 line_text: "".to_string(),
2499 line_number: 0,
2500 column_number: 0,
2501 category: "script".to_string(),
2502 time_stamp: SystemTime::now()
2503 .duration_since(UNIX_EPOCH)
2504 .unwrap_or_default()
2505 .as_millis() as u64,
2506 error: false,
2507 warning: true,
2508 exception: true,
2509 strict: false,
2510 private: false,
2511 },
2512 ));
2513 }
2514 }
2515
2516 pub(crate) fn mem_profiler_chan(&self) -> &profile_mem::ProfilerChan {
2518 &self.mem_profiler_chan
2519 }
2520
2521 pub(crate) fn time_profiler_chan(&self) -> &profile_time::ProfilerChan {
2523 &self.time_profiler_chan
2524 }
2525
2526 pub(crate) fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan {
2528 &self.script_to_constellation_chan
2529 }
2530
2531 pub(crate) fn script_to_embedder_chan(&self) -> &ScriptToEmbedderChan {
2532 &self.script_to_embedder_chan
2533 }
2534
2535 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
2536 self.script_to_embedder_chan().send(msg).unwrap();
2537 }
2538
2539 pub(crate) fn send_to_constellation(&self, msg: ScriptToConstellationMessage) {
2540 self.script_to_constellation_chan().send(msg).unwrap();
2541 }
2542
2543 pub(crate) fn pipeline_id(&self) -> PipelineId {
2545 self.pipeline_id
2546 }
2547
2548 pub(crate) fn origin(&self) -> &MutableOrigin {
2550 &self.origin
2551 }
2552
2553 pub(crate) fn creation_url(&self) -> &ServoUrl {
2555 &self.creation_url
2556 }
2557
2558 pub(crate) fn top_level_creation_url(&self) -> &Option<ServoUrl> {
2560 &self.top_level_creation_url
2561 }
2562
2563 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
2564 if let Some(window) = self.downcast::<Window>() {
2565 return window.image_cache();
2566 }
2567 if let Some(worker) = self.downcast::<DedicatedWorkerGlobalScope>() {
2568 return worker.image_cache();
2569 }
2570 if let Some(worker) = self.downcast::<PaintWorkletGlobalScope>() {
2571 return worker.image_cache();
2572 }
2573 unreachable!();
2574 }
2575
2576 pub(crate) fn schedule_timer(&self, request: TimerEventRequest) -> Option<TimerId> {
2580 match self.downcast::<WorkerGlobalScope>() {
2581 Some(worker_global) => Some(worker_global.timer_scheduler().schedule_timer(request)),
2582 _ => with_script_thread(|script_thread| Some(script_thread.schedule_timer(request))),
2583 }
2584 }
2585
2586 pub(crate) fn request_client(&self) -> RequestClient {
2588 let preloaded_resources = self
2591 .downcast::<Window>()
2592 .map(|window: &Window| window.Document().preloaded_resources())
2593 .unwrap_or_default();
2594 RequestClient {
2595 preloaded_resources,
2596 policy_container: RequestPolicyContainer::PolicyContainer(self.policy_container()),
2597 origin: RequestOrigin::Origin(self.origin().immutable().clone()),
2598 }
2599 }
2600
2601 pub(crate) fn policy_container(&self) -> PolicyContainer {
2603 if let Some(window) = self.downcast::<Window>() {
2604 return window.Document().policy_container().to_owned();
2605 }
2606 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2607 return worker.policy_container().to_owned();
2608 }
2609 unreachable!();
2610 }
2611
2612 pub(crate) fn api_base_url(&self) -> ServoUrl {
2615 if let Some(window) = self.downcast::<Window>() {
2616 return window.Document().base_url();
2618 }
2619 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2620 return worker.get_url().clone();
2622 }
2623 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2624 return worklet.base_url();
2626 }
2627 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2628 return self.creation_url.clone();
2629 }
2630 unreachable!();
2631 }
2632
2633 pub(crate) fn get_url(&self) -> ServoUrl {
2635 if let Some(window) = self.downcast::<Window>() {
2636 return window.get_url();
2637 }
2638 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2639 return worker.get_url().clone();
2640 }
2641 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2642 return worklet.base_url();
2644 }
2645 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2646 return self.creation_url.clone();
2647 }
2648 unreachable!();
2649 }
2650
2651 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
2653 if let Some(window) = self.downcast::<Window>() {
2654 let document = window.Document();
2655
2656 return document.get_referrer_policy();
2657 }
2658 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2659 let policy_container = worker.policy_container().to_owned();
2660
2661 return policy_container.get_referrer_policy();
2662 }
2663 unreachable!();
2664 }
2665
2666 pub(crate) fn get_referrer(&self) -> Referrer {
2668 if let Some(window) = self.downcast::<Window>() {
2670 let mut document = window.Document();
2674
2675 if let ImmutableOrigin::Opaque(_) = document.origin().immutable() {
2677 return Referrer::NoReferrer;
2678 }
2679
2680 let mut url = document.url();
2681
2682 while url.as_str() == "about:srcdoc" {
2684 let Some(parent_document) =
2687 document.browsing_context().and_then(|browsing_context| {
2688 browsing_context
2689 .parent()
2690 .and_then(|parent| parent.document())
2691 })
2692 else {
2693 return Referrer::NoReferrer;
2694 };
2695 document = parent_document;
2696 url = document.url();
2697 }
2698
2699 Referrer::Client(url)
2701 } else {
2702 Referrer::Client(self.get_url())
2704 }
2705 }
2706
2707 pub(crate) fn as_window(&self) -> &Window {
2709 self.downcast::<Window>().expect("expected a Window scope")
2710 }
2711
2712 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
2714 if let Some(window) = self.downcast::<Window>() {
2715 return window.Document().insecure_requests_policy();
2716 }
2717 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2718 return worker.insecure_requests_policy();
2719 }
2720 debug!("unsupported global, defaulting insecure requests policy to DoNotUpgrade");
2721 InsecureRequestsPolicy::DoNotUpgrade
2722 }
2723
2724 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
2726 self.downcast::<Window>()
2727 .is_some_and(|window| window.Document().has_trustworthy_ancestor_origin())
2728 }
2729
2730 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
2732 self.downcast::<Window>().is_some_and(|window| {
2733 window
2734 .Document()
2735 .has_trustworthy_ancestor_or_current_origin()
2736 })
2737 }
2738
2739 pub(crate) fn report_an_exception(&self, cx: SafeJSContext, error: HandleValue, can_gc: CanGc) {
2741 let error_info = crate::dom::bindings::error::ErrorInfo::from_value(error, cx, can_gc);
2752 self.report_an_error(error_info, error, can_gc);
2758 }
2759
2760 pub(crate) fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue, can_gc: CanGc) {
2762 if self.in_error_reporting_mode.get() {
2764 return;
2765 }
2766
2767 self.in_error_reporting_mode.set(true);
2769
2770 let event = ErrorEvent::new(
2776 self,
2777 atom!("error"),
2778 EventBubbles::DoesNotBubble,
2779 EventCancelable::Cancelable,
2780 error_info.message.as_str().into(),
2781 error_info.filename.as_str().into(),
2782 error_info.lineno,
2783 error_info.column,
2784 value,
2785 can_gc,
2786 );
2787
2788 let not_handled = event
2789 .upcast::<Event>()
2790 .fire(self.upcast::<EventTarget>(), can_gc);
2791
2792 self.in_error_reporting_mode.set(false);
2794
2795 if not_handled {
2797 if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2803 dedicated.forward_error_to_worker_object(error_info);
2804 } else if self.is::<Window>() {
2805 if let Some(ref chan) = self.devtools_chan {
2807 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2808 self.pipeline_id,
2809 PageError {
2810 type_: "PageError".to_string(),
2811 error_message: error_info.message.clone(),
2812 source_name: error_info.filename.clone(),
2813 line_text: "".to_string(), line_number: error_info.lineno,
2815 column_number: error_info.column,
2816 category: "script".to_string(),
2817 time_stamp: SystemTime::now()
2818 .duration_since(UNIX_EPOCH)
2819 .unwrap_or_default()
2820 .as_millis() as u64,
2821 error: true,
2822 warning: false,
2823 exception: true,
2824 strict: false,
2825 private: false,
2826 },
2827 ));
2828 }
2829 }
2830 }
2831 }
2832
2833 pub(crate) fn resource_threads(&self) -> &ResourceThreads {
2835 &self.resource_threads
2836 }
2837
2838 pub(crate) fn core_resource_thread(&self) -> CoreResourceThread {
2840 self.resource_threads().sender()
2841 }
2842
2843 pub(crate) fn storage_threads(&self) -> &StorageThreads {
2845 &self.storage_threads
2846 }
2847
2848 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
2852 if let Some(window) = self.downcast::<Window>() {
2853 Some(window.event_loop_sender())
2854 } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2855 dedicated.event_loop_sender()
2856 } else if let Some(service_worker) = self.downcast::<ServiceWorkerGlobalScope>() {
2857 Some(service_worker.event_loop_sender())
2858 } else {
2859 unreachable!(
2860 "Tried to access event loop sender for incompatible \
2861 GlobalScope (PaintWorklet or DissimilarOriginWindow)"
2862 );
2863 }
2864 }
2865
2866 pub(crate) fn task_manager(&self) -> &TaskManager {
2868 let shared_canceller = self
2869 .downcast::<WorkerGlobalScope>()
2870 .map(WorkerGlobalScope::shared_task_canceller);
2871 self.task_manager.get_or_init(|| {
2872 TaskManager::new(
2873 self.event_loop_sender(),
2874 self.pipeline_id(),
2875 shared_canceller,
2876 )
2877 })
2878 }
2879
2880 pub(crate) fn evaluate_js_on_global_with_result(
2882 &self,
2883 code: Cow<'_, str>,
2884 rval: MutableHandleValue,
2885 fetch_options: ScriptFetchOptions,
2886 script_base_url: ServoUrl,
2887 can_gc: CanGc,
2888 introduction_type: Option<&'static CStr>,
2889 ) -> Result<(), JavaScriptEvaluationError> {
2890 let source_code = SourceCode::Text(Rc::new(DOMString::from_string(code.into_owned())));
2891 self.evaluate_script_on_global_with_result(
2892 &source_code,
2893 "",
2894 rval,
2895 1,
2896 fetch_options,
2897 script_base_url,
2898 can_gc,
2899 introduction_type,
2900 )
2901 }
2902
2903 #[expect(unsafe_code)]
2905 #[allow(clippy::too_many_arguments)]
2906 pub(crate) fn evaluate_script_on_global_with_result(
2907 &self,
2908 code: &SourceCode,
2909 filename: &str,
2910 rval: MutableHandleValue,
2911 line_number: u32,
2912 fetch_options: ScriptFetchOptions,
2913 script_base_url: ServoUrl,
2914 can_gc: CanGc,
2915 introduction_type: Option<&'static CStr>,
2916 ) -> Result<(), JavaScriptEvaluationError> {
2917 let cx = GlobalScope::get_cx();
2918
2919 let ar = enter_realm(self);
2920
2921 let _aes = AutoEntryScript::new(self);
2922
2923 unsafe {
2924 rooted!(in(*cx) let mut compiled_script = std::ptr::null_mut::<JSScript>());
2925 match code {
2926 SourceCode::Text(text_code) => {
2927 let mut options = CompileOptionsWrapper::new_raw(*cx, filename, line_number);
2928 if let Some(introduction_type) = introduction_type {
2929 options.set_introduction_type(introduction_type);
2930 }
2931
2932 debug!("compiling dom string");
2933 compiled_script.set(Compile1(
2934 *cx,
2935 options.ptr,
2936 &mut transform_str_to_source_text(&text_code.str()),
2937 ));
2938
2939 if compiled_script.is_null() {
2940 debug!("error compiling Dom string");
2941 report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc);
2942 return Err(JavaScriptEvaluationError::CompilationFailure);
2943 }
2944 },
2945 SourceCode::Compiled(pre_compiled_script) => {
2946 let options = InstantiateOptions {
2947 skipFilenameValidation: false,
2948 hideScriptFromDebugger: false,
2949 deferDebugMetadata: false,
2950 eagerDelazificationStrategy_: DelazificationOption::OnDemandOnly,
2951 };
2952 let script = InstantiateGlobalStencil(
2953 *cx,
2954 &options,
2955 *pre_compiled_script.source_code,
2956 ptr::null_mut(),
2957 );
2958 compiled_script.set(script);
2959 },
2960 };
2961
2962 assert!(!compiled_script.is_null());
2963
2964 rooted!(in(*cx) let mut script_private = UndefinedValue());
2965 JS_GetScriptPrivate(*compiled_script, script_private.handle_mut());
2966
2967 if script_private.is_undefined() {
2970 debug!("Set script private for {}", script_base_url);
2971
2972 let module_script_data = Rc::new(ModuleScript::new(
2973 script_base_url,
2974 fetch_options,
2975 None,
2979 ));
2980
2981 SetScriptPrivate(
2982 *compiled_script,
2983 &PrivateValue(Rc::into_raw(module_script_data) as *const _),
2984 );
2985 }
2986
2987 let result = JS_ExecuteScript(*cx, compiled_script.handle(), rval);
2988
2989 if !result {
2990 debug!("error evaluating Dom string");
2991 let error_info =
2992 take_and_report_pending_exception_for_api(cx, InRealm::Entered(&ar), can_gc);
2993 return Err(JavaScriptEvaluationError::EvaluationFailure(error_info));
2994 }
2995
2996 maybe_resume_unwind();
2997 Ok(())
2998 }
2999 }
3000
3001 pub(crate) fn schedule_callback(
3003 &self,
3004 callback: OneshotTimerCallback,
3005 duration: Duration,
3006 ) -> OneshotTimerHandle {
3007 self.timers()
3008 .schedule_callback(callback, duration, self.timer_source())
3009 }
3010
3011 pub(crate) fn unschedule_callback(&self, handle: OneshotTimerHandle) {
3012 self.timers().unschedule_callback(handle);
3013 }
3014
3015 pub(crate) fn set_timeout_or_interval(
3017 &self,
3018 callback: TimerCallback,
3019 arguments: Vec<HandleValue>,
3020 timeout: Duration,
3021 is_interval: IsInterval,
3022 can_gc: CanGc,
3023 ) -> Fallible<i32> {
3024 self.timers().set_timeout_or_interval(
3025 self,
3026 callback,
3027 arguments,
3028 timeout,
3029 is_interval,
3030 self.timer_source(),
3031 can_gc,
3032 )
3033 }
3034
3035 pub(crate) fn clear_timeout_or_interval(&self, handle: i32) {
3036 self.timers().clear_timeout_or_interval(self, handle);
3037 }
3038
3039 pub(crate) fn fire_timer(&self, handle: TimerEventId, can_gc: CanGc) {
3040 self.timers().fire_timer(handle, self, can_gc);
3041 }
3042
3043 pub(crate) fn resume(&self) {
3044 self.timers().resume();
3045 }
3046
3047 pub(crate) fn suspend(&self) {
3048 self.timers().suspend();
3049 }
3050
3051 pub(crate) fn slow_down_timers(&self) {
3052 self.timers().slow_down();
3053 }
3054
3055 pub(crate) fn speed_up_timers(&self) {
3056 self.timers().speed_up();
3057 }
3058
3059 fn timer_source(&self) -> TimerSource {
3060 if self.is::<Window>() {
3061 return TimerSource::FromWindow(self.pipeline_id());
3062 }
3063 if self.is::<WorkerGlobalScope>() {
3064 return TimerSource::FromWorker;
3065 }
3066 unreachable!();
3067 }
3068
3069 pub(crate) fn can_continue_running(&self) -> bool {
3072 if self.is::<Window>() {
3073 return ScriptThread::can_continue_running();
3074 }
3075 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3076 return !worker.is_closing();
3077 }
3078
3079 true
3081 }
3082
3083 pub(crate) fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
3085 if let Some(window) = self.downcast::<Window>() {
3086 window.perform_a_microtask_checkpoint(can_gc);
3087 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3088 worker.perform_a_microtask_checkpoint(can_gc);
3089 }
3090 }
3091
3092 pub(crate) fn enqueue_microtask(&self, job: Microtask) {
3094 if self.is::<Window>() {
3095 ScriptThread::enqueue_microtask(job);
3096 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3097 worker.enqueue_microtask(job);
3098 }
3099 }
3100
3101 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
3105 if let Some(window) = self.downcast::<Window>() {
3106 return window.new_script_pair();
3107 }
3108 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3109 return worker.new_script_pair();
3110 }
3111 unreachable!();
3112 }
3113
3114 pub(crate) fn process_event(&self, msg: CommonScriptMsg, can_gc: CanGc) -> bool {
3118 if self.is::<Window>() {
3119 return ScriptThread::process_event(msg, can_gc);
3120 }
3121 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3122 return worker.process_event(msg);
3123 }
3124 unreachable!();
3125 }
3126
3127 pub(crate) fn runtime_handle(&self) -> ParentRuntime {
3128 if self.is::<Window>() {
3129 ScriptThread::runtime_handle()
3130 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3131 worker.runtime_handle()
3132 } else {
3133 unreachable!()
3134 }
3135 }
3136
3137 #[expect(unsafe_code)]
3141 pub(crate) fn current() -> Option<DomRoot<Self>> {
3142 let cx = Runtime::get()?;
3143 unsafe {
3144 let global = CurrentGlobalOrNull(cx.as_ptr());
3145 if global.is_null() {
3146 None
3147 } else {
3148 Some(global_scope_from_global(global, cx.as_ptr()))
3149 }
3150 }
3151 }
3152
3153 pub(crate) fn entry() -> DomRoot<Self> {
3157 entry_global()
3158 }
3159
3160 pub(crate) fn incumbent() -> Option<DomRoot<Self>> {
3164 incumbent_global()
3165 }
3166
3167 pub(crate) fn performance(&self) -> DomRoot<Performance> {
3168 if let Some(window) = self.downcast::<Window>() {
3169 return window.Performance();
3170 }
3171 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3172 return worker.Performance();
3173 }
3174 unreachable!();
3175 }
3176
3177 pub(crate) fn supported_performance_entry_types(
3179 &self,
3180 cx: SafeJSContext,
3181 retval: MutableHandleValue,
3182 can_gc: CanGc,
3183 ) {
3184 self.frozen_supported_performance_entry_types.get_or_init(
3185 || {
3186 EntryType::VARIANTS
3187 .iter()
3188 .map(|t| DOMString::from(t.as_str()))
3189 .collect()
3190 },
3191 cx,
3192 retval,
3193 can_gc,
3194 );
3195 }
3196
3197 pub(crate) fn get_https_state(&self) -> HttpsState {
3198 self.https_state.get()
3199 }
3200
3201 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
3202 self.https_state.set(https_state);
3203 }
3204
3205 pub(crate) fn inherited_secure_context(&self) -> Option<bool> {
3206 self.inherited_secure_context
3207 }
3208
3209 pub(crate) fn is_secure_context(&self) -> bool {
3211 if Some(false) == self.inherited_secure_context {
3216 return false;
3217 }
3218 match self.top_level_creation_url() {
3221 None => {
3222 assert!(
3224 self.downcast::<WorkerGlobalScope>().is_some() ||
3225 self.downcast::<WorkletGlobalScope>().is_some()
3226 );
3227 true
3228 },
3229 Some(top_level_creation_url) => {
3230 assert!(self.downcast::<Window>().is_some());
3231 if top_level_creation_url.scheme() == "blob" &&
3235 Some(true) == self.inherited_secure_context
3236 {
3237 return true;
3238 }
3239 top_level_creation_url.is_potentially_trustworthy()
3240 },
3241 }
3242 }
3243
3244 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
3246 if self.downcast::<Window>().is_some() || self.downcast::<WorkerGlobalScope>().is_some() {
3247 return self.policy_container().csp_list;
3248 }
3249 None
3251 }
3252
3253 pub(crate) fn status_code(&self) -> Option<u16> {
3254 if let Some(window) = self.downcast::<Window>() {
3255 return window.Document().status_code();
3256 }
3257 None
3258 }
3259
3260 #[cfg(feature = "webgpu")]
3261 pub(crate) fn wgpu_id_hub(&self) -> Arc<IdentityHub> {
3262 self.gpu_id_hub.clone()
3263 }
3264
3265 #[cfg(feature = "webgpu")]
3266 pub(crate) fn add_gpu_device(&self, device: &GPUDevice) {
3267 self.gpu_devices
3268 .borrow_mut()
3269 .insert(device.id(), WeakRef::new(device));
3270 }
3271
3272 #[cfg(feature = "webgpu")]
3273 pub(crate) fn remove_gpu_device(&self, device: WebGPUDevice) {
3274 let device = self
3275 .gpu_devices
3276 .borrow_mut()
3277 .remove(&device)
3278 .expect("GPUDevice should still be in devices hashmap");
3279 assert!(device.root().is_none())
3280 }
3281
3282 #[cfg(feature = "webgpu")]
3283 pub(crate) fn gpu_device_lost(
3284 &self,
3285 device: WebGPUDevice,
3286 reason: DeviceLostReason,
3287 msg: String,
3288 ) {
3289 let reason = match reason {
3290 DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown,
3291 DeviceLostReason::Destroyed => GPUDeviceLostReason::Destroyed,
3292 };
3293 let _ac = enter_realm(self);
3294 if let Some(device) = self
3295 .gpu_devices
3296 .borrow_mut()
3297 .get_mut(&device)
3298 .expect("GPUDevice should still be in devices hashmap")
3299 .root()
3300 {
3301 device.lose(reason, msg);
3302 }
3303 }
3304
3305 #[cfg(feature = "webgpu")]
3306 pub(crate) fn handle_uncaptured_gpu_error(
3307 &self,
3308 device: WebGPUDevice,
3309 error: webgpu_traits::Error,
3310 ) {
3311 if let Some(gpu_device) = self
3312 .gpu_devices
3313 .borrow()
3314 .get(&device)
3315 .and_then(|device| device.root())
3316 {
3317 gpu_device.fire_uncaptured_error(error);
3318 } else {
3319 warn!("Recived error for lost GPUDevice!")
3320 }
3321 }
3322
3323 pub(crate) fn current_group_label(&self) -> Option<DOMString> {
3324 self.console_group_stack
3325 .borrow()
3326 .last()
3327 .map(|label| DOMString::from(format!("[{}]", label)))
3328 }
3329
3330 pub(crate) fn push_console_group(&self, group: DOMString) {
3331 self.console_group_stack.borrow_mut().push(group);
3332 }
3333
3334 pub(crate) fn pop_console_group(&self) {
3335 let _ = self.console_group_stack.borrow_mut().pop();
3336 }
3337
3338 pub(crate) fn increment_console_count(&self, label: &DOMString) -> usize {
3339 *self
3340 .console_count_map
3341 .borrow_mut()
3342 .entry(label.clone())
3343 .and_modify(|e| *e += 1)
3344 .or_insert(1)
3345 }
3346
3347 pub(crate) fn reset_console_count(&self, label: &DOMString) -> Result<(), ()> {
3348 match self.console_count_map.borrow_mut().get_mut(label) {
3349 Some(value) => {
3350 *value = 0;
3351 Ok(())
3352 },
3353 None => Err(()),
3354 }
3355 }
3356
3357 pub(crate) fn dynamic_module_list(&self) -> RefMut<'_, DynamicModuleList> {
3358 self.dynamic_modules.borrow_mut()
3359 }
3360
3361 pub(crate) fn structured_clone(
3362 &self,
3363 cx: SafeJSContext,
3364 value: HandleValue,
3365 options: RootedTraceableBox<StructuredSerializeOptions>,
3366 retval: MutableHandleValue,
3367 can_gc: CanGc,
3368 ) -> Fallible<()> {
3369 let mut rooted = CustomAutoRooter::new(
3370 options
3371 .transfer
3372 .iter()
3373 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
3374 .collect(),
3375 );
3376 let guard = CustomAutoRooterGuard::new(*cx, &mut rooted);
3377
3378 let data = structuredclone::write(cx, value, Some(guard))?;
3379
3380 structuredclone::read(self, data, retval, can_gc)?;
3381
3382 Ok(())
3383 }
3384
3385 pub(crate) fn fetch<Listener: FetchResponseListener>(
3386 &self,
3387 request_builder: RequestBuilder,
3388 context: Listener,
3389 task_source: SendableTaskSource,
3390 ) {
3391 let network_listener = NetworkListener::new(context, task_source);
3392 self.fetch_with_network_listener(request_builder, network_listener);
3393 }
3394
3395 pub(crate) fn fetch_with_network_listener<Listener: FetchResponseListener>(
3396 &self,
3397 request_builder: RequestBuilder,
3398 network_listener: NetworkListener<Listener>,
3399 ) {
3400 fetch_async(
3401 &self.core_resource_thread(),
3402 request_builder,
3403 None,
3404 network_listener.into_callback(),
3405 );
3406 }
3407
3408 pub(crate) fn unminify_js(&self) -> bool {
3409 self.unminified_js_dir.is_some()
3410 }
3411
3412 pub(crate) fn unminified_js_dir(&self) -> Option<String> {
3413 self.unminified_js_dir.clone()
3414 }
3415
3416 pub(crate) fn set_byte_length_queuing_strategy_size(&self, function: Rc<Function>) {
3417 if self
3418 .byte_length_queuing_strategy_size_function
3419 .set(function)
3420 .is_err()
3421 {
3422 warn!("byte length queuing strategy size function is set twice.");
3423 };
3424 }
3425
3426 pub(crate) fn get_byte_length_queuing_strategy_size(&self) -> Option<Rc<Function>> {
3427 self.byte_length_queuing_strategy_size_function
3428 .get()
3429 .cloned()
3430 }
3431
3432 pub(crate) fn set_count_queuing_strategy_size(&self, function: Rc<Function>) {
3433 if self
3434 .count_queuing_strategy_size_function
3435 .set(function)
3436 .is_err()
3437 {
3438 warn!("count queuing strategy size function is set twice.");
3439 };
3440 }
3441
3442 pub(crate) fn get_count_queuing_strategy_size(&self) -> Option<Rc<Function>> {
3443 self.count_queuing_strategy_size_function.get().cloned()
3444 }
3445
3446 pub(crate) fn add_notification_permission_request_callback(
3447 &self,
3448 callback_id: String,
3449 callback: Rc<NotificationPermissionCallback>,
3450 ) {
3451 self.notification_permission_request_callback_map
3452 .borrow_mut()
3453 .insert(callback_id, callback.clone());
3454 }
3455
3456 pub(crate) fn remove_notification_permission_request_callback(
3457 &self,
3458 callback_id: String,
3459 ) -> Option<Rc<NotificationPermissionCallback>> {
3460 self.notification_permission_request_callback_map
3461 .borrow_mut()
3462 .remove(&callback_id)
3463 }
3464
3465 pub(crate) fn trusted_types(&self, can_gc: CanGc) -> DomRoot<TrustedTypePolicyFactory> {
3466 if let Some(window) = self.downcast::<Window>() {
3467 return window.TrustedTypes(can_gc);
3468 }
3469 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3470 return worker.TrustedTypes(can_gc);
3471 }
3472 unreachable!();
3473 }
3474
3475 pub(crate) fn append_reporting_observer(&self, reporting_observer: &ReportingObserver) {
3476 if let Some(window) = self.downcast::<Window>() {
3477 return window.append_reporting_observer(DomRoot::from_ref(reporting_observer));
3478 }
3479 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3480 return worker.append_reporting_observer(DomRoot::from_ref(reporting_observer));
3481 }
3482 unreachable!();
3483 }
3484
3485 pub(crate) fn remove_reporting_observer(&self, reporting_observer: &ReportingObserver) {
3486 if let Some(window) = self.downcast::<Window>() {
3487 return window.remove_reporting_observer(reporting_observer);
3488 }
3489 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3490 return worker.remove_reporting_observer(reporting_observer);
3491 }
3492 unreachable!();
3493 }
3494
3495 pub(crate) fn registered_reporting_observers(&self) -> Vec<DomRoot<ReportingObserver>> {
3496 if let Some(window) = self.downcast::<Window>() {
3497 return window.registered_reporting_observers();
3498 }
3499 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3500 return worker.registered_reporting_observers();
3501 }
3502 unreachable!();
3503 }
3504
3505 pub(crate) fn append_report(&self, report: Report) {
3506 if let Some(window) = self.downcast::<Window>() {
3507 return window.append_report(report);
3508 }
3509 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3510 return worker.append_report(report);
3511 }
3512 unreachable!();
3513 }
3514
3515 pub(crate) fn buffered_reports(&self) -> Vec<Report> {
3516 if let Some(window) = self.downcast::<Window>() {
3517 return window.buffered_reports();
3518 }
3519 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3520 return worker.buffered_reports();
3521 }
3522 unreachable!();
3523 }
3524
3525 pub(crate) fn import_map(&self) -> Ref<'_, ImportMap> {
3526 self.import_map.borrow()
3527 }
3528
3529 pub(crate) fn import_map_mut(&self) -> RefMut<'_, ImportMap> {
3530 self.import_map.borrow_mut()
3531 }
3532
3533 pub(crate) fn resolved_module_set(&self) -> Ref<'_, HashSet<ResolvedModule>> {
3534 self.resolved_module_set.borrow()
3535 }
3536
3537 pub(crate) fn resolved_module_set_mut(&self) -> RefMut<'_, HashSet<ResolvedModule>> {
3538 self.resolved_module_set.borrow_mut()
3539 }
3540
3541 pub(crate) fn add_module_to_resolved_module_set(
3543 &self,
3544 base_url: &str,
3545 specifier: &str,
3546 specifier_url: Option<ServoUrl>,
3547 ) {
3548 if self.is::<Window>() {
3551 let record =
3555 ResolvedModule::new(base_url.to_owned(), specifier.to_owned(), specifier_url);
3556 self.resolved_module_set.borrow_mut().insert(record);
3558 }
3559 }
3560
3561 pub(crate) fn run_a_classic_script(
3563 &self,
3564 script: &ScriptOrigin,
3565 line_number: u32,
3566 introduction_type: Option<&'static CStr>,
3567 can_gc: CanGc,
3568 ) {
3569 if !self.can_run_script() {
3572 return;
3573 }
3574
3575 rooted!(in(*GlobalScope::get_cx()) let mut rval = UndefinedValue());
3577 _ = self.evaluate_script_on_global_with_result(
3578 &script.code,
3579 script.url.as_str(),
3580 rval.handle_mut(),
3581 line_number,
3582 script.fetch_options.clone(),
3583 script.url.clone(),
3584 can_gc,
3585 introduction_type,
3586 );
3587 }
3588
3589 fn can_run_script(&self) -> bool {
3591 if let Some(window) = self.downcast::<Window>() {
3602 let doc = window.Document();
3603 doc.is_fully_active() ||
3604 !doc.has_active_sandboxing_flag(
3605 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
3606 )
3607 } else {
3608 true
3609 }
3610 }
3611
3612 pub(crate) fn run_steps_after_a_timeout<F>(
3616 &self,
3617 ordering_identifier: DOMString,
3618 milliseconds: i64,
3619 completion_steps: F,
3620 ) -> i32
3621 where
3622 F: 'static + FnOnce(&GlobalScope, CanGc),
3623 {
3624 let timers = self.timers();
3625
3626 let timer_key = timers.fresh_runsteps_key();
3628
3629 let start_time = timers.now_for_runsteps();
3631
3632 let ms = milliseconds.max(0) as u64;
3634 let delay = std::time::Duration::from_millis(ms);
3635 let deadline = start_time + delay;
3636 timers.runsteps_set_active(timer_key, deadline);
3637
3638 let callback = crate::timers::OneshotTimerCallback::RunStepsAfterTimeout {
3641 timer_key,
3643 ordering_id: ordering_identifier,
3645 milliseconds: ms,
3647 completion: Box::new(completion_steps),
3649 };
3650 let _ = self.schedule_callback(callback, delay);
3651
3652 timer_key
3654 }
3655}
3656
3657#[expect(unsafe_code)]
3659unsafe fn global_scope_from_global(
3660 global: *mut JSObject,
3661 cx: *mut JSContext,
3662) -> DomRoot<GlobalScope> {
3663 unsafe {
3664 assert!(!global.is_null());
3665 let clasp = get_object_class(global);
3666 assert_ne!(
3667 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3668 0
3669 );
3670 root_from_object(global, cx).unwrap()
3671 }
3672}
3673
3674#[expect(unsafe_code)]
3676unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot<GlobalScope> {
3677 assert!(!global.is_null());
3678 let clasp = unsafe { get_object_class(global) };
3679
3680 unsafe {
3681 assert_ne!(
3682 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3683 0
3684 );
3685 }
3686
3687 root_from_object_static(global).unwrap()
3688}
3689
3690#[expect(unsafe_code)]
3691impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
3692 unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot<Self> {
3693 unsafe { GlobalScope::from_context(cx, realm) }
3694 }
3695
3696 fn from_current_realm(realm: &'_ CurrentRealm) -> DomRoot<Self> {
3697 GlobalScope::from_current_realm(realm)
3698 }
3699
3700 fn get_cx() -> SafeJSContext {
3701 GlobalScope::get_cx()
3702 }
3703
3704 unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
3705 unsafe { GlobalScope::from_object(obj) }
3706 }
3707
3708 fn from_reflector(reflector: &impl DomObject, realm: InRealm) -> DomRoot<Self> {
3709 GlobalScope::from_reflector(reflector, realm)
3710 }
3711
3712 fn origin(&self) -> &MutableOrigin {
3713 GlobalScope::origin(self)
3714 }
3715
3716 fn incumbent() -> Option<DomRoot<Self>> {
3717 GlobalScope::incumbent()
3718 }
3719
3720 fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
3721 GlobalScope::perform_a_microtask_checkpoint(self, can_gc)
3722 }
3723
3724 fn get_url(&self) -> ServoUrl {
3725 self.get_url()
3726 }
3727
3728 fn is_secure_context(&self) -> bool {
3729 self.is_secure_context()
3730 }
3731}