diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 5904488c37f..3c2d0533ac7 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -20,9 +20,7 @@ use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment}; use js::jsapi::{JSContext, JSObject, JS_GetClass}; use script_runtime::{CommonScriptMsg, EnqueuedPromiseCallback, ScriptChan, ScriptPort}; use script_thread::{RunnableWrapper, ScriptThread}; -use script_traits::MsDuration; use task_source::file_reading::FileReadingTaskSource; -use timers::{OneshotTimerCallback, OneshotTimerHandle}; /// A freely-copyable reference to a rooted global object. #[derive(Copy, Clone)] @@ -87,26 +85,6 @@ impl<'a> GlobalRef<'a> { } } - /// Schedule the given `callback` to be invoked after at least `duration` milliseconds have - /// passed. - pub fn schedule_callback(&self, - callback: OneshotTimerCallback, - duration: MsDuration) - -> OneshotTimerHandle { - match *self { - GlobalRef::Window(window) => window.schedule_callback(callback, duration), - GlobalRef::Worker(worker) => worker.schedule_callback(callback, duration), - } - } - - /// Unschedule a previously-scheduled callback. - pub fn unschedule_callback(&self, handle: OneshotTimerHandle) { - match *self { - GlobalRef::Window(window) => window.unschedule_callback(handle), - GlobalRef::Worker(worker) => worker.unschedule_callback(handle), - } - } - /// Returns a wrapper for runnables to ensure they are cancelled if the global /// is being destroyed. pub fn get_runnable_wrapper(&self) -> RunnableWrapper { diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 64f932c31f9..96528a80164 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -28,13 +28,16 @@ use net_traits::{CoreResourceThread, ResourceThreads, IpcSend}; use profile_traits::{mem, time}; use script_runtime::{ScriptChan, maybe_take_panic_result}; use script_thread::MainThreadScriptChan; -use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest}; +use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEvent}; +use script_traits::{TimerEventId, TimerEventRequest, TimerSource}; use std::cell::Cell; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::ffi::CString; use std::panic; use time::{Timespec, get_time}; +use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle}; +use timers::{OneshotTimers, TimerCallback}; use url::Url; #[dom_struct] @@ -78,6 +81,8 @@ pub struct GlobalScope { /// Associated resource threads for use by DOM objects like XMLHttpRequest, /// including resource_thread, filemanager_thread and storage_thread resource_threads: ResourceThreads, + + timers: OneshotTimers, } impl GlobalScope { @@ -88,7 +93,8 @@ impl GlobalScope { time_profiler_chan: time::ProfilerChan, constellation_chan: IpcSender, scheduler_chan: IpcSender, - resource_threads: ResourceThreads) + resource_threads: ResourceThreads, + timer_event_chan: IpcSender) -> Self { GlobalScope { eventtarget: EventTarget::new_inherited(), @@ -101,9 +107,10 @@ impl GlobalScope { mem_profiler_chan: mem_profiler_chan, time_profiler_chan: time_profiler_chan, constellation_chan: constellation_chan, - scheduler_chan: scheduler_chan, + scheduler_chan: scheduler_chan.clone(), in_error_reporting_mode: Default::default(), resource_threads: resource_threads, + timers: OneshotTimers::new(timer_event_chan, scheduler_chan), } } @@ -334,6 +341,61 @@ impl GlobalScope { } ) } + + pub fn schedule_callback( + &self, callback: OneshotTimerCallback, duration: MsDuration) + -> OneshotTimerHandle { + self.timers.schedule_callback(callback, duration, self.timer_source()) + } + + pub fn unschedule_callback(&self, handle: OneshotTimerHandle) { + self.timers.unschedule_callback(handle); + } + + pub fn set_timeout_or_interval( + &self, + callback: TimerCallback, + arguments: Vec, + timeout: i32, + is_interval: IsInterval) + -> i32 { + self.timers.set_timeout_or_interval( + self, callback, arguments, timeout, is_interval, self.timer_source()) + } + + pub fn clear_timeout_or_interval(&self, handle: i32) { + self.timers.clear_timeout_or_interval(self, handle) + } + + pub fn fire_timer(&self, handle: TimerEventId) { + self.timers.fire_timer(handle, self) + } + + pub fn resume(&self) { + self.timers.resume() + } + + pub fn suspend(&self) { + self.timers.suspend() + } + + pub fn slow_down_timers(&self) { + self.timers.slow_down() + } + + pub fn speed_up_timers(&self) { + self.timers.speed_up() + } + + fn timer_source(&self) -> TimerSource { + if self.is::() { + return TimerSource::FromWindow(self.pipeline_id()); + } + if self.is::() { + return TimerSource::FromWorker; + } + unreachable!(); + } } fn timestamp_in_ms(time: Timespec) -> u64 { diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 3f4d3dbcaf1..bc7c5643533 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -683,8 +683,10 @@ impl TestBindingMethods for TestBinding { promise: TrustedPromise::new(promise), value: value, }; - let _ = self.global().r().schedule_callback(OneshotTimerCallback::TestBindingCallback(cb), - MsDuration::new(delay)); + let _ = self.global_scope() + .schedule_callback( + OneshotTimerCallback::TestBindingCallback(cb), + MsDuration::new(delay)); } #[allow(unrooted_must_root)] diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 0d55cb98f91..4365ba44999 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -71,8 +71,8 @@ use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventC use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper}; use script_thread::SendableMainThreadScriptChan; use script_traits::{ConstellationControlMsg, MozBrowserEvent, UntrustedNodeAddress}; -use script_traits::{DocumentState, MsDuration, TimerEvent, TimerEventId}; -use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSource, WindowSizeData}; +use script_traits::{DocumentState, TimerEvent, TimerEventId}; +use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, WindowSizeData}; use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; use std::ascii::AsciiExt; use std::borrow::ToOwned; @@ -97,7 +97,7 @@ use task_source::history_traversal::HistoryTraversalTaskSource; use task_source::networking::NetworkingTaskSource; use task_source::user_interaction::UserInteractionTaskSource; use time; -use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback}; +use timers::{IsInterval, TimerCallback}; #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use tinyfiledialogs::{self, MessageBoxIcon}; use url::Url; @@ -168,7 +168,6 @@ pub struct Window { session_storage: MutNullableHeap>, local_storage: MutNullableHeap>, status: DOMRefCell, - timers: OneshotTimers, /// For sending timeline markers. Will be ignored if /// no devtools server @@ -475,47 +474,43 @@ impl WindowMethods for Window { // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout fn SetTimeout(&self, _cx: *mut JSContext, callback: Rc, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Window(self), - TimerCallback::FunctionTimerCallback(callback), - args, - timeout, - IsInterval::NonInterval, - TimerSource::FromWindow(self.upcast::().pipeline_id())) + self.upcast::().set_timeout_or_interval( + TimerCallback::FunctionTimerCallback(callback), + args, + timeout, + IsInterval::NonInterval) } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout fn SetTimeout_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Window(self), - TimerCallback::StringTimerCallback(callback), - args, - timeout, - IsInterval::NonInterval, - TimerSource::FromWindow(self.upcast::().pipeline_id())) + self.upcast::().set_timeout_or_interval( + TimerCallback::StringTimerCallback(callback), + args, + timeout, + IsInterval::NonInterval) } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-cleartimeout fn ClearTimeout(&self, handle: i32) { - self.timers.clear_timeout_or_interval(GlobalRef::Window(self), handle); + self.upcast::().clear_timeout_or_interval(handle); } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval fn SetInterval(&self, _cx: *mut JSContext, callback: Rc, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Window(self), - TimerCallback::FunctionTimerCallback(callback), - args, - timeout, - IsInterval::Interval, - TimerSource::FromWindow(self.upcast::().pipeline_id())) + self.upcast::().set_timeout_or_interval( + TimerCallback::FunctionTimerCallback(callback), + args, + timeout, + IsInterval::Interval) } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval fn SetInterval_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Window(self), - TimerCallback::StringTimerCallback(callback), - args, - timeout, - IsInterval::Interval, - TimerSource::FromWindow(self.upcast::().pipeline_id())) + self.upcast::().set_timeout_or_interval( + TimerCallback::StringTimerCallback(callback), + args, + timeout, + IsInterval::Interval) } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-clearinterval @@ -1341,7 +1336,7 @@ impl Window { } pub fn handle_fire_timer(&self, timer_id: TimerEventId) { - self.timers.fire_timer(timer_id, self); + self.upcast::().fire_timer(timer_id); self.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::Timer); @@ -1371,16 +1366,6 @@ impl Window { &self.layout_chan } - pub fn schedule_callback(&self, callback: OneshotTimerCallback, duration: MsDuration) -> OneshotTimerHandle { - self.timers.schedule_callback(callback, - duration, - TimerSource::FromWindow(self.upcast::().pipeline_id())) - } - - pub fn unschedule_callback(&self, handle: OneshotTimerHandle) { - self.timers.unschedule_callback(handle); - } - pub fn windowproxy_handler(&self) -> WindowProxyHandler { WindowProxyHandler(self.dom_static.windowproxy_handler.0) } @@ -1436,25 +1421,13 @@ impl Window { } pub fn thaw(&self) { - self.timers.resume(); + self.upcast::().resume(); // Push the document title to the compositor since we are // activating this document due to a navigation. self.Document().title_changed(); } - pub fn freeze(&self) { - self.timers.suspend(); - } - - pub fn slow_down_timers(&self) { - self.timers.slow_down(); - } - - pub fn speed_up_timers(&self) { - self.timers.speed_up(); - } - pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool { let markers = self.devtools_markers.borrow(); markers.contains(&timeline_type) @@ -1579,8 +1552,9 @@ impl Window { mem_profiler_chan, time_profiler_chan, constellation_chan, - scheduler_chan.clone(), - resource_threads), + scheduler_chan, + resource_threads, + timer_event_chan), script_chan: script_chan, dom_manipulation_task_source: dom_task_source, user_interaction_task_source: user_task_source, @@ -1599,7 +1573,6 @@ impl Window { session_storage: Default::default(), local_storage: Default::default(), status: DOMRefCell::new(DOMString::new()), - timers: OneshotTimers::new(timer_event_chan, scheduler_chan), parent_info: parent_info, dom_static: GlobalStaticData::new(), js_runtime: DOMRefCell::new(Some(runtime.clone())), diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 93361d8e620..49b1d4e3257 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -34,7 +34,7 @@ use net_traits::{LoadContext, load_whole_resource}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, maybe_take_panic_result}; use script_runtime::{ScriptThreadEventCategory, PromiseJobQueue, EnqueuedPromiseCallback}; use script_thread::{Runnable, RunnableWrapper}; -use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerSource}; +use script_traits::{TimerEvent, TimerEventId}; use script_traits::WorkerGlobalScopeInit; use std::default::Default; use std::panic; @@ -43,7 +43,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::Receiver; use task_source::file_reading::FileReadingTaskSource; -use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback}; +use timers::{IsInterval, TimerCallback}; use url::Url; pub fn prepare_workerscope_init(global: &GlobalScope, @@ -76,7 +76,6 @@ pub struct WorkerGlobalScope { runtime: Runtime, location: MutNullableHeap>, navigator: MutNullableHeap>, - timers: OneshotTimers, #[ignore_heap_size_of = "Defined in ipc-channel"] /// Optional `IpcSender` for sending the `DevtoolScriptControlMsg` @@ -107,15 +106,15 @@ impl WorkerGlobalScope { init.mem_profiler_chan, init.time_profiler_chan, init.constellation_chan, - init.scheduler_chan.clone(), - init.resource_threads), + init.scheduler_chan, + init.resource_threads, + timer_event_chan), worker_id: init.worker_id, worker_url: worker_url, closing: closing, runtime: runtime, location: Default::default(), navigator: Default::default(), - timers: OneshotTimers::new(timer_event_chan, init.scheduler_chan), from_devtools_sender: init.from_devtools_sender, from_devtools_receiver: from_devtools_receiver, promise_job_queue: PromiseJobQueue::new(), @@ -130,16 +129,6 @@ impl WorkerGlobalScope { &self.from_devtools_receiver } - pub fn schedule_callback(&self, callback: OneshotTimerCallback, duration: MsDuration) -> OneshotTimerHandle { - self.timers.schedule_callback(callback, - duration, - TimerSource::FromWorker) - } - - pub fn unschedule_callback(&self, handle: OneshotTimerHandle) { - self.timers.unschedule_callback(handle); - } - pub fn runtime(&self) -> *mut JSRuntime { self.runtime.rt() } @@ -281,49 +270,45 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { base64_atob(atob) } - // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval + // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout fn SetTimeout(&self, _cx: *mut JSContext, callback: Rc, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Worker(self), - TimerCallback::FunctionTimerCallback(callback), - args, - timeout, - IsInterval::NonInterval, - TimerSource::FromWorker) + self.upcast::().set_timeout_or_interval( + TimerCallback::FunctionTimerCallback(callback), + args, + timeout, + IsInterval::NonInterval) } - // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval + // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout fn SetTimeout_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Worker(self), - TimerCallback::StringTimerCallback(callback), - args, - timeout, - IsInterval::NonInterval, - TimerSource::FromWorker) + self.upcast::().set_timeout_or_interval( + TimerCallback::StringTimerCallback(callback), + args, + timeout, + IsInterval::NonInterval) } - // https://html.spec.whatwg.org/multipage/#dom-windowtimers-clearinterval + // https://html.spec.whatwg.org/multipage/#dom-windowtimers-cleartimeout fn ClearTimeout(&self, handle: i32) { - self.timers.clear_timeout_or_interval(GlobalRef::Worker(self), handle); + self.upcast::().clear_timeout_or_interval(handle); } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval fn SetInterval(&self, _cx: *mut JSContext, callback: Rc, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Worker(self), - TimerCallback::FunctionTimerCallback(callback), - args, - timeout, - IsInterval::Interval, - TimerSource::FromWorker) + self.upcast::().set_timeout_or_interval( + TimerCallback::FunctionTimerCallback(callback), + args, + timeout, + IsInterval::Interval) } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval fn SetInterval_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec) -> i32 { - self.timers.set_timeout_or_interval(GlobalRef::Worker(self), - TimerCallback::StringTimerCallback(callback), - args, - timeout, - IsInterval::Interval, - TimerSource::FromWorker) + self.upcast::().set_timeout_or_interval( + TimerCallback::StringTimerCallback(callback), + args, + timeout, + IsInterval::Interval) } // https://html.spec.whatwg.org/multipage/#dom-windowtimers-clearinterval @@ -401,7 +386,7 @@ impl WorkerGlobalScope { } pub fn handle_fire_timer(&self, timer_id: TimerEventId) { - self.timers.fire_timer(timer_id, self); + self.upcast::().fire_timer(timer_id); } pub fn close(&self) { diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index a5b09193b7f..7a586cfe6a1 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -1077,15 +1077,14 @@ impl XMLHttpRequest { xhr: Trusted::new(self), generation_id: self.generation_id.get(), }); - let global = self.global(); let duration = Length::new(duration_ms as u64); - *self.timeout_cancel.borrow_mut() = Some(global.r().schedule_callback(callback, duration)); + *self.timeout_cancel.borrow_mut() = + Some(self.global_scope().schedule_callback(callback, duration)); } fn cancel_timeout(&self) { if let Some(handle) = self.timeout_cancel.borrow_mut().take() { - let global = self.global(); - global.r().unschedule_callback(handle); + self.global_scope().unschedule_callback(handle); } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index cbfcbd0cca4..0d3f605fac1 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -1244,9 +1244,9 @@ impl ScriptThread { if let Some(ref inner_context) = root_context.find(id) { let window = inner_context.active_window(); if visible { - window.speed_up_timers(); + window.upcast::().speed_up_timers(); } else { - window.slow_down_timers(); + window.upcast::().slow_down_timers(); } return true; } @@ -1291,7 +1291,7 @@ impl ScriptThread { if let Some(root_context) = self.browsing_context.get() { if let Some(ref inner_context) = root_context.find(id) { let window = inner_context.active_window(); - window.freeze(); + window.upcast::().suspend(); return; } } @@ -1805,7 +1805,7 @@ impl ScriptThread { } if incomplete.is_frozen { - window.freeze(); + window.upcast::().suspend(); } if !incomplete.is_visible { diff --git a/components/script/timers.rs b/components/script/timers.rs index 7b326f6b164..ddfd336cd4f 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -5,9 +5,9 @@ use dom::bindings::callback::ExceptionHandling::Report; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::FunctionBinding::Function; -use dom::bindings::global::GlobalRef; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; +use dom::globalscope::GlobalScope; use dom::testbinding::TestBindingCallback; use dom::xmlhttprequest::XHRTimeoutCallback; use euclid::length::Length; @@ -167,7 +167,7 @@ impl OneshotTimers { } } - pub fn fire_timer(&self, id: TimerEventId, this: &T) { + pub fn fire_timer(&self, id: TimerEventId, global: &GlobalScope) { let expected_id = self.expected_event_id.get(); if expected_id != id { debug!("ignoring timer fire event {:?} (expected {:?})", id, expected_id); @@ -200,7 +200,7 @@ impl OneshotTimers { for timer in timers_to_run { let callback = timer.callback; - callback.invoke(this, &self.js_timers); + callback.invoke(global, &self.js_timers); } self.schedule_timer_call(); @@ -272,7 +272,7 @@ impl OneshotTimers { } pub fn set_timeout_or_interval(&self, - global: GlobalRef, + global: &GlobalScope, callback: TimerCallback, arguments: Vec, timeout: i32, @@ -287,7 +287,7 @@ impl OneshotTimers { source) } - pub fn clear_timeout_or_interval(&self, global: GlobalRef, handle: i32) { + pub fn clear_timeout_or_interval(&self, global: &GlobalScope, handle: i32) { self.js_timers.clear_timeout_or_interval(global, handle) } } @@ -364,7 +364,7 @@ impl JsTimers { // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps pub fn set_timeout_or_interval(&self, - global: GlobalRef, + global: &GlobalScope, callback: TimerCallback, arguments: Vec, timeout: i32, @@ -414,7 +414,7 @@ impl JsTimers { new_handle } - pub fn clear_timeout_or_interval(&self, global: GlobalRef, handle: i32) { + pub fn clear_timeout_or_interval(&self, global: &GlobalScope, handle: i32) { let mut active_timers = self.active_timers.borrow_mut(); if let Some(entry) = active_timers.remove(&JsTimerHandle(handle)) { @@ -441,7 +441,7 @@ impl JsTimers { } // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps - fn initialize_and_schedule(&self, global: GlobalRef, mut task: JsTimerTask) { + fn initialize_and_schedule(&self, global: &GlobalScope, mut task: JsTimerTask) { let handle = task.handle; let mut active_timers = self.active_timers.borrow_mut(); @@ -514,7 +514,7 @@ impl JsTimerTask { // reschedule repeating timers when they were not canceled as part of step 4.2. if self.is_interval == IsInterval::Interval && timers.active_timers.borrow().contains_key(&self.handle) { - timers.initialize_and_schedule(this.global().r(), self); + timers.initialize_and_schedule(&this.global_scope(), self); } } }