aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2013-03-21 15:04:36 -0400
committerJosh Matthews <josh@joshmatthews.net>2013-03-21 15:05:04 -0400
commit6660ea02787ba82ad5921c7276da7335c3db759c (patch)
tree936faf97d71068ffcdb378df4ffa75bcae9b71c3
parent5f672775b21f6d39fa586f89c65a6449dc673690 (diff)
downloadservo-6660ea02787ba82ad5921c7276da7335c3db759c.tar.gz
servo-6660ea02787ba82ad5921c7276da7335c3db759c.zip
Add basic binding for HTMLCollection.
-rw-r--r--src/servo/dom/bindings/codegen/Bindings.conf12
-rw-r--r--src/servo/dom/bindings/codegen/CodegenRust.py60
-rw-r--r--src/servo/dom/bindings/codegen/Configuration.py2
-rw-r--r--src/servo/dom/bindings/codegen/HTMLCollection.webidl20
-rw-r--r--src/servo/dom/bindings/codegen/RegisterBindings.cpp2
-rw-r--r--src/servo/dom/bindings/document.rs104
-rw-r--r--src/servo/dom/bindings/element.rs6
-rw-r--r--src/servo/dom/bindings/htmlcollection.rs65
-rw-r--r--src/servo/dom/bindings/utils.rs52
-rw-r--r--src/servo/dom/document.rs24
-rw-r--r--src/servo/dom/node.rs3
-rwxr-xr-xsrc/servo/servo.rc2
-rw-r--r--src/test/test_bindings.html12
-rw-r--r--src/test/test_bindings.js9
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]);