diff options
author | Pawel Kondzior <pawel@kondzior.com> | 2015-02-19 11:20:55 +0700 |
---|---|---|
committer | Pawel Kondzior <pawel@kondzior.com> | 2015-02-24 05:33:27 +0100 |
commit | c2961c94b49a401d647e3f10cf04cd74aa7287c8 (patch) | |
tree | 710a28fef8f76006e6978ab37ee7521774fd487d /components | |
parent | dc31d96f65246def19cb7a23f3a62795cd7344a1 (diff) | |
download | servo-c2961c94b49a401d647e3f10cf04cd74aa7287c8.tar.gz servo-c2961c94b49a401d647e3f10cf04cd74aa7287c8.zip |
Add thaw/freeze messages that can suspend/resume webcontent timers #4907
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/constellation.rs | 5 | ||||
-rw-r--r-- | components/compositing/pipeline.rs | 10 | ||||
-rw-r--r-- | components/script/dom/window.rs | 11 | ||||
-rw-r--r-- | components/script/script_task.rs | 24 | ||||
-rw-r--r-- | components/script/timers.rs | 60 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 4 |
6 files changed, 105 insertions, 9 deletions
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index dedf6e07b5e..daf2cb2503d 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -834,6 +834,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { pipeline.clone(), parent.borrow().clone())), NavigationType::Load); + // Send message to ScriptTask that will suspend all timers + source_frame.pipeline.borrow().freeze(); self.pipelines.insert(pipeline.id, pipeline); } @@ -853,6 +855,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { let old = self.current_frame().as_ref().unwrap(); for frame in old.iter() { frame.pipeline.borrow().revoke_paint_permission(); + frame.pipeline.borrow().freeze(); } } self.navigation_context.forward(&mut *self.compositor_proxy) @@ -865,6 +868,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { let old = self.current_frame().as_ref().unwrap(); for frame in old.iter() { frame.pipeline.borrow().revoke_paint_permission(); + frame.pipeline.borrow().freeze(); } } self.navigation_context.back(&mut *self.compositor_proxy) @@ -873,6 +877,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { for frame in destination_frame.iter() { frame.pipeline.borrow().load(); + frame.pipeline.borrow().thaw(); } self.send_frame_tree_and_grant_paint_permission(destination_frame); diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 9bb29db622f..27ee5eba150 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -191,6 +191,16 @@ impl Pipeline { } + pub fn freeze(&self) { + let ScriptControlChan(ref script_channel) = self.script_chan; + let _ = script_channel.send(ConstellationControlMsg::Freeze(self.id)).unwrap(); + } + + pub fn thaw(&self) { + let ScriptControlChan(ref script_channel) = self.script_chan; + let _ = script_channel.send(ConstellationControlMsg::Thaw(self.id)).unwrap(); + } + pub fn force_exit(&self) { let ScriptControlChan(ref script_channel) = self.script_chan; let _ = script_channel.send( diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index fcc56776c8d..2ec968ed6e5 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -335,6 +335,8 @@ pub trait WindowHelpers { fn load_url(self, href: DOMString); fn handle_fire_timer(self, timer_id: TimerId); fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>; + fn thaw(self); + fn freeze(self); } pub trait ScriptHelpers { @@ -404,6 +406,15 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>> { None } + + fn thaw(self) { + self.timers.resume(); + } + + fn freeze(self) { + self.timers.suspend(); + } + } impl Window { diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 8573efa9d3f..fa397113c9b 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -602,6 +602,10 @@ impl ScriptTask { panic!("should have handled ExitPipeline already"), ConstellationControlMsg::GetTitle(pipeline_id) => self.handle_get_title_msg(pipeline_id), + ConstellationControlMsg::Freeze(pipeline_id) => + self.handle_freeze_msg(pipeline_id), + ConstellationControlMsg::Thaw(pipeline_id) => + self.handle_thaw_msg(pipeline_id) } } @@ -685,6 +689,26 @@ impl ScriptTask { window.r().handle_fire_timer(timer_id); } + /// Handles freeze message + fn handle_freeze_msg(&self, id: PipelineId) { + let page = self.page.borrow_mut(); + let page = page.find(id).expect("ScriptTask: received freeze msg for a + pipeline ID not associated with this script task. This is a bug."); + let frame = page.frame(); + let window = frame.as_ref().unwrap().window.root(); + window.r().freeze(); + } + + /// Handles thaw message + fn handle_thaw_msg(&self, id: PipelineId) { + let page = self.page.borrow_mut(); + let page = page.find(id).expect("ScriptTask: received thaw msg for a + pipeline ID not associated with this script task. This is a bug."); + let frame = page.frame(); + let window = frame.as_ref().unwrap().window.root(); + window.r().thaw(); + } + /// Handles a notification that reflow completed. fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) { debug!("Script: Reflow {:?} complete for {:?}", reflow_id, pipeline_id); diff --git a/components/script/timers.rs b/components/script/timers.rs index 8f361ebcb7b..59efeeb7959 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -37,7 +37,7 @@ pub struct TimerId(i32); struct TimerHandle { handle: TimerId, data: TimerData, - cancel_chan: Option<Sender<()>>, + control_chan: Option<Sender<TimerControlMsg>>, } #[jstraceable] @@ -56,7 +56,13 @@ impl<H: Writer + Hasher> Hash<H> for TimerId { impl TimerHandle { fn cancel(&mut self) { - self.cancel_chan.as_ref().map(|chan| chan.send(()).ok()); + self.control_chan.as_ref().map(|chan| chan.send(TimerControlMsg::Cancel).ok()); + } + fn suspend(&mut self) { + self.control_chan.as_ref().map(|chan| chan.send(TimerControlMsg::Suspend).ok()); + } + fn resume(&mut self) { + self.control_chan.as_ref().map(|chan| chan.send(TimerControlMsg::Resume).ok()); } } @@ -85,6 +91,15 @@ pub enum IsInterval { NonInterval, } +// Messages sent control timers from script task +#[jstraceable] +#[derive(PartialEq, Copy, Clone, Show)] +pub enum TimerControlMsg { + Cancel, + Suspend, + Resume +} + // Holder for the various JS values associated with setTimeout // (ie. function value to invoke and all arguments to pass // to the function when calling it) @@ -106,6 +121,17 @@ impl TimerManager { } } + pub fn suspend(&self) { + for (_, timer_handle) in self.active_timers.borrow_mut().iter_mut() { + timer_handle.suspend(); + } + } + pub fn resume(&self) { + for (_, timer_handle) in self.active_timers.borrow_mut().iter_mut() { + timer_handle.resume(); + } + } + #[allow(unsafe_blocks)] pub fn set_timeout_or_interval(&self, callback: TimerCallback, @@ -122,7 +148,7 @@ impl TimerManager { // Spawn a new timer task; it will dispatch the `ScriptMsg::FireTimer` // to the relevant script handler that will deal with it. let tm = Timer::new().unwrap(); - let (cancel_chan, cancel_port) = channel(); + let (control_chan, control_port) = channel(); let spawn_name = match source { TimerSource::FromWindow(_) if is_interval == IsInterval::Interval => "Window:SetInterval", TimerSource::FromWorker if is_interval == IsInterval::Interval => "Worker:SetInterval", @@ -137,31 +163,47 @@ impl TimerManager { } else { tm.oneshot(duration) }; - let cancel_port = cancel_port; + let control_port = control_port; let select = Select::new(); let mut timeout_handle = select.handle(&timeout_port); unsafe { timeout_handle.add() }; - let mut cancel_handle = select.handle(&cancel_port); - unsafe { cancel_handle.add() }; + let mut control_handle = select.handle(&control_port); + unsafe { control_handle.add() }; loop { let id = select.wait(); + if id == timeout_handle.id() { timeout_port.recv().unwrap(); script_chan.send(ScriptMsg::FireTimer(source, TimerId(handle))); if is_interval == IsInterval::NonInterval { break; } - } else if id == cancel_handle.id() { - break; + } else if id == control_handle.id() {; + match control_port.recv().unwrap() { + TimerControlMsg::Suspend => { + let msg = control_port.recv().unwrap(); + match msg { + TimerControlMsg::Suspend => panic!("Nothing to suspend!"), + TimerControlMsg::Resume => {}, + TimerControlMsg::Cancel => { + break; + }, + } + }, + TimerControlMsg::Resume => panic!("Nothing to resume!"), + TimerControlMsg::Cancel => { + break; + } + } } } }); let timer_id = TimerId(handle); let timer = TimerHandle { handle: timer_id, - cancel_chan: Some(cancel_chan), + control_chan: Some(control_chan), data: TimerData { is_interval: is_interval, callback: callback, diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 6bee3c388d1..aedb11f2dd5 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -71,6 +71,10 @@ pub enum ConstellationControlMsg { Viewport(PipelineId, Rect<f32>), /// Requests that the script task immediately send the constellation the title of a pipeline. GetTitle(PipelineId), + /// Notifies script task to suspend all its timers + Freeze(PipelineId), + /// Notifies script task to resume all its timers + Thaw(PipelineId) } unsafe impl Send for ConstellationControlMsg { |