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