diff --git a/src/components/script/dom/webidls/Window.webidl b/src/components/script/dom/webidls/Window.webidl index 0260324b91e5..2405055c15cd 100644 --- a/src/components/script/dom/webidls/Window.webidl +++ b/src/components/script/dom/webidls/Window.webidl @@ -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); diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index 9ba9d00da82f..a0b7ef3740b7 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -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 diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index a585c320ad9b..096a0d40b6af 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -660,9 +660,15 @@ impl ScriptTask { let frame = page.frame(); let mut window = frame.get_ref().window.clone(); - let timer_handle = window.get_mut().active_timers.pop(&timer_data.handle); - if timer_handle.is_none() { - return; + { + let timer_handle = window.get().active_timers.find(&timer_data.handle); + if timer_handle.is_none() { + return; + } + } + + if !timer_data.is_interval { + window.get_mut().active_timers.remove(&timer_data.handle); } let js_info = page.js_info(); diff --git a/src/test/content/test_window_setInterval.html b/src/test/content/test_window_setInterval.html new file mode 100644 index 000000000000..6fb3ddeb6ba7 --- /dev/null +++ b/src/test/content/test_window_setInterval.html @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/src/test/html/test_interval.html b/src/test/html/test_interval.html new file mode 100644 index 000000000000..3f95b98695a6 --- /dev/null +++ b/src/test/html/test_interval.html @@ -0,0 +1,19 @@ + + + + + + +