mirror of
https://github.com/servo/servo.git
synced 2025-06-09 09:03:23 +00:00
Add thaw/freeze messages that can suspend/resume webcontent timers #4907
This commit is contained in:
parent
dc31d96f65
commit
c2961c94b4
6 changed files with 105 additions and 9 deletions
|
@ -834,6 +834,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
pipeline.clone(),
|
pipeline.clone(),
|
||||||
parent.borrow().clone())),
|
parent.borrow().clone())),
|
||||||
NavigationType::Load);
|
NavigationType::Load);
|
||||||
|
// Send message to ScriptTask that will suspend all timers
|
||||||
|
source_frame.pipeline.borrow().freeze();
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
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();
|
let old = self.current_frame().as_ref().unwrap();
|
||||||
for frame in old.iter() {
|
for frame in old.iter() {
|
||||||
frame.pipeline.borrow().revoke_paint_permission();
|
frame.pipeline.borrow().revoke_paint_permission();
|
||||||
|
frame.pipeline.borrow().freeze();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.navigation_context.forward(&mut *self.compositor_proxy)
|
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();
|
let old = self.current_frame().as_ref().unwrap();
|
||||||
for frame in old.iter() {
|
for frame in old.iter() {
|
||||||
frame.pipeline.borrow().revoke_paint_permission();
|
frame.pipeline.borrow().revoke_paint_permission();
|
||||||
|
frame.pipeline.borrow().freeze();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.navigation_context.back(&mut *self.compositor_proxy)
|
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() {
|
for frame in destination_frame.iter() {
|
||||||
frame.pipeline.borrow().load();
|
frame.pipeline.borrow().load();
|
||||||
|
frame.pipeline.borrow().thaw();
|
||||||
}
|
}
|
||||||
self.send_frame_tree_and_grant_paint_permission(destination_frame);
|
self.send_frame_tree_and_grant_paint_permission(destination_frame);
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
pub fn force_exit(&self) {
|
||||||
let ScriptControlChan(ref script_channel) = self.script_chan;
|
let ScriptControlChan(ref script_channel) = self.script_chan;
|
||||||
let _ = script_channel.send(
|
let _ = script_channel.send(
|
||||||
|
|
|
@ -335,6 +335,8 @@ pub trait WindowHelpers {
|
||||||
fn load_url(self, href: DOMString);
|
fn load_url(self, href: DOMString);
|
||||||
fn handle_fire_timer(self, timer_id: TimerId);
|
fn handle_fire_timer(self, timer_id: TimerId);
|
||||||
fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>;
|
fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>;
|
||||||
|
fn thaw(self);
|
||||||
|
fn freeze(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ScriptHelpers {
|
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>> {
|
fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn thaw(self) {
|
||||||
|
self.timers.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freeze(self) {
|
||||||
|
self.timers.suspend();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
|
|
@ -602,6 +602,10 @@ impl ScriptTask {
|
||||||
panic!("should have handled ExitPipeline already"),
|
panic!("should have handled ExitPipeline already"),
|
||||||
ConstellationControlMsg::GetTitle(pipeline_id) =>
|
ConstellationControlMsg::GetTitle(pipeline_id) =>
|
||||||
self.handle_get_title_msg(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);
|
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.
|
/// Handles a notification that reflow completed.
|
||||||
fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) {
|
fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) {
|
||||||
debug!("Script: Reflow {:?} complete for {:?}", reflow_id, pipeline_id);
|
debug!("Script: Reflow {:?} complete for {:?}", reflow_id, pipeline_id);
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub struct TimerId(i32);
|
||||||
struct TimerHandle {
|
struct TimerHandle {
|
||||||
handle: TimerId,
|
handle: TimerId,
|
||||||
data: TimerData,
|
data: TimerData,
|
||||||
cancel_chan: Option<Sender<()>>,
|
control_chan: Option<Sender<TimerControlMsg>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[jstraceable]
|
#[jstraceable]
|
||||||
|
@ -56,7 +56,13 @@ impl<H: Writer + Hasher> Hash<H> for TimerId {
|
||||||
|
|
||||||
impl TimerHandle {
|
impl TimerHandle {
|
||||||
fn cancel(&mut self) {
|
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,
|
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
|
// Holder for the various JS values associated with setTimeout
|
||||||
// (ie. function value to invoke and all arguments to pass
|
// (ie. function value to invoke and all arguments to pass
|
||||||
// to the function when calling it)
|
// 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)]
|
#[allow(unsafe_blocks)]
|
||||||
pub fn set_timeout_or_interval(&self,
|
pub fn set_timeout_or_interval(&self,
|
||||||
callback: TimerCallback,
|
callback: TimerCallback,
|
||||||
|
@ -122,7 +148,7 @@ impl TimerManager {
|
||||||
// Spawn a new timer task; it will dispatch the `ScriptMsg::FireTimer`
|
// Spawn a new timer task; it will dispatch the `ScriptMsg::FireTimer`
|
||||||
// to the relevant script handler that will deal with it.
|
// to the relevant script handler that will deal with it.
|
||||||
let tm = Timer::new().unwrap();
|
let tm = Timer::new().unwrap();
|
||||||
let (cancel_chan, cancel_port) = channel();
|
let (control_chan, control_port) = channel();
|
||||||
let spawn_name = match source {
|
let spawn_name = match source {
|
||||||
TimerSource::FromWindow(_) if is_interval == IsInterval::Interval => "Window:SetInterval",
|
TimerSource::FromWindow(_) if is_interval == IsInterval::Interval => "Window:SetInterval",
|
||||||
TimerSource::FromWorker if is_interval == IsInterval::Interval => "Worker:SetInterval",
|
TimerSource::FromWorker if is_interval == IsInterval::Interval => "Worker:SetInterval",
|
||||||
|
@ -137,31 +163,47 @@ impl TimerManager {
|
||||||
} else {
|
} else {
|
||||||
tm.oneshot(duration)
|
tm.oneshot(duration)
|
||||||
};
|
};
|
||||||
let cancel_port = cancel_port;
|
let control_port = control_port;
|
||||||
|
|
||||||
let select = Select::new();
|
let select = Select::new();
|
||||||
let mut timeout_handle = select.handle(&timeout_port);
|
let mut timeout_handle = select.handle(&timeout_port);
|
||||||
unsafe { timeout_handle.add() };
|
unsafe { timeout_handle.add() };
|
||||||
let mut cancel_handle = select.handle(&cancel_port);
|
let mut control_handle = select.handle(&control_port);
|
||||||
unsafe { cancel_handle.add() };
|
unsafe { control_handle.add() };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let id = select.wait();
|
let id = select.wait();
|
||||||
|
|
||||||
if id == timeout_handle.id() {
|
if id == timeout_handle.id() {
|
||||||
timeout_port.recv().unwrap();
|
timeout_port.recv().unwrap();
|
||||||
script_chan.send(ScriptMsg::FireTimer(source, TimerId(handle)));
|
script_chan.send(ScriptMsg::FireTimer(source, TimerId(handle)));
|
||||||
if is_interval == IsInterval::NonInterval {
|
if is_interval == IsInterval::NonInterval {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if id == cancel_handle.id() {
|
} else if id == control_handle.id() {;
|
||||||
break;
|
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_id = TimerId(handle);
|
||||||
let timer = TimerHandle {
|
let timer = TimerHandle {
|
||||||
handle: timer_id,
|
handle: timer_id,
|
||||||
cancel_chan: Some(cancel_chan),
|
control_chan: Some(control_chan),
|
||||||
data: TimerData {
|
data: TimerData {
|
||||||
is_interval: is_interval,
|
is_interval: is_interval,
|
||||||
callback: callback,
|
callback: callback,
|
||||||
|
|
|
@ -71,6 +71,10 @@ pub enum ConstellationControlMsg {
|
||||||
Viewport(PipelineId, Rect<f32>),
|
Viewport(PipelineId, Rect<f32>),
|
||||||
/// Requests that the script task immediately send the constellation the title of a pipeline.
|
/// Requests that the script task immediately send the constellation the title of a pipeline.
|
||||||
GetTitle(PipelineId),
|
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 {
|
unsafe impl Send for ConstellationControlMsg {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue