diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index f65c0e2297d..5108a7d65d3 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -3648,8 +3648,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, declType = CGGeneric("JS::Rooted") declArgs = "cx" else: - assert (isMember == "Sequence" or isMember == "Variadic" or - isMember == "Dictionary" or isMember == "OwningUnion") + assert (isMember in + ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap")) # We'll get traced by the sequence or dictionary or union tracer declType = CGGeneric("JSObject*") declArgs = None @@ -3702,7 +3702,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: sequenceClass = "binding_detail::AutoSequence" - # XXXbz we can't include the index in the the sourceDescription, because + # XXXbz we can't include the index in the sourceDescription, because # we don't really have a way to pass one in dynamically at runtime... elementInfo = getJSToNativeConversionInfo( elementType, descriptorProvider, isMember="Sequence", @@ -3722,6 +3722,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: arrayRef = "${declName}" + elementConversion = string.Template(elementInfo.template).substitute({ + "val": "temp", + "mutableVal": "&temp", + "declName": "slot", + # We only need holderName here to handle isExternal() + # interfaces, which use an internal holder for the + # conversion even when forceOwningType ends up true. + "holderName": "tempHolder" + }) + # NOTE: Keep this in sync with variadic conversions as needed templateBody = fill( """ @@ -3748,25 +3758,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, $*{exceptionCode} } ${elementType}& slot = *slotPtr; + $*{elementConversion} + } """, exceptionCode=exceptionCode, notSequence=notSequence, sequenceType=sequenceType, arrayRef=arrayRef, - elementType=elementInfo.declType.define()) + elementType=elementInfo.declType.define(), + elementConversion=elementConversion) - templateBody += indent( - string.Template(elementInfo.template).substitute({ - "val": "temp", - "mutableVal": "&temp", - "declName": "slot", - # We only need holderName here to handle isExternal() - # interfaces, which use an internal holder for the - # conversion even when forceOwningType ends up true. - "holderName": "tempHolder" - })) - - templateBody += "}\n" templateBody = wrapObjectTemplate(templateBody, type, "${declName}.SetNull();\n", notSequence) # Sequence arguments that might contain traceable things need @@ -3786,6 +3787,110 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, dealWithOptional=isOptional, holderArgs=holderArgs) + if type.isMozMap(): + assert not isEnforceRange and not isClamp + if failureCode is None: + notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n' + "%s" % (firstCap(sourceDescription), exceptionCode)) + else: + notMozMap = failureCode + + nullable = type.nullable() + # Be very careful not to change "type": we need it later + if nullable: + valueType = type.inner.inner + else: + valueType = type.inner + + valueInfo = getJSToNativeConversionInfo( + valueType, descriptorProvider, isMember="MozMap", + exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode, + isCallbackReturnValue=isCallbackReturnValue, + sourceDescription="value in %s" % sourceDescription) + if valueInfo.dealWithOptional: + raise TypeError("Shouldn't have optional things in MozMap") + if valueInfo.holderType is not None: + raise TypeError("Shouldn't need holders for MozMap") + + typeName = CGTemplatedType("MozMap", valueInfo.declType) + mozMapType = typeName.define() + if nullable: + typeName = CGTemplatedType("Nullable", typeName) + mozMapRef = "${declName}.SetValue()" + else: + mozMapRef = "${declName}" + + valueConversion = string.Template(valueInfo.template).substitute({ + "val": "temp", + "mutableVal": "&temp", + "declName": "slot", + # We only need holderName here to handle isExternal() + # interfaces, which use an internal holder for the + # conversion even when forceOwningType ends up true. + "holderName": "tempHolder" + }) + + templateBody = fill( + """ + ${mozMapType} &mozMap = ${mozMapRef}; + + JS::Rooted mozMapObj(cx, &$${val}.toObject()); + JS::AutoIdArray ids(cx, JS_Enumerate(cx, mozMapObj)); + if (!ids) { + $*{exceptionCode} + } + JS::Rooted propNameValue(cx); + JS::Rooted temp(cx); + JS::Rooted curId(cx); + for (size_t i = 0; i < ids.length(); ++i) { + // Make sure we get the value before converting the name, since + // getting the value can trigger GC but our name is a dependent + // string. + curId = ids[i]; + binding_detail::FakeDependentString propName; + if (!JS_GetPropertyById(cx, mozMapObj, curId, &temp) || + !JS_IdToValue(cx, curId, &propNameValue) || + !ConvertJSValueToString(cx, propNameValue, &propNameValue, + eStringify, eStringify, propName)) { + $*{exceptionCode} + } + + ${valueType}* slotPtr = mozMap.AddEntry(propName); + if (!slotPtr) { + JS_ReportOutOfMemory(cx); + $*{exceptionCode} + } + ${valueType}& slot = *slotPtr; + $*{valueConversion} + } + """, + exceptionCode=exceptionCode, + mozMapType=mozMapType, + mozMapRef=mozMapRef, + valueType=valueInfo.declType.define(), + valueConversion=valueConversion) + + templateBody = wrapObjectTemplate(templateBody, type, + "${declName}.SetNull();\n", + notMozMap) + + # MozMap arguments that might contain traceable things need + # to get traced + if not isMember and typeNeedsRooting(valueType): + holderType = CGTemplatedType("MozMapRooter", valueInfo.declType) + # If our MozMap is nullable, this will set the Nullable to be + # not-null, but that's ok because we make an explicit SetNull() call + # on it as needed if our JS value is actually null. + holderArgs = "cx, &%s" % mozMapRef + else: + holderType = None + holderArgs = None + + return JSToNativeConversionInfo(templateBody, declType=typeName, + holderType=holderType, + dealWithOptional=isOptional, + holderArgs=holderArgs) + if type.isUnion(): nullable = type.nullable() if nullable: @@ -3858,6 +3963,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: setDictionary = None + mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes) + if len(mozMapMemberTypes) > 0: + raise TypeError("We don't support MozMap in unions yet") + objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) if len(objectMemberTypes) > 0: assert len(objectMemberTypes) == 1 @@ -4491,7 +4600,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not isEnforceRange and not isClamp declArgs = None - if isMember in ("Variadic", "Sequence", "Dictionary"): + if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"): # Rooting is handled by the sequence and dictionary tracers. declType = "JS::Value" else: @@ -5403,7 +5512,7 @@ def typeMatchesLambda(type, func): return False if type.nullable(): return typeMatchesLambda(type.inner, func) - if type.isSequence() or type.isArray(): + if type.isSequence() or type.isMozMap() or type.isArray(): return typeMatchesLambda(type.inner, func) if type.isUnion(): return any(typeMatchesLambda(t, func) for t in @@ -5586,6 +5695,8 @@ class CGCallGenerator(CGThing): return True if a.type.isSequence(): return True + if a.type.isMozMap(): + return True # isObject() types are always a JS::Rooted, whether # nullable or not, and it turns out a const JS::Rooted # is not very helpful at all (in particular, it won't diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index 0088d967d1f..0d09f86e699 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -9,6 +9,7 @@ #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Date.h" +#include "mozilla/dom/MozMap.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/ErrorResult.h" @@ -401,6 +402,26 @@ public: void PassSequenceOfSequences(const Sequence< Sequence >&); void ReceiveSequenceOfSequences(nsTArray< nsTArray >&); + // MozMap types + void PassMozMap(const MozMap &); + void PassNullableMozMap(const Nullable< MozMap >&); + void PassMozMapOfNullableInts(const MozMap >&); + void PassOptionalMozMapOfNullableInts(const Optional > > &); + void PassOptionalNullableMozMapOfNullableInts(const Optional > > > &); + void PassCastableObjectMozMap(const MozMap< OwningNonNull >&); + void PassNullableCastableObjectMozMap(const MozMap< nsRefPtr > &); + void PassCastableObjectNullableMozMap(const Nullable< MozMap< OwningNonNull > >&); + void PassNullableCastableObjectNullableMozMap(const Nullable< MozMap< nsRefPtr > >&); + void PassOptionalMozMap(const Optional >&); + void PassOptionalNullableMozMap(const Optional > >&); + void PassOptionalNullableMozMapWithDefaultValue(const Nullable< MozMap >&); + void PassOptionalObjectMozMap(const Optional > >&); + void PassExternalInterfaceMozMap(const MozMap >&); + void PassNullableExternalInterfaceMozMap(const MozMap >&); + void PassStringMozMap(const MozMap&); + void PassByteStringMozMap(const MozMap&); + void PassMozMapOfMozMaps(const MozMap< MozMap >&); + // Typed array types void PassArrayBuffer(const ArrayBuffer&); void PassNullableArrayBuffer(const Nullable&); @@ -419,6 +440,8 @@ public: void PassFloat64Array(const Float64Array&); void PassSequenceOfArrayBuffers(const Sequence&); void PassSequenceOfNullableArrayBuffers(const Sequence >&); + void PassMozMapOfArrayBuffers(const MozMap&); + void PassMozMapOfNullableArrayBuffers(const MozMap >&); void PassVariadicTypedArray(const Sequence&); void PassVariadicNullableTypedArray(const Sequence >&); JSObject* ReceiveUint8Array(JSContext*); @@ -483,6 +506,17 @@ public: void PassSequenceOfNullableSequenceOfAny(JSContext*, const Sequence > >&); void PassNullableSequenceOfNullableSequenceOfAny(JSContext*, const Nullable > > >&); void PassOptionalNullableSequenceOfNullableSequenceOfAny(JSContext*, const Optional > > > >&); + void PassMozMapOfAny(JSContext*, const MozMap&); + void PassNullableMozMapOfAny(JSContext*, const Nullable >&); + void PassOptionalMozMapOfAny(JSContext*, const Optional >&); + void PassOptionalNullableMozMapOfAny(JSContext*, const Optional > >&); + void PassOptionalMozMapOfAnyWithDefaultValue(JSContext*, const Nullable >&); + void PassMozMapOfMozMapOfAny(JSContext*, const MozMap >&); + void PassMozMapOfNullableMozMapOfAny(JSContext*, const MozMap > >&); + void PassNullableMozMapOfNullableMozMapOfAny(JSContext*, const Nullable > > >&); + void PassOptionalNullableMozMapOfNullableMozMapOfAny(JSContext*, const Optional>>>>&); + void PassOptionalNullableMozMapOfNullableSequenceOfAny(JSContext*, const Optional>>>>&); + void PassOptionalNullableSequenceOfNullableMozMapOfAny(JSContext*, const Optional>>>>&); JS::Value ReceiveAny(JSContext*); // object types @@ -498,6 +532,7 @@ public: void PassNullableSequenceOfObject(JSContext*, const Nullable >&); void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, const Optional > > > >&); void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, const Optional > > > >&); + void PassMozMapOfObject(JSContext*, const MozMap&); JSObject* ReceiveObject(JSContext*); JSObject* ReceiveNullableObject(JSContext*); @@ -579,6 +614,8 @@ public: void PassSequenceOfNullableUnions(const Sequence>&); void PassVariadicNullableUnion(const Sequence>&); + void PassMozMapOfUnions(const MozMap&); + void PassMozMapOfUnions2(JSContext*, const MozMap&); void ReceiveUnion(OwningCanvasPatternOrCanvasGradient&); void ReceiveUnion2(JSContext*, OwningObjectOrLong&); @@ -599,6 +636,7 @@ public: void PassOptionalNullableDate(const Optional >&); void PassOptionalNullableDateWithDefaultValue(const Nullable&); void PassDateSequence(const Sequence&); + void PassDateMozMap(const MozMap&); void PassNullableDateSequence(const Sequence >&); Date ReceiveDate(); Nullable ReceiveNullableDate(); @@ -624,6 +662,7 @@ public: void ReceiveNullableDictionary(JSContext*, Nullable&); void PassOtherDictionary(const GrandparentDict&); void PassSequenceOfDictionaries(JSContext*, const Sequence&); + void PassMozMapOfDictionaries(const MozMap&); void PassDictionaryOrLong(JSContext*, const Dict&); void PassDictionaryOrLong(int32_t); void PassDictContainingDict(JSContext*, const DictContainingDict&); diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index 04e3e73f198..0a9ffc9658a 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -360,6 +360,26 @@ interface TestInterface { void passSequenceOfSequences(sequence> arg); sequence> receiveSequenceOfSequences(); + // MozMap types + void passMozMap(MozMap arg); + void passNullableMozMap(MozMap? arg); + void passMozMapOfNullableInts(MozMap arg); + void passOptionalMozMapOfNullableInts(optional MozMap arg); + void passOptionalNullableMozMapOfNullableInts(optional MozMap? arg); + void passCastableObjectMozMap(MozMap arg); + void passNullableCastableObjectMozMap(MozMap arg); + void passCastableObjectNullableMozMap(MozMap? arg); + void passNullableCastableObjectNullableMozMap(MozMap? arg); + void passOptionalMozMap(optional MozMap arg); + void passOptionalNullableMozMap(optional MozMap? arg); + void passOptionalNullableMozMapWithDefaultValue(optional MozMap? arg = null); + void passOptionalObjectMozMap(optional MozMap arg); + void passExternalInterfaceMozMap(MozMap arg); + void passNullableExternalInterfaceMozMap(MozMap arg); + void passStringMozMap(MozMap arg); + void passByteStringMozMap(MozMap arg); + void passMozMapOfMozMaps(MozMap> arg); + // Typed array types void passArrayBuffer(ArrayBuffer arg); void passNullableArrayBuffer(ArrayBuffer? arg); @@ -378,6 +398,8 @@ interface TestInterface { void passFloat64Array(Float64Array arg); void passSequenceOfArrayBuffers(sequence arg); void passSequenceOfNullableArrayBuffers(sequence arg); + void passMozMapOfArrayBuffers(MozMap arg); + void passMozMapOfNullableArrayBuffers(MozMap arg); void passVariadicTypedArray(Float32Array... arg); void passVariadicNullableTypedArray(Float32Array?... arg); Uint8Array receiveUint8Array(); @@ -439,6 +461,17 @@ interface TestInterface { void passSequenceOfNullableSequenceOfAny(sequence?> arg); void passNullableSequenceOfNullableSequenceOfAny(sequence?>? arg); void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence?>? arg); + void passMozMapOfAny(MozMap arg); + void passNullableMozMapOfAny(MozMap? arg); + void passOptionalMozMapOfAny(optional MozMap arg); + void passOptionalNullableMozMapOfAny(optional MozMap? arg); + void passOptionalMozMapOfAnyWithDefaultValue(optional MozMap? arg = null); + void passMozMapOfMozMapOfAny(MozMap> arg); + void passMozMapOfNullableMozMapOfAny(MozMap?> arg); + void passNullableMozMapOfNullableMozMapOfAny(MozMap?>? arg); + void passOptionalNullableMozMapOfNullableMozMapOfAny(optional MozMap?>? arg); + void passOptionalNullableMozMapOfNullableSequenceOfAny(optional MozMap?>? arg); + void passOptionalNullableSequenceOfNullableMozMapOfAny(optional sequence?>? arg); any receiveAny(); // object types @@ -454,6 +487,7 @@ interface TestInterface { void passNullableSequenceOfObject(sequence? arg); void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence?>? arg); void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence?>? arg); + void passMozMapOfObject(MozMap arg); object receiveObject(); object? receiveNullableObject(); @@ -527,6 +561,9 @@ interface TestInterface { void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg); void passVariadicNullableUnion((CanvasPattern or CanvasGradient)?... arg); + void passMozMapOfUnions(MozMap<(CanvasPattern or CanvasGradient)> arg); + // XXXbz no move constructor on some unions + // void passMozMapOfUnions2(MozMap<(object or long)> arg); (CanvasPattern or CanvasGradient) receiveUnion(); (object or long) receiveUnion2(); @@ -546,6 +583,7 @@ interface TestInterface { void passOptionalNullableDateWithDefaultValue(optional Date? arg = null); void passDateSequence(sequence arg); void passNullableDateSequence(sequence arg); + void passDateMozMap(MozMap arg); Date receiveDate(); Date? receiveNullableDate(); @@ -572,6 +610,7 @@ interface TestInterface { Dict? receiveNullableDictionary(); void passOtherDictionary(optional GrandparentDict x); void passSequenceOfDictionaries(sequence x); + void passMozMapOfDictionaries(MozMap x); // No support for nullable dictionaries inside a sequence (nor should there be) // void passSequenceOfNullableDictionaries(sequence x); void passDictionaryOrLong(optional Dict x);