diff options
Diffstat (limited to 'components/script/dom/globalscope.rs')
-rw-r--r-- | components/script/dom/globalscope.rs | 103 |
1 files changed, 95 insertions, 8 deletions
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 1933d1e926e..4896c59e048 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -39,6 +39,7 @@ use crate::task_source::networking::NetworkingTaskSource; use crate::task_source::performance_timeline::PerformanceTimelineTaskSource; use crate::task_source::port_message::PortMessageQueue; use crate::task_source::remote_event::RemoteEventTaskSource; +use crate::task_source::timer::TimerTaskSource; use crate::task_source::websocket::WebsocketTaskSource; use crate::task_source::TaskSource; use crate::task_source::TaskSourceName; @@ -134,8 +135,13 @@ pub struct GlobalScope { /// including resource_thread, filemanager_thread and storage_thread resource_threads: ResourceThreads, + /// The mechanism by which time-outs and intervals are scheduled. + /// <https://html.spec.whatwg.org/multipage/#timers> timers: OneshotTimers, + /// Have timers been initialized? + init_timers: Cell<bool>, + /// The origin of the globalscope origin: MutableOrigin, @@ -188,6 +194,13 @@ struct MessageListener { context: Trusted<GlobalScope>, } +/// A wrapper between timer events coming in over IPC, and the event-loop. +struct TimerListener { + canceller: TaskCanceller, + task_source: TimerTaskSource, + context: Trusted<GlobalScope>, +} + /// Data representing a message-port managed by this global. #[derive(JSTraceable, MallocSizeOf)] pub enum ManagedMessagePort { @@ -212,6 +225,34 @@ pub enum MessagePortState { UnManaged, } +impl TimerListener { + /// Handle a timer-event coming-in over IPC, + /// by queuing the appropriate task on the relevant event-loop. + fn handle(&self, event: TimerEvent) { + let context = self.context.clone(); + // Step 18, queue a task, + // https://html.spec.whatwg.org/multipage/#timer-initialisation-steps + let _ = self.task_source.queue_with_canceller( + task!(timer_event: move || { + let global = context.root(); + let TimerEvent(source, id) = event; + match source { + TimerSource::FromWorker => { + global.downcast::<WorkerGlobalScope>().expect("Window timer delivered to worker"); + }, + TimerSource::FromWindow(pipeline) => { + assert_eq!(pipeline, global.pipeline_id()); + global.downcast::<Window>().expect("Worker timer delivered to window"); + }, + }; + // Step 7, substeps run in a task. + global.fire_timer(id); + }), + &self.canceller, + ); + } +} + impl MessageListener { /// A new message came in, handle it via a task enqueued on the event-loop. /// A task is required, since we are using a trusted globalscope, @@ -297,7 +338,6 @@ impl GlobalScope { script_to_constellation_chan: ScriptToConstellationChan, scheduler_chan: IpcSender<TimerSchedulerMsg>, resource_threads: ResourceThreads, - timer_event_chan: IpcSender<TimerEvent>, origin: MutableOrigin, microtask_queue: Rc<MicrotaskQueue>, is_headless: bool, @@ -318,7 +358,8 @@ impl GlobalScope { scheduler_chan: scheduler_chan.clone(), in_error_reporting_mode: Default::default(), resource_threads, - timers: OneshotTimers::new(timer_event_chan, scheduler_chan), + timers: OneshotTimers::new(scheduler_chan), + init_timers: Default::default(), origin, microtask_queue, list_auto_close_worker: Default::default(), @@ -349,6 +390,36 @@ impl GlobalScope { false } + /// Setup the IPC-to-event-loop glue for timers to schedule themselves. + fn setup_timers(&self) { + if self.init_timers.get() { + return; + } + self.init_timers.set(true); + + let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap(); + self.timers.setup_scheduling(timer_ipc_chan); + + // Setup route from IPC to task-queue for the timer-task-source. + let context = Trusted::new(&*self); + let (task_source, canceller) = ( + self.timer_task_source(), + self.task_canceller(TaskSourceName::Timer), + ); + let timer_listener = TimerListener { + context, + task_source, + canceller, + }; + ROUTER.add_route( + timer_ipc_port.to_opaque(), + Box::new(move |message| { + let event = message.to().unwrap(); + timer_listener.handle(event); + }), + ); + } + /// Complete the transfer of a message-port. fn complete_port_transfer(&self, port_id: MessagePortId, tasks: VecDeque<PortMessageTask>) { let should_start = if let MessagePortState::Managed(_id, message_ports) = @@ -1063,6 +1134,18 @@ impl GlobalScope { unreachable!(); } + /// `TaskSource` to send messages to the timer queue of + /// this global scope. + pub fn timer_task_source(&self) -> TimerTaskSource { + if let Some(window) = self.downcast::<Window>() { + return window.task_manager().timer_task_source(); + } + if let Some(worker) = self.downcast::<WorkerGlobalScope>() { + return worker.timer_task_source(); + } + unreachable!(); + } + /// `TaskSource` to send messages to the remote-event task source of /// this global scope. pub fn remote_event_task_source(&self) -> RemoteEventTaskSource { @@ -1145,11 +1228,13 @@ impl GlobalScope { ) } + /// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps> pub fn schedule_callback( &self, callback: OneshotTimerCallback, duration: MsDuration, ) -> OneshotTimerHandle { + self.setup_timers(); self.timers .schedule_callback(callback, duration, self.timer_source()) } @@ -1158,6 +1243,7 @@ impl GlobalScope { self.timers.unschedule_callback(handle); } + /// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps> pub fn set_timeout_or_interval( &self, callback: TimerCallback, @@ -1165,6 +1251,7 @@ impl GlobalScope { timeout: i32, is_interval: IsInterval, ) -> i32 { + self.setup_timers(); self.timers.set_timeout_or_interval( self, callback, @@ -1176,27 +1263,27 @@ impl GlobalScope { } pub fn clear_timeout_or_interval(&self, handle: i32) { - self.timers.clear_timeout_or_interval(self, handle) + self.timers.clear_timeout_or_interval(self, handle); } pub fn fire_timer(&self, handle: TimerEventId) { - self.timers.fire_timer(handle, self) + self.timers.fire_timer(handle, self); } pub fn resume(&self) { - self.timers.resume() + self.timers.resume(); } pub fn suspend(&self) { - self.timers.suspend() + self.timers.suspend(); } pub fn slow_down_timers(&self) { - self.timers.slow_down() + self.timers.slow_down(); } pub fn speed_up_timers(&self) { - self.timers.speed_up() + self.timers.speed_up(); } fn timer_source(&self) -> TimerSource { |