diff options
author | Josh Matthews <josh@joshmatthews.net> | 2013-03-21 15:04:36 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2013-03-21 15:05:04 -0400 |
commit | 6660ea02787ba82ad5921c7276da7335c3db759c (patch) | |
tree | 936faf97d71068ffcdb378df4ffa75bcae9b71c3 | |
parent | 5f672775b21f6d39fa586f89c65a6449dc673690 (diff) | |
download | servo-6660ea02787ba82ad5921c7276da7335c3db759c.tar.gz servo-6660ea02787ba82ad5921c7276da7335c3db759c.zip |
Add basic binding for HTMLCollection.
-rw-r--r-- | src/servo/dom/bindings/codegen/Bindings.conf | 12 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/CodegenRust.py | 60 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/Configuration.py | 2 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/HTMLCollection.webidl | 20 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/RegisterBindings.cpp | 2 | ||||
-rw-r--r-- | src/servo/dom/bindings/document.rs | 104 | ||||
-rw-r--r-- | src/servo/dom/bindings/element.rs | 6 | ||||
-rw-r--r-- | src/servo/dom/bindings/htmlcollection.rs | 65 | ||||
-rw-r--r-- | src/servo/dom/bindings/utils.rs | 52 | ||||
-rw-r--r-- | src/servo/dom/document.rs | 24 | ||||
-rw-r--r-- | src/servo/dom/node.rs | 3 | ||||
-rwxr-xr-x | src/servo/servo.rc | 2 | ||||
-rw-r--r-- | src/test/test_bindings.html | 12 | ||||
-rw-r--r-- | src/test/test_bindings.js | 9 |
14 files changed, 280 insertions, 93 deletions
diff --git a/src/servo/dom/bindings/codegen/Bindings.conf b/src/servo/dom/bindings/codegen/Bindings.conf index fcca574d510..8bfc300ca49 100644 --- a/src/servo/dom/bindings/codegen/Bindings.conf +++ b/src/servo/dom/bindings/codegen/Bindings.conf @@ -212,9 +212,9 @@ DOMInterfaces = { 'HTMLCollection': [ { - 'nativeType': 'nsIHTMLCollection', - 'prefable': True, - 'resultNotAddRefed': [ 'item' ] + 'nativeType': 'HTMLCollection', + #'prefable': True, + #'resultNotAddRefed': [ 'item' ] }], 'HTMLOptionsCollection': [ @@ -490,7 +490,7 @@ DOMInterfaces = { } # These are temporary, until they've been converted to use new DOM bindings -def addExternalIface(iface, nativeType=None, headerFile=None): +def addExternalIface(iface, nativeType=None, headerFile=None, pointerType=None): domInterface = { 'concrete': False } @@ -498,6 +498,8 @@ def addExternalIface(iface, nativeType=None, headerFile=None): domInterface['nativeType'] = nativeType if not headerFile is None: domInterface['headerFile'] = headerFile + if not pointerType is None: + domInterface['pointerType'] = pointerType DOMInterfaces[iface] = domInterface # If you add one of these, you need to make sure nsDOMQS.h has the relevant @@ -519,7 +521,7 @@ addExternalIface('CSSRule') addExternalIface('CSSValue') addExternalIface('DOMStringList', nativeType='nsDOMStringList', headerFile='nsDOMLists.h') -addExternalIface('Element', nativeType='nsGenericElement') +addExternalIface('Element', nativeType='AbstractNode', pointerType='') addExternalIface('File') addExternalIface('HitRegionOptions', nativeType='nsISupports') addExternalIface('HTMLElement') diff --git a/src/servo/dom/bindings/codegen/CodegenRust.py b/src/servo/dom/bindings/codegen/CodegenRust.py index e35be6e3148..4421023bec8 100644 --- a/src/servo/dom/bindings/codegen/CodegenRust.py +++ b/src/servo/dom/bindings/codegen/CodegenRust.py @@ -1041,10 +1041,16 @@ for (uint32_t i = 0; i < length; ++i) { undefinedBehavior = treatAs[treatUndefinedAs] def getConversionCode(varName): + #conversionCode = ( + # "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n" + # " return false;\n" + # "}" % (nullBehavior, undefinedBehavior, varName)) conversionCode = ( - "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n" - " return false;\n" - "}" % (nullBehavior, undefinedBehavior, varName)) + "let strval = jsval_to_str(cx, ${val});\n" + "if strval.is_err() {\n" + " return 0;\n" + "}\n" + "%s = str(strval.get());" % varName) if defaultValue is None: return conversionCode @@ -1072,15 +1078,15 @@ for (uint32_t i = 0; i < length; ++i) { declType, None, isOptional) if isOptional: - declType = "Optional<nsAString>" + declType = "Option<DOMString>" else: - declType = "NonNull<nsAString>" + declType = "DOMString" return ( - "%s\n" - "const_cast<%s&>(${declName}) = &${holderName};" % - (getConversionCode("${holderName}"), declType), - CGGeneric("const " + declType), CGGeneric("FakeDependentString"), + "%s\n" % + #"const_cast<%s&>(${declName}) = &${holderName};" % + (getConversionCode("${declName}")), + CGGeneric(declType), None, #CGGeneric("FakeDependentString"), # No need to deal with Optional here; we have handled it already False) @@ -1441,7 +1447,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, "}\n" + successCode) else: - tail = "return JS_WrapValue(cx, ${jsvalPtr});" + tail = "return JS_WrapValue(cx, cast::transmute(${jsvalPtr}));" return ("${jsvalRef} = %s;\n" + tail) % (value) @@ -1511,7 +1517,8 @@ for (uint32_t i = 0; i < length; ++i) { if type.nullable(): wrappingCode = ("if %s.is_none() {\n" % (result) + CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + - "}\n") + "}\n" + + "let mut %s = %s.get();\n" % (result, result)) else: wrappingCode = "" if (not descriptor.interface.isExternal() and @@ -1522,7 +1529,7 @@ for (uint32_t i = 0; i < length; ++i) { if not isCreator: raise MethodNotCreatorError(descriptor.interface.identifier.name) wrapMethod = "WrapNewBindingNonWrapperCachedObject" - wrap = "%s(cx, ${obj}, %s.get(), ${jsvalPtr})" % (wrapMethod, result) + wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, result) # We don't support prefable stuff in workers. assert(not descriptor.prefable or not descriptor.workers) if not descriptor.prefable: @@ -1544,7 +1551,8 @@ for (uint32_t i = 0; i < length; ++i) { getIID = "&NS_GET_IID(%s), " % descriptor.nativeType else: getIID = "" - wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID) + #wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID) + wrap = "%s.wrap(cx, ${obj}, %s${jsvalPtr})" % (result, getIID) wrappingCode += wrapAndSetPtr(wrap) return (wrappingCode, False) @@ -1587,7 +1595,7 @@ if (!%(resultStr)s) { # See comments in WrapNewBindingObject explaining why we need # to wrap here. if type.nullable(): - toValue = "JS::ObjectOrNullValue(%s)" + toValue = "RUST_OBJECT_TO_JSVAL(%s)" else: toValue = "JS::ObjectValue(*%s)" # NB: setValue(..., True) calls JS_WrapValue(), so is fallible @@ -1690,10 +1698,11 @@ def getRetvalDeclarationForType(returnType, descriptorProvider, raise TypeError("We don't support nullable enum return values") return CGGeneric(returnType.inner.identifier.name), False if returnType.isGeckoInterface(): - result = CGGeneric(descriptorProvider.getDescriptor( - returnType.unroll().inner.identifier.name).nativeType) + descriptor = descriptorProvider.getDescriptor( + returnType.unroll().inner.identifier.name) + result = CGGeneric(descriptor.nativeType) if resultAlreadyAddRefed: - result = CGWrapper(result, pre="Option<~", post=">") + result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">") else: result = CGWrapper(result, post="*") return result, False @@ -2901,7 +2910,7 @@ class CGCallGenerator(CGThing): if resultOutParam: args.append(CGGeneric("result")) if isFallible: - args.append(CGGeneric("rv")) + args.append(CGGeneric("&mut rv")) needsCx = (typeNeedsCx(returnType, True) or any(typeNeedsCx(a.type) for (a, _) in arguments) or @@ -2930,8 +2939,8 @@ class CGCallGenerator(CGThing): self.cgRoot.append(call) if isFallible: - self.cgRoot.prepend(CGGeneric("ErrorResult rv;")) - self.cgRoot.append(CGGeneric("if (rv.Failed()) {")) + self.cgRoot.prepend(CGGeneric("let mut rv: ErrorResult = Ok(());")) + self.cgRoot.append(CGGeneric("if (rv.is_err()) {")) self.cgRoot.append(CGIndenter(errorReport)) self.cgRoot.append(CGGeneric("}")) @@ -3031,10 +3040,11 @@ class CGPerSignatureCall(CGThing): self.idlNode.identifier.name)) def getErrorReport(self): - return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");' - % (toStringBool(not self.descriptor.workers), - self.descriptor.interface.identifier.name, - self.idlNode.identifier.name)) + #return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");' + # % (toStringBool(not self.descriptor.workers), + # self.descriptor.interface.identifier.name, + # self.idlNode.identifier.name)) + return CGGeneric('return 0'); #XXXjdm def define(self): return (self.cgRoot.define() + "\n" + self.wrap_return_value()) @@ -3844,10 +3854,12 @@ class CGBindingRoot(CGThing): 'js::jsfriendapi::bindgen::*', 'js::glue::bindgen::*', 'js::glue::*', + 'dom::node::AbstractNode', 'dom::bindings::utils::*', 'dom::bindings::conversions::*', 'dom::bindings::clientrect::*', #XXXjdm 'dom::bindings::clientrectlist::*', #XXXjdm + 'dom::bindings::htmlcollection::*', #XXXjdm 'dom::bindings::proxyhandler::*', 'content::content_task::task_from_context' ], diff --git a/src/servo/dom/bindings/codegen/Configuration.py b/src/servo/dom/bindings/codegen/Configuration.py index 9f0c20f6584..d1ca528a3a3 100644 --- a/src/servo/dom/bindings/codegen/Configuration.py +++ b/src/servo/dom/bindings/codegen/Configuration.py @@ -139,7 +139,7 @@ class Descriptor(DescriptorProvider): nativeTypeDefault = "mozilla::dom::" + ifaceName self.nativeType = desc.get('nativeType', nativeTypeDefault) - self.pointerType = desc.get('pointerType', '@') + self.pointerType = desc.get('pointerType', '~') self.hasInstanceInterface = desc.get('hasInstanceInterface', None) # Do something sane for JSObject diff --git a/src/servo/dom/bindings/codegen/HTMLCollection.webidl b/src/servo/dom/bindings/codegen/HTMLCollection.webidl new file mode 100644 index 00000000000..5797f85e392 --- /dev/null +++ b/src/servo/dom/bindings/codegen/HTMLCollection.webidl @@ -0,0 +1,20 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. + * + * The origin of this IDL file is + * http://www.w3.org/TR/2012/WD-dom-20120105/ + * + * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +interface Element; + +interface HTMLCollection { + readonly attribute unsigned long length; + getter Element? item(unsigned long index); + [Throws] + getter object? namedItem(DOMString name); // only returns Element +}; diff --git a/src/servo/dom/bindings/codegen/RegisterBindings.cpp b/src/servo/dom/bindings/codegen/RegisterBindings.cpp index 12e20c201d3..0cc45d1ddc4 100644 --- a/src/servo/dom/bindings/codegen/RegisterBindings.cpp +++ b/src/servo/dom/bindings/codegen/RegisterBindings.cpp @@ -1,5 +1,6 @@ #include "ClientRectBinding.h" #include "ClientRectListBinding.h" +#include "HTMLCollectionBinding.h" #include "nsScriptNameSpaceManager.h" namespace mozilla { @@ -13,6 +14,7 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager) REGISTER_PROTO(ClientRect, nullptr); REGISTER_PROTO(ClientRectList, nullptr); +REGISTER_PROTO(HTMLCollection, nullptr); #undef REGISTER_PROTO } diff --git a/src/servo/dom/bindings/document.rs b/src/servo/dom/bindings/document.rs index 8c8df125c61..6879db9c837 100644 --- a/src/servo/dom/bindings/document.rs +++ b/src/servo/dom/bindings/document.rs @@ -2,7 +2,8 @@ use js::rust::{Compartment, jsobj}; use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL, JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS}; use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSFreeOp, - JSPropertySpec, JSPropertyOpWrapper, JSStrictPropertyOpWrapper}; + JSPropertySpec, JSPropertyOpWrapper, JSStrictPropertyOpWrapper, + JSNativeWrapper, JSFunctionSpec}; use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError, JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty, JS_DefineProperties}; @@ -12,67 +13,53 @@ use js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_Con use core::ptr::null; use core::libc::c_uint; use dom::bindings::utils::{DOMString, domstring_to_jsval, rust_box, squirrel_away, str}; +use dom::bindings::utils::{jsval_to_str, WrapNewBindingObject, CacheableWrapper}; +use dom::bindings::utils::WrapperCache; use dom::bindings::node::create; use dom::document::Document; +use dom::bindings::htmlcollection::HTMLCollection; use dom::bindings::node; use dom::bindings::utils; use dom::node::Node; -enum DOMException { - INVALID_CHARACTER_ERR -} - -struct Element(int); - -/*extern fn getElementById(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool { - //XXX check if actually document object - if argc != 1 { - //XXX throw proper DOM exception - str::as_c_str("Not enough arguments", |s| { - JS_ReportError(cx, s); - }); - return 0; - } - let id; +extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { unsafe { - id = JS_ARGV(cx, vp)[0]; - } - alt jsval_to_str(cx, id) { - ok(s) { - unsafe { - let doc: *Document = cast::reinterpret_cast(JS_GetContextPrivate(cx)); - let elem = (*doc).getElementById(s); + let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp)); + if obj.is_null() { + return 0; } - //XXX wrap result + + let doc = &mut (*unwrap(obj)).payload; + *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, &mut doc.root).ptr); return 1; - } - err(_) { - str::as_c_str("???", |s| { - JS_ReportError(cx, s); - }); - return 0; - } } -}*/ +} -/*extern fn getDocumentURI(cx: *JSContext, _argc: c_uint, vp: *jsval) -> JSBool { +extern fn getElementsByTagName(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool { unsafe { - let uri = (*unwrap(JS_THIS_OBJECT(cx, vp))).payload.getDocumentURI(); - JS_SET_RVAL(cx, vp, domstring_to_jsval(cx, uri)); - } - return 1; -}*/ + let obj = JS_THIS_OBJECT(cx, vp); -extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { - unsafe { - let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp)); - if obj.is_null() { + 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 doc = &mut (*unwrap(obj)).payload; - *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, &mut doc.root).ptr); + let rval: Option<~HTMLCollection>; + rval = doc.getElementsByTagName(arg0); + if rval.is_none() { + JS_SET_RVAL(cx, vp, JSVAL_NULL); + } else { + let cache = doc.get_wrappercache(); + fail_unless!(WrapNewBindingObject(cx, cache.get_wrapper(), + rval.get(), + cast::transmute(vp))); + } return 1; } } @@ -112,11 +99,26 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) { fail_unless!(JS_DefineProperties(compartment.cx.ptr, obj.ptr, specs) == 1); }); + let methods = @~[JSFunctionSpec {name: compartment.add_name(~"getElementsByTagName"), + call: JSNativeWrapper {op: getElementsByTagName, info: null()}, + nargs: 0, + flags: 0, + selfHostedName: null()}, + JSFunctionSpec {name: null(), + call: JSNativeWrapper {op: null(), info: null()}, + nargs: 0, + flags: 0, + selfHostedName: null()}]; + vec::as_imm_buf(*methods, |fns, _len| { + JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns); + }); + compartment.register_class(utils::instance_jsclass(~"DocumentInstance", finalize)); let instance : jsobj = result::unwrap( compartment.new_object_with_proto(~"DocumentInstance", ~"Document", compartment.global_obj.ptr)); + doc.wrapper.set_wrapper(instance.ptr); unsafe { let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc)); @@ -128,3 +130,17 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) { GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8, JSPROP_ENUMERATE); } + +impl CacheableWrapper for Document { + fn get_wrappercache(&mut self) -> &mut WrapperCache { + unsafe { cast::transmute(&self.wrapper) } + } + + fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject { + fail!(~"need to implement wrapping"); + } + + fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject { + fail!(~"need to implement wrapping"); + } +} diff --git a/src/servo/dom/bindings/element.rs b/src/servo/dom/bindings/element.rs index ba2c139003a..da3b2e4d440 100644 --- a/src/servo/dom/bindings/element.rs +++ b/src/servo/dom/bindings/element.rs @@ -2,7 +2,6 @@ use content::content_task::{Content, task_from_context}; use dom::bindings::utils::{rust_box, squirrel_away_unique, get_compartment}; use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject}; use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT}; -use dom::bindings::utils; use dom::bindings::clientrectlist::ClientRectListImpl; use dom::element::*; use dom::node::{AbstractNode, Node, Element, ElementNodeTypeId}; @@ -22,7 +21,7 @@ use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, J use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS}; extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { - debug!("element finalize!"); + debug!("element 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)); @@ -123,8 +122,7 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa let width = match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { let content = task_from_context(cx); - let node = Node::as_abstract_node(~*node); - match (*content).query_layout(layout_task::ContentBox(node)) { + match (*content).query_layout(layout_task::ContentBox(*node)) { Ok(rect) => rect.width, Err(()) => 0 } diff --git a/src/servo/dom/bindings/htmlcollection.rs b/src/servo/dom/bindings/htmlcollection.rs new file mode 100644 index 00000000000..319f9095532 --- /dev/null +++ b/src/servo/dom/bindings/htmlcollection.rs @@ -0,0 +1,65 @@ +use content::content_task::task_from_context; +use dom::element::Element; +use dom::node::AbstractNode; +use dom::bindings::codegen::HTMLCollectionBinding; +use dom::bindings::utils::{DOMString, ErrorResult, OpaqueBindingReference}; +use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache}; +use js::jsapi::{JSObject, JSContext}; + +pub struct HTMLCollection { + elements: ~[AbstractNode], + wrapper: WrapperCache +} + +pub impl HTMLCollection { + static 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<AbstractNode> { + 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<AbstractNode> { + *found = true; + self.Item(index) + } +} + +impl BindingObject for HTMLCollection { + fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference { + let content = task_from_context(cx); + unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) } + } +} + +impl CacheableWrapper for HTMLCollection { + fn get_wrappercache(&mut self) -> &mut WrapperCache { + unsafe { cast::transmute(&self.wrapper) } + } + + fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject { + let mut unused = false; + HTMLCollectionBinding::Wrap(cx, scope, self, &mut unused) + } + + fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject { + fail!(~"nyi") + } +} diff --git a/src/servo/dom/bindings/utils.rs b/src/servo/dom/bindings/utils.rs index 9d2b5a135b4..35c74548bf8 100644 --- a/src/servo/dom/bindings/utils.rs +++ b/src/servo/dom/bindings/utils.rs @@ -13,9 +13,10 @@ use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_Repor JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject, JS_GetInternedStringCharsAndLength, JS_DefineProperties, JS_WrapValue, JS_GetObjectPrototype, JS_ForwardGetPropertyTo, - JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject}; + JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject, + JS_EncodeString, JS_free}; use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType; -use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass}; +use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL}; use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB, RESOLVE_STUB}; use js::glue::bindgen::*; @@ -25,6 +26,9 @@ use content::content_task::{Content, task_from_context}; use core::hashmap::linear; +use dom::bindings::node; +use dom::node::AbstractNode; + const TOSTRING_CLASS_RESERVED_SLOT: u64 = 0; const TOSTRING_NAME_RESERVED_SLOT: u64 = 1; @@ -131,15 +135,11 @@ pub fn jsval_to_str(cx: *JSContext, v: JSVal) -> Result<~str, ()> { } } - let len = 0; - let chars = JS_GetStringCharsZAndLength(cx, jsstr, ptr::to_unsafe_ptr(&len)); - return if chars.is_null() { - Err(()) - } else { - unsafe { - let buf = vec::raw::from_buf_raw(chars as *u8, len as uint); - Ok(str::from_bytes(buf)) - } + unsafe { + let strbuf = JS_EncodeString(cx, jsstr); + let buf = str::raw::from_buf(strbuf as *u8); + JS_free(cx, strbuf as *libc::c_void); + Ok(buf) } } @@ -330,7 +330,7 @@ pub struct ConstantSpec { pub struct DOMClass { // A list of interfaces that this object implements, in order of decreasing // derivedness. - interface_chain: [prototypes::id::Prototype * 2 /*prototypes::id::_ID_Count*/], + interface_chain: [prototypes::id::Prototype * 2 /*max prototype chain length*/], unused: bool, // DOMObjectIsISupports (always false) native_hooks: *NativePropertyHooks @@ -353,6 +353,7 @@ pub mod prototypes { pub enum Prototype { ClientRect, ClientRectList, + HTMLCollection, _ID_Count } } @@ -540,7 +541,7 @@ pub extern fn ThrowingConstructor(cx: *JSContext, argc: uint, vp: *JSVal) -> JSB } pub fn initialize_global(global: *JSObject) { - let protoArray = @mut [0 as *JSObject, ..2]; //XXXjdm number of constructors + let protoArray = @mut [0 as *JSObject, ..3]; //XXXjdm prototypes::_ID_COUNT unsafe { //XXXjdm we should be storing the box pointer instead of the inner let box = squirrel_away(protoArray); @@ -777,4 +778,27 @@ pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &mut [jsid]) -> bo } } rval -}
\ No newline at end of file +} + +pub trait DerivedWrapper { + fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32; +} + +impl DerivedWrapper for AbstractNode { + 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; + } + unsafe { *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, self).ptr) }; + return 1; + } +} + +pub enum Error { + FailureUnknown +} + +pub type ErrorResult = Result<(), Error>;
\ No newline at end of file diff --git a/src/servo/dom/document.rs b/src/servo/dom/document.rs index 18b033a4934..d47b473663c 100644 --- a/src/servo/dom/document.rs +++ b/src/servo/dom/document.rs @@ -1,3 +1,5 @@ +use dom::bindings::htmlcollection::HTMLCollection; +use dom::bindings::utils::{DOMString, WrapperCache, str}; use dom::node::AbstractNode; use newcss::stylesheet::Stylesheet; @@ -5,10 +7,32 @@ use std::arc::ARC; pub struct Document { root: AbstractNode, + wrapper: WrapperCache } pub fn Document(root: AbstractNode) -> Document { Document { root: root, + wrapper: WrapperCache::new() } } + +pub impl Document { + fn getElementsByTagName(&self, tag: DOMString) -> Option<~HTMLCollection> { + let mut elements = ~[]; + let tag = match tag { + str(s) => s, + _ => ~"" + }; + let _ = for self.root.traverse_preorder |child| { + if child.is_element() { + do child.with_imm_element |elem| { + if elem.tag_name == tag { + elements.push(child); + } + } + } + }; + Some(~HTMLCollection::new(elements)) + } +}
\ No newline at end of file diff --git a/src/servo/dom/node.rs b/src/servo/dom/node.rs index 54a86bf871f..2f6bd608449 100644 --- a/src/servo/dom/node.rs +++ b/src/servo/dom/node.rs @@ -390,4 +390,7 @@ pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @ fail_unless!(codegen::ClientRectListBinding::DefineDOMInterface(compartment.cx.ptr, compartment.global_obj.ptr, &mut unused)); + fail_unless!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr, + compartment.global_obj.ptr, + &mut unused)); } diff --git a/src/servo/servo.rc b/src/servo/servo.rc index f2dbdef6ec8..9d5b12820cb 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -49,9 +49,11 @@ pub mod dom { pub mod proxyhandler; pub mod clientrect; pub mod clientrectlist; + pub mod htmlcollection; pub mod codegen { pub mod ClientRectBinding; pub mod ClientRectListBinding; + pub mod HTMLCollectionBinding; } } pub mod document; diff --git a/src/test/test_bindings.html b/src/test/test_bindings.html index d40ed32fe9e..7b906908e1c 100644 --- a/src/test/test_bindings.html +++ b/src/test/test_bindings.html @@ -1 +1,11 @@ -<script src="test_bindings.js"></script> +<html> + <head> + <script src="test_bindings.js"></script> + </head> + <body> + <div id="first"></div> + <div id="second"></div> + <span id="third"></div> + <div id="fourth"></div> + </body> +</html> diff --git a/src/test/test_bindings.js b/src/test/test_bindings.js index 1823cc4ba9f..1f48599d08e 100644 --- a/src/test/test_bindings.js +++ b/src/test/test_bindings.js @@ -23,3 +23,12 @@ window.alert(rect.right); window.alert(rect.width); window.alert(rect.height); +window.alert("HTMLCollection:"); +let tags = document.getElementsByTagName("head"); +//let tag = tags[0]; +window.alert(tags); +window.alert(tags.length); +window.alert(tags[0]); +window.alert(tags[1]); +window.alert(tags[2]); +window.alert(tags[3]); |