diff options
author | Josh Matthews <josh@joshmatthews.net> | 2014-04-17 14:54:11 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2014-04-17 17:41:09 -0400 |
commit | 742f73ded59eb9e9f4208642e053ddbfc48bce73 (patch) | |
tree | 0bdc322085ecc7113d45bd5e487c01ad534ea16c /src | |
parent | 7441dae1aff4966e40ef3cf4129f307d23e2eeba (diff) | |
download | servo-742f73ded59eb9e9f4208642e053ddbfc48bce73.tar.gz servo-742f73ded59eb9e9f4208642e053ddbfc48bce73.zip |
Add transparent Traceable and Untraceable types to aid proper rooting practices, and replace ad-hoc Untraceable structs with empty Encodable implementations.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/script/dom/bindings/codegen/CodegenRust.py | 10 | ||||
-rw-r--r-- | src/components/script/dom/bindings/js.rs | 3 | ||||
-rw-r--r-- | src/components/script/dom/bindings/trace.rs | 69 | ||||
-rw-r--r-- | src/components/script/dom/bindings/utils.rs | 8 | ||||
-rw-r--r-- | src/components/script/dom/document.rs | 37 | ||||
-rw-r--r-- | src/components/script/dom/htmliframeelement.rs | 21 | ||||
-rw-r--r-- | src/components/script/dom/htmlimageelement.rs | 26 | ||||
-rw-r--r-- | src/components/script/dom/htmlstyleelement.rs | 2 | ||||
-rw-r--r-- | src/components/script/dom/location.rs | 16 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 3 | ||||
-rw-r--r-- | src/components/script/dom/window.rs | 67 | ||||
-rw-r--r-- | src/components/script/html/hubbub_html_parser.rs | 2 | ||||
-rw-r--r-- | src/components/script/layout_interface.rs | 20 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 128 |
14 files changed, 217 insertions, 195 deletions
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py index 9470b61fab2..8d89fe1b879 100644 --- a/src/components/script/dom/bindings/codegen/CodegenRust.py +++ b/src/components/script/dom/bindings/codegen/CodegenRust.py @@ -1864,7 +1864,7 @@ def CreateBindingJSObject(descriptor, parent=None): assert not descriptor.createGlobal handler = """ let js_info = aScope.get().page().js_info(); - let handler = js_info.get_ref().dom_static.proxy_handlers.get(&(PrototypeList::id::%s as uint)); + let handler = js_info.get_ref().dom_static.proxy_handlers.deref().get(&(PrototypeList::id::%s as uint)); """ % descriptor.name create += handler + """ let obj = NewProxyObject(aCx, *handler, &PrivateValue(squirrel_away_unique(aObject) as *libc::c_void), @@ -2204,7 +2204,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): ('Some(%s)' % TRACE_HOOK_NAME), self.descriptor.name) - return (body + """ let cx = js_info.js_context.deref().ptr; + return (body + """ let cx = (*js_info.js_context).deref().ptr; let receiver = js_info.js_compartment.global_obj; let global: *JSObject = JS_GetGlobalForObject(cx, receiver); assert!(%s(cx, global, receiver).is_not_null());""" % (getter)) @@ -4517,7 +4517,7 @@ class CGBindingRoot(CGThing): 'dom::bindings::utils::{ThrowingConstructor, unwrap, unwrap_jsmanaged}', 'dom::bindings::utils::{VoidVal, with_gc_disabled}', 'dom::bindings::utils::{with_gc_enabled}', - 'dom::bindings::trace::Traceable', + 'dom::bindings::trace::JSTraceable', 'dom::bindings::callback::{CallbackContainer,CallbackInterface}', 'dom::bindings::callback::{CallSetup,ExceptionHandling}', 'dom::bindings::callback::{WrapCallThisObject}', @@ -5472,7 +5472,7 @@ class GlobalGenRoots(): allprotos = [CGGeneric("#[allow(unused_imports)];\n"), CGGeneric("use dom::types::*;\n"), CGGeneric("use dom::bindings::js::JS;\n"), - CGGeneric("use dom::bindings::trace::Traceable;\n"), + CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use serialize::{Encodable, Encoder};\n"), CGGeneric("use js::jsapi::JSTracer;\n\n")] for descriptor in descriptors: @@ -5523,7 +5523,7 @@ class GlobalGenRoots(): 'toBound': name + 'Derived'})), CGGeneric("impl %s for %s {}\n\n" % (name + 'Cast', name))] - trace = [CGGeneric(string.Template('''impl Traceable for ${name} { + trace = [CGGeneric(string.Template('''impl JSTraceable for ${name} { fn trace(&self, tracer: *mut JSTracer) { unsafe { self.encode(&mut *tracer); diff --git a/src/components/script/dom/bindings/js.rs b/src/components/script/dom/bindings/js.rs index 71ca2d7ac86..5d2640a2bdf 100644 --- a/src/components/script/dom/bindings/js.rs +++ b/src/components/script/dom/bindings/js.rs @@ -44,8 +44,9 @@ impl<T: Reflectable> JS<T> { pub unsafe fn from_trusted_node_address(inner: TrustedNodeAddress) -> JS<T> { + let TrustedNodeAddress(addr) = inner; JS { - ptr: RefCell::new(inner as *mut T) + ptr: RefCell::new(addr as *mut T) } } } diff --git a/src/components/script/dom/bindings/trace.rs b/src/components/script/dom/bindings/trace.rs index 1cedf246728..4e32bacec68 100644 --- a/src/components/script/dom/bindings/trace.rs +++ b/src/components/script/dom/bindings/trace.rs @@ -8,6 +8,7 @@ use dom::bindings::utils::{Reflectable, Reflector}; use js::jsapi::{JSTracer, JS_CallTracer, JSTRACE_OBJECT}; use std::cast; +use std::cell::RefCell; use std::libc; use std::ptr; use std::ptr::null; @@ -30,7 +31,7 @@ impl<S: Encoder> Encodable<S> for Reflector { } } -pub trait Traceable { +pub trait JSTraceable { fn trace(&self, trc: *mut JSTracer); } @@ -46,3 +47,69 @@ pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Ref }); } } + +/// Encapsulates a type that cannot easily have Encodable derived automagically, +/// but also does not need to be made known to the SpiderMonkey garbage collector. +/// Use only with types that are not associated with a JS reflector and do not contain +/// fields of types associated with JS reflectors. +pub struct Untraceable<T> { + priv inner: T, +} + +impl<T> Untraceable<T> { + pub fn new(val: T) -> Untraceable<T> { + Untraceable { + inner: val + } + } +} + +impl<S: Encoder, T> Encodable<S> for Untraceable<T> { + fn encode(&self, _s: &mut S) { + } +} + +impl<T> Deref<T> for Untraceable<T> { + fn deref<'a>(&'a self) -> &'a T { + &self.inner + } +} + +impl<T> DerefMut<T> for Untraceable<T> { + fn deref_mut<'a>(&'a mut self) -> &'a mut T { + &mut self.inner + } +} + +/// Encapsulates a type that can be traced but is boxed in a type we don't control +/// (such as RefCell). Wrap a field in Traceable and implement the Encodable trait +/// for that new concrete type to achieve magic compiler-derived trace hooks. +pub struct Traceable<T> { + priv inner: T +} + +impl<T> Traceable<T> { + pub fn new(val: T) -> Traceable<T> { + Traceable { + inner: val + } + } +} + +impl<T> Deref<T> for Traceable<T> { + fn deref<'a>(&'a self) -> &'a T { + &self.inner + } +} + +impl<T> DerefMut<T> for Traceable<T> { + fn deref_mut<'a>(&'a mut self) -> &'a mut T { + &mut self.inner + } +} + +impl<S: Encoder, T: Encodable<S>> Encodable<S> for Traceable<RefCell<T>> { + fn encode(&self, s: &mut S) { + self.borrow().encode(s) + } +}
\ No newline at end of file diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs index ec1472bac28..71c82ae86dc 100644 --- a/src/components/script/dom/bindings/utils.rs +++ b/src/components/script/dom/bindings/utils.rs @@ -6,6 +6,7 @@ use dom::bindings::codegen::PrototypeList; use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH; use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::js::JS; +use dom::bindings::trace::Untraceable; use dom::window; use servo_util::str::DOMString; @@ -42,13 +43,14 @@ use js::JSPROP_PERMANENT; use js::{JSFUN_CONSTRUCTOR, JSPROP_READONLY}; use js; +#[deriving(Encodable)] pub struct GlobalStaticData { - proxy_handlers: HashMap<uint, *libc::c_void> + proxy_handlers: Untraceable<HashMap<uint, *libc::c_void>> } pub fn GlobalStaticData() -> GlobalStaticData { GlobalStaticData { - proxy_handlers: HashMap::new() + proxy_handlers: Untraceable::new(HashMap::new()) } } @@ -533,7 +535,7 @@ fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext { let win = global_object_for_js_object(obj); let js_info = win.get().page().js_info(); match *js_info { - Some(ref info) => info.js_context.deref().ptr, + Some(ref info) => info.js_context.deref().deref().ptr, None => fail!("no JS context for DOM global") } } diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index f4391e4e541..637785a6bbc 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -8,6 +8,7 @@ use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, Elemen use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast}; use dom::bindings::codegen::DocumentBinding; use dom::bindings::js::JS; +use dom::bindings::trace::Untraceable; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest, NamespaceError}; use dom::bindings::utils::{xml_name_type, InvalidXMLName, Name, QName}; @@ -46,8 +47,6 @@ use js::jsapi::JSContext; use std::ascii::StrAsciiExt; use url::{Url, from_str}; -use serialize::{Encoder, Encodable}; - #[deriving(Eq,Encodable)] pub enum IsHTMLDocument { HTMLDocument, @@ -64,17 +63,8 @@ pub struct Document { content_type: DOMString, encoding_name: DOMString, is_html_document: bool, - priv extra: Untraceable, -} - -struct Untraceable { - url: Url, - quirks_mode: QuirksMode, -} - -impl<S: Encoder> Encodable<S> for Untraceable { - fn encode(&self, _: &mut S) { - } + url: Untraceable<Url>, + quirks_mode: Untraceable<QuirksMode>, } impl DocumentDerived for EventTarget { @@ -106,6 +96,8 @@ impl Document { url: Option<Url>, is_html_document: IsHTMLDocument, content_type: Option<DOMString>) -> Document { + let url = url.unwrap_or_else(|| from_str("about:blank").unwrap()); + Document { node: Node::new_without_doc(DocumentNodeTypeId), reflector_: Reflector::new(), @@ -121,14 +113,9 @@ impl Document { NonHTMLDocument => ~"application/xml" } }, - extra: Untraceable { - url: match url { - None => from_str("about:blank").unwrap(), - Some(_url) => _url - }, - // http://dom.spec.whatwg.org/#concept-document-quirks - quirks_mode: NoQuirks, - }, + url: Untraceable::new(url), + // http://dom.spec.whatwg.org/#concept-document-quirks + quirks_mode: Untraceable::new(NoQuirks), // http://dom.spec.whatwg.org/#concept-document-encoding encoding_name: ~"utf-8", is_html_document: is_html_document == HTMLDocument, @@ -143,7 +130,7 @@ impl Document { impl Document { pub fn url<'a>(&'a self) -> &'a Url { - &self.extra.url + &*self.url } } @@ -185,18 +172,18 @@ impl Document { // http://dom.spec.whatwg.org/#dom-document-compatmode pub fn CompatMode(&self) -> DOMString { - match self.extra.quirks_mode { + match *self.quirks_mode { NoQuirks => ~"CSS1Compat", LimitedQuirks | FullQuirks => ~"BackCompat" } } pub fn quirks_mode(&self) -> QuirksMode { - self.extra.quirks_mode + *self.quirks_mode } pub fn set_quirks_mode(&mut self, mode: QuirksMode) { - self.extra.quirks_mode = mode; + *self.quirks_mode = mode; } // http://dom.spec.whatwg.org/#dom-document-characterset diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs index c98634682a6..d0f127fbc94 100644 --- a/src/components/script/dom/htmliframeelement.rs +++ b/src/components/script/dom/htmliframeelement.rs @@ -4,8 +4,9 @@ use dom::bindings::codegen::HTMLIFrameElementBinding; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived, HTMLElementCast}; -use dom::bindings::js::JS; use dom::bindings::error::ErrorResult; +use dom::bindings::js::JS; +use dom::bindings::trace::Untraceable; use dom::document::Document; use dom::element::{HTMLIFrameElementTypeId, Element}; use dom::element::AttributeHandlers; @@ -16,7 +17,6 @@ use dom::virtualmethods::VirtualMethods; use dom::windowproxy::WindowProxy; use servo_util::str::DOMString; -use serialize::{Encoder, Encodable}; use servo_msg::constellation_msg::{PipelineId, SubpageId}; use std::ascii::StrAsciiExt; use url::Url; @@ -34,20 +34,11 @@ enum SandboxAllowance { #[deriving(Encodable)] pub struct HTMLIFrameElement { htmlelement: HTMLElement, - priv extra: Untraceable, + frame: Untraceable<Option<Url>>, size: Option<IFrameSize>, sandbox: Option<u8> } -struct Untraceable { - frame: Option<Url>, -} - -impl<S: Encoder> Encodable<S> for Untraceable { - fn encode(&self, _s: &mut S) { - } -} - impl HTMLIFrameElementDerived for EventTarget { fn is_htmliframeelement(&self) -> bool { match self.type_id { @@ -69,7 +60,7 @@ impl HTMLIFrameElement { } pub fn set_frame(&mut self, frame: Url) { - self.extra.frame = Some(frame); + *self.frame = Some(frame); } } @@ -77,9 +68,7 @@ impl HTMLIFrameElement { pub fn new_inherited(localName: DOMString, document: JS<Document>) -> HTMLIFrameElement { HTMLIFrameElement { htmlelement: HTMLElement::new_inherited(HTMLIFrameElementTypeId, localName, document), - extra: Untraceable { - frame: None - }, + frame: Untraceable::new(None), size: None, sandbox: None, } diff --git a/src/components/script/dom/htmlimageelement.rs b/src/components/script/dom/htmlimageelement.rs index 3b966bbfe24..a62aea8b991 100644 --- a/src/components/script/dom/htmlimageelement.rs +++ b/src/components/script/dom/htmlimageelement.rs @@ -5,8 +5,9 @@ use dom::bindings::codegen::HTMLImageElementBinding; use dom::bindings::codegen::InheritTypes::{NodeCast, HTMLImageElementDerived}; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; -use dom::bindings::js::JS; use dom::bindings::error::ErrorResult; +use dom::bindings::js::JS; +use dom::bindings::trace::Untraceable; use dom::document::Document; use dom::element::{Element, HTMLImageElementTypeId}; use dom::element::AttributeHandlers; @@ -21,21 +22,10 @@ use servo_util::url::parse_url; use servo_util::str::DOMString; use url::Url; -use serialize::{Encoder, Encodable}; - #[deriving(Encodable)] pub struct HTMLImageElement { htmlelement: HTMLElement, - priv extra: Untraceable, -} - -struct Untraceable { - image: Option<Url>, -} - -impl<S: Encoder> Encodable<S> for Untraceable { - fn encode(&self, _s: &mut S) { - } + image: Untraceable<Option<Url>>, } impl HTMLImageElementDerived for EventTarget { @@ -51,9 +41,7 @@ impl HTMLImageElement { pub fn new_inherited(localName: DOMString, document: JS<Document>) -> HTMLImageElement { HTMLImageElement { htmlelement: HTMLElement::new_inherited(HTMLImageElementTypeId, localName, document), - extra: Untraceable { - image: None, - } + image: Untraceable::new(None), } } @@ -65,7 +53,7 @@ impl HTMLImageElement { impl HTMLImageElement { pub fn image<'a>(&'a self) -> &'a Option<Url> { - &self.extra.image + &*self.image } /// Makes the local `image` member match the status of the `src` attribute and starts @@ -77,11 +65,11 @@ impl HTMLImageElement { let image_cache = &window.image_cache_task; match value { None => { - self.extra.image = None; + *self.image = None; } Some(src) => { let img_url = parse_url(src, url); - self.extra.image = Some(img_url.clone()); + *self.image = Some(img_url.clone()); // inform the image cache to load this, but don't store a // handle. diff --git a/src/components/script/dom/htmlstyleelement.rs b/src/components/script/dom/htmlstyleelement.rs index ed335dd70eb..32e4276a2a1 100644 --- a/src/components/script/dom/htmlstyleelement.rs +++ b/src/components/script/dom/htmlstyleelement.rs @@ -88,7 +88,7 @@ impl StyleElementHelpers for JS<HTMLStyleElement> { let data = node.get().GetTextContent(&node).expect("Element.textContent must be a string"); let sheet = parse_inline_css(url, data); - let LayoutChan(ref layout_chan) = win.get().page().layout_chan; + let LayoutChan(ref layout_chan) = *win.get().page().layout_chan; layout_chan.send(AddStylesheetMsg(sheet)); } } diff --git a/src/components/script/dom/location.rs b/src/components/script/dom/location.rs index 168ded0a4c7..f813b375eca 100644 --- a/src/components/script/dom/location.rs +++ b/src/components/script/dom/location.rs @@ -18,26 +18,14 @@ use serialize::{Encoder, Encodable}; #[deriving(Encodable)] pub struct Location { reflector_: Reflector, //XXXjdm cycle: window->Location->window - priv extra: Untraceable, -} - -struct Untraceable { page: Rc<Page>, } -impl<S: Encoder> Encodable<S> for Untraceable { - fn encode(&self, s: &mut S) { - self.page.encode(s); - } -} - impl Location { pub fn new_inherited(page: Rc<Page>) -> Location { Location { reflector_: Reflector::new(), - extra: Untraceable { - page: page - } + page: page } } @@ -60,7 +48,7 @@ impl Location { } pub fn Href(&self) -> DOMString { - self.extra.page.get_url().to_str() + self.page.get_url().to_str() } pub fn SetHref(&self, _href: DOMString) -> Fallible<()> { diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index bf2669512ff..fd55732da82 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -37,6 +37,7 @@ use std::cast::transmute; use std::cast; use std::cell::{RefCell, Ref, RefMut}; use std::iter::{Map, Filter}; +use std::libc; use std::libc::uintptr_t; use std::mem; @@ -562,7 +563,7 @@ impl NodeHelpers for JS<Node> { } fn to_trusted_node_address(&self) -> TrustedNodeAddress { - self.get() as *Node as TrustedNodeAddress + TrustedNodeAddress(self.get() as *Node as *libc::c_void) } } diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index a0b7ef3740b..87d94eaff62 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -4,6 +4,7 @@ use dom::bindings::codegen::WindowBinding; use dom::bindings::js::JS; +use dom::bindings::trace::Untraceable; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; use dom::element::Element; @@ -84,29 +85,19 @@ pub struct Window { image_cache_task: ImageCacheTask, active_timers: ~HashMap<i32, TimerHandle>, next_timer_handle: i32, - priv extra: Untraceable -} - -struct Untraceable { + compositor: Untraceable<~ScriptListener>, + timer_chan: Untraceable<Sender<TimerControlMsg>>, page: Rc<Page>, - compositor: ~ScriptListener, - timer_chan: Sender<TimerControlMsg>, -} - -impl<S: Encoder> Encodable<S> for Untraceable { - fn encode(&self, s: &mut S) { - self.page.encode(s); - } } impl Window { pub fn get_cx(&self) -> *JSObject { let js_info = self.page().js_info(); - js_info.get_ref().js_compartment.cx.deref().ptr + js_info.get_ref().js_compartment.deref().cx.deref().ptr } pub fn page<'a>(&'a self) -> &'a Page { - &*self.extra.page + &*self.page } pub fn get_url(&self) -> Url { self.page().get_url() @@ -116,7 +107,7 @@ impl Window { #[unsafe_destructor] impl Drop for Window { fn drop(&mut self) { - self.extra.timer_chan.send(TimerMessageClose); + self.timer_chan.send(TimerMessageClose); for timer_handle in self.active_timers.values() { timer_handle.cancel(); } @@ -140,7 +131,7 @@ impl Window { } pub fn Close(&self) { - self.extra.timer_chan.send(TimerMessageTriggerExit); + self.timer_chan.deref().send(TimerMessageTriggerExit); } pub fn Document(&self) -> JS<Document> { @@ -181,7 +172,7 @@ impl Window { pub fn Location(&mut self, abstract_self: &JS<Window>) -> JS<Location> { if self.location.is_none() { - self.location = Some(Location::new(abstract_self, self.extra.page.clone())); + self.location = Some(Location::new(abstract_self, self.page.clone())); } self.location.get_ref().clone() } @@ -236,7 +227,7 @@ impl Window { // to the relevant script handler that will deal with it. let tm = Timer::new().unwrap(); let (cancel_chan, cancel_port) = channel(); - let chan = self.extra.timer_chan.clone(); + let chan = self.timer_chan.clone(); let spawn_name = if is_interval { "Window:SetInterval" } else { @@ -304,7 +295,7 @@ impl Window { // currently rely on the display list, which means we can't destroy it by // doing a query reflow. self.page().damage(damage); - self.page().reflow(ReflowForDisplay, self.script_chan.clone(), self.extra.compositor); + self.page().reflow(ReflowForDisplay, self.script_chan.clone(), *self.compositor); } pub fn wait_until_safe_to_modify_dom(&self) { @@ -319,29 +310,27 @@ impl Window { compositor: ~ScriptListener, image_cache_task: ImageCacheTask) -> JS<Window> { + let script_chan_clone = script_chan.clone(); + let (timer_chan, timer_port): (Sender<TimerControlMsg>, Receiver<TimerControlMsg>) = channel(); + let id = page.id.clone(); + spawn_named("timer controller", proc() { + let ScriptChan(script_chan) = script_chan; + loop { + match timer_port.recv() { + TimerMessageClose => break, + TimerMessageFire(td) => script_chan.send(FireTimerMsg(id, td)), + TimerMessageTriggerExit => script_chan.send(ExitWindowMsg(id)), + } + } + }); + let win = ~Window { eventtarget: EventTarget::new_inherited(WindowTypeId), - script_chan: script_chan.clone(), + script_chan: script_chan_clone, console: None, - extra: Untraceable { - compositor: compositor, - page: page.clone(), - timer_chan: { - let (timer_chan, timer_port): (Sender<TimerControlMsg>, Receiver<TimerControlMsg>) = channel(); - let id = page.id.clone(); - spawn_named("timer controller", proc() { - let ScriptChan(script_chan) = script_chan; - loop { - match timer_port.recv() { - TimerMessageClose => break, - TimerMessageFire(td) => script_chan.send(FireTimerMsg(id, td)), - TimerMessageTriggerExit => script_chan.send(ExitWindowMsg(id)), - } - } - }); - timer_chan - } - }, + compositor: Untraceable::new(compositor), + timer_chan: Untraceable::new(timer_chan), + page: page.clone(), location: None, navigator: None, image_cache_task: image_cache_task, diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index c7c4e79b165..b9dd26311ff 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -252,7 +252,7 @@ pub fn parse_html(page: &Page, resource_task: ResourceTask) -> HtmlParserResult { debug!("Hubbub: parsing {:?}", url); - let next_subpage_id: SubpageId = *page.next_subpage_id.borrow(); + let next_subpage_id: SubpageId = *page.next_subpage_id.deref().borrow(); // Spawn a CSS parser to receive links to CSS style sheets. let resource_task2 = resource_task.clone(); diff --git a/src/components/script/layout_interface.rs b/src/components/script/layout_interface.rs index 197bd123e3f..a29aa2fa08e 100644 --- a/src/components/script/layout_interface.rs +++ b/src/components/script/layout_interface.rs @@ -6,7 +6,8 @@ /// coupling between these two components, and enables the DOM to be placed in a separate crate /// from layout. -use dom::node::LayoutDataRef; +use dom::bindings::js::JS; +use dom::node::{Node, LayoutDataRef}; use geom::point::Point2D; use geom::rect::Rect; @@ -19,6 +20,8 @@ use std::libc::c_void; use style::Stylesheet; use url::Url; +use serialize::{Encodable, Encoder}; + /// Asynchronous messages that script can send to layout. /// /// FIXME(pcwalton): I think this should probably be merged with `LayoutQuery` below. @@ -62,7 +65,17 @@ pub enum LayoutQuery { /// The address of a node known to be valid. These must only be sent from content -> layout, /// because we do not trust layout. -pub type TrustedNodeAddress = *c_void; +pub struct TrustedNodeAddress(*c_void); + +impl<S: Encoder> Encodable<S> for TrustedNodeAddress { + fn encode(&self, s: &mut S) { + let TrustedNodeAddress(addr) = *self; + let node = addr as *Node as *mut Node; + unsafe { + JS::from_raw(node).encode(s) + } + } +} /// The address of a node. Layout sends these back. They must be validated via /// `from_untrusted_node_address` before they can be used, because we do not trust layout. @@ -74,7 +87,7 @@ pub struct HitTestResponse(UntrustedNodeAddress); pub struct MouseOverResponse(~[UntrustedNodeAddress]); /// Determines which part of the -#[deriving(Eq, Ord, TotalEq, TotalOrd)] +#[deriving(Eq, Ord, TotalEq, TotalOrd, Encodable)] pub enum DocumentDamageLevel { /// Reflow, but do not perform CSS selector matching. ReflowDocumentDamage, @@ -94,6 +107,7 @@ impl DocumentDamageLevel { /// What parts of the document have changed, as far as the script task can tell. /// /// Note that this is fairly coarse-grained and is separate from layout's notion of the document +#[deriving(Encodable)] pub struct DocumentDamage { /// The topmost node in the tree that has changed. root: TrustedNodeAddress, diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 096a0d40b6a..854b060513d 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -8,6 +8,7 @@ use dom::bindings::codegen::RegisterBindings; use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, ElementCast, EventCast}; use dom::bindings::js::JS; +use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils::{Reflectable, GlobalStaticData, with_gc_enabled}; use dom::document::{Document, HTMLDocument}; use dom::element::{Element, AttributeHandlers}; @@ -107,50 +108,44 @@ impl ScriptChan { } /// Encapsulates a handle to a frame and its associated layout information. +#[deriving(Encodable)] pub struct Page { /// Pipeline id associated with this page. id: PipelineId, /// Unique id for last reflow request; used for confirming completion reply. - last_reflow_id: RefCell<uint>, + last_reflow_id: Traceable<RefCell<uint>>, /// The outermost frame containing the document, window, and page URL. - frame: RefCell<Option<Frame>>, + frame: Traceable<RefCell<Option<Frame>>>, /// A handle for communicating messages to the layout task. - layout_chan: LayoutChan, + layout_chan: Untraceable<LayoutChan>, /// The port that we will use to join layout. If this is `None`, then layout is not running. - layout_join_port: RefCell<Option<Receiver<()>>>, + layout_join_port: Untraceable<RefCell<Option<Receiver<()>>>>, /// What parts of the document are dirty, if any. - damage: RefCell<Option<DocumentDamage>>, + damage: Traceable<RefCell<Option<DocumentDamage>>>, /// The current size of the window, in pixels. - window_size: RefCell<Size2D<uint>>, + window_size: Untraceable<RefCell<Size2D<uint>>>, - js_info: RefCell<Option<JSPageInfo>>, + js_info: Traceable<RefCell<Option<JSPageInfo>>>, /// Cached copy of the most recent url loaded by the script /// TODO(tkuehn): this currently does not follow any particular caching policy /// and simply caches pages forever (!). The bool indicates if reflow is required /// when reloading. - url: RefCell<Option<(Url, bool)>>, + url: Untraceable<RefCell<Option<(Url, bool)>>>, - next_subpage_id: RefCell<SubpageId>, + next_subpage_id: Untraceable<RefCell<SubpageId>>, /// Pending resize event, if any. - resize_event: RefCell<Option<Size2D<uint>>>, + resize_event: Untraceable<RefCell<Option<Size2D<uint>>>>, /// Pending scroll to fragment event, if any - fragment_node: RefCell<Option<JS<Element>>> -} - -impl<S: Encoder> Encodable<S> for Page { - fn encode(&self, s: &mut S) { - let fragment_node = self.fragment_node.borrow(); - fragment_node.encode(s); - } + fragment_node: Traceable<RefCell<Option<JS<Element>>>> } pub struct PageTree { @@ -167,17 +162,17 @@ impl PageTree { PageTree { page: Rc::new(Page { id: id, - frame: RefCell::new(None), - layout_chan: layout_chan, - layout_join_port: RefCell::new(None), - damage: RefCell::new(None), - window_size: RefCell::new(window_size), - js_info: RefCell::new(None), - url: RefCell::new(None), - next_subpage_id: RefCell::new(SubpageId(0)), - resize_event: RefCell::new(None), - fragment_node: RefCell::new(None), - last_reflow_id: RefCell::new(0) + frame: Traceable::new(RefCell::new(None)), + layout_chan: Untraceable::new(layout_chan), + layout_join_port: Untraceable::new(RefCell::new(None)), + damage: Traceable::new(RefCell::new(None)), + window_size: Untraceable::new(RefCell::new(window_size)), + js_info: Traceable::new(RefCell::new(None)), + url: Untraceable::new(RefCell::new(None)), + next_subpage_id: Untraceable::new(RefCell::new(SubpageId(0))), + resize_event: Untraceable::new(RefCell::new(None)), + fragment_node: Traceable::new(RefCell::new(None)), + last_reflow_id: Traceable::new(RefCell::new(0)) }), inner: ~[], } @@ -251,27 +246,27 @@ impl<'a> Iterator<Rc<Page>> for PageTreeIterator<'a> { impl Page { pub fn mut_js_info<'a>(&'a self) -> RefMut<'a, Option<JSPageInfo>> { - self.js_info.borrow_mut() + self.js_info.deref().borrow_mut() } pub fn js_info<'a>(&'a self) -> Ref<'a, Option<JSPageInfo>> { - self.js_info.borrow() + self.js_info.deref().borrow() } pub fn url<'a>(&'a self) -> Ref<'a, Option<(Url, bool)>> { - self.url.borrow() + self.url.deref().borrow() } pub fn mut_url<'a>(&'a self) -> RefMut<'a, Option<(Url, bool)>> { - self.url.borrow_mut() + self.url.deref().borrow_mut() } pub fn frame<'a>(&'a self) -> Ref<'a, Option<Frame>> { - self.frame.borrow() + self.frame.deref().borrow() } pub fn mut_frame<'a>(&'a self) -> RefMut<'a, Option<Frame>> { - self.frame.borrow_mut() + self.frame.deref().borrow_mut() } /// Adds the given damage. @@ -284,7 +279,7 @@ impl Page { None => {}, Some(root) => { let root: JS<Node> = NodeCast::from(&root); - let mut damage = *self.damage.borrow_mut(); + let mut damage = *self.damage.deref().borrow_mut(); match damage { None => {} Some(ref mut damage) => { @@ -295,7 +290,7 @@ impl Page { } } - *self.damage.borrow_mut() = Some(DocumentDamage { + *self.damage.deref().borrow_mut() = Some(DocumentDamage { root: root.to_trusted_node_address(), level: level, }) @@ -310,7 +305,7 @@ impl Page { /// Sends a ping to layout and waits for the response. The response will arrive when the /// layout task has finished any pending request messages. pub fn join_layout(&self) { - let mut layout_join_port = self.layout_join_port.borrow_mut(); + let mut layout_join_port = self.layout_join_port.deref().borrow_mut(); if layout_join_port.is_some() { let join_port = replace(&mut *layout_join_port, None); match join_port { @@ -339,7 +334,7 @@ impl Page { response_port: Receiver<T>) -> T { self.join_layout(); - let LayoutChan(ref chan) = self.layout_chan; + let LayoutChan(ref chan) = *self.layout_chan; chan.send(QueryMsg(query)); response_port.recv() } @@ -375,15 +370,15 @@ impl Page { // Layout will let us know when it's done. let (join_chan, join_port) = channel(); - let mut layout_join_port = self.layout_join_port.borrow_mut(); + let mut layout_join_port = self.layout_join_port.deref().borrow_mut(); *layout_join_port = Some(join_port); - let mut last_reflow_id = self.last_reflow_id.borrow_mut(); + let mut last_reflow_id = self.last_reflow_id.deref().borrow_mut(); *last_reflow_id += 1; let root: JS<Node> = NodeCast::from(&root); - let mut damage = self.damage.borrow_mut(); - let window_size = self.window_size.borrow(); + let mut damage = self.damage.deref().borrow_mut(); + let window_size = self.window_size.deref().borrow(); // Send new document and relevant styles to layout. let reflow = ~Reflow { @@ -397,7 +392,7 @@ impl Page { id: *last_reflow_id, }; - let LayoutChan(ref chan) = self.layout_chan; + let LayoutChan(ref chan) = *self.layout_chan; chan.send(ReflowMsg(reflow)); debug!("script: layout forked") @@ -443,8 +438,8 @@ impl Page { let mut js_info = self.mut_js_info(); *js_info = Some(JSPageInfo { dom_static: GlobalStaticData(), - js_compartment: compartment, - js_context: js_context, + js_compartment: Untraceable::new(compartment), + js_context: Untraceable::new(js_context), }); } } @@ -459,13 +454,14 @@ pub struct Frame { } /// Encapsulation of the javascript information associated with each frame. +#[deriving(Encodable)] pub struct JSPageInfo { /// Global static data related to the DOM. dom_static: GlobalStaticData, /// The JavaScript compartment for the origin associated with the script task. - js_compartment: Rc<Compartment>, + js_compartment: Untraceable<Rc<Compartment>>, /// The JavaScript context. - js_context: Rc<Cx>, + js_context: Untraceable<Rc<Cx>>, } /// Information for an entire page. Pages are top-level browsing contexts and can contain multiple @@ -573,9 +569,9 @@ impl ScriptTask { let mut page_tree = self.page_tree.borrow_mut(); for page in page_tree.iter() { // Only process a resize if layout is idle. - let layout_join_port = page.layout_join_port.borrow(); + let layout_join_port = page.layout_join_port.deref().borrow(); if layout_join_port.is_none() { - let mut resize_event = page.resize_event.borrow_mut(); + let mut resize_event = page.resize_event.deref().borrow_mut(); match resize_event.take() { Some(size) => resizes.push((page.id, size)), None => () @@ -599,7 +595,7 @@ impl ScriptTask { ResizeMsg(id, size) => { let mut page_tree = self.page_tree.borrow_mut(); let page = page_tree.find(id).expect("resize sent to nonexistent pipeline").page(); - let mut resize_event = page.resize_event.borrow_mut(); + let mut resize_event = page.resize_event.deref().borrow_mut(); *resize_event = Some(size); } _ => { @@ -646,7 +642,7 @@ impl ScriptTask { whose parent has a PipelineId which does not correspond to a pipeline in the script task's page tree. This is a bug."); let new_page_tree = { - let window_size = parent_page_tree.page().window_size.borrow(); + let window_size = parent_page_tree.page().window_size.deref().borrow(); PageTree::new(new_id, layout_chan, *window_size) }; parent_page_tree.inner.push(new_page_tree); @@ -680,7 +676,7 @@ impl ScriptTask { // TODO: Support extra arguments. This requires passing a `*JSVal` array as `argv`. let rval = NullValue(); - let cx = js_info.get_ref().js_context.deref().ptr; + let cx = js_info.get_ref().js_context.deref().deref().ptr; with_gc_enabled(cx, || { unsafe { JS_CallFunctionValue(cx, this_value, timer_data.funval, 0, ptr::null(), &rval); @@ -695,9 +691,9 @@ impl ScriptTask { let page = page_tree.find(pipeline_id).expect( "ScriptTask: received a load message for a layout channel that is not associated \ with this script task. This is a bug.").page(); - let last_reflow_id = page.last_reflow_id.borrow(); + let last_reflow_id = page.last_reflow_id.deref().borrow(); if *last_reflow_id == reflow_id { - let mut layout_join_port = page.layout_join_port.borrow_mut(); + let mut layout_join_port = page.layout_join_port.deref().borrow_mut(); *layout_join_port = None; } self.compositor.set_ready_state(FinishedLoading); @@ -715,7 +711,7 @@ impl ScriptTask { let mut page_tree = self.page_tree.borrow_mut(); let page = page_tree.find(id).expect("Received resize message for PipelineId not associated with a page in the page tree. This is a bug.").page(); - let mut window_size = page.window_size.borrow_mut(); + let mut window_size = page.window_size.deref().borrow_mut(); *window_size = new_size; let mut page_url = page.mut_url(); let last_loaded_url = replace(&mut *page_url, None); @@ -845,12 +841,12 @@ impl ScriptTask { js_scripts = Some(scripts); } Some(HtmlDiscoveredStyle(sheet)) => { - let LayoutChan(ref chan) = page.layout_chan; + let LayoutChan(ref chan) = *page.layout_chan; chan.send(AddStylesheetMsg(sheet)); } Some(HtmlDiscoveredIFrame((iframe_url, subpage_id, sandboxed))) => { let SubpageId(num) = subpage_id; - page.next_subpage_id.set(SubpageId(num + 1)); + page.next_subpage_id.deref().set(SubpageId(num + 1)); let sandboxed = if sandboxed { IFrameSandboxed } else { @@ -886,9 +882,9 @@ impl ScriptTask { let cx = { let js_info = page.js_info(); let js_info = js_info.get_ref(); - assert!(js_info.js_compartment.define_functions(DEBUG_FNS).is_ok()); + assert!(js_info.js_compartment.deref().define_functions(DEBUG_FNS).is_ok()); - js_info.js_context.deref().ptr + js_info.js_context.deref().deref().ptr }; // Evaluate every script in the document. @@ -896,7 +892,7 @@ impl ScriptTask { with_gc_enabled(cx, || { let (cx, global_obj) = { let js_info = page.js_info(); - (js_info.get_ref().js_context.clone(), + (js_info.get_ref().js_context.deref().clone(), js_info.get_ref().js_compartment.global_obj) }; //FIXME: this should have some kind of error handling, or explicitly @@ -918,7 +914,7 @@ impl ScriptTask { let winclone = wintarget.clone(); let _ = wintarget.get_mut().dispatch_event_with_target(&winclone, Some(doctarget), &mut event); - let mut fragment_node = page.fragment_node.borrow_mut(); + let mut fragment_node = page.fragment_node.deref().borrow_mut(); *fragment_node = fragment.map_or(None, |fragid| page.find_fragment_node(fragid)); let ConstellationChan(ref chan) = self.constellation_chan; @@ -953,7 +949,7 @@ impl ScriptTask { debug!("script got resize event: {:u}, {:u}", new_width, new_height); { - let mut window_size = page.window_size.borrow_mut(); + let mut window_size = page.window_size.deref().borrow_mut(); *window_size = Size2D(new_width, new_height); } @@ -965,7 +961,7 @@ impl ScriptTask { } } - let mut fragment_node = page.fragment_node.borrow_mut(); + let mut fragment_node = page.fragment_node.deref().borrow_mut(); match fragment_node.take() { Some(node) => self.scroll_fragment_point(pipeline_id, page, node), None => {} @@ -1145,7 +1141,7 @@ fn shut_down_layout(page: &Page) { // Tell the layout task to begin shutting down. let (response_chan, response_port) = channel(); - let LayoutChan(ref chan) = page.layout_chan; + let LayoutChan(ref chan) = *page.layout_chan; chan.send(layout_interface::PrepareToExitMsg(response_chan)); response_port.recv(); @@ -1154,7 +1150,7 @@ fn shut_down_layout(page: &Page) { let mut js_info = page.mut_js_info(); unsafe { - JS_AllowGC(js_info.get_ref().js_context.deref().ptr); + JS_AllowGC(js_info.get_ref().js_context.deref().deref().ptr); } let mut frame = page.mut_frame(); |