Implement Window.set/clearInterval.(fixes #2116)

This commit is contained in:
lpy 2014-04-16 22:55:39 +08:00
parent 896cadbf62
commit b7dcf62ed0
5 changed files with 92 additions and 13 deletions

View file

@ -71,6 +71,8 @@ interface WindowTimers {
//XXXjdm No support for Function or variadic arguments yet
long setTimeout(any handler, optional long timeout = 0/*, any... arguments*/);
void clearTimeout(optional long handle = 0);
long setInterval(any handler, optional long timeout = 0/*, any... arguments*/);
void clearInterval(optional long handler = 0);
/*long setTimeout(DOMString handler, optional long timeout = 0, any... arguments);
long setInterval(Function handler, optional long timeout = 0, any... arguments);
long setInterval(DOMString handler, optional long timeout = 0, any... arguments);

View file

@ -128,6 +128,7 @@ impl Drop for Window {
// to the function when calling it)
pub struct TimerData {
handle: i32,
is_interval: bool,
funval: JSVal,
args: ~[JSVal],
}
@ -226,7 +227,7 @@ impl Reflectable for Window {
}
impl Window {
pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
fn set_timeout_or_interval(&mut self, callback: JSVal, timeout: i32, is_interval: bool) -> i32 {
let timeout = cmp::max(0, timeout) as u64;
let handle = self.next_timer_handle;
self.next_timer_handle += 1;
@ -236,9 +237,18 @@ impl Window {
let tm = Timer::new().unwrap();
let (cancel_chan, cancel_port) = channel();
let chan = self.extra.timer_chan.clone();
spawn_named("Window:SetTimeout", proc() {
let spawn_name = if is_interval {
"Window:SetInterval"
} else {
"Window:SetTimeout"
};
spawn_named(spawn_name, proc() {
let mut tm = tm;
let timeout_port = tm.oneshot(timeout);
let timeout_port = if is_interval {
tm.periodic(timeout)
} else {
tm.oneshot(timeout)
};
let cancel_port = cancel_port;
let select = Select::new();
@ -246,19 +256,33 @@ impl Window {
unsafe { timeout_handle.add() };
let mut cancel_handle = select.handle(&cancel_port);
unsafe { cancel_handle.add() };
let id = select.wait();
if id == timeout_handle.id() {
chan.send(TimerMessageFire(~TimerData {
handle: handle,
funval: callback,
args: ~[],
}));
loop {
let id = select.wait();
if id == timeout_handle.id() {
timeout_port.recv();
chan.send(TimerMessageFire(~TimerData {
handle: handle,
is_interval: is_interval,
funval: callback,
args: ~[],
}));
if !is_interval {
break;
}
} else if id == cancel_handle.id() {
break;
}
}
});
self.active_timers.insert(handle, TimerHandle { handle: handle, cancel_chan: Some(cancel_chan) });
handle
}
pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
self.set_timeout_or_interval(callback, timeout, false)
}
pub fn ClearTimeout(&mut self, handle: i32) {
let timer_handle = self.active_timers.pop(&handle);
match timer_handle {
@ -267,6 +291,14 @@ impl Window {
}
}
pub fn SetInterval(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
self.set_timeout_or_interval(callback, timeout, true)
}
pub fn ClearInterval(&mut self, handle: i32) {
self.ClearTimeout(handle);
}
pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
// FIXME This should probably be ReflowForQuery, not Display. All queries currently
// currently rely on the display list, which means we can't destroy it by