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