aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/bindings/js.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/script/dom/bindings/js.rs')
-rw-r--r--src/components/script/dom/bindings/js.rs224
1 files changed, 220 insertions, 4 deletions
diff --git a/src/components/script/dom/bindings/js.rs b/src/components/script/dom/bindings/js.rs
index 10aec5424bc..dac459f9c03 100644
--- a/src/components/script/dom/bindings/js.rs
+++ b/src/components/script/dom/bindings/js.rs
@@ -4,11 +4,13 @@
use dom::bindings::utils::{Reflector, Reflectable};
use dom::window::Window;
-use js::jsapi::JSContext;
+use js::jsapi::{JSObject, JSContext};
use layout_interface::TrustedNodeAddress;
use std::cast;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
+use std::ptr;
+//use std::ops::{Deref, DerefMut};
pub struct JS<T> {
ptr: RefCell<*mut T>
@@ -31,8 +33,8 @@ impl <T> Clone for JS<T> {
impl<T: Reflectable> JS<T> {
pub fn new(obj: ~T,
- window: &JS<Window>,
- wrap_fn: extern "Rust" fn(*JSContext, &JS<Window>, ~T) -> JS<T>) -> JS<T> {
+ window: &JSRef<Window>,
+ wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~T) -> JS<T>) -> JS<T> {
wrap_fn(window.get().get_cx(), window, obj)
}
@@ -49,6 +51,10 @@ impl<T: Reflectable> JS<T> {
ptr: RefCell::new(addr as *mut T)
}
}
+
+ pub fn root<'a>(&self, collection: &'a RootCollection) -> Root<'a, T> {
+ collection.new_root(self)
+ }
}
impl<T: Reflectable> Reflectable for JS<T> {
@@ -94,3 +100,213 @@ impl<From, To> JS<From> {
cast::transmute_copy(self)
}
}
+
+pub trait RootedReference<T> {
+ fn root_ref<'a>(&'a self) -> Option<JSRef<'a, T>>;
+}
+
+impl<'a, T: Reflectable> RootedReference<T> for Option<Root<'a, T>> {
+ fn root_ref<'a>(&'a self) -> Option<JSRef<'a, T>> {
+ self.as_ref().map(|root| root.root_ref())
+ }
+}
+
+#[deriving(Eq, Clone)]
+struct RootReference(*JSObject);
+
+impl RootReference {
+ fn new<'a, T: Reflectable>(unrooted: &Root<'a, T>) -> RootReference {
+ RootReference(unrooted.rooted())
+ }
+
+ fn null() -> RootReference {
+ RootReference(ptr::null())
+ }
+}
+
+static MAX_STACK_ROOTS: uint = 10;
+
+pub struct RootCollection {
+ roots: [Cell<RootReference>, ..MAX_STACK_ROOTS],
+ current: Cell<uint>,
+}
+
+impl RootCollection {
+ pub fn new() -> RootCollection {
+ RootCollection {
+ roots: [Cell::new(RootReference::null()), ..MAX_STACK_ROOTS],
+ current: Cell::new(0),
+ }
+ }
+
+ fn new_root<'a, T: Reflectable>(&'a self, unrooted: &JS<T>) -> Root<'a, T> {
+ Root::new(self, unrooted)
+ }
+
+ fn root_impl(&self, unrooted: RootReference) {
+ let current = self.current.get();
+ assert!(current < MAX_STACK_ROOTS);
+ self.roots[current].set(unrooted);
+ self.current.set(current + 1);
+ }
+
+ fn root<'a, T: Reflectable>(&self, unrooted: &Root<'a, T>) {
+ self.root_impl(RootReference::new(unrooted));
+ }
+
+ pub fn root_raw(&self, unrooted: *JSObject) {
+ self.root_impl(RootReference(unrooted));
+ }
+
+ fn unroot_impl(&self, rooted: RootReference) {
+ let mut current = self.current.get();
+ assert!(current != 0);
+ current -= 1;
+ assert!(self.roots[current].get() == rooted);
+ self.roots[current].set(RootReference::null());
+ self.current.set(current);
+ }
+
+ fn unroot<'a, T: Reflectable>(&self, rooted: &Root<'a, T>) {
+ self.unroot_impl(RootReference::new(rooted));
+ }
+
+ pub fn unroot_raw(&self, rooted: *JSObject) {
+ self.unroot_impl(RootReference(rooted));
+ }
+}
+
+pub struct Root<'a, T> {
+ root_list: &'a RootCollection,
+ ptr: RefCell<*mut T>,
+}
+
+impl<'a, T: Reflectable> Root<'a, T> {
+ fn new(roots: &'a RootCollection, unrooted: &JS<T>) -> Root<'a, T> {
+ let root = Root {
+ root_list: roots,
+ ptr: unrooted.ptr.clone()
+ };
+ roots.root(&root);
+ root
+ }
+
+ pub fn get<'a>(&'a self) -> &'a T {
+ unsafe {
+ let borrow = self.ptr.borrow();
+ &**borrow
+ }
+ }
+
+ pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
+ unsafe {
+ let mut borrow = self.ptr.borrow_mut();
+ &mut **borrow
+ }
+ }
+
+ fn rooted(&self) -> *JSObject {
+ self.reflector().get_jsobject()
+ }
+
+ pub fn root_ref<'b>(&'b self) -> JSRef<'b,T> {
+ unsafe {
+ JSRef {
+ ptr: self.ptr.clone(),
+ chain: ::std::cast::transmute_region(&()),
+ }
+ }
+ }
+}
+
+#[unsafe_destructor]
+impl<'a, T: Reflectable> Drop for Root<'a, T> {
+ fn drop(&mut self) {
+ self.root_list.unroot(self);
+ }
+}
+
+impl<'a, T: Reflectable> Reflectable for Root<'a, T> {
+ fn reflector<'a>(&'a self) -> &'a Reflector {
+ self.get().reflector()
+ }
+
+ fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
+ self.get_mut().mut_reflector()
+ }
+}
+
+/*impl<'a, T> Deref for Root<'a, T> {
+ fn deref<'a>(&'a self) -> &'a T {
+ self.get()
+ }
+}
+
+impl<'a, T> DerefMut for Root<'a, T> {
+ fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+ self.get_mut()
+ }
+}*/
+
+/// Encapsulates a reference to something that is guaranteed to be alive. This is freely copyable.
+pub struct JSRef<'a, T> {
+ ptr: RefCell<*mut T>,
+ chain: &'a (),
+}
+
+impl<'a, T> Clone for JSRef<'a, T> {
+ fn clone(&self) -> JSRef<'a, T> {
+ JSRef {
+ ptr: self.ptr.clone(),
+ chain: self.chain
+ }
+ }
+}
+
+impl<'a, T> Eq for JSRef<'a, T> {
+ fn eq(&self, other: &JSRef<T>) -> bool {
+ self.ptr == other.ptr
+ }
+}
+
+impl<'a,T> JSRef<'a,T> {
+ pub fn get<'a>(&'a self) -> &'a T {
+ unsafe {
+ let borrow = self.ptr.borrow();
+ &**borrow
+ }
+ }
+
+ pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
+ let mut borrowed = self.ptr.borrow_mut();
+ unsafe {
+ &mut **borrowed
+ }
+ }
+
+ //XXXjdm It would be lovely if this could be private.
+ pub unsafe fn transmute<'b, To>(&'b self) -> &'b JSRef<'a, To> {
+ cast::transmute(self)
+ }
+
+ //XXXjdm It would be lovely if this could be private.
+ pub unsafe fn transmute_mut<'b, To>(&'b mut self) -> &'b mut JSRef<'a, To> {
+ cast::transmute(self)
+ }
+
+ pub fn unrooted(&self) -> JS<T> {
+ JS {
+ ptr: self.ptr.clone()
+ }
+ }
+}
+
+impl<'a, T: Reflectable> Reflectable for JSRef<'a, T> {
+ fn reflector<'a>(&'a self) -> &'a Reflector {
+ self.get().reflector()
+ }
+
+ fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
+ self.get_mut().mut_reflector()
+ }
+}