diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index 70c384db822..b5af443a1a4 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -68,6 +68,7 @@ impl DissimilarOriginWindow { global_to_clone_from.wgpu_id_hub(), Some(global_to_clone_from.is_secure_context()), false, + global_to_clone_from.is_online().clone(), ), window_proxy: Dom::from_ref(window_proxy), location: Default::default(), diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index ec2ed70dd15..1da3928831c 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -374,6 +374,11 @@ pub(crate) struct GlobalScope { #[ignore_malloc_size_of = "Rc is hard"] notification_permission_request_callback_map: DomRefCell>>, + + /// Switch offline and online events + #[no_trace] + #[ignore_malloc_size_of = "Arc> does not implement MallocSizeOf"] + is_online: Arc>, } /// A wrapper for glue-code between the ipc router and the event-loop. @@ -735,6 +740,7 @@ impl GlobalScope { #[cfg(feature = "webgpu")] gpu_id_hub: Arc, inherited_secure_context: Option, unminify_js: bool, + is_online: Arc>, ) -> Self { Self { task_manager: Default::default(), @@ -779,6 +785,7 @@ impl GlobalScope { byte_length_queuing_strategy_size_function: OnceCell::new(), count_queuing_strategy_size_function: OnceCell::new(), notification_permission_request_callback_map: Default::default(), + is_online, } } @@ -3444,6 +3451,10 @@ impl GlobalScope { unreachable!(); } + pub(crate) fn is_online(&self) -> Arc> { + self.is_online.clone() + } + /// #[allow(unsafe_code)] pub(crate) fn report_csp_violations( diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index ee67359f859..615ba80174d 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -224,7 +224,7 @@ impl NavigatorMethods for Navigator { /// fn OnLine(&self) -> bool { - true + *self.global().is_online().lock().unwrap() } // https://html.spec.whatwg.org/multipage/#dom-navigator-plugins diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 24e694b4f06..c286f456132 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -398,6 +398,11 @@ pub(crate) struct Window { /// current_event: DomRefCell>>, + + /// Switch offline and online events + #[no_trace] + #[ignore_malloc_size_of = "Arc> does not implement MallocSizeOf"] + is_online: Arc>, } impl Window { @@ -3033,6 +3038,7 @@ impl Window { player_context: WindowGLContext, #[cfg(feature = "webgpu")] gpu_id_hub: Arc, inherited_secure_context: Option, + is_online: Arc>, ) -> DomRoot { let error_reporter = CSSErrorReporter { pipelineid: pipeline_id, @@ -3060,6 +3066,7 @@ impl Window { gpu_id_hub, inherited_secure_context, unminify_js, + is_online, ), script_chan, layout: RefCell::new(layout), @@ -3120,6 +3127,7 @@ impl Window { current_event: DomRefCell::new(None), theme: Cell::new(PrefersColorScheme::Light), trusted_types: Default::default(), + is_online: Arc::new(Mutex::new(true)), }); unsafe { diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index fa94dcc1d04..a158a5b0c1e 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -5,8 +5,8 @@ use std::cell::{RefCell, RefMut}; use std::default::Default; use std::rc::Rc; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; use std::time::Duration; use base::cross_process_instant::CrossProcessInstant; @@ -174,6 +174,7 @@ impl WorkerGlobalScope { gpu_id_hub, init.inherited_secure_context, false, + Arc::new(Mutex::new(true)), ), worker_id: init.worker_id, worker_name, diff --git a/components/script/dom/workernavigator.rs b/components/script/dom/workernavigator.rs index 0b0e90ffd0c..e3c7f290acc 100644 --- a/components/script/dom/workernavigator.rs +++ b/components/script/dom/workernavigator.rs @@ -107,7 +107,7 @@ impl WorkerNavigatorMethods for WorkerNavigator { /// fn OnLine(&self) -> bool { - true + *self.global().is_online().lock().unwrap() } // https://w3c.github.io/permissions/#navigator-and-workernavigator-extension diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index c478830ac0c..27337aa338c 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use base::id::PipelineId; use constellation_traits::{ScriptToConstellationChan, ScriptToConstellationMessage}; @@ -110,6 +110,7 @@ impl WorkletGlobalScope { init.gpu_id_hub.clone(), init.inherited_secure_context, false, + Arc::new(Mutex::new(true)), ), base_url, to_script_thread_sender: init.to_script_thread_sender.clone(), diff --git a/components/script/messaging.rs b/components/script/messaging.rs index 08d6fc841cf..9f9453305b8 100644 --- a/components/script/messaging.rs +++ b/components/script/messaging.rs @@ -92,6 +92,7 @@ impl MixedMessage { ScriptThreadMessage::SetWebGPUPort(..) => None, ScriptThreadMessage::SetScrollStates(id, ..) => Some(*id), ScriptThreadMessage::EvaluateJavaScript(id, _, _) => Some(*id), + ScriptThreadMessage::SetNetWorkState(..) => None, }, MixedMessage::FromScript(inner_msg) => match inner_msg { MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index e0309298f3d..bc9095e67ec 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -23,8 +23,8 @@ use std::default::Default; use std::option::Option; use std::rc::Rc; use std::result::Result; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; use std::thread; use std::time::{Duration, Instant, SystemTime}; @@ -128,6 +128,7 @@ use crate::dom::document::{ Document, DocumentSource, FocusInitiator, HasBrowsingContext, IsHTMLDocument, TouchEventResult, }; use crate::dom::element::Element; +use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmliframeelement::HTMLIFrameElement; @@ -336,6 +337,10 @@ pub struct ScriptThread { /// The screen coordinates where the primary mouse button was pressed. #[no_trace] relative_mouse_down_point: Cell>, + + /// Switch offline and online events + #[no_trace] + is_online: Arc>, } struct BHMExitSignal { @@ -957,6 +962,7 @@ impl ScriptThread { inherited_secure_context: state.inherited_secure_context, layout_factory, relative_mouse_down_point: Cell::new(Point2D::zero()), + is_online: Arc::new(Mutex::new(true)), } } @@ -1903,6 +1909,23 @@ impl ScriptThread { ScriptThreadMessage::EvaluateJavaScript(pipeline_id, evaluation_id, script) => { self.handle_evaluate_javascript(pipeline_id, evaluation_id, script, can_gc); }, + ScriptThreadMessage::SetNetWorkState(is_online) => { + self.handle_network_state(is_online, can_gc); + }, + } + } + + fn fire_network_events(&self, is_online: bool, can_gc: CanGc) { + let event_name = if is_online { + Atom::from("online") + } else { + Atom::from("offline") + }; + + for (_, document) in self.documents.borrow().iter() { + let window = document.window(); + let event_target = window.upcast::(); + event_target.fire_event(event_name.clone(), can_gc); } } @@ -3228,6 +3251,7 @@ impl ScriptThread { #[cfg(feature = "webgpu")] self.gpu_id_hub.clone(), incomplete.load_data.inherited_secure_context, + self.is_online.clone(), ); let _realm = enter_realm(&*window); @@ -3821,6 +3845,17 @@ impl ScriptThread { }; } + fn handle_network_state(&self, is_online: bool, can_gc: CanGc) { + let mut online_lock = self.is_online.lock().unwrap(); + let previous = *online_lock; + *online_lock = is_online; + drop(online_lock); + + if previous != is_online { + self.fire_network_events(is_online, can_gc); + } + } + pub(crate) fn enqueue_microtask(job: Microtask) { with_script_thread(|script_thread| { script_thread diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 29acc51765c..d6c0531e6c3 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -248,6 +248,8 @@ pub enum ScriptThreadMessage { /// Evaluate the given JavaScript and return a result via a corresponding message /// to the Constellation. EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String), + /// Parameter indicates if online (true) or offline (false) + SetNetWorkState(bool), } impl fmt::Debug for ScriptThreadMessage {