Auto merge of #8026 - eefriedman:js-rooting, r=nox

Fix uses of JS<T> as a type on the stack

`JS<T>` belongs on the heap, and only on the heap.  This is a collection of fixes so that code uses either `Root<T>` or `&T` to pass around garbage-collected pointers.

Ideally, we could completely ban constructing a `JS<T>` outside of constructor functions, but we aren't quite there yet.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8026)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-10-16 08:05:59 -06:00
commit 7c7dbde0f4
18 changed files with 204 additions and 186 deletions

View file

@ -180,7 +180,7 @@ impl Attr {
name: name, name: name,
namespace: namespace, namespace: namespace,
prefix: prefix, prefix: prefix,
owner: MutNullableHeap::new(owner.map(JS::from_ref)), owner: MutNullableHeap::new(owner),
} }
} }
@ -315,7 +315,7 @@ impl Attr {
} }
(old, new) => assert!(old == new) (old, new) => assert!(old == new)
} }
self.owner.set(owner.map(JS::from_ref)) self.owner.set(owner);
} }
pub fn owner(&self) -> Option<Root<Element>> { pub fn owner(&self) -> Option<Root<Element>> {

View file

@ -32,13 +32,19 @@ use js::jsapi::{Heap, JSObject, JSTracer};
use js::jsval::JSVal; use js::jsval::JSVal;
use layout_interface::TrustedNodeAddress; use layout_interface::TrustedNodeAddress;
use script_task::STACK_ROOTS; use script_task::STACK_ROOTS;
use std::cell::{Cell, UnsafeCell}; use std::cell::UnsafeCell;
use std::default::Default; use std::default::Default;
use std::ops::Deref; use std::ops::Deref;
use std::ptr;
use util::mem::HeapSizeOf; use util::mem::HeapSizeOf;
/// A traced reference to a DOM object. Must only be used as a field in other /// A traced reference to a DOM object
/// DOM objects. ///
/// This type is critical to making garbage collection work with the DOM,
/// but it is very dangerous; if garbage collection happens with a `JS<T>`
/// on the stack, the `JS<T>` can point to freed memory.
///
/// This should only be used as a field in other DOM objects.
#[must_root] #[must_root]
pub struct JS<T> { pub struct JS<T> {
ptr: NonZero<*const T> ptr: NonZero<*const T>
@ -54,12 +60,13 @@ impl<T> HeapSizeOf for JS<T> {
impl<T> JS<T> { impl<T> JS<T> {
/// Returns `LayoutJS<T>` containing the same pointer. /// Returns `LayoutJS<T>` containing the same pointer.
pub unsafe fn to_layout(self) -> LayoutJS<T> { pub unsafe fn to_layout(&self) -> LayoutJS<T> {
LayoutJS { LayoutJS {
ptr: self.ptr.clone() ptr: self.ptr.clone()
} }
} }
} }
impl<T: Reflectable> JS<T> { impl<T: Reflectable> JS<T> {
/// Root this JS-owned value to prevent its collection as garbage. /// Root this JS-owned value to prevent its collection as garbage.
pub fn root(&self) -> Root<T> { pub fn root(&self) -> Root<T> {
@ -109,8 +116,6 @@ impl<T: Reflectable> LayoutJS<T> {
} }
} }
impl<T> Copy for JS<T> {}
impl<T> Copy for LayoutJS<T> {} impl<T> Copy for LayoutJS<T> {}
impl<T> PartialEq for JS<T> { impl<T> PartialEq for JS<T> {
@ -205,73 +210,76 @@ impl MutHeapJSVal {
/// A holder that provides interior mutability for GC-managed values such as /// A holder that provides interior mutability for GC-managed values such as
/// `JS<T>`. /// `JS<T>`. Essentially a `Cell<JS<T>>`, but safer.
///
/// This should only be used as a field in other DOM objects; see warning
/// on `JS<T>`.
#[must_root] #[must_root]
#[derive(JSTraceable)] #[derive(JSTraceable)]
#[derive(HeapSizeOf)] pub struct MutHeap<T: HeapGCValue> {
pub struct MutHeap<T: HeapGCValue + Copy> { val: UnsafeCell<T>,
val: Cell<T>,
} }
impl<T: HeapGCValue + Copy> MutHeap<T> { impl<T: Reflectable> MutHeap<JS<T>> {
/// Create a new `MutHeap`. /// Create a new `MutHeap`.
pub fn new(initial: T) -> MutHeap<T> { pub fn new(initial: &T) -> MutHeap<JS<T>> {
MutHeap { MutHeap {
val: Cell::new(initial), val: UnsafeCell::new(JS::from_ref(initial)),
} }
} }
/// Set this `MutHeap` to the given value. /// Set this `MutHeap` to the given value.
pub fn set(&self, val: T) { pub fn set(&self, val: &T) {
self.val.set(val) unsafe {
} *self.val.get() = JS::from_ref(val);
/// Set the value in this `MutHeap`.
pub fn get(&self) -> T {
self.val.get()
}
}
/// A mutable holder for GC-managed values such as `JSval` and `JS<T>`, with
/// nullability represented by an enclosing Option wrapper. Must be used in
/// place of traditional internal mutability to ensure that the proper GC
/// barriers are enforced.
#[must_root]
#[derive(JSTraceable, HeapSizeOf)]
pub struct MutNullableHeap<T: HeapGCValue + Copy> {
ptr: Cell<Option<T>>
}
impl<T: HeapGCValue + Copy> MutNullableHeap<T> {
/// Create a new `MutNullableHeap`.
pub fn new(initial: Option<T>) -> MutNullableHeap<T> {
MutNullableHeap {
ptr: Cell::new(initial)
} }
} }
/// Set this `MutNullableHeap` to the given value. /// Set the value in this `MutHeap`.
pub fn set(&self, val: Option<T>) { pub fn get(&self) -> Root<T> {
self.ptr.set(val); unsafe {
} ptr::read(self.val.get()).root()
}
/// Retrieve a copy of the current optional inner value.
pub fn get(&self) -> Option<T> {
self.ptr.get()
} }
} }
impl<T: HeapGCValue> HeapSizeOf for MutHeap<T> {
fn heap_size_of_children(&self) -> usize {
// See comment on HeapSizeOf for JS<T>.
0
}
}
/// A holder that provides interior mutability for GC-managed values such as
/// `JS<T>`, with nullability represented by an enclosing Option wrapper.
/// Essentially a `Cell<Option<JS<T>>>`, but safer.
///
/// This should only be used as a field in other DOM objects; see warning
/// on `JS<T>`.
#[must_root]
#[derive(JSTraceable)]
pub struct MutNullableHeap<T: HeapGCValue> {
ptr: UnsafeCell<Option<T>>
}
impl<T: Reflectable> MutNullableHeap<JS<T>> { impl<T: Reflectable> MutNullableHeap<JS<T>> {
/// Create a new `MutNullableHeap`.
pub fn new(initial: Option<&T>) -> MutNullableHeap<JS<T>> {
MutNullableHeap {
ptr: UnsafeCell::new(initial.map(JS::from_ref))
}
}
/// Retrieve a copy of the current inner value. If it is `None`, it is /// Retrieve a copy of the current inner value. If it is `None`, it is
/// initialized with the result of `cb` first. /// initialized with the result of `cb` first.
pub fn or_init<F>(&self, cb: F) -> Root<T> pub fn or_init<F>(&self, cb: F) -> Root<T>
where F: FnOnce() -> Root<T> where F: FnOnce() -> Root<T>
{ {
match self.get() { match self.get() {
Some(inner) => Root::from_rooted(inner), Some(inner) => inner,
None => { None => {
let inner = cb(); let inner = cb();
self.set(Some(JS::from_rooted(&inner))); self.set(Some(&inner));
inner inner
}, },
} }
@ -280,25 +288,45 @@ impl<T: Reflectable> MutNullableHeap<JS<T>> {
/// Retrieve a copy of the inner optional `JS<T>` as `LayoutJS<T>`. /// Retrieve a copy of the inner optional `JS<T>` as `LayoutJS<T>`.
/// For use by layout, which can't use safe types like Temporary. /// For use by layout, which can't use safe types like Temporary.
pub unsafe fn get_inner_as_layout(&self) -> Option<LayoutJS<T>> { pub unsafe fn get_inner_as_layout(&self) -> Option<LayoutJS<T>> {
self.ptr.get().map(|js| js.to_layout()) ptr::read(self.ptr.get()).map(|js| js.to_layout())
}
/// Get a rooted value out of this object
pub fn get(&self) -> Option<Root<T>> {
unsafe {
ptr::read(self.ptr.get()).map(|o| o.root())
}
} }
/// Get a rooted value out of this object /// Get a rooted value out of this object
// FIXME(#6684)
pub fn get_rooted(&self) -> Option<Root<T>> { pub fn get_rooted(&self) -> Option<Root<T>> {
self.get().map(|o| o.root()) self.get()
}
/// Set this `MutNullableHeap` to the given value.
pub fn set(&self, val: Option<&T>) {
unsafe {
*self.ptr.get() = val.map(|p| JS::from_ref(p));
}
} }
} }
impl<T: HeapGCValue + Copy> Default for MutNullableHeap<T> { impl<T: HeapGCValue> Default for MutNullableHeap<T> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn default() -> MutNullableHeap<T> { fn default() -> MutNullableHeap<T> {
MutNullableHeap { MutNullableHeap {
ptr: Cell::new(None) ptr: UnsafeCell::new(None)
} }
} }
} }
impl<T: HeapGCValue> HeapSizeOf for MutNullableHeap<T> {
fn heap_size_of_children(&self) -> usize {
// See comment on HeapSizeOf for JS<T>.
0
}
}
impl<T: Reflectable> LayoutJS<T> { impl<T: Reflectable> LayoutJS<T> {
/// Returns an unsafe pointer to the interior of this JS object. This is /// Returns an unsafe pointer to the interior of this JS object. This is
/// the only method that be safely accessed from layout. (The fact that /// the only method that be safely accessed from layout. (The fact that
@ -435,12 +463,6 @@ impl<T: Reflectable> Root<T> {
pub fn r(&self) -> &T { pub fn r(&self) -> &T {
&**self &**self
} }
/// Generate a new root from a JS<T> reference
#[allow(unrooted_must_root)]
pub fn from_rooted(js: JS<T>) -> Root<T> {
js.root()
}
} }
impl<T: Reflectable> Deref for Root<T> { impl<T: Reflectable> Deref for Root<T> {

View file

@ -54,7 +54,7 @@ impl BrowsingContext {
} }
pub fn frame_element(&self) -> Option<Root<Element>> { pub fn frame_element(&self) -> Option<Root<Element>> {
self.frame_element.map(Root::from_rooted) self.frame_element.as_ref().map(JS::root)
} }
pub fn window_proxy(&self) -> *mut JSObject { pub fn window_proxy(&self) -> *mut JSObject {

View file

@ -763,7 +763,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
serialize(rgba, &mut result).unwrap(); serialize(rgba, &mut result).unwrap();
StringOrCanvasGradientOrCanvasPattern::eString(result) StringOrCanvasGradientOrCanvasPattern::eString(result)
}, },
CanvasFillOrStrokeStyle::Gradient(gradient) => { CanvasFillOrStrokeStyle::Gradient(ref gradient) => {
StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient.root()) StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient.root())
}, },
} }
@ -803,7 +803,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
serialize(rgba, &mut result).unwrap(); serialize(rgba, &mut result).unwrap();
StringOrCanvasGradientOrCanvasPattern::eString(result) StringOrCanvasGradientOrCanvasPattern::eString(result)
}, },
CanvasFillOrStrokeStyle::Gradient(gradient) => { CanvasFillOrStrokeStyle::Gradient(ref gradient) => {
StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient.root()) StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient.root())
}, },
} }

View file

@ -297,7 +297,7 @@ impl Document {
.filter_map(HTMLBaseElementCast::to_root) .filter_map(HTMLBaseElementCast::to_root)
.filter(|element| ElementCast::from_ref(&**element).has_attribute(&atom!("href"))) .filter(|element| ElementCast::from_ref(&**element).has_attribute(&atom!("href")))
.next(); .next();
self.base_element.set(base.map(|element| JS::from_ref(&*element))); self.base_element.set(base.r());
} }
pub fn quirks_mode(&self) -> QuirksMode { pub fn quirks_mode(&self) -> QuirksMode {
@ -506,7 +506,7 @@ impl Document {
/// Request that the given element receive focus once the current transaction is complete. /// Request that the given element receive focus once the current transaction is complete.
pub fn request_focus(&self, elem: &Element) { pub fn request_focus(&self, elem: &Element) {
if elem.is_focusable_area() { if elem.is_focusable_area() {
self.possibly_focused.set(Some(JS::from_ref(elem))) self.possibly_focused.set(Some(elem))
} }
} }
@ -520,7 +520,7 @@ impl Document {
node.set_focus_state(false); node.set_focus_state(false);
} }
self.focused.set(self.possibly_focused.get()); self.focused.set(self.possibly_focused.get().r());
if let Some(ref elem) = self.focused.get_rooted() { if let Some(ref elem) = self.focused.get_rooted() {
let node = NodeCast::from_ref(elem.r()); let node = NodeCast::from_ref(elem.r());
@ -852,7 +852,7 @@ impl Document {
} }
pub fn set_current_script(&self, script: Option<&HTMLScriptElement>) { pub fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
self.current_script.set(script.map(JS::from_ref)); self.current_script.set(script);
} }
pub fn trigger_mozbrowser_event(&self, event: MozBrowserEvent) { pub fn trigger_mozbrowser_event(&self, event: MozBrowserEvent) {
@ -959,7 +959,7 @@ impl Document {
} }
pub fn set_current_parser(&self, script: Option<&ServoHTMLParser>) { pub fn set_current_parser(&self, script: Option<&ServoHTMLParser>) {
self.current_parser.set(script.map(JS::from_ref)); self.current_parser.set(script);
} }
pub fn get_current_parser(&self) -> Option<Root<ServoHTMLParser>> { pub fn get_current_parser(&self) -> Option<Root<ServoHTMLParser>> {
@ -1119,8 +1119,7 @@ impl Document {
let new_doc = Document::new( let new_doc = Document::new(
&*self.window(), None, doctype, None, None, &*self.window(), None, doctype, None, None,
DocumentSource::NotFromParser, DocumentLoader::new(&self.loader())); DocumentSource::NotFromParser, DocumentLoader::new(&self.loader()));
new_doc.appropriate_template_contents_owner_document.set( new_doc.appropriate_template_contents_owner_document.set(Some(&new_doc));
Some(JS::from_ref(&*new_doc)));
new_doc new_doc
}) })
} }

View file

@ -106,12 +106,12 @@ impl Event {
#[inline] #[inline]
pub fn set_current_target(&self, val: &EventTarget) { pub fn set_current_target(&self, val: &EventTarget) {
self.current_target.set(Some(JS::from_ref(val))); self.current_target.set(Some(val));
} }
#[inline] #[inline]
pub fn set_target(&self, val: &EventTarget) { pub fn set_target(&self, val: &EventTarget) {
self.target.set(Some(JS::from_ref(val))); self.target.set(Some(val));
} }
#[inline] #[inline]

View file

@ -116,7 +116,7 @@ impl FileReader {
let global = fr.global.root(); let global = fr.global.root();
let exception = DOMException::new(global.r(), error); let exception = DOMException::new(global.r(), error);
fr.error.set(Some(JS::from_rooted(&exception))); fr.error.set(Some(&exception));
fr.dispatch_progress_event("error".to_owned(), 0, None); fr.dispatch_progress_event("error".to_owned(), 0, None);
return_on_abort!(); return_on_abort!();
@ -292,7 +292,7 @@ impl FileReaderMethods for FileReader {
let global = self.global.root(); let global = self.global.root();
let exception = DOMException::new(global.r(), DOMErrorName::AbortError); let exception = DOMException::new(global.r(), DOMErrorName::AbortError);
self.error.set(Some(JS::from_rooted(&exception))); self.error.set(Some(&exception));
self.terminate_ongoing_reading(); self.terminate_ongoing_reading();
// Steps 5 & 6 // Steps 5 & 6
@ -346,7 +346,7 @@ impl FileReader {
if blob.IsClosed() { if blob.IsClosed() {
let global = self.global.root(); let global = self.global.root();
let exception = DOMException::new(global.r(), DOMErrorName::InvalidStateError); let exception = DOMException::new(global.r(), DOMErrorName::InvalidStateError);
self.error.set(Some(JS::from_rooted(&exception))); self.error.set(Some(&exception));
self.dispatch_progress_event("error".to_owned(), 0, None); self.dispatch_progress_event("error".to_owned(), 0, None);
return Ok(()); return Ok(());

View file

@ -4,13 +4,14 @@
use canvas_traits::{CanvasMsg, FromLayoutMsg}; use canvas_traits::{CanvasMsg, FromLayoutMsg};
use dom::attr::Attr; use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::codegen::UnionTypes::CanvasRenderingContext2DOrWebGLRenderingContext; use dom::bindings::codegen::UnionTypes::CanvasRenderingContext2DOrWebGLRenderingContext;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, MutNullableHeap, Root}; use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::utils::{Reflectable}; use dom::bindings::utils::{Reflectable};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers}; use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document; use dom::document::Document;
@ -24,7 +25,6 @@ use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{HandleValue, JSContext};
use offscreen_gl_context::GLContextAttributes; use offscreen_gl_context::GLContextAttributes;
use std::cell::Cell; use std::cell::Cell;
use std::default::Default;
use std::iter::repeat; use std::iter::repeat;
use util::str::{DOMString, parse_unsigned_integer}; use util::str::{DOMString, parse_unsigned_integer};
@ -32,7 +32,7 @@ const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150; const DEFAULT_HEIGHT: u32 = 150;
#[must_root] #[must_root]
#[derive(JSTraceable, Clone, Copy, HeapSizeOf)] #[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext { pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>), Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>), WebGL(JS<WebGLRenderingContext>),
@ -43,7 +43,7 @@ impl HeapGCValue for CanvasContext {}
#[dom_struct] #[dom_struct]
pub struct HTMLCanvasElement { pub struct HTMLCanvasElement {
htmlelement: HTMLElement, htmlelement: HTMLElement,
context: MutNullableHeap<CanvasContext>, context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>, width: Cell<u32>,
height: Cell<u32>, height: Cell<u32>,
} }
@ -59,9 +59,8 @@ impl HTMLCanvasElement {
prefix: Option<DOMString>, prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement { document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement { HTMLCanvasElement {
htmlelement: htmlelement: HTMLElement::new_inherited(localName, prefix, document),
HTMLElement::new_inherited(localName, prefix, document), context: DOMRefCell::new(None),
context: Default::default(),
width: Cell::new(DEFAULT_WIDTH), width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT), height: Cell::new(DEFAULT_HEIGHT),
} }
@ -77,10 +76,10 @@ impl HTMLCanvasElement {
fn recreate_contexts(&self) { fn recreate_contexts(&self) {
let size = self.get_size(); let size = self.get_size();
if let Some(context) = self.context.get() { if let Some(ref context) = *self.context.borrow() {
match context { match *context {
CanvasContext::Context2d(context) => context.root().r().recreate(size), CanvasContext::Context2d(ref context) => context.root().r().recreate(size),
CanvasContext::WebGL(context) => context.root().r().recreate(size), CanvasContext::WebGL(ref context) => context.root().r().recreate(size),
} }
} }
} }
@ -105,10 +104,10 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn get_renderer_id(&self) -> Option<usize> { unsafe fn get_renderer_id(&self) -> Option<usize> {
let ref canvas = *self.unsafe_get(); let ref canvas = *self.unsafe_get();
canvas.context.get().map(|context| { canvas.context.borrow_for_layout().as_ref().map(|context| {
match context { match *context {
CanvasContext::Context2d(context) => context.to_layout().get_renderer_id(), CanvasContext::Context2d(ref context) => context.to_layout().get_renderer_id(),
CanvasContext::WebGL(context) => context.to_layout().get_renderer_id(), CanvasContext::WebGL(ref context) => context.to_layout().get_renderer_id(),
} }
}) })
} }
@ -116,10 +115,10 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn get_ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> { unsafe fn get_ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
let ref canvas = *self.unsafe_get(); let ref canvas = *self.unsafe_get();
canvas.context.get().map(|context| { canvas.context.borrow_for_layout().as_ref().map(|context| {
match context { match *context {
CanvasContext::Context2d(context) => context.to_layout().get_ipc_renderer(), CanvasContext::Context2d(ref context) => context.to_layout().get_ipc_renderer(),
CanvasContext::WebGL(context) => context.to_layout().get_ipc_renderer(), CanvasContext::WebGL(ref context) => context.to_layout().get_ipc_renderer(),
} }
}) })
} }
@ -138,24 +137,24 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
impl HTMLCanvasElement { impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> { pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.get().map(|context| { self.context.borrow().as_ref().map(|context| {
match context { match *context {
CanvasContext::Context2d(context) => context.root().r().ipc_renderer(), CanvasContext::Context2d(ref context) => context.root().r().ipc_renderer(),
CanvasContext::WebGL(context) => context.root().r().ipc_renderer(), CanvasContext::WebGL(ref context) => context.root().r().ipc_renderer(),
} }
}) })
} }
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> { pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.get().is_none() { if self.context.borrow().is_none() {
let window = window_from_node(self); let window = window_from_node(self);
let size = self.get_size(); let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size); let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
self.context.set(Some(CanvasContext::Context2d(JS::from_rooted(&context)))); *self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
} }
match self.context.get().unwrap() { match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(context) => Some(context.root()), CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None, _ => None,
} }
} }
@ -163,7 +162,7 @@ impl HTMLCanvasElement {
pub fn get_or_init_webgl_context(&self, pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext, cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> { attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.get().is_none() { if self.context.borrow().is_none() {
let window = window_from_node(self); let window = window_from_node(self);
let size = self.get_size(); let size = self.get_size();
@ -180,12 +179,12 @@ impl HTMLCanvasElement {
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs); let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
self.context.set(maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)))); *self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
} }
if let Some(context) = self.context.get() { if let Some(ref context) = *self.context.borrow() {
match context { match *context {
CanvasContext::WebGL(context) => Some(context.root()), CanvasContext::WebGL(ref context) => Some(context.root()),
_ => None, _ => None,
} }
} else { } else {

View file

@ -758,7 +758,7 @@ impl Activatable for HTMLInputElement {
InputType::InputRadio => { InputType::InputRadio => {
// We want to restore state only if the element had been changed in the first place // We want to restore state only if the element had been changed in the first place
if cache.was_mutable { if cache.was_mutable {
let old_checked: Option<Root<HTMLInputElement>> = cache.checked_radio.map(|t| t.root()); let old_checked = cache.checked_radio.as_ref().map(|t| t.root());
let name = self.get_radio_group_name(); let name = self.get_radio_group_name();
match old_checked { match old_checked {
Some(ref o) => { Some(ref o) => {

View file

@ -205,6 +205,6 @@ impl MouseEventMethods for MouseEvent {
self.shift_key.set(shiftKeyArg); self.shift_key.set(shiftKeyArg);
self.meta_key.set(metaKeyArg); self.meta_key.set(metaKeyArg);
self.button.set(buttonArg); self.button.set(buttonArg);
self.related_target.set(relatedTargetArg.map(JS::from_ref)); self.related_target.set(relatedTargetArg);
} }
} }

View file

@ -271,32 +271,32 @@ impl Node {
match prev_sibling { match prev_sibling {
None => { None => {
assert!(Some(*before) == self.first_child.get_rooted().r()); assert!(Some(*before) == self.first_child.get_rooted().r());
self.first_child.set(Some(JS::from_ref(new_child))); self.first_child.set(Some(new_child));
}, },
Some(ref prev_sibling) => { Some(ref prev_sibling) => {
prev_sibling.next_sibling.set(Some(JS::from_ref(new_child))); prev_sibling.next_sibling.set(Some(new_child));
new_child.prev_sibling.set(Some(JS::from_ref(prev_sibling.r()))); new_child.prev_sibling.set(Some(prev_sibling.r()));
}, },
} }
before.prev_sibling.set(Some(JS::from_ref(new_child))); before.prev_sibling.set(Some(new_child));
new_child.next_sibling.set(Some(JS::from_ref(before))); new_child.next_sibling.set(Some(before));
}, },
None => { None => {
let last_child = self.GetLastChild(); let last_child = self.GetLastChild();
match last_child { match last_child {
None => self.first_child.set(Some(JS::from_ref(new_child))), None => self.first_child.set(Some(new_child)),
Some(ref last_child) => { Some(ref last_child) => {
assert!(last_child.next_sibling.get().is_none()); assert!(last_child.next_sibling.get().is_none());
last_child.r().next_sibling.set(Some(JS::from_ref(new_child))); last_child.r().next_sibling.set(Some(new_child));
new_child.prev_sibling.set(Some(JS::from_rooted(&last_child))); new_child.prev_sibling.set(Some(&last_child));
} }
} }
self.last_child.set(Some(JS::from_ref(new_child))); self.last_child.set(Some(new_child));
}, },
} }
new_child.parent_node.set(Some(JS::from_ref(self))); new_child.parent_node.set(Some(self));
let parent_in_doc = self.is_in_doc(); let parent_in_doc = self.is_in_doc();
for node in new_child.traverse_preorder() { for node in new_child.traverse_preorder() {
@ -315,19 +315,19 @@ impl Node {
let prev_sibling = child.GetPreviousSibling(); let prev_sibling = child.GetPreviousSibling();
match prev_sibling { match prev_sibling {
None => { None => {
self.first_child.set(child.next_sibling.get()); self.first_child.set(child.next_sibling.get().r());
} }
Some(ref prev_sibling) => { Some(ref prev_sibling) => {
prev_sibling.next_sibling.set(child.next_sibling.get()); prev_sibling.next_sibling.set(child.next_sibling.get().r());
} }
} }
let next_sibling = child.GetNextSibling(); let next_sibling = child.GetNextSibling();
match next_sibling { match next_sibling {
None => { None => {
self.last_child.set(child.prev_sibling.get()); self.last_child.set(child.prev_sibling.get().r());
} }
Some(ref next_sibling) => { Some(ref next_sibling) => {
next_sibling.prev_sibling.set(child.prev_sibling.get()); next_sibling.prev_sibling.set(child.prev_sibling.get().r());
} }
} }
@ -591,7 +591,7 @@ impl Node {
match self.parent_node.get() { match self.parent_node.get() {
None => return, None => return,
Some(parent) => parent, Some(parent) => parent,
}.root(); };
for sibling in parent.r().children() { for sibling in parent.r().children() {
sibling.r().set_has_dirty_siblings(true); sibling.r().set_has_dirty_siblings(true);
@ -660,7 +660,7 @@ impl Node {
pub fn is_parent_of(&self, child: &Node) -> bool { pub fn is_parent_of(&self, child: &Node) -> bool {
match child.parent_node.get() { match child.parent_node.get() {
Some(ref parent) => parent.root().r() == self, Some(ref parent) => parent.r() == self,
None => false, None => false,
} }
} }
@ -689,7 +689,7 @@ impl Node {
// Step 2. // Step 2.
let parent = match parent.get() { let parent = match parent.get() {
None => return Ok(()), None => return Ok(()),
Some(ref parent) => parent.root(), Some(parent) => parent,
}; };
// Step 3. // Step 3.
@ -702,7 +702,7 @@ impl Node {
let viable_previous_sibling = match viable_previous_sibling { let viable_previous_sibling = match viable_previous_sibling {
Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(), Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
None => parent.first_child.get(), None => parent.first_child.get(),
}.map(|s| s.root()); };
// Step 6. // Step 6.
try!(Node::pre_insert(&node, &parent, viable_previous_sibling.r())); try!(Node::pre_insert(&node, &parent, viable_previous_sibling.r()));
@ -718,7 +718,7 @@ impl Node {
// Step 2. // Step 2.
let parent = match parent.get() { let parent = match parent.get() {
None => return Ok(()), None => return Ok(()),
Some(ref parent) => parent.root(), Some(parent) => parent,
}; };
// Step 3. // Step 3.
@ -745,7 +745,7 @@ impl Node {
let doc = self.owner_doc(); let doc = self.owner_doc();
let node = try!(doc.r().node_from_nodes_and_strings(nodes)); let node = try!(doc.r().node_from_nodes_and_strings(nodes));
// Step 3. // Step 3.
parent_node.root().r().ReplaceChild(node.r(), self).map(|_| ()) parent_node.r().ReplaceChild(node.r(), self).map(|_| ())
}, },
} }
} }
@ -823,11 +823,11 @@ impl Node {
} }
pub fn owner_doc(&self) -> Root<Document> { pub fn owner_doc(&self) -> Root<Document> {
self.owner_doc.get().unwrap().root() self.owner_doc.get().unwrap()
} }
pub fn set_owner_doc(&self, document: &Document) { pub fn set_owner_doc(&self, document: &Document) {
self.owner_doc.set(Some(JS::from_ref(document))); self.owner_doc.set(Some(document));
} }
pub fn is_in_html_doc(&self) -> bool { pub fn is_in_html_doc(&self) -> bool {
@ -1367,7 +1367,7 @@ impl Node {
last_child: Default::default(), last_child: Default::default(),
next_sibling: Default::default(), next_sibling: Default::default(),
prev_sibling: Default::default(), prev_sibling: Default::default(),
owner_doc: MutNullableHeap::new(doc.map(JS::from_ref)), owner_doc: MutNullableHeap::new(doc),
child_list: Default::default(), child_list: Default::default(),
children_count: Cell::new(0u32), children_count: Cell::new(0u32),
flags: Cell::new(flags), flags: Cell::new(flags),

View file

@ -36,7 +36,7 @@ impl NodeIterator {
NodeIterator { NodeIterator {
reflector_: Reflector::new(), reflector_: Reflector::new(),
root_node: JS::from_ref(root_node), root_node: JS::from_ref(root_node),
reference_node: MutHeap::new(JS::from_ref(root_node)), reference_node: MutHeap::new(root_node),
pointer_before_reference_node: Cell::new(true), pointer_before_reference_node: Cell::new(true),
what_to_show: what_to_show, what_to_show: what_to_show,
filter: filter filter: filter
@ -87,7 +87,7 @@ impl NodeIteratorMethods for NodeIterator {
// https://dom.spec.whatwg.org/#dom-nodeiterator-referencenode // https://dom.spec.whatwg.org/#dom-nodeiterator-referencenode
fn ReferenceNode(&self) -> Root<Node> { fn ReferenceNode(&self) -> Root<Node> {
self.reference_node.get().root() self.reference_node.get()
} }
// https://dom.spec.whatwg.org/#dom-nodeiterator-pointerbeforereferencenode // https://dom.spec.whatwg.org/#dom-nodeiterator-pointerbeforereferencenode
@ -99,7 +99,7 @@ impl NodeIteratorMethods for NodeIterator {
fn NextNode(&self) -> Fallible<Option<Root<Node>>> { fn NextNode(&self) -> Fallible<Option<Root<Node>>> {
// https://dom.spec.whatwg.org/#concept-NodeIterator-traverse // https://dom.spec.whatwg.org/#concept-NodeIterator-traverse
// Step 1. // Step 1.
let node = self.reference_node.get().root(); let node = self.reference_node.get();
// Step 2. // Step 2.
let mut before_node = self.pointer_before_reference_node.get(); let mut before_node = self.pointer_before_reference_node.get();
@ -114,7 +114,7 @@ impl NodeIteratorMethods for NodeIterator {
// Step 3-3. // Step 3-3.
if result == NodeFilterConstants::FILTER_ACCEPT { if result == NodeFilterConstants::FILTER_ACCEPT {
// Step 4. // Step 4.
self.reference_node.set(JS::from_ref(node.r())); self.reference_node.set(node.r());
self.pointer_before_reference_node.set(before_node); self.pointer_before_reference_node.set(before_node);
return Ok(Some(node)); return Ok(Some(node));
@ -129,7 +129,7 @@ impl NodeIteratorMethods for NodeIterator {
// Step 3-3. // Step 3-3.
if result == NodeFilterConstants::FILTER_ACCEPT { if result == NodeFilterConstants::FILTER_ACCEPT {
// Step 4. // Step 4.
self.reference_node.set(JS::from_ref(following_node.r())); self.reference_node.set(following_node.r());
self.pointer_before_reference_node.set(before_node); self.pointer_before_reference_node.set(before_node);
return Ok(Some(following_node)); return Ok(Some(following_node));
@ -143,7 +143,7 @@ impl NodeIteratorMethods for NodeIterator {
fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> { fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> {
// https://dom.spec.whatwg.org/#concept-NodeIterator-traverse // https://dom.spec.whatwg.org/#concept-NodeIterator-traverse
// Step 1. // Step 1.
let node = self.reference_node.get().root(); let node = self.reference_node.get();
// Step 2. // Step 2.
let mut before_node = self.pointer_before_reference_node.get(); let mut before_node = self.pointer_before_reference_node.get();
@ -158,7 +158,7 @@ impl NodeIteratorMethods for NodeIterator {
// Step 3-3. // Step 3-3.
if result == NodeFilterConstants::FILTER_ACCEPT { if result == NodeFilterConstants::FILTER_ACCEPT {
// Step 4. // Step 4.
self.reference_node.set(JS::from_ref(node.r())); self.reference_node.set(node.r());
self.pointer_before_reference_node.set(before_node); self.pointer_before_reference_node.set(before_node);
return Ok(Some(node)); return Ok(Some(node));
@ -174,7 +174,7 @@ impl NodeIteratorMethods for NodeIterator {
// Step 3-3. // Step 3-3.
if result == NodeFilterConstants::FILTER_ACCEPT { if result == NodeFilterConstants::FILTER_ACCEPT {
// Step 4. // Step 4.
self.reference_node.set(JS::from_ref(preceding_node.r())); self.reference_node.set(preceding_node.r());
self.pointer_before_reference_node.set(before_node); self.pointer_before_reference_node.set(before_node);
return Ok(Some(preceding_node)); return Ok(Some(preceding_node));

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding; use dom::bindings::codegen::Bindings::NodeListBinding;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::node::{ChildrenMutation, Node}; use dom::node::{ChildrenMutation, Node};
use dom::window::Window; use dom::window::Window;
@ -64,7 +64,7 @@ impl NodeListMethods for NodeList {
fn Item(&self, index: u32) -> Option<Root<Node>> { fn Item(&self, index: u32) -> Option<Root<Node>> {
match self.list_type { match self.list_type {
NodeListType::Simple(ref elems) => { NodeListType::Simple(ref elems) => {
elems.get(index as usize).map(|node| Root::from_rooted(*node)) elems.get(index as usize).map(|node| node.root())
}, },
NodeListType::Children(ref list) => list.item(index), NodeListType::Children(ref list) => list.item(index),
} }
@ -103,8 +103,7 @@ impl ChildrenList {
let last_visited = node.GetFirstChild(); let last_visited = node.GetFirstChild();
ChildrenList { ChildrenList {
node: JS::from_ref(node), node: JS::from_ref(node),
last_visited: last_visited: MutNullableHeap::new(last_visited.r()),
MutNullableHeap::new(last_visited.as_ref().map(JS::from_rooted)),
last_index: Cell::new(0u32), last_index: Cell::new(0u32),
} }
} }
@ -127,14 +126,14 @@ impl ChildrenList {
let last_index = self.last_index.get(); let last_index = self.last_index.get();
if index == last_index { if index == last_index {
// Item is last visited child, no need to update last visited. // Item is last visited child, no need to update last visited.
return Some(self.last_visited.get().unwrap().root()); return Some(self.last_visited.get().unwrap());
} }
let last_visited = if index - 1u32 == last_index { let last_visited = if index - 1u32 == last_index {
// Item is last visited's next sibling. // Item is last visited's next sibling.
self.last_visited.get().unwrap().root().GetNextSibling().unwrap() self.last_visited.get().unwrap().GetNextSibling().unwrap()
} else if last_index > 0 && index == last_index - 1u32 { } else if last_index > 0 && index == last_index - 1u32 {
// Item is last visited's previous sibling. // Item is last visited's previous sibling.
self.last_visited.get().unwrap().root().GetPreviousSibling().unwrap() self.last_visited.get().unwrap().GetPreviousSibling().unwrap()
} else if index > last_index { } else if index > last_index {
if index == len - 1u32 { if index == len - 1u32 {
// Item is parent's last child, not worth updating last visited. // Item is parent's last child, not worth updating last visited.
@ -142,7 +141,7 @@ impl ChildrenList {
} }
if index <= last_index + (len - last_index) / 2u32 { if index <= last_index + (len - last_index) / 2u32 {
// Item is closer to the last visited child and follows it. // Item is closer to the last visited child and follows it.
self.last_visited.get().unwrap().root() self.last_visited.get().unwrap()
.inclusively_following_siblings() .inclusively_following_siblings()
.nth((index - last_index) as usize).unwrap() .nth((index - last_index) as usize).unwrap()
} else { } else {
@ -154,7 +153,7 @@ impl ChildrenList {
} }
} else if index >= last_index / 2u32 { } else if index >= last_index / 2u32 {
// Item is closer to the last visited child and precedes it. // Item is closer to the last visited child and precedes it.
self.last_visited.get().unwrap().root() self.last_visited.get().unwrap()
.inclusively_preceding_siblings() .inclusively_preceding_siblings()
.nth((last_index - index) as usize).unwrap() .nth((last_index - index) as usize).unwrap()
} else { } else {
@ -165,7 +164,7 @@ impl ChildrenList {
.nth(index as usize) .nth(index as usize)
.unwrap() .unwrap()
}; };
self.last_visited.set(Some(JS::from_rooted(&last_visited))); self.last_visited.set(Some(last_visited.r()));
self.last_index.set(index); self.last_index.set(index);
Some(last_visited) Some(last_visited)
} }
@ -178,7 +177,7 @@ impl ChildrenList {
} }
let index = list.last_index.get(); let index = list.last_index.get();
if index < len { if index < len {
list.last_visited.set(Some(JS::from_ref(added[index as usize]))); list.last_visited.set(Some(added[index as usize]));
} else if index / 2u32 >= len { } else if index / 2u32 >= len {
// If last index is twice as large as the number of added nodes, // If last index is twice as large as the number of added nodes,
// updating only it means that less nodes will be traversed if // updating only it means that less nodes will be traversed if
@ -187,7 +186,7 @@ impl ChildrenList {
} else { } else {
// If last index is not twice as large but still larger, // If last index is not twice as large but still larger,
// it's better to update it to the number of added nodes. // it's better to update it to the number of added nodes.
list.last_visited.set(Some(JS::from_ref(next))); list.last_visited.set(Some(next));
list.last_index.set(len); list.last_index.set(len);
} }
} }
@ -198,7 +197,7 @@ impl ChildrenList {
added: &[&Node], added: &[&Node],
next: Option<&Node>) { next: Option<&Node>) {
let index = list.last_index.get(); let index = list.last_index.get();
if removed == &*list.last_visited.get().unwrap().root() { if removed == &*list.last_visited.get().unwrap() {
let visited = match (prev, added, next) { let visited = match (prev, added, next) {
(None, _, None) => { (None, _, None) => {
// Such cases where parent had only one child should // Such cases where parent had only one child should
@ -213,7 +212,7 @@ impl ChildrenList {
prev prev
}, },
}; };
list.last_visited.set(Some(JS::from_ref(visited))); list.last_visited.set(Some(visited));
} else if added.len() != 1 { } else if added.len() != 1 {
// The replaced child isn't the last visited one, and there are // The replaced child isn't the last visited one, and there are
// 0 or more than 1 nodes to replace it. Special care must be // 0 or more than 1 nodes to replace it. Special care must be
@ -250,13 +249,13 @@ impl ChildrenList {
self.last_visited.set(None); self.last_visited.set(None);
self.last_index.set(0u32); self.last_index.set(0u32);
} else if index < len as u32 { } else if index < len as u32 {
self.last_visited.set(Some(JS::from_ref(added[index as usize]))); self.last_visited.set(Some(added[index as usize]));
} else { } else {
// Setting last visited to parent's last child serves no purpose, // Setting last visited to parent's last child serves no purpose,
// so the middle is arbitrarily chosen here in case the caller // so the middle is arbitrarily chosen here in case the caller
// wants random access. // wants random access.
let middle = len / 2; let middle = len / 2;
self.last_visited.set(Some(JS::from_ref(added[middle]))); self.last_visited.set(Some(added[middle]));
self.last_index.set(middle as u32); self.last_index.set(middle as u32);
} }
}, },
@ -264,8 +263,7 @@ impl ChildrenList {
} }
fn reset(&self) { fn reset(&self) {
self.last_visited.set( self.last_visited.set(self.node.root().GetFirstChild().as_ref().map(Root::r));
self.node.root().GetFirstChild().map(|node| JS::from_rooted(&node)));
self.last_index.set(0u32); self.last_index.set(0u32);
} }
} }

View file

@ -37,7 +37,7 @@ impl StorageEvent {
oldValue: oldValue, oldValue: oldValue,
newValue: newValue, newValue: newValue,
url: url, url: url,
storageArea: MutNullableHeap::new(storageArea.map(JS::from_ref)) storageArea: MutNullableHeap::new(storageArea)
} }
} }

View file

@ -35,7 +35,7 @@ impl TreeWalker {
TreeWalker { TreeWalker {
reflector_: Reflector::new(), reflector_: Reflector::new(),
root_node: JS::from_ref(root_node), root_node: JS::from_ref(root_node),
current_node: MutHeap::new(JS::from_ref(root_node)), current_node: MutHeap::new(root_node),
what_to_show: what_to_show, what_to_show: what_to_show,
filter: filter filter: filter
} }
@ -85,18 +85,18 @@ impl TreeWalkerMethods for TreeWalker {
// https://dom.spec.whatwg.org/#dom-treewalker-currentnode // https://dom.spec.whatwg.org/#dom-treewalker-currentnode
fn CurrentNode(&self) -> Root<Node> { fn CurrentNode(&self) -> Root<Node> {
self.current_node.get().root() self.current_node.get()
} }
// https://dom.spec.whatwg.org/#dom-treewalker-currentnode // https://dom.spec.whatwg.org/#dom-treewalker-currentnode
fn SetCurrentNode(&self, node: &Node) { fn SetCurrentNode(&self, node: &Node) {
self.current_node.set(JS::from_ref(node)); self.current_node.set(node);
} }
// https://dom.spec.whatwg.org/#dom-treewalker-parentnode // https://dom.spec.whatwg.org/#dom-treewalker-parentnode
fn ParentNode(&self) -> Fallible<Option<Root<Node>>> { fn ParentNode(&self) -> Fallible<Option<Root<Node>>> {
// "1. Let node be the value of the currentNode attribute." // "1. Let node be the value of the currentNode attribute."
let mut node = self.current_node.get().root(); let mut node = self.current_node.get();
// "2. While node is not null and is not root, run these substeps:" // "2. While node is not null and is not root, run these substeps:"
while !self.is_root_node(node.r()) { while !self.is_root_node(node.r()) {
// "1. Let node be node's parent." // "1. Let node be node's parent."
@ -106,7 +106,7 @@ impl TreeWalkerMethods for TreeWalker {
// "2. If node is not null and filtering node returns FILTER_ACCEPT, // "2. If node is not null and filtering node returns FILTER_ACCEPT,
// then set the currentNode attribute to node, return node." // then set the currentNode attribute to node, return node."
if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(node.r())) { if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(node.r())) {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(node)) return Ok(Some(node))
} }
}, },
@ -148,7 +148,7 @@ impl TreeWalkerMethods for TreeWalker {
// https://dom.spec.whatwg.org/#dom-treewalker-previousnode // https://dom.spec.whatwg.org/#dom-treewalker-previousnode
fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> { fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> {
// "1. Let node be the value of the currentNode attribute." // "1. Let node be the value of the currentNode attribute."
let mut node = self.current_node.get().root(); let mut node = self.current_node.get();
// "2. While node is not root, run these substeps:" // "2. While node is not root, run these substeps:"
while !self.is_root_node(node.r()) { while !self.is_root_node(node.r()) {
// "1. Let sibling be the previous sibling of node." // "1. Let sibling be the previous sibling of node."
@ -170,7 +170,7 @@ impl TreeWalkerMethods for TreeWalker {
_ if node.GetFirstChild().is_some() => _ if node.GetFirstChild().is_some() =>
node = node.GetLastChild().unwrap(), node = node.GetLastChild().unwrap(),
NodeFilterConstants::FILTER_ACCEPT => { NodeFilterConstants::FILTER_ACCEPT => {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(node)) return Ok(Some(node))
}, },
_ => break _ => break
@ -194,7 +194,7 @@ impl TreeWalkerMethods for TreeWalker {
// "5. Filter node and if the return value is FILTER_ACCEPT, then // "5. Filter node and if the return value is FILTER_ACCEPT, then
// set the currentNode attribute to node and return node." // set the currentNode attribute to node and return node."
if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(node.r())) { if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(node.r())) {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(node)) return Ok(Some(node))
} }
} }
@ -205,7 +205,7 @@ impl TreeWalkerMethods for TreeWalker {
// https://dom.spec.whatwg.org/#dom-treewalker-nextnode // https://dom.spec.whatwg.org/#dom-treewalker-nextnode
fn NextNode(&self) -> Fallible<Option<Root<Node>>> { fn NextNode(&self) -> Fallible<Option<Root<Node>>> {
// "1. Let node be the value of the currentNode attribute." // "1. Let node be the value of the currentNode attribute."
let mut node = self.current_node.get().root(); let mut node = self.current_node.get();
// "2. Let result be FILTER_ACCEPT." // "2. Let result be FILTER_ACCEPT."
let mut result = NodeFilterConstants::FILTER_ACCEPT; let mut result = NodeFilterConstants::FILTER_ACCEPT;
// "3. Run these substeps:" // "3. Run these substeps:"
@ -225,7 +225,7 @@ impl TreeWalkerMethods for TreeWalker {
// "3. If result is FILTER_ACCEPT, then // "3. If result is FILTER_ACCEPT, then
// set the currentNode attribute to node and return node." // set the currentNode attribute to node and return node."
if NodeFilterConstants::FILTER_ACCEPT == result { if NodeFilterConstants::FILTER_ACCEPT == result {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(node)) return Ok(Some(node))
} }
} }
@ -243,7 +243,7 @@ impl TreeWalkerMethods for TreeWalker {
// "4. If result is FILTER_ACCEPT, then // "4. If result is FILTER_ACCEPT, then
// set the currentNode attribute to node and return node." // set the currentNode attribute to node and return node."
if NodeFilterConstants::FILTER_ACCEPT == result { if NodeFilterConstants::FILTER_ACCEPT == result {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(node)) return Ok(Some(node))
} }
} }
@ -267,7 +267,7 @@ impl TreeWalker {
{ {
// "To **traverse children** of type *type*, run these steps:" // "To **traverse children** of type *type*, run these steps:"
// "1. Let node be the value of the currentNode attribute." // "1. Let node be the value of the currentNode attribute."
let cur = self.current_node.get().root(); let cur = self.current_node.get();
// "2. Set node to node's first child if type is first, and node's last child if type is last." // "2. Set node to node's first child if type is first, and node's last child if type is last."
// "3. If node is null, return null." // "3. If node is null, return null."
@ -284,7 +284,7 @@ impl TreeWalker {
// "2. If result is FILTER_ACCEPT, then set the currentNode // "2. If result is FILTER_ACCEPT, then set the currentNode
// attribute to node and return node." // attribute to node and return node."
NodeFilterConstants::FILTER_ACCEPT => { NodeFilterConstants::FILTER_ACCEPT => {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(Root::from_ref(node.r()))) return Ok(Some(Root::from_ref(node.r())))
}, },
// "3. If result is FILTER_SKIP, run these subsubsteps:" // "3. If result is FILTER_SKIP, run these subsubsteps:"
@ -342,7 +342,7 @@ impl TreeWalker {
{ {
// "To **traverse siblings** of type *type* run these steps:" // "To **traverse siblings** of type *type* run these steps:"
// "1. Let node be the value of the currentNode attribute." // "1. Let node be the value of the currentNode attribute."
let mut node = self.current_node.get().root(); let mut node = self.current_node.get();
// "2. If node is root, return null." // "2. If node is root, return null."
if self.is_root_node(node.r()) { if self.is_root_node(node.r()) {
return Ok(None) return Ok(None)
@ -361,7 +361,7 @@ impl TreeWalker {
// "3. If result is FILTER_ACCEPT, then set the currentNode // "3. If result is FILTER_ACCEPT, then set the currentNode
// attribute to node and return node." // attribute to node and return node."
if NodeFilterConstants::FILTER_ACCEPT == result { if NodeFilterConstants::FILTER_ACCEPT == result {
self.current_node.set(JS::from_rooted(&node)); self.current_node.set(&node);
return Ok(Some(node)) return Ok(Some(node))
} }
@ -447,7 +447,7 @@ impl TreeWalker {
} }
fn is_current_node(&self, node: &Node) -> bool { fn is_current_node(&self, node: &Node) -> bool {
JS::from_ref(node) == self.current_node.get() node == &*self.current_node.get()
} }
} }

View file

@ -92,7 +92,7 @@ impl UIEventMethods for UIEvent {
} }
event.InitEvent(type_, can_bubble, cancelable); event.InitEvent(type_, can_bubble, cancelable);
self.view.set(view.map(JS::from_ref)); self.view.set(view);
self.detail.set(detail); self.detail.set(detail);
} }
} }

View file

@ -86,7 +86,7 @@ impl WebGLProgram {
return Err(WebGLError::InvalidOperation); return Err(WebGLError::InvalidOperation);
} }
shader_slot.set(Some(JS::from_ref(shader))); shader_slot.set(Some(shader));
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::AttachShader(self.id, shader.id()))).unwrap(); self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::AttachShader(self.id, shader.id()))).unwrap();

View file

@ -12,7 +12,7 @@ use dom::bindings::codegen::InheritTypes::{EventCast, EventTargetCast, NodeCast}
use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement; use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::{JS, LayoutJS, Root}; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::event::{EventBubbles, EventCancelable}; use dom::event::{EventBubbles, EventCancelable};
use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::HTMLCanvasElement;
@ -78,8 +78,8 @@ pub struct WebGLRenderingContext {
canvas: JS<HTMLCanvasElement>, canvas: JS<HTMLCanvasElement>,
last_error: Cell<Option<WebGLError>>, last_error: Cell<Option<WebGLError>>,
texture_unpacking_settings: Cell<TextureUnpacking>, texture_unpacking_settings: Cell<TextureUnpacking>,
bound_texture_2d: Cell<Option<JS<WebGLTexture>>>, bound_texture_2d: MutNullableHeap<JS<WebGLTexture>>,
bound_texture_cube_map: Cell<Option<JS<WebGLTexture>>>, bound_texture_cube_map: MutNullableHeap<JS<WebGLTexture>>,
} }
impl WebGLRenderingContext { impl WebGLRenderingContext {
@ -104,8 +104,8 @@ impl WebGLRenderingContext {
canvas: JS::from_ref(canvas), canvas: JS::from_ref(canvas),
last_error: Cell::new(None), last_error: Cell::new(None),
texture_unpacking_settings: Cell::new(CONVERT_COLORSPACE), texture_unpacking_settings: Cell::new(CONVERT_COLORSPACE),
bound_texture_2d: Cell::new(None), bound_texture_2d: MutNullableHeap::new(None),
bound_texture_cube_map: Cell::new(None), bound_texture_cube_map: MutNullableHeap::new(None),
} }
}) })
} }
@ -149,8 +149,8 @@ impl WebGLRenderingContext {
pub fn bound_texture_for(&self, target: u32) -> Option<Root<WebGLTexture>> { pub fn bound_texture_for(&self, target: u32) -> Option<Root<WebGLTexture>> {
match target { match target {
constants::TEXTURE_2D => self.bound_texture_2d.get().map(|t| t.root()), constants::TEXTURE_2D => self.bound_texture_2d.get_rooted(),
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get().map(|t| t.root()), constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get_rooted(),
_ => unreachable!(), _ => unreachable!(),
} }
@ -360,7 +360,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if let Some(texture) = texture { if let Some(texture) = texture {
match texture.bind(target) { match texture.bind(target) {
Ok(_) => slot.set(Some(JS::from_ref(texture))), Ok(_) => slot.set(Some(texture)),
Err(err) => return self.webgl_error(err), Err(err) => return self.webgl_error(err),
} }
} else { } else {