diff options
Diffstat (limited to 'src/components/script/dom')
44 files changed, 1316 insertions, 1519 deletions
diff --git a/src/components/script/dom/attr.rs b/src/components/script/dom/attr.rs index 906e1b7f02c..8357665b63d 100644 --- a/src/components/script/dom/attr.rs +++ b/src/components/script/dom/attr.rs @@ -43,18 +43,18 @@ impl Attr { } } - pub fn new(window: &Window, local_name: DOMString, value: DOMString) -> JS<Attr> { + pub fn new(window: &JS<Window>, local_name: DOMString, value: DOMString) -> JS<Attr> { let name = local_name.clone(); Attr::new_helper(window, local_name, value, name, Null, None) } - pub fn new_ns(window: &Window, local_name: DOMString, value: DOMString, + pub fn new_ns(window: &JS<Window>, local_name: DOMString, value: DOMString, name: DOMString, namespace: Namespace, prefix: Option<DOMString>) -> JS<Attr> { Attr::new_helper(window, local_name, value, name, namespace, prefix) } - fn new_helper(window: &Window, local_name: DOMString, value: DOMString, + fn new_helper(window: &JS<Window>, local_name: DOMString, value: DOMString, name: DOMString, namespace: Namespace, prefix: Option<DOMString>) -> JS<Attr> { let attr = Attr::new_inherited(local_name, value, name, namespace, prefix); diff --git a/src/components/script/dom/attrlist.rs b/src/components/script/dom/attrlist.rs index 100f057fe8f..b172e976705 100644 --- a/src/components/script/dom/attrlist.rs +++ b/src/components/script/dom/attrlist.rs @@ -27,7 +27,7 @@ impl AttrList { pub fn new(window: &JS<Window>, elem: &JS<Element>) -> JS<AttrList> { reflect_dom_object(~AttrList::new_inherited(window.clone(), elem.clone()), - window.get(), AttrListBinding::Wrap) + window, AttrListBinding::Wrap) } pub fn Length(&self) -> u32 { diff --git a/src/components/script/dom/bindings/callback.rs b/src/components/script/dom/bindings/callback.rs index 10cb35c3af4..b965fcbfb72 100644 --- a/src/components/script/dom/bindings/callback.rs +++ b/src/components/script/dom/bindings/callback.rs @@ -3,9 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::utils::Reflectable; -use js::jsapi::{JSContext, JSObject, JS_WrapObject, JSVal, JS_ObjectIsCallable}; +use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable}; use js::jsapi::{JS_GetProperty, JSTracer, JS_CallTracer}; -use js::{JSVAL_IS_OBJECT, JSVAL_TO_OBJECT, JSTRACE_OBJECT}; +use js::jsval::JSVal; +use js::JSTRACE_OBJECT; use std::cast; use std::libc; @@ -66,8 +67,8 @@ impl CallbackInterface { return false; } - if !JSVAL_IS_OBJECT(*callable) || - JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(*callable)) == 0 { + if !callable.is_object() || + JS_ObjectIsCallable(cx, callable.to_object()) == 0 { //ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get()); return false; } diff --git a/src/components/script/dom/bindings/codegen/BindingGen.py b/src/components/script/dom/bindings/codegen/BindingGen.py index e292427e33b..408280dacfb 100644 --- a/src/components/script/dom/bindings/codegen/BindingGen.py +++ b/src/components/script/dom/bindings/codegen/BindingGen.py @@ -10,30 +10,6 @@ import cPickle import WebIDL from Configuration import * from CodegenRust import CGBindingRoot, replaceFileIfChanged -# import Codegen in general, so we can set a variable on it -import Codegen - -def generate_binding_header(config, outputprefix, webidlfile): - """ - |config| Is the configuration object. - |outputprefix| is a prefix to use for the header guards and filename. - """ - - filename = outputprefix + ".h" - root = CGBindingRoot(config, outputprefix, webidlfile) - if replaceFileIfChanged(filename, root.declare()): - print "Generating binding header: %s" % (filename) - -def generate_binding_cpp(config, outputprefix, webidlfile): - """ - |config| Is the configuration object. - |outputprefix| is a prefix to use for the header guards and filename. - """ - - filename = outputprefix + ".cpp" - root = CGBindingRoot(config, outputprefix, webidlfile) - if replaceFileIfChanged(filename, root.define()): - print "Generating binding implementation: %s" % (filename) def generate_binding_rs(config, outputprefix, webidlfile): """ @@ -43,27 +19,23 @@ def generate_binding_rs(config, outputprefix, webidlfile): filename = outputprefix + ".rs" root = CGBindingRoot(config, outputprefix, webidlfile) - root2 = CGBindingRoot(config, outputprefix, webidlfile) - if replaceFileIfChanged(filename, root.declare() + root2.define()): - #if replaceFileIfChanged(filename, root.declare()): + if replaceFileIfChanged(filename, root.define()): print "Generating binding implementation: %s" % (filename) def main(): - # Parse arguments. from optparse import OptionParser - usagestring = "usage: %prog [header|cpp] configFile outputPrefix webIDLFile" + usagestring = "usage: %prog configFile outputPrefix webIDLFile" o = OptionParser(usage=usagestring) o.add_option("--verbose-errors", action='store_true', default=False, help="When an error happens, display the Python traceback.") (options, args) = o.parse_args() - if len(args) != 4 or (args[0] != "header" and args[0] != "cpp" and args[0] != "rs"): + if len(args) != 3: o.error(usagestring) - buildTarget = args[0] - configFile = os.path.normpath(args[1]) - outputPrefix = args[2] - webIDLFile = os.path.normpath(args[3]) + configFile = os.path.normpath(args[0]) + outputPrefix = args[1] + webIDLFile = os.path.normpath(args[2]) # Load the parsing results f = open('ParserResults.pkl', 'rb') @@ -74,14 +46,7 @@ def main(): config = Configuration(configFile, parserData) # Generate the prototype classes. - if buildTarget == "header": - generate_binding_header(config, outputPrefix, webIDLFile); - elif buildTarget == "cpp": - generate_binding_cpp(config, outputPrefix, webIDLFile); - elif buildTarget == "rs": - generate_binding_rs(config, outputPrefix, webIDLFile); - else: - assert False # not reached + generate_binding_rs(config, outputPrefix, webIDLFile); if __name__ == '__main__': main() diff --git a/src/components/script/dom/bindings/codegen/Bindings.conf b/src/components/script/dom/bindings/codegen/Bindings.conf index aabb3511bee..369d08bfdf0 100644 --- a/src/components/script/dom/bindings/codegen/Bindings.conf +++ b/src/components/script/dom/bindings/codegen/Bindings.conf @@ -26,12 +26,23 @@ DOMInterfaces = { 'Console': {}, 'Document': { 'needsAbstract': [ + 'anchors', + 'applets', 'body', 'createComment', 'createDocumentFragment', 'createElement', 'createProcessingInstruction', 'createTextNode', + 'embeds', + 'forms', + 'getElementsByClassName', + 'getElementsByTagName', + 'getElementsByTagNameNS', + 'images', + 'links', + 'plugins', + 'scripts', 'title', ], }, @@ -43,6 +54,9 @@ DOMInterfaces = { 'attributes', 'getBoundingClientRect', 'getClientRects', + 'getElementsByClassName', + 'getElementsByTagName', + 'getElementsByTagNameNS', 'id', 'innerHTML', 'outerHTML', @@ -85,10 +99,17 @@ DOMInterfaces = { 'ValidityState': {}, 'Window': { 'createGlobal': True, + 'needsAbstract': [ + 'console', + 'location', + 'navigator', + ], }, 'WindowProxy': {}, +'TestBinding': {}, + } # FIXME: This should be renamed: https://github.com/mozilla/servo/issues/1625 diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py index 7492723eca4..2162d445c24 100644 --- a/src/components/script/dom/bindings/codegen/CodegenRust.py +++ b/src/components/script/dom/bindings/codegen/CodegenRust.py @@ -141,11 +141,9 @@ class CGThing(): """ def __init__(self): pass # Nothing for now - def declare(self): - """Produce code for a header file.""" - assert(False) # Override me! + def define(self): - """Produce code for a cpp file.""" + """Produce code for a Rust file.""" assert(False) # Override me! class CGMethodCall(CGThing): @@ -290,7 +288,7 @@ class CGMethodCall(CGThing): # also allow the unwrapping test to skip having to do codegen # for the null-or-undefined case, which we already handled # above. - caseBody.append(CGGeneric("if JSVAL_IS_OBJECT(%s) {" % + caseBody.append(CGGeneric("if (%s).is_object() {" % (distinguishingArg))) for idx, sig in enumerate(interfacesSigs): caseBody.append(CGIndenter(CGGeneric("loop {"))); @@ -570,11 +568,11 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, # Handle the non-object cases by wrapping up the whole # thing in an if cascade. templateBody = ( - "if JSVAL_IS_OBJECT(${val}) {\n" + + "if (${val}).is_object() {\n" + CGIndenter(CGGeneric(templateBody)).define() + "\n") if type.nullable(): templateBody += ( - "} else if RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0 {\n" + "} else if (${val}).is_null_or_undefined() {\n" " %s;\n" % codeToSetNull) templateBody += ( "} else {\n" + @@ -593,303 +591,34 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, raise TypeError("Can't handle array arguments yet") if type.isSequence(): - assert not isEnforceRange and not isClamp - - if failureCode is not None: - raise TypeError("Can't handle sequences when failureCode is not None") - nullable = type.nullable(); - # Be very careful not to change "type": we need it later - if nullable: - elementType = type.inner.inner - else: - elementType = type.inner - - # We have to be careful with reallocation behavior for arrays. In - # particular, if we have a sequence of elements which are themselves - # sequences (so nsAutoTArrays) or have sequences as members, we have a - # problem. In that case, resizing the outermost nsAutoTarray to the - # right size will memmove its elements, but nsAutoTArrays are not - # memmovable and hence will end up with pointers to bogus memory, which - # is bad. To deal with this, we disallow sequences, arrays, - # dictionaries, and unions which contain sequences as sequence item - # types. If WebIDL ever adds another container type, we'd have to - # disallow it as well. - if typeIsSequenceOrHasSequenceMember(elementType): - raise TypeError("Can't handle a sequence containing another " - "sequence as an element or member of an element. " - "See the big comment explaining why.\n%s" % - str(type.location)) - - (elementTemplate, elementDeclType, - elementHolderType, dealWithOptional, - initialValue) = getJSToNativeConversionTemplate( - elementType, descriptorProvider, isMember=True) - if dealWithOptional: - raise TypeError("Shouldn't have optional things in sequences") - if elementHolderType is not None: - raise TypeError("Shouldn't need holders for sequences") - - typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >") - if nullable: - typeName = CGWrapper(typeName, pre="Nullable< ", post=" >") - arrayRef = "${declName}.Value()" - else: - arrayRef = "${declName}" - # If we're optional, the const will come from the Optional - mutableTypeName = typeName - if not isOptional: - typeName = CGWrapper(typeName, pre="const ") - - templateBody = ("""JSObject* seq = &${val}.toObject();\n -if (!IsArrayLike(cx, seq)) { - return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS); -} -uint32_t length; -// JS_GetArrayLength actually works on all objects -if (!JS_GetArrayLength(cx, seq, &length)) { - return false; -} -Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s); -if (!arr.SetCapacity(length)) { - return Throw(cx, NS_ERROR_OUT_OF_MEMORY); -} -for (uint32_t i = 0; i < length; ++i) { - jsval temp; - if (!JS_GetElement(cx, seq, i, &temp)) { - return false; - } -""" % (elementDeclType.define(), - elementDeclType.define(), - arrayRef)) - - templateBody += CGIndenter(CGGeneric( - string.Template(elementTemplate).substitute( - { - "val" : "temp", - "valPtr": "&temp", - "declName" : "(*arr.AppendElement())" - } - ))).define() - - templateBody += "\n}" - templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, - type, - "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define()) - return (templateBody, typeName, None, isOptional, None) + raise TypeError("Can't handle sequence arguments yet") if type.isUnion(): if isMember: raise TypeError("Can't handle unions as members, we have a " "holderType") - nullable = type.nullable(); - if nullable: - type = type.inner - - assert(defaultValue is None or - (isinstance(defaultValue, IDLNullValue) and nullable)) - - unionArgumentObj = "${holderName}" - #if isOptional or nullable: - # unionArgumentObj += ".get_mut_ref()" - - memberTypes = type.flatMemberTypes - names = [] - - interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes) - if len(interfaceMemberTypes) > 0: - interfaceObject = [] - for memberType in interfaceMemberTypes: - if type.isGeckoInterface(): - name = memberType.inner.identifier.name - else: - name = memberType.name - interfaceObject.append(CGGeneric("{res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()}" % (unionArgumentObj, name))) - names.append(name) - interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True) - else: - interfaceObject = None - - arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes) - if len(arrayObjectMemberTypes) > 0: - assert len(arrayObjectMemberTypes) == 1 - memberType = arrayObjectMemberTypes[0] - name = memberType.name - arrayObject = CGGeneric("done = {res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()};" % (unionArgumentObj, name)) - # XXX Now we're supposed to check for an array or a platform object - # that supports indexed properties... skip that last for now. It's a - # bit of a pain. - arrayObject = CGWrapper(CGIndenter(arrayObject), - pre="if (IsArrayLike(cx, &argObj)) {\n", - post="}") - names.append(name) - else: - arrayObject = None - dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes) - if len(dateObjectMemberTypes) > 0: - assert len(dateObjectMemberTypes) == 1 - memberType = dateObjectMemberTypes[0] - name = memberType.name - dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${valPtr});\n" - "done = true;" % (unionArgumentObj, name)) - dateObject = CGWrapper(CGIndenter(dateObject), - pre="if (JS_ObjectIsDate(cx, &argObj)) {\n", - post="\n}") - names.append(name) - else: - dateObject = None - - callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) - if len(callbackMemberTypes) > 0: - assert len(callbackMemberTypes) == 1 - memberType = callbackMemberTypes[0] - name = memberType.name - callbackObject = CGGeneric("done = {res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()};" % (unionArgumentObj, name)) - names.append(name) - else: - callbackObject = None - - dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes) - if len(dictionaryMemberTypes) > 0: - raise TypeError("No support for unwrapping dictionaries as member " - "of a union") - else: - dictionaryObject = None - - if callbackObject or dictionaryObject: - nonPlatformObject = CGList([callbackObject, dictionaryObject], "\n") - nonPlatformObject = CGWrapper(CGIndenter(nonPlatformObject), - pre="if (!IsPlatformObject(cx, &argObj)) {\n", - post="\n}") - else: - nonPlatformObject = None - - objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) - if len(objectMemberTypes) > 0: - object = CGGeneric("%s.SetToObject(&argObj);\n" - "done = true;" % unionArgumentObj) - else: - object = None - - hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object - if hasObjectTypes: - # If we try more specific object types first then we need to check - # whether that succeeded before converting to object. - if object and (interfaceObject or arrayObject or dateObject or nonPlatformObject): - object = CGWrapper(CGIndenter(object), pre="if (!done) {\n", - post=("\n}")) - - if arrayObject or dateObject or nonPlatformObject: - # An object can be both an array object and not a platform - # object, but we shouldn't have both in the union's members - # because they are not distinguishable. - assert not (arrayObject and nonPlatformObject) - templateBody = CGList([arrayObject, dateObject, nonPlatformObject], " else ") - else: - templateBody = None - if interfaceObject: - if templateBody: - templateBody = CGList([templateBody, object], "\n") - templateBody = CGWrapper(CGIndenter(templateBody), - pre="if (!done) {\n", post=("\n}")) - templateBody = CGList([interfaceObject, templateBody], "\n") - else: - templateBody = CGList([templateBody, object], "\n") - - if any([arrayObject, dateObject, nonPlatformObject, object]): - templateBody.prepend(CGGeneric("JSObject& argObj = ${val}.toObject();")) - templateBody = CGWrapper(CGIndenter(templateBody), - pre="if JSVAL_IS_OBJECT(${val}) {\n", - post="\n}") - else: - templateBody = CGGeneric() - - otherMemberTypes = filter(lambda t: t.isString() or t.isEnum(), - memberTypes) - otherMemberTypes.extend(t for t in memberTypes if t.isPrimitive()) - if len(otherMemberTypes) > 0: - assert len(otherMemberTypes) == 1 - memberType = otherMemberTypes[0] - if memberType.isEnum(): - name = memberType.inner.identifier.name - else: - name = memberType.name - other = CGGeneric("done = {res = %s.TrySetTo%s(cx, ${val}, ${valPtr}); res.is_err() || !res.unwrap()};" % (unionArgumentObj, name)) - names.append(name) - if hasObjectTypes: - other = CGWrapper(CGIndenter(other), "{\n", post="\n}") - if object: - join = " else " - else: - other = CGWrapper(other, pre="if (!done) ") - join = "\n" - templateBody = CGList([templateBody, other], join) - else: - other = None - - templateBody = CGWrapper(templateBody, pre="let mut done = false;\n" - "let mut res = Ok(true);\n") - throw = CGGeneric("if res.is_err() {\n" - " return 0;\n" - "}\n" - "if !done {\n" - " return throw_not_in_union(cx, \"%s\");\n" - "}" % ", ".join(names)) - templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}") - - typeName = type.name - argumentTypeName = typeName + "Argument" - if nullable: - typeName = "Option<" + typeName + " >" - nonConstDecl = "${declName}" - - def handleNull(templateBody, setToNullVar, extraConditionForNull=""): - null = CGGeneric("if %s(RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0) {\n" - " %s = None;\n" - "}" % (extraConditionForNull, setToNullVar)) - templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}") - return CGList([null, templateBody], " else ") + declType = CGGeneric(type.name) + value = CGGeneric("value") + if type.nullable(): + declType = CGWrapper(declType, pre="Option<", post=" >") + value = CGWrapper(value, pre="Some(", post=")") - if type.hasNullableType: - templateBody = handleNull(templateBody, unionArgumentObj) + templateBody = CGGeneric("match %s::from_value(cx, ${val}) {\n" + " Err(()) => { %s },\n" + " Ok(value) => ${declName} = %s,\n" + "}" % (type.name, exceptionCode, value.define())) - declType = CGGeneric(typeName) - holderType = CGGeneric(argumentTypeName) - if isOptional: - mutableDecl = nonConstDecl + ".Value()" - declType = CGWrapper(declType, pre="const Optional<", post=" >") - holderType = CGWrapper(holderType, pre="Option<", post=" >") - constructDecl = CGGeneric(nonConstDecl + ".Construct();") - if nullable: - constructHolder = CGGeneric("${holderName} = Some(%s.SetValue());" % mutableDecl) - else: - constructHolder = CGGeneric("${holderName} = Some(${declName}.Value());") - else: - mutableDecl = nonConstDecl - constructDecl = None - holderInit = "${declName}" - if nullable: - holderInit += ".get_mut_ref()" - else: - holderInit = "&mut " + holderInit - constructHolder = CGWrapper(holderType, pre="let mut ${holderName} = ", post="::new(" + holderInit + ");") - if nullable: - constructHolder = CGWrapper(constructHolder, pre="${declName} = Some(uninit());\n") - holderType = None + if type.nullable(): + templateBody = CGIfElseWrapper( + "(${val}).is_null_or_undefined()", + CGGeneric("${declName} = None;"), + templateBody) - templateBody = CGList([constructHolder, templateBody], "\n") - if nullable: - if defaultValue: - assert(isinstance(defaultValue, IDLNullValue)) - valueMissing = "!(${haveValue}) || " - else: - valueMissing = "" - templateBody = handleNull(templateBody, mutableDecl, - extraConditionForNull=valueMissing) - templateBody = CGWrapper(CGIndenter(CGList([constructDecl, templateBody], "\n")), - pre="{\n", post="\n}") + templateBody = handleDefaultNull(templateBody.define(), + "${declName} = None") - return templateBody.define(), declType, holderType, False, "uninit()" if not nullable else None + return (templateBody, declType, None, isOptional, "None" if isOptional else None) if type.isGeckoInterface(): assert not isEnforceRange and not isClamp @@ -900,39 +629,19 @@ for (uint32_t i = 0; i < length; ++i) { if descriptor.interface.isCallback(): name = descriptor.nativeType declType = CGGeneric("Option<%s>" % name); - conversion = (" ${declName} = Some(%s::new(JSVAL_TO_OBJECT(${val})));\n" % name) + conversion = (" ${declName} = Some(%s::new((${val}).to_object()));\n" % name) template = wrapObjectTemplate(conversion, type, "${declName} = None", failureCode) return (template, declType, None, isOptional, None) - # This is an interface that we implement as a concrete class - # or an XPCOM interface. - - argIsPointer = type.nullable() - # Sequences and callbacks have to hold a strong ref to the thing being # passed down. forceOwningType = descriptor.interface.isCallback() or isMember typePtr = descriptor.nativeType - # Compute a few things: - # - declType is the type we want to return as the first element of our - # tuple. - # - holderType is the type we want to return as the third element - # of our tuple. - - # Set up some sensible defaults for these things insofar as we can. - holderType = None - initialValue = None - if argIsPointer or isOptional: - declType = "Option<" + typePtr + ">" - initialValue = "None" - else: - declType = typePtr - templateBody = "" if descriptor.castable: if descriptor.interface.isConsequential(): @@ -942,17 +651,17 @@ for (uint32_t i = 0; i < length; ++i) { if failureCode is not None: templateBody += str(CastableObjectUnwrapper( descriptor, - "JSVAL_TO_OBJECT(${val})", + "(${val}).to_object()", "${declName}", failureCode, - isOptional or argIsPointer or type.nullable(), + isOptional or type.nullable(), preUnwrapped=preSuccess, postUnwrapped=postSuccess)) else: templateBody += str(FailureFatalCastableObjectUnwrapper( descriptor, - "JSVAL_TO_OBJECT(${val})", + "(${val}).to_object()", "${declName}", - isOptional or argIsPointer or type.nullable())) + isOptional or type.nullable())) else: templateBody += ( "match unwrap_value::<" + typePtr + ">(&${val} as *JSVal, " @@ -969,66 +678,14 @@ for (uint32_t i = 0; i < length; ++i) { type, "${declName} = None", failureCode) - declType = CGGeneric(declType) - if holderType is not None: - holderType = CGGeneric(holderType) - return (templateBody, declType, holderType, isOptional, initialValue) + declType = CGGeneric(typePtr) + if type.nullable() or isOptional: + declType = CGWrapper(declType, pre="Option<", post=">") + + return (templateBody, declType, None, isOptional, "None" if isOptional else None) if type.isSpiderMonkeyInterface(): - assert not isEnforceRange and not isClamp - if isMember: - raise TypeError("Can't handle member arraybuffers or " - "arraybuffer views because making sure all the " - "objects are properly rooted is hard") - name = type.name - # By default, we use a Maybe<> to hold our typed array. And in the optional - # non-nullable case we want to pass Optional<TypedArray> to consumers, not - # Optional<NonNull<TypedArray> >, so jump though some hoops to do that. - holderType = "Maybe<%s>" % name - constructLoc = "${holderName}" - constructMethod = "construct" - constructInternal = "ref" - if type.nullable(): - if isOptional: - declType = "const Optional<" + name + "*>" - else: - declType = name + "*" - else: - if isOptional: - declType = "const Optional<" + name + ">" - # We don't need a holder in this case - holderType = None - constructLoc = "(const_cast<Optional<" + name + ">& >(${declName}))" - constructMethod = "Construct" - constructInternal = "Value" - else: - declType = "NonNull<" + name + ">" - template = ( - "%s.%s(cx, &${val}.toObject());\n" - "if (!%s.%s().inited()) {\n" - "%s" # No newline here because onFailureBadType() handles that - "}\n" % - (constructLoc, constructMethod, constructLoc, constructInternal, - CGIndenter(onFailureBadType(failureCode, type.name)).define())) - nullableTarget = "" - if type.nullable(): - if isOptional: - mutableDecl = "(const_cast<Optional<" + name + "*>& >(${declName}))" - template += "%s.Construct();\n" % mutableDecl - nullableTarget = "%s.Value()" % mutableDecl - else: - nullableTarget = "${declName}" - template += "%s = ${holderName}.addr();" % nullableTarget - elif not isOptional: - template += "${declName} = ${holderName}.addr();" - template = wrapObjectTemplate(template, isDefinitelyObject, type, - "%s = NULL" % nullableTarget, - failureCode) - - if holderType is not None: - holderType = CGGeneric(holderType) - # We handle all the optional stuff ourselves; no need for caller to do it. - return (template, CGGeneric(declType), holderType, False, None) + raise TypeError("Can't handle SpiderMonkey interface arguments yet") if type.isString(): assert not isEnforceRange and not isClamp @@ -1039,43 +696,48 @@ for (uint32_t i = 0; i < length; ++i) { } if treatNullAs not in treatAs: raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs) - nullBehavior = treatAs[treatNullAs] + if type.nullable(): + nullBehavior = "()" + else: + nullBehavior = treatAs[treatNullAs] - def getConversionCode(varName, isOptional=False): + def getConversionCode(isOptional=False): strval = "strval" if isOptional: strval = "Some(%s)" % strval - if type.nullable(): - call = "jsval_to_domstring(cx, ${val})" - else: - call = "jsval_to_str(cx, ${val}, %s)" % nullBehavior + conversionCode = ( - "let strval = %s;\n" - "if strval.is_err() {\n" - " return 0;\n" - "}\n" - "let strval = strval.unwrap();\n" - "%s = %s;" % (call, varName, strval)) + "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n" + " Ok(strval) => ${declName} = %s,\n" + " Err(_) => return 0,\n" + "}" % (nullBehavior, strval)) + if defaultValue is None: return conversionCode if isinstance(defaultValue, IDLNullValue): assert(type.nullable()) return handleDefault(conversionCode, - "%s.SetNull()" % varName) - return handleDefault( - conversionCode, - ("static data: [u8, ..%s] = [ %s ];\n" - "%s = str::from_utf8(data).to_owned()" % - (len(defaultValue.value) + 1, - ", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]), - varName))) + "${declName}.SetNull()") + + value = "str::from_utf8(data).to_owned()" + if type.nullable(): + value = "Some(%s)" % value + + default = ( + "static data: [u8, ..%s] = [ %s ];\n" + "${declName} = %s" % + (len(defaultValue.value) + 1, + ", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]), + value)) + + return handleDefault(conversionCode, default) if isMember: # We have to make a copy, because our jsval may well not # live as long as our string needs to. declType = CGGeneric("DOMString") - return ("%s\n" % getConversionCode("${declName}"), + return ("%s\n" % getConversionCode(), declType, None, isOptional, None) declType = "DOMString" @@ -1089,8 +751,7 @@ for (uint32_t i = 0; i < length; ++i) { return ( "%s\n" % - #"const_cast<%s&>(${declName}) = &${holderName};" % - (getConversionCode("${declName}", isOptional)), + (getConversionCode(isOptional)), CGGeneric(declType), None, #CGGeneric("FakeDependentString"), False, initialValue) @@ -1156,26 +817,21 @@ for (uint32_t i = 0; i < length; ++i) { if isMember: raise TypeError("Can't handle member 'any'; need to sort out " "rooting issues") - templateBody = "${declName} = ${val};" + + declType = CGGeneric("JSVal") + value = CGGeneric("${val}") + if isOptional: + declType = CGWrapper(declType, pre="Option<", post=">") + value = CGWrapper(value, pre="Some(", post=")") + + templateBody = "${declName} = %s;" % value.define() templateBody = handleDefaultNull(templateBody, - "${declName} = JSVAL_NULL") - return (templateBody, CGGeneric("JSVal"), None, isOptional, "JSVAL_NULL") + "${declName} = NullValue()") - if type.isObject(): - assert not isEnforceRange and not isClamp + return (templateBody, declType, None, isOptional, "None" if isOptional else None) - if isMember: - raise TypeError("Can't handle member 'object'; need to sort out " - "rooting issues") - template = wrapObjectTemplate("${declName} = &${val}.toObject();", - isDefinitelyObject, type, - "${declName} = NULL", - failureCode) - if type.nullable(): - declType = CGGeneric("JSObject*") - else: - declType = CGGeneric("NonNull<JSObject>") - return (template, declType, None, isOptional, None) + if type.isObject(): + raise TypeError("Can't handle object arguments yet") if type.isDictionary(): if failureCode is not None: @@ -1201,7 +857,7 @@ for (uint32_t i = 0; i < length; ++i) { # actually do want a jsval, and we only handle null anyway if defaultValue is not None: assert(isinstance(defaultValue, IDLNullValue)) - val = "if ${haveValue} { ${val} } else { JSVAL_NULL }" + val = "if ${haveValue} { ${val} } else { NullValue() }" else: val = "${val}" @@ -1232,54 +888,42 @@ for (uint32_t i = 0; i < length; ++i) { if failureCode is None: failureCode = 'return 0' + successVal = "v" + if preSuccess or postSuccess: + successVal = preSuccess + successVal + postSuccess + #XXXjdm support conversionBehavior here + template = ( + "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" + " Ok(v) => ${declName} = %s,\n" + " Err(_) => { %s }\n" + "}" % (successVal, exceptionCode)) + if type.nullable(): - dataLoc = "${declName}.SetValue()" - nullCondition = "(RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0)" - if defaultValue is not None and isinstance(defaultValue, IDLNullValue): - nullCondition = "!(${haveValue}) || " + nullCondition - successVal = "val_" - if preSuccess or postSuccess: - successVal = preSuccess + successVal + postSuccess - #XXXjdm support conversionBehavior here - template = ( - "if (%s) {\n" - " ${declName} = None;\n" - "} else {\n" - " match JSValConvertible::from_jsval(cx, ${val}) {\n" - " Some(val_) => ${declName} = Some(%s),\n" - " None => %s\n" - " }\n" - "}" % (nullCondition, successVal, failureCode)) declType = CGGeneric("Option<" + typeName + ">") else: - assert(defaultValue is None or - not isinstance(defaultValue, IDLNullValue)) - dataLoc = "${declName}" - #XXXjdm conversionBehavior should be used - successVal = "v" - if preSuccess or postSuccess: - successVal = preSuccess + successVal + postSuccess - template = ( - "match JSValConvertible::from_jsval(cx, ${val}) {\n" - " None => %s,\n" - " Some(v) => %s = %s\n" - "}" % (failureCode, dataLoc, successVal)) declType = CGGeneric(typeName) - if (defaultValue is not None and - # We already handled IDLNullValue, so just deal with the other ones - not isinstance(defaultValue, IDLNullValue)): - tag = defaultValue.type.tag() - if tag in numericTags: - defaultStr = defaultValue.value + + if defaultValue is not None: + if isinstance(defaultValue, IDLNullValue): + assert type.nullable() + defaultStr = "None" else: - assert(tag == IDLType.Tags.bool) - defaultStr = toStringBool(defaultValue.value) + tag = defaultValue.type.tag() + if tag in numericTags: + defaultStr = defaultValue.value + else: + assert(tag == IDLType.Tags.bool) + defaultStr = toStringBool(defaultValue.value) + + if type.nullable(): + defaultStr = "Some(%s)" % defaultStr + template = CGWrapper(CGIndenter(CGGeneric(template)), pre="if ${haveValue} {\n", post=("\n" "} else {\n" - " %s = %s;\n" - "}" % (dataLoc, defaultStr))).define() + " ${declName} = %s;\n" + "}" % defaultStr)).define() initialVal = "false" if typeName == "bool" else ("0 as %s" % typeName) if type.nullable(): @@ -1468,94 +1112,20 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, return ("${jsvalRef} = %s;\n" + tail) % (value) - def wrapAndSetPtr(wrapCall, failureCode=None): - """ - Returns the code to set the jsval by calling "wrapCall". "failureCode" - is the code to run if calling "wrapCall" fails - """ - if failureCode is None: - if not haveSuccessCode: - return wrapCall + ";\n" + "return if (*vp).v != 0 { 1 } else { 0 };" - failureCode = "return 0;" - str = ("if !(%s != 0) {\n" + - CGIndenter(CGGeneric(failureCode)).define() + "\n" + - "}\n" + - successCode) % (wrapCall) - return str - if type is None or type.isVoid(): - return (setValue("JSVAL_VOID"), True) + return (setValue("UndefinedValue()"), True) if type.isArray(): raise TypeError("Can't handle array return values yet") if type.isSequence(): - if type.nullable(): - # Nullable sequences are Nullable< nsTArray<T> > - (recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider, - "%s.Value()" % result, successCode, - isCreator, exceptionCode) - return (""" -if (%s.IsNull()) { -%s -} -%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), recTemplate), recInfall) - - # Now do non-nullable sequences. We use setting the element - # in the array as our succcess code because when we succeed in - # wrapping that's what we should do. - innerTemplate = wrapForType( - type.inner, descriptorProvider, - { - 'result' : "%s[i]" % result, - 'successCode': ("if (!JS_DefineElement(cx, returnArray, i, tmp,\n" - " NULL, NULL, JSPROP_ENUMERATE)) {\n" - " return false;\n" - "}"), - 'jsvalRef': "tmp", - 'jsvalPtr': "&tmp", - 'isCreator': isCreator - } - ) - innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define() - return ((""" -uint32_t length = %s.Length(); -JSObject *returnArray = JS_NewArrayObject(cx, length, NULL); -if (!returnArray) { - return false; -} -jsval tmp; -for (uint32_t i = 0; i < length; ++i) { -%s -}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)"), False) + raise TypeError("Can't handle sequence return values yet") if type.isGeckoInterface(): - descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name) - if type.nullable(): - wrappingCode = ("if %s.is_none() {\n" % (result) + - CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + - "}\n" + - "let mut %s = %s.unwrap();\n" % (result, result)) - else: - wrappingCode = "" - if not descriptor.interface.isCallback(): - wrap = "GetReflector(cx, (%s).reflector(), ${jsvalPtr} as *mut JSVal)" % result - # Non-prefable bindings can only fail to wrap as a new-binding object - # if they already threw an exception. Same thing for - # non-prefable bindings. - failed = ("assert!(unsafe { JS_IsExceptionPending(cx) != 0 });\n" + - "%s" % exceptionCode) - wrappingCode += wrapAndSetPtr(wrap, failed) - else: - wrap = "GetReflector(cx, (%s).reflector(), ${jsvalPtr} as *mut JSVal)" % result - wrappingCode += wrapAndSetPtr(wrap) - return (wrappingCode, False) + return (setValue("(%s).to_jsval(cx)" % result), True) if type.isString(): - if type.nullable(): - return (wrapAndSetPtr("*${jsvalPtr} = domstring_to_jsval(cx, %s)" % result), False) - else: - return (wrapAndSetPtr("*${jsvalPtr} = str_to_jsval(cx, %s)" % result), False) + return (setValue("(%s).to_jsval(cx)" % result), True) if type.isEnum(): if type.nullable(): @@ -1569,7 +1139,7 @@ if %(resultStr)s.is_null() { """ % { "result" : result, "resultStr" : result + "_str", "strings" : type.inner.identifier.name + "Values::strings" } + - setValue("RUST_STRING_TO_JSVAL(%s_str)" % result), False) + setValue("StringValue(&*(%s_str))" % result), False) if type.isCallback(): assert not type.isInterface() @@ -1590,43 +1160,17 @@ if %(resultStr)s.is_null() { # See comments in WrapNewBindingObject explaining why we need # to wrap here. if type.nullable(): - toValue = "RUST_OBJECT_TO_JSVAL(%s)" + toValue = "ObjectOrNullValue(%s)" else: - toValue = "RUST_OBJECT_TO_JSVAL(%s)" + toValue = "ObjectValue(&*(%s))" # NB: setValue(..., True) calls JS_WrapValue(), so is fallible return (setValue(toValue % result, True), False) if not type.isPrimitive(): raise TypeError("Need to learn to wrap %s" % type) - if type.nullable(): - (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider, - "%s.Value()" % result, successCode, - isCreator, exceptionCode) - return ("if (%s.IsNull()) {\n" % result + - CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + - "}\n" + recTemplate, recInfal) - - tag = type.tag() - - if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16, - IDLType.Tags.uint16, IDLType.Tags.int32]: - return (setValue("RUST_INT_TO_JSVAL(%s as i32)" % result), True) - - elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float, - IDLType.Tags.double]: - # XXXbz will cast to double do the "even significand" thing that webidl - # calls for for 64-bit ints? Do we care? - return (setValue("RUST_JS_NumberValue(%s as f64)" % result), True) + return (setValue("(%s).to_jsval(cx)" % result), True) - elif tag == IDLType.Tags.uint32: - return (setValue("RUST_UINT_TO_JSVAL(%s)" % result), True) - - elif tag == IDLType.Tags.bool: - return (setValue("RUST_BOOLEAN_TO_JSVAL(%s as JSBool)" % result), True) - - else: - raise TypeError("Need to learn to wrap primitive: %s" % type) def wrapForType(type, descriptorProvider, templateValues): """ @@ -1685,7 +1229,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.isPrimitive() and returnType.tag() in builtinNames: result = CGGeneric(builtinNames[returnType.tag()]) if returnType.nullable(): - result = CGWrapper(result, pre="Nullable<", post=">") + result = CGWrapper(result, pre="Option<", post=">") return result, False if returnType.isString(): result = CGGeneric("DOMString") @@ -1712,17 +1256,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.isObject() or returnType.isSpiderMonkeyInterface(): return CGGeneric("*JSObject"), False if returnType.isSequence(): - nullable = returnType.nullable() - if nullable: - returnType = returnType.inner - # If our result is already addrefed, use the right type in the - # sequence argument here. - (result, _) = getRetvalDeclarationForType(returnType.inner, - descriptorProvider) - result = CGWrapper(result, pre="nsTArray< ", post=" >") - if nullable: - result = CGWrapper(result, pre="Nullable< ", post=" >") - return result, True + raise TypeError("We don't support sequence return values") + raise TypeError("Don't know how to declare return value for %s" % returnType) @@ -2038,9 +1573,7 @@ class CGNativePropertyHooks(CGThing): def __init__(self, descriptor): CGThing.__init__(self) self.descriptor = descriptor - def declare(self): - #return "extern const NativePropertyHooks NativeHooks;\n" - return "" + def define(self): if self.descriptor.concrete and self.descriptor.proxy: resolveOwnProperty = "ResolveOwnProperty" @@ -2063,20 +1596,14 @@ class CGIndenter(CGThing): A class that takes another CGThing and generates code that indents that CGThing by some number of spaces. The default indent is two spaces. """ - def __init__(self, child, indentLevel=2, declareOnly=False): + def __init__(self, child, indentLevel=2): CGThing.__init__(self) self.child = child self.indent = " " * indentLevel - self.declareOnly = declareOnly - def declare(self): - decl = self.child.declare() - if decl is not "": - return re.sub(lineStartDetector, self.indent, decl) - else: - return "" + def define(self): defn = self.child.define() - if defn is not "" and not self.declareOnly: + if defn is not "": return re.sub(lineStartDetector, self.indent, defn) else: return defn @@ -2085,62 +1612,49 @@ class CGWrapper(CGThing): """ Generic CGThing that wraps other CGThings with pre and post text. """ - def __init__(self, child, pre="", post="", declarePre=None, - declarePost=None, definePre=None, definePost=None, - declareOnly=False, defineOnly=False, reindent=False): + def __init__(self, child, pre="", post="", reindent=False): CGThing.__init__(self) self.child = child - self.declarePre = declarePre or pre - self.declarePost = declarePost or post - self.definePre = definePre or pre - self.definePost = definePost or post - self.declareOnly = declareOnly - self.defineOnly = defineOnly + self.pre = pre + self.post = post self.reindent = reindent - def declare(self): - if self.defineOnly: - return '' - decl = self.child.declare() - if self.reindent: - # We don't use lineStartDetector because we don't want to - # insert whitespace at the beginning of our _first_ line. - decl = stripTrailingWhitespace( - decl.replace("\n", "\n" + (" " * len(self.declarePre)))) - return self.declarePre + decl + self.declarePost + def define(self): - if self.declareOnly: - return '' defn = self.child.define() if self.reindent: # We don't use lineStartDetector because we don't want to # insert whitespace at the beginning of our _first_ line. defn = stripTrailingWhitespace( - defn.replace("\n", "\n" + (" " * len(self.definePre)))) - return self.definePre + defn + self.definePost + defn.replace("\n", "\n" + (" " * len(self.pre)))) + return self.pre + defn + self.post class CGImports(CGWrapper): """ Generates the appropriate import/use statements. """ - def __init__(self, descriptors, dictionaries, declareImports, defineImports, child): + def __init__(self, child, imports): """ - Builds a set of imports to cover |descriptors|. - - Also includes the files in |declareIncludes| in the header - file and the files in |defineIncludes| in the .cpp. + Adds a set of imports. """ + ignored_warnings = [ + # Allow unreachable_code because we use 'break' in a way that + # sometimes produces two 'break's in a row. See for example + # CallbackMember.getArgConversions. + 'unreachable_code', + 'non_uppercase_statics', + 'unused_imports', + 'unused_variable', + 'unused_unsafe', + 'unused_mut', + 'dead_assignment', + 'dead_code', + ] + + statements = ['#[allow(%s)];' % ','.join(ignored_warnings)] + statements.extend('use %s;' % i for i in sorted(imports)) - # TODO imports to cover descriptors, etc. - - def _useString(imports): - # Allow unreachable_code because we use 'break' in a way that sometimes produces - # two 'break's in a row. See for example CallbackMember.getArgConversions. - return '\n'.join([ - '#[allow(unreachable_code,non_uppercase_statics,unused_imports,unused_variable,unused_unsafe,unused_mut,dead_assignment,dead_code)];', - ''.join('use %s;\n' % i for i in imports), - '']) CGWrapper.__init__(self, child, - declarePre=_useString(sorted(declareImports))) + pre='\n'.join(statements) + '\n\n') @staticmethod def getDeclarationFilename(decl): @@ -2157,23 +1671,20 @@ class CGIfWrapper(CGWrapper): post="\n}") class CGNamespace(CGWrapper): - def __init__(self, namespace, child, declareOnly=False, public=False): + def __init__(self, namespace, child, 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) + CGWrapper.__init__(self, child, pre=pre, post=post) + @staticmethod - def build(namespaces, child, declareOnly=False, public=False): + def build(namespaces, child, 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, public=public) - return CGNamespace(namespaces[0], inner, declareOnly=declareOnly, public=public) - - def declare(self): - return "" + return child + inner = CGNamespace.build(namespaces[1:], child, public=public) + return CGNamespace(namespaces[0], inner, public=public) def DOMClass(descriptor): protoList = ['PrototypeList::id::' + proto for proto in descriptor.prototypeChain] @@ -2196,9 +1707,7 @@ class CGDOMJSClass(CGThing): def __init__(self, descriptor): CGThing.__init__(self) self.descriptor = descriptor - def declare(self): - #return "extern DOMJSClass Class;\n" - return "" + def define(self): traceHook = "Some(%s)" % TRACE_HOOK_NAME if self.descriptor.createGlobal: @@ -2250,9 +1759,7 @@ class CGPrototypeJSClass(CGThing): def __init__(self, descriptor): CGThing.__init__(self) self.descriptor = descriptor - def declare(self): - # We're purely for internal consumption - return "" + def define(self): return """ static PrototypeClassName__: [u8, ..%s] = %s; @@ -2288,9 +1795,7 @@ class CGInterfaceObjectJSClass(CGThing): def __init__(self, descriptor): CGThing.__init__(self) self.descriptor = descriptor - def declare(self): - # We're purely for internal consumption - return "" + def define(self): if True: return "" @@ -2331,23 +1836,28 @@ class CGList(CGThing): self.children.insert(0, child) def join(self, generator): return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator))) - def declare(self): - return self.join(child.declare() for child in self.children if child is not None) + def define(self): return self.join(child.define() for child in self.children if child is not None) + +class CGIfElseWrapper(CGList): + def __init__(self, condition, ifTrue, ifFalse): + kids = [ CGIfWrapper(ifTrue, condition), + CGWrapper(CGIndenter(ifFalse), pre=" else {\n", post="\n}") ] + CGList.__init__(self, kids) + + class CGGeneric(CGThing): """ A class that spits out a fixed string into the codegen. Can spit out a separate string for the declaration too. """ - def __init__(self, define="", declare=""): - self.declareText = declare - self.defineText = define - def declare(self): - return self.declareText + def __init__(self, text): + self.text = text + def define(self): - return self.defineText + return self.text def getTypes(descriptor): """ @@ -2486,22 +1996,17 @@ class CGAbstractMethod(CGThing): alwaysInline should be True to generate an inline method annotated with MOZ_ALWAYS_INLINE. - static should be True to generate a static method, which only has - a definition. - If templateArgs is not None it should be a list of strings containing template arguments, and the function will be templatized using those arguments. """ - def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, extern=False, pub=False, templateArgs=None, unsafe=True): + def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, extern=False, pub=False, templateArgs=None, unsafe=True): CGThing.__init__(self) self.descriptor = descriptor self.name = name self.returnType = returnType self.args = args - self.inline = inline self.alwaysInline = alwaysInline - self.static = static self.extern = extern self.templateArgs = templateArgs self.pub = pub; @@ -2512,44 +2017,32 @@ class CGAbstractMethod(CGThing): if self.templateArgs is None: return '' return '<%s>\n' % ', '.join(self.templateArgs) + def _decorators(self): decorators = [] if self.alwaysInline: decorators.append('#[inline(always)]') - elif self.inline: - #decorators.append('inline') - pass + if self.extern: decorators.append('extern') - if not self.extern: - pass - if self.static: - #decorators.append('static') - pass + if self.pub: decorators.append('pub') + if not decorators: return '' - #maybeNewline = " " if self.inline else "\n" - maybeNewline = " " - return ' '.join(decorators) + maybeNewline + return ' '.join(decorators) + ' ' + def _returnType(self): return (" -> %s" % self.returnType) if self.returnType != "void" else "" def _unsafe_open(self): return "\n unsafe {" if self.unsafe else "" def _unsafe_close(self): return "\n }\n" if self.unsafe else "" - def declare(self): - if self.inline: - return self._define() - #return "%sfn %s%s(%s)%s;\n" % (self._decorators(), self.name, self._template(), - # self._argstring(), self._returnType()) - return "" - def _define(self, fromDeclare=False): + def define(self, fromDeclare=False): return self.definition_prologue(fromDeclare) + "\n" + self.definition_body() + self.definition_epilogue() - def define(self): - return "" if self.inline else self._define() + def definition_prologue(self, fromDeclare): return "%sfn %s%s(%s)%s {%s" % (self._decorators(), self.name, self._template(), self._argstring(fromDeclare), self._returnType(), self._unsafe_open()) @@ -2569,12 +2062,11 @@ def CreateBindingJSObject(descriptor, parent=None): if descriptor.proxy: assert not descriptor.createGlobal handler = """ - let page = page_from_context(aCx); - let mut js_info = (*page).js_info(); + let js_info = aScope.get().page().js_info(); let handler = js_info.get().get_ref().dom_static.proxy_handlers.get(&(PrototypeList::id::%s as uint)); """ % descriptor.name create += handler + """ let obj = NewProxyObject(aCx, *handler, - ptr::to_unsafe_ptr(&RUST_PRIVATE_TO_JSVAL(squirrel_away_unique(aObject) as *libc::c_void)), + ptr::to_unsafe_ptr(&PrivateValue(squirrel_away_unique(aObject) as *libc::c_void)), proto, %s, ptr::null(), ptr::null()); if obj.is_null() { @@ -2592,25 +2084,30 @@ def CreateBindingJSObject(descriptor, parent=None): } JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32, - RUST_PRIVATE_TO_JSVAL(squirrel_away_unique(aObject) as *libc::c_void)); + PrivateValue(squirrel_away_unique(aObject) as *libc::c_void)); """ return create -class CGWrapWithCacheMethod(CGAbstractMethod): +class CGWrapMethod(CGAbstractMethod): def __init__(self, descriptor): assert descriptor.interface.hasInterfacePrototypeObject() - args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'), - Argument(DOMObjectPointerArg(descriptor), 'aObject', mutable=True)] - CGAbstractMethod.__init__(self, descriptor, 'Wrap_', '*JSObject', args) + if not descriptor.createGlobal: + args = [Argument('*JSContext', 'aCx'), Argument('&JS<Window>', 'aScope'), + Argument(DOMObjectPointerArg(descriptor), 'aObject', mutable=True)] + else: + args = [Argument('*JSContext', 'aCx'), + Argument(DOMObjectPointerArg(descriptor), 'aObject', mutable=True)] + CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, pub=True) def definition_body(self): if not self.descriptor.createGlobal: return """ - assert!(aScope.is_not_null()); - assert!(((*JS_GetClass(aScope)).flags & JSCLASS_IS_GLOBAL) != 0); + let scope = aScope.reflector().get_jsobject(); + assert!(scope.is_not_null()); + assert!(((*JS_GetClass(scope)).flags & JSCLASS_IS_GLOBAL) != 0); - //JSAutoCompartment ac(aCx, aScope); - let proto = GetProtoObject(aCx, aScope, aScope); + //JSAutoCompartment ac(aCx, scope); + let proto = GetProtoObject(aCx, scope, scope); if proto.is_null() { return ptr::null(); } @@ -2619,28 +2116,15 @@ class CGWrapWithCacheMethod(CGAbstractMethod): (*raw).mut_reflector().set_jsobject(obj); - return obj;""" % CreateBindingJSObject(self.descriptor, "aScope") + return obj;""" % CreateBindingJSObject(self.descriptor, "scope") else: return """ - assert!(aScope.is_null()); - %s let proto = GetProtoObject(aCx, obj, obj); JS_SetPrototype(aCx, obj, proto); (*raw).mut_reflector().set_jsobject(obj); return obj;""" % CreateBindingJSObject(self.descriptor) -class CGWrapMethod(CGAbstractMethod): - def __init__(self, descriptor): - # 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(DOMObjectPointerArg(descriptor), 'aObject', mutable=True)] - CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, pub=True) - - def definition_body(self): - return "return Wrap_(aCx, aScope, aObject);" - class CGAbstractExternMethod(CGAbstractMethod): """ Abstract base class for codegen of implementation-only (no @@ -2649,9 +2133,6 @@ class CGAbstractExternMethod(CGAbstractMethod): def __init__(self, descriptor, name, returnType, args): CGAbstractMethod.__init__(self, descriptor, name, returnType, args, inline=False, extern=True) - def declare(self): - # We only have implementation - return "" class PropertyArrays(): def __init__(self, descriptor): @@ -2709,38 +2190,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): # if we don't need to create anything, why are we generating this? assert needInterfaceObject or needInterfacePrototypeObject - idsToInit = [] - if False: #XXXjdm don't need xray stuff yet - for var in self.properties.xrayRelevantArrayNames(): - props = getattr(self.properties, var) - # We only have non-chrome ids to init if we have no chrome ids. - if props.hasChromeOnly(): - idsToInit.append(props.variableName(True)) - elif props.hasNonChromeOnly(): - idsToInit.append(props.variableName(False)) - if len(idsToInit) > 0: - setup = CGList([CGGeneric("let page = page_from_context(aCx);"), - CGList([CGGeneric("let mut js_info = (*page).js_info();\n" - "let %s_ids_mut = js_info.get().get_ref().dom_static.attribute_ids.get(&(PrototypeList::id::%s as uint));" % (varname, self.descriptor.name)) for varname in idsToInit], '\n')], '\n') - initIds = CGList( - [CGGeneric("!InitIds(aCx, %s, *%s_ids_mut)" % (varname, varname)) for - varname in idsToInit], ' ||\n') - if len(idsToInit) > 1: - initIds = CGWrapper(initIds, pre="(", post=")", reindent=True) - initIds = CGList( - [CGGeneric("%s_ids_mut[0] == JSID_VOID &&" % idsToInit[0]), initIds], - "\n") - initIds = CGWrapper(initIds, pre="if ", post=" {", reindent=True) - initIds = CGList( - [setup, - initIds, - CGGeneric((" %s_ids_mut[0] = JSID_VOID;\n" - " return ptr::null();") % idsToInit[0]), - CGGeneric("}")], - "\n") - else: - initIds = None - prefCacheData = [] for var in self.properties.arrayNames(): props = getattr(self.properties, var) @@ -2807,7 +2256,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): chrome = None functionBody = CGList( - [CGGeneric(getParentProto), initIds, prefCache, chrome, + [CGGeneric(getParentProto), prefCache, chrome, CGGeneric(call % self.properties.variableNames(False))], "\n\n") #return CGIndenter(CGWrapper(functionBody, pre="/*", post="*/return ptr::null()")).define() @@ -2822,7 +2271,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod): args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aGlobal'), Argument('*JSObject', 'aReceiver')] CGAbstractMethod.__init__(self, descriptor, name, - '*JSObject', args, inline=True, pub=pub) + '*JSObject', args, pub=pub) self.id = idPrefix + "id::" + self.descriptor.name def definition_body(self): return """ @@ -2881,10 +2330,6 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): args = [Argument('&mut JSPageInfo', 'js_info')] CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args, pub=True) - def declare(self): - #return CGAbstractMethod.declare(self) - return "" - def define(self): return CGAbstractMethod.define(self) @@ -3272,18 +2717,6 @@ class CGGenericMethod(CGAbstractBindingMethod): "let _info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, &*vp));\n" "return CallJitMethodOp(_info, cx, obj, this as *libc::c_void, argc, &*vp);")) -class CGAbstractStaticMethod(CGAbstractMethod): - """ - Abstract base class for codegen of implementation-only (no - declaration) static methods. - """ - def __init__(self, descriptor, name, returnType, args): - CGAbstractMethod.__init__(self, descriptor, name, returnType, args, - inline=False, static=True) - def declare(self): - # We only have implementation - return "" - class CGSpecializedMethod(CGAbstractExternMethod): """ A class for generating the C++ code for a specialized method that the JIT @@ -3394,7 +2827,7 @@ class CGGenericSetter(CGAbstractBindingMethod): def generate_code(self): return CGIndenter(CGGeneric( - "let undef = JSVAL_VOID;\n" + "let undef = UndefinedValue();\n" "let argv: *JSVal = if argc != 0 { JS_ARGV(cx, vp as *JSVal) } else { &undef as *JSVal };\n" "let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp as *JSVal));\n" "let ok = with_gc_disabled(cx, || {\n" @@ -3403,7 +2836,7 @@ class CGGenericSetter(CGAbstractBindingMethod): "if ok == 0 {\n" " return 0;\n" "}\n" - "*vp = JSVAL_VOID;\n" + "*vp = UndefinedValue();\n" "return 1;")) class CGSpecializedSetter(CGAbstractExternMethod): @@ -3458,9 +2891,6 @@ class CGMemberJITInfo(CGThing): self.member = member self.descriptor = descriptor - def declare(self): - return "" - def defineJitInfo(self, infoName, opName, infallible): protoID = "PrototypeList::id::%s as u32" % self.descriptor.name depth = self.descriptor.interface.inheritanceDepth() @@ -3534,9 +2964,6 @@ class CGEnum(CGThing): CGThing.__init__(self) self.enum = enum - def declare(self): - return "" - def define(self): return """ #[repr(uint)] @@ -3654,176 +3081,178 @@ def getUnionTypeTemplateVars(type, descriptorProvider): name = type.name typeName = "/*" + type.name + "*/" - tryNextCode = """{ - return Ok(true); -}""" (template, declType, holderType, dealWithOptional, initialValue) = getJSToNativeConversionTemplate( - type, descriptorProvider, failureCode=tryNextCode, - isDefinitelyObject=True, isOptional=type.nullable(), preSuccess="e" + name + "(", postSuccess=")") + type, descriptorProvider, failureCode="return Ok(None);", + exceptionCode='return Err(());', + isDefinitelyObject=True, isOptional=False) structType = declType.define() externalType = getUnionAccessorSignatureType(type, descriptorProvider).define() - if type.isObject(): - setter = CGGeneric("pub fn SetToObject(obj: *JSObject) {\n" - " mUnion = Some(eObject(obj));\n" - "}") - else: - jsConversion = string.Template(template).substitute( - { - "val": "value", - "valPtr": "pvalue", - "declName": "*self.mUnion", - "holderName": "m" + name + "Holder" - } - ) - jsConversion = CGWrapper(CGGeneric(jsConversion), - post="\n" - "return Ok(false);") - setter = CGWrapper(CGIndenter(jsConversion), - pre="pub fn TrySetTo" + name + "(&mut self, cx: *JSContext, value: JSVal, pvalue: *JSVal) -> Result<bool,()> {\n", - post="\n" - "}") + assert not type.isObject() + jsConversion = string.Template(template).substitute({ + "val": "value", + "valPtr": None, + "declName": "retval", + "holderName": None, + }) + jsConversion = CGWrapper(CGGeneric(jsConversion), + pre="let retval;\n", + post="\nOk(Some(retval))") return { - "name": name, - "typeName": typeName, - "structType": structType, - "externalType": externalType, - "optRef": 'ref ' if externalType[0] == '&' else '', - "setter": CGIndenter(setter).define(), - "holderType": holderType.define() if holderType else None - } - -def mapTemplate(template, templateVarArray): - return map(lambda v: string.Template(template).substitute(v), - templateVarArray) + "name": name, + "typeName": typeName, + "jsConversion": jsConversion, + } class CGUnionStruct(CGThing): def __init__(self, type, descriptorProvider): + assert not type.nullable() + assert not type.hasNullableType + CGThing.__init__(self) - self.type = type.unroll() + self.type = type self.descriptorProvider = descriptorProvider - def declare(self): + def define(self): templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider), self.type.flatMemberTypes) + enumValues = [ + " e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars + ] + return ("pub enum %s {\n" + "%s\n" + "}\n") % (self.type, "\n".join(enumValues)) - callDestructors = [] - enumValues = [] - methods = [] - if self.type.hasNullableType: - callDestructors.append(" case eNull:\n" - " break;") - enumValues.append("eNull") - methods.append(""" pub fn IsNull(&self) -> bool { - match *self { - eNull => true, - _ => false - } - }""") - - destructorTemplate = """ fn Destroy${name}(&mut self) { - assert!(Is${name}(), "Wrong type!"); - *self.mUnion = None; - }""" - destructors = mapTemplate(destructorTemplate, templateVars) - callDestructors.extend(mapTemplate(" case e${name}:\n" - " Destroy${name}();\n" - " break;", templateVars)) - enumValues.extend(mapTemplate("e${name}(${typeName})", templateVars)) - methodTemplate = """ pub fn Is${name}(&self) -> bool { - match *self { - e${name}(_) => true, - _ => false - } - } - pub fn GetAs${name}<'a>(&'a self) -> ${externalType} { - assert!(self.Is${name}()); - match *self { - e${name}(${optRef}inner) => inner, - _ => unreachable!() - } - }""" - methods.extend(mapTemplate(methodTemplate, templateVars)) - values = mapTemplate("UnionMember<${structType} > m${name};", templateVars) - return string.Template(""" -pub enum ${structName} { - ${enumValues} -} - -impl ${structName} { -${methods} -} -""").substitute( - { - "structName": self.type.__str__(), - "callDestructors": "\n".join(callDestructors), - "destructors": "\n".join(destructors), - "methods": "\n\n".join(methods), - "enumValues": ",\n ".join(enumValues), - "values": "\n ".join(values), - }) - - def define(self): - return """ -""" class CGUnionConversionStruct(CGThing): def __init__(self, type, descriptorProvider): + assert not type.nullable() + assert not type.hasNullableType + CGThing.__init__(self) - self.type = type.unroll() + self.type = type self.descriptorProvider = descriptorProvider - def declare(self): - setters = [] + def from_value_method(self): + memberTypes = self.type.flatMemberTypes + names = [] + conversions = [] - if self.type.hasNullableType: - setters.append(""" pub fn SetNull(&mut self) -> bool - { - mUnion = Some(eNull); - return true; - }""") + interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes) + if len(interfaceMemberTypes) > 0: + def get_name(memberType): + if self.type.isGeckoInterface(): + return memberType.inner.identifier.name + + return memberType.name + + def get_match(name): + return ( + "match %s::TryConvertTo%s(cx, value) {\n" + " Err(_) => return Err(()),\n" + " Ok(Some(value)) => return Ok(e%s(value)),\n" + " Ok(None) => (),\n" + "}\n") % (self.type, name, name) + + typeNames = [get_name(memberType) for memberType in interfaceMemberTypes] + interfaceObject = CGList(CGGeneric(get_match(typeName)) for typeName in typeNames) + names.extend(typeNames) + else: + interfaceObject = None - templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider), - self.type.flatMemberTypes) - structName = self.type.__str__() - - setters.extend(mapTemplate("${setter}", templateVars)) - private = "\n".join(mapTemplate(""" fn SetAs${name}() -> &${structType} - { - mUnion.mType = mUnion.e${name}; - return mUnion.mValue.m${name}.SetValue(); - }""", templateVars)) - private += "\n\n" - holders = filter(lambda v: v["holderType"] is not None, templateVars) - if len(holders) > 0: - private += "\n".join(mapTemplate(" ${holderType} m${name}Holder;", holders)) - private += "\n\n" - private += " " + structName + "& mUnion;" - return string.Template(""" -pub struct ${structName}Argument<'a> { - mUnion: &'a mut ${innerType} -} + arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes) + if len(arrayObjectMemberTypes) > 0: + assert len(arrayObjectMemberTypes) == 1 + raise TypeError("Can't handle arrays or sequences in unions.") + else: + arrayObject = None -impl<'a> ${structName}Argument<'a> { - pub fn new(union: &'a mut ${innerType}) -> ${structName}Argument<'a> { - ${structName}Argument { - mUnion: union - } - } + dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes) + if len(dateObjectMemberTypes) > 0: + assert len(dateObjectMemberTypes) == 1 + raise TypeError("Can't handle dates in unions.") + else: + dateObject = None -${setters} -} -""").substitute({"structName": structName, - "innerType": ("Option<%s>" % structName) if self.type.nullable() else structName, - "setters": "\n\n".join(setters), - }) + callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) + if len(callbackMemberTypes) > 0: + assert len(callbackMemberTypes) == 1 + raise TypeError("Can't handle callbacks in unions.") + else: + callbackObject = None + + dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes) + if len(dictionaryMemberTypes) > 0: + raise TypeError("No support for unwrapping dictionaries as member " + "of a union") + else: + dictionaryObject = None + + if callbackObject or dictionaryObject: + assert False, "Not currently supported" + else: + nonPlatformObject = None + + objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) + if len(objectMemberTypes) > 0: + raise TypeError("Can't handle objects in unions.") + else: + object = None + + hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object + if hasObjectTypes: + assert interfaceObject + templateBody = CGList([interfaceObject], "\n") + conversions.append(CGIfWrapper(templateBody, "value.is_object()")) + + otherMemberTypes = [ + t for t in memberTypes if t.isPrimitive() or t.isString() or t.isEnum() + ] + if len(otherMemberTypes) > 0: + assert len(otherMemberTypes) == 1 + memberType = otherMemberTypes[0] + if memberType.isEnum(): + name = memberType.inner.identifier.name + else: + name = memberType.name + match = ( + "match %s::TryConvertTo%s(cx, value) {\n" + " Err(_) => return Err(()),\n" + " Ok(Some(value)) => return Ok(e%s(value)),\n" + " Ok(None) => (),\n" + "}\n") % (self.type, name, name) + conversions.append(CGGeneric(match)) + names.append(name) + + conversions.append(CGGeneric( + "throw_not_in_union(cx, \"%s\");\n" + "Err(())" % ", ".join(names))) + return CGWrapper( + CGIndenter(CGList(conversions, "\n\n")), + pre="pub fn from_value(cx: *JSContext, value: JSVal) -> Result<%s, ()> {\n" % self.type, + post="\n}") + + def try_method(self, t): + templateVars = getUnionTypeTemplateVars(t, self.descriptorProvider) + returnType = "Result<Option<%s>, ()>" % templateVars["typeName"] + jsConversion = templateVars["jsConversion"] + + return CGWrapper( + CGIndenter(jsConversion, 4), + pre="pub fn TryConvertTo%s(cx: *JSContext, value: JSVal) -> %s {\n" % (t.name, returnType), + post="\n}") def define(self): + methods = [self.from_value_method()] + methods.extend(self.try_method(t) for t in self.type.flatMemberTypes) return """ -""" +impl %s { +%s +}""" % (self.type, CGIndenter(CGList(methods, "\n\n")).define()) + class ClassItem: """ Use with CGClass """ @@ -4206,7 +3635,7 @@ class CGClass(CGThing): in self.templateSpecialization]) return className - def declare(self): + def define(self): result = '' if self.templateArgs: templateArgs = [a.declare() for a in self.templateArgs] @@ -4282,8 +3711,6 @@ class CGClass(CGThing): result += "}" return result - def define(self): - return '' class CGXrayHelper(CGAbstractExternMethod): def __init__(self, descriptor, name, args, properties): @@ -4293,13 +3720,13 @@ class CGXrayHelper(CGAbstractExternMethod): def definition_body(self): varNames = self.properties.variableNames(True) - setup = "let page = page_from_context(cx);\n" + setup = ("let window = global_object_for_js_object(wrapper);\n" + "let js_info = window.get().page().js_info();\n") methods = self.properties.methods if methods.hasNonChromeOnly() or methods.hasChromeOnly(): methodArgs = "Some(zip_copies(%(methods)s, *method_ids))" % varNames - setup += "let mut js_info = (*page).js_info();\n" \ - "let method_ids = js_info.get().get_ref().dom_static.method_ids.get(&(PrototypeList::id::ClientRect as uint));\n" + setup += "let method_ids = js_info.get().get_ref().dom_static.method_ids.get(&(PrototypeList::id::ClientRect as uint));\n" else: methodArgs = "None" methodArgs = CGGeneric(methodArgs) @@ -4307,8 +3734,7 @@ class CGXrayHelper(CGAbstractExternMethod): attrs = self.properties.attrs if attrs.hasNonChromeOnly() or attrs.hasChromeOnly(): attrArgs = "Some(zip_copies(%(attrs)s, *attr_ids))" % varNames - setup += "let mut js_info = (*page).js_info();\n" \ - "let attr_ids = js_info.get().get_ref().dom_static.attribute_ids.get(&(PrototypeList::id::ClientRect as uint));\n" + setup += "let attr_ids = js_info.get().get_ref().dom_static.attribute_ids.get(&(PrototypeList::id::ClientRect as uint));\n" else: attrArgs = "None" attrArgs = CGGeneric(attrArgs) @@ -4316,8 +3742,7 @@ class CGXrayHelper(CGAbstractExternMethod): consts = self.properties.consts if consts.hasNonChromeOnly() or consts.hasChromeOnly(): constArgs = "Some(zip_copies(%(consts)s, *const_ids))" % varNames - setup += "let mut js_info = (*page).js_info();\n" \ - "let const_ids = js_info.get().get_ref().dom_static.constant_ids.get(&(PrototypeList::id::ClientRect as uint));\n" + setup += "let const_ids = js_info.get().get_ref().dom_static.constant_ids.get(&(PrototypeList::id::ClientRect as uint));\n" else: constArgs = "None" constArgs = CGGeneric(constArgs) @@ -4439,14 +3864,13 @@ class CGProxyUnwrap(CGAbstractMethod): def __init__(self, descriptor): args = [Argument('*JSObject', 'obj')] CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*' + descriptor.concreteType, args, alwaysInline=True) - def declare(self): - return "" + def definition_body(self): return """ /*if (xpc::WrapperFactory::IsXrayWrapper(obj)) { obj = js::UnwrapObject(obj); }*/ //MOZ_ASSERT(IsProxy(obj)); - let box_: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj))); + let box_: *Box<%s> = cast::transmute(GetProxyPrivate(obj).to_private()); return ptr::to_unsafe_ptr(&(*box_).data);""" % (self.descriptor.concreteType) class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): @@ -4707,7 +4131,7 @@ if found { return 1; } %s -*vp = JSVAL_VOID; +*vp = UndefinedValue(); return 1;""" % (getIndexedOrExpando, getNamed) def definition_body(self): @@ -4768,7 +4192,7 @@ class CGAbstractClassHook(CGAbstractExternMethod): def finalizeHook(descriptor, hookName, context): release = """let val = JS_GetReservedSlot(obj, dom_object_slot(obj)); -let _: %s %s = cast::transmute(RUST_JSVAL_TO_PRIVATE(val)); +let _: %s %s = cast::transmute(val.to_private()); debug!("%s finalize: {:p}", this); """ % (DOMObjectPointerType(descriptor), descriptor.concreteType, descriptor.concreteType) return release @@ -4805,13 +4229,7 @@ class CGClassConstructHook(CGAbstractExternMethod): def generate_code(self): preamble = """ - //JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp))); - //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 page = page_from_context(cx); - let frame = (*page).frame(); - let global = frame.get().get_ref().window.clone(); + let global = global_object_for_js_object(JS_CALLEE(cx, &*vp).to_object()); let obj = global.reflector().get_jsobject(); """ nativeName = MakeNativeName(self._ctor.identifier.name) @@ -4835,9 +4253,7 @@ class CGDOMJSProxyHandlerDOMClass(CGThing): def __init__(self, descriptor): CGThing.__init__(self) self.descriptor = descriptor - def declare(self): - #return "extern const DOMClass Class;\n" - return "" + def define(self): return """ static Class: DOMClass = """ + DOMClass(self.descriptor) + """; @@ -4852,6 +4268,11 @@ class CGDescriptor(CGThing): cgThings = [] if descriptor.interface.hasInterfacePrototypeObject(): + cgThings.append(CGGetProtoObjectMethod(descriptor)) + else: + cgThings.append(CGGetConstructorObjectMethod(descriptor)) + + if descriptor.interface.hasInterfacePrototypeObject(): (hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter) = False, False, False, False, False for m in descriptor.interface.members: @@ -4892,12 +4313,8 @@ class CGDescriptor(CGThing): cgThings.append(CGPrototypeJSClass(descriptor)) properties = PropertyArrays(descriptor) - cgThings.append(CGGeneric(define=str(properties))) + cgThings.append(CGGeneric(str(properties))) cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties)) - if descriptor.interface.hasInterfacePrototypeObject(): - cgThings.append(CGGetProtoObjectMethod(descriptor)) - else: - cgThings.append(CGGetConstructorObjectMethod(descriptor)) # Set up our Xray callbacks as needed. if descriptor.interface.hasInterfacePrototypeObject(): @@ -4937,18 +4354,15 @@ class CGDescriptor(CGThing): cgThings.append(CGDOMJSClass(descriptor)) pass - cgThings.append(CGWrapWithCacheMethod(descriptor)) cgThings.append(CGWrapMethod(descriptor)) - cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n") + cgThings = CGList(cgThings, "\n") cgThings = CGWrapper(cgThings, pre='\n', post='\n') #self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name), # cgThings), # post='\n') self.cgRoot = cgThings - def declare(self): - return self.cgRoot.declare() def define(self): return self.cgRoot.define() @@ -4992,8 +4406,6 @@ class CGNamespacedEnum(CGThing): # Save the result. self.node = curr - def declare(self): - return self.node.declare() def define(self): return self.node.define() @@ -5016,9 +4428,12 @@ class CGDictionary(CGThing): defaultValue=member.defaultValue)) for member in dictionary.members ] - def declare(self): + def define(self): if not self.generatable: return "" + return self.struct() + "\n" + self.impl() + + def struct(self): d = self.dictionary if d.parent: inheritance = " parent: %s::%s,\n" % (self.makeModuleName(d.parent), @@ -5039,9 +4454,7 @@ class CGDictionary(CGThing): "}").substitute( { "selfName": self.makeClassName(d), "inheritance": inheritance })) - def define(self): - if not self.generatable: - return "" + def impl(self): d = self.dictionary if d.parent: initParent = ("// Per spec, we init the parent's members first\n" @@ -5104,9 +4517,9 @@ class CGDictionary(CGThing): " }\n" "${initParent}" " let mut found: JSBool = 0;\n" - " let temp: JSVal = JSVAL_NULL;\n" - " let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n" - " if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n" + " let temp: JSVal = NullValue();\n" + " let isNull = val.is_null_or_undefined();\n" + " if !isNull && val.is_primitive() {\n" " return 0; //XXXjdm throw properly here\n" " //return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n" " }\n" @@ -5166,15 +4579,15 @@ class CGDictionary(CGThing): if True: #XXXjdm hack until 'static mut' exists for global jsids propName = member.identifier.name - propCheck = ('"%s".to_c_str().with_ref(|s| { JS_HasProperty(cx, RUST_JSVAL_TO_OBJECT(val), s, ptr::to_unsafe_ptr(&found)) })' % + propCheck = ('"%s".to_c_str().with_ref(|s| { JS_HasProperty(cx, val.to_object(), s, ptr::to_unsafe_ptr(&found)) })' % propName) - propGet = ('"%s".to_c_str().with_ref(|s| { JS_GetProperty(cx, RUST_JSVAL_TO_OBJECT(val), s, ptr::to_unsafe_ptr(&temp)) })' % + propGet = ('"%s".to_c_str().with_ref(|s| { JS_GetProperty(cx, val.to_object(), s, ptr::to_unsafe_ptr(&temp)) })' % propName) else: propId = self.makeIdName(member.identifier.name); - propCheck = ("JS_HasPropertyById(cx, RUST_JSVAL_TO_OBJECT(val), %s, ptr::to_unsafe_ptr(&found))" % + propCheck = ("JS_HasPropertyById(cx, val.to_object(), %s, ptr::to_unsafe_ptr(&found))" % propId) - propGet = ("JS_GetPropertyById(cx, RUST_JSVAL_TO_OBJECT(val), %s, ptr::to_unsafe_ptr(&temp))" % + propGet = ("JS_GetPropertyById(cx, val.to_object(), %s, ptr::to_unsafe_ptr(&temp))" % propId) conversionReplacements = { @@ -5270,8 +4683,8 @@ class CGBindingRoot(CGThing): 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))) + return CGGeneric("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] ] @@ -5321,46 +4734,79 @@ class CGBindingRoot(CGThing): # Add imports #XXXjdm This should only import the namespace for the current binding, # not every binding ever. - curr = CGImports(descriptors, - dictionaries, - ['js::*', - 'js::jsapi::*', - 'js::jsfriendapi::bindgen::*', - 'js::glue::*', - 'dom::types::*', - 'dom::bindings::js::JS', - 'dom::bindings::utils::*', - 'dom::bindings::trace::Traceable', - 'dom::bindings::callback::*', - 'dom::bindings::error::{FailureUnknown, Fallible, Error, ErrorResult, throw_method_failed_with_details, throw_not_in_union}', - 'dom::bindings::conversions::*', - 'dom::bindings::codegen::*', #XXXjdm - 'dom::bindings::codegen::UnionTypes::*', #XXXjdm - 'dom::bindings::codegen::UnionConversions::*', #XXXjdm - 'script_task::{JSPageInfo, page_from_context}', - 'dom::bindings::proxyhandler', - 'dom::bindings::proxyhandler::*', - 'servo_util::str::DOMString', - 'servo_util::vec::zip_copies', - 'std::cast', - 'std::libc', - 'std::ptr', - 'std::vec', - 'std::str', - 'std::num', - 'std::unstable::intrinsics::uninit', - 'std::unstable::raw::Box', - ], - [], - curr) + curr = CGImports(curr, [ + 'js::{crust, JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', + 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}', + 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', + 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}', + 'js::{JSPROP_ENUMERATE, JSPROP_NATIVE_ACCESSORS, JSPROP_SHARED}', + 'js::{JSRESOLVE_ASSIGNING, JSRESOLVE_QUALIFIED}', + 'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}', + 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}', + 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}', + 'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}', + 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetPrototype}', + 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}', + 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}', + 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor}', + 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec}', + 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer}', + 'js::jsval::JSVal', + 'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}', + 'js::jsval::{NullValue, UndefinedValue}', + 'js::glue::{CallJitMethodOp, CallJitPropertyOp, CreateProxyHandler}', + 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}', + 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}', + 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}', + 'dom::types::*', + 'dom::bindings::js::JS', + 'dom::bindings::utils::{CreateDOMGlobal, CreateInterfaceObjects2}', + 'dom::bindings::utils::{ConstantSpec, cx_for_dom_object, Default}', + 'dom::bindings::utils::{dom_object_slot, DOM_OBJECT_SLOT, DOMClass}', + 'dom::bindings::utils::{DOMJSClass}', + 'dom::bindings::utils::{FindEnumStringIndex, GetArrayIndexFromId}', + 'dom::bindings::utils::{GetPropertyOnPrototype, GetProtoOrIfaceArray}', + 'dom::bindings::utils::{HasPropertyOnPrototype, IntVal}', + 'dom::bindings::utils::{jsid_to_str}', + 'dom::bindings::utils::{NativePropertyHooks}', + 'dom::bindings::utils::global_object_for_js_object', + 'dom::bindings::utils::{Reflectable}', + 'dom::bindings::utils::{squirrel_away_unique}', + 'dom::bindings::utils::{ThrowingConstructor, unwrap, unwrap_jsmanaged}', + 'dom::bindings::utils::{unwrap_object, VoidVal, with_gc_disabled}', + 'dom::bindings::utils::{with_gc_enabled, XrayResolveProperty}', + 'dom::bindings::trace::Traceable', + 'dom::bindings::callback::{CallbackContainer,CallbackInterface}', + 'dom::bindings::callback::{CallSetup,ExceptionHandling}', + 'dom::bindings::callback::{WrapCallThisObject}', + 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}', + 'dom::bindings::conversions::{Default, Empty}', + 'dom::bindings::codegen::*', + 'dom::bindings::codegen::UnionTypes::*', + 'dom::bindings::error::{FailureUnknown, Fallible, Error, ErrorResult}', + 'dom::bindings::error::{throw_method_failed_with_details}', + 'script_task::JSPageInfo', + 'dom::bindings::proxyhandler', + 'dom::bindings::proxyhandler::{_obj_toString, defineProperty}', + 'dom::bindings::proxyhandler::{FillPropertyDescriptor, GetExpandoObject}', + 'dom::bindings::proxyhandler::{getPropertyDescriptor}', + 'servo_util::str::DOMString', + 'servo_util::vec::zip_copies', + 'std::cast', + 'std::libc', + 'std::ptr', + 'std::vec', + 'std::str', + 'std::num', + 'std::unstable::raw::Box', + ]) # Add the auto-generated comment. curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) # Store the final result. self.root = curr - def declare(self): - return stripTrailingWhitespace(self.root.declare()) + def define(self): return stripTrailingWhitespace(self.root.define()) @@ -5747,7 +5193,7 @@ class CGCallback(CGClass): # the private method. argnames = [arg.name for arg in args] argnamesWithThis = ["s.GetContext()", "thisObjJS"] + argnames - argnamesWithoutThis = ["s.GetContext()", "JSVAL_TO_OBJECT(JSVAL_NULL)"] + argnames + argnamesWithoutThis = ["s.GetContext()", "ptr::null()"] + argnames # Now that we've recorded the argnames for our call to our private # method, insert our optional argument for deciding whether the # CallSetup should re-throw exceptions on aRv. @@ -5912,7 +5358,7 @@ class CallbackMember(CGNativeMember): if self.argCount > 0: replacements["argCount"] = self.argCountStr replacements["argvDecl"] = string.Template( - "let mut argv = vec::from_elem(${argCount}, JSVAL_VOID);\n" + "let mut argv = vec::from_elem(${argCount}, UndefinedValue());\n" ).substitute(replacements) else: # Avoid weird 0-sized arrays @@ -6001,7 +5447,7 @@ class CallbackMember(CGNativeMember): { 'result' : result, 'successCode' : "continue;" if arg.variadic else "break;", - 'jsvalRef' : "argv.handleAt(%s)" % jsvalIndex, + 'jsvalRef' : "argv[%s]" % jsvalIndex, 'jsvalHandle' : "argv.handleAt(%s)" % jsvalIndex, 'jsvalPtr': "&mut argv[%s]" % jsvalIndex, # XXXbz we don't have anything better to use for 'obj', @@ -6096,7 +5542,7 @@ class CallbackMethod(CallbackMember): CallbackMember.__init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException) def getRvalDecl(self): - return "let mut rval = JSVAL_VOID;\n" + return "let mut rval = UndefinedValue();\n" def getCall(self): replacements = { @@ -6163,9 +5609,9 @@ class CallbackOperationBase(CallbackMethod): return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp return ( 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback) != 0 };\n' - 'let mut callable = JSVAL_VOID;\n' + 'let mut callable = UndefinedValue();\n' 'if isCallable {\n' - ' callable = unsafe { RUST_OBJECT_TO_JSVAL(self.parent.callback) };\n' + ' callable = unsafe { ObjectValue(&*self.parent.callback) };\n' '} else {\n' '%s' '}\n' % CGIndenter(CGGeneric(getCallableFromProp)).define()) @@ -6249,74 +5695,23 @@ class GlobalGenRoots(): @staticmethod def PrototypeList(config): - # Prototype ID enum. protos = [d.name for d in config.getDescriptors(hasInterfacePrototypeObject=True)] - idEnum = CGNamespacedEnum('id', 'ID', protos, [0], deriving="Eq") - idEnum = CGList([idEnum]) - idEnum.append(CGGeneric(declare="pub static MAX_PROTO_CHAIN_LENGTH: uint = " + - str(config.maxProtoChainLength) + ";\n\n")) + return CGList([ + CGGeneric(AUTOGENERATED_WARNING_COMMENT), + CGGeneric("pub static MAX_PROTO_CHAIN_LENGTH: uint = %d;\n\n" % config.maxProtoChainLength), + CGNamespacedEnum('id', 'ID', protos, [0], deriving="Eq"), + ]) - # Wrap all of that in our namespaces. - #idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'], - # CGWrapper(idEnum, pre='\n')) - #idEnum = CGWrapper(idEnum, post='\n') - - curr = CGList([idEnum]) - - # Constructor ID enum. - constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True, - hasInterfacePrototypeObject=False)] - idEnum = CGNamespacedEnum('id', 'ID', constructors, [0]) - - # Wrap all of that in our namespaces. - idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'], - CGWrapper(idEnum, pre='\n')) - idEnum = CGWrapper(idEnum, post='\n') - - #XXXjdm Not sure what to do with the constructors right now - #curr.append(idEnum) - - #traitsDecl = CGGeneric(declare=""" -#template <prototypes::ID PrototypeID> -#struct PrototypeTraits; -# -#template <class ConcreteClass> -#struct PrototypeIDMap; -#""") - - #traitsDecl = CGNamespace.build(['mozilla', 'dom'], - # CGWrapper(traitsDecl, post='\n')) - - #curr.append(traitsDecl) - - # Add the auto-generated comment. - curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) - - # Done. - return curr @staticmethod def RegisterBindings(config): - # TODO - Generate the methods we want - curr = CGRegisterProtos(config) - - # Wrap all of that in our namespaces. - #curr = CGNamespace.build(['mozilla', 'dom'], - # CGWrapper(curr, post='\n')) - #curr = CGWrapper(curr, post='\n') - - # Add the includes - defineIncludes = [CGImports.getDeclarationFilename(desc.interface) - for desc in config.getDescriptors(hasInterfaceObject=True, - register=True)] - curr = CGImports([], [], ['dom::bindings::codegen', - 'script_task::JSPageInfo'], defineIncludes, curr) - - # Done. - return curr + return CGImports(CGRegisterProtos(config), [ + 'dom::bindings::codegen', + 'script_task::JSPageInfo', + ]) @staticmethod def InterfaceTypes(config): @@ -6327,7 +5722,7 @@ class GlobalGenRoots(): return "dom::%s" % descriptor.name.lower() descriptors = [d.name for d in config.getDescriptors(register=True, hasInterfaceObject=True)] - curr = CGList([CGGeneric(declare="pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors]) + curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors]) curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) return curr @@ -6335,7 +5730,7 @@ class GlobalGenRoots(): def BindingDeclarations(config): descriptors = [d.name for d in config.getDescriptors(register=True)] - curr = CGList([CGGeneric(declare="pub mod %sBinding;\n" % name) for name in descriptors]) + curr = CGList([CGGeneric("pub mod %sBinding;\n" % name) for name in descriptors]) curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) return curr @@ -6343,19 +5738,19 @@ class GlobalGenRoots(): def InheritTypes(config): descriptors = config.getDescriptors(register=True, hasInterfaceObject=True) - allprotos = [CGGeneric(declare="#[allow(unused_imports)];\n"), - CGGeneric(declare="use dom::types::*;\n"), - CGGeneric(declare="use dom::bindings::js::JS;\n"), - CGGeneric(declare="use dom::bindings::trace::Traceable;\n"), - CGGeneric(declare="use extra::serialize::{Encodable, Encoder};\n"), - CGGeneric(declare="use js::jsapi::JSTracer;\n\n")] + allprotos = [CGGeneric("#[allow(unused_imports)];\n"), + CGGeneric("use dom::types::*;\n"), + CGGeneric("use dom::bindings::js::JS;\n"), + CGGeneric("use dom::bindings::trace::Traceable;\n"), + CGGeneric("use extra::serialize::{Encodable, Encoder};\n"), + CGGeneric("use js::jsapi::JSTracer;\n\n")] for descriptor in descriptors: name = descriptor.name - protos = [CGGeneric(declare='pub trait %s {}\n' % (name + 'Base'))] + protos = [CGGeneric('pub trait %s {}\n' % (name + 'Base'))] for proto in descriptor.prototypeChain: - protos += [CGGeneric(declare='impl %s for %s {}\n' % (proto + 'Base', + protos += [CGGeneric('impl %s for %s {}\n' % (proto + 'Base', descriptor.concreteType))] - derived = [CGGeneric(declare='pub trait %s { fn %s(&self) -> bool; }\n' % + derived = [CGGeneric('pub trait %s { fn %s(&self) -> bool; }\n' % (name + 'Derived', 'is_' + name.lower()))] for protoName in descriptor.prototypeChain[1:-1]: protoDescriptor = config.getDescriptor(protoName) @@ -6368,10 +5763,10 @@ class GlobalGenRoots(): 'selfName': name + 'Derived', 'baseName': protoDescriptor.concreteType, 'parentName': protoDescriptor.prototypeChain[-2].lower()}) - derived += [CGGeneric(declare=delegate)] - derived += [CGGeneric(declare='\n')] + derived += [CGGeneric(delegate)] + derived += [CGGeneric('\n')] - cast = [CGGeneric(declare=string.Template('''pub trait ${castTraitName} { + cast = [CGGeneric(string.Template('''pub trait ${castTraitName} { fn from<T: ${fromBound}>(derived: &JS<T>) -> JS<Self> { unsafe { derived.clone().transmute() } } @@ -6385,9 +5780,9 @@ class GlobalGenRoots(): 'castTraitName': name + 'Cast', 'fromBound': name + 'Base', 'toBound': name + 'Derived'})), - CGGeneric(declare="impl %s for %s {}\n\n" % (name + 'Cast', name))] + CGGeneric("impl %s for %s {}\n\n" % (name + 'Cast', name))] - trace = [CGGeneric(declare=string.Template('''impl Traceable for ${name} { + trace = [CGGeneric(string.Template('''impl Traceable for ${name} { fn trace(&self, tracer: *mut JSTracer) { unsafe { self.encode(&mut *tracer); @@ -6442,45 +5837,43 @@ class GlobalGenRoots(): #stack[len(elements)].append(clazz) - curr = CGList([stack[0], curr], "\n") + curr = CGList([stack[0], curr, UnionConversions(config.getDescriptors())], "\n") #curr = CGHeaders([], [], includes, [], curr) # Add include guards. #curr = CGIncludeGuard('UnionTypes', curr) - curr = CGImports([], [], ['dom::bindings::js::JS', - 'dom::types::*'], [], curr) - - # Add the auto-generated comment. - curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) - - # Done. - return curr - - @staticmethod - def UnionConversions(config): - - unions = UnionConversions(config.getDescriptors()) - curr = unions - - # Wrap all of that in our namespaces. - #curr = CGNamespace.build(['mozilla', 'dom'], unions) - - curr = CGWrapper(curr, post='\n') - - #curr = CGHeaders([], [], ["nsDebug.h", "mozilla/dom/UnionTypes.h", "nsDOMQS.h"], [], curr) - - # Add include guards. - #curr = CGIncludeGuard('UnionConversions', curr) - - curr = CGImports([], [], ['dom::bindings::utils::unwrap_jsmanaged', - 'dom::bindings::codegen::UnionTypes::*', - 'dom::bindings::codegen::PrototypeList', - 'dom::bindings::conversions::JSValConvertible', - 'js::*', - 'js::jsapi::*', - 'js::glue::*'], [], curr) + curr = CGImports(curr, [ + 'dom::bindings::utils::unwrap_jsmanaged', + 'dom::bindings::codegen::PrototypeList', + 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}', + 'dom::bindings::error::throw_not_in_union', + 'dom::bindings::js::JS', + 'dom::types::*', + 'js::{crust, JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', + 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}', + 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', + 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}', + 'js::{JSPROP_ENUMERATE, JSPROP_NATIVE_ACCESSORS, JSPROP_SHARED}', + 'js::{JSRESOLVE_ASSIGNING, JSRESOLVE_QUALIFIED}', + 'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}', + 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}', + 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}', + 'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}', + 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetPrototype}', + 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}', + 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}', + 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor}', + 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec}', + 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer}', + 'js::jsval::JSVal', + 'js::jsval::PrivateValue', + 'js::glue::{CallJitMethodOp, CallJitPropertyOp, CreateProxyHandler}', + 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}', + 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}', + 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}', + ]) # Add the auto-generated comment. curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) diff --git a/src/components/script/dom/bindings/codegen/GlobalGen.py b/src/components/script/dom/bindings/codegen/GlobalGen.py index bd8b3d70793..90310fc9aff 100644 --- a/src/components/script/dom/bindings/codegen/GlobalGen.py +++ b/src/components/script/dom/bindings/codegen/GlobalGen.py @@ -17,21 +17,11 @@ from CodegenRust import GlobalGenRoots, replaceFileIfChanged # import Codegen in general, so we can set a variable on it import Codegen -def generate_file(config, name, action): +def generate_file(config, name): + filename = name + '.rs' root = getattr(GlobalGenRoots, name)(config) - if action is 'declare': - filename = name + '.rs' - code = root.declare() - elif action == 'declare+define': - filename = name + '.rs' - code = root.declare() - root2 = getattr(GlobalGenRoots, name)(config) - code += root2.define() - else: - assert action is 'define' - filename = name + '.rs' - code = root.define() + code = root.define() if replaceFileIfChanged(filename, code): print "Generating %s" % (filename) @@ -75,22 +65,21 @@ def main(): config = Configuration(configFile, parserResults) # Generate the prototype list. - generate_file(config, 'PrototypeList', 'declare+define') + generate_file(config, 'PrototypeList') # Generate the common code. - generate_file(config, 'RegisterBindings', 'declare+define') + generate_file(config, 'RegisterBindings') # Generate the type list. - generate_file(config, 'InterfaceTypes', 'declare+define') + generate_file(config, 'InterfaceTypes') # Generate the type list. - generate_file(config, 'InheritTypes', 'declare+define') + generate_file(config, 'InheritTypes') # Generate the module declarations. - generate_file(config, 'BindingDeclarations', 'declare+define') + generate_file(config, 'BindingDeclarations') - generate_file(config, 'UnionTypes', 'declare+define') - generate_file(config, 'UnionConversions', 'declare+define') + generate_file(config, 'UnionTypes') if __name__ == '__main__': main() diff --git a/src/components/script/dom/bindings/conversions.rs b/src/components/script/dom/bindings/conversions.rs index 116b74e8efa..311745603a5 100644 --- a/src/components/script/dom/bindings/conversions.rs +++ b/src/components/script/dom/bindings/conversions.rs @@ -2,114 +2,259 @@ * 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/. */ -use js::jsapi::{JSVal, JSBool, JSContext}; -use js::jsapi::{JS_ValueToInt64, JS_ValueToECMAInt32, JS_ValueToECMAUint32}; +use dom::bindings::js::JS; +use dom::bindings::utils::Reflectable; +use dom::bindings::utils::jsstring_to_str; +use servo_util::str::DOMString; + +use js::jsapi::{JSBool, JSContext}; +use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64}; +use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32}; use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean}; -use js::{JSVAL_FALSE, JSVAL_TRUE}; -use js::glue::{RUST_UINT_TO_JSVAL, RUST_DOUBLE_TO_JSVAL}; +use js::jsapi::{JS_NewUCStringCopyN, JS_ValueToString}; +use js::jsapi::{JS_WrapValue}; +use js::jsval::JSVal; +use js::jsval::{NullValue, BooleanValue, Int32Value, UInt32Value, StringValue}; +use js::jsval::ObjectValue; +use js::glue::RUST_JS_NumberValue; +use std::libc; + +pub trait ToJSValConvertible { + fn to_jsval(&self, cx: *JSContext) -> JSVal; +} -pub trait JSValConvertible { - fn to_jsval(&self) -> JSVal; - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<Self>; +pub trait FromJSValConvertible<T> { + fn from_jsval(cx: *JSContext, val: JSVal, option: T) -> Result<Self, ()>; } unsafe fn convert_from_jsval<T: Default>( cx: *JSContext, value: JSVal, - convert_fn: extern "C" unsafe fn(*JSContext, JSVal, *T) -> JSBool) -> Option<T> { + convert_fn: extern "C" unsafe fn(*JSContext, JSVal, *T) -> JSBool) -> Result<T, ()> { let mut ret = Default::default(); if convert_fn(cx, value, &mut ret as *mut T as *T) == 0 { - None + Err(()) } else { - Some(ret) + Ok(ret) + } +} + + +impl ToJSValConvertible for bool { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + BooleanValue(*self) + } +} + +impl FromJSValConvertible<()> for bool { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<bool, ()> { + let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) }; + result.map(|b| b != 0) + } +} + +impl ToJSValConvertible for i8 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + Int32Value(*self as i32) + } +} + +impl FromJSValConvertible<()> for i8 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<i8, ()> { + let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + result.map(|v| v as i8) + } +} + +impl ToJSValConvertible for u8 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + Int32Value(*self as i32) + } +} + +impl FromJSValConvertible<()> for u8 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<u8, ()> { + let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + result.map(|v| v as u8) + } +} + +impl ToJSValConvertible for i16 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + Int32Value(*self as i32) + } +} + +impl FromJSValConvertible<()> for i16 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<i16, ()> { + let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + result.map(|v| v as i16) + } +} + +impl ToJSValConvertible for u16 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + Int32Value(*self as i32) + } +} + +impl FromJSValConvertible<()> for u16 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<u16, ()> { + unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) } + } +} + +impl ToJSValConvertible for i32 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + Int32Value(*self) + } +} + +impl FromJSValConvertible<()> for i32 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<i32, ()> { + unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) } } } +impl ToJSValConvertible for u32 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + UInt32Value(*self) + } +} + +impl FromJSValConvertible<()> for u32 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<u32, ()> { + unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) } + } +} -impl JSValConvertible for i64 { - fn to_jsval(&self) -> JSVal { +impl ToJSValConvertible for i64 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { unsafe { - RUST_DOUBLE_TO_JSVAL(*self as f64) + RUST_JS_NumberValue(*self as f64) } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<i64> { +impl FromJSValConvertible<()> for i64 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<i64, ()> { unsafe { convert_from_jsval(cx, val, JS_ValueToInt64) } } } -impl JSValConvertible for u32 { - fn to_jsval(&self) -> JSVal { +impl ToJSValConvertible for u64 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { unsafe { - RUST_UINT_TO_JSVAL(*self) + RUST_JS_NumberValue(*self as f64) } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<u32> { - unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) } +impl FromJSValConvertible<()> for u64 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<u64, ()> { + unsafe { convert_from_jsval(cx, val, JS_ValueToUint64) } } } -impl JSValConvertible for i32 { - fn to_jsval(&self) -> JSVal { +impl ToJSValConvertible for f32 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { unsafe { - RUST_UINT_TO_JSVAL(*self as u32) + RUST_JS_NumberValue(*self as f64) } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<i32> { - unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) } +impl FromJSValConvertible<()> for f32 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<f32, ()> { + let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }; + result.map(|f| f as f32) } } -impl JSValConvertible for u16 { - fn to_jsval(&self) -> JSVal { +impl ToJSValConvertible for f64 { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { unsafe { - RUST_UINT_TO_JSVAL(*self as u32) + RUST_JS_NumberValue(*self) } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<u16> { - unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) } +impl FromJSValConvertible<()> for f64 { + fn from_jsval(cx: *JSContext, val: JSVal, _option: ()) -> Result<f64, ()> { + unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) } } } -impl JSValConvertible for bool { - fn to_jsval(&self) -> JSVal { - if *self { - JSVAL_TRUE - } else { - JSVAL_FALSE +impl ToJSValConvertible for DOMString { + fn to_jsval(&self, cx: *JSContext) -> JSVal { + unsafe { + let string_utf16 = self.to_utf16(); + let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t); + if jsstr.is_null() { + fail!("JS_NewUCStringCopyN failed"); + } + StringValue(&*jsstr) } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<bool> { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) }; - result.map(|b| b != 0) +#[deriving(Eq)] +pub enum StringificationBehavior { + Default, + Empty, +} + +impl Default for StringificationBehavior { + fn default() -> StringificationBehavior { + Default } } -impl JSValConvertible for f32 { - fn to_jsval(&self) -> JSVal { - unsafe { - RUST_DOUBLE_TO_JSVAL(*self as f64) +impl FromJSValConvertible<StringificationBehavior> for DOMString { + fn from_jsval(cx: *JSContext, value: JSVal, nullBehavior: StringificationBehavior) -> Result<DOMString, ()> { + if nullBehavior == Empty && value.is_null() { + Ok(~"") + } else { + let jsstr = unsafe { JS_ValueToString(cx, value) }; + if jsstr.is_null() { + debug!("JS_ValueToString failed"); + Err(()) + } else { + Ok(jsstring_to_str(cx, jsstr)) + } } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<f32> { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }; - result.map(|f| f as f32) +impl<T: Reflectable> ToJSValConvertible for JS<T> { + fn to_jsval(&self, cx: *JSContext) -> JSVal { + let obj = self.reflector().get_jsobject(); + assert!(obj.is_not_null()); + let mut value = ObjectValue(unsafe { &*obj }); + if unsafe { JS_WrapValue(cx, &mut value as *mut JSVal as *JSVal) } == 0 { + fail!("JS_WrapValue failed."); + } + value } } -impl JSValConvertible for f64 { - fn to_jsval(&self) -> JSVal { - unsafe { - RUST_DOUBLE_TO_JSVAL(*self as f64) +impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> { + fn to_jsval(&self, cx: *JSContext) -> JSVal { + match self { + &Some(ref value) => value.to_jsval(cx), + &None => NullValue(), } } +} - fn from_jsval(cx: *JSContext, val: JSVal) -> Option<f64> { - unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) } +impl<X: Default, T: FromJSValConvertible<X>> FromJSValConvertible<()> for Option<T> { + fn from_jsval(cx: *JSContext, value: JSVal, _: ()) -> Result<Option<T>, ()> { + if value.is_null_or_undefined() { + Ok(None) + } else { + let option: X = Default::default(); + let result: Result<T, ()> = FromJSValConvertible::from_jsval(cx, value, option); + result.map(Some) + } } } diff --git a/src/components/script/dom/bindings/js.rs b/src/components/script/dom/bindings/js.rs index 4aaf3506ae8..9f8e44ba06f 100644 --- a/src/components/script/dom/bindings/js.rs +++ b/src/components/script/dom/bindings/js.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::utils::{Reflector, Reflectable}; -use dom::window; +use dom::window::Window; use js::jsapi::{JSContext, JSObject}; use layout_interface::TrustedNodeAddress; @@ -31,12 +31,11 @@ impl <T> Clone for JS<T> { impl<T: Reflectable> JS<T> { pub fn new(mut obj: ~T, - window: &window::Window, - wrap_fn: extern "Rust" fn(*JSContext, *JSObject, ~T) -> *JSObject) -> JS<T> { - let cx = window.get_cx(); - let scope = window.reflector().get_jsobject(); + window: &JS<Window>, + wrap_fn: extern "Rust" fn(*JSContext, &JS<Window>, ~T) -> *JSObject) -> JS<T> { + let cx = window.get().get_cx(); let raw: *mut T = &mut *obj; - if wrap_fn(cx, scope, obj).is_null() { + if wrap_fn(cx, window, obj).is_null() { fail!("Could not eagerly wrap object"); } JS { diff --git a/src/components/script/dom/bindings/proxyhandler.rs b/src/components/script/dom/bindings/proxyhandler.rs index 2f8267d4f29..aaf75a7bc7a 100644 --- a/src/components/script/dom/bindings/proxyhandler.rs +++ b/src/components/script/dom/bindings/proxyhandler.rs @@ -6,7 +6,8 @@ use dom::bindings::utils::is_dom_proxy; use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar}; use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free}; use js::jsapi::{JSBool, JS_DefinePropertyById, JS_NewObjectWithGivenProto}; -use js::glue::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra, RUST_OBJECT_TO_JSVAL}; +use js::jsval::ObjectValue; +use js::glue::GetProxyExtra; use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler}; use js::glue::InvokeGetOwnPropertyDescriptor; use js::crust::{JS_StrictPropertyStub}; @@ -97,10 +98,10 @@ pub fn GetExpandoObject(obj: *JSObject) -> *JSObject { unsafe { assert!(is_dom_proxy(obj)); let val = GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); - if RUST_JSVAL_IS_VOID(val) == 1 { + if val.is_undefined() { ptr::null() } else { - RUST_JSVAL_TO_OBJECT(val) + val.to_object() } } } @@ -116,7 +117,7 @@ pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject { return ptr::null(); } - SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, RUST_OBJECT_TO_JSVAL(expando)); + SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(&*expando)); } return expando; } diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs index 22f10b65c47..54e518fcc97 100644 --- a/src/components/script/dom/bindings/utils.rs +++ b/src/components/script/dom/bindings/utils.rs @@ -19,41 +19,30 @@ use std::str; use std::vec; use std::unstable::raw::Box; use js::glue::*; -use js::glue::{RUST_OBJECT_TO_JSVAL}; use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction}; -use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo}; +use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo}; use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength}; use js::jsapi::{JS_ObjectIsRegExp, JS_ObjectIsDate}; use js::jsapi::{JS_InternString, JS_GetFunctionObject}; use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject}; -use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty}; +use js::jsapi::{JS_DefineFunctions, JS_DefineProperty}; use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot}; use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative}; -use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor}; +use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSPropertyDescriptor}; use js::jsapi::{JS_NewGlobalObject, JS_InitStandardClasses}; use js::jsapi::{JSString}; use js::jsapi::{JS_AllowGC, JS_InhibitGC}; use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType; -use js::{JSPROP_ENUMERATE, JSVAL_NULL, JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS}; +use js::jsval::JSVal; +use js::jsval::{PrivateValue, ObjectValue, NullValue, Int32Value}; +use js::jsval::{UInt32Value, DoubleValue, BooleanValue, UndefinedValue}; +use js::{JSPROP_ENUMERATE, JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS}; use js::{JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER}; -use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE}; +use js::JSPROP_SETTER; use js::{JSFUN_CONSTRUCTOR, JSPROP_READONLY}; use js; -mod jsval { - use js::glue::{RUST_JSVAL_IS_NULL, RUST_JSVAL_IS_VOID}; - use js::jsapi::JSVal; - - pub fn is_null(v: JSVal) -> bool { - unsafe { RUST_JSVAL_IS_NULL(v) == 1 } - } - - pub fn is_undefined(v: JSVal) -> bool { - unsafe { RUST_JSVAL_IS_VOID(v) == 1 } - } -} - pub struct GlobalStaticData { proxy_handlers: HashMap<uint, *libc::c_void>, attribute_ids: HashMap<uint, ~[jsid]>, @@ -96,7 +85,7 @@ pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 { pub unsafe fn unwrap<T>(obj: *JSObject) -> T { let slot = dom_object_slot(obj); let val = JS_GetReservedSlot(obj, slot); - cast::transmute(RUST_JSVAL_TO_PRIVATE(val)) + cast::transmute(val.to_private()) } pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> { @@ -142,7 +131,7 @@ pub fn unwrap_jsmanaged<T: Reflectable>(obj: *JSObject, pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> { unsafe { - let obj = RUST_JSVAL_TO_OBJECT(*val); + let obj = (*val).to_object(); unwrap_object(obj, proto_id, proto_depth) } } @@ -172,59 +161,6 @@ pub fn jsid_to_str(cx: *JSContext, id: jsid) -> DOMString { } } -#[deriving(Eq)] -pub enum StringificationBehavior { - Default, - Empty, -} - -pub fn jsval_to_str(cx: *JSContext, v: JSVal, - nullBehavior: StringificationBehavior) -> Result<DOMString, ()> { - if jsval::is_null(v) && nullBehavior == Empty { - Ok(~"") - } else { - let jsstr = unsafe { JS_ValueToString(cx, v) }; - if jsstr.is_null() { - debug!("JS_ValueToString failed"); - Err(()) - } else { - Ok(jsstring_to_str(cx, jsstr)) - } - } -} - -pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>, ()> { - if jsval::is_null(v) || jsval::is_undefined(v) { - Ok(None) - } else { - let jsstr = unsafe { JS_ValueToString(cx, v) }; - if jsstr.is_null() { - debug!("JS_ValueToString failed"); - Err(()) - } else { - Ok(Some(jsstring_to_str(cx, jsstr))) - } - } -} - -pub unsafe fn str_to_jsval(cx: *JSContext, string: DOMString) -> JSVal { - let string_utf16 = string.to_utf16(); - let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t); - if jsstr.is_null() { - // FIXME: is there something else we should do on failure? - JSVAL_NULL - } else { - RUST_STRING_TO_JSVAL(jsstr) - } -} - -pub unsafe fn domstring_to_jsval(cx: *JSContext, string: Option<DOMString>) -> JSVal { - match string { - None => JSVAL_NULL, - Some(s) => str_to_jsval(cx, s), - } -} - // We use slot 0 for holding the raw object. This is safe for both // globals and non-globals. pub static DOM_OBJECT_SLOT: uint = 0; @@ -310,7 +246,7 @@ pub struct DOMJSClass { pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject { unsafe { /*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/ - cast::transmute(RUST_JSVAL_TO_PRIVATE(JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT))) + cast::transmute(JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT).to_private()) } } @@ -335,7 +271,7 @@ pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSO unsafe { JS_SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT, - RUST_PRIVATE_TO_JSVAL(domClass as *libc::c_void)); + PrivateValue(domClass as *libc::c_void)); } } @@ -394,7 +330,7 @@ fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject, } if alreadyDefined == 0 && - JS_DefineProperty(cx, receiver, name, RUST_OBJECT_TO_JSVAL(constructor), + JS_DefineProperty(cx, receiver, name, ObjectValue(&*constructor), None, None, 0) == 0 { return ptr::null(); } @@ -412,13 +348,12 @@ fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) -> return true; } let jsval = match spec.value { - NullVal => JSVAL_NULL, - IntVal(i) => RUST_INT_TO_JSVAL(i), - UintVal(u) => RUST_UINT_TO_JSVAL(u), - DoubleVal(d) => RUST_DOUBLE_TO_JSVAL(d), - BoolVal(b) if b => JSVAL_TRUE, - BoolVal(_) => JSVAL_FALSE, - VoidVal => JSVAL_VOID + NullVal => NullValue(), + IntVal(i) => Int32Value(i), + UintVal(u) => UInt32Value(u), + DoubleVal(d) => DoubleValue(d), + BoolVal(b) => BooleanValue(b), + VoidVal => UndefinedValue(), }; if JS_DefineProperty(cx, obj, spec.name, jsval, None, @@ -482,7 +417,7 @@ pub fn initialize_global(global: *JSObject) { let box_ = squirrel_away_unboxed(protoArray); JS_SetReservedSlot(global, DOM_PROTOTYPE_SLOT, - RUST_PRIVATE_TO_JSVAL(box_ as *libc::c_void)); + PrivateValue(box_ as *libc::c_void)); } } @@ -493,8 +428,8 @@ pub trait Reflectable { pub fn reflect_dom_object<T: Reflectable> (obj: ~T, - window: &window::Window, - wrap_fn: extern "Rust" fn(*JSContext, *JSObject, ~T) -> *JSObject) + window: &JS<window::Window>, + wrap_fn: extern "Rust" fn(*JSContext, &JS<window::Window>, ~T) -> *JSObject) -> JS<T> { JS::new(obj, window, wrap_fn) } @@ -525,16 +460,6 @@ impl Reflector { } } -pub fn GetReflector(cx: *JSContext, reflector: &Reflector, - vp: *mut JSVal) -> JSBool { - let obj = reflector.get_jsobject(); - assert!(obj.is_not_null()); - unsafe { - *vp = RUST_OBJECT_TO_JSVAL(obj); - return JS_WrapValue(cx, cast::transmute(vp)); - } -} - pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool, vp: *JSVal) -> bool { unsafe { @@ -720,32 +645,30 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject { } /// Returns the global object of the realm that the given JS object was created in. -fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> { +pub fn global_object_for_js_object(obj: *JSObject) -> JS<window::Window> { unsafe { let global = GetGlobalForObjectCrossCompartment(obj); let clasp = JS_GetClass(global); assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0); // FIXME(jdm): Either don't hardcode or sanity assert prototype stuff. - match unwrap_object::<*Box<window::Window>>(global, PrototypeList::id::Window, 1) { - Ok(win) => win, + match unwrap_object::<*mut Box<window::Window>>(global, PrototypeList::id::Window, 1) { + Ok(win) => JS::from_box(win), Err(_) => fail!("found DOM global that doesn't unwrap to Window"), } } } fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext { - unsafe { - let win = global_object_for_js_object(obj); - let js_info = (*win).data.page().js_info(); - match *js_info.get() { - Some(ref info) => info.js_context.borrow().ptr, - None => fail!("no JS context for DOM global") - } + let win = global_object_for_js_object(obj); + let js_info = win.get().page().js_info(); + match *js_info.get() { + Some(ref info) => info.js_context.borrow().ptr, + None => fail!("no JS context for DOM global") } } /// Returns the global object of the realm that the given DOM object was created in. -pub fn global_object_for_dom_object<T: Reflectable>(obj: &T) -> *Box<window::Window> { +pub fn global_object_for_dom_object<T: Reflectable>(obj: &T) -> JS<window::Window> { global_object_for_js_object(obj.reflector().get_jsobject()) } diff --git a/src/components/script/dom/blob.rs b/src/components/script/dom/blob.rs index 87034e5107e..f1c4f677cf3 100644 --- a/src/components/script/dom/blob.rs +++ b/src/components/script/dom/blob.rs @@ -25,7 +25,7 @@ impl Blob { pub fn new(window: &JS<Window>) -> JS<Blob> { reflect_dom_object(~Blob::new_inherited(window.clone()), - window.get(), + window, BlobBinding::Wrap) } } diff --git a/src/components/script/dom/clientrect.rs b/src/components/script/dom/clientrect.rs index e4fd8716c26..2e68044c115 100644 --- a/src/components/script/dom/clientrect.rs +++ b/src/components/script/dom/clientrect.rs @@ -36,7 +36,7 @@ impl ClientRect { top: Au, bottom: Au, left: Au, right: Au) -> JS<ClientRect> { let rect = ClientRect::new_inherited(window.clone(), top, bottom, left, right); - reflect_dom_object(~rect, window.get(), ClientRectBinding::Wrap) + reflect_dom_object(~rect, window, ClientRectBinding::Wrap) } diff --git a/src/components/script/dom/clientrectlist.rs b/src/components/script/dom/clientrectlist.rs index bae001379ae..3d8ade6031f 100644 --- a/src/components/script/dom/clientrectlist.rs +++ b/src/components/script/dom/clientrectlist.rs @@ -28,7 +28,7 @@ impl ClientRectList { pub fn new(window: &JS<Window>, rects: ~[JS<ClientRect>]) -> JS<ClientRectList> { reflect_dom_object(~ClientRectList::new_inherited(window.clone(), rects), - window.get(), ClientRectListBinding::Wrap) + window, ClientRectListBinding::Wrap) } pub fn Length(&self) -> u32 { diff --git a/src/components/script/dom/console.rs b/src/components/script/dom/console.rs index 3c5a219b39c..8a7a935e918 100644 --- a/src/components/script/dom/console.rs +++ b/src/components/script/dom/console.rs @@ -20,7 +20,7 @@ impl Console { } } - pub fn new(window: &Window) -> JS<Console> { + pub fn new(window: &JS<Window>) -> JS<Console> { reflect_dom_object(~Console::new_inherited(), window, ConsoleBinding::Wrap) } diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index 5994f653f18..07660e30e88 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -21,6 +21,7 @@ use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId}; use dom::event::Event; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlcollection::HTMLCollection; +use dom::nodelist::NodeList; use dom::htmlelement::HTMLElement; use dom::htmlheadelement::HTMLHeadElement; use dom::htmlhtmlelement::HTMLHtmlElement; @@ -34,7 +35,7 @@ use dom::window::Window; use html::hubbub_html_parser::build_element_from_tag; use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks}; use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage}; -use servo_util::namespace::Null; +use servo_util::namespace::{Namespace, Null}; use servo_util::str::DOMString; use extra::url::{Url, from_str}; @@ -86,10 +87,10 @@ impl Document { pub fn reflect_document<D: Reflectable+DocumentBase> (document: ~D, window: &JS<Window>, - wrap_fn: extern "Rust" fn(*JSContext, *JSObject, ~D) -> *JSObject) + wrap_fn: extern "Rust" fn(*JSContext, &JS<Window>, ~D) -> *JSObject) -> JS<D> { assert!(document.reflector().get_jsobject().is_null()); - let raw_doc = reflect_dom_object(document, window.get(), wrap_fn); + let raw_doc = reflect_dom_object(document, window, wrap_fn); assert!(raw_doc.reflector().get_jsobject().is_not_null()); let document = DocumentCast::from(&raw_doc); @@ -211,8 +212,22 @@ impl Document { } // http://dom.spec.whatwg.org/#dom-document-getelementsbytagname - pub fn GetElementsByTagName(&self, tag: DOMString) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| elem.tag_name == tag) + pub fn GetElementsByTagName(&self, abstract_self: &JS<Document>, tag_name: DOMString) -> JS<HTMLCollection> { + HTMLCollection::by_tag_name(&self.window, &NodeCast::from(abstract_self), tag_name) + } + + // http://dom.spec.whatwg.org/#dom-document-getelementsbytagnamens + pub fn GetElementsByTagNameNS(&self, abstract_self: &JS<Document>, maybe_ns: Option<DOMString>, tag_name: DOMString) -> JS<HTMLCollection> { + let namespace = match maybe_ns { + Some(namespace) => Namespace::from_str(namespace), + None => Null + }; + HTMLCollection::by_tag_name_ns(&self.window, &NodeCast::from(abstract_self), tag_name, namespace) + } + + // http://dom.spec.whatwg.org/#dom-document-getelementsbyclassname + pub fn GetElementsByClassName(&self, abstract_self: &JS<Document>, classes: DOMString) -> JS<HTMLCollection> { + HTMLCollection::by_class_name(&self.window, &NodeCast::from(abstract_self), classes) } // http://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid @@ -403,69 +418,89 @@ impl Document { } // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-getelementsbyname - pub fn GetElementsByName(&self, name: DOMString) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| { - elem.get_attribute(Null, "name").map_default(false, |attr| { + pub fn GetElementsByName(&self, name: DOMString) -> JS<NodeList> { + self.createNodeList(|node| { + if !node.is_element() { + return false; + } + + let element: JS<Element> = ElementCast::to(node); + element.get().get_attribute(Null, "name").map_default(false, |attr| { attr.get().value_ref() == name }) }) } - pub fn Images(&self) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| "img" == elem.tag_name) + pub fn Images(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + HTMLCollection::by_tag_name(&self.window, &NodeCast::from(abstract_self), ~"img") } - pub fn Embeds(&self) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| "embed" == elem.tag_name) + pub fn Embeds(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + HTMLCollection::by_tag_name(&self.window, &NodeCast::from(abstract_self), ~"embed") } - pub fn Plugins(&self) -> JS<HTMLCollection> { - self.Embeds() + pub fn Plugins(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + self.Embeds(abstract_self) } - pub fn Links(&self) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| { - ("a" == elem.tag_name || "area" == elem.tag_name) && - elem.get_attribute(Null, "href").is_some() + pub fn Links(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + HTMLCollection::create(&self.window, &NodeCast::from(abstract_self), |elem| { + ("a" == elem.get().tag_name || "area" == elem.get().tag_name) && + elem.get().get_attribute(Null, "href").is_some() }) } - pub fn Forms(&self) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| "form" == elem.tag_name) + pub fn Forms(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + HTMLCollection::by_tag_name(&self.window, &NodeCast::from(abstract_self), ~"form") } - pub fn Scripts(&self) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| "script" == elem.tag_name) + pub fn Scripts(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + HTMLCollection::by_tag_name(&self.window, &NodeCast::from(abstract_self), ~"script") } - pub fn Anchors(&self) -> JS<HTMLCollection> { - self.createHTMLCollection(|elem| { - "a" == elem.tag_name && elem.get_attribute(Null, "name").is_some() + pub fn Anchors(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1847 + HTMLCollection::create(&self.window, &NodeCast::from(abstract_self), |elem| { + "a" == elem.get().tag_name && elem.get().get_attribute(Null, "name").is_some() }) } - pub fn Applets(&self) -> JS<HTMLCollection> { + pub fn Applets(&self, abstract_self: &JS<Document>) -> JS<HTMLCollection> { // FIXME: This should be return OBJECT elements containing applets. - self.createHTMLCollection(|elem| "applet" == elem.tag_name) + HTMLCollection::by_tag_name(&self.window, &NodeCast::from(abstract_self), ~"applet") } - pub fn createHTMLCollection(&self, callback: |elem: &Element| -> bool) -> JS<HTMLCollection> { - let mut elements = ~[]; + pub fn create_collection<T>(&self, callback: |elem: &JS<Node>| -> Option<JS<T>>) -> ~[JS<T>] { + let mut nodes = ~[]; match self.GetDocumentElement() { None => {}, Some(root) => { let root: JS<Node> = NodeCast::from(&root); for child in root.traverse_preorder() { - if child.is_element() { - let elem: JS<Element> = ElementCast::to(&child); - if callback(elem.get()) { - elements.push(elem); - } + match callback(&child) { + Some(node) => nodes.push(node), + None => (), } } } } - HTMLCollection::new(&self.window, elements) + nodes + } + + pub fn createNodeList(&self, callback: |node: &JS<Node>| -> bool) -> JS<NodeList> { + NodeList::new_simple_list(&self.window, self.create_collection(|node| { + if !callback(node) { + return None; + } + + Some(node.clone()) + })) } pub fn content_changed(&self) { diff --git a/src/components/script/dom/domexception.rs b/src/components/script/dom/domexception.rs index f6eb1751adc..9d8142ac938 100644 --- a/src/components/script/dom/domexception.rs +++ b/src/components/script/dom/domexception.rs @@ -48,7 +48,7 @@ impl DOMException { } } - pub fn new(window: &Window, code: DOMErrorName) -> JS<DOMException> { + pub fn new(window: &JS<Window>, code: DOMErrorName) -> JS<DOMException> { reflect_dom_object(~DOMException::new_inherited(code), window, DOMExceptionBinding::Wrap) } } diff --git a/src/components/script/dom/domimplementation.rs b/src/components/script/dom/domimplementation.rs index 47ba1026dec..5a11d0119d4 100644 --- a/src/components/script/dom/domimplementation.rs +++ b/src/components/script/dom/domimplementation.rs @@ -34,7 +34,7 @@ impl DOMImplementation { } pub fn new(owner: &JS<Window>) -> JS<DOMImplementation> { - reflect_dom_object(~DOMImplementation::new_inherited(owner.clone()), owner.get(), + reflect_dom_object(~DOMImplementation::new_inherited(owner.clone()), owner, DOMImplementationBinding::Wrap) } } diff --git a/src/components/script/dom/domparser.rs b/src/components/script/dom/domparser.rs index 3e20ea2941a..1ab00d1f14d 100644 --- a/src/components/script/dom/domparser.rs +++ b/src/components/script/dom/domparser.rs @@ -26,7 +26,7 @@ impl DOMParser { } pub fn new(owner: &JS<Window>) -> JS<DOMParser> { - reflect_dom_object(~DOMParser::new_inherited(owner.clone()), owner.get(), + reflect_dom_object(~DOMParser::new_inherited(owner.clone()), owner, DOMParserBinding::Wrap) } diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 2805ea8c25e..95e4e7f9af9 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -220,7 +220,7 @@ impl Element { None => { let doc = self.node.owner_doc(); let doc = doc.get(); - let new_attr = Attr::new_ns(doc.window.get(), local_name.clone(), value.clone(), + let new_attr = Attr::new_ns(&doc.window, local_name.clone(), value.clone(), name.clone(), namespace.clone(), prefix); self.attrs.push(new_attr); @@ -370,6 +370,13 @@ impl Element { _ => false } } + + pub fn has_class(&self, name: &str) -> bool { + // FIXME: https://github.com/mozilla/servo/issues/1840 + let class_names = self.get_string_attribute("class"); + let mut classes = class_names.split(' '); + classes.any(|class| name == class) + } } // http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes @@ -503,25 +510,27 @@ impl Element { self.GetAttributeNS(namespace, local_name).is_some() } - // http://dom.spec.whatwg.org/#dom-element-getelementsbytagname - pub fn GetElementsByTagName(&self, _localname: DOMString) -> JS<HTMLCollection> { - // FIXME: stub - https://github.com/mozilla/servo/issues/1660 + pub fn GetElementsByTagName(&self, abstract_self: &JS<Element>, localname: DOMString) -> JS<HTMLCollection> { let doc = self.node.owner_doc(); - HTMLCollection::new(&doc.get().window, ~[]) + let doc = doc.get(); + HTMLCollection::by_tag_name(&doc.window, &NodeCast::from(abstract_self), localname) } - // http://dom.spec.whatwg.org/#dom-element-getelementsbytagnamens - pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<JS<HTMLCollection>> { - // FIXME: stub - https://github.com/mozilla/servo/issues/1660 + pub fn GetElementsByTagNameNS(&self, abstract_self: &JS<Element>, maybe_ns: Option<DOMString>, + localname: DOMString) -> JS<HTMLCollection> { let doc = self.node.owner_doc(); - Ok(HTMLCollection::new(&doc.get().window, ~[])) + let doc = doc.get(); + let namespace = match maybe_ns { + Some(namespace) => Namespace::from_str(namespace), + None => Null + }; + HTMLCollection::by_tag_name_ns(&doc.window, &NodeCast::from(abstract_self), localname, namespace) } - // http://dom.spec.whatwg.org/#dom-element-getelementsbyclassname - pub fn GetElementsByClassName(&self, _names: DOMString) -> JS<HTMLCollection> { - // FIXME: stub - https://github.com/mozilla/servo/issues/1660 + pub fn GetElementsByClassName(&self, abstract_self: &JS<Element>, classes: DOMString) -> JS<HTMLCollection> { let doc = self.node.owner_doc(); - HTMLCollection::new(&doc.get().window, ~[]) + let doc = doc.get(); + HTMLCollection::by_class_name(&doc.window, &NodeCast::from(abstract_self), classes) } // http://dev.w3.org/csswg/cssom-view/#dom-element-getclientrects diff --git a/src/components/script/dom/event.rs b/src/components/script/dom/event.rs index 4c3fb0e5b5b..6b612b4a220 100644 --- a/src/components/script/dom/event.rs +++ b/src/components/script/dom/event.rs @@ -77,7 +77,7 @@ impl Event { pub fn new(window: &JS<Window>) -> JS<Event> { reflect_dom_object(~Event::new_inherited(HTMLEventTypeId), - window.get(), + window, EventBinding::Wrap) } diff --git a/src/components/script/dom/eventdispatcher.rs b/src/components/script/dom/eventdispatcher.rs index c22ef7716c1..699dc1f68b5 100644 --- a/src/components/script/dom/eventdispatcher.rs +++ b/src/components/script/dom/eventdispatcher.rs @@ -17,10 +17,9 @@ pub fn dispatch_event(target: &JS<EventTarget>, { let event = event.get_mut(); - event.target = match pseudo_target { - Some(pseudo_target) => Some(pseudo_target), - None => Some(target.clone()) - }; + event.target = pseudo_target.or_else(|| { + Some(target.clone()) + }); event.dispatching = true; } diff --git a/src/components/script/dom/formdata.rs b/src/components/script/dom/formdata.rs index 011722ea275..bd4c7a03d6e 100644 --- a/src/components/script/dom/formdata.rs +++ b/src/components/script/dom/formdata.rs @@ -38,7 +38,7 @@ impl FormData { } pub fn new(form: Option<JS<HTMLFormElement>>, window: &JS<Window>) -> JS<FormData> { - reflect_dom_object(~FormData::new_inherited(form, window.clone()), window.get(), FormDataBinding::Wrap) + reflect_dom_object(~FormData::new_inherited(form, window.clone()), window, FormDataBinding::Wrap) } pub fn Constructor(window: &JS<Window>, form: Option<JS<HTMLFormElement>>) diff --git a/src/components/script/dom/htmlcollection.rs b/src/components/script/dom/htmlcollection.rs index 0ad4d94d357..96e04d46d3b 100644 --- a/src/components/script/dom/htmlcollection.rs +++ b/src/components/script/dom/htmlcollection.rs @@ -2,18 +2,16 @@ * 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/. */ +use dom::bindings::codegen::InheritTypes::{ElementCast}; use dom::bindings::codegen::HTMLCollectionBinding; use dom::bindings::js::JS; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; -use dom::bindings::error::Fallible; use dom::element::Element; +use dom::node::{Node, NodeHelpers}; use dom::window::Window; +use servo_util::namespace::Namespace; use servo_util::str::DOMString; -use js::jsapi::{JSObject, JSContext}; - -use std::ptr; - #[deriving(Encodable)] pub struct HTMLCollection { elements: ~[JS<Element>], @@ -32,13 +30,46 @@ impl HTMLCollection { pub fn new(window: &JS<Window>, elements: ~[JS<Element>]) -> JS<HTMLCollection> { reflect_dom_object(~HTMLCollection::new_inherited(window.clone(), elements), - window.get(), HTMLCollectionBinding::Wrap) + window, HTMLCollectionBinding::Wrap) + } +} + +impl HTMLCollection { + pub fn create(window: &JS<Window>, root: &JS<Node>, predicate: |elem: &JS<Element>| -> bool) -> JS<HTMLCollection> { + let mut elements = ~[]; + for child in root.traverse_preorder() { + if child.is_element() { + let elem: JS<Element> = ElementCast::to(&child); + if predicate(&elem) { + elements.push(elem); + } + } + } + HTMLCollection::new(window, elements) + } + + pub fn by_tag_name(window: &JS<Window>, root: &JS<Node>, tag_name: DOMString) -> JS<HTMLCollection> { + HTMLCollection::create(window, root, |elem| elem.get().tag_name == tag_name) + } + + pub fn by_tag_name_ns(window: &JS<Window>, root: &JS<Node>, tag_name: DOMString, namespace: Namespace) -> JS<HTMLCollection> { + HTMLCollection::create(window, root, |elem| elem.get().namespace == namespace && elem.get().tag_name == tag_name) } - + + pub fn by_class_name(window: &JS<Window>, root: &JS<Node>, classes: DOMString) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1840 + let classes: ~[&str] = classes.split(' ').collect(); + HTMLCollection::create(window, root, |elem| classes.iter().all(|class| elem.get().has_class(*class))) + } +} + +impl HTMLCollection { + // http://dom.spec.whatwg.org/#dom-htmlcollection-length pub fn Length(&self) -> u32 { self.elements.len() as u32 } + // http://dom.spec.whatwg.org/#dom-htmlcollection-item pub fn Item(&self, index: u32) -> Option<JS<Element>> { if index < self.Length() { Some(self.elements[index].clone()) @@ -47,17 +78,40 @@ impl HTMLCollection { } } - pub fn NamedItem(&self, _cx: *JSContext, _name: DOMString) -> Fallible<*JSObject> { - Ok(ptr::null()) + // http://dom.spec.whatwg.org/#dom-htmlcollection-nameditem + pub fn NamedItem(&self, key: DOMString) -> Option<JS<Element>> { + // Step 1. + if key.is_empty() { + return None; + } + + // Step 2. + self.elements.iter().find(|elem| { + let elem = elem.get(); + elem.get_string_attribute("name") == key || elem.get_string_attribute("id") == key + }).map(|maybe_elem| maybe_elem.clone()) } +} +impl HTMLCollection { pub fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<JS<Element>> { - *found = true; - self.Item(index) + let maybe_elem = self.Item(index); + *found = maybe_elem.is_some(); + maybe_elem } - pub fn NamedGetter(&self, _cx: *JSContext, _name: Option<DOMString>, _found: &mut bool) -> Fallible<*JSObject> { - Ok(ptr::null()) + pub fn NamedGetter(&self, maybe_name: Option<DOMString>, found: &mut bool) -> Option<JS<Element>> { + match maybe_name { + Some(name) => { + let maybe_elem = self.NamedItem(name); + *found = maybe_elem.is_some(); + maybe_elem + }, + None => { + *found = false; + None + } + } } } diff --git a/src/components/script/dom/htmldatalistelement.rs b/src/components/script/dom/htmldatalistelement.rs index 6cd888029c2..ef3f91f1702 100644 --- a/src/components/script/dom/htmldatalistelement.rs +++ b/src/components/script/dom/htmldatalistelement.rs @@ -42,6 +42,7 @@ impl HTMLDataListElement { impl HTMLDataListElement { pub fn Options(&self) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1842 let doc = self.htmlelement.element.node.owner_doc(); let doc = doc.get(); HTMLCollection::new(&doc.window, ~[]) diff --git a/src/components/script/dom/htmlelement.rs b/src/components/script/dom/htmlelement.rs index b27afdfff2e..8464d23aec0 100644 --- a/src/components/script/dom/htmlelement.rs +++ b/src/components/script/dom/htmlelement.rs @@ -10,8 +10,8 @@ use dom::document::Document; use dom::element::{Element, ElementTypeId, HTMLElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::node::{Node, ElementNodeTypeId}; -use js::jsapi::{JSContext, JSVal}; -use js::JSVAL_NULL; +use js::jsapi::JSContext; +use js::jsval::{JSVal, NullValue}; use servo_util::namespace; use servo_util::str::DOMString; @@ -66,7 +66,7 @@ impl HTMLElement { } pub fn GetItemValue(&self, _cx: *JSContext) -> Fallible<JSVal> { - Ok(JSVAL_NULL) + Ok(NullValue()) } pub fn SetItemValue(&mut self, _cx: *JSContext, _val: JSVal) -> ErrorResult { diff --git a/src/components/script/dom/htmlfieldsetelement.rs b/src/components/script/dom/htmlfieldsetelement.rs index cdfc6eab402..4dec639d041 100644 --- a/src/components/script/dom/htmlfieldsetelement.rs +++ b/src/components/script/dom/htmlfieldsetelement.rs @@ -69,6 +69,7 @@ impl HTMLFieldSetElement { } pub fn Elements(&self) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1843 let doc = self.htmlelement.element.node.owner_doc(); let doc = doc.get(); HTMLCollection::new(&doc.window, ~[]) diff --git a/src/components/script/dom/htmlformelement.rs b/src/components/script/dom/htmlformelement.rs index 03d2ee8eeb1..a1ca7d5dc2f 100644 --- a/src/components/script/dom/htmlformelement.rs +++ b/src/components/script/dom/htmlformelement.rs @@ -115,6 +115,7 @@ impl HTMLFormElement { } pub fn Elements(&self) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1844 let doc = self.htmlelement.element.node.owner_doc(); let doc = doc.get(); HTMLCollection::new(&doc.window, ~[]) diff --git a/src/components/script/dom/htmlmapelement.rs b/src/components/script/dom/htmlmapelement.rs index 41516e9a5d2..d343073a278 100644 --- a/src/components/script/dom/htmlmapelement.rs +++ b/src/components/script/dom/htmlmapelement.rs @@ -51,6 +51,7 @@ impl HTMLMapElement { } pub fn Areas(&self) -> JS<HTMLCollection> { + // FIXME: https://github.com/mozilla/servo/issues/1845 let doc = self.htmlelement.element.node.owner_doc(); let doc = doc.get(); HTMLCollection::new(&doc.window, ~[]) diff --git a/src/components/script/dom/location.rs b/src/components/script/dom/location.rs index 7d0c5294711..2fc06fb353b 100644 --- a/src/components/script/dom/location.rs +++ b/src/components/script/dom/location.rs @@ -41,7 +41,7 @@ impl Location { } } - pub fn new(window: &Window, page: Rc<Page>) -> JS<Location> { + pub fn new(window: &JS<Window>, page: Rc<Page>) -> JS<Location> { reflect_dom_object(~Location::new_inherited(page), window, LocationBinding::Wrap) diff --git a/src/components/script/dom/mouseevent.rs b/src/components/script/dom/mouseevent.rs index 0e11d2e838b..8741ea48a68 100644 --- a/src/components/script/dom/mouseevent.rs +++ b/src/components/script/dom/mouseevent.rs @@ -54,7 +54,7 @@ impl MouseEvent { pub fn new(window: &JS<Window>) -> JS<MouseEvent> { reflect_dom_object(~MouseEvent::new_inherited(), - window.get(), + window, MouseEventBinding::Wrap) } diff --git a/src/components/script/dom/navigator.rs b/src/components/script/dom/navigator.rs index e3c648ec4ed..140fa082f91 100644 --- a/src/components/script/dom/navigator.rs +++ b/src/components/script/dom/navigator.rs @@ -21,7 +21,7 @@ impl Navigator { } } - pub fn new(window: &Window) -> JS<Navigator> { + pub fn new(window: &JS<Window>) -> JS<Navigator> { reflect_dom_object(~Navigator::new_inherited(), window, NavigatorBinding::Wrap) diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index ef3b4a03ffa..9999503a758 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -754,10 +754,10 @@ impl Node { pub fn reflect_node<N: Reflectable+NodeBase> (node: ~N, document: &JS<Document>, - wrap_fn: extern "Rust" fn(*JSContext, *JSObject, ~N) -> *JSObject) + wrap_fn: extern "Rust" fn(*JSContext, &JS<Window>, ~N) -> *JSObject) -> JS<N> { assert!(node.reflector().get_jsobject().is_null()); - let node = reflect_dom_object(node, document.get().window.get(), wrap_fn); + let node = reflect_dom_object(node, &document.get().window, wrap_fn); assert!(node.reflector().get_jsobject().is_not_null()); node } @@ -840,6 +840,7 @@ impl Node { // http://dom.spec.whatwg.org/#dom-node-baseuri pub fn GetBaseURI(&self) -> Option<DOMString> { + // FIXME (#1824) implement. None } @@ -873,6 +874,20 @@ impl Node { self.first_child.is_some() } + // http://dom.spec.whatwg.org/#dom-node-childnodes + pub fn ChildNodes(&mut self, abstract_self: &JS<Node>) -> JS<NodeList> { + match self.child_list { + None => { + let doc = self.owner_doc(); + let doc = doc.get(); + let list = NodeList::new_child_list(&doc.window, abstract_self); + self.child_list = Some(list.clone()); + list + } + Some(ref list) => list.clone() + } + } + // http://dom.spec.whatwg.org/#dom-node-firstchild pub fn GetFirstChild(&self) -> Option<JS<Node>> { self.first_child.clone() @@ -909,9 +924,16 @@ impl Node { } // http://dom.spec.whatwg.org/#dom-node-nodevalue - pub fn SetNodeValue(&mut self, _abstract_self: &JS<Node>, _val: Option<DOMString>) + pub fn SetNodeValue(&mut self, abstract_self: &mut JS<Node>, val: Option<DOMString>) -> ErrorResult { - // FIXME: Stub - https://github.com/mozilla/servo/issues/1655 + match self.type_id { + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId => { + self.SetTextContent(abstract_self, val); + } + _ => {} + } Ok(()) } @@ -942,18 +964,39 @@ impl Node { } } - // http://dom.spec.whatwg.org/#dom-node-childnodes - pub fn ChildNodes(&mut self, abstract_self: &JS<Node>) -> JS<NodeList> { - match self.child_list { - None => { - let doc = self.owner_doc(); - let doc = doc.get(); - let list = NodeList::new_child_list(&doc.window, abstract_self); - self.child_list = Some(list.clone()); - list + // http://dom.spec.whatwg.org/#dom-node-textcontent + pub fn SetTextContent(&mut self, abstract_self: &mut JS<Node>, value: Option<DOMString>) + -> ErrorResult { + let value = null_str_as_empty(&value); + match self.type_id { + DocumentFragmentNodeTypeId | + ElementNodeTypeId(..) => { + // Step 1-2. + let node = if value.len() == 0 { + None + } else { + let document = self.owner_doc(); + Some(NodeCast::from(&document.get().CreateTextNode(&document, value))) + }; + // Step 3. + Node::replace_all(node, abstract_self); } - Some(ref list) => list.clone() + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId => { + self.wait_until_safe_to_modify_dom(); + + let mut characterdata: JS<CharacterData> = CharacterDataCast::to(abstract_self); + characterdata.get_mut().data = value.clone(); + + // Notify the document that the content of this node is different + let document = self.owner_doc(); + document.get().content_changed(); + } + DoctypeNodeTypeId | + DocumentNodeTypeId => {} } + Ok(()) } // http://dom.spec.whatwg.org/#concept-node-adopt @@ -1227,41 +1270,6 @@ impl Node { } } - // http://dom.spec.whatwg.org/#dom-node-textcontent - pub fn SetTextContent(&mut self, abstract_self: &mut JS<Node>, value: Option<DOMString>) - -> ErrorResult { - let value = null_str_as_empty(&value); - match self.type_id { - DocumentFragmentNodeTypeId | - ElementNodeTypeId(..) => { - // Step 1-2. - let node = if value.len() == 0 { - None - } else { - let document = self.owner_doc(); - Some(NodeCast::from(&document.get().CreateTextNode(&document, value))) - }; - // Step 3. - Node::replace_all(node, abstract_self); - } - CommentNodeTypeId | - TextNodeTypeId | - ProcessingInstructionNodeTypeId => { - self.wait_until_safe_to_modify_dom(); - - let mut characterdata: JS<CharacterData> = CharacterDataCast::to(abstract_self); - characterdata.get_mut().data = value.clone(); - - // Notify the document that the content of this node is different - let document = self.owner_doc(); - document.get().content_changed(); - } - DoctypeNodeTypeId | - DocumentNodeTypeId => {} - } - Ok(()) - } - // http://dom.spec.whatwg.org/#dom-node-insertbefore pub fn InsertBefore(&self, abstract_self: &mut JS<Node>, node: &mut JS<Node>, child: Option<JS<Node>>) -> Fallible<JS<Node>> { @@ -1415,7 +1423,7 @@ impl Node { // http://dom.spec.whatwg.org/#dom-node-normalize pub fn Normalize(&mut self) { - // FIXME: stub - https://github.com/mozilla/servo/issues/1655 + // FIXME (#1823) implement. } // http://dom.spec.whatwg.org/#dom-node-clonenode @@ -1500,7 +1508,7 @@ impl Node { // http://dom.spec.whatwg.org/#dom-node-comparedocumentposition pub fn CompareDocumentPosition(&self, _other: &JS<Node>) -> u16 { - // FIXME: stub - https://github.com/mozilla/servo/issues/1655 + // FIXME (#1794) implement. 0 } @@ -1514,19 +1522,19 @@ impl Node { // http://dom.spec.whatwg.org/#dom-node-lookupprefix pub fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString> { - // FIXME: stub - https://github.com/mozilla/servo/issues/1655 + // FIXME (#1826) implement. None } // http://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri pub fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString> { - // FIXME: stub - https://github.com/mozilla/servo/issues/1655 + // FIXME (#1826) implement. None } // http://dom.spec.whatwg.org/#dom-node-isdefaultnamespace pub fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool { - // FIXME: stub - https://github.com/mozilla/servo/issues/1655 + // FIXME (#1826) implement. false } @@ -1545,11 +1553,6 @@ impl Node { None } - // http://dom.spec.whatwg.org/#dom-node-hasattributes - pub fn HasAttributes(&self) -> bool { - false - } - // // Low-level pointer stitching // diff --git a/src/components/script/dom/nodelist.rs b/src/components/script/dom/nodelist.rs index 84de1a56d19..ab2bbb7f575 100644 --- a/src/components/script/dom/nodelist.rs +++ b/src/components/script/dom/nodelist.rs @@ -31,18 +31,18 @@ impl NodeList { } } - pub fn new(window: JS<Window>, + pub fn new(window: &JS<Window>, list_type: NodeListType) -> JS<NodeList> { reflect_dom_object(~NodeList::new_inherited(window.clone(), list_type), - window.get(), NodeListBinding::Wrap) + window, NodeListBinding::Wrap) } pub fn new_simple_list(window: &JS<Window>, elements: ~[JS<Node>]) -> JS<NodeList> { - NodeList::new(window.clone(), Simple(elements)) + NodeList::new(window, Simple(elements)) } pub fn new_child_list(window: &JS<Window>, node: &JS<Node>) -> JS<NodeList> { - NodeList::new(window.clone(), Children(node.clone())) + NodeList::new(window, Children(node.clone())) } pub fn Length(&self) -> u32 { diff --git a/src/components/script/dom/testbinding.rs b/src/components/script/dom/testbinding.rs new file mode 100644 index 00000000000..514260c5c10 --- /dev/null +++ b/src/components/script/dom/testbinding.rs @@ -0,0 +1,155 @@ +/* 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/. */ + +use dom::bindings::js::JS; +use dom::bindings::utils::{Reflector, Reflectable}; +use dom::blob::Blob; +use dom::window::Window; +use servo_util::str::DOMString; + +use js::jsapi::JSContext; +use js::jsval::{JSVal, NullValue}; + +#[deriving(Encodable)] +pub struct TestBinding { + reflector: Reflector, + window: JS<Window>, +} + +impl TestBinding { + pub fn BooleanAttribute(&self) -> bool { false } + pub fn SetBooleanAttribute(&self, _: bool) {} + pub fn ByteAttribute(&self) -> i8 { 0 } + pub fn SetByteAttribute(&self, _: i8) {} + pub fn OctetAttribute(&self) -> u8 { 0 } + pub fn SetOctetAttribute(&self, _: u8) {} + pub fn ShortAttribute(&self) -> i16 { 0 } + pub fn SetShortAttribute(&self, _: i16) {} + pub fn UnsignedShortAttribute(&self) -> u16 { 0 } + pub fn SetUnsignedShortAttribute(&self, _: u16) {} + pub fn LongAttribute(&self) -> i32 { 0 } + pub fn SetLongAttribute(&self, _: i32) {} + pub fn UnsignedLongAttribute(&self) -> u32 { 0 } + pub fn SetUnsignedLongAttribute(&self, _: u32) {} + pub fn LongLongAttribute(&self) -> i64 { 0 } + pub fn SetLongLongAttribute(&self, _: i64) {} + pub fn UnsignedLongLongAttribute(&self) -> u64 { 0 } + pub fn SetUnsignedLongLongAttribute(&self, _: u64) {} + pub fn FloatAttribute(&self) -> f32 { 0. } + pub fn SetFloatAttribute(&self, _: f32) {} + pub fn DoubleAttribute(&self) -> f64 { 0. } + pub fn SetDoubleAttribute(&self, _: f64) {} + pub fn StringAttribute(&self) -> DOMString { ~"" } + pub fn SetStringAttribute(&self, _: DOMString) {} + pub fn InterfaceAttribute(&self) -> JS<Blob> { Blob::new(&self.window) } + pub fn SetInterfaceAttribute(&self, _: &JS<Blob>) {} + pub fn AnyAttribute(&self, _: *JSContext) -> JSVal { NullValue() } + pub fn SetAnyAttribute(&self, _: *JSContext, _: JSVal) {} + + pub fn GetBooleanAttributeNullable(&self) -> Option<bool> { Some(false) } + pub fn SetBooleanAttributeNullable(&self, _: Option<bool>) {} + pub fn GetByteAttributeNullable(&self) -> Option<i8> { Some(0) } + pub fn SetByteAttributeNullable(&self, _: Option<i8>) {} + pub fn GetOctetAttributeNullable(&self) -> Option<u8> { Some(0) } + pub fn SetOctetAttributeNullable(&self, _: Option<u8>) {} + pub fn GetShortAttributeNullable(&self) -> Option<i16> { Some(0) } + pub fn SetShortAttributeNullable(&self, _: Option<i16>) {} + pub fn GetUnsignedShortAttributeNullable(&self) -> Option<u16> { Some(0) } + pub fn SetUnsignedShortAttributeNullable(&self, _: Option<u16>) {} + pub fn GetLongAttributeNullable(&self) -> Option<i32> { Some(0) } + pub fn SetLongAttributeNullable(&self, _: Option<i32>) {} + pub fn GetUnsignedLongAttributeNullable(&self) -> Option<u32> { Some(0) } + pub fn SetUnsignedLongAttributeNullable(&self, _: Option<u32>) {} + pub fn GetLongLongAttributeNullable(&self) -> Option<i64> { Some(0) } + pub fn SetLongLongAttributeNullable(&self, _: Option<i64>) {} + pub fn GetUnsignedLongLongAttributeNullable(&self) -> Option<u64> { Some(0) } + pub fn SetUnsignedLongLongAttributeNullable(&self, _: Option<u64>) {} + pub fn GetFloatAttributeNullable(&self) -> Option<f32> { Some(0.) } + pub fn SetFloatAttributeNullable(&self, _: Option<f32>) {} + pub fn GetDoubleAttributeNullable(&self) -> Option<f64> { Some(0.) } + pub fn SetDoubleAttributeNullable(&self, _: Option<f64>) {} + pub fn GetStringAttributeNullable(&self) -> Option<DOMString> { Some(~"") } + pub fn SetStringAttributeNullable(&self, _: Option<DOMString>) {} + pub fn GetInterfaceAttributeNullable(&self) -> Option<JS<Blob>> { Some(Blob::new(&self.window)) } + pub fn SetInterfaceAttributeNullable(&self, _: Option<JS<Blob>>) {} + + // FIXME (issue #1813) Doesn't currently compile. + // pub fn PassOptionalBoolean(&self, _: Option<bool>) {} + // pub fn PassOptionalByte(&self, _: Option<i8>) {} + // pub fn PassOptionalOctet(&self, _: Option<u8>) {} + // pub fn PassOptionalShort(&self, _: Option<i16>) {} + // pub fn PassOptionalUnsignedShort(&self, _: Option<u16>) {} + // pub fn PassOptionalLong(&self, _: Option<i32>) {} + // pub fn PassOptionalUnsignedLong(&self, _: Option<u32>) {} + // pub fn PassOptionalLongLong(&self, _: Option<i64>) {} + // pub fn PassOptionalUnsignedLongLong(&self, _: Option<u64>) {} + // pub fn PassOptionalFloat(&self, _: Option<f32>) {} + // pub fn PassOptionalDouble(&self, _: Option<f64>) {} + pub fn PassOptionalString(&self, _: Option<DOMString>) {} + pub fn PassOptionalInterface(&self, _: Option<JS<Blob>>) {} + pub fn PassOptionalAny(&self, _: *JSContext, _: Option<JSVal>) {} + + // pub fn PassOptionalNullableBoolean(&self, _: Option<Option<bool>>) {} + // pub fn PassOptionalNullableByte(&self, _: Option<Option<i8>>) {} + // pub fn PassOptionalNullableOctet(&self, _: Option<Option<u8>>) {} + // pub fn PassOptionalNullableShort(&self, _: Option<Option<i16>>) {} + // pub fn PassOptionalNullableUnsignedShort(&self, _: Option<Option<u16>>) {} + // pub fn PassOptionalNullableLong(&self, _: Option<Option<i32>>) {} + // pub fn PassOptionalNullableUnsignedLong(&self, _: Option<Option<u32>>) {} + // pub fn PassOptionalNullableLongLong(&self, _: Option<Option<i64>>) {} + // pub fn PassOptionalNullableUnsignedLongLong(&self, _: Option<Option<u64>>) {} + // pub fn PassOptionalNullableFloat(&self, _: Option<Option<f32>>) {} + // pub fn PassOptionalNullableDouble(&self, _: Option<Option<f64>>) {} + pub fn PassOptionalNullableString(&self, _: Option<Option<DOMString>>) {} + // pub fn PassOptionalNullableInterface(&self, _: Option<Option<JS<Blob>>>) {} + + pub fn PassOptionalBooleanWithDefault(&self, _: bool) {} + pub fn PassOptionalByteWithDefault(&self, _: i8) {} + pub fn PassOptionalOctetWithDefault(&self, _: u8) {} + pub fn PassOptionalShortWithDefault(&self, _: i16) {} + pub fn PassOptionalUnsignedShortWithDefault(&self, _: u16) {} + pub fn PassOptionalLongWithDefault(&self, _: i32) {} + pub fn PassOptionalUnsignedLongWithDefault(&self, _: u32) {} + pub fn PassOptionalLongLongWithDefault(&self, _: i64) {} + pub fn PassOptionalUnsignedLongLongWithDefault(&self, _: u64) {} + pub fn PassOptionalStringWithDefault(&self, _: DOMString) {} + + pub fn PassOptionalNullableBooleanWithDefault(&self, _: Option<bool>) {} + pub fn PassOptionalNullableByteWithDefault(&self, _: Option<i8>) {} + pub fn PassOptionalNullableOctetWithDefault(&self, _: Option<u8>) {} + pub fn PassOptionalNullableShortWithDefault(&self, _: Option<i16>) {} + pub fn PassOptionalNullableUnsignedShortWithDefault(&self, _: Option<u16>) {} + pub fn PassOptionalNullableLongWithDefault(&self, _: Option<i32>) {} + pub fn PassOptionalNullableUnsignedLongWithDefault(&self, _: Option<u32>) {} + pub fn PassOptionalNullableLongLongWithDefault(&self, _: Option<i64>) {} + pub fn PassOptionalNullableUnsignedLongLongWithDefault(&self, _: Option<u64>) {} + pub fn PassOptionalNullableFloatWithDefault(&self, _: Option<f32>) {} + pub fn PassOptionalNullableDoubleWithDefault(&self, _: Option<f64>) {} + // pub fn PassOptionalNullableStringWithDefault(&self, _: Option<DOMString>) {} + pub fn PassOptionalNullableInterfaceWithDefault(&self, _: Option<JS<Blob>>) {} + pub fn PassOptionalAnyWithDefault(&self, _: *JSContext, _: JSVal) {} + + pub fn PassOptionalNullableBooleanWithNonNullDefault(&self, _: Option<bool>) {} + pub fn PassOptionalNullableByteWithNonNullDefault(&self, _: Option<i8>) {} + pub fn PassOptionalNullableOctetWithNonNullDefault(&self, _: Option<u8>) {} + pub fn PassOptionalNullableShortWithNonNullDefault(&self, _: Option<i16>) {} + pub fn PassOptionalNullableUnsignedShortWithNonNullDefault(&self, _: Option<u16>) {} + pub fn PassOptionalNullableLongWithNonNullDefault(&self, _: Option<i32>) {} + pub fn PassOptionalNullableUnsignedLongWithNonNullDefault(&self, _: Option<u32>) {} + pub fn PassOptionalNullableLongLongWithNonNullDefault(&self, _: Option<i64>) {} + pub fn PassOptionalNullableUnsignedLongLongWithNonNullDefault(&self, _: Option<u64>) {} + // pub fn PassOptionalNullableFloatWithNonNullDefault(&self, _: Option<f32>) {} + // pub fn PassOptionalNullableDoubleWithNonNullDefault(&self, _: Option<f64>) {} + pub fn PassOptionalNullableStringWithNonNullDefault(&self, _: Option<DOMString>) {} +} + +impl Reflectable for TestBinding { + fn reflector<'a>(&'a self) -> &'a Reflector { + &self.reflector + } + + fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector { + &mut self.reflector + } +} diff --git a/src/components/script/dom/uievent.rs b/src/components/script/dom/uievent.rs index f5564bee284..46ca3736fc3 100644 --- a/src/components/script/dom/uievent.rs +++ b/src/components/script/dom/uievent.rs @@ -37,7 +37,7 @@ impl UIEvent { pub fn new(window: &JS<Window>) -> JS<UIEvent> { reflect_dom_object(~UIEvent::new_inherited(UIEventTypeId), - window.get(), + window, UIEventBinding::Wrap) } diff --git a/src/components/script/dom/validitystate.rs b/src/components/script/dom/validitystate.rs index 1d7a690ffab..4ad6d8657e4 100644 --- a/src/components/script/dom/validitystate.rs +++ b/src/components/script/dom/validitystate.rs @@ -25,7 +25,7 @@ impl ValidityState { pub fn new(window: &JS<Window>) -> JS<ValidityState> { reflect_dom_object(~ValidityState::new_inherited(window.clone()), - window.get(), + window, ValidityStateBinding::Wrap) } } diff --git a/src/components/script/dom/webidls/Document.webidl b/src/components/script/dom/webidls/Document.webidl index daa91f540fb..98df0b2aef9 100644 --- a/src/components/script/dom/webidls/Document.webidl +++ b/src/components/script/dom/webidls/Document.webidl @@ -21,6 +21,8 @@ interface Document : Node { readonly attribute DocumentType? doctype; readonly attribute Element? documentElement; HTMLCollection getElementsByTagName(DOMString localName); + HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); + HTMLCollection getElementsByClassName(DOMString classNames); Element? getElementById(DOMString elementId); [Creator, Throws] @@ -44,7 +46,7 @@ partial interface Document { attribute DOMString title; attribute HTMLElement? body; readonly attribute HTMLHeadElement? head; - /*NodeList*/ HTMLCollection getElementsByName(DOMString elementName); + NodeList getElementsByName(DOMString elementName); readonly attribute HTMLCollection images; readonly attribute HTMLCollection embeds; diff --git a/src/components/script/dom/webidls/Element.webidl b/src/components/script/dom/webidls/Element.webidl index 6c393f00067..e26c9415d4a 100644 --- a/src/components/script/dom/webidls/Element.webidl +++ b/src/components/script/dom/webidls/Element.webidl @@ -51,7 +51,6 @@ interface Element : Node { boolean hasAttributeNS(DOMString? namespace, DOMString localName); HTMLCollection getElementsByTagName(DOMString localName); - [Throws] HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); HTMLCollection getElementsByClassName(DOMString classNames); }; diff --git a/src/components/script/dom/webidls/HTMLCollection.webidl b/src/components/script/dom/webidls/HTMLCollection.webidl index 2c1fc60e04a..7389e776834 100644 --- a/src/components/script/dom/webidls/HTMLCollection.webidl +++ b/src/components/script/dom/webidls/HTMLCollection.webidl @@ -10,6 +10,5 @@ interface HTMLCollection { readonly attribute unsigned long length; getter Element? item(unsigned long index); - [Throws] - getter object? namedItem(DOMString name); // only returns Element + getter Element? namedItem(DOMString name); }; diff --git a/src/components/script/dom/webidls/Node.webidl b/src/components/script/dom/webidls/Node.webidl index f21d528be26..0670e6eb3f6 100644 --- a/src/components/script/dom/webidls/Node.webidl +++ b/src/components/script/dom/webidls/Node.webidl @@ -50,14 +50,6 @@ interface Node : EventTarget { attribute DOMString? nodeValue; [SetterThrows, Pure] attribute DOMString? textContent; - [Throws] - Node insertBefore(Node node, Node? child); - [Throws] - Node appendChild(Node node); - [Throws] - Node replaceChild(Node node, Node child); - [Throws] - Node removeChild(Node child); void normalize(); [Throws] @@ -69,7 +61,7 @@ interface Node : EventTarget { const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04; const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08; const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10; - const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; // historical + const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; unsigned short compareDocumentPosition(Node other); boolean contains(Node? other); @@ -77,6 +69,15 @@ interface Node : EventTarget { DOMString? lookupNamespaceURI(DOMString? prefix); boolean isDefaultNamespace(DOMString? namespace); + [Throws] + Node insertBefore(Node node, Node? child); + [Throws] + Node appendChild(Node node); + [Throws] + Node replaceChild(Node node, Node child); + [Throws] + Node removeChild(Node child); + // Mozilla-specific stuff // These have been moved to Element in the spec. // If we move namespaceURI, prefix and localName to Element they should return @@ -87,6 +88,4 @@ interface Node : EventTarget { readonly attribute DOMString? prefix; [Constant] readonly attribute DOMString? localName; - - boolean hasAttributes(); }; diff --git a/src/components/script/dom/webidls/TestBinding.webidl b/src/components/script/dom/webidls/TestBinding.webidl new file mode 100644 index 00000000000..3a967f5484a --- /dev/null +++ b/src/components/script/dom/webidls/TestBinding.webidl @@ -0,0 +1,101 @@ +/* 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/. */ + +interface TestBinding { + attribute boolean booleanAttribute; + attribute byte byteAttribute; + attribute octet octetAttribute; + attribute short shortAttribute; + attribute unsigned short unsignedShortAttribute; + attribute long longAttribute; + attribute unsigned long unsignedLongAttribute; + attribute long long longLongAttribute; + attribute unsigned long long unsignedLongLongAttribute; + attribute float floatAttribute; + attribute double doubleAttribute; + attribute DOMString stringAttribute; + attribute Blob interfaceAttribute; + attribute any anyAttribute; + + attribute boolean? booleanAttributeNullable; + attribute byte? byteAttributeNullable; + attribute octet? octetAttributeNullable; + attribute short? shortAttributeNullable; + attribute unsigned short? unsignedShortAttributeNullable; + attribute long? longAttributeNullable; + attribute unsigned long? unsignedLongAttributeNullable; + attribute long long? longLongAttributeNullable; + attribute unsigned long long? unsignedLongLongAttributeNullable; + attribute float? floatAttributeNullable; + attribute double? doubleAttributeNullable; + attribute DOMString? stringAttributeNullable; + attribute Blob? interfaceAttributeNullable; + + // FIXME (issue #1813) Doesn't currently compile. + // void passOptionalBoolean(optional boolean arg); + // void passOptionalByte(optional byte arg); + // void passOptionalOctet(optional octet arg); + // void passOptionalShort(optional short arg); + // void passOptionalUnsignedShort(optional unsigned short arg); + // void passOptionalLong(optional long arg); + // void passOptionalUnsignedLong(optional unsigned long arg); + // void passOptionalLongLong(optional long long arg); + // void passOptionalUnsignedLongLong(optional unsigned long long arg); + // void passOptionalFloat(optional float arg); + // void passOptionalDouble(optional double arg); + void passOptionalString(optional DOMString arg); + void passOptionalInterface(optional Blob arg); + void passOptionalAny(optional any arg); + + // void passOptionalNullableBoolean(optional boolean? arg); + // void passOptionalNullableByte(optional byte? arg); + // void passOptionalNullableOctet(optional octet? arg); + // void passOptionalNullableShort(optional short? arg); + // void passOptionalNullableUnsignedShort(optional unsigned short? arg); + // void passOptionalNullableLong(optional long? arg); + // void passOptionalNullableUnsignedLong(optional unsigned long? arg); + // void passOptionalNullableLongLong(optional long long? arg); + // void passOptionalNullableUnsignedLongLong(optional unsigned long long? arg); + // void passOptionalNullableFloat(optional float? arg); + // void passOptionalNullableDouble(optional double? arg); + void passOptionalNullableString(optional DOMString? arg); + // void passOptionalNullableInterface(optional Blob? arg); + + void passOptionalBooleanWithDefault(optional boolean arg = false); + void passOptionalByteWithDefault(optional byte arg = 0); + void passOptionalOctetWithDefault(optional octet arg = 19); + void passOptionalShortWithDefault(optional short arg = 5); + void passOptionalUnsignedShortWithDefault(optional unsigned short arg = 2); + void passOptionalLongWithDefault(optional long arg = 7); + void passOptionalUnsignedLongWithDefault(optional unsigned long arg = 6); + void passOptionalLongLongWithDefault(optional long long arg = -12); + void passOptionalUnsignedLongLongWithDefault(optional unsigned long long arg = 17); + void passOptionalStringWithDefault(optional DOMString arg = ""); + + void passOptionalNullableBooleanWithDefault(optional boolean? arg = null); + void passOptionalNullableByteWithDefault(optional byte? arg = null); + void passOptionalNullableOctetWithDefault(optional octet? arg = null); + void passOptionalNullableShortWithDefault(optional short? arg = null); + void passOptionalNullableUnsignedShortWithDefault(optional unsigned short? arg = null); + void passOptionalNullableLongWithDefault(optional long? arg = null); + void passOptionalNullableUnsignedLongWithDefault(optional unsigned long? arg = null); + void passOptionalNullableLongLongWithDefault(optional long long? arg = null); + void passOptionalNullableUnsignedLongLongWithDefault(optional unsigned long long? arg = null); + // void passOptionalNullableStringWithDefault(optional DOMString? arg = null); + void passOptionalNullableInterfaceWithDefault(optional Blob? arg = null); + void passOptionalAnyWithDefault(optional any arg = null); + + void passOptionalNullableBooleanWithNonNullDefault(optional boolean? arg = false); + void passOptionalNullableByteWithNonNullDefault(optional byte? arg = 7); + void passOptionalNullableOctetWithNonNullDefault(optional octet? arg = 7); + void passOptionalNullableShortWithNonNullDefault(optional short? arg = 7); + void passOptionalNullableUnsignedShortWithNonNullDefault(optional unsigned short? arg = 7); + void passOptionalNullableLongWithNonNullDefault(optional long? arg = 7); + void passOptionalNullableUnsignedLongWithNonNullDefault(optional unsigned long? arg = 7); + void passOptionalNullableLongLongWithNonNullDefault(optional long long? arg = 7); + void passOptionalNullableUnsignedLongLongWithNonNullDefault(optional unsigned long long? arg = 7); + // void passOptionalNullableFloatWithNonNullDefault(optional float? arg = 0.0); + // void passOptionalNullableDoubleWithNonNullDefault(optional double? arg = 0.0); + void passOptionalNullableStringWithNonNullDefault(optional DOMString? arg = ""); +}; diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index 68a9e3364b9..7c3d2e90280 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -20,8 +20,10 @@ use servo_util::str::DOMString; use servo_util::task::{spawn_named}; use js::glue::*; -use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JSVal}; -use js::{JSVAL_NULL, JSPROP_ENUMERATE}; +use js::jsapi::{JSObject, JSContext, JS_DefineProperty}; +use js::jsval::JSVal; +use js::jsval::{NullValue, ObjectValue}; +use js::JSPROP_ENUMERATE; use std::cast; use std::comm::SharedChan; @@ -29,7 +31,6 @@ use std::comm::Select; use std::hashmap::HashSet; use std::io::timer::Timer; use std::num; -use std::ptr; use std::rc::Rc; use std::to_bytes::Cb; @@ -176,23 +177,23 @@ impl Window { None } - pub fn Location(&mut self) -> JS<Location> { + pub fn Location(&mut self, abstract_self: &JS<Window>) -> JS<Location> { if self.location.is_none() { - self.location = Some(Location::new(self, self.extra.page.clone())); + self.location = Some(Location::new(abstract_self, self.extra.page.clone())); } self.location.get_ref().clone() } - pub fn Console(&mut self) -> JS<Console> { + pub fn Console(&mut self, abstract_self: &JS<Window>) -> JS<Console> { if self.console.is_none() { - self.console = Some(Console::new(self)); + self.console = Some(Console::new(abstract_self)); } self.console.get_ref().clone() } - pub fn Navigator(&mut self) -> JS<Navigator> { + pub fn Navigator(&mut self, abstract_self: &JS<Window>) -> JS<Navigator> { if self.navigator.is_none() { - self.navigator = Some(Navigator::new(self)); + self.navigator = Some(Navigator::new(abstract_self)); } self.navigator.get_ref().clone() } @@ -208,8 +209,8 @@ impl Window { pub fn Print(&self) { } - pub fn ShowModalDialog(&self, _cx: *JSContext, _url: DOMString, _argument: JSVal) -> JSVal { - JSVAL_NULL + pub fn ShowModalDialog(&self, _cx: *JSContext, _url: DOMString, _argument: Option<JSVal>) -> JSVal { + NullValue() } } @@ -311,14 +312,14 @@ impl Window { }; let raw: *mut Window = &mut *win; - let global = WindowBinding::Wrap(cx, ptr::null(), win); + let global = WindowBinding::Wrap(cx, win); assert!(global.is_not_null()); unsafe { let fn_names = ["window","self"]; for str in fn_names.iter() { (*str).to_c_str().with_ref(|name| { JS_DefineProperty(cx, global, name, - RUST_OBJECT_TO_JSVAL(global), + ObjectValue(&*global), Some(cast::transmute(GetJSClassHookStubPointer(PROPERTY_STUB))), Some(cast::transmute(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB))), JSPROP_ENUMERATE); diff --git a/src/components/script/dom/windowproxy.rs b/src/components/script/dom/windowproxy.rs index 35304d25d3c..dc1e0092f36 100644 --- a/src/components/script/dom/windowproxy.rs +++ b/src/components/script/dom/windowproxy.rs @@ -13,11 +13,11 @@ pub struct WindowProxy { } impl WindowProxy { - pub fn new(owner: JS<Window>) -> JS<WindowProxy> { + pub fn new(owner: &JS<Window>) -> JS<WindowProxy> { let proxy = ~WindowProxy { reflector_: Reflector::new() }; - reflect_dom_object(proxy, owner.get(), WindowProxyBinding::Wrap) + reflect_dom_object(proxy, owner, WindowProxyBinding::Wrap) } } |