XHR timeouts use same abstraction as scripts timers. (fixes #3396)

This commit is contained in:
benshu 2015-10-23 11:54:45 +02:00
parent 13226f8472
commit d27a3244f2
6 changed files with 139 additions and 49 deletions

View file

@ -7,6 +7,7 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::reflector::Reflectable;
use dom::bindings::trace::JSTraceable;
use dom::window::ScriptHelpers;
use euclid::length::Length;
use js::jsapi::{HandleValue, Heap, RootedValue};
@ -106,6 +107,7 @@ pub enum TimerCallback {
enum InternalTimerCallback {
StringTimerCallback(DOMString),
FunctionTimerCallback(Rc<Function>, Rc<Vec<Heap<JSVal>>>),
InternalCallback(Box<ScheduledCallback>),
}
impl HeapSizeOf for InternalTimerCallback {
@ -115,6 +117,18 @@ impl HeapSizeOf for InternalTimerCallback {
}
}
pub trait ScheduledCallback: JSTraceable + HeapSizeOf {
fn invoke(self: Box<Self>);
fn box_clone(&self) -> Box<ScheduledCallback>;
}
impl Clone for Box<ScheduledCallback> {
fn clone(&self) -> Box<ScheduledCallback> {
self.box_clone()
}
}
impl ActiveTimers {
pub fn new(timer_event_chan: Box<TimerEventChan + Send>,
scheduler_chan: Sender<TimerEventRequest>)
@ -139,15 +153,6 @@ impl ActiveTimers {
is_interval: IsInterval,
source: TimerSource)
-> i32 {
// step 3
let TimerHandle(new_handle) = self.next_timer_handle.get();
self.next_timer_handle.set(TimerHandle(new_handle + 1));
let timeout = cmp::max(0, timeout);
// step 7
let duration = self.clamp_duration(Length::new(timeout as u64));
let next_call = self.base_time() + duration;
let callback = match callback {
TimerCallback::StringTimerCallback(code_str) =>
InternalTimerCallback::StringTimerCallback(code_str),
@ -165,6 +170,38 @@ impl ActiveTimers {
}
};
let timeout = cmp::max(0, timeout);
// step 7
let duration = self.clamp_duration(Length::new(timeout as u64));
let TimerHandle(handle) = self.schedule_internal_callback(callback, duration, is_interval, source);
handle
}
pub fn schedule_callback(&self,
callback: Box<ScheduledCallback>,
duration: MsDuration,
source: TimerSource) -> TimerHandle {
self.schedule_internal_callback(InternalTimerCallback::InternalCallback(callback),
duration,
IsInterval::NonInterval,
source)
}
// see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
fn schedule_internal_callback(&self,
callback: InternalTimerCallback,
duration: MsDuration,
is_interval: IsInterval,
source: TimerSource) -> TimerHandle {
assert!(self.suspended_since.get().is_none());
// step 3
let TimerHandle(new_handle) = self.next_timer_handle.get();
self.next_timer_handle.set(TimerHandle(new_handle + 1));
let next_call = self.base_time() + duration;
let timer = Timer {
handle: TimerHandle(new_handle),
source: source,
@ -184,11 +221,14 @@ impl ActiveTimers {
}
// step 10
new_handle
TimerHandle(new_handle)
}
pub fn clear_timeout_or_interval(&self, handle: i32) {
let handle = TimerHandle(handle);
self.unschedule_callback(TimerHandle(handle));
}
pub fn unschedule_callback(&self, handle: TimerHandle) {
let was_next = self.is_next_timer(handle);
self.timers.borrow_mut().retain(|t| t.handle != handle);
@ -258,7 +298,10 @@ impl ActiveTimers {
}).collect();
let _ = function.Call_(this, arguments, Report);
}
},
InternalTimerCallback::InternalCallback(callback) => {
callback.invoke();
},
};
self.nesting_level.set(0);