aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/window.rs
diff options
context:
space:
mode:
authorbors-servo <release+servo@mozilla.com>2014-05-03 14:25:22 -0400
committerbors-servo <release+servo@mozilla.com>2014-05-03 14:25:22 -0400
commit731e66ff132e41cdc49bc5324c0e15be19c46ec2 (patch)
treeccce9b42e8a6c54245e53620082efe0b9840eae1 /src/components/script/dom/window.rs
parent4051a8096d7ba7e7f9c86e76d0b4bffd83e85805 (diff)
parent91278da9dd55582401154e07f9eea34425a332c2 (diff)
downloadservo-731e66ff132e41cdc49bc5324c0e15be19c46ec2.tar.gz
servo-731e66ff132e41cdc49bc5324c0e15be19c46ec2.zip
auto merge of #2101 : jdm/servo/newroot_rebase, r=Ms2ger
As described in #1764, this strategy uses the following properties: * DOM members are `JS<T>` types. These cannot be used with being explicitly rooted, but they are required for compiler-derived trace hooks. * Methods that take DOM type arguments receive `&[mut] JSRef<T>`. These are rooted value references that are cloneable but cannot escape. * Methods that return DOM values use `Unrooted<T>`. These are values that may or may not be rooted elsewhere, but callers must root them in order to interact with them in any way. One unsoundness hole exists - `Unrooted` values must be rooted ASAP, or there exists the danger that JSAPI calls could be made that could cause the underlying JS value to be GCed. * All methods are implemented on `JSRef<T>`, enforcing the requirement that all DOM values are rooted for the duration of a method call (with a few exceptions for layout-related code, which cannot root values and therefore interacts with `JS<T>` and `&T` values - this is safe under the assumption that layout code interacts with DOM nodes that are in the tree, therefore rooted, and does not run concurrently with content code)
Diffstat (limited to 'src/components/script/dom/window.rs')
-rw-r--r--src/components/script/dom/window.rs205
1 files changed, 117 insertions, 88 deletions
diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs
index 1e4f7167f45..258a85b1455 100644
--- a/src/components/script/dom/window.rs
+++ b/src/components/script/dom/window.rs
@@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::BindingDeclarations::WindowBinding;
-use dom::bindings::js::JS;
-use dom::bindings::trace::Untraceable;
+use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable};
+use dom::bindings::trace::{Traceable, Untraceable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::browsercontext::BrowserContext;
use dom::document::Document;
@@ -35,33 +35,25 @@ use std::rc::Rc;
use serialize::{Encoder, Encodable};
use url::Url;
-pub struct TimerHandle {
- pub handle: i32,
- pub cancel_chan: Option<Sender<()>>,
-}
+#[deriving(Eq, Encodable, TotalEq)]
+pub struct TimerId(i32);
-impl<S: Encoder<E>, E> Encodable<S, E> for TimerHandle {
- fn encode(&self, _s: &mut S) -> Result<(), E> {
- Ok(())
- }
+#[deriving(Encodable)]
+pub struct TimerHandle {
+ pub handle: TimerId,
+ pub data: TimerData,
+ pub cancel_chan: Untraceable<Option<Sender<()>>>,
}
-impl Hash for TimerHandle {
+impl Hash for TimerId {
fn hash(&self, state: &mut sip::SipState) {
- self.handle.hash(state);
+ let TimerId(id) = *self;
+ id.hash(state);
}
}
-impl Eq for TimerHandle {
- fn eq(&self, other: &TimerHandle) -> bool {
- self.handle == other.handle
- }
-}
-
-impl TotalEq for TimerHandle { }
-
impl TimerHandle {
- fn cancel(&self) {
+ fn cancel(&mut self) {
self.cancel_chan.as_ref().map(|chan| chan.send(()));
}
}
@@ -74,7 +66,7 @@ pub struct Window {
pub location: Option<JS<Location>>,
pub navigator: Option<JS<Navigator>>,
pub image_cache_task: ImageCacheTask,
- pub active_timers: ~HashMap<i32, TimerHandle>,
+ pub active_timers: ~HashMap<TimerId, TimerHandle>,
pub next_timer_handle: i32,
pub compositor: Untraceable<~ScriptListener>,
pub browser_context: Option<BrowserContext>,
@@ -98,7 +90,7 @@ impl Window {
#[unsafe_destructor]
impl Drop for Window {
fn drop(&mut self) {
- for timer_handle in self.active_timers.values() {
+ for (_, timer_handle) in self.active_timers.mut_iter() {
timer_handle.cancel();
}
}
@@ -107,94 +99,155 @@ impl Drop for Window {
// 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)
+#[deriving(Encodable)]
pub struct TimerData {
- pub handle: i32,
pub is_interval: bool,
- pub funval: JSVal,
+ pub funval: Traceable<JSVal>,
}
-impl Window {
- pub fn Alert(&self, s: DOMString) {
+pub trait WindowMethods {
+ fn Alert(&self, s: DOMString);
+ fn Close(&self);
+ fn Document(&self) -> Temporary<Document>;
+ fn Name(&self) -> DOMString;
+ fn SetName(&self, _name: DOMString);
+ fn Status(&self) -> DOMString;
+ fn SetStatus(&self, _status: DOMString);
+ fn Closed(&self) -> bool;
+ fn Stop(&self);
+ fn Focus(&self);
+ fn Blur(&self);
+ fn GetFrameElement(&self) -> Option<Temporary<Element>>;
+ fn Location(&mut self) -> Temporary<Location>;
+ fn Console(&mut self) -> Temporary<Console>;
+ fn Navigator(&mut self) -> Temporary<Navigator>;
+ fn Confirm(&self, _message: DOMString) -> bool;
+ fn Prompt(&self, _message: DOMString, _default: DOMString) -> Option<DOMString>;
+ fn Print(&self);
+ fn ShowModalDialog(&self, _cx: *JSContext, _url: DOMString, _argument: Option<JSVal>) -> JSVal;
+ fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32;
+ fn ClearTimeout(&mut self, handle: i32);
+ fn SetInterval(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32;
+ fn ClearInterval(&mut self, handle: i32);
+ fn Window(&self) -> Temporary<Window>;
+ fn Self(&self) -> Temporary<Window>;
+}
+
+impl<'a> WindowMethods for JSRef<'a, Window> {
+ fn Alert(&self, s: DOMString) {
// Right now, just print to the console
println!("ALERT: {:s}", s);
}
- pub fn Close(&self) {
+ fn Close(&self) {
let ScriptChan(ref chan) = self.script_chan;
chan.send(ExitWindowMsg(self.page.id.clone()));
}
- pub fn Document(&self) -> JS<Document> {
+ fn Document(&self) -> Temporary<Document> {
let frame = self.page().frame();
- frame.get_ref().document.clone()
+ Temporary::new(frame.get_ref().document.clone())
}
- pub fn Name(&self) -> DOMString {
+ fn Name(&self) -> DOMString {
~""
}
- pub fn SetName(&self, _name: DOMString) {
+ fn SetName(&self, _name: DOMString) {
}
- pub fn Status(&self) -> DOMString {
+ fn Status(&self) -> DOMString {
~""
}
- pub fn SetStatus(&self, _status: DOMString) {
+ fn SetStatus(&self, _status: DOMString) {
}
- pub fn Closed(&self) -> bool {
+ fn Closed(&self) -> bool {
false
}
- pub fn Stop(&self) {
+ fn Stop(&self) {
}
- pub fn Focus(&self) {
+ fn Focus(&self) {
}
- pub fn Blur(&self) {
+ fn Blur(&self) {
}
- pub fn GetFrameElement(&self) -> Option<JS<Element>> {
+ fn GetFrameElement(&self) -> Option<Temporary<Element>> {
None
}
- pub fn Location(&mut self, abstract_self: &JS<Window>) -> JS<Location> {
+ fn Location(&mut self) -> Temporary<Location> {
if self.location.is_none() {
- self.location = Some(Location::new(abstract_self, self.page.clone()));
+ let page = self.deref().page.clone();
+ let location = Location::new(self, page);
+ self.location.assign(Some(location));
}
- self.location.get_ref().clone()
+ Temporary::new(self.location.get_ref().clone())
}
- pub fn Console(&mut self, abstract_self: &JS<Window>) -> JS<Console> {
+ fn Console(&mut self) -> Temporary<Console> {
if self.console.is_none() {
- self.console = Some(Console::new(abstract_self));
+ let console = Console::new(self);
+ self.console.assign(Some(console));
}
- self.console.get_ref().clone()
+ Temporary::new(self.console.get_ref().clone())
}
- pub fn Navigator(&mut self, abstract_self: &JS<Window>) -> JS<Navigator> {
+ fn Navigator(&mut self) -> Temporary<Navigator> {
if self.navigator.is_none() {
- self.navigator = Some(Navigator::new(abstract_self));
+ let navigator = Navigator::new(self);
+ self.navigator.assign(Some(navigator));
}
- self.navigator.get_ref().clone()
+ Temporary::new(self.navigator.get_ref().clone())
}
- pub fn Confirm(&self, _message: DOMString) -> bool {
+ fn Confirm(&self, _message: DOMString) -> bool {
false
}
- pub fn Prompt(&self, _message: DOMString, _default: DOMString) -> Option<DOMString> {
+ fn Prompt(&self, _message: DOMString, _default: DOMString) -> Option<DOMString> {
None
}
- pub fn Print(&self) {
+ fn Print(&self) {
}
- pub fn ShowModalDialog(&self, _cx: *JSContext, _url: DOMString, _argument: Option<JSVal>) -> JSVal {
+ fn ShowModalDialog(&self, _cx: *JSContext, _url: DOMString, _argument: Option<JSVal>) -> JSVal {
NullValue()
}
+
+ fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
+ self.set_timeout_or_interval(callback, timeout, false)
+ }
+
+ fn ClearTimeout(&mut self, handle: i32) {
+ let mut timer_handle = self.active_timers.pop(&TimerId(handle));
+ match timer_handle {
+ Some(ref mut handle) => handle.cancel(),
+ None => { }
+ }
+ self.active_timers.remove(&TimerId(handle));
+ }
+
+ fn SetInterval(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
+ self.set_timeout_or_interval(callback, timeout, true)
+ }
+
+ fn ClearInterval(&mut self, handle: i32) {
+ self.ClearTimeout(handle);
+ }
+
+ fn Window(&self) -> Temporary<Window> {
+ Temporary::from_rooted(self)
+ }
+
+ fn Self(&self) -> Temporary<Window> {
+ self.Window()
+ }
}
impl Reflectable for Window {
@@ -243,13 +296,8 @@ impl Window {
let id = select.wait();
if id == timeout_handle.id() {
timeout_port.recv();
- let data = ~TimerData {
- handle: handle,
- is_interval: is_interval,
- funval: callback,
- };
let ScriptChan(ref chan) = chan;
- chan.send(FireTimerMsg(page_id, data));
+ chan.send(FireTimerMsg(page_id, TimerId(handle)));
if !is_interval {
break;
}
@@ -258,38 +306,19 @@ impl Window {
}
}
});
- self.active_timers.insert(handle, TimerHandle { handle: handle, cancel_chan: Some(cancel_chan) });
+ let timer_id = TimerId(handle);
+ let timer = TimerHandle {
+ handle: timer_id,
+ cancel_chan: Untraceable::new(Some(cancel_chan)),
+ data: TimerData {
+ is_interval: is_interval,
+ funval: Traceable::new(callback),
+ }
+ };
+ self.active_timers.insert(timer_id, timer);
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 {
- Some(handle) => handle.cancel(),
- None => { }
- }
- }
-
- 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 Window(&self, abstract_self: &JS<Window>) -> JS<Window> {
- abstract_self.clone()
- }
-
- pub fn Self(&self, abstract_self: &JS<Window>) -> JS<Window> {
- self.Window(abstract_self)
- }
-
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
@@ -304,7 +333,7 @@ impl Window {
self.page().join_layout();
}
- pub fn init_browser_context(&mut self, doc: &JS<Document>) {
+ pub fn init_browser_context(&mut self, doc: &JSRef<Document>) {
self.browser_context = Some(BrowserContext::new(doc));
}