Add basic binding for HTMLCollection.

This commit is contained in:
Josh Matthews 2013-03-21 15:04:36 -04:00
parent 5f672775b2
commit 6660ea0278
14 changed files with 282 additions and 95 deletions

View file

@ -212,9 +212,9 @@ DOMInterfaces = {
'HTMLCollection': [ 'HTMLCollection': [
{ {
'nativeType': 'nsIHTMLCollection', 'nativeType': 'HTMLCollection',
'prefable': True, #'prefable': True,
'resultNotAddRefed': [ 'item' ] #'resultNotAddRefed': [ 'item' ]
}], }],
'HTMLOptionsCollection': [ 'HTMLOptionsCollection': [
@ -490,7 +490,7 @@ DOMInterfaces = {
} }
# These are temporary, until they've been converted to use new DOM bindings # 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 = { domInterface = {
'concrete': False 'concrete': False
} }
@ -498,6 +498,8 @@ def addExternalIface(iface, nativeType=None, headerFile=None):
domInterface['nativeType'] = nativeType domInterface['nativeType'] = nativeType
if not headerFile is None: if not headerFile is None:
domInterface['headerFile'] = headerFile domInterface['headerFile'] = headerFile
if not pointerType is None:
domInterface['pointerType'] = pointerType
DOMInterfaces[iface] = domInterface DOMInterfaces[iface] = domInterface
# If you add one of these, you need to make sure nsDOMQS.h has the relevant # 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('CSSValue')
addExternalIface('DOMStringList', nativeType='nsDOMStringList', addExternalIface('DOMStringList', nativeType='nsDOMStringList',
headerFile='nsDOMLists.h') headerFile='nsDOMLists.h')
addExternalIface('Element', nativeType='nsGenericElement') addExternalIface('Element', nativeType='AbstractNode', pointerType='')
addExternalIface('File') addExternalIface('File')
addExternalIface('HitRegionOptions', nativeType='nsISupports') addExternalIface('HitRegionOptions', nativeType='nsISupports')
addExternalIface('HTMLElement') addExternalIface('HTMLElement')

View file

@ -1041,10 +1041,16 @@ for (uint32_t i = 0; i < length; ++i) {
undefinedBehavior = treatAs[treatUndefinedAs] undefinedBehavior = treatAs[treatUndefinedAs]
def getConversionCode(varName): def getConversionCode(varName):
#conversionCode = (
# "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
# " return false;\n"
# "}" % (nullBehavior, undefinedBehavior, varName))
conversionCode = ( conversionCode = (
"if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n" "let strval = jsval_to_str(cx, ${val});\n"
" return false;\n" "if strval.is_err() {\n"
"}" % (nullBehavior, undefinedBehavior, varName)) " return 0;\n"
"}\n"
"%s = str(strval.get());" % varName)
if defaultValue is None: if defaultValue is None:
return conversionCode return conversionCode
@ -1072,15 +1078,15 @@ for (uint32_t i = 0; i < length; ++i) {
declType, None, isOptional) declType, None, isOptional)
if isOptional: if isOptional:
declType = "Optional<nsAString>" declType = "Option<DOMString>"
else: else:
declType = "NonNull<nsAString>" declType = "DOMString"
return ( return (
"%s\n" "%s\n" %
"const_cast<%s&>(${declName}) = &${holderName};" % #"const_cast<%s&>(${declName}) = &${holderName};" %
(getConversionCode("${holderName}"), declType), (getConversionCode("${declName}")),
CGGeneric("const " + declType), CGGeneric("FakeDependentString"), CGGeneric(declType), None, #CGGeneric("FakeDependentString"),
# No need to deal with Optional here; we have handled it already # No need to deal with Optional here; we have handled it already
False) False)
@ -1441,7 +1447,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
"}\n" + "}\n" +
successCode) successCode)
else: else:
tail = "return JS_WrapValue(cx, ${jsvalPtr});" tail = "return JS_WrapValue(cx, cast::transmute(${jsvalPtr}));"
return ("${jsvalRef} = %s;\n" + return ("${jsvalRef} = %s;\n" +
tail) % (value) tail) % (value)
@ -1511,7 +1517,8 @@ for (uint32_t i = 0; i < length; ++i) {
if type.nullable(): if type.nullable():
wrappingCode = ("if %s.is_none() {\n" % (result) + wrappingCode = ("if %s.is_none() {\n" % (result) +
CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
"}\n") "}\n" +
"let mut %s = %s.get();\n" % (result, result))
else: else:
wrappingCode = "" wrappingCode = ""
if (not descriptor.interface.isExternal() and if (not descriptor.interface.isExternal() and
@ -1522,7 +1529,7 @@ for (uint32_t i = 0; i < length; ++i) {
if not isCreator: if not isCreator:
raise MethodNotCreatorError(descriptor.interface.identifier.name) raise MethodNotCreatorError(descriptor.interface.identifier.name)
wrapMethod = "WrapNewBindingNonWrapperCachedObject" 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. # We don't support prefable stuff in workers.
assert(not descriptor.prefable or not descriptor.workers) assert(not descriptor.prefable or not descriptor.workers)
if not descriptor.prefable: if not descriptor.prefable:
@ -1544,7 +1551,8 @@ for (uint32_t i = 0; i < length; ++i) {
getIID = "&NS_GET_IID(%s), " % descriptor.nativeType getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
else: else:
getIID = "" 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) wrappingCode += wrapAndSetPtr(wrap)
return (wrappingCode, False) return (wrappingCode, False)
@ -1587,7 +1595,7 @@ if (!%(resultStr)s) {
# See comments in WrapNewBindingObject explaining why we need # See comments in WrapNewBindingObject explaining why we need
# to wrap here. # to wrap here.
if type.nullable(): if type.nullable():
toValue = "JS::ObjectOrNullValue(%s)" toValue = "RUST_OBJECT_TO_JSVAL(%s)"
else: else:
toValue = "JS::ObjectValue(*%s)" toValue = "JS::ObjectValue(*%s)"
# NB: setValue(..., True) calls JS_WrapValue(), so is fallible # 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") raise TypeError("We don't support nullable enum return values")
return CGGeneric(returnType.inner.identifier.name), False return CGGeneric(returnType.inner.identifier.name), False
if returnType.isGeckoInterface(): if returnType.isGeckoInterface():
result = CGGeneric(descriptorProvider.getDescriptor( descriptor = descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeType) returnType.unroll().inner.identifier.name)
result = CGGeneric(descriptor.nativeType)
if resultAlreadyAddRefed: if resultAlreadyAddRefed:
result = CGWrapper(result, pre="Option<~", post=">") result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
else: else:
result = CGWrapper(result, post="*") result = CGWrapper(result, post="*")
return result, False return result, False
@ -2901,7 +2910,7 @@ class CGCallGenerator(CGThing):
if resultOutParam: if resultOutParam:
args.append(CGGeneric("result")) args.append(CGGeneric("result"))
if isFallible: if isFallible:
args.append(CGGeneric("rv")) args.append(CGGeneric("&mut rv"))
needsCx = (typeNeedsCx(returnType, True) or needsCx = (typeNeedsCx(returnType, True) or
any(typeNeedsCx(a.type) for (a, _) in arguments) or any(typeNeedsCx(a.type) for (a, _) in arguments) or
@ -2930,8 +2939,8 @@ class CGCallGenerator(CGThing):
self.cgRoot.append(call) self.cgRoot.append(call)
if isFallible: if isFallible:
self.cgRoot.prepend(CGGeneric("ErrorResult rv;")) self.cgRoot.prepend(CGGeneric("let mut rv: ErrorResult = Ok(());"))
self.cgRoot.append(CGGeneric("if (rv.Failed()) {")) self.cgRoot.append(CGGeneric("if (rv.is_err()) {"))
self.cgRoot.append(CGIndenter(errorReport)) self.cgRoot.append(CGIndenter(errorReport))
self.cgRoot.append(CGGeneric("}")) self.cgRoot.append(CGGeneric("}"))
@ -3031,10 +3040,11 @@ class CGPerSignatureCall(CGThing):
self.idlNode.identifier.name)) self.idlNode.identifier.name))
def getErrorReport(self): def getErrorReport(self):
return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");' #return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
% (toStringBool(not self.descriptor.workers), # % (toStringBool(not self.descriptor.workers),
self.descriptor.interface.identifier.name, # self.descriptor.interface.identifier.name,
self.idlNode.identifier.name)) # self.idlNode.identifier.name))
return CGGeneric('return 0'); #XXXjdm
def define(self): def define(self):
return (self.cgRoot.define() + "\n" + self.wrap_return_value()) return (self.cgRoot.define() + "\n" + self.wrap_return_value())
@ -3844,10 +3854,12 @@ class CGBindingRoot(CGThing):
'js::jsfriendapi::bindgen::*', 'js::jsfriendapi::bindgen::*',
'js::glue::bindgen::*', 'js::glue::bindgen::*',
'js::glue::*', 'js::glue::*',
'dom::node::AbstractNode',
'dom::bindings::utils::*', 'dom::bindings::utils::*',
'dom::bindings::conversions::*', 'dom::bindings::conversions::*',
'dom::bindings::clientrect::*', #XXXjdm 'dom::bindings::clientrect::*', #XXXjdm
'dom::bindings::clientrectlist::*', #XXXjdm 'dom::bindings::clientrectlist::*', #XXXjdm
'dom::bindings::htmlcollection::*', #XXXjdm
'dom::bindings::proxyhandler::*', 'dom::bindings::proxyhandler::*',
'content::content_task::task_from_context' 'content::content_task::task_from_context'
], ],

View file

@ -139,7 +139,7 @@ class Descriptor(DescriptorProvider):
nativeTypeDefault = "mozilla::dom::" + ifaceName nativeTypeDefault = "mozilla::dom::" + ifaceName
self.nativeType = desc.get('nativeType', nativeTypeDefault) self.nativeType = desc.get('nativeType', nativeTypeDefault)
self.pointerType = desc.get('pointerType', '@') self.pointerType = desc.get('pointerType', '~')
self.hasInstanceInterface = desc.get('hasInstanceInterface', None) self.hasInstanceInterface = desc.get('hasInstanceInterface', None)
# Do something sane for JSObject # Do something sane for JSObject

View file

@ -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
};

View file

@ -1,5 +1,6 @@
#include "ClientRectBinding.h" #include "ClientRectBinding.h"
#include "ClientRectListBinding.h" #include "ClientRectListBinding.h"
#include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h" #include "nsScriptNameSpaceManager.h"
namespace mozilla { namespace mozilla {
@ -13,6 +14,7 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
REGISTER_PROTO(ClientRect, nullptr); REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr); REGISTER_PROTO(ClientRectList, nullptr);
REGISTER_PROTO(HTMLCollection, nullptr);
#undef REGISTER_PROTO #undef REGISTER_PROTO
} }

View file

@ -2,7 +2,8 @@ use js::rust::{Compartment, jsobj};
use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED,
JSVAL_NULL, JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS}; JSVAL_NULL, JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSFreeOp, 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, use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN, JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
JS_DefineFunctions, JS_DefineProperty, JS_DefineProperties}; JS_DefineFunctions, JS_DefineProperty, JS_DefineProperties};
@ -12,58 +13,16 @@ use js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_Con
use core::ptr::null; use core::ptr::null;
use core::libc::c_uint; use core::libc::c_uint;
use dom::bindings::utils::{DOMString, domstring_to_jsval, rust_box, squirrel_away, str}; 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::bindings::node::create;
use dom::document::Document; use dom::document::Document;
use dom::bindings::htmlcollection::HTMLCollection;
use dom::bindings::node; use dom::bindings::node;
use dom::bindings::utils; use dom::bindings::utils;
use dom::node::Node; 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;
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);
}
//XXX wrap result
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 {
unsafe {
let uri = (*unwrap(JS_THIS_OBJECT(cx, vp))).payload.getDocumentURI();
JS_SET_RVAL(cx, vp, domstring_to_jsval(cx, uri));
}
return 1;
}*/
extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool { extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
unsafe { unsafe {
let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp)); let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp));
@ -77,6 +36,34 @@ extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> J
} }
} }
extern fn getElementsByTagName(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
unsafe {
let obj = JS_THIS_OBJECT(cx, vp);
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;
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;
}
}
unsafe fn unwrap(obj: *JSObject) -> *mut rust_box<Document> { unsafe fn unwrap(obj: *JSObject) -> *mut rust_box<Document> {
//TODO: some kind of check if this is a Document object //TODO: some kind of check if this is a Document object
let val = JS_GetReservedSlot(obj, 0); let val = JS_GetReservedSlot(obj, 0);
@ -112,11 +99,26 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
fail_unless!(JS_DefineProperties(compartment.cx.ptr, obj.ptr, specs) == 1); 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)); compartment.register_class(utils::instance_jsclass(~"DocumentInstance", finalize));
let instance : jsobj = result::unwrap( let instance : jsobj = result::unwrap(
compartment.new_object_with_proto(~"DocumentInstance", ~"Document", compartment.new_object_with_proto(~"DocumentInstance", ~"Document",
compartment.global_obj.ptr)); compartment.global_obj.ptr));
doc.wrapper.set_wrapper(instance.ptr);
unsafe { unsafe {
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc)); 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, GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
JSPROP_ENUMERATE); 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");
}
}

View file

@ -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::{rust_box, squirrel_away_unique, get_compartment};
use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject}; 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};
use dom::bindings::utils;
use dom::bindings::clientrectlist::ClientRectListImpl; use dom::bindings::clientrectlist::ClientRectListImpl;
use dom::element::*; use dom::element::*;
use dom::node::{AbstractNode, Node, Element, ElementNodeTypeId}; 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}; use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
debug!("element finalize!"); debug!("element finalize: %?!", obj as uint);
unsafe { unsafe {
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32); let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val)); 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() { let width = match node.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => { ElementNodeTypeId(HTMLImageElementTypeId) => {
let content = task_from_context(cx); 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, Ok(rect) => rect.width,
Err(()) => 0 Err(()) => 0
} }

View file

@ -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")
}
}

View file

@ -13,9 +13,10 @@ use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_Repor
JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject, JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject,
JS_GetInternedStringCharsAndLength, JS_DefineProperties, JS_GetInternedStringCharsAndLength, JS_DefineProperties,
JS_WrapValue, JS_GetObjectPrototype, JS_ForwardGetPropertyTo, 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::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, use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
RESOLVE_STUB}; RESOLVE_STUB};
use js::glue::bindgen::*; use js::glue::bindgen::*;
@ -25,6 +26,9 @@ use content::content_task::{Content, task_from_context};
use core::hashmap::linear; use core::hashmap::linear;
use dom::bindings::node;
use dom::node::AbstractNode;
const TOSTRING_CLASS_RESERVED_SLOT: u64 = 0; const TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
const TOSTRING_NAME_RESERVED_SLOT: u64 = 1; 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 { unsafe {
let buf = vec::raw::from_buf_raw(chars as *u8, len as uint); let strbuf = JS_EncodeString(cx, jsstr);
Ok(str::from_bytes(buf)) 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 { pub struct DOMClass {
// A list of interfaces that this object implements, in order of decreasing // A list of interfaces that this object implements, in order of decreasing
// derivedness. // 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) unused: bool, // DOMObjectIsISupports (always false)
native_hooks: *NativePropertyHooks native_hooks: *NativePropertyHooks
@ -353,6 +353,7 @@ pub mod prototypes {
pub enum Prototype { pub enum Prototype {
ClientRect, ClientRect,
ClientRectList, ClientRectList,
HTMLCollection,
_ID_Count _ID_Count
} }
} }
@ -540,7 +541,7 @@ pub extern fn ThrowingConstructor(cx: *JSContext, argc: uint, vp: *JSVal) -> JSB
} }
pub fn initialize_global(global: *JSObject) { 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 { unsafe {
//XXXjdm we should be storing the box pointer instead of the inner //XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray); let box = squirrel_away(protoArray);
@ -778,3 +779,26 @@ pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &mut [jsid]) -> bo
} }
rval rval
} }
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>;

View file

@ -1,3 +1,5 @@
use dom::bindings::htmlcollection::HTMLCollection;
use dom::bindings::utils::{DOMString, WrapperCache, str};
use dom::node::AbstractNode; use dom::node::AbstractNode;
use newcss::stylesheet::Stylesheet; use newcss::stylesheet::Stylesheet;
@ -5,10 +7,32 @@ use std::arc::ARC;
pub struct Document { pub struct Document {
root: AbstractNode, root: AbstractNode,
wrapper: WrapperCache
} }
pub fn Document(root: AbstractNode) -> Document { pub fn Document(root: AbstractNode) -> Document {
Document { Document {
root: root, 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))
} }
} }

View file

@ -390,4 +390,7 @@ pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @
fail_unless!(codegen::ClientRectListBinding::DefineDOMInterface(compartment.cx.ptr, fail_unless!(codegen::ClientRectListBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr, compartment.global_obj.ptr,
&mut unused)); &mut unused));
fail_unless!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
} }

View file

@ -49,9 +49,11 @@ pub mod dom {
pub mod proxyhandler; pub mod proxyhandler;
pub mod clientrect; pub mod clientrect;
pub mod clientrectlist; pub mod clientrectlist;
pub mod htmlcollection;
pub mod codegen { pub mod codegen {
pub mod ClientRectBinding; pub mod ClientRectBinding;
pub mod ClientRectListBinding; pub mod ClientRectListBinding;
pub mod HTMLCollectionBinding;
} }
} }
pub mod document; pub mod document;

View file

@ -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>

View file

@ -23,3 +23,12 @@ window.alert(rect.right);
window.alert(rect.width); window.alert(rect.width);
window.alert(rect.height); 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]);