1use std::borrow::Cow;
6use std::cell::{Cell, OnceCell, Ref, RefCell};
7use std::collections::hash_map::Entry;
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::ffi::CStr;
10use std::mem;
11use std::ops::{Deref, Index};
12use std::rc::Rc;
13use std::sync::Arc;
14use std::sync::atomic::{AtomicBool, Ordering};
15use std::thread::JoinHandle;
16use std::time::{Duration, Instant};
17
18use content_security_policy::CspList;
19use crossbeam_channel::Sender;
20#[cfg(feature = "devtools")]
21use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, get_time_stamp};
22use dom_struct::dom_struct;
23use embedder_traits::{
24 ConsoleLogLevel, EmbedderMsg, JavaScriptEvaluationError, ScriptToEmbedderChan,
25};
26use fonts::FontContext;
27use js::context::{JSContext, NoGC};
28use js::jsapi::{GetNonCCWObjectGlobal, HandleObject, Heap, JSObject};
29use js::jsval::UndefinedValue;
30use js::panic::maybe_resume_unwind;
31use js::realm::CurrentRealm;
32use js::rust::wrappers2::{Compile1, CurrentGlobalOrNull, JS_ExecuteScript};
33use js::rust::{
34 HandleValue, MutableHandleValue, ParentRuntime, get_object_class, transform_str_to_source_text,
35};
36use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
37use net_traits::blob_url_store::BlobBuf;
38use net_traits::filemanager_thread::{
39 FileManagerResult, FileManagerThreadMsg, ReadFileProgress, RelativePos,
40};
41use net_traits::image_cache::ImageCache;
42use net_traits::policy_container::PolicyContainer;
43use net_traits::request::{
44 InsecureRequestsPolicy, Origin as RequestOrigin, Referrer, RequestBuilder, RequestClient,
45};
46use net_traits::{CoreResourceMsg, CoreResourceThread, ReferrerPolicy, ResourceThreads};
47use profile_traits::{
48 generic_callback as profile_generic_callback, generic_channel as profile_generic_channel,
49 mem as profile_mem, time as profile_time,
50};
51use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
52use script_bindings::callback::{OwnerWindow, RootedCallback, TracedCallback};
53use script_bindings::cell::{DomRefCell, RefMut};
54use script_bindings::domstring::TracedDOMString;
55use script_bindings::interfaces::GlobalScopeHelpers;
56use script_bindings::reflector::DomObject;
57use script_bindings::settings_stack::run_a_script;
58use servo_base::generic_channel;
59use servo_base::generic_channel::{GenericCallback, GenericSend};
60use servo_base::id::{
61 BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId,
62 ServiceWorkerId, ServiceWorkerRegistrationId, TEST_WEBVIEW_ID, WebViewId,
63};
64use servo_config::pref;
65use servo_constellation_traits::{
66 BlobData, BlobImpl, BroadcastChannelMsg, ConstellationInterest, FileBlob, MessagePortImpl,
67 PortMessageTask, ScriptToConstellationChan, ScriptToConstellationMessage,
68 ScriptToConstellationSender, ServiceWorkerState,
69};
70use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
71use storage_traits::StorageThreads;
72use strum::VariantArray;
73use timers::{TimerEventRequest, TimerId};
74use uuid::Uuid;
75#[cfg(feature = "webgpu")]
76use webgpu_traits::{DeviceLostReason, WebGPUDevice};
77
78use crate::DomTypeHolder;
79use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
80use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods;
81use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
82use crate::dom::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
83use crate::dom::bindings::codegen::Bindings::NotificationBinding::NotificationPermissionCallback;
84use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
85 PermissionName, PermissionState,
86};
87#[cfg(feature = "webgpu")]
88use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
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};
92#[cfg(feature = "js_backtrace")]
93use crate::dom::bindings::error::LAST_EXCEPTION_BACKTRACE;
94use crate::dom::bindings::error::{
95 ErrorInfo, Fallible, report_pending_exception, take_and_report_pending_exception_for_api,
96};
97use crate::dom::bindings::frozenarray::CachedFrozenArray;
98use crate::dom::bindings::inheritance::Castable;
99use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
100use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
101use crate::dom::bindings::settings_stack::{entry_global, incumbent_global};
102use crate::dom::bindings::str::DOMString;
103use crate::dom::bindings::structuredclone;
104use crate::dom::bindings::trace::{CustomTraceable, HashMapTracedValues};
105use crate::dom::bindings::weakref::{DOMTracker, WeakRef};
106use crate::dom::blob::Blob;
107use crate::dom::dedicatedworkerglobalscope::{
108 DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
109};
110use crate::dom::dissimilaroriginwindow::DissimilarOriginWindow;
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::globalscope::auto_close_worker::AutoCloseWorker;
117use crate::dom::globalscope::broadcastchannel::BroadcastChannel;
118use crate::dom::globalscope::listeners::{
119 BlobInfo, BlobResult, BlobTracker, BroadcastChannelState, BroadcastListener, FileListener,
120 FileListenerCallback, FileListenerState, FileListenerTarget, ManagedMessagePort,
121 MessageListener, MessagePortState,
122};
123use crate::dom::idbfactory::IDBFactory;
124use crate::dom::messageport::MessagePort;
125use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
126use crate::dom::performance::performance::Performance;
127use crate::dom::performance::performanceentry::EntryType;
128use crate::dom::promise::RootedPromise;
129use crate::dom::readablestream::{CrossRealmTransformReadable, ReadableStream};
130use crate::dom::serviceworker::ServiceWorker;
131use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
132use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
133use crate::dom::sharedworkerglobalscope::SharedWorkerGlobalScope;
134use crate::dom::stream::underlyingsourcecontainer::UnderlyingSourceType;
135use crate::dom::stream::writablestream::CrossRealmTransformWritable;
136use crate::dom::transformstream::CrossRealmTransform;
137#[cfg(feature = "devtools")]
138use crate::dom::types::DebuggerGlobalScope;
139use crate::dom::types::{AbortSignal, MessageEvent};
140#[cfg(feature = "webgpu")]
141use crate::dom::webgpu::gpudevice::GPUDevice;
142#[cfg(feature = "webgpu")]
143use crate::dom::webgpu::identityhub::IdentityHub;
144use crate::dom::window::Window;
145use crate::dom::workerglobalscope::WorkerGlobalScope;
146use crate::dom::workletglobalscope::WorkletGlobalScope;
147use crate::event_loop::script_thread::{ScriptThread, with_script_thread};
148use crate::event_loop::timers::{
149 IsInterval, JsTimerTaskData, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers,
150 RootedInternalTimerCallback, TimerCallback, TimerEventId, TimerSource,
151};
152use crate::fetch::fetch::FetchGroup;
153use crate::fetch::network_listener::{FetchResponseListener, NetworkListener};
154use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
155use crate::realms::enter_auto_realm;
156use crate::runtime::job_queue::MicrotaskRunnable;
157use crate::runtime::script_runtime::ThreadSafeJSContext;
158use crate::scripting::fetching_options::ScriptFetchOptions;
159use crate::scripting::import_map::ImportMap;
160use crate::scripting::script_execution::{
161 ScriptOptions, fill_compile_options, maybe_associate_with_script,
162};
163use crate::scripting::script_module::{ModuleRequest, ModuleStatus, ResolvedModule};
164use crate::tasks::task_manager::TaskManager;
165use crate::tasks::task_source::SendableTaskSource;
166use crate::unminify::unminified_path;
167
168#[dom_struct]
169pub(crate) struct GlobalScope {
170 eventtarget: EventTarget,
171
172 message_port_state: DomRefCell<MessagePortState>,
174
175 broadcast_channel_state: DomRefCell<BroadcastChannelState>,
177
178 #[no_trace]
182 constellation_interest_counts: RefCell<FxHashMap<ConstellationInterest, usize>>,
183
184 blob_state: DomRefCell<HashMapTracedValues<BlobId, BlobInfo, FxBuildHasher>>,
186
187 registration_map: DomRefCell<
189 HashMapTracedValues<
190 ServiceWorkerRegistrationId,
191 Dom<ServiceWorkerRegistration>,
192 FxBuildHasher,
193 >,
194 >,
195
196 indexeddb: MutNullableDom<IDBFactory>,
198
199 worker_map: DomRefCell<HashMapTracedValues<ServiceWorkerId, Dom<ServiceWorker>, FxBuildHasher>>,
201
202 console_timers: DomRefCell<HashMap<TracedDOMString, Instant>>,
204
205 #[no_trace]
207 #[cfg(feature = "devtools")]
208 devtools_chan: Option<GenericCallback<ScriptToDevtoolsControlMsg>>,
209
210 #[no_trace]
212 mem_profiler_chan: profile_mem::ProfilerChan,
213
214 #[no_trace]
216 time_profiler_chan: profile_time::ProfilerChan,
217
218 #[no_trace]
220 script_to_constellation_sender: ScriptToConstellationSender,
221
222 #[no_trace]
224 script_to_embedder_chan: ScriptToEmbedderChan,
225
226 in_error_reporting_mode: Cell<bool>,
228
229 #[no_trace]
232 resource_threads: ResourceThreads,
233
234 #[no_trace]
237 storage_threads: StorageThreads,
238
239 #[no_trace]
241 creation_url: DomRefCell<ServoUrl>,
242
243 #[no_trace]
245 top_level_creation_url: DomRefCell<Option<ServoUrl>>,
246
247 permission_state_invocation_results: DomRefCell<HashMap<PermissionName, PermissionState>>,
249
250 list_auto_close_worker: DomRefCell<Vec<AutoCloseWorker>>,
252
253 event_source_tracker: DOMTracker<EventSource>,
255
256 abort_signal_dependents: DomRefCell<FxHashSet<Dom<AbortSignal>>>,
259
260 #[ignore_malloc_size_of = "mozjs"]
269 #[allow(clippy::vec_box)]
272 uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
273
274 #[ignore_malloc_size_of = "mozjs"]
280 #[allow(clippy::vec_box)]
283 consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
284
285 #[ignore_malloc_size_of = "defined in wgpu"]
287 #[no_trace]
288 #[cfg(feature = "webgpu")]
289 gpu_id_hub: Arc<IdentityHub>,
290
291 #[cfg(feature = "webgpu")]
293 gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>, FxBuildHasher>>,
294
295 #[ignore_malloc_size_of = "mozjs"]
297 frozen_supported_performance_entry_types: CachedFrozenArray,
298
299 console_group_stack: DomRefCell<Vec<TracedDOMString>>,
301
302 console_count_map: DomRefCell<HashMap<TracedDOMString, usize>>,
306
307 inherited_secure_context: Option<bool>,
309
310 unminified_js_dir: Option<String>,
313
314 byte_length_queuing_strategy_size_function: OnceCell<TracedCallback<Function>>,
319
320 count_queuing_strategy_size_function: OnceCell<TracedCallback<Function>>,
325
326 notification_permission_request_callback_map:
327 DomRefCell<HashMap<String, TracedCallback<NotificationPermissionCallback>>>,
328
329 import_map: DomRefCell<ImportMap>,
334
335 resolved_module_set: DomRefCell<HashSet<ResolvedModule>>,
337
338 fetch_group: DomRefCell<FetchGroup>,
340}
341
342impl GlobalScope {
343 pub(crate) fn tear_down(&self) {
345 self.fetch_group_mut().terminate(self);
346 self.close_event_sources();
347 self.with_module_map(|module_map| std::mem::take(&mut *module_map.borrow_mut()));
348 }
349
350 pub(crate) fn obtain_storage_key_for_non_storage_purposes(&self) -> ImmutableOrigin {
352 self.origin().immutable().clone()
355 }
356
357 pub(crate) fn obtain_storage_key(&self) -> Option<ImmutableOrigin> {
359 let key = self.obtain_storage_key_for_non_storage_purposes();
362
363 if let ImmutableOrigin::Opaque(_) = key {
365 return None;
366 }
367
368 if !pref!(dom_indexeddb_enabled) {
370 return None;
371 }
372
373 Some(key)
375 }
376
377 pub(crate) fn webview_id(&self) -> Option<WebViewId> {
378 if let Some(window) = self.downcast::<Window>() {
379 return Some(window.webview_id());
380 }
381 if let Some(worker) = self.downcast::<DedicatedWorkerGlobalScope>() {
382 return Some(worker.webview_id());
383 }
384 if let Some(worker) = self.downcast::<SharedWorkerGlobalScope>() {
385 return Some(worker.webview_id());
386 }
387 None
389 }
390
391 #[allow(clippy::too_many_arguments)]
392 pub(crate) fn new_inherited(
393 #[cfg(feature = "devtools")] devtools_chan: Option<
394 GenericCallback<ScriptToDevtoolsControlMsg>,
395 >,
396 mem_profiler_chan: profile_mem::ProfilerChan,
397 time_profiler_chan: profile_time::ProfilerChan,
398 script_to_constellation_sender: ScriptToConstellationSender,
399 script_to_embedder_chan: ScriptToEmbedderChan,
400 resource_threads: ResourceThreads,
401 storage_threads: StorageThreads,
402 creation_url: ServoUrl,
403 top_level_creation_url: Option<ServoUrl>,
404 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
405 inherited_secure_context: Option<bool>,
406 unminify_js: bool,
407 ) -> Self {
408 let resource_threads_sender = resource_threads.sender();
409 Self {
410 message_port_state: DomRefCell::new(MessagePortState::UnManaged),
411 broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged),
412 constellation_interest_counts: Default::default(),
413 blob_state: Default::default(),
414 eventtarget: EventTarget::new_inherited(),
415 registration_map: DomRefCell::new(HashMapTracedValues::new_fx()),
416 indexeddb: Default::default(),
417 worker_map: DomRefCell::new(HashMapTracedValues::new_fx()),
418 console_timers: DomRefCell::new(Default::default()),
419 #[cfg(feature = "devtools")]
420 devtools_chan,
421 mem_profiler_chan,
422 time_profiler_chan,
423 script_to_constellation_sender,
424 script_to_embedder_chan,
425 in_error_reporting_mode: Default::default(),
426 resource_threads,
427 storage_threads,
428 creation_url: DomRefCell::new(creation_url),
429 top_level_creation_url: DomRefCell::new(top_level_creation_url),
430 permission_state_invocation_results: Default::default(),
431 list_auto_close_worker: Default::default(),
432 event_source_tracker: DOMTracker::new(),
433 abort_signal_dependents: Default::default(),
434 uncaught_rejections: Default::default(),
435 consumed_rejections: Default::default(),
436 #[cfg(feature = "webgpu")]
437 gpu_id_hub,
438 #[cfg(feature = "webgpu")]
439 gpu_devices: DomRefCell::new(HashMapTracedValues::new_fx()),
440 frozen_supported_performance_entry_types: CachedFrozenArray::new(),
441 console_group_stack: DomRefCell::new(Vec::new()),
442 console_count_map: Default::default(),
443 inherited_secure_context,
444 unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
445 byte_length_queuing_strategy_size_function: OnceCell::new(),
446 count_queuing_strategy_size_function: OnceCell::new(),
447 notification_permission_request_callback_map: Default::default(),
448 import_map: Default::default(),
449 resolved_module_set: Default::default(),
450 fetch_group: DomRefCell::new(FetchGroup::new(resource_threads_sender)),
451 }
452 }
453
454 pub(super) fn port_router_id(&self) -> Option<MessagePortRouterId> {
456 if let MessagePortState::Managed(id, _message_ports) = &*self.message_port_state.borrow() {
457 Some(*id)
458 } else {
459 None
460 }
461 }
462
463 pub(super) fn is_managing_port(&self, port_id: &MessagePortId) -> bool {
465 if let MessagePortState::Managed(_router_id, message_ports) =
466 &*self.message_port_state.borrow()
467 {
468 return message_ports.contains_key(port_id);
469 }
470 false
471 }
472
473 fn with_timers<T>(&self, f: impl FnOnce(&OneshotTimers) -> T) -> T {
474 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
475 f(worker.timers())
476 } else if let Some(window) = self.downcast::<Window>() {
477 window.with_timers(f)
478 } else {
479 unreachable!("Unsupported global type retrieving timers")
480 }
481 }
482
483 pub(crate) fn font_context(&self) -> Arc<FontContext> {
484 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
485 worker.font_context()
486 } else if let Some(window) = self.downcast::<Window>() {
487 window.font_context()
488 } else {
489 unreachable!("Unsupported global type retrieving font context")
490 }
491 }
492
493 #[allow(clippy::too_many_arguments)]
495 pub(crate) fn get_serviceworker_registration(
496 &self,
497 cx: &mut JSContext,
498 script_url: &ServoUrl,
499 scope: &ServoUrl,
500 registration_id: ServiceWorkerRegistrationId,
501 installing_worker: Option<ServiceWorkerId>,
502 _waiting_worker: Option<ServiceWorkerId>,
503 _active_worker: Option<ServiceWorkerId>,
504 ) -> DomRoot<ServiceWorkerRegistration> {
505 {
507 let registrations = self.registration_map.borrow_mut();
508
509 if let Some(registration) = registrations.get(®istration_id) {
510 return DomRoot::from_ref(&**registration);
512 }
513 }
514
515 let new_registration =
517 ServiceWorkerRegistration::new(cx, self, scope.clone(), registration_id);
518
519 if let Some(worker_id) = installing_worker {
521 let worker = self.get_serviceworker(cx, script_url, scope, worker_id);
522 new_registration.set_installing(&worker);
523 }
524
525 self.registration_map
531 .borrow_mut()
532 .insert(registration_id, Dom::from_ref(&*new_registration));
533
534 new_registration
536 }
537
538 pub(crate) fn update_service_worker_state(
540 &self,
541 cx: &mut js::context::JSContext,
542 state: ServiceWorkerState,
543 worker_id: ServiceWorkerId,
544 ) {
545 let object_map = self.worker_map.borrow();
547
548 let Some(worker) = object_map.get(&worker_id) else {
550 return;
552 };
553
554 worker.set_state(state);
556
557 worker.upcast().fire_event(cx, atom!("statechange"));
559 }
560
561 pub(crate) fn get_serviceworker(
563 &self,
564 cx: &mut JSContext,
565 script_url: &ServoUrl,
566 scope: &ServoUrl,
567 worker_id: ServiceWorkerId,
568 ) -> DomRoot<ServiceWorker> {
569 {
571 let workers = self.worker_map.borrow_mut();
572
573 if let Some(worker) = workers.get(&worker_id) {
574 return DomRoot::from_ref(&**worker);
576 }
577 }
578
579 let new_worker = ServiceWorker::new(cx, self, script_url.clone(), scope.clone(), worker_id);
582
583 self.worker_map
585 .borrow_mut()
586 .insert(worker_id, Dom::from_ref(&*new_worker));
587
588 new_worker
590 }
591
592 pub(super) fn complete_port_transfer(
594 &self,
595 cx: &mut JSContext,
596 port_id: MessagePortId,
597 tasks: VecDeque<PortMessageTask>,
598 disentangled: bool,
599 ) {
600 let should_start = if let MessagePortState::Managed(_id, message_ports) =
601 &mut *self.message_port_state.borrow_mut()
602 {
603 match message_ports.get_mut(&port_id) {
604 None => {
605 panic!("complete_port_transfer called for an unknown port.");
606 },
607 Some(managed_port) => {
608 if managed_port.pending {
609 panic!("CompleteTransfer msg received for a pending port.");
610 }
611 if let Some(port_impl) = managed_port.port_impl.as_mut() {
612 port_impl.complete_transfer(tasks);
613 if disentangled {
614 port_impl.disentangle();
615 managed_port.dom_port.disentangle();
616 }
617 port_impl.enabled()
618 } else {
619 panic!("managed-port has no port-impl.");
620 }
621 },
622 }
623 } else {
624 panic!("complete_port_transfer called for an unknown port.");
625 };
626 if should_start {
627 self.start_message_port(cx, &port_id);
628 }
629 }
630
631 pub(super) fn try_complete_disentanglement(&self, cx: &mut JSContext, port_id: MessagePortId) {
634 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
635 &mut *self.message_port_state.borrow_mut()
636 {
637 if let Some(managed_port) = message_ports.get_mut(&port_id) {
638 if managed_port.pending {
639 unreachable!("CompleteDisentanglement msg received for a pending port.");
640 }
641 let port_impl = managed_port
642 .port_impl
643 .as_mut()
644 .expect("managed-port has no port-impl.");
645 port_impl.disentangle();
646 managed_port.dom_port.as_rooted()
647 } else {
648 return;
652 }
653 } else {
654 return;
655 };
656
657 dom_port.upcast().fire_event(cx, atom!("close"));
659
660 let res = self.script_to_constellation_chan().send(
661 ScriptToConstellationMessage::DisentanglePorts(port_id, None),
662 );
663 if res.is_err() {
664 warn!("Sending DisentanglePorts failed");
665 }
666 }
667
668 pub(crate) fn perform_a_dom_garbage_collection_checkpoint(&self) {
670 self.perform_a_message_port_garbage_collection_checkpoint();
671 self.perform_a_blob_garbage_collection_checkpoint();
672 self.perform_a_broadcast_channel_garbage_collection_checkpoint();
673 self.perform_an_abort_signal_garbage_collection_checkpoint();
674 }
675
676 pub(crate) fn remove_web_messaging_and_dedicated_workers_infra(&self) {
679 self.remove_message_ports_router();
680 self.remove_broadcast_channel_router();
681
682 self.list_auto_close_worker
686 .borrow_mut()
687 .drain(0..)
688 .for_each(drop);
689 }
690
691 fn remove_message_ports_router(&self) {
694 if let MessagePortState::Managed(router_id, _message_ports) =
695 &*self.message_port_state.borrow()
696 {
697 let _ = self.script_to_constellation_chan().send(
698 ScriptToConstellationMessage::RemoveMessagePortRouter(*router_id),
699 );
700 }
701 *self.message_port_state.borrow_mut() = MessagePortState::UnManaged;
702 }
703
704 fn remove_broadcast_channel_router(&self) {
707 if let BroadcastChannelState::Managed(router_id, _channels) =
708 &*self.broadcast_channel_state.borrow()
709 {
710 let _ = self.script_to_constellation_chan().send(
711 ScriptToConstellationMessage::RemoveBroadcastChannelRouter(
712 *router_id,
713 self.origin().immutable().clone(),
714 ),
715 );
716 }
717 *self.broadcast_channel_state.borrow_mut() = BroadcastChannelState::UnManaged;
718 }
719
720 pub(crate) fn disentangle_port(&self, cx: &mut JSContext, port: &MessagePort) {
722 let initiator_port = port.message_port_id();
723 let Some(other_port) = port.disentangle() else {
725 return;
729 };
730
731 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
734 &mut *self.message_port_state.borrow_mut()
735 {
736 let mut dom_port = None;
737 for port_id in &[initiator_port, &other_port] {
738 match message_ports.get_mut(port_id) {
739 None => {
740 continue;
741 },
742 Some(managed_port) => {
743 let port_impl = managed_port
744 .port_impl
745 .as_mut()
746 .expect("managed-port has no port-impl.");
747 managed_port.dom_port.disentangle();
748 port_impl.disentangle();
749
750 if **port_id == other_port {
751 dom_port = Some(managed_port.dom_port.as_rooted())
752 }
753 },
754 }
755 }
756 dom_port
757 } else {
758 panic!("disentangle_port called on a global not managing any ports.");
759 };
760
761 if let Some(dom_port) = dom_port {
764 dom_port.upcast().fire_event(cx, atom!("close"));
765 }
766
767 let chan = self.script_to_constellation_chan();
768 let initiator_port = *initiator_port;
769 self.task_manager()
770 .port_message_queue()
771 .queue(task!(post_message: move || {
772 let res = chan.send(ScriptToConstellationMessage::DisentanglePorts(initiator_port, Some(other_port)));
775 if res.is_err() {
776 warn!("Sending DisentanglePorts failed");
777 }
778 }));
779 }
780
781 pub(crate) fn entangle_ports(&self, port1: MessagePortId, port2: MessagePortId) {
783 if let MessagePortState::Managed(_id, message_ports) =
784 &mut *self.message_port_state.borrow_mut()
785 {
786 for (port_id, entangled_id) in &[(port1, port2), (port2, port1)] {
787 match message_ports.get_mut(port_id) {
788 None => {
789 return warn!("entangled_ports called on a global not managing the port.");
790 },
791 Some(managed_port) => {
792 if let Some(port_impl) = managed_port.port_impl.as_mut() {
793 managed_port.dom_port.entangle(*entangled_id);
794 port_impl.entangle(*entangled_id);
795 } else {
796 panic!("managed-port has no port-impl.");
797 }
798 },
799 }
800 }
801 } else {
802 panic!("entangled_ports called on a global not managing any ports.");
803 }
804
805 let _ = self
806 .script_to_constellation_chan()
807 .send(ScriptToConstellationMessage::EntanglePorts(port1, port2));
808 }
809
810 pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl {
812 if let MessagePortState::Managed(_id, message_ports) =
813 &mut *self.message_port_state.borrow_mut()
814 {
815 let mut port_impl = message_ports
816 .remove(port_id)
817 .map(|ref mut managed_port| {
818 managed_port
819 .port_impl
820 .take()
821 .expect("Managed port doesn't have a port-impl.")
822 })
823 .expect("mark_port_as_transferred called on a global not managing the port.");
824 port_impl.set_has_been_shipped();
825 let _ = self
826 .script_to_constellation_chan()
827 .send(ScriptToConstellationMessage::MessagePortShipped(*port_id));
828 port_impl
829 } else {
830 panic!("mark_port_as_transferred called on a global not managing any ports.");
831 }
832 }
833
834 pub(crate) fn start_message_port(&self, cx: &mut JSContext, port_id: &MessagePortId) {
836 let (message_buffer, dom_port) = if let MessagePortState::Managed(_id, message_ports) =
837 &mut *self.message_port_state.borrow_mut()
838 {
839 let (message_buffer, dom_port) = match message_ports.get_mut(port_id) {
840 None => panic!("start_message_port called on a unknown port."),
841 Some(managed_port) => {
842 if let Some(port_impl) = managed_port.port_impl.as_mut() {
843 (port_impl.start(), managed_port.dom_port.as_rooted())
844 } else {
845 panic!("managed-port has no port-impl.");
846 }
847 },
848 };
849 (message_buffer, dom_port)
850 } else {
851 return warn!("start_message_port called on a global not managing any ports.");
852 };
853 if let Some(message_buffer) = message_buffer {
854 for task in message_buffer {
855 self.route_task_to_port(cx, *port_id, task);
856 }
857 if dom_port.disentangled() {
858 dom_port.upcast().fire_event(cx, atom!("close"));
861
862 let res = self.script_to_constellation_chan().send(
863 ScriptToConstellationMessage::DisentanglePorts(*port_id, None),
864 );
865 if res.is_err() {
866 warn!("Sending DisentanglePorts failed");
867 }
868 }
869 }
870 }
871
872 pub(crate) fn close_message_port(&self, port_id: &MessagePortId) {
874 if let MessagePortState::Managed(_id, message_ports) =
875 &mut *self.message_port_state.borrow_mut() &&
876 let Some(managed_port) = message_ports.get_mut(port_id)
877 {
878 if let Some(port_impl) = managed_port.port_impl.as_mut() {
879 port_impl.close();
880 managed_port.explicitly_closed = true;
881 } else {
882 panic!("managed-port has no port-impl.");
883 }
884 } else {
885 warn!("close_message_port called on a global not managing any ports.")
886 }
887 }
888
889 pub(crate) fn post_messageport_msg(&self, port_id: MessagePortId, task: PortMessageTask) {
892 if let MessagePortState::Managed(_id, message_ports) =
893 &mut *self.message_port_state.borrow_mut()
894 {
895 let entangled_port = match message_ports.get_mut(&port_id) {
896 None => panic!("post_messageport_msg called on an unknown port."),
897 Some(managed_port) => {
898 if let Some(port_impl) = managed_port.port_impl.as_mut() {
899 port_impl.entangled_port_id()
900 } else {
901 panic!("managed-port has no port-impl.");
902 }
903 },
904 };
905 if let Some(entangled_id) = entangled_port {
906 let this = Trusted::new(self);
908 self.task_manager()
909 .port_message_queue()
910 .queue(task!(post_message: move |cx| {
911 let global = this.root();
912 global.route_task_to_port(cx, entangled_id, task);
915 }));
916 }
917 } else {
918 warn!("post_messageport_msg called on a global not managing any ports.");
919 }
920 }
921
922 fn re_route_port_task(&self, port_id: MessagePortId, task: PortMessageTask) {
925 let _ = self.script_to_constellation_chan().send(
926 ScriptToConstellationMessage::RerouteMessagePort(port_id, task),
927 );
928 }
929
930 pub(crate) fn schedule_broadcast(&self, msg: BroadcastChannelMsg, channel_id: &Uuid) {
933 self.broadcast_message_event(msg.clone(), Some(channel_id));
935
936 if let BroadcastChannelState::Managed(router_id, _) =
937 &*self.broadcast_channel_state.borrow()
938 {
939 let _ = self.script_to_constellation_chan().send(
944 ScriptToConstellationMessage::ScheduleBroadcast(*router_id, msg),
945 );
946 } else {
947 panic!("Attemps to broadcast a message via global not managing any channels.");
948 }
949 }
950
951 pub(crate) fn broadcast_message_event(
954 &self,
955 event: BroadcastChannelMsg,
956 channel_id: Option<&Uuid>,
957 ) {
958 let BroadcastChannelState::Managed(_, channels) = &*self.broadcast_channel_state.borrow()
959 else {
960 return;
961 };
962
963 let BroadcastChannelMsg {
964 data,
965 origin,
966 channel_name,
967 } = event;
968
969 if let Some(worker) = self.downcast::<WorkerGlobalScope>() &&
973 worker.is_closing()
974 {
975 return;
976 }
977
978 if let Some(window) = self.downcast::<Window>() &&
980 !window.Document().is_fully_active()
981 {
982 return;
983 }
984
985 let Some(channels) = channels.get(&channel_name.into()) else {
987 return;
988 };
989 channels
990 .iter()
991 .filter(|channel| {
992 if let Some(id) = channel_id {
995 channel.id() != id
996 } else {
997 true
998 }
999 })
1000 .map(|channel| DomRoot::from_ref(&**channel))
1001 .for_each(|channel| {
1004 let data = data.clone_for_broadcast();
1005 let origin = origin.clone();
1006
1007 let channel = Trusted::new(&*channel);
1010 let global = Trusted::new(self);
1011 self.task_manager().dom_manipulation_task_source().queue(
1012 task!(process_pending_port_messages: move |cx| {
1013 let destination = channel.root();
1014 let global = global.root();
1015
1016 if destination.closed() {
1018 return;
1019 }
1020
1021 rooted!(&in(cx) let mut message = UndefinedValue());
1022
1023 if let Ok(ports) = structuredclone::read(cx, &global, data, message.handle_mut()) {
1025 MessageEvent::dispatch_jsval(
1027 cx,
1028 destination.upcast(),
1029 &global,
1030 message.handle(),
1031 Some(origin.ascii_serialization().as_ref()),
1032 None,
1033 ports,
1034 );
1035 } else {
1036 MessageEvent::dispatch_error(cx, destination.upcast(), &global);
1038 }
1039 })
1040 );
1041 });
1042 }
1043
1044 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
1046 if let Some(window) = self.downcast::<Window>() {
1047 return window.Document().encoding_parse_a_url(url);
1048 }
1049
1050 let base = self.api_base_url();
1052 base.join(url)
1053 }
1054
1055 pub(crate) fn note_cross_realm_transform_readable(
1059 &self,
1060 cross_realm_transform_readable: &CrossRealmTransformReadable,
1061 port_id: &MessagePortId,
1062 ) {
1063 let MessagePortState::Managed(_id, message_ports) =
1064 &mut *self.message_port_state.borrow_mut()
1065 else {
1066 unreachable!(
1067 "Cross realm transform readable must be called on a global managing ports"
1068 );
1069 };
1070
1071 let Some(managed_port) = message_ports.get_mut(port_id) else {
1072 unreachable!("Cross realm transform readable must match a managed port");
1073 };
1074
1075 managed_port.cross_realm_transform = Some(CrossRealmTransform::Readable(
1076 cross_realm_transform_readable.clone(),
1077 ));
1078 }
1079
1080 pub(crate) fn note_cross_realm_transform_writable(
1084 &self,
1085 cross_realm_transform_writable: &CrossRealmTransformWritable,
1086 port_id: &MessagePortId,
1087 ) {
1088 let MessagePortState::Managed(_id, message_ports) =
1089 &mut *self.message_port_state.borrow_mut()
1090 else {
1091 unreachable!(
1092 "Cross realm transform writable must be called on a global managing ports"
1093 );
1094 };
1095
1096 let Some(managed_port) = message_ports.get_mut(port_id) else {
1097 unreachable!("Cross realm transform writable must match a managed port");
1098 };
1099
1100 managed_port.cross_realm_transform = Some(CrossRealmTransform::Writable(
1101 cross_realm_transform_writable.clone(),
1102 ));
1103 }
1104
1105 pub(super) fn route_task_to_port(
1108 &self,
1109 cx: &mut JSContext,
1110 port_id: MessagePortId,
1111 task: PortMessageTask,
1112 ) {
1113 rooted!(&in(cx) let mut cross_realm_transform = None);
1114
1115 let should_dispatch = if let MessagePortState::Managed(_id, message_ports) =
1116 &mut *self.message_port_state.borrow_mut()
1117 {
1118 if !message_ports.contains_key(&port_id) {
1119 self.re_route_port_task(port_id, task);
1120 return;
1121 }
1122 match message_ports.get_mut(&port_id) {
1123 None => panic!("route_task_to_port called for an unknown port."),
1124 Some(managed_port) => {
1125 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1128 let to_dispatch = port_impl.handle_incoming(task).map(|to_dispatch| {
1129 (DomRoot::from_ref(&*managed_port.dom_port), to_dispatch)
1130 });
1131 cross_realm_transform.set(managed_port.cross_realm_transform.clone());
1132 to_dispatch
1133 } else {
1134 panic!("managed-port has no port-impl.");
1135 }
1136 },
1137 }
1138 } else {
1139 self.re_route_port_task(port_id, task);
1140 return;
1141 };
1142
1143 if let Some((dom_port, PortMessageTask { origin, data })) = should_dispatch {
1148 let message_event_target = dom_port.upcast();
1150
1151 rooted!(&in(cx) let mut message_clone = UndefinedValue());
1157
1158 let mut realm = enter_auto_realm(cx, self);
1159 let cx = &mut realm.current_realm();
1160
1161 run_a_script::<DomTypeHolder, _, _>(cx, self, |cx| {
1165 if let Ok(ports) = structuredclone::read(cx, self, data, message_clone.handle_mut())
1171 {
1172 if let Some(transform) = cross_realm_transform.deref().as_ref() {
1174 match transform {
1175 CrossRealmTransform::Readable(readable) => {
1178 readable.handle_message(
1179 cx,
1180 self,
1181 &dom_port,
1182 message_clone.handle(),
1183 );
1184 },
1185 CrossRealmTransform::Writable(writable) => {
1188 writable.handle_message(cx, self, message_clone.handle());
1189 },
1190 }
1191 } else {
1192 MessageEvent::dispatch_jsval(
1197 cx,
1198 message_event_target,
1199 self,
1200 message_clone.handle(),
1201 Some(origin.ascii_serialization().as_ref()),
1202 None,
1203 ports,
1204 );
1205 }
1206 } else if let Some(transform) = cross_realm_transform.deref().as_ref() {
1207 match transform {
1208 CrossRealmTransform::Readable(readable) => {
1211 readable.handle_error(cx, self, &dom_port);
1212 },
1213 CrossRealmTransform::Writable(writable) => {
1216 writable.handle_error(cx, self, &dom_port);
1217 },
1218 }
1219 } else {
1220 MessageEvent::dispatch_error(cx, message_event_target, self);
1224 }
1225 });
1226 }
1227 }
1228
1229 pub(crate) fn maybe_add_pending_ports(&self) {
1232 if let MessagePortState::Managed(router_id, message_ports) =
1233 &mut *self.message_port_state.borrow_mut()
1234 {
1235 let to_be_added: Vec<MessagePortId> = message_ports
1236 .iter()
1237 .filter_map(|(id, managed_port)| {
1238 if managed_port.pending {
1239 Some(*id)
1240 } else {
1241 None
1242 }
1243 })
1244 .collect();
1245 for id in to_be_added.iter() {
1246 let managed_port = message_ports
1247 .get_mut(id)
1248 .expect("Collected port-id to match an entry");
1249 if !managed_port.pending {
1250 panic!("Only pending ports should be found in to_be_added")
1251 }
1252 managed_port.pending = false;
1253 }
1254 let _ = self.script_to_constellation_chan().send(
1255 ScriptToConstellationMessage::CompleteMessagePortTransfer(*router_id, to_be_added),
1256 );
1257 } else {
1258 warn!("maybe_add_pending_ports called on a global not managing any ports.");
1259 }
1260 }
1261
1262 pub(crate) fn perform_a_message_port_garbage_collection_checkpoint(&self) {
1264 let is_empty = if let MessagePortState::Managed(_id, message_ports) =
1265 &mut *self.message_port_state.borrow_mut()
1266 {
1267 let to_be_removed: Vec<MessagePortId> = message_ports
1268 .iter()
1269 .filter_map(|(id, managed_port)| {
1270 if managed_port.explicitly_closed {
1271 Some(*id)
1272 } else {
1273 None
1274 }
1275 })
1276 .collect();
1277 for id in to_be_removed {
1278 message_ports.remove(&id);
1279 }
1280 message_ports.is_empty()
1284 } else {
1285 false
1286 };
1287 if is_empty {
1288 self.remove_message_ports_router();
1289 }
1290 }
1291
1292 pub(crate) fn perform_a_broadcast_channel_garbage_collection_checkpoint(&self) {
1296 let is_empty = if let BroadcastChannelState::Managed(router_id, channels) =
1297 &mut *self.broadcast_channel_state.borrow_mut()
1298 {
1299 channels.retain(|name, ref mut channels| {
1300 channels.retain(|chan| !chan.closed());
1301 if channels.is_empty() {
1302 let _ = self.script_to_constellation_chan().send(
1303 ScriptToConstellationMessage::RemoveBroadcastChannelNameInRouter(
1304 *router_id,
1305 name.to_string(),
1306 self.origin().immutable().clone(),
1307 ),
1308 );
1309 false
1310 } else {
1311 true
1312 }
1313 });
1314 channels.is_empty()
1315 } else {
1316 false
1317 };
1318 if is_empty {
1319 self.remove_broadcast_channel_router();
1320 }
1321 }
1322
1323 pub(crate) fn register_dependent_abort_signal(&self, signal: &AbortSignal) {
1326 self.abort_signal_dependents
1327 .borrow_mut()
1328 .insert(Dom::from_ref(signal));
1329 }
1330
1331 pub(crate) fn perform_an_abort_signal_garbage_collection_checkpoint(&self) {
1333 let mut set = self.abort_signal_dependents.borrow_mut();
1334
1335 set.retain(|dom_signal| dom_signal.must_keep_alive_for_gc());
1336 }
1337
1338 pub(crate) fn track_broadcast_channel(&self, dom_channel: &BroadcastChannel) {
1340 let mut current_state = self.broadcast_channel_state.borrow_mut();
1341
1342 if let BroadcastChannelState::UnManaged = &*current_state {
1343 let context = Trusted::new(self);
1344 let listener = BroadcastListener {
1345 task_source: self.task_manager().dom_manipulation_task_source().into(),
1346 context,
1347 };
1348 let broadcast_control_callback = GenericCallback::new(move |message| match message {
1349 Ok(msg) => listener.handle(msg),
1350 Err(err) => warn!("Error receiving a BroadcastChannelMsg: {:?}", err),
1351 })
1352 .expect("Could not generate callback");
1353 let router_id = BroadcastChannelRouterId::new();
1354 *current_state = BroadcastChannelState::Managed(router_id, HashMap::new());
1355 let _ = self.script_to_constellation_chan().send(
1356 ScriptToConstellationMessage::NewBroadcastChannelRouter(
1357 router_id,
1358 broadcast_control_callback,
1359 self.origin().immutable().clone(),
1360 ),
1361 );
1362 }
1363
1364 if let BroadcastChannelState::Managed(router_id, channels) = &mut *current_state {
1365 let entry = channels
1366 .entry(dom_channel.Name().traced())
1367 .or_insert_with(|| {
1368 let _ = self.script_to_constellation_chan().send(
1369 ScriptToConstellationMessage::NewBroadcastChannelNameInRouter(
1370 *router_id,
1371 String::from(dom_channel.Name()),
1372 self.origin().immutable().clone(),
1373 ),
1374 );
1375 VecDeque::new()
1376 });
1377 entry.push_back(Dom::from_ref(dom_channel));
1378 } else {
1379 panic!("track_broadcast_channel should have first switched the state to managed.");
1380 }
1381 }
1382
1383 pub(crate) fn track_message_port(
1385 &self,
1386 dom_port: &MessagePort,
1387 port_impl: Option<MessagePortImpl>,
1388 ) {
1389 let mut current_state = self.message_port_state.borrow_mut();
1390
1391 if let MessagePortState::UnManaged = &*current_state {
1392 let context = Trusted::new(self);
1394 let listener = MessageListener {
1395 task_source: self.task_manager().port_message_queue().into(),
1396 context,
1397 };
1398
1399 let port_control_callback = GenericCallback::new(move |message| match message {
1400 Ok(msg) => listener.notify(msg),
1401 Err(err) => warn!("Error receiving a MessagePortMsg: {:?}", err),
1402 })
1403 .expect("Could not create callback");
1404 let router_id = MessagePortRouterId::new();
1405 *current_state = MessagePortState::Managed(router_id, HashMapTracedValues::new_fx());
1406 let _ = self.script_to_constellation_chan().send(
1407 ScriptToConstellationMessage::NewMessagePortRouter(
1408 router_id,
1409 port_control_callback,
1410 ),
1411 );
1412 }
1413
1414 if let MessagePortState::Managed(router_id, message_ports) = &mut *current_state {
1415 if let Some(port_impl) = port_impl {
1416 message_ports.insert(
1420 *dom_port.message_port_id(),
1421 ManagedMessagePort {
1422 port_impl: Some(port_impl),
1423 dom_port: Dom::from_ref(dom_port),
1424 pending: true,
1425 explicitly_closed: false,
1426 cross_realm_transform: None,
1427 },
1428 );
1429
1430 let this = Trusted::new(self);
1433 self.task_manager().port_message_queue().queue(
1434 task!(process_pending_port_messages: move || {
1435 let target_global = this.root();
1436 target_global.maybe_add_pending_ports();
1437 }),
1438 );
1439 } else {
1440 let port_impl = MessagePortImpl::new(*dom_port.message_port_id());
1442 message_ports.insert(
1443 *dom_port.message_port_id(),
1444 ManagedMessagePort {
1445 port_impl: Some(port_impl),
1446 dom_port: Dom::from_ref(dom_port),
1447 pending: false,
1448 explicitly_closed: false,
1449 cross_realm_transform: None,
1450 },
1451 );
1452 let _ = self.script_to_constellation_chan().send(
1453 ScriptToConstellationMessage::NewMessagePort(
1454 *router_id,
1455 *dom_port.message_port_id(),
1456 ),
1457 );
1458 };
1459 } else {
1460 panic!("track_message_port should have first switched the state to managed.");
1461 }
1462 }
1463
1464 pub(crate) fn serialize_blob(&self, blob_id: &BlobId) -> BlobImpl {
1468 let bytes = self
1472 .get_blob_bytes(blob_id)
1473 .expect("Could not read bytes from blob as part of serialization steps.");
1474 let type_string = self.get_blob_type_string(blob_id);
1475
1476 BlobImpl::new_from_bytes(bytes, type_string)
1478 }
1479
1480 fn track_blob_info(&self, blob_info: BlobInfo, blob_id: BlobId) {
1481 self.blob_state.borrow_mut().insert(blob_id, blob_info);
1482 }
1483
1484 pub(crate) fn track_blob(&self, dom_blob: &Blob, blob_impl: BlobImpl) {
1486 let blob_id = blob_impl.blob_id();
1487
1488 let blob_info = BlobInfo {
1489 blob_impl,
1490 tracker: BlobTracker::Blob(WeakRef::new(dom_blob)),
1491 has_url: false,
1492 };
1493
1494 self.track_blob_info(blob_info, blob_id);
1495 }
1496
1497 pub(crate) fn track_file(&self, file: &File, blob_impl: BlobImpl) {
1499 let blob_id = blob_impl.blob_id();
1500
1501 let blob_info = BlobInfo {
1502 blob_impl,
1503 tracker: BlobTracker::File(WeakRef::new(file)),
1504 has_url: false,
1505 };
1506
1507 self.track_blob_info(blob_info, blob_id);
1508 }
1509
1510 fn perform_a_blob_garbage_collection_checkpoint(&self) {
1514 let mut blob_state = self.blob_state.borrow_mut();
1515 blob_state.0.retain(|_id, blob_info| {
1516 let garbage_collected = match &blob_info.tracker {
1517 BlobTracker::File(weak) => weak.root().is_none(),
1518 BlobTracker::Blob(weak) => weak.root().is_none(),
1519 };
1520 if garbage_collected && !blob_info.has_url {
1521 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1522 self.decrement_file_ref(f.get_id());
1523 }
1524 false
1525 } else {
1526 true
1527 }
1528 });
1529 }
1530
1531 pub(crate) fn clean_up_all_file_resources(&self) {
1534 self.blob_state
1535 .borrow_mut()
1536 .drain()
1537 .for_each(|(_id, blob_info)| {
1538 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1539 self.decrement_file_ref(f.get_id());
1540 }
1541 });
1542 }
1543
1544 fn decrement_file_ref(&self, id: Uuid) {
1545 let origin = self.origin().immutable().clone();
1546
1547 let (tx, rx) = profile_generic_channel::channel(self.time_profiler_chan().clone()).unwrap();
1548
1549 let msg = FileManagerThreadMsg::DecRef(id, origin, tx);
1550 self.send_to_file_manager(msg);
1551 let _ = rx.recv();
1552 }
1553
1554 pub(crate) fn get_blob_bytes(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1557 let parent = {
1558 match *self.get_blob_data(blob_id) {
1559 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1560 _ => None,
1561 }
1562 };
1563
1564 match parent {
1565 Some((parent_id, rel_pos)) => self.get_blob_bytes_non_sliced(&parent_id).map(|v| {
1566 let range = rel_pos.to_abs_range(v.len());
1567 v.index(range).to_vec()
1568 }),
1569 None => self.get_blob_bytes_non_sliced(blob_id),
1570 }
1571 }
1572
1573 pub(crate) fn get_blob_data<'a>(&'a self, blob_id: &BlobId) -> Ref<'a, BlobData> {
1578 Ref::map(self.blob_state.borrow(), |blob_state| {
1579 blob_state
1580 .get(blob_id)
1581 .expect("get_blob_impl called for a unknown blob")
1582 .blob_impl
1583 .blob_data()
1584 })
1585 }
1586
1587 fn get_blob_bytes_non_sliced(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1589 match *self.get_blob_data(blob_id) {
1590 BlobData::File(ref f) => {
1591 let (buffer, is_new_buffer) = match f.get_cache() {
1592 Some(bytes) => (bytes, false),
1593 None => {
1594 let bytes = self.read_file(f.get_id())?;
1595 (bytes, true)
1596 },
1597 };
1598
1599 if is_new_buffer {
1601 f.cache_bytes(buffer.clone());
1602 }
1603
1604 Ok(buffer)
1605 },
1606 BlobData::Memory(ref s) => Ok(s.clone()),
1607 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1608 }
1609 }
1610
1611 fn get_blob_bytes_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1618 let parent = {
1619 match *self.get_blob_data(blob_id) {
1620 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1621 _ => None,
1622 }
1623 };
1624
1625 match parent {
1626 Some((parent_id, rel_pos)) => {
1627 match self.get_blob_bytes_non_sliced_or_file_id(&parent_id) {
1628 BlobResult::Bytes(bytes) => {
1629 let range = rel_pos.to_abs_range(bytes.len());
1630 BlobResult::Bytes(bytes.index(range).to_vec())
1631 },
1632 res => res,
1633 }
1634 },
1635 None => self.get_blob_bytes_non_sliced_or_file_id(blob_id),
1636 }
1637 }
1638
1639 fn get_blob_bytes_non_sliced_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1645 match *self.get_blob_data(blob_id) {
1646 BlobData::File(ref f) => match f.get_cache() {
1647 Some(bytes) => BlobResult::Bytes(bytes),
1648 None => BlobResult::File(f.get_id(), f.get_size() as usize),
1649 },
1650 BlobData::Memory(ref s) => BlobResult::Bytes(s.clone()),
1651 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1652 }
1653 }
1654
1655 pub(crate) fn get_blob_type_string(&self, blob_id: &BlobId) -> String {
1657 let blob_state = self.blob_state.borrow();
1658 let blob_info = blob_state
1659 .get(blob_id)
1660 .expect("get_blob_type_string called for a unknown blob.");
1661 blob_info.blob_impl.type_string()
1662 }
1663
1664 pub(crate) fn get_blob_size(&self, blob_id: &BlobId) -> u64 {
1666 let parent = {
1667 match *self.get_blob_data(blob_id) {
1668 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1669 _ => None,
1670 }
1671 };
1672 match parent {
1673 Some((parent_id, rel_pos)) => {
1674 let parent_size = match *self.get_blob_data(&parent_id) {
1675 BlobData::File(ref f) => f.get_size(),
1676 BlobData::Memory(ref v) => v.len() as u64,
1677 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
1678 };
1679 rel_pos.to_abs_range(parent_size as usize).len() as u64
1680 },
1681 None => match *self.get_blob_data(blob_id) {
1682 BlobData::File(ref f) => f.get_size(),
1683 BlobData::Memory(ref v) => v.len() as u64,
1684 BlobData::Sliced(_, _) => {
1685 panic!("It was previously checked that this blob does not have a parent.")
1686 },
1687 },
1688 }
1689 }
1690
1691 pub(crate) fn get_blob_url_id(&self, blob_id: &BlobId) -> Uuid {
1692 let mut blob_state = self.blob_state.borrow_mut();
1693 let parent = {
1694 let blob_info = blob_state
1695 .get_mut(blob_id)
1696 .expect("get_blob_url_id called for a unknown blob.");
1697
1698 blob_info.has_url = true;
1700
1701 match blob_info.blob_impl.blob_data() {
1702 BlobData::Sliced(parent, rel_pos) => Some((*parent, *rel_pos)),
1703 _ => None,
1704 }
1705 };
1706 match parent {
1707 Some((parent_id, rel_pos)) => {
1708 let parent_info = blob_state
1709 .get_mut(&parent_id)
1710 .expect("Parent of blob whose url is requested is unknown.");
1711 let parent_file_id = self.promote(parent_info, false);
1712 let parent_size = match parent_info.blob_impl.blob_data() {
1713 BlobData::File(f) => f.get_size(),
1714 BlobData::Memory(v) => v.len() as u64,
1715 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
1716 };
1717 let parent_size = rel_pos.to_abs_range(parent_size as usize).len() as u64;
1718 let blob_info = blob_state
1719 .get_mut(blob_id)
1720 .expect("Blob whose url is requested is unknown.");
1721 self.create_sliced_url_id(blob_info, &parent_file_id, &rel_pos, parent_size)
1722 },
1723 None => {
1724 let blob_info = blob_state
1725 .get_mut(blob_id)
1726 .expect("Blob whose url is requested is unknown.");
1727 self.promote(blob_info, true)
1728 },
1729 }
1730 }
1731
1732 fn create_sliced_url_id(
1734 &self,
1735 blob_info: &mut BlobInfo,
1736 parent_file_id: &Uuid,
1737 rel_pos: &RelativePos,
1738 parent_len: u64,
1739 ) -> Uuid {
1740 let origin = self.origin().immutable().clone();
1741
1742 let (tx, rx) = profile_generic_channel::channel(self.time_profiler_chan().clone()).unwrap();
1743 let msg = FileManagerThreadMsg::AddSlicedURLEntry(*parent_file_id, *rel_pos, tx, origin);
1744 self.send_to_file_manager(msg);
1745 match rx.recv().expect("File manager thread is down.") {
1746 Ok(new_id) => {
1747 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
1748 new_id,
1749 None,
1750 None,
1751 rel_pos.to_abs_range(parent_len as usize).len() as u64,
1752 ));
1753
1754 new_id
1756 },
1757 Err(_) => {
1758 Uuid::new_v4()
1760 },
1761 }
1762 }
1763
1764 fn promote_memory_entry(
1768 &self,
1769 blob_info: &BlobInfo,
1770 blob_bytes: &[u8],
1771 set_valid: bool,
1772 ) -> Uuid {
1773 let origin = self.origin().immutable().clone();
1774 let blob_buf = BlobBuf {
1775 filename: None,
1776 type_string: blob_info.blob_impl.type_string(),
1777 size: blob_bytes.len() as u64,
1778 bytes: blob_bytes.to_vec(),
1779 };
1780 let id = Uuid::new_v4();
1781 let msg = FileManagerThreadMsg::PromoteMemory(id, blob_buf, set_valid, origin);
1782 self.send_to_file_manager(msg);
1783 id
1784 }
1785
1786 pub(crate) fn promote(&self, blob_info: &mut BlobInfo, set_valid: bool) -> Uuid {
1792 let mut bytes = vec![];
1793
1794 match blob_info.blob_impl.blob_data_mut() {
1795 BlobData::Sliced(_, _) => {
1796 panic!("Sliced blobs should use create_sliced_url_id instead of promote.");
1797 },
1798 BlobData::File(f) => {
1799 if set_valid {
1800 if let Some(cached_bytes) = f.get_cache() {
1803 return self.promote_memory_entry(blob_info, &cached_bytes, true);
1804 }
1805
1806 let origin = self.origin().immutable().clone();
1807 let (tx, rx) =
1808 profile_generic_channel::channel(self.time_profiler_chan().clone())
1809 .unwrap();
1810
1811 let msg = FileManagerThreadMsg::ActivateBlobURL(f.get_id(), tx, origin);
1812 self.send_to_file_manager(msg);
1813
1814 match rx.recv().unwrap() {
1815 Ok(_) => return f.get_id(),
1816 Err(_) => return Uuid::new_v4(),
1818 }
1819 } else {
1820 return f.get_id();
1822 }
1823 },
1824 BlobData::Memory(bytes_in) => mem::swap(bytes_in, &mut bytes),
1825 };
1826
1827 let id = self.promote_memory_entry(blob_info, &bytes, set_valid);
1828
1829 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
1830 id,
1831 None,
1832 Some(bytes.to_vec()),
1833 bytes.len() as u64,
1834 ));
1835
1836 id
1837 }
1838
1839 fn send_to_file_manager(&self, msg: FileManagerThreadMsg) {
1840 let resource_threads = self.resource_threads();
1841 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
1842 }
1843
1844 fn read_file(&self, id: Uuid) -> Result<Vec<u8>, ()> {
1845 let (chan, recv) = profile_generic_callback::GenericCallback::new_blocking(
1846 self.time_profiler_chan().clone(),
1847 )
1848 .expect("Couldn't create read_file callback");
1849
1850 self.send_msg(id, chan);
1851
1852 GlobalScope::read_msg(recv)
1853 }
1854
1855 pub(crate) fn get_blob_stream(
1857 &self,
1858 cx: &mut JSContext,
1859 blob_id: &BlobId,
1860 ) -> Fallible<DomRoot<ReadableStream>> {
1861 let (file_id, size) = match self.get_blob_bytes_or_file_id(blob_id) {
1862 BlobResult::Bytes(bytes) => {
1863 return ReadableStream::new_from_bytes_with_byte_reading_support(cx, self, bytes);
1865 },
1866 BlobResult::File(id, size) => (id, size),
1867 };
1868
1869 let stream = ReadableStream::new_with_external_underlying_byte_source(
1870 cx,
1871 self,
1872 UnderlyingSourceType::Blob(size),
1873 )?;
1874
1875 let trusted_stream = Trusted::new(&*stream);
1876 let mut file_listener = FileListener {
1877 state: Some(FileListenerState::Empty(FileListenerTarget::Stream(
1878 trusted_stream,
1879 ))),
1880 task_source: self.task_manager().file_reading_task_source().into(),
1881 };
1882
1883 let chan = profile_generic_callback::GenericCallback::new(move |msg| {
1884 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
1885 })
1886 .expect("Couldn't create get_blob_stream callback");
1887
1888 self.send_msg(file_id, chan);
1889
1890 Ok(stream)
1891 }
1892
1893 pub(crate) fn read_file_async(
1894 &self,
1895 id: Uuid,
1896 promise: &RootedPromise,
1897 callback: FileListenerCallback,
1898 ) {
1899 let trusted_promise = TrustedPromise::from(promise);
1900 let mut file_listener = FileListener {
1901 state: Some(FileListenerState::Empty(FileListenerTarget::Promise(
1902 trusted_promise,
1903 callback,
1904 ))),
1905 task_source: self.task_manager().file_reading_task_source().into(),
1906 };
1907
1908 let chan = profile_generic_callback::GenericCallback::new(move |msg| {
1909 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
1910 })
1911 .expect("Couldn't create read_file_async callback");
1912
1913 self.send_msg(id, chan);
1914 }
1915
1916 fn send_msg(
1917 &self,
1918 id: Uuid,
1919 chan: profile_generic_callback::GenericCallback<FileManagerResult<ReadFileProgress>>,
1920 ) {
1921 let resource_threads = self.resource_threads();
1922 let origin = self.origin().immutable().clone();
1923 let msg = FileManagerThreadMsg::ReadFile(chan, id, origin);
1924 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
1925 }
1926
1927 fn read_msg(
1928 receiver: profile_generic_channel::GenericReceiver<FileManagerResult<ReadFileProgress>>,
1929 ) -> Result<Vec<u8>, ()> {
1930 let mut bytes = vec![];
1931
1932 loop {
1933 match receiver.recv().unwrap() {
1934 Ok(ReadFileProgress::Meta(mut blob_buf)) => {
1935 bytes.append(&mut blob_buf.bytes);
1936 },
1937 Ok(ReadFileProgress::Partial(mut bytes_in)) => {
1938 bytes.append(&mut bytes_in);
1939 },
1940 Ok(ReadFileProgress::EOF) => {
1941 return Ok(bytes);
1942 },
1943 Err(_) => return Err(()),
1944 }
1945 }
1946 }
1947
1948 pub(crate) fn permission_state_invocation_results(
1949 &self,
1950 ) -> &DomRefCell<HashMap<PermissionName, PermissionState>> {
1951 &self.permission_state_invocation_results
1952 }
1953
1954 pub(crate) fn track_worker(
1955 &self,
1956 closing: Arc<AtomicBool>,
1957 animation_frame_provider_supported: Arc<AtomicBool>,
1958 join_handle: JoinHandle<()>,
1959 control_sender: Sender<DedicatedWorkerControlMsg>,
1960 context: ThreadSafeJSContext,
1961 ) {
1962 self.list_auto_close_worker
1963 .borrow_mut()
1964 .push(AutoCloseWorker {
1965 closing,
1966 animation_frame_provider_supported,
1967 join_handle: Some(join_handle),
1968 control_sender,
1969 context,
1970 });
1971 }
1972
1973 pub(crate) fn disable_owned_worker_animation_frame_providers(&self) {
1974 for worker in &*self.list_auto_close_worker.borrow() {
1975 worker
1976 .animation_frame_provider_supported
1977 .store(false, Ordering::SeqCst);
1978 let _ = worker
1979 .control_sender
1980 .send(DedicatedWorkerControlMsg::AnimationFrameProviderUnsupported);
1981 }
1982 }
1983
1984 pub(crate) fn track_event_source(&self, event_source: &EventSource) {
1985 self.event_source_tracker.track(event_source);
1986 }
1987
1988 pub(crate) fn close_event_sources(&self) -> bool {
1989 let mut canceled_any_fetch = false;
1990 self.event_source_tracker
1991 .for_each(
1992 |event_source: DomRoot<EventSource>| match event_source.ReadyState() {
1993 2 => {},
1994 _ => {
1995 event_source.cancel();
1996 canceled_any_fetch = true;
1997 },
1998 },
1999 );
2000 canceled_any_fetch
2001 }
2002
2003 #[expect(unsafe_code)]
2006 pub(crate) fn from_reflector<T: DomObject>(reflector: &T) -> DomRoot<Self> {
2007 unsafe { GlobalScope::from_object(*reflector.reflector().get_jsobject()) }
2008 }
2009
2010 #[expect(unsafe_code)]
2012 pub(crate) unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
2013 assert!(!obj.is_null());
2014 let global = unsafe { GetNonCCWObjectGlobal(obj) };
2015 unsafe { global_scope_from_global_static(global) }
2016 }
2017
2018 #[expect(unsafe_code)]
2022 pub(crate) fn from_current_realm(realm: &'_ mut CurrentRealm) -> DomRoot<Self> {
2023 let global = realm.global().get();
2024 unsafe { global_scope_from_global(realm, global) }
2025 }
2026
2027 pub(crate) fn add_uncaught_rejection(&self, rejection: HandleObject) {
2028 self.uncaught_rejections
2029 .borrow_mut()
2030 .push(Heap::boxed(rejection.get()));
2031 }
2032
2033 pub(crate) fn remove_uncaught_rejection(&self, rejection: HandleObject) {
2034 let mut uncaught_rejections = self.uncaught_rejections.borrow_mut();
2035
2036 if let Some(index) = uncaught_rejections
2037 .iter()
2038 .position(|promise| *promise == Heap::boxed(rejection.get()))
2039 {
2040 uncaught_rejections.remove(index);
2041 }
2042 }
2043
2044 #[allow(clippy::vec_box)]
2047 pub(crate) fn get_uncaught_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2049 &self.uncaught_rejections
2050 }
2051
2052 pub(crate) fn add_consumed_rejection(&self, rejection: HandleObject) {
2053 self.consumed_rejections
2054 .borrow_mut()
2055 .push(Heap::boxed(rejection.get()));
2056 }
2057
2058 pub(crate) fn remove_consumed_rejection(&self, rejection: HandleObject) {
2059 let mut consumed_rejections = self.consumed_rejections.borrow_mut();
2060
2061 if let Some(index) = consumed_rejections
2062 .iter()
2063 .position(|promise| *promise == Heap::boxed(rejection.get()))
2064 {
2065 consumed_rejections.remove(index);
2066 }
2067 }
2068
2069 #[allow(clippy::vec_box)]
2072 pub(crate) fn get_consumed_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2073 &self.consumed_rejections
2074 }
2075
2076 pub(crate) fn with_module_map<T>(
2077 &self,
2078 f: impl FnOnce(&DomRefCell<HashMapTracedValues<ModuleRequest, ModuleStatus>>) -> T,
2079 ) -> T {
2080 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2081 f(worker.module_map())
2082 } else if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2083 f(worklet.module_map())
2084 } else if let Some(window) = self.downcast::<Window>() {
2085 f(window.Document().module_map())
2086 } else {
2087 unreachable!("Unsupported global type retrieving module map")
2088 }
2089 }
2090
2091 pub(crate) fn time(&self, label: DOMString) -> Result<(), ()> {
2092 let mut timers = self.console_timers.borrow_mut();
2093 if timers.len() >= 10000 {
2094 return Err(());
2095 }
2096 match timers.entry(label.traced()) {
2097 Entry::Vacant(entry) => {
2098 entry.insert(Instant::now());
2099 Ok(())
2100 },
2101 Entry::Occupied(_) => Err(()),
2102 }
2103 }
2104
2105 pub(crate) fn time_log(&self, label: &DOMString) -> Result<u64, ()> {
2109 self.console_timers
2110 .borrow()
2111 .get(label)
2112 .ok_or(())
2113 .map(|&start| (Instant::now() - start).as_millis() as u64)
2114 }
2115
2116 pub(crate) fn time_end(&self, label: &DOMString) -> Result<u64, ()> {
2121 self.console_timers
2122 .borrow_mut()
2123 .remove(label)
2124 .ok_or(())
2125 .map(|start| (Instant::now() - start).as_millis() as u64)
2126 }
2127
2128 #[cfg(feature = "devtools")]
2131 pub(crate) fn devtools_chan(&self) -> Option<&GenericCallback<ScriptToDevtoolsControlMsg>> {
2132 self.devtools_chan.as_ref()
2133 }
2134
2135 pub(crate) fn mem_profiler_chan(&self) -> &profile_mem::ProfilerChan {
2137 &self.mem_profiler_chan
2138 }
2139
2140 pub(crate) fn time_profiler_chan(&self) -> &profile_time::ProfilerChan {
2142 &self.time_profiler_chan
2143 }
2144
2145 pub(crate) fn script_to_constellation_chan(&self) -> ScriptToConstellationChan {
2147 ScriptToConstellationChan {
2148 sender: self.script_to_constellation_sender.clone(),
2149 webview_id: self.webview_id().unwrap_or(TEST_WEBVIEW_ID),
2150 pipeline_id: self.pipeline_id(),
2151 }
2152 }
2153
2154 pub(crate) fn script_to_embedder_chan(&self) -> &ScriptToEmbedderChan {
2155 &self.script_to_embedder_chan
2156 }
2157
2158 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
2159 self.script_to_embedder_chan().send(msg).unwrap();
2160 }
2161
2162 pub(crate) fn pipeline_id(&self) -> PipelineId {
2164 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2165 worker.pipeline_id()
2166 } else if let Some(window) = self.downcast::<Window>() {
2167 window.pipeline_id()
2168 } else if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2169 worklet.pipeline_id()
2170 } else if let Some(dissimilar) = self.downcast::<DissimilarOriginWindow>() {
2171 dissimilar.pipeline_id()
2172 } else {
2173 #[cfg(feature = "devtools")]
2174 if let Some(debugger) = self.downcast::<DebuggerGlobalScope>() {
2175 return debugger.pipeline_id();
2176 }
2177 unreachable!("Unsupported global type for pipeline id")
2178 }
2179 }
2180
2181 pub(crate) fn register_interest(&self, interest: ConstellationInterest) {
2184 let mut counts = self.constellation_interest_counts.borrow_mut();
2185 let count = counts.entry(interest).or_insert(0);
2186 *count += 1;
2187 if *count == 1 {
2188 let _ = self
2189 .script_to_constellation_chan()
2190 .send(ScriptToConstellationMessage::RegisterInterest(interest));
2191 }
2192 }
2193
2194 pub(crate) fn unregister_interest(&self, interest: ConstellationInterest) {
2197 let mut counts = self.constellation_interest_counts.borrow_mut();
2198 if let Some(count) = counts.get_mut(&interest) {
2199 *count = count.saturating_sub(1);
2200 if *count == 0 {
2201 counts.remove(&interest);
2202 let _ = self
2203 .script_to_constellation_chan()
2204 .send(ScriptToConstellationMessage::UnregisterInterest(interest));
2205 }
2206 }
2207 }
2208
2209 pub(crate) fn origin(&self) -> MutableOrigin {
2211 if let Some(window) = self.downcast::<Window>() {
2212 window.origin()
2213 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2214 worker.origin()
2215 } else if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2216 worklet.origin()
2217 } else if let Some(dissimilar_window) = self.downcast::<DissimilarOriginWindow>() {
2218 dissimilar_window.origin()
2219 } else {
2220 #[cfg(feature = "devtools")]
2221 if let Some(debugger) = self.downcast::<DebuggerGlobalScope>() {
2222 return debugger.origin();
2223 }
2224 unreachable!("Unexpected origin check against global")
2225 }
2226 }
2227
2228 pub(crate) fn creation_url(&self) -> ServoUrl {
2230 self.creation_url.borrow().clone()
2231 }
2232
2233 pub(crate) fn set_creation_url(&self, creation_url: ServoUrl) {
2234 *self.creation_url.borrow_mut() = creation_url;
2235 }
2236
2237 pub(crate) fn top_level_creation_url(&self) -> Option<ServoUrl> {
2239 self.top_level_creation_url.borrow().clone()
2240 }
2241
2242 pub(crate) fn set_top_level_creation_url(&self, url: ServoUrl) {
2244 *self.top_level_creation_url.borrow_mut() = Some(url);
2245 }
2246
2247 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
2248 if let Some(window) = self.downcast::<Window>() {
2249 return window.image_cache();
2250 }
2251 if let Some(worker) = self.downcast::<DedicatedWorkerGlobalScope>() {
2252 return worker.image_cache();
2253 }
2254 if let Some(worker) = self.downcast::<SharedWorkerGlobalScope>() {
2255 return worker.image_cache();
2256 }
2257 if let Some(worker) = self.downcast::<PaintWorkletGlobalScope>() {
2258 return worker.image_cache();
2259 }
2260 unreachable!();
2261 }
2262
2263 pub(crate) fn schedule_timer(&self, request: TimerEventRequest) -> Option<TimerId> {
2267 match self.downcast::<WorkerGlobalScope>() {
2268 Some(worker_global) => Some(worker_global.timer_scheduler().schedule_timer(request)),
2269 _ => with_script_thread(|script_thread| Some(script_thread.schedule_timer(request))),
2270 }
2271 }
2272
2273 pub(crate) fn is_nested_browsing_context(&self) -> bool {
2275 self.downcast::<Window>()
2276 .is_some_and(|window| !window.is_top_level())
2277 }
2278
2279 pub(crate) fn total_size_of_in_flight_keep_alive_records(&self) -> u64 {
2285 let (sender, receiver) = generic_channel::channel().unwrap();
2286 if self
2287 .core_resource_thread()
2288 .send(CoreResourceMsg::TotalSizeOfInFlightKeepAliveRecords(
2289 self.pipeline_id(),
2290 sender,
2291 ))
2292 .is_err()
2293 {
2294 return u64::MAX;
2295 }
2296 receiver.recv().unwrap_or(u64::MAX)
2297 }
2298
2299 pub(crate) fn request_client(&self, no_gc: Option<&NoGC>) -> RequestClient {
2301 if let Some(window) = self.downcast::<Window>() {
2302 return window.request_client(no_gc);
2303 }
2304 RequestClient {
2305 preloaded_resources: Default::default(),
2306 policy_container: self.policy_container(),
2307 origin: RequestOrigin::Origin(self.origin().immutable().clone()),
2308 is_nested_browsing_context: false,
2309 insecure_requests_policy: self.insecure_requests_policy(),
2310 has_trustworthy_ancestor_origin: false,
2311 network_partition_key: None,
2312 }
2313 }
2314
2315 pub(crate) fn policy_container(&self) -> Arc<PolicyContainer> {
2317 if let Some(window) = self.downcast::<Window>() {
2318 return window.Document().policy_container().clone();
2319 }
2320 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2321 return worker.policy_container().clone();
2322 }
2323 unreachable!();
2324 }
2325
2326 pub(crate) fn api_base_url(&self) -> ServoUrl {
2329 if let Some(window) = self.downcast::<Window>() {
2330 return window.Document().base_url();
2332 }
2333 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2334 return worker.get_url().clone();
2336 }
2337 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2338 return worklet.base_url();
2340 }
2341 #[cfg(feature = "devtools")]
2342 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2343 return self.creation_url();
2344 }
2345 unreachable!();
2346 }
2347
2348 pub(crate) fn get_url(&self) -> ServoUrl {
2350 if let Some(window) = self.downcast::<Window>() {
2351 return window.get_url();
2352 }
2353 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2354 return worker.get_url().clone();
2355 }
2356 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2357 return worklet.base_url();
2359 }
2360 if self.is::<DissimilarOriginWindow>() {
2361 return self.creation_url();
2362 }
2363 #[cfg(feature = "devtools")]
2364 if self.downcast::<DebuggerGlobalScope>().is_some() {
2365 return self.creation_url();
2366 }
2367 unreachable!();
2368 }
2369
2370 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
2372 if let Some(window) = self.downcast::<Window>() {
2373 let document = window.Document();
2374
2375 return document.get_referrer_policy();
2376 }
2377 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2378 return worker.policy_container().get_referrer_policy();
2379 }
2380 unreachable!();
2381 }
2382
2383 pub(crate) fn get_referrer(&self) -> Referrer {
2386 if let Some(window) = self.downcast::<Window>() {
2388 let mut document = window.Document();
2390
2391 if let ImmutableOrigin::Opaque(_) = document.origin().immutable() {
2393 return Referrer::NoReferrer;
2394 }
2395
2396 let mut url = document.url();
2397
2398 while url.as_str() == "about:srcdoc" {
2401 let Some(parent_document) =
2404 document.browsing_context().and_then(|browsing_context| {
2405 browsing_context
2406 .parent()
2407 .and_then(|parent| parent.document())
2408 })
2409 else {
2410 return Referrer::NoReferrer;
2411 };
2412 document = parent_document;
2413 url = document.url();
2414 }
2415
2416 Referrer::Client(url)
2418 } else {
2419 Referrer::Client(self.creation_url())
2421 }
2422 }
2423
2424 pub(crate) fn as_window(&self) -> &Window {
2426 self.downcast::<Window>().expect("expected a Window scope")
2427 }
2428
2429 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
2431 if let Some(window) = self.downcast::<Window>() {
2432 return window.Document().insecure_requests_policy();
2433 }
2434 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2435 return worker.insecure_requests_policy();
2436 }
2437 debug!("unsupported global, defaulting insecure requests policy to DoNotUpgrade");
2438 InsecureRequestsPolicy::DoNotUpgrade
2439 }
2440
2441 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
2443 self.downcast::<Window>()
2444 .is_some_and(|window| window.Document().has_trustworthy_ancestor_origin())
2445 }
2446
2447 pub(crate) fn report_an_exception(&self, cx: &mut JSContext, error: HandleValue) {
2449 let error_info = ErrorInfo::from_value(cx, error);
2451
2452 self.report_an_error(cx, error_info, error);
2465 }
2466
2467 pub(crate) fn report_an_error(
2469 &self,
2470 cx: &mut JSContext,
2471 error_info: ErrorInfo,
2472 value: HandleValue,
2473 ) {
2474 self.send_to_embedder(EmbedderMsg::ShowConsoleApiMessage(
2475 self.webview_id(),
2476 ConsoleLogLevel::Error,
2477 format!(
2478 "Error at {}:{}:{} {}",
2479 error_info.filename, error_info.lineno, error_info.column, error_info.message
2480 ),
2481 ));
2482
2483 #[cfg(feature = "js_backtrace")]
2484 LAST_EXCEPTION_BACKTRACE.with(|backtrace| {
2485 if let Some((js_backtrace, rust_backtrace)) = backtrace.borrow_mut().take() {
2486 if let Some(stack) = js_backtrace {
2487 error!("JS backtrace:\n{}", stack);
2488 }
2489 error!("Rust backtrace:\n{}", rust_backtrace);
2490 }
2491 });
2492
2493 let mut not_handled = true;
2495
2496 if !self.in_error_reporting_mode.get() {
2498 self.in_error_reporting_mode.set(true);
2500
2501 let event = ErrorEvent::new(
2506 cx,
2507 self,
2508 atom!("error"),
2509 EventBubbles::DoesNotBubble,
2510 EventCancelable::Cancelable,
2511 error_info.message.as_str().into(),
2512 error_info.filename.as_str().into(),
2513 error_info.lineno,
2514 error_info.column,
2515 value,
2516 );
2517 not_handled = event
2518 .upcast::<Event>()
2519 .fire(cx, self.upcast::<EventTarget>());
2520
2521 self.in_error_reporting_mode.set(false);
2523 }
2524
2525 if not_handled {
2527 if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2533 dedicated.forward_error_to_worker_object(error_info);
2534 } else if self.is::<Window>() {
2535 #[cfg(feature = "devtools")]
2537 if let Some(ref chan) = self.devtools_chan {
2538 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2539 self.pipeline_id(),
2540 PageError {
2541 error_message: error_info.message.clone(),
2542 source_name: error_info.filename.clone(),
2543 line_number: error_info.lineno,
2544 column_number: error_info.column,
2545 time_stamp: get_time_stamp(),
2546 },
2547 ));
2548 }
2549 }
2550 }
2551 }
2552
2553 pub(crate) fn resource_threads(&self) -> &ResourceThreads {
2555 &self.resource_threads
2556 }
2557
2558 pub(crate) fn core_resource_thread(&self) -> CoreResourceThread {
2560 self.resource_threads().sender()
2561 }
2562
2563 pub(crate) fn storage_threads(&self) -> &StorageThreads {
2565 &self.storage_threads
2566 }
2567
2568 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
2572 if let Some(window) = self.downcast::<Window>() {
2573 Some(window.event_loop_sender())
2574 } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2575 dedicated.event_loop_sender()
2576 } else if let Some(shared_worker) = self.downcast::<SharedWorkerGlobalScope>() {
2577 Some(shared_worker.event_loop_sender())
2578 } else if let Some(service_worker) = self.downcast::<ServiceWorkerGlobalScope>() {
2579 Some(service_worker.event_loop_sender())
2580 } else {
2581 unreachable!(
2582 "Tried to access event loop sender for incompatible \
2583 GlobalScope (PaintWorklet or DissimilarOriginWindow)"
2584 );
2585 }
2586 }
2587
2588 pub(crate) fn task_manager(&self) -> Rc<TaskManager> {
2590 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2591 worker.task_manager()
2592 } else if let Some(window) = self.downcast::<Window>() {
2593 window.task_manager()
2594 } else if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2595 worklet.task_manager()
2596 } else {
2597 unreachable!("Attempted to use task manager with unsupported global");
2598 }
2599 }
2600
2601 #[expect(unsafe_code)]
2603 pub(crate) fn evaluate_js_on_global(
2604 &self,
2605 cx: &mut CurrentRealm,
2606 code: Cow<'_, str>,
2607 filename: &str,
2608 introduction_type: Option<&'static CStr>,
2609 rval: Option<MutableHandleValue>,
2610 ) -> Result<(), JavaScriptEvaluationError> {
2611 run_a_script::<DomTypeHolder, _, _>(cx, self, |cx| {
2612 let url = self.api_base_url();
2613 let fetch_options = ScriptFetchOptions::default_classic_script();
2614
2615 let mut script_options = ScriptOptions::empty();
2616 script_options.set(ScriptOptions::ReturnsAValue, rval.is_some());
2617
2618 let options = fill_compile_options(
2619 cx,
2620 filename,
2621 script_options,
2622 introduction_type,
2623 1, );
2625
2626 let mut source = transform_str_to_source_text(&code);
2627 rooted!(&in(cx) let compiled_script = unsafe { Compile1(cx, options.ptr, &mut source) });
2628
2629 if compiled_script.is_null() {
2630 debug!("error compiling Dom string");
2631 report_pending_exception(cx);
2632 return Err(JavaScriptEvaluationError::CompilationFailure);
2633 }
2634
2635 rooted!(&in(cx) let mut value = UndefinedValue());
2636 let rval = rval.unwrap_or_else(|| value.handle_mut());
2637
2638 maybe_associate_with_script(cx, compiled_script.handle(), url, fetch_options);
2639
2640 if unsafe { !JS_ExecuteScript(cx, compiled_script.handle(), rval) } {
2641 let error_info = take_and_report_pending_exception_for_api(cx);
2642 return Err(JavaScriptEvaluationError::EvaluationFailure(error_info));
2643 }
2644
2645 maybe_resume_unwind();
2646 Ok(())
2647 })
2648 }
2649
2650 pub(crate) fn schedule_js_callback(
2652 &self,
2653 callback: RootedInternalTimerCallback,
2654 data: JsTimerTaskData,
2655 duration: Duration,
2656 ) -> OneshotTimerHandle {
2657 self.with_timers(|timers| {
2658 timers.schedule_js_callback(callback, data, duration, self.timer_source())
2659 })
2660 }
2661
2662 pub(crate) fn schedule_callback(
2664 &self,
2665 callback: OneshotTimerCallback,
2666 duration: Duration,
2667 ) -> OneshotTimerHandle {
2668 self.with_timers(|timers| timers.schedule_callback(callback, duration, self.timer_source()))
2669 }
2670
2671 pub(crate) fn unschedule_callback(&self, handle: OneshotTimerHandle) {
2672 self.with_timers(|timers| timers.unschedule_callback(handle));
2673 }
2674
2675 pub(crate) fn set_timeout_or_interval(
2677 &self,
2678 cx: &mut JSContext,
2679 callback: TimerCallback,
2680 arguments: Vec<HandleValue>,
2681 timeout: Duration,
2682 is_interval: IsInterval,
2683 ) -> Fallible<i32> {
2684 self.with_timers(|timers| {
2685 timers.set_timeout_or_interval(
2686 cx,
2687 self,
2688 callback,
2689 arguments,
2690 timeout,
2691 is_interval,
2692 self.timer_source(),
2693 )
2694 })
2695 }
2696
2697 pub(crate) fn clear_timeout_or_interval(&self, handle: i32) {
2698 self.with_timers(|timers| timers.clear_timeout_or_interval(self, handle));
2699 }
2700
2701 pub(crate) fn fire_timer(&self, cx: &mut JSContext, handle: TimerEventId) {
2702 self.with_timers(|timers| timers.fire_timer(cx, handle));
2703 }
2704
2705 pub(crate) fn resume(&self) {
2706 self.with_timers(|timers| timers.resume());
2707 }
2708
2709 pub(crate) fn suspend(&self) {
2710 self.with_timers(|timers| timers.suspend());
2711 }
2712
2713 pub(crate) fn slow_down_timers(&self) {
2714 self.with_timers(|timers| timers.slow_down());
2715 }
2716
2717 pub(crate) fn speed_up_timers(&self) {
2718 self.with_timers(|timers| timers.speed_up());
2719 }
2720
2721 fn timer_source(&self) -> TimerSource {
2722 if self.is::<Window>() {
2723 return TimerSource::FromWindow(self.pipeline_id());
2724 }
2725 if self.is::<WorkerGlobalScope>() {
2726 return TimerSource::FromWorker;
2727 }
2728 unreachable!();
2729 }
2730
2731 pub(crate) fn can_continue_running(&self) -> bool {
2734 if self.is::<Window>() {
2735 return ScriptThread::can_continue_running();
2736 }
2737 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2738 return !worker.is_closing();
2739 }
2740
2741 true
2743 }
2744
2745 pub(crate) fn ensure_indexeddb_factory(&self, cx: &mut JSContext) -> DomRoot<IDBFactory> {
2747 self.indexeddb.or_init(|| IDBFactory::new(cx, self))
2748 }
2749
2750 pub(crate) fn indexeddb_factory(&self) -> Option<DomRoot<IDBFactory>> {
2752 self.indexeddb.get()
2753 }
2754
2755 pub(crate) fn perform_a_microtask_checkpoint(&self, cx: &mut JSContext) {
2757 if let Some(window) = self.downcast::<Window>() {
2758 window.perform_a_microtask_checkpoint(cx);
2759 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2760 worker.perform_a_microtask_checkpoint(cx);
2761 } else if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2762 worklet.perform_a_microtask_checkpoint(cx);
2763 }
2764 }
2765
2766 pub(crate) fn enqueue_microtask(
2768 &self,
2769 cx: &js::context::JSContext,
2770 job: Box<dyn MicrotaskRunnable>,
2771 ) {
2772 if self.is::<Window>() {
2773 ScriptThread::enqueue_microtask(cx, job);
2774 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2775 worker.enqueue_microtask(cx, job);
2776 }
2777 }
2778
2779 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
2783 if let Some(window) = self.downcast::<Window>() {
2784 return window.new_script_pair();
2785 }
2786 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2787 return worker.new_script_pair();
2788 }
2789 unreachable!();
2790 }
2791
2792 pub(crate) fn process_event(&self, cx: &mut JSContext, msg: CommonScriptMsg) -> bool {
2796 if self.is::<Window>() {
2797 return ScriptThread::process_event(cx, msg);
2798 }
2799 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2800 return worker.process_event(msg, cx);
2801 }
2802 unreachable!();
2803 }
2804
2805 pub(crate) fn runtime_handle(&self) -> ParentRuntime {
2806 if self.is::<Window>() {
2807 ScriptThread::runtime_handle()
2808 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2809 worker.runtime_handle()
2810 } else {
2811 unreachable!()
2812 }
2813 }
2814
2815 #[expect(unsafe_code)]
2819 pub(crate) fn current() -> Option<DomRoot<Self>> {
2820 let mut cx = unsafe { JSContext::get_from_thread()? };
2821 unsafe {
2822 let global = CurrentGlobalOrNull(&cx);
2823 if global.is_null() {
2824 None
2825 } else {
2826 Some(global_scope_from_global(&mut cx, global))
2827 }
2828 }
2829 }
2830
2831 pub(crate) fn entry() -> DomRoot<Self> {
2835 entry_global()
2836 }
2837
2838 pub(crate) fn incumbent() -> Option<DomRoot<Self>> {
2842 incumbent_global()
2843 }
2844
2845 pub(crate) fn performance(&self, cx: &mut JSContext) -> DomRoot<Performance> {
2846 if let Some(window) = self.downcast::<Window>() {
2847 return window.Performance(cx);
2848 }
2849 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2850 return worker.Performance(cx);
2851 }
2852 unreachable!();
2853 }
2854
2855 pub(crate) fn supported_performance_entry_types(
2857 &self,
2858 cx: &mut JSContext,
2859 retval: MutableHandleValue,
2860 ) {
2861 self.frozen_supported_performance_entry_types.get_or_init(
2862 cx,
2863 || {
2864 EntryType::VARIANTS
2865 .iter()
2866 .map(|t| DOMString::from(t.as_str()))
2867 .collect()
2868 },
2869 retval,
2870 );
2871 }
2872
2873 pub(crate) fn inherited_secure_context(&self) -> Option<bool> {
2874 self.inherited_secure_context
2875 }
2876
2877 pub(crate) fn is_secure_context(&self) -> bool {
2879 if Some(false) == self.inherited_secure_context {
2884 return false;
2885 }
2886 match self.top_level_creation_url() {
2889 None => {
2890 assert!(self.is::<WorkerGlobalScope>() || self.is::<WorkletGlobalScope>());
2892 true
2893 },
2894 Some(top_level_creation_url) => {
2895 assert!(self.is::<Window>());
2896 if top_level_creation_url.scheme() == "blob" &&
2900 Some(true) == self.inherited_secure_context
2901 {
2902 return true;
2903 }
2904 top_level_creation_url.is_potentially_trustworthy()
2905 },
2906 }
2907 }
2908
2909 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
2911 if self.is::<Window>() || self.is::<WorkerGlobalScope>() {
2912 return self.policy_container().csp_list.clone();
2913 }
2914 None
2916 }
2917
2918 pub(crate) fn status_code(&self) -> Option<u16> {
2919 if let Some(window) = self.downcast::<Window>() {
2920 return window.Document().status_code();
2921 }
2922 None
2923 }
2924
2925 pub(crate) fn online(&self) -> bool {
2926 if let Some(worker_global_scope) = self.downcast::<WorkerGlobalScope>() {
2927 return worker_global_scope.online();
2928 }
2929 ScriptThread::online()
2930 }
2931
2932 #[cfg(feature = "webgpu")]
2933 pub(crate) fn wgpu_id_hub(&self) -> Arc<IdentityHub> {
2934 self.gpu_id_hub.clone()
2935 }
2936
2937 #[cfg(feature = "webgpu")]
2938 pub(crate) fn add_gpu_device(&self, device: &GPUDevice) {
2939 self.gpu_devices
2940 .borrow_mut()
2941 .insert(device.id(), WeakRef::new(device));
2942 }
2943
2944 #[cfg(feature = "webgpu")]
2945 pub(crate) fn remove_gpu_device(&self, device: WebGPUDevice) {
2946 let device = self
2947 .gpu_devices
2948 .borrow_mut()
2949 .remove(&device)
2950 .expect("GPUDevice should still be in devices hashmap");
2951 assert!(device.root().is_none())
2952 }
2953
2954 #[cfg(feature = "webgpu")]
2955 pub(crate) fn gpu_device_lost(
2956 &self,
2957 device: WebGPUDevice,
2958 reason: DeviceLostReason,
2959 msg: String,
2960 ) {
2961 let reason = match reason {
2962 DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown,
2963 DeviceLostReason::Destroyed => GPUDeviceLostReason::Destroyed,
2964 };
2965 if let Some(device) = self
2966 .gpu_devices
2967 .borrow_mut()
2968 .get_mut(&device)
2969 .expect("GPUDevice should still be in devices hashmap")
2970 .root()
2971 {
2972 device.lose(reason, msg);
2973 }
2974 }
2975
2976 #[cfg(feature = "webgpu")]
2977 pub(crate) fn handle_uncaptured_gpu_error(
2978 &self,
2979 device: WebGPUDevice,
2980 error: webgpu_traits::Error,
2981 ) {
2982 if let Some(gpu_device) = self
2983 .gpu_devices
2984 .borrow()
2985 .get(&device)
2986 .and_then(|device| device.root())
2987 {
2988 gpu_device.fire_uncaptured_error(error);
2989 } else {
2990 warn!("Recived error for lost GPUDevice!")
2991 }
2992 }
2993
2994 pub(crate) fn current_group_label(&self) -> Option<DOMString> {
2995 self.console_group_stack
2996 .borrow()
2997 .last()
2998 .map(|label| DOMString::from(format!("[{}]", label)))
2999 }
3000
3001 pub(crate) fn push_console_group(&self, group: DOMString) {
3002 self.console_group_stack.borrow_mut().push(group.traced());
3003 }
3004
3005 pub(crate) fn pop_console_group(&self) {
3006 let _ = self.console_group_stack.borrow_mut().pop();
3007 }
3008
3009 pub(crate) fn increment_console_count(&self, label: &DOMString) -> usize {
3010 *self
3011 .console_count_map
3012 .borrow_mut()
3013 .entry(label.clone().traced())
3014 .and_modify(|e| *e += 1)
3015 .or_insert(1)
3016 }
3017
3018 pub(crate) fn reset_console_count(&self, label: &DOMString) -> Result<(), ()> {
3019 match self.console_count_map.borrow_mut().get_mut(label) {
3020 Some(value) => {
3021 *value = 0;
3022 Ok(())
3023 },
3024 None => Err(()),
3025 }
3026 }
3027
3028 pub(crate) fn structured_clone(
3029 &self,
3030 cx: &mut JSContext,
3031 value: HandleValue,
3032 options: &StructuredSerializeOptions,
3033 retval: MutableHandleValue,
3034 ) -> Fallible<()> {
3035 auto_root!(&in(cx) let guard =
3036 options
3037 .transfer
3038 .iter()
3039 .map(|js| js.get())
3040 .collect::<Vec<_>>());
3041
3042 let data = structuredclone::write(cx, value, Some(guard))?;
3043
3044 structuredclone::read(cx, self, data, retval)?;
3045
3046 Ok(())
3047 }
3048
3049 pub(crate) fn fetch<Listener: FetchResponseListener>(
3050 &self,
3051 request_builder: RequestBuilder,
3052 context: Listener,
3053 task_source: SendableTaskSource,
3054 ) {
3055 self.fetch_group_mut().fetch(
3056 request_builder,
3057 NetworkListener::new(context, task_source),
3058 None, );
3060 }
3061
3062 pub(crate) fn unminify_js(&self) -> bool {
3063 self.unminified_js_dir.is_some()
3064 }
3065
3066 pub(crate) fn unminified_js_dir(&self) -> Option<String> {
3067 self.unminified_js_dir.clone()
3068 }
3069
3070 pub(crate) fn set_byte_length_queuing_strategy_size(&self, function: RootedCallback<Function>) {
3071 if self
3072 .byte_length_queuing_strategy_size_function
3073 .set(function.to_traced())
3074 .is_err()
3075 {
3076 warn!("byte length queuing strategy size function is set twice.");
3077 };
3078 }
3079
3080 pub(crate) fn get_byte_length_queuing_strategy_size(
3081 &self,
3082 cx: &JSContext,
3083 ) -> Option<RootedCallback<Function>> {
3084 self.byte_length_queuing_strategy_size_function
3085 .get()
3086 .cloned()
3087 .map(|f| f.root(cx))
3088 }
3089
3090 pub(crate) fn set_count_queuing_strategy_size(&self, function: RootedCallback<Function>) {
3091 if self
3092 .count_queuing_strategy_size_function
3093 .set(function.to_traced())
3094 .is_err()
3095 {
3096 warn!("count queuing strategy size function is set twice.");
3097 };
3098 }
3099
3100 pub(crate) fn get_count_queuing_strategy_size(
3101 &self,
3102 cx: &JSContext,
3103 ) -> Option<RootedCallback<Function>> {
3104 self.count_queuing_strategy_size_function
3105 .get()
3106 .cloned()
3107 .map(|f| f.root(cx))
3108 }
3109
3110 pub(crate) fn add_notification_permission_request_callback(
3111 &self,
3112 callback_id: String,
3113 callback: RootedCallback<NotificationPermissionCallback>,
3114 ) {
3115 self.notification_permission_request_callback_map
3116 .borrow_mut()
3117 .insert(callback_id, callback.to_traced());
3118 }
3119
3120 pub(crate) fn remove_notification_permission_request_callback(
3121 &self,
3122 callback_id: String,
3123 ) -> Option<TracedCallback<NotificationPermissionCallback>> {
3124 self.notification_permission_request_callback_map
3125 .borrow_mut()
3126 .remove(&callback_id)
3127 }
3128
3129 pub(crate) fn fetch_group(&self) -> Ref<'_, FetchGroup> {
3130 self.fetch_group.borrow()
3131 }
3132
3133 pub(crate) fn fetch_group_mut(&self) -> RefMut<'_, FetchGroup> {
3134 self.fetch_group.borrow_mut()
3135 }
3136
3137 pub(crate) fn import_map(&self) -> Ref<'_, ImportMap> {
3138 self.import_map.borrow()
3139 }
3140
3141 pub(crate) fn import_map_mut(&self) -> RefMut<'_, ImportMap> {
3142 self.import_map.borrow_mut()
3143 }
3144
3145 pub(crate) fn resolved_module_set(&self) -> Ref<'_, HashSet<ResolvedModule>> {
3146 self.resolved_module_set.borrow()
3147 }
3148
3149 pub(crate) fn add_module_to_resolved_module_set(
3151 &self,
3152 base_url: &str,
3153 specifier: &str,
3154 specifier_url: Option<ServoUrl>,
3155 ) {
3156 if self.is::<Window>() {
3159 let record =
3163 ResolvedModule::new(base_url.to_owned(), specifier.to_owned(), specifier_url);
3164 self.resolved_module_set.borrow_mut().insert(record);
3166 }
3167 }
3168
3169 pub(crate) fn run_steps_after_a_timeout<F>(
3173 &self,
3174 ordering_identifier: DOMString,
3175 milliseconds: i64,
3176 completion_steps: F,
3177 ) -> i32
3178 where
3179 F: 'static + FnOnce(&mut JSContext, &GlobalScope),
3180 {
3181 let ms = milliseconds.max(0) as u64;
3182 let delay = std::time::Duration::from_millis(ms);
3183
3184 let (callback, timer_key) = self.with_timers(|timers| {
3185 let timer_key = timers.fresh_runsteps_key();
3187
3188 let start_time = timers.now_for_runsteps();
3190
3191 let deadline = start_time + delay;
3193 timers.runsteps_set_active(timer_key, deadline);
3194
3195 let callback = OneshotTimerCallback::RunStepsAfterTimeout {
3198 timer_key,
3200 ordering_id: ordering_identifier,
3202 milliseconds: ms,
3204 completion: Box::new(completion_steps),
3206 };
3207 (callback, timer_key)
3208 });
3209 let _ = self.schedule_callback(callback, delay);
3210
3211 timer_key
3213 }
3214
3215 pub(crate) fn set_network_online_state_on_dedicated_workers(&self, online: bool) {
3216 for worker in &*self.list_auto_close_worker.borrow() {
3217 _ = worker
3218 .control_sender
3219 .send(DedicatedWorkerControlMsg::SetNetworkOnlineState(online));
3220 }
3221 }
3222}
3223
3224#[expect(unsafe_code)]
3226unsafe fn global_scope_from_global(
3227 cx: &mut JSContext,
3228 global: *mut JSObject,
3229) -> DomRoot<GlobalScope> {
3230 unsafe {
3231 assert!(!global.is_null());
3232 let clasp = get_object_class(global);
3233 assert_ne!(
3234 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3235 0
3236 );
3237 root_from_object(cx, global).unwrap()
3238 }
3239}
3240
3241#[expect(unsafe_code)]
3243unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot<GlobalScope> {
3244 assert!(!global.is_null());
3245 let clasp = unsafe { get_object_class(global) };
3246
3247 unsafe {
3248 assert_ne!(
3249 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3250 0
3251 );
3252 }
3253
3254 root_from_object_static(global).unwrap()
3255}
3256
3257#[expect(unsafe_code)]
3258impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
3259 fn from_current_realm(realm: &'_ mut CurrentRealm) -> DomRoot<Self> {
3260 GlobalScope::from_current_realm(realm)
3261 }
3262
3263 unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
3264 unsafe { GlobalScope::from_object(obj) }
3265 }
3266
3267 fn from_reflector(reflector: &impl DomObject) -> DomRoot<Self> {
3268 GlobalScope::from_reflector(reflector)
3269 }
3270
3271 fn origin(&self) -> MutableOrigin {
3272 GlobalScope::origin(self)
3273 }
3274
3275 fn incumbent() -> Option<DomRoot<Self>> {
3276 GlobalScope::incumbent()
3277 }
3278
3279 fn perform_a_microtask_checkpoint(&self, cx: &mut JSContext) {
3280 GlobalScope::perform_a_microtask_checkpoint(self, cx)
3281 }
3282
3283 fn get_url(&self) -> ServoUrl {
3284 self.get_url()
3285 }
3286
3287 fn is_secure_context(&self) -> bool {
3288 self.is_secure_context()
3289 }
3290
3291 fn pipeline_id(&self) -> PipelineId {
3292 self.pipeline_id()
3293 }
3294
3295 fn script_to_constellation_chan(&self) -> ScriptToConstellationChan {
3296 self.script_to_constellation_chan()
3297 }
3298
3299 fn entry() -> DomRoot<Self> {
3300 GlobalScope::entry()
3301 }
3302}
3303
3304impl OwnerWindow<DomTypeHolder> for GlobalScope {}