diff options
author | Josh Matthews <josh@joshmatthews.net> | 2013-04-01 15:14:31 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2013-04-23 23:56:40 +0200 |
commit | 886eb35dfde369cbba6b98e210a5b09c045990ec (patch) | |
tree | b5234bf0adbca39f5fdc29dffbce648398727dd8 | |
parent | de7e26d17360df46c372eee2c7326a45177875a7 (diff) | |
download | servo-886eb35dfde369cbba6b98e210a5b09c045990ec.tar.gz servo-886eb35dfde369cbba6b98e210a5b09c045990ec.zip |
Generate DOMParser bindings.
m--------- | src/rust-mozjs | 0 | ||||
-rw-r--r-- | src/servo/dom/bindings/clientrect.rs | 37 | ||||
-rw-r--r-- | src/servo/dom/bindings/clientrectlist.rs | 28 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/Bindings.conf | 19 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/CodegenRust.py | 139 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/DOMParser.webidl | 48 | ||||
-rw-r--r-- | src/servo/dom/bindings/codegen/RegisterBindings.cpp | 2 | ||||
-rw-r--r-- | src/servo/dom/bindings/document.rs | 28 | ||||
-rw-r--r-- | src/servo/dom/bindings/domparser.rs | 44 | ||||
-rw-r--r-- | src/servo/dom/bindings/element.rs | 5 | ||||
-rw-r--r-- | src/servo/dom/bindings/htmlcollection.rs | 16 | ||||
-rw-r--r-- | src/servo/dom/bindings/node.rs | 2 | ||||
-rw-r--r-- | src/servo/dom/bindings/utils.rs | 139 | ||||
-rw-r--r-- | src/servo/dom/bindings/window.rs | 2 | ||||
-rw-r--r-- | src/servo/dom/document.rs | 4 | ||||
-rw-r--r-- | src/servo/dom/domparser.rs | 30 | ||||
-rw-r--r-- | src/servo/dom/element.rs | 4 | ||||
-rw-r--r-- | src/servo/dom/node.rs | 3 | ||||
-rwxr-xr-x | src/servo/servo.rc | 3 | ||||
-rw-r--r-- | src/test/test_bindings.js | 6 |
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 |