From daf95fb41b98faf32df332f40009813061383d81 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 20 Aug 2012 18:12:31 -0700 Subject: [PATCH] Add prototypes to DOMDocument and Node. --- src/rust-mozjs | 2 +- src/servo/dom/base.rs | 2 +- src/servo/dom/bindings/document.rs | 51 +++++++++++++++++++++--- src/servo/dom/bindings/node.rs | 62 +++++++++++++++++++++++++----- src/servo/dom/bindings/utils.rs | 18 ++++++++- src/test/test_docelem.js | 23 +++++++---- 6 files changed, 132 insertions(+), 26 deletions(-) diff --git a/src/rust-mozjs b/src/rust-mozjs index 8fa47b7a1dc..fc904d3a7c3 160000 --- a/src/rust-mozjs +++ b/src/rust-mozjs @@ -1 +1 @@ -Subproject commit 8fa47b7a1dcc4e13f0f5a1e978cf332a4e3d0189 +Subproject commit fc904d3a7c36934ad0b2a4f83ad99f3862febada diff --git a/src/servo/dom/base.rs b/src/servo/dom/base.rs index 554a90f20b9..9ca7aa27252 100644 --- a/src/servo/dom/base.rs +++ b/src/servo/dom/base.rs @@ -70,8 +70,8 @@ struct Attr { } fn define_bindings(compartment: bare_compartment, doc: @Document) { - //bindings::window::init(compartment); bindings::document::init(compartment, doc); + bindings::node::init(compartment); } enum ElementKind { diff --git a/src/servo/dom/bindings/document.rs b/src/servo/dom/bindings/document.rs index 50edc1aeee5..1151974856d 100644 --- a/src/servo/dom/bindings/document.rs +++ b/src/servo/dom/bindings/document.rs @@ -66,6 +66,7 @@ extern fn getDocumentElement(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *m } unsafe fn unwrap(obj: *JSObject) -> *rust_box { + //TODO: some kind of check if this is a Document object let val = JS_GetReservedSlot(obj, 0); unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val)) } @@ -79,6 +80,32 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { } fn init(compartment: bare_compartment, doc: @Document) { + fn DocumentProto_class(compartment: bare_compartment) -> JSClass { + {name: compartment.add_name(~"DOMDocumentPrototype"), + flags: 0, + addProperty: JS_PropertyStub, + delProperty: JS_PropertyStub, + getProperty: JS_PropertyStub, + setProperty: JS_StrictPropertyStub, + enumerate: JS_EnumerateStub, + resolve: JS_ResolveStub, + convert: JS_ConvertStub, + finalize: null(), + checkAccess: null(), + call: null(), + construct: null(), + hasInstance: utils::has_instance, + trace: null(), + reserved: (null(), null(), null(), null(), null(), // 05 + null(), null(), null(), null(), null(), // 10 + null(), null(), null(), null(), null(), // 15 + null(), null(), null(), null(), null(), // 20 + null(), null(), null(), null(), null(), // 25 + null(), null(), null(), null(), null(), // 30 + null(), null(), null(), null(), null(), // 35 + null(), null(), null(), null(), null())} // 40 + }; + fn Document_class(compartment: bare_compartment) -> JSClass { {name: compartment.add_name(~"DOMDocument"), flags: JSCLASS_HAS_RESERVED_SLOTS(1), @@ -93,7 +120,7 @@ fn init(compartment: bare_compartment, doc: @Document) { checkAccess: null(), call: null(), construct: null(), - hasInstance: null(), + hasInstance: utils::has_instance, trace: null(), reserved: (null(), null(), null(), null(), null(), // 05 null(), null(), null(), null(), null(), // 10 @@ -105,8 +132,13 @@ fn init(compartment: bare_compartment, doc: @Document) { null(), null(), null(), null(), null())} // 40 }; + compartment.register_class(DocumentProto_class); + compartment.register_class(Document_class); + + //TODO error checking let obj = result::unwrap( - compartment.new_object(Document_class, null(), null())); + compartment.new_object(~"DOMDocumentPrototype", null(), + compartment.global_obj.ptr)); /*let methods = ~[ {name: compartment.add_name("getDocumentURI"), call: getDocumentURI, @@ -123,16 +155,25 @@ fn init(compartment: bare_compartment, doc: @Document) { getter: getDocumentElement, setter: null()}]; vec::push(compartment.global_props, attrs); - vec::as_buf(*attrs, |specs, _len| { + vec::as_buf(*attrs, |specs, _len| { JS_DefineProperties(compartment.cx.ptr, obj.ptr, specs); }); + compartment.define_property(~"Document", RUST_OBJECT_TO_JSVAL(obj.ptr), + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_ENUMERATE); + + let instance = result::unwrap( + //compartment.new_object(Document_class, null(), compartment.global_obj.ptr)); + compartment.new_object_with_proto(~"DOMDocument", ~"DOMDocumentPrototype", + compartment.global_obj.ptr)); + unsafe { let raw_ptr: *libc::c_void = unsafe::reinterpret_cast(squirrel_away(doc)); - JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr)); + JS_SetReservedSlot(instance.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr)); } - compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(obj.ptr), + compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(instance.ptr), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE); } diff --git a/src/servo/dom/bindings/node.rs b/src/servo/dom/bindings/node.rs index 7291afbe00b..d8514fe440f 100644 --- a/src/servo/dom/bindings/node.rs +++ b/src/servo/dom/bindings/node.rs @@ -22,8 +22,33 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { } } -fn create(cx: *JSContext, node: Node) -> jsobj unsafe { - let compartment = get_compartment(cx); +fn init(compartment: bare_compartment) { + fn NodeProto_class(compartment: bare_compartment) -> JSClass { + {name: compartment.add_name(~"NodePrototype"), + flags: 0, + addProperty: JS_PropertyStub, + delProperty: JS_PropertyStub, + getProperty: JS_PropertyStub, + setProperty: JS_StrictPropertyStub, + enumerate: JS_EnumerateStub, + resolve: JS_PropertyStub, + convert: JS_ConvertStub, + finalize: null(), + checkAccess: null(), + call: null(), + construct: null(), + hasInstance: utils::has_instance, + trace: null(), + reserved: (null(), null(), null(), null(), null(), // 05 + null(), null(), null(), null(), null(), // 10 + null(), null(), null(), null(), null(), // 15 + null(), null(), null(), null(), null(), // 20 + null(), null(), null(), null(), null(), // 25 + null(), null(), null(), null(), null(), // 30 + null(), null(), null(), null(), null(), // 35 + null(), null(), null(), null(), null())} // 40 + }; + fn Node_class(compartment: bare_compartment) -> JSClass { {name: compartment.add_name(~"Node"), flags: JSCLASS_HAS_RESERVED_SLOTS(1), @@ -38,7 +63,7 @@ fn create(cx: *JSContext, node: Node) -> jsobj unsafe { checkAccess: null(), call: null(), construct: null(), - hasInstance: null(), + hasInstance: utils::has_instance, trace: null(), reserved: (null(), null(), null(), null(), null(), // 05 null(), null(), null(), null(), null(), // 10 @@ -50,32 +75,49 @@ fn create(cx: *JSContext, node: Node) -> jsobj unsafe { null(), null(), null(), null(), null())} // 40 }; + compartment.register_class(NodeProto_class); + compartment.register_class(Node_class); + let obj = result::unwrap( - (*compartment).new_object(Node_class, null(), - (*compartment).global_obj.ptr)); + compartment.new_object(~"NodePrototype", null(), + compartment.global_obj.ptr)); let attrs = @~[ - {name: (*compartment).add_name(~"firstChild"), + {name: compartment.add_name(~"firstChild"), tinyid: 0, flags: 0, getter: getFirstChild, setter: null()}, - {name: (*compartment).add_name(~"nextSibling"), + {name: compartment.add_name(~"nextSibling"), tinyid: 0, flags: 0, getter: getNextSibling, setter: null()}, - {name: (*compartment).add_name(~"tagName"), + {name: compartment.add_name(~"tagName"), tinyid: 0, flags: 0, getter: getTagName, setter: null()}]; - vec::push((*compartment).global_props, attrs); + vec::push(compartment.global_props, attrs); vec::as_buf(*attrs, |specs, _len| { - JS_DefineProperties((*compartment).cx.ptr, obj.ptr, specs); + JS_DefineProperties(compartment.cx.ptr, obj.ptr, specs); }); + compartment.define_property(~"Node", RUST_OBJECT_TO_JSVAL(obj.ptr), + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_ENUMERATE); +} + +fn create(cx: *JSContext, node: Node) -> jsobj unsafe { + let compartment = get_compartment(cx); + + //XXXjdm the parent should probably be the node parent instead of the global + //TODO error checking + let obj = result::unwrap( + (*compartment).new_object_with_proto(~"Node", ~"NodePrototype", + (*compartment).global_obj.ptr)); + unsafe { let raw_ptr: *libc::c_void = unsafe::reinterpret_cast(squirrel_away_unique(~node)); JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr)); diff --git a/src/servo/dom/bindings/utils.rs b/src/servo/dom/bindings/utils.rs index e56b8440f4d..d7aceb337d8 100644 --- a/src/servo/dom/bindings/utils.rs +++ b/src/servo/dom/bindings/utils.rs @@ -4,7 +4,8 @@ import js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED import js::jsapi::{JSContext, jsval, JSObject, JSBool, jsid, JSClass, JSFreeOp}; import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError, JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN, - JS_DefineFunctions, JS_DefineProperty, JS_GetContextPrivate}; + JS_DefineFunctions, JS_DefineProperty, JS_GetContextPrivate, + JS_GetClass, JS_GetPrototype}; import js::glue::bindgen::*; import result::{result, ok, err}; @@ -75,3 +76,18 @@ fn get_compartment(cx: *JSContext) -> *bare_compartment { compartment } } + +extern fn has_instance(_cx: *JSContext, obj: *JSObject, v: *jsval, bp: *mut JSBool) -> JSBool { + //XXXjdm this is totally broken for non-object values + let mut o = RUST_JSVAL_TO_OBJECT(unsafe {*v}); + let clasp = JS_GetClass(obj); + unsafe { *bp = 0; } + while o.is_not_null() { + if JS_GetClass(o) == clasp { + unsafe { *bp = 1; } + break; + } + o = JS_GetPrototype(o); + } + return 1; +} diff --git a/src/test/test_docelem.js b/src/test/test_docelem.js index caa7058db31..18594a4bed7 100644 --- a/src/test/test_docelem.js +++ b/src/test/test_docelem.js @@ -1,10 +1,17 @@ debug("hi"); var elem = document.documentElement; -debug(elem); -debug(elem.tagName); -debug(elem.firstChild); -debug(elem.firstChild.tagName); -debug(elem.firstChild.nextSibling); -debug(elem.firstChild.nextSibling.tagName); -debug(elem.nextSibling); -debug(elem.nextSibling.tagName); \ No newline at end of file +debug("document.documentElement: " + elem); +debug("Document: " + Document); +debug("Node: " + Node); +debug("Document instanceof Node: " + (Document instanceof Node)); +debug("elem instanceof Node: " + (elem instanceof Node)); +debug("elem instanceof Document: " + (elem instanceof Document)); +debug("document instanceof Document: " + (document instanceof Document)); +debug("document instanceof Node: " + (document instanceof Node)); +debug("elem.tagName: " + elem.tagName); +debug("elem.firstChild: " + elem.firstChild); +debug("elem.firstChild.tagName: " + elem.firstChild.tagName); +debug("elem.firstChild.nextSibling: " + elem.firstChild.nextSibling); +debug("elem.firstChild.nextSibling.tagName: " + elem.firstChild.nextSibling.tagName); +debug("elem.nextSibling: " + elem.nextSibling); +debug("elem.nextSibling.tagName: " + elem.nextSibling.tagName); \ No newline at end of file