aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2013-04-01 15:14:31 -0400
committerJosh Matthews <josh@joshmatthews.net>2013-04-23 23:56:40 +0200
commit886eb35dfde369cbba6b98e210a5b09c045990ec (patch)
treeb5234bf0adbca39f5fdc29dffbce648398727dd8
parentde7e26d17360df46c372eee2c7326a45177875a7 (diff)
downloadservo-886eb35dfde369cbba6b98e210a5b09c045990ec.tar.gz
servo-886eb35dfde369cbba6b98e210a5b09c045990ec.zip
Generate DOMParser bindings.
m---------src/rust-mozjs0
-rw-r--r--src/servo/dom/bindings/clientrect.rs37
-rw-r--r--src/servo/dom/bindings/clientrectlist.rs28
-rw-r--r--src/servo/dom/bindings/codegen/Bindings.conf19
-rw-r--r--src/servo/dom/bindings/codegen/CodegenRust.py139
-rw-r--r--src/servo/dom/bindings/codegen/DOMParser.webidl48
-rw-r--r--src/servo/dom/bindings/codegen/RegisterBindings.cpp2
-rw-r--r--src/servo/dom/bindings/document.rs28
-rw-r--r--src/servo/dom/bindings/domparser.rs44
-rw-r--r--src/servo/dom/bindings/element.rs5
-rw-r--r--src/servo/dom/bindings/htmlcollection.rs16
-rw-r--r--src/servo/dom/bindings/node.rs2
-rw-r--r--src/servo/dom/bindings/utils.rs139
-rw-r--r--src/servo/dom/bindings/window.rs2
-rw-r--r--src/servo/dom/document.rs4
-rw-r--r--src/servo/dom/domparser.rs30
-rw-r--r--src/servo/dom/element.rs4
-rw-r--r--src/servo/dom/node.rs3
-rwxr-xr-xsrc/servo/servo.rc3
-rw-r--r--src/test/test_bindings.js6
20 files changed, 416 insertions, 143 deletions
diff --git a/src/rust-mozjs b/src/rust-mozjs
-Subproject aefcf146400a42e7302243db2844f4022f938fc
+Subproject fe2f31f7f33150615e0cc5385cf869053e64a65
diff --git a/src/servo/dom/bindings/clientrect.rs b/src/servo/dom/bindings/clientrect.rs
index 90e81f03e9b..5746733a53e 100644
--- a/src/servo/dom/bindings/clientrect.rs
+++ b/src/servo/dom/bindings/clientrect.rs
@@ -3,9 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use content::content_task::task_from_context;
-use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, OpaqueBindingReference};
+use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::bindings::codegen::ClientRectBinding;
-use js::jsapi::{JSObject, JSContext};
+use js::jsapi::{JSObject, JSContext, JSVal};
+use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
pub trait ClientRect {
fn Top(&self) -> f32;
@@ -62,19 +63,35 @@ impl CacheableWrapper for ClientRectImpl {
unsafe { cast::transmute(&self.wrapper) }
}
- fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
- let mut unused = false;
- ClientRectBinding::Wrap(cx, scope, self, &mut unused)
+ fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
+ fail!(~"nyi")
}
- fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
- fail!(~"nyi")
+ fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
+ let mut unused = false;
+ ClientRectBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for ClientRectImpl {
- fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
+ fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
- unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
+ unsafe { (*content).window.get() as @mut CacheableWrapper }
}
-} \ No newline at end of file
+}
+
+impl DerivedWrapper for ClientRectImpl {
+ fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
+ fail!(~"nyi")
+ }
+
+ fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
+ let obj = self.wrap_object_shared(cx, scope);
+ if obj.is_null() {
+ return 0;
+ } else {
+ unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
+ return 1;
+ }
+ }
+}
diff --git a/src/servo/dom/bindings/clientrectlist.rs b/src/servo/dom/bindings/clientrectlist.rs
index f4660b5ae44..86d6c0fc788 100644
--- a/src/servo/dom/bindings/clientrectlist.rs
+++ b/src/servo/dom/bindings/clientrectlist.rs
@@ -5,13 +5,13 @@
use content::content_task::task_from_context;
use dom::bindings::clientrect::{ClientRect, ClientRectImpl};
use dom::bindings::codegen::ClientRectListBinding;
-use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject, OpaqueBindingReference};
+use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
use js::jsapi::{JSObject, JSContext};
pub trait ClientRectList {
fn Length(&self) -> u32;
- fn Item(&self, index: u32) -> Option<~ClientRectImpl>;
- fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~ClientRectImpl>;
+ fn Item(&self, index: u32) -> Option<@mut ClientRectImpl>;
+ fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl>;
}
pub struct ClientRectListImpl {
@@ -24,16 +24,16 @@ impl ClientRectList for ClientRectListImpl {
self.rects.len() as u32
}
- fn Item(&self, index: u32) -> Option<~ClientRectImpl> {
+ fn Item(&self, index: u32) -> Option<@mut ClientRectImpl> {
if index < self.rects.len() as u32 {
let (top, bottom, left, right) = self.rects[index];
- Some(~ClientRect(top, bottom, left, right))
+ Some(@mut ClientRect(top, bottom, left, right))
} else {
None
}
}
- fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~ClientRectImpl> {
+ fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl> {
*found = index < self.rects.len() as u32;
self.Item(index)
}
@@ -53,19 +53,19 @@ impl CacheableWrapper for ClientRectListImpl {
unsafe { cast::transmute(&self.wrapper) }
}
- fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
- let mut unused = false;
- ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
+ fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
+ fail!(~"nyi")
}
- fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
- fail!(~"nyi")
+ fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
+ let mut unused = false;
+ ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for ClientRectListImpl {
- fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
+ fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
- unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
+ unsafe { (*content).window.get() as @mut CacheableWrapper }
}
-} \ No newline at end of file
+}
diff --git a/src/servo/dom/bindings/codegen/Bindings.conf b/src/servo/dom/bindings/codegen/Bindings.conf
index 8bfc300ca49..bc5a19cf172 100644
--- a/src/servo/dom/bindings/codegen/Bindings.conf
+++ b/src/servo/dom/bindings/codegen/Bindings.conf
@@ -116,14 +116,13 @@ DOMInterfaces = {
'ClientRect': [
{
'nativeType': 'ClientRectImpl',
+ 'pointerType': '@mut '
}],
'ClientRectList': [
{
'nativeType': 'ClientRectListImpl',
- #'headerFile': 'nsClientRect.h',
- #'prefable': True,
- #'resultNotAddRefed': [ 'item' ]
+ 'pointerType': '@mut '
}],
'CSS2Properties': {
@@ -136,13 +135,10 @@ DOMInterfaces = {
'prefable': True
},
-'Document': [
-{
- 'nativeType': 'nsIDocument',
+'DOMParser': {
+ 'nativeType': 'DOMParser',
+ 'pointerType': '@mut '
},
-{
- 'workers': True,
-}],
'DOMSettableTokenList': [
{
@@ -213,8 +209,7 @@ DOMInterfaces = {
'HTMLCollection': [
{
'nativeType': 'HTMLCollection',
- #'prefable': True,
- #'resultNotAddRefed': [ 'item' ]
+ 'pointerType': '@mut '
}],
'HTMLOptionsCollection': [
@@ -516,9 +511,9 @@ addExternalHTMLElement('HTMLOptGroupElement')
addExternalHTMLElement('HTMLVideoElement')
addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
-#addExternalIface('ClientRect')
addExternalIface('CSSRule')
addExternalIface('CSSValue')
+addExternalIface('Document', nativeType='Document', pointerType='@mut ')
addExternalIface('DOMStringList', nativeType='nsDOMStringList',
headerFile='nsDOMLists.h')
addExternalIface('Element', nativeType='AbstractNode', pointerType='')
diff --git a/src/servo/dom/bindings/codegen/CodegenRust.py b/src/servo/dom/bindings/codegen/CodegenRust.py
index 71c22234ec5..50dd7f6aa24 100644
--- a/src/servo/dom/bindings/codegen/CodegenRust.py
+++ b/src/servo/dom/bindings/codegen/CodegenRust.py
@@ -1098,22 +1098,19 @@ for (uint32_t i = 0; i < length; ++i) {
"yet")
enum = type.inner.identifier.name
if invalidEnumValueFatal:
- handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
+ handleInvalidEnumValueCode = " return 0;\n"
else:
- handleInvalidEnumValueCode = (
- " if (index < 0) {\n"
- " return true;\n"
- " }\n")
+ handleInvalidEnumValueCode = " return 1;\n"
template = (
"{\n"
- " bool ok;\n"
- " int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
- " if (!ok) {\n"
- " return false;\n"
- " }\n"
+ #" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
+ " let result = FindEnumStringIndex(cx, ${val}, %(values)s);\n"
+ " if result.is_err() {\n"
"%(handleInvalidEnumValueCode)s"
- " ${declName} = static_cast<%(enumtype)s>(index);\n"
+ " }\n"
+ " let index = result.get();\n"
+ " ${declName} = cast::transmute(index); //XXXjdm need some range checks up in here\n"
"}" % { "enumtype" : enum,
"values" : enum + "Values::strings",
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
@@ -1529,7 +1526,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, ${jsvalPtr})" % (wrapMethod, result)
+ wrap = "%s(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr})" % (wrapMethod, result)
# We don't support prefable stuff in workers.
assert(not descriptor.prefable or not descriptor.workers)
if not descriptor.prefable:
@@ -1547,12 +1544,11 @@ for (uint32_t i = 0; i < length; ++i) {
failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
wrappingCode += wrapAndSetPtr(wrap, failed)
else:
- if descriptor.notflattened:
- getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
- else:
- getIID = ""
#wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
- wrap = "%s.wrap(cx, ${obj}, %s${jsvalPtr})" % (result, getIID)
+ if descriptor.pointerType == '':
+ wrap = "%s.wrap(cx, ${obj}, ${jsvalPtr})" % result
+ else:
+ wrap = "if WrapNewBindingObject(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr}) { 1 } else { 0 };" % result
wrappingCode += wrapAndSetPtr(wrap)
return (wrappingCode, False)
@@ -1701,10 +1697,10 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
descriptor = descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name)
result = CGGeneric(descriptor.nativeType)
- if resultAlreadyAddRefed:
+ if returnType.nullable():
result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
else:
- result = CGWrapper(result, post="*")
+ result = CGWrapper(result, pre=descriptor.pointerType)
return result, False
if returnType.isCallback():
# XXXbz we're going to assume that callback types are always
@@ -2154,20 +2150,23 @@ class CGIfWrapper(CGWrapper):
post="\n}")
class CGNamespace(CGWrapper):
- def __init__(self, namespace, child, declareOnly=False):
- pre = "mod %s {\n" % namespace
+ def __init__(self, namespace, child, declareOnly=False, public=False):
+ pre = "%smod %s {\n" % ("pub " if public else "", namespace)
post = "} // mod %s\n" % namespace
CGWrapper.__init__(self, child, pre=pre, post=post,
declareOnly=declareOnly)
@staticmethod
- def build(namespaces, child, declareOnly=False):
+ def build(namespaces, child, declareOnly=False, public=False):
"""
Static helper method to build multiple wrapped namespaces.
"""
if not namespaces:
return CGWrapper(child, declareOnly=declareOnly)
- inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
- return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
+ inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly, public=public)
+ return CGNamespace(namespaces[0], inner, declareOnly=declareOnly, public=public)
+
+ def declare(self):
+ return ""
def DOMClass(descriptor):
protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
@@ -2474,7 +2473,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
return """ *aTriedToWrap = true;
let mut parent = aObject.GetParentObject(aCx);
- let parent = WrapNativeParent(aCx, aScope, &mut parent);
+ let parent = WrapNativeParent(aCx, aScope, parent);
if parent.is_null() {
return ptr::null();
}
@@ -2502,11 +2501,11 @@ class CGWrapMethod(CGAbstractMethod):
# XXX can we wrap if we don't have an interface prototype object?
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
- Argument('~' + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
+ Argument(descriptor.pointerType + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, pub=True)
def definition_body(self):
- return " let mut binding = BindingReference(Left(aObject)); \
+ return " let mut binding = BindingReference(Right(aObject)); \
return Wrap_(aCx, aScope, &mut binding, aTriedToWrap);"
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
@@ -3289,6 +3288,46 @@ class CGMemberJITInfo(CGThing):
return result
raise TypeError("Illegal member type to CGPropertyJITInfo")
+def getEnumValueName(value):
+ # Some enum values can be empty strings. Others might have weird
+ # characters in them. Deal with the former by returning "_empty",
+ # deal with possible name collisions from that by throwing if the
+ # enum value is actually "_empty", and throw on any value
+ # containing non-ASCII chars for now. Replace all chars other than
+ # [0-9A-Za-z_] with '_'.
+ if re.match("[^\x20-\x7E]", value):
+ raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
+ if re.match("^[0-9]", value):
+ raise SyntaxError('Enum value "' + value + '" starts with a digit')
+ value = re.sub(r'[^0-9A-Za-z_]', '_', value)
+ if re.match("^_[A-Z]|__", value):
+ raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
+ if value == "_empty":
+ raise SyntaxError('"_empty" is not an IDL enum value we support yet')
+ if value == "":
+ return "_empty"
+ return MakeNativeName(value)
+
+class CGEnum(CGThing):
+ def __init__(self, enum):
+ CGThing.__init__(self)
+ self.enum = enum
+
+ def declare(self):
+ return ""
+
+ def define(self):
+ return """
+ pub enum valuelist {
+ %s
+ }
+
+ pub static strings: &'static [EnumEntry] = &[
+ %s,
+ ];
+""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
+ ",\n ".join(['EnumEntry {value: &"' + val + '", length: ' + str(len(val)) + '}' for val in self.enum.values()]))
+
class CGXrayHelper(CGAbstractExternMethod):
def __init__(self, descriptor, name, args, properties):
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -3574,42 +3613,38 @@ let _: %s = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
#return clearWrapper + release
return release
-class CGClassConstructHook(CGAbstractStaticMethod):
+class CGClassConstructHook(CGAbstractExternMethod):
"""
JS-visible constructor for our objects
"""
def __init__(self, descriptor):
- args = [Argument('*JSContext', 'cx'), Argument('unsigned', 'argc'), Argument('*jsval', 'vp')]
- CGAbstractStaticMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
+ args = [Argument('*JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
+ CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
'JSBool', args)
self._ctor = self.descriptor.interface.ctor()
def define(self):
if not self._ctor:
return ""
- return CGAbstractStaticMethod.define(self)
+ return CGAbstractExternMethod.define(self)
def definition_body(self):
return self.generate_code()
def generate_code(self):
preamble = """
- JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
+ //JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
"""
if self.descriptor.workers:
preArgs = ["cx", "obj"]
else:
preamble += """
- nsISupports* global;
- xpc_qsSelfRef globalRef;
- {
- nsresult rv;
- JS::Value val = OBJECT_TO_JSVAL(obj);
- rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr, &val);
- if (NS_FAILED(rv)) {
- return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
- }
- }
+ //XXXjdm Gecko obtains a GlobalObject from the global (maybe from the private value,
+ // or through unwrapping a slot or something). We'll punt and get the Window
+ // from the context for now.
+ let content = task_from_context(cx);
+ let global = (*content).window.get();
+ let obj = global.get_wrappercache().get_wrapper();
"""
preArgs = ["global"]
@@ -3835,6 +3870,17 @@ class CGBindingRoot(CGThing):
cgthings = []
+ # Do codegen for all the enums
+ def makeEnum(e):
+ return CGNamespace.build([e.identifier.name + "Values"],
+ CGList([CGGeneric(" use dom::bindings::utils::EnumEntry;"),
+ CGEnum(e)]), public=True)
+ def makeEnumTypedef(e):
+ return CGGeneric(declare=("pub type %s = self::%sValues::valuelist;\n" %
+ (e.identifier.name, e.identifier.name)))
+ cgthings = [ fun(e) for e in config.getEnums(webIDLFile)
+ for fun in [makeEnum, makeEnumTypedef] ]
+
# Do codegen for all the descriptors
cgthings.extend([CGDescriptor(x) for x in descriptors])
@@ -3846,6 +3892,8 @@ class CGBindingRoot(CGThing):
# CGWrapper(curr, pre="\n"))
# Add imports
+ #XXXjdm This should only import the namespace for the current binding,
+ # not every binding ever.
curr = CGImports(descriptors,
dictionaries,
['js::*',
@@ -3854,14 +3902,17 @@ class CGBindingRoot(CGThing):
'js::jsfriendapi::bindgen::*',
'js::glue::bindgen::*',
'js::glue::*',
- 'dom::node::AbstractNode',
+ 'dom::node::AbstractNode', #XXXjdm
+ 'dom::document::Document', #XXXjdm
'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'
+ 'dom::domparser::*', #XXXjdm
+ 'content::content_task::task_from_context',
+ 'dom::bindings::utils::EnumEntry',
],
[],
curr)
diff --git a/src/servo/dom/bindings/codegen/DOMParser.webidl b/src/servo/dom/bindings/codegen/DOMParser.webidl
new file mode 100644
index 00000000000..435cd8dda92
--- /dev/null
+++ b/src/servo/dom/bindings/codegen/DOMParser.webidl
@@ -0,0 +1,48 @@
+/* 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://domparsing.spec.whatwg.org/#the-domparser-interface
+ */
+
+/*interface Principal;
+interface URI;
+interface InputStream;*/
+interface Document;
+
+enum SupportedType {
+ "text/html",
+ "text/xml",
+ "application/xml",
+ "application/xhtml+xml",
+ "image/svg+xml"
+};
+
+// the latter is Mozilla-specific
+/*[Constructor,
+ Constructor(Principal? prin, optional URI? documentURI = null,
+ optional URI? baseURI = null)]*/
+[Constructor]
+interface DOMParser {
+ [Creator, Throws]
+ Document parseFromString(DOMString str, SupportedType type);
+
+ /* // Mozilla-specific stuff
+ // Throws if the passed-in length is greater than the actual sequence length
+ [Creator, Throws, ChromeOnly]
+ Document parseFromBuffer(sequence<octet> buf, unsigned long bufLen,
+ SupportedType type);
+ // Throws if the passed-in length is greater than the actual typed array length
+ [Creator, Throws, ChromeOnly]
+ Document parseFromBuffer(Uint8Array buf, unsigned long bufLen,
+ SupportedType type);
+ [Creator, Throws, ChromeOnly]
+ Document parseFromStream(InputStream stream, DOMString? charset,
+ long contentLength, SupportedType type);
+ [Throws, ChromeOnly]
+ void init(optional Principal? principal = null,
+ optional URI? documentURI = null,
+ optional URI? baseURI = null);*/
+};
+
diff --git a/src/servo/dom/bindings/codegen/RegisterBindings.cpp b/src/servo/dom/bindings/codegen/RegisterBindings.cpp
index 0cc45d1ddc4..c1fb6c3350b 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 "DOMParserBinding.h"
#include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h"
@@ -14,6 +15,7 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr);
+REGISTER_PROTO(DOMParser, 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 17f35735f52..5c55b960f80 100644
--- a/src/servo/dom/bindings/document.rs
+++ b/src/servo/dom/bindings/document.rs
@@ -14,6 +14,7 @@ use js::glue::bindgen::*;
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB};
use core::ptr::null;
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;
@@ -50,15 +51,16 @@ extern fn getElementsByTagName(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSB
arg0 = str(strval.get());
let doc = &mut (*unwrap(obj)).payload;
- let rval: Option<~HTMLCollection>;
+ let rval: Option<@mut HTMLCollection>;
rval = doc.getElementsByTagName(arg0);
if rval.is_none() {
JS_SET_RVAL(cx, vp, JSVAL_NULL);
} else {
let cache = doc.get_wrappercache();
+ let rval = rval.get() as @mut CacheableWrapper;
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
- rval.get(),
- cast::transmute(vp)));
+ rval,
+ cast::transmute(vp)));
}
return 1;
}
@@ -115,6 +117,15 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
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);
+}
+
+pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject {
let instance : jsobj = result::unwrap(
compartment.new_object_with_proto(~"DocumentInstance", ~"Document",
compartment.global_obj.ptr));
@@ -124,11 +135,7 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
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
}
impl CacheableWrapper for Document {
@@ -140,7 +147,8 @@ impl CacheableWrapper for Document {
fail!(~"need to implement wrapping");
}
- fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
- fail!(~"need to implement wrapping");
+ fn wrap_object_shared(@mut self, cx: *JSContext, _scope: *JSObject) -> *JSObject {
+ let content = task_from_context(cx);
+ unsafe { create((*content).compartment.get(), self) }
}
}
diff --git a/src/servo/dom/bindings/domparser.rs b/src/servo/dom/bindings/domparser.rs
new file mode 100644
index 00000000000..61c80044871
--- /dev/null
+++ b/src/servo/dom/bindings/domparser.rs
@@ -0,0 +1,44 @@
+use dom::bindings::codegen::DOMParserBinding;
+use dom::bindings::utils::{CacheableWrapper, WrapperCache};
+use dom::bindings::utils::{BindingObject, DerivedWrapper};
+use dom::domparser::DOMParser;
+
+use js::jsapi::{JSContext, JSObject, JSVal};
+use js::glue::bindgen::{RUST_OBJECT_TO_JSVAL};
+
+impl CacheableWrapper for DOMParser {
+ 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(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
+ let mut unused = false;
+ DOMParserBinding::Wrap(cx, scope, self, &mut unused)
+ }
+}
+
+impl BindingObject for DOMParser {
+ fn GetParentObject(&self, _cx: *JSContext) -> @mut CacheableWrapper {
+ return self.owner as @mut CacheableWrapper;
+ }
+}
+
+impl DerivedWrapper for DOMParser {
+ fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
+ fail!(~"nyi")
+ }
+
+ fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
+ let obj = self.wrap_object_shared(cx, scope);
+ if obj.is_null() {
+ return 0;
+ } else {
+ unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
+ return 1;
+ }
+ }
+}
diff --git a/src/servo/dom/bindings/element.rs b/src/servo/dom/bindings/element.rs
index 9270375030d..cfb02df48b4 100644
--- a/src/servo/dom/bindings/element.rs
+++ b/src/servo/dom/bindings/element.rs
@@ -102,9 +102,10 @@ extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
JS_SET_RVAL(cx, vp, JSVAL_NULL);
} else {
let cache = node.get_wrappercache();
+ let rval = rval.get() as @mut CacheableWrapper;
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
- rval.get(),
- cast::transmute(vp)));
+ rval,
+ cast::transmute(vp)));
}
return 1;
}
diff --git a/src/servo/dom/bindings/htmlcollection.rs b/src/servo/dom/bindings/htmlcollection.rs
index c8d110c8c1b..d09057cc9a3 100644
--- a/src/servo/dom/bindings/htmlcollection.rs
+++ b/src/servo/dom/bindings/htmlcollection.rs
@@ -5,7 +5,7 @@
use content::content_task::task_from_context;
use dom::node::AbstractNode;
use dom::bindings::codegen::HTMLCollectionBinding;
-use dom::bindings::utils::{DOMString, ErrorResult, OpaqueBindingReference};
+use dom::bindings::utils::{DOMString, ErrorResult};
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
use js::jsapi::{JSObject, JSContext};
@@ -46,9 +46,9 @@ pub impl HTMLCollection {
}
impl BindingObject for HTMLCollection {
- fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
+ fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
- unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
+ unsafe { (*content).window.get() as @mut CacheableWrapper }
}
}
@@ -57,12 +57,12 @@ impl CacheableWrapper for HTMLCollection {
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_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
+ fail!(~"nyi")
}
- fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
- fail!(~"nyi")
+ fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
+ let mut unused = false;
+ HTMLCollectionBinding::Wrap(cx, scope, self, &mut unused)
}
}
diff --git a/src/servo/dom/bindings/node.rs b/src/servo/dom/bindings/node.rs
index 90d70e72445..d9fc8225012 100644
--- a/src/servo/dom/bindings/node.rs
+++ b/src/servo/dom/bindings/node.rs
@@ -175,7 +175,7 @@ impl CacheableWrapper for AbstractNode {
fail!(~"need to implement wrapping");
}
- fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
+ fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"need to implement wrapping");
}
}
diff --git a/src/servo/dom/bindings/utils.rs b/src/servo/dom/bindings/utils.rs
index c2cbd671483..47dafe5e6db 100644
--- a/src/servo/dom/bindings/utils.rs
+++ b/src/servo/dom/bindings/utils.rs
@@ -18,7 +18,7 @@ use js::jsapi::bindgen::{JS_ValueToString,
JS_DefineProperties,
JS_WrapValue, JS_ForwardGetPropertyTo,
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject,
- JS_EncodeString, JS_free};
+ JS_EncodeString, JS_free, JS_GetStringCharsAndLength};
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
@@ -30,7 +30,9 @@ 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;
@@ -356,6 +358,7 @@ pub mod prototypes {
pub enum Prototype {
ClientRect,
ClientRectList,
+ DOMParser,
HTMLCollection,
_ID_Count
}
@@ -540,7 +543,7 @@ pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) ->
}
pub fn initialize_global(global: *JSObject) {
- let protoArray = @mut ([0 as *JSObject, ..3]); //XXXjdm prototypes::_ID_COUNT
+ let protoArray = @mut ([0 as *JSObject, ..4]); //XXXjdm prototypes::_ID_COUNT
unsafe {
//XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray);
@@ -554,7 +557,7 @@ pub fn initialize_global(global: *JSObject) {
pub trait CacheableWrapper {
fn get_wrappercache(&mut self) -> &mut WrapperCache;
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject;
- fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject;
+ fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject;
}
pub struct WrapperCache {
@@ -577,64 +580,48 @@ pub impl WrapperCache {
}
}
-pub fn WrapNewBindingObject<T: CacheableWrapper>(cx: *JSContext, scope: *JSObject,
- mut value: ~T, vp: *mut JSVal) -> bool {
+pub fn WrapNewBindingObject(cx: *JSContext, scope: *JSObject,
+ mut value: @mut CacheableWrapper,
+ vp: *mut JSVal) -> bool {
unsafe {
- let obj = value.get_wrappercache().get_wrapper();
+ let mut cache = value.get_wrappercache();
+ let mut obj = cache.get_wrapper();
if obj.is_not_null() /*&& js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)*/ {
*vp = RUST_OBJECT_TO_JSVAL(obj);
return true;
}
- let obj = if obj.is_not_null() {
- obj
- } else {
- value.wrap_object_unique(cx, scope)
- };
-
+ let obj = value.wrap_object_shared(cx, scope);
if obj.is_null() {
return false;
}
// MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
+ cache.set_wrapper(obj);
*vp = RUST_OBJECT_TO_JSVAL(obj);
return JS_WrapValue(cx, cast::transmute(vp)) != 0;
}
}
-pub struct OpaqueBindingReference(Either<~CacheableWrapper, @CacheableWrapper>);
-
-pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, p: &mut OpaqueBindingReference) -> *JSObject {
- match p {
- &OpaqueBindingReference(Left(ref mut p)) => {
- let cache = p.get_wrappercache();
- let obj = cache.get_wrapper();
- if obj.is_not_null() {
- return obj;
- }
- let mut tmp: ~CacheableWrapper = unstable::intrinsics::init();
- tmp <-> *p;
- tmp.wrap_object_unique(cx, scope)
- }
- &OpaqueBindingReference(Right(ref mut p)) => {
- let cache = p.get_wrappercache();
- let obj = cache.get_wrapper();
- if obj.is_not_null() {
- return obj;
- }
- p.wrap_object_shared(cx, scope)
- }
+pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, mut p: @mut CacheableWrapper) -> *JSObject {
+ let cache = p.get_wrappercache();
+ let wrapper = cache.get_wrapper();
+ if wrapper.is_not_null() {
+ return wrapper;
}
+ let wrapper = p.wrap_object_shared(cx, scope);
+ cache.set_wrapper(wrapper);
+ wrapper
}
pub struct BindingReference<T>(Either<~T, @mut T>);
pub trait BindingObject {
- fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference;
+ fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper;
}
pub impl<T: BindingObject + CacheableWrapper> BindingReference<T> {
- fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
+ fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
match **self {
Left(ref obj) => obj.GetParentObject(cx),
Right(ref obj) => obj.GetParentObject(cx)
@@ -781,6 +768,7 @@ pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &mut [jsid]) -> bo
pub trait DerivedWrapper {
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32;
+ fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32;
}
impl DerivedWrapper for AbstractNode {
@@ -794,10 +782,87 @@ impl DerivedWrapper for AbstractNode {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, self).ptr) };
return 1;
}
+
+ fn wrap_shared(@mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
+ fail!(~"nyi")
+ }
+}
+
+/*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
}
-pub type ErrorResult = Result<(), Error>; \ No newline at end of file
+pub type ErrorResult = Result<(), Error>;
+
+pub struct EnumEntry {
+ value: &'static str,
+ length: uint
+}
+
+pub fn FindEnumStringIndex(cx: *JSContext,
+ v: JSVal,
+ values: &[EnumEntry]) -> Result<uint, ()> {
+ unsafe {
+ let jsstr = JS_ValueToString(cx, v);
+ if jsstr.is_null() {
+ return Err(());
+ }
+ let length = 0;
+ let chars = JS_GetStringCharsAndLength(cx, jsstr, ptr::to_unsafe_ptr(&length));
+ if chars.is_null() {
+ return Err(());
+ }
+ for values.eachi |i, value| {
+ if value.length != length as uint {
+ loop;
+ }
+ let mut equal = true;
+ for uint::iterate(0, length as uint) |j| {
+ if value.value[j] as u16 != *chars.offset(j) {
+ equal = false;
+ break;
+ }
+ };
+
+ if equal {
+ return Ok(i);
+ }
+ }
+
+ return Err(()); //XXX pass in behaviour for value not found
+ }
+}
diff --git a/src/servo/dom/bindings/window.rs b/src/servo/dom/bindings/window.rs
index e764674a4c9..da24c5e3757 100644
--- a/src/servo/dom/bindings/window.rs
+++ b/src/servo/dom/bindings/window.rs
@@ -141,7 +141,7 @@ impl CacheableWrapper for Window {
fail!(~"should this be called?");
}
- fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
+ fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"should this be called?");
}
}
diff --git a/src/servo/dom/document.rs b/src/servo/dom/document.rs
index 16a178be051..1085a6120b4 100644
--- a/src/servo/dom/document.rs
+++ b/src/servo/dom/document.rs
@@ -20,7 +20,7 @@ pub fn Document(root: AbstractNode) -> Document {
}
pub impl Document {
- fn getElementsByTagName(&self, tag: DOMString) -> Option<~HTMLCollection> {
+ fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> {
let mut elements = ~[];
let tag = match tag {
str(s) => s,
@@ -35,6 +35,6 @@ pub impl Document {
}
}
};
- Some(~HTMLCollection::new(elements))
+ Some(@mut HTMLCollection::new(elements))
}
} \ No newline at end of file
diff --git a/src/servo/dom/domparser.rs b/src/servo/dom/domparser.rs
new file mode 100644
index 00000000000..e10e37e5ff4
--- /dev/null
+++ b/src/servo/dom/domparser.rs
@@ -0,0 +1,30 @@
+use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
+use dom::bindings::codegen::DOMParserBinding;
+use dom::document::Document;
+use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
+use dom::node::Node;
+use dom::window::Window;
+
+pub struct DOMParser {
+ owner: @mut Window, //XXXjdm Document instead?
+ wrapper: WrapperCache
+}
+
+pub impl DOMParser {
+ fn new(owner: @mut Window) -> DOMParser {
+ DOMParser {
+ owner: owner,
+ wrapper: WrapperCache::new()
+ }
+ }
+
+ fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser {
+ @mut 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)
+ }
+} \ No newline at end of file
diff --git a/src/servo/dom/element.rs b/src/servo/dom/element.rs
index d366320a701..4c86d413f1c 100644
--- a/src/servo/dom/element.rs
+++ b/src/servo/dom/element.rs
@@ -144,8 +144,8 @@ pub impl<'self> Element {
self.attrs.push(Attr::new(name.to_str(), value_cell.take()));
}
- fn getClientRects(&self) -> Option<~ClientRectListImpl> {
- Some(~ClientRectListImpl::new())
+ fn getClientRects(&self) -> Option<@mut ClientRectListImpl> {
+ Some(@mut ClientRectListImpl::new())
}
}
diff --git a/src/servo/dom/node.rs b/src/servo/dom/node.rs
index f1903892e0a..d5e38bda35a 100644
--- a/src/servo/dom/node.rs
+++ b/src/servo/dom/node.rs
@@ -385,4 +385,7 @@ pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @
assert!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
+ assert!(codegen::DOMParserBinding::DefineDOMInterface(compartment.cx.ptr,
+ compartment.global_obj.ptr,
+ &mut unused));
}
diff --git a/src/servo/servo.rc b/src/servo/servo.rc
index 30db1ec3c81..b6c25bd881f 100755
--- a/src/servo/servo.rc
+++ b/src/servo/servo.rc
@@ -68,14 +68,17 @@ pub mod dom {
pub mod proxyhandler;
pub mod clientrect;
pub mod clientrectlist;
+ pub mod domparser;
pub mod htmlcollection;
pub mod codegen {
pub mod ClientRectBinding;
pub mod ClientRectListBinding;
+ pub mod DOMParserBinding;
pub mod HTMLCollectionBinding;
}
}
pub mod document;
+ pub mod domparser;
pub mod element;
pub mod event;
pub mod node;
diff --git a/src/test/test_bindings.js b/src/test/test_bindings.js
index 1f48599d08e..5f9409b36be 100644
--- a/src/test/test_bindings.js
+++ b/src/test/test_bindings.js
@@ -32,3 +32,9 @@ window.alert(tags[0]);
window.alert(tags[1]);
window.alert(tags[2]);
window.alert(tags[3]);
+
+window.alert("DOMParser:");
+window.alert(DOMParser);
+let parser = new DOMParser();
+window.alert(parser);
+window.alert(parser.parseFromString("<html></html>", "text/html")); \ No newline at end of file