diff --git a/src/servo/content/content_task.rs b/src/servo/content/content_task.rs index b7518cadafa..ee1466a8233 100644 --- a/src/servo/content/content_task.rs +++ b/src/servo/content/content_task.rs @@ -151,14 +151,30 @@ pub fn Content(layout_task: LayoutTask, }; cx.set_cx_private(ptr::to_unsafe_ptr(&*content) as *()); + unsafe { task::local_data::local_data_set(global_content_key, cast::transmute(content)); } content } +fn global_content_key(_: @Content) {} + +pub fn global_content() -> @Content { + unsafe { + return task::local_data::local_data_get(global_content_key).get(); + } +} + pub fn task_from_context(cx: *JSContext) -> *mut Content { JS_GetContextPrivate(cx) as *mut Content } +#[unsafe_destructor] +impl Drop for Content { + fn finalize(&self) { + unsafe { task::local_data::local_data_pop(global_content_key) }; + } +} + #[allow(non_implicitly_copyable_typarams)] pub impl Content { fn start(&mut self) { @@ -185,6 +201,8 @@ pub impl Content { ParseMsg(url) => { debug!("content: Received url `%s` to parse", url_to_str(&url)); + define_bindings(self.compartment.get()); + // Note: we can parse the next document in parallel // with any previous documents. @@ -209,8 +227,13 @@ pub impl Content { let js_scripts = result.js_port.recv(); debug!("js_scripts: %?", js_scripts); - let document = @mut Document(root); - let window = @mut Window(self.control_chan.clone()); + let window = Window(self.control_chan.clone(), + self.event_chan.clone()); + let document = Document(root, Some(window)); + + do root.with_mut_node |node| { + node.add_to_doc(document); + } self.damage.add(MatchSelectorsDamage); self.relayout(document, &url); @@ -221,7 +244,6 @@ pub impl Content { let compartment = self.compartment.expect(~"TODO error checking"); compartment.define_functions(debug_fns); - define_bindings(compartment, document, window); do vec::consume(js_scripts) |_i, bytes| { self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u); diff --git a/src/servo/dom/bindings/clientrect.rs b/src/servo/dom/bindings/clientrect.rs index 5746733a53e..af65ca60c27 100644 --- a/src/servo/dom/bindings/clientrect.rs +++ b/src/servo/dom/bindings/clientrect.rs @@ -2,63 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use content::content_task::task_from_context; +use content::content_task::{task_from_context, global_content}; use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper}; use dom::bindings::codegen::ClientRectBinding; +use dom::clientrect::ClientRect; use js::jsapi::{JSObject, JSContext, JSVal}; use js::glue::bindgen::RUST_OBJECT_TO_JSVAL; -pub trait ClientRect { - fn Top(&self) -> f32; - fn Bottom(&self) -> f32; - fn Left(&self) -> f32; - fn Right(&self) -> f32; - fn Width(&self) -> f32; - fn Height(&self) -> f32; -} - -pub struct ClientRectImpl { - wrapper: WrapperCache, - top: f32, - bottom: f32, - left: f32, - right: f32, -} - -impl ClientRect for ClientRectImpl { - fn Top(&self) -> f32 { - self.top - } - - fn Bottom(&self) -> f32 { - self.bottom - } - - fn Left(&self) -> f32 { - self.left - } - - fn Right(&self) -> f32 { - self.right - } - - fn Width(&self) -> f32 { - f32::abs(self.right - self.left) - } - - fn Height(&self) -> f32 { - f32::abs(self.bottom - self.top) +pub impl ClientRect { + pub fn init_wrapper(@mut self) { + let content = global_content(); + let cx = content.compartment.get().cx.ptr; + let owner = content.window.get(); + let cache = owner.get_wrappercache(); + let scope = cache.get_wrapper(); + self.wrap_object_shared(cx, scope); } } -pub fn ClientRect(top: f32, bottom: f32, left: f32, right: f32) -> ClientRectImpl { - ClientRectImpl { - top: top, bottom: bottom, left: left, right: right, - wrapper: WrapperCache::new() - } -} - -impl CacheableWrapper for ClientRectImpl { +impl CacheableWrapper for ClientRect { fn get_wrappercache(&mut self) -> &mut WrapperCache { unsafe { cast::transmute(&self.wrapper) } } @@ -73,14 +35,14 @@ impl CacheableWrapper for ClientRectImpl { } } -impl BindingObject for ClientRectImpl { +impl BindingObject for ClientRect { fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper { let content = task_from_context(cx); unsafe { (*content).window.get() as @mut CacheableWrapper } } } -impl DerivedWrapper for ClientRectImpl { +impl DerivedWrapper for ClientRect { fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 { fail!(~"nyi") } diff --git a/src/servo/dom/bindings/clientrectlist.rs b/src/servo/dom/bindings/clientrectlist.rs index 86d6c0fc788..a04eadf4165 100644 --- a/src/servo/dom/bindings/clientrectlist.rs +++ b/src/servo/dom/bindings/clientrectlist.rs @@ -2,53 +2,24 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use content::content_task::task_from_context; -use dom::bindings::clientrect::{ClientRect, ClientRectImpl}; +use content::content_task::{task_from_context, global_content}; use dom::bindings::codegen::ClientRectListBinding; use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject}; +use dom::clientrectlist::ClientRectList; use js::jsapi::{JSObject, JSContext}; -pub trait ClientRectList { - fn Length(&self) -> u32; - fn Item(&self, index: u32) -> Option<@mut ClientRectImpl>; - fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl>; -} - -pub struct ClientRectListImpl { - wrapper: WrapperCache, - rects: ~[(f32, f32, f32, f32)] -} - -impl ClientRectList for ClientRectListImpl { - fn Length(&self) -> u32 { - self.rects.len() as u32 - } - - fn Item(&self, index: u32) -> Option<@mut ClientRectImpl> { - if index < self.rects.len() as u32 { - let (top, bottom, left, right) = self.rects[index]; - Some(@mut ClientRect(top, bottom, left, right)) - } else { - None - } - } - - fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl> { - *found = index < self.rects.len() as u32; - self.Item(index) +pub impl ClientRectList { + fn init_wrapper(@mut self) { + let content = global_content(); + let cx = content.compartment.get().cx.ptr; + let owner = content.window.get(); + let cache = owner.get_wrappercache(); + let scope = cache.get_wrapper(); + self.wrap_object_shared(cx, scope); } } -pub impl ClientRectListImpl { - fn new() -> ClientRectListImpl { - ClientRectListImpl { - wrapper: WrapperCache::new(), - rects: ~[(5.6, 80.2, 3.7, 4.8), (800.1, 8001.1, -50.000001, -45.01)] - } - } -} - -impl CacheableWrapper for ClientRectListImpl { +impl CacheableWrapper for ClientRectList { fn get_wrappercache(&mut self) -> &mut WrapperCache { unsafe { cast::transmute(&self.wrapper) } } @@ -63,7 +34,7 @@ impl CacheableWrapper for ClientRectListImpl { } } -impl BindingObject for ClientRectListImpl { +impl BindingObject for ClientRectList { fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper { let content = task_from_context(cx); unsafe { (*content).window.get() as @mut CacheableWrapper } diff --git a/src/servo/dom/bindings/codegen/Bindings.conf b/src/servo/dom/bindings/codegen/Bindings.conf index bc5a19cf172..8c2b3cb29a5 100644 --- a/src/servo/dom/bindings/codegen/Bindings.conf +++ b/src/servo/dom/bindings/codegen/Bindings.conf @@ -115,13 +115,13 @@ DOMInterfaces = { 'ClientRect': [ { - 'nativeType': 'ClientRectImpl', + 'nativeType': 'ClientRect', 'pointerType': '@mut ' }], 'ClientRectList': [ { - 'nativeType': 'ClientRectListImpl', + 'nativeType': 'ClientRectList', 'pointerType': '@mut ' }], diff --git a/src/servo/dom/bindings/codegen/CodegenRust.py b/src/servo/dom/bindings/codegen/CodegenRust.py index 7dec994c0af..b828b80a0bc 100644 --- a/src/servo/dom/bindings/codegen/CodegenRust.py +++ b/src/servo/dom/bindings/codegen/CodegenRust.py @@ -3906,9 +3906,9 @@ class CGBindingRoot(CGThing): 'dom::document::Document', #XXXjdm 'dom::bindings::utils::*', 'dom::bindings::conversions::*', - 'dom::bindings::clientrect::*', #XXXjdm - 'dom::bindings::clientrectlist::*', #XXXjdm - 'dom::bindings::htmlcollection::*', #XXXjdm + 'dom::clientrect::*', #XXXjdm + 'dom::clientrectlist::*', #XXXjdm + 'dom::htmlcollection::*', #XXXjdm 'dom::bindings::proxyhandler::*', 'dom::domparser::*', #XXXjdm 'content::content_task::task_from_context', diff --git a/src/servo/dom/bindings/document.rs b/src/servo/dom/bindings/document.rs index 5c55b960f80..992b574ed95 100644 --- a/src/servo/dom/bindings/document.rs +++ b/src/servo/dom/bindings/document.rs @@ -17,11 +17,10 @@ use core::libc::c_uint; use content::content_task::task_from_context; use dom::bindings::utils::{DOMString, rust_box, squirrel_away, str}; use dom::bindings::utils::{jsval_to_str, WrapNewBindingObject, CacheableWrapper}; -use dom::bindings::utils::WrapperCache; +use dom::bindings::utils::{WrapperCache, DerivedWrapper}; use dom::document::Document; -use dom::bindings::htmlcollection::HTMLCollection; -use dom::bindings::node; +use dom::htmlcollection::HTMLCollection; use dom::bindings::utils; extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { @@ -32,7 +31,9 @@ extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> J } let doc = &mut (*unwrap(obj)).payload; - *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, &mut doc.root).ptr); + let root = &mut doc.root; + assert!(root.is_element()); + root.wrap(cx, ptr::null(), vp); //XXXjdm proper scope at some point return 1; } } @@ -80,7 +81,7 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { } } -pub fn init(compartment: @mut Compartment, doc: @mut Document) { +pub fn init(compartment: @mut Compartment) { let obj = utils::define_empty_prototype(~"Document", None, compartment); let attrs = @~[ @@ -115,14 +116,9 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) { JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns); }); - compartment.register_class(utils::instance_jsclass(~"DocumentInstance", finalize)); - - let ptr = create(compartment, doc); - - compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(ptr), - GetJSClassHookStubPointer(PROPERTY_STUB) as *u8, - GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8, - JSPROP_ENUMERATE); + compartment.register_class(utils::instance_jsclass(~"DocumentInstance", + finalize, + ptr::null())); } pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject { @@ -135,6 +131,12 @@ pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject { let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc)); JS_SetReservedSlot(instance.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr)); } + + compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(instance.ptr), + GetJSClassHookStubPointer(PROPERTY_STUB) as *u8, + GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8, + JSPROP_ENUMERATE); + instance.ptr } diff --git a/src/servo/dom/bindings/element.rs b/src/servo/dom/bindings/element.rs index cfb02df48b4..52af49b497f 100644 --- a/src/servo/dom/bindings/element.rs +++ b/src/servo/dom/bindings/element.rs @@ -3,8 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use content::content_task::task_from_context; +use dom::bindings::node::unwrap; use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject}; -use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT}; +use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT, DOMString}; +use dom::bindings::utils::jsval_to_str; use dom::element::*; use dom::node::{AbstractNode, Element, ElementNodeTypeId}; use layout::layout_task; @@ -16,20 +18,44 @@ use js::glue::bindgen::*; use js::jsapi::bindgen::*; use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSPropertySpec}; use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper, JSFunctionSpec}; -use js::jsapi::JSNativeWrapper; +use js::jsapi::{JSNativeWrapper, JSTracer, JSTRACE_OBJECT}; use js::rust::{Compartment, jsobj}; use js::{JS_ARGV, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL}; use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS}; extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { - debug!("element finalize: %?!", obj as uint); + debug!("element finalize: %x!", obj as uint); unsafe { - let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32); - let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val)); + let node: AbstractNode = unwrap(obj); + //XXXjdm We need separate finalizers for each specialty element type like headings let _elem: ~Element = cast::transmute(node.raw_object()); } } +pub extern fn trace(tracer: *JSTracer, obj: *JSObject) { + let node = unsafe { unwrap(obj) }; + + fn trace_node(tracer: *JSTracer, node: Option, name: &str) { + if node.is_none() { + return; + } + error!("tracing %s", name); + let mut node = node.get(); + let cache = node.get_wrappercache(); + let wrapper = cache.get_wrapper(); + assert!(wrapper.is_not_null()); + unsafe { + JS_CallTracer(tracer, wrapper, JSTRACE_OBJECT as u32); + } + } + error!("tracing %?:", obj as uint); + trace_node(tracer, node.parent_node(), "parent"); + trace_node(tracer, node.first_child(), "first child"); + trace_node(tracer, node.last_child(), "last child"); + trace_node(tracer, node.next_sibling(), "next sibling"); + trace_node(tracer, node.prev_sibling(), "prev sibling"); +} + pub fn init(compartment: @mut Compartment) { let obj = utils::define_empty_prototype(~"Element", Some(~"Node"), compartment); let attrs = @~[ @@ -55,6 +81,11 @@ pub fn init(compartment: @mut Compartment) { nargs: 0, flags: 0, selfHostedName: null()}, + JSFunctionSpec {name: compartment.add_name(~"setAttribute"), + call: JSNativeWrapper {op: setAttribute, info: null()}, + nargs: 0, + flags: 0, + selfHostedName: null()}, JSFunctionSpec {name: null(), call: JSNativeWrapper {op: null(), info: null()}, nargs: 0, @@ -65,7 +96,7 @@ pub fn init(compartment: @mut Compartment) { }); compartment.register_class(utils::instance_jsclass(~"GenericElementInstance", - finalize)); + finalize, trace)); let _ = utils::define_empty_prototype(~"HTMLElement", Some(~"Element"), compartment); let _ = utils::define_empty_prototype(~"HTMLDivElement", Some(~"HTMLElement"), compartment); @@ -93,8 +124,7 @@ pub fn init(compartment: @mut Compartment) { extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool { unsafe { let obj = JS_THIS_OBJECT(cx, vp); - let mut box = utils::unwrap::<*mut AbstractNode>(obj); - let node = &mut *box; + let mut node = unwrap(obj); let rval = do node.with_imm_element |elem| { elem.getClientRects() }; @@ -111,6 +141,39 @@ extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool { } } +extern fn setAttribute(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool { + unsafe { + let obj = JS_THIS_OBJECT(cx, vp); + let mut node = unwrap(obj); + + if (argc < 2) { + return 0; //XXXjdm throw exception + } + + let argv = JS_ARGV(cx, cast::transmute(vp)); + + let arg0: DOMString; + let strval = jsval_to_str(cx, (*argv.offset(0))); + if strval.is_err() { + return 0; + } + arg0 = str(strval.get()); + + let arg1: DOMString; + let strval = jsval_to_str(cx, (*argv.offset(1))); + if strval.is_err() { + return 0; + } + arg1 = str(strval.get()); + + do node.as_mut_element |elem| { + elem.set_attr(&arg0, &arg1); + }; + + return 1; + } +} + #[allow(non_implicitly_copyable_typarams)] extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { unsafe { @@ -119,12 +182,11 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa return 0; } - let mut box = utils::unwrap::<*mut AbstractNode>(obj); - let node = &mut *box; + let mut node = unwrap(obj); let width = match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { let content = task_from_context(cx); - match (*content).query_layout(layout_task::ContentBox(*node)) { + match (*content).query_layout(layout_task::ContentBox(node)) { Ok(rect) => rect.width, Err(()) => 0 } @@ -148,13 +210,13 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa return 0; } - let mut box = utils::unwrap::<*mut AbstractNode>(obj); - let node = &mut *box; + let mut node = unwrap(obj); match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { do node.as_mut_element |elem| { let arg = ptr::offset(JS_ARGV(cx, cast::reinterpret_cast(&vp)), 0); - elem.set_attr(~"width", (RUST_JSVAL_TO_INT(*arg) as int).to_str()) + elem.set_attr(&str(~"width"), + &str((RUST_JSVAL_TO_INT(*arg) as int).to_str())) } } ElementNodeTypeId(_) => fail!(~"why is this not an image element?"), @@ -165,7 +227,6 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa } } -#[allow(non_implicitly_copyable_typarams)] extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { unsafe { let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp)); @@ -173,8 +234,7 @@ extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { return 0; } - let mut box = utils::unwrap::<*mut AbstractNode>(obj); - let node = &mut *box; + let mut node = unwrap(obj); do node.with_imm_element |elem| { let s = str(copy elem.tag_name); *vp = domstring_to_jsval(cx, &s); @@ -183,7 +243,6 @@ extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { return 1; } -#[allow(non_implicitly_copyable_typarams)] pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj { let proto = match node.type_id() { ElementNodeTypeId(HTMLDivElementTypeId) => ~"HTMLDivElement", @@ -201,9 +260,11 @@ pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj { proto, compartment.global_obj.ptr)); - node.get_wrappercache().set_wrapper(obj.ptr); + let cache = node.get_wrappercache(); + assert!(cache.get_wrapper().is_null()); + cache.set_wrapper(obj.ptr); - let raw_ptr = ptr::addr_of(node) as *libc::c_void; + let raw_ptr = node.raw_object() as *libc::c_void; JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT as u32, RUST_PRIVATE_TO_JSVAL(raw_ptr)); return obj; diff --git a/src/servo/dom/bindings/htmlcollection.rs b/src/servo/dom/bindings/htmlcollection.rs index d09057cc9a3..4e2ac722b5f 100644 --- a/src/servo/dom/bindings/htmlcollection.rs +++ b/src/servo/dom/bindings/htmlcollection.rs @@ -2,46 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use content::content_task::task_from_context; -use dom::node::AbstractNode; +use content::content_task::{task_from_context, global_content}; use dom::bindings::codegen::HTMLCollectionBinding; -use dom::bindings::utils::{DOMString, ErrorResult}; use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache}; +use dom::htmlcollection::HTMLCollection; use js::jsapi::{JSObject, JSContext}; -pub struct HTMLCollection { - elements: ~[AbstractNode], - wrapper: WrapperCache -} - pub impl HTMLCollection { - fn new(elements: ~[AbstractNode]) -> HTMLCollection { - HTMLCollection { - elements: elements, - wrapper: WrapperCache::new() - } - } - - fn Length(&self) -> u32 { - self.elements.len() as u32 - } - - fn Item(&self, index: u32) -> Option { - if index < self.Length() { - Some(self.elements[index]) - } else { - None - } - } - - fn NamedItem(&self, _cx: *JSContext, _name: DOMString, rv: &mut ErrorResult) -> *JSObject { - *rv = Ok(()); - ptr::null() - } - - fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option { - *found = true; - self.Item(index) + fn init_wrapper(@mut self) { + let content = global_content(); + let cx = content.compartment.get().cx.ptr; + let owner = content.window.get(); + let cache = owner.get_wrappercache(); + let scope = cache.get_wrapper(); + self.wrap_object_shared(cx, scope); } } diff --git a/src/servo/dom/bindings/node.rs b/src/servo/dom/bindings/node.rs index d9fc8225012..41a14b93507 100644 --- a/src/servo/dom/bindings/node.rs +++ b/src/servo/dom/bindings/node.rs @@ -2,24 +2,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use dom::bindings::utils::{CacheableWrapper, WrapperCache}; -use dom::bindings::utils::{DOM_OBJECT_SLOT}; +use dom::bindings::element; +use dom::bindings::text; +use dom::bindings::utils; +use dom::bindings::utils::{CacheableWrapper, WrapperCache, DerivedWrapper}; use dom::node::{AbstractNode, Node, ElementNodeTypeId, TextNodeTypeId, CommentNodeTypeId}; use dom::node::{DoctypeNodeTypeId}; -use super::element; -use super::utils; use core::libc::c_uint; use core::ptr::null; -use js::glue::bindgen::*; use js::jsapi::bindgen::*; use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSPropertySpec}; use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper}; -use js::jsval::{INT_TO_JSVAL, JSVAL_TO_PRIVATE}; +use js::jsval::{INT_TO_JSVAL}; use js::rust::{Compartment, jsobj}; use js::{JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL}; use js::{JS_THIS_OBJECT, JSPROP_NATIVE_ACCESSORS}; -use js; pub fn init(compartment: @mut Compartment) { let obj = utils::define_empty_prototype(~"Node", None, compartment); @@ -62,15 +60,15 @@ pub fn init(compartment: @mut Compartment) { pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj { match node.type_id() { ElementNodeTypeId(_) => element::create(cx, node), - TextNodeTypeId => fail!(~"no text node bindings yet"), - CommentNodeTypeId => fail!(~"no comment node bindings yet"), - DoctypeNodeTypeId => fail!(~"no doctype node bindings yet") + TextNodeTypeId | + CommentNodeTypeId | + DoctypeNodeTypeId => text::create(cx, node), } } -pub unsafe fn unwrap(obj: *JSObject) -> *AbstractNode { - let val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT as u64); - cast::transmute(JSVAL_TO_PRIVATE(val)) +pub unsafe fn unwrap(obj: *JSObject) -> AbstractNode { + let raw = unsafe { utils::unwrap::<*mut Node>(obj) }; + AbstractNode::from_raw(raw) } #[allow(non_implicitly_copyable_typarams)] @@ -81,14 +79,13 @@ extern fn getFirstChild(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool return 0; } - let node = *unwrap(obj); + let node = unwrap(obj); let rval = do node.with_mut_node |node| { node.getFirstChild() }; match rval { Some(n) => { - let obj = create(cx, n).ptr; - *vp = RUST_OBJECT_TO_JSVAL(obj) + n.wrap(cx, ptr::null(), vp); //XXXjdm pass a real scope } None => *vp = JSVAL_NULL }; @@ -104,14 +101,13 @@ extern fn getNextSibling(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBoo return 0; } - let node = *unwrap(obj); + let node = unwrap(obj); let rval = do node.with_mut_node |node| { node.getNextSibling() }; match rval { Some(n) => { - let obj = create(cx, n).ptr; - *vp = RUST_OBJECT_TO_JSVAL(obj) + n.wrap(cx, ptr::null(), vp); //XXXjdm pass a real scope } None => *vp = JSVAL_NULL }; @@ -155,7 +151,7 @@ extern fn getNodeType(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { return 0; } - let node = *unwrap(obj); + let node = unwrap(obj); let rval = do node.with_imm_node |node| { node.getNodeType() }; diff --git a/src/servo/dom/bindings/text.rs b/src/servo/dom/bindings/text.rs new file mode 100644 index 00000000000..001b8647f61 --- /dev/null +++ b/src/servo/dom/bindings/text.rs @@ -0,0 +1,90 @@ +use dom::bindings::element; +use dom::bindings::utils; +use dom::bindings::utils::{DOM_OBJECT_SLOT, CacheableWrapper}; +use dom::node::{AbstractNode, Text, Comment, Doctype, TextNodeTypeId, CommentNodeTypeId}; +use dom::node::{DoctypeNodeTypeId}; + +use js::jsapi::{JSFreeOp, JSObject, JSContext}; +use js::jsapi::bindgen::{JS_GetReservedSlot, JS_SetReservedSlot}; +use js::glue::bindgen::{RUST_JSVAL_TO_PRIVATE, RUST_PRIVATE_TO_JSVAL}; +use js::rust::{Compartment, jsobj}; + +extern fn finalize_text(_fop: *JSFreeOp, obj: *JSObject) { + debug!("text finalize: %?!", obj as uint); + unsafe { + let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32); + let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val)); + let _elem: ~Text = cast::transmute(node.raw_object()); + } +} + +extern fn finalize_comment(_fop: *JSFreeOp, obj: *JSObject) { + debug!("comment finalize: %?!", obj as uint); + unsafe { + let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32); + let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val)); + let _elem: ~Comment = cast::transmute(node.raw_object()); + } +} + +extern fn finalize_doctype(_fop: *JSFreeOp, obj: *JSObject) { + debug!("doctype finalize: %?!", obj as uint); + unsafe { + let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32); + let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val)); + let _elem: ~Doctype = cast::transmute(node.raw_object()); + } +} + +pub fn init(compartment: @mut Compartment) { + let _ = utils::define_empty_prototype(~"CharacterData", Some(~"Node"), compartment); + + let _ = utils::define_empty_prototype(~"TextPrototype", + Some(~"CharacterData"), + compartment); + let _ = utils::define_empty_prototype(~"CommentPrototype", + Some(~"CharacterData"), + compartment); + let _ = utils::define_empty_prototype(~"DocumentTypePrototype", + Some(~"Node"), + compartment); + + compartment.register_class(utils::instance_jsclass(~"Text", + finalize_text, + element::trace)); + compartment.register_class(utils::instance_jsclass(~"Comment", + finalize_comment, + element::trace)); + compartment.register_class(utils::instance_jsclass(~"DocumentType", + finalize_doctype, + element::trace)); + + +} + +pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj { + let (proto, instance) = match node.type_id() { + TextNodeTypeId => (~"TextPrototype", ~"Text"), + CommentNodeTypeId => (~"CommentPrototype", ~"Comment"), + DoctypeNodeTypeId => (~"DocumentTypePrototype", ~"DocumentType"), + _ => fail!(~"text::create only handles textual nodes") + }; + + //XXXjdm the parent should probably be the node parent instead of the global + //TODO error checking + let compartment = utils::get_compartment(cx); + let obj = result::unwrap(compartment.new_object_with_proto(instance, + proto, + compartment.global_obj.ptr)); + + let cache = node.get_wrappercache(); + assert!(cache.get_wrapper().is_null()); + cache.set_wrapper(obj.ptr); + + unsafe { + let raw_ptr = ptr::to_unsafe_ptr(node) as *libc::c_void; + JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT as u32, RUST_PRIVATE_TO_JSVAL(raw_ptr)); + } + + return obj; +} \ No newline at end of file diff --git a/src/servo/dom/bindings/utils.rs b/src/servo/dom/bindings/utils.rs index 47dafe5e6db..3e23170a904 100644 --- a/src/servo/dom/bindings/utils.rs +++ b/src/servo/dom/bindings/utils.rs @@ -30,9 +30,7 @@ use content::content_task::task_from_context; use core::hashmap::HashMap; -use dom::bindings::document; use dom::bindings::node; -use dom::document::Document; use dom::node::AbstractNode; static TOSTRING_CLASS_RESERVED_SLOT: u64 = 0; @@ -93,6 +91,15 @@ pub enum DOMString { null_string } +pub impl DOMString { + fn to_str(&self) -> ~str { + match *self { + str(ref s) => s.clone(), + null_string => ~"" + } + } +} + pub struct rust_box { rc: uint, td: *sys::TypeDesc, @@ -219,7 +226,7 @@ pub fn prototype_jsclass(name: ~str) -> @fn(compartment: @mut Compartment) -> JS return f; } -pub fn instance_jsclass(name: ~str, finalize: *u8) +pub fn instance_jsclass(name: ~str, finalize: *u8, trace: *u8) -> @fn(compartment: @mut Compartment) -> JSClass { let f: @fn(@mut Compartment) -> JSClass = |compartment: @mut Compartment| { JSClass { @@ -237,7 +244,7 @@ pub fn instance_jsclass(name: ~str, finalize: *u8) call: null(), hasInstance: has_instance, construct: null(), - trace: null(), + trace: trace, reserved: (null(), null(), null(), null(), null(), // 05 null(), null(), null(), null(), null(), // 10 null(), null(), null(), null(), null(), // 15 @@ -788,40 +795,6 @@ impl DerivedWrapper for AbstractNode { } } -/*impl DerivedWrapper for Document { - fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 { - let cache = self.get_wrappercache(); - let wrapper = cache.get_wrapper(); - if wrapper.is_not_null() { - unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) }; - return 1; - } - let content = task_from_context(cx); - unsafe { - let compartment = (*content).compartment.get(); - *vp = RUST_OBJECT_TO_JSVAL(document::create(compartment, self)); - } - return 1; - } -}*/ - -pub impl Document { - fn wrap(@mut self, cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 { - let cache = self.get_wrappercache(); - let wrapper = cache.get_wrapper(); - if wrapper.is_not_null() { - unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) }; - return 1; - } - let content = task_from_context(cx); - unsafe { - let compartment = (*content).compartment.get(); - *vp = RUST_OBJECT_TO_JSVAL(document::create(compartment, self)); - } - return 1; - } -} - pub enum Error { FailureUnknown } diff --git a/src/servo/dom/bindings/window.rs b/src/servo/dom/bindings/window.rs index da24c5e3757..f50bb1f6c2c 100644 --- a/src/servo/dom/bindings/window.rs +++ b/src/servo/dom/bindings/window.rs @@ -76,13 +76,9 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { } } -pub fn init(compartment: @mut Compartment, win: @mut Window) { +pub fn init(compartment: @mut Compartment) { let proto = utils::define_empty_prototype(~"Window", None, compartment); - compartment.register_class(utils::instance_jsclass(~"WindowInstance", finalize)); - - let obj = result::unwrap( - compartment.new_object_with_proto(~"WindowInstance", - ~"Window", null())); + compartment.register_class(utils::instance_jsclass(~"WindowInstance", finalize, null())); /* Define methods on a window */ let methods = [ @@ -116,11 +112,19 @@ pub fn init(compartment: @mut Compartment, win: @mut Window) { } ]; + unsafe { + JS_DefineFunctions(compartment.cx.ptr, proto.ptr, &methods[0]); + } +} + +pub fn create(compartment: @mut Compartment, win: @mut Window) { + let obj = result::unwrap( + compartment.new_object_with_proto(~"WindowInstance", + ~"Window", null())); + win.get_wrappercache().set_wrapper(obj.ptr); unsafe { - JS_DefineFunctions(compartment.cx.ptr, proto.ptr, &methods[0]); - let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(win)); JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr)); } diff --git a/src/servo/dom/characterdata.rs b/src/servo/dom/characterdata.rs new file mode 100644 index 00000000000..b078d6dd03c --- /dev/null +++ b/src/servo/dom/characterdata.rs @@ -0,0 +1,57 @@ +use dom::bindings::utils::{DOMString, null_string, str}; +use dom::node::{Node, NodeTypeId}; + +use core::str; + +pub struct CharacterData { + parent: Node, + data: DOMString +} + +pub impl CharacterData { + fn new(id: NodeTypeId, data: ~str) -> CharacterData { + CharacterData { + parent: Node::new(id), + data: str(data) + } + } + + fn GetData(&self) -> DOMString { + copy self.data + } + + fn SetData(&mut self, arg: DOMString) { + self.data = arg; + } + + fn Length(&self) -> u32 { + match self.data { + str(ref s) => s.len() as u32, + null_string => 0 + } + } + + fn SubstringData(&self, offset: u32, count: u32) -> DOMString { + match self.data { + str(ref s) => str(s.slice(offset as uint, count as uint).to_str()), + null_string => null_string + } + } + + fn AppendData(&mut self, arg: DOMString) { + let s = self.data.to_str(); + self.data = str(str::append(s, arg.to_str())); + } + + fn InsertData(&mut self, _offset: u32, _arg: DOMString) { + fail!(~"nyi") + } + + fn DeleteData(&mut self, _offset: u32, _count: u32) { + fail!(~"nyi") + } + + fn ReplaceData(&mut self, _offset: u32, _count: u32, _arg: DOMString) { + fail!(~"nyi") + } +} diff --git a/src/servo/dom/clientrect.rs b/src/servo/dom/clientrect.rs new file mode 100644 index 00000000000..90856ca5cd3 --- /dev/null +++ b/src/servo/dom/clientrect.rs @@ -0,0 +1,45 @@ +//use dom::bindings::clientrect::ClientRect; +use dom::bindings::utils::WrapperCache; + +pub struct ClientRect { + wrapper: WrapperCache, + top: f32, + bottom: f32, + left: f32, + right: f32, +} + +pub impl ClientRect { + fn new(top: f32, bottom: f32, left: f32, right: f32) -> @mut ClientRect { + let rect = @mut ClientRect { + top: top, bottom: bottom, left: left, right: right, + wrapper: WrapperCache::new() + }; + rect.init_wrapper(); + rect + } + + fn Top(&self) -> f32 { + self.top + } + + fn Bottom(&self) -> f32 { + self.bottom + } + + fn Left(&self) -> f32 { + self.left + } + + fn Right(&self) -> f32 { + self.right + } + + fn Width(&self) -> f32 { + f32::abs(self.right - self.left) + } + + fn Height(&self) -> f32 { + f32::abs(self.bottom - self.top) + } +} diff --git a/src/servo/dom/clientrectlist.rs b/src/servo/dom/clientrectlist.rs new file mode 100644 index 00000000000..ab25d5f4764 --- /dev/null +++ b/src/servo/dom/clientrectlist.rs @@ -0,0 +1,36 @@ +use dom::clientrect::ClientRect; +use dom::bindings::utils::WrapperCache; + +pub struct ClientRectList { + wrapper: WrapperCache, + rects: ~[(f32, f32, f32, f32)] +} + +pub impl ClientRectList { + fn new() -> @mut ClientRectList { + let list = @mut ClientRectList { + wrapper: WrapperCache::new(), + rects: ~[(5.6, 80.2, 3.7, 4.8), (800.1, 8001.1, -50.000001, -45.01)] + }; + list.init_wrapper(); + list + } + + fn Length(&self) -> u32 { + self.rects.len() as u32 + } + + fn Item(&self, index: u32) -> Option<@mut ClientRect> { + if index < self.rects.len() as u32 { + let (top, bottom, left, right) = self.rects[index]; + Some(ClientRect::new(top, bottom, left, right)) + } else { + None + } + } + + fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRect> { + *found = index < self.rects.len() as u32; + self.Item(index) + } +} \ No newline at end of file diff --git a/src/servo/dom/document.rs b/src/servo/dom/document.rs index 1085a6120b4..2cd3f9b2ade 100644 --- a/src/servo/dom/document.rs +++ b/src/servo/dom/document.rs @@ -2,30 +2,55 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use dom::bindings::htmlcollection::HTMLCollection; -use dom::bindings::utils::{DOMString, WrapperCache, str}; +use content::content_task::global_content; +use dom::bindings::document; +use dom::bindings::utils::{DOMString, WrapperCache}; +use dom::event::ReflowEvent; +use dom::htmlcollection::HTMLCollection; use dom::node::AbstractNode; +use dom::window::Window; +use js::jsapi::bindgen::{JS_AddObjectRoot, JS_RemoveObjectRoot}; pub struct Document { root: AbstractNode, - wrapper: WrapperCache + wrapper: WrapperCache, + window: Option<@mut Window>, } -pub fn Document(root: AbstractNode) -> Document { - Document { +pub fn Document(root: AbstractNode, + window: Option<@mut Window>) -> @mut Document { + let doc = @mut Document { root: root, - wrapper: WrapperCache::new() + wrapper: WrapperCache::new(), + window: window + }; + let compartment = global_content().compartment.get(); + do root.with_imm_node |node| { + let wrapper = node.wrapper.get_wrapper(); + assert!(wrapper.is_not_null()); + unsafe { JS_AddObjectRoot(compartment.cx.ptr, ptr::addr_of(&wrapper)); } + } + document::create(compartment, doc); + doc +} + +#[unsafe_destructor] +impl Drop for Document { + fn finalize(&self) { + let compartment = global_content().compartment.get(); + do self.root.with_imm_node |node| { + let wrapper = node.wrapper.get_wrapper(); + assert!(wrapper.is_not_null()); + unsafe { JS_RemoveObjectRoot(compartment.cx.ptr, ptr::addr_of(&wrapper)); } + } } } pub impl Document { fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> { let mut elements = ~[]; - let tag = match tag { - str(s) => s, - _ => ~"" - }; + let tag = tag.to_str(); let _ = for self.root.traverse_preorder |child| { if child.is_element() { do child.with_imm_element |elem| { @@ -35,6 +60,13 @@ pub impl Document { } } }; - Some(@mut HTMLCollection::new(elements)) + Some(HTMLCollection::new(elements)) + } + + fn content_changed(&self) { + do self.window.map |window| { + let chan = &mut window.dom_event_chan; + chan.send(ReflowEvent) + }; } } \ No newline at end of file diff --git a/src/servo/dom/domparser.rs b/src/servo/dom/domparser.rs index e10e37e5ff4..2b08540e40f 100644 --- a/src/servo/dom/domparser.rs +++ b/src/servo/dom/domparser.rs @@ -1,4 +1,5 @@ -use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache}; +use content::content_task::global_content; +use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache, CacheableWrapper}; use dom::bindings::codegen::DOMParserBinding; use dom::document::Document; use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId}; @@ -11,20 +12,25 @@ pub struct DOMParser { } pub impl DOMParser { - fn new(owner: @mut Window) -> DOMParser { - DOMParser { + fn new(owner: @mut Window) -> @mut DOMParser { + let parser = @mut DOMParser { owner: owner, wrapper: WrapperCache::new() - } + }; + let cx = global_content().compartment.get().cx.ptr; + let cache = owner.get_wrappercache(); + let scope = cache.get_wrapper(); + parser.wrap_object_shared(cx, scope); + parser } fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser { - @mut DOMParser::new(owner) + DOMParser::new(owner) } fn ParseFromString(&self, _s: DOMString, _type_: DOMParserBinding::SupportedType, _rv: &mut ErrorResult) -> @mut Document { let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") }; let root = unsafe { Node::as_abstract_node(root) }; - @mut Document(root) + Document(root, None) } } \ No newline at end of file diff --git a/src/servo/dom/element.rs b/src/servo/dom/element.rs index 4c86d413f1c..5512e0c68d5 100644 --- a/src/servo/dom/element.rs +++ b/src/servo/dom/element.rs @@ -7,7 +7,8 @@ // use dom::node::{ElementNodeTypeId, Node}; -use dom::bindings::clientrectlist::ClientRectListImpl; +use dom::clientrectlist::ClientRectList; +use dom::bindings::utils::DOMString; use core::str::eq_slice; use core::cell::Cell; @@ -19,6 +20,13 @@ pub struct Element { attrs: ~[Attr], } +#[unsafe_destructor] +impl Drop for Element { + fn finalize(&self) { + fail!(~"uh oh"); + } +} + #[deriving(Eq)] pub enum ElementTypeId { HTMLAnchorElementTypeId, @@ -132,20 +140,31 @@ pub impl<'self> Element { return None; } - fn set_attr(&mut self, name: &str, value: ~str) { + fn set_attr(&mut self, name: &DOMString, value: &DOMString) { + let name = name.to_str(); + let value = value.to_str(); // FIXME: We need a better each_mut in Rust; this is ugly. let value_cell = Cell(value); + let mut found = false; for uint::range(0, self.attrs.len()) |i| { if eq_slice(self.attrs[i].name, name) { - self.attrs[i].value = value_cell.take(); - return; + self.attrs[i].value = value_cell.take().clone(); + found = true; + break; } } - self.attrs.push(Attr::new(name.to_str(), value_cell.take())); + if !found { + self.attrs.push(Attr::new(name.to_str(), value_cell.take().clone())); + } + + match self.parent.owner_doc { + Some(owner) => owner.content_changed(), + None => {} + } } - fn getClientRects(&self) -> Option<@mut ClientRectListImpl> { - Some(@mut ClientRectListImpl::new()) + fn getClientRects(&self) -> Option<@mut ClientRectList> { + Some(ClientRectList::new()) } } diff --git a/src/servo/dom/htmlcollection.rs b/src/servo/dom/htmlcollection.rs new file mode 100644 index 00000000000..51025cf6c10 --- /dev/null +++ b/src/servo/dom/htmlcollection.rs @@ -0,0 +1,43 @@ +use dom::bindings::utils::WrapperCache; +use dom::bindings::utils::{DOMString, ErrorResult}; +use dom::node::AbstractNode; + +use js::jsapi::{JSObject, JSContext}; + +pub struct HTMLCollection { + elements: ~[AbstractNode], + wrapper: WrapperCache +} + +pub impl HTMLCollection { + fn new(elements: ~[AbstractNode]) -> @mut HTMLCollection { + let collection = @mut HTMLCollection { + elements: elements, + wrapper: WrapperCache::new() + }; + collection.init_wrapper(); + collection + } + + fn Length(&self) -> u32 { + self.elements.len() as u32 + } + + fn Item(&self, index: u32) -> Option { + if index < self.Length() { + Some(self.elements[index]) + } else { + None + } + } + + fn NamedItem(&self, _cx: *JSContext, _name: DOMString, rv: &mut ErrorResult) -> *JSObject { + *rv = Ok(()); + ptr::null() + } + + fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option { + *found = true; + self.Item(index) + } +} diff --git a/src/servo/dom/node.rs b/src/servo/dom/node.rs index d5e38bda35a..050eb85feac 100644 --- a/src/servo/dom/node.rs +++ b/src/servo/dom/node.rs @@ -6,13 +6,15 @@ // The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. // +use content::content_task::global_content; use dom::bindings; use dom::bindings::codegen; +use dom::bindings::node; use dom::bindings::utils::WrapperCache; +use dom::characterdata::CharacterData; use dom::document::Document; use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId}; use dom::element::{HTMLStyleElementTypeId}; -use dom::window::Window; use layout::debug::DebugMethods; use layout::flow::FlowContext; use newcss::complete::CompleteSelectResults; @@ -47,6 +49,8 @@ pub struct Node { next_sibling: Option, prev_sibling: Option, + owner_doc: Option<@mut Document>, + // You must not touch this if you are not layout. priv layout_data: Option<@mut LayoutData> } @@ -106,29 +110,25 @@ impl Doctype { } pub struct Comment { - parent: Node, - text: ~str, + parent: CharacterData, } impl Comment { pub fn new(text: ~str) -> Comment { Comment { - parent: Node::new(CommentNodeTypeId), - text: text + parent: CharacterData::new(CommentNodeTypeId, text) } } } pub struct Text { - parent: Node, - text: ~str, + parent: CharacterData, } impl Text { pub fn new(text: ~str) -> Text { Text { - parent: Node::new(TextNodeTypeId), - text: text + parent: CharacterData::new(TextNodeTypeId, text) } } } @@ -316,6 +316,12 @@ pub impl AbstractNode { unsafe fn raw_object(self) -> *mut Node { self.obj } + + fn from_raw(raw: *mut Node) -> AbstractNode { + AbstractNode { + obj: raw + } + } } impl DebugMethods for AbstractNode { @@ -348,8 +354,25 @@ impl DebugMethods for AbstractNode { impl Node { pub unsafe fn as_abstract_node(node: ~N) -> AbstractNode { // This surrenders memory management of the node! - AbstractNode { + let mut node = AbstractNode { obj: transmute(node), + }; + let cx = global_content().compartment.get().cx.ptr; + node::create(cx, &mut node); + node + } + + pub fn add_to_doc(&mut self, doc: @mut Document) { + self.owner_doc = Some(doc); + let mut node = self.first_child; + while node.is_some() { + node.get().traverse_preorder(|n| { + do n.with_mut_node |n| { + n.owner_doc = Some(doc); + } + true + }); + node = node.get().next_sibling(); } } @@ -364,16 +387,19 @@ impl Node { next_sibling: None, prev_sibling: None, + owner_doc: None, + layout_data: None, } } } -pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @mut Window) { - bindings::window::init(compartment, win); - bindings::document::init(compartment, doc); +pub fn define_bindings(compartment: @mut Compartment) { + bindings::window::init(compartment); + bindings::document::init(compartment); bindings::node::init(compartment); bindings::element::init(compartment); + bindings::text::init(compartment); bindings::utils::initialize_global(compartment.global_obj.ptr); let mut unused = false; assert!(codegen::ClientRectBinding::DefineDOMInterface(compartment.cx.ptr, diff --git a/src/servo/dom/window.rs b/src/servo/dom/window.rs index 2c90fa77c29..6775c1a26da 100644 --- a/src/servo/dom/window.rs +++ b/src/servo/dom/window.rs @@ -2,12 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use content::content_task::{ControlMsg, Timer, ExitMsg}; +use content::content_task::{ControlMsg, Timer, ExitMsg, global_content}; use dom::bindings::utils::WrapperCache; +use dom::bindings::window; +use dom::event::Event; use js::jsapi::JSVal; use util::task::spawn_listener; -use core::comm::{Port, Chan}; +use core::comm::{Port, Chan, SharedChan}; use std::timer; use std::uv_global_loop; @@ -19,6 +21,7 @@ pub enum TimerControlMsg { pub struct Window { timer_chan: Chan, + dom_event_chan: SharedChan, wrapper: WrapperCache } @@ -77,10 +80,12 @@ pub impl Window { } } -pub fn Window(content_chan: comm::SharedChan) -> Window { +pub fn Window(content_chan: comm::SharedChan, + dom_event_chan: comm::SharedChan) -> @mut Window { - Window { + let win = @mut Window { wrapper: WrapperCache::new(), + dom_event_chan: dom_event_chan, timer_chan: do spawn_listener |timer_port: Port| { loop { match timer_port.recv() { @@ -92,5 +97,8 @@ pub fn Window(content_chan: comm::SharedChan) -> Window { } } } - } + }; + let compartment = global_content().compartment.get(); + window::create(compartment, win); + win } diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs index a9c1c03fbdb..ff6d35ff4c1 100644 --- a/src/servo/layout/box_builder.rs +++ b/src/servo/layout/box_builder.rs @@ -489,7 +489,7 @@ pub impl LayoutTreeBuilder { // FIXME: Don't copy text. I guess it should be atomically reference counted? do node.with_imm_text |text_node| { - let string = text_node.text.to_str(); + let string = text_node.parent.data.to_str(); @mut UnscannedTextBox(RenderBoxData(node, ctx, self.next_box_id()), string) } } diff --git a/src/servo/servo.rc b/src/servo/servo.rc index b6c25bd881f..b2d6424cdae 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -62,6 +62,7 @@ pub mod dom { pub mod document; pub mod element; pub mod node; + pub mod text; pub mod utils; pub mod conversions; pub mod window; @@ -77,10 +78,14 @@ pub mod dom { pub mod HTMLCollectionBinding; } } + pub mod characterdata; + pub mod clientrect; + pub mod clientrectlist; pub mod document; pub mod domparser; pub mod element; pub mod event; + pub mod htmlcollection; pub mod node; pub mod window; } diff --git a/src/test/test_bindings.js b/src/test/test_bindings.js index 5f9409b36be..0897476d3b3 100644 --- a/src/test/test_bindings.js +++ b/src/test/test_bindings.js @@ -3,6 +3,7 @@ window.alert("1"); let elem = document.documentElement; +window.alert(elem.nodeType); window.alert(elem); window.alert("2"); var rects = elem.getClientRects(); @@ -24,11 +25,13 @@ window.alert(rect.width); window.alert(rect.height); window.alert("HTMLCollection:"); -let tags = document.getElementsByTagName("head"); +let tags = document.getElementsByTagName("div"); //let tag = tags[0]; window.alert(tags); window.alert(tags.length); window.alert(tags[0]); +window.alert(tags[0].tagName); +window.alert(tags[0].getClientRects()); window.alert(tags[1]); window.alert(tags[2]); window.alert(tags[3]); diff --git a/src/test/test_hammer_layout.css b/src/test/test_hammer_layout.css new file mode 100644 index 00000000000..0e141509285 --- /dev/null +++ b/src/test/test_hammer_layout.css @@ -0,0 +1,3 @@ +div #styled { + color: red; +} \ No newline at end of file diff --git a/src/test/test_hammer_layout.html b/src/test/test_hammer_layout.html new file mode 100644 index 00000000000..b2cb232036a --- /dev/null +++ b/src/test/test_hammer_layout.html @@ -0,0 +1,9 @@ + + + + + + +
This text is unstyled.
+ + diff --git a/src/test/test_hammer_layout.js b/src/test/test_hammer_layout.js new file mode 100644 index 00000000000..89cb0139d8c --- /dev/null +++ b/src/test/test_hammer_layout.js @@ -0,0 +1,17 @@ +window.setTimeout(function() { + //var divs = document.getElementsByTagName("div"); +// divs[0].setAttribute('id', 'styled'); + function print_tree(n) { + window.alert(n.nodeType); + //window.alert(n.tagName); + n = n.firstChild; + while (n) { + print_tree(n); + n = n.nextSibling; + } + } + print_tree(document.documentElement); +//window.alert(document.documentElement.tagName); +//window.alert(document.documentElement.firstChild.nodeType); +//window.alert(document.documentElement.firstChild.firstChild.nodeType); +}, 200); \ No newline at end of file