MozMap and string stuff

master
Fedor 2019-05-20 09:00:47 +03:00
parent 5670037d3d
commit 7a4ff54306
18 changed files with 520 additions and 423 deletions

View File

@ -2558,7 +2558,7 @@ NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
template<typename T> static void template<typename T> static void
NormalizeUSVStringInternal(JSContext* aCx, T& aString) NormalizeUSVStringInternal(T& aString)
{ {
char16_t* start = aString.BeginWriting(); char16_t* start = aString.BeginWriting();
// Must use const here because we can't pass char** to UTF16CharEnumerator as // Must use const here because we can't pass char** to UTF16CharEnumerator as
@ -2575,15 +2575,15 @@ NormalizeUSVStringInternal(JSContext* aCx, T& aString)
} }
void void
NormalizeUSVString(JSContext* aCx, nsAString& aString) NormalizeUSVString(nsAString& aString)
{ {
NormalizeUSVStringInternal(aCx, aString); NormalizeUSVStringInternal(aString);
} }
void void
NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString) NormalizeUSVString(binding_detail::FakeString& aString)
{ {
NormalizeUSVStringInternal(aCx, aString); NormalizeUSVStringInternal(aString);
} }
bool bool

View File

@ -49,7 +49,7 @@ namespace mozilla {
enum UseCounter : int16_t; enum UseCounter : int16_t;
namespace dom { namespace dom {
template<typename DataType> class MozMap; template<typename KeyType, typename ValueType> class Record;
nsresult nsresult
UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg); UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
@ -2127,11 +2127,30 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
return AssignJSString(cx, result, s); return AssignJSString(cx, result, s);
} }
void template<typename T>
NormalizeUSVString(JSContext* aCx, nsAString& aString); static inline bool
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
{
return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
}
void void
NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString); NormalizeUSVString(nsAString& aString);
void
NormalizeUSVString(binding_detail::FakeString& aString);
template<typename T>
static inline bool
ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
{
if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
return false;
}
NormalizeUSVString(result);
return true;
}
template<typename T> template<typename T>
inline bool inline bool
@ -2158,6 +2177,13 @@ bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v, ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
bool nullable, nsACString& result); bool nullable, nsACString& result);
inline bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
nsACString& result)
{
return ConvertJSValueToByteString(cx, v, false, result);
}
template<typename T> template<typename T>
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq); void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
template<typename T> template<typename T>
@ -2293,31 +2319,26 @@ public:
} }
}; };
template<typename T> template<typename K, typename V>
static void void TraceRecord(JSTracer* trc, Record<K, V>& record)
TraceMozMapValue(T* aValue, void* aClosure)
{ {
JSTracer* trc = static_cast<JSTracer*>(aClosure); for (auto& entry : record.Entries()) {
// Act like it's a one-element sequence to leverage all that infrastructure. // Act like it's a one-element sequence to leverage all that infrastructure.
SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1); SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
}
} }
template<typename T> // sequence<record>
void TraceMozMap(JSTracer* trc, MozMap<T>& map) template<typename K, typename V>
{ class SequenceTracer<Record<K, V>, false, false, false>
map.EnumerateValues(TraceMozMapValue<T>, trc);
}
// sequence<MozMap>
template<typename T>
class SequenceTracer<MozMap<T>, false, false, false>
{ {
explicit SequenceTracer() = delete; // Should never be instantiated explicit SequenceTracer() = delete; // Should never be instantiated
public: public:
static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) { static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
Record<K, V>* end) {
for (; seqp != end; ++seqp) { for (; seqp != end; ++seqp) {
seqp->EnumerateValues(TraceMozMapValue<T>, trc); TraceRecord(trc, *seqp);
} }
} }
}; };
@ -2395,51 +2416,51 @@ public:
SequenceType mSequenceType; SequenceType mSequenceType;
}; };
// Rooter class for MozMap; this is what we mostly use in the codegen. // Rooter class for Record; this is what we mostly use in the codegen.
template<typename T> template<typename K, typename V>
class MOZ_RAII MozMapRooter final : private JS::CustomAutoRooter class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
{ {
public: public:
MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap RecordRooter(JSContext *aCx, Record<K, V>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mMozMap(aMozMap), mRecord(aRecord),
mMozMapType(eMozMap) mRecordType(eRecord)
{ {
} }
MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mNullableMozMap(aMozMap), mNullableRecord(aRecord),
mMozMapType(eNullableMozMap) mRecordType(eNullableRecord)
{ {
} }
private: private:
enum MozMapType { enum RecordType {
eMozMap, eRecord,
eNullableMozMap eNullableRecord
}; };
virtual void trace(JSTracer *trc) override virtual void trace(JSTracer *trc) override
{ {
if (mMozMapType == eMozMap) { if (mRecordType == eRecord) {
TraceMozMap(trc, *mMozMap); TraceRecord(trc, *mRecord);
} else { } else {
MOZ_ASSERT(mMozMapType == eNullableMozMap); MOZ_ASSERT(mRecordType == eNullableRecord);
if (!mNullableMozMap->IsNull()) { if (!mNullableRecord->IsNull()) {
TraceMozMap(trc, mNullableMozMap->Value()); TraceRecord(trc, mNullableRecord->Value());
} }
} }
} }
union { union {
MozMap<T>* mMozMap; Record<K, V>* mRecord;
Nullable<MozMap<T>>* mNullableMozMap; Nullable<Record<K, V>>* mNullableRecord;
}; };
MozMapType mMozMapType; RecordType mRecordType;
}; };
template<typename T> template<typename T>

View File

@ -84,7 +84,7 @@ def idlTypeNeedsCycleCollection(type):
return True return True
elif type.isUnion(): elif type.isUnion():
return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes) return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
elif type.isMozMap(): elif type.isRecord():
if idlTypeNeedsCycleCollection(type.inner): if idlTypeNeedsCycleCollection(type.inner):
raise TypeError("Cycle collection for type %s is not supported" % type) raise TypeError("Cycle collection for type %s is not supported" % type)
return False return False
@ -996,6 +996,8 @@ class CGElseChain(CGThing):
class CGTemplatedType(CGWrapper): class CGTemplatedType(CGWrapper):
def __init__(self, templateName, child, isConst=False, isReference=False): def __init__(self, templateName, child, isConst=False, isReference=False):
if isinstance(child, list):
child = CGList(child, ", ")
const = "const " if isConst else "" const = "const " if isConst else ""
pre = "%s%s<" % (const, templateName) pre = "%s%s<" % (const, templateName)
ref = "&" if isReference else "" ref = "&" if isReference else ""
@ -1171,12 +1173,12 @@ class CGHeaders(CGWrapper):
declareIncludes.add(filename) declareIncludes.add(filename)
elif unrolled.isPrimitive(): elif unrolled.isPrimitive():
bindingHeaders.add("mozilla/dom/PrimitiveConversions.h") bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
elif unrolled.isMozMap(): elif unrolled.isRecord():
if dictionary or jsImplementedDescriptors: if dictionary or jsImplementedDescriptors:
declareIncludes.add("mozilla/dom/MozMap.h") declareIncludes.add("mozilla/dom/Record.h")
else: else:
bindingHeaders.add("mozilla/dom/MozMap.h") bindingHeaders.add("mozilla/dom/Record.h")
# Also add headers for the type the MozMap is # Also add headers for the type the record is
# parametrized over, if needed. # parametrized over, if needed.
addHeadersForType((t.inner, dictionary)) addHeadersForType((t.inner, dictionary))
@ -1388,8 +1390,8 @@ def UnionTypes(unionTypes, config):
# the right header to be able to Release() in our inlined # the right header to be able to Release() in our inlined
# code. # code.
headers.add(CGHeaders.getDeclarationFilename(f.callback)) headers.add(CGHeaders.getDeclarationFilename(f.callback))
elif f.isMozMap(): elif f.isRecord():
headers.add("mozilla/dom/MozMap.h") headers.add("mozilla/dom/Record.h")
# And add headers for the type we're parametrized over # And add headers for the type we're parametrized over
addHeadersForType(f.inner) addHeadersForType(f.inner)
@ -1448,9 +1450,9 @@ def UnionConversions(unionTypes, config):
headers.add(CGHeaders.getDeclarationFilename(f.inner)) headers.add(CGHeaders.getDeclarationFilename(f.inner))
elif f.isPrimitive(): elif f.isPrimitive():
headers.add("mozilla/dom/PrimitiveConversions.h") headers.add("mozilla/dom/PrimitiveConversions.h")
elif f.isMozMap(): elif f.isRecord():
headers.add("mozilla/dom/MozMap.h") headers.add("mozilla/dom/Record.h")
# And the internal type of the MozMap # And the internal type of the record
addHeadersForType(f.inner) addHeadersForType(f.inner)
# We plan to include UnionTypes.h no matter what, so it's # We plan to include UnionTypes.h no matter what, so it's
@ -4290,6 +4292,9 @@ class JSToNativeConversionInfo():
for whether we have a JS::Value. Only used when for whether we have a JS::Value. Only used when
defaultValue is not None or when True is passed for defaultValue is not None or when True is passed for
checkForValue to instantiateJSToNativeConversion. checkForValue to instantiateJSToNativeConversion.
This expression may not be already-parenthesized, so if
you use it with && or || make sure to put parens
around it.
${passedToJSImpl} replaced by an expression that evaluates to a boolean ${passedToJSImpl} replaced by an expression that evaluates to a boolean
for whether this value is being passed to a JS- for whether this value is being passed to a JS-
implemented interface. implemented interface.
@ -4355,7 +4360,9 @@ def handleDefaultStringValue(defaultValue, method):
passing as the second argument of handleDefault; in particular it does not passing as the second argument of handleDefault; in particular it does not
end with a ';' end with a ';'
""" """
assert defaultValue.type.isDOMString() or defaultValue.type.isByteString() assert (defaultValue.type.isDOMString() or
defaultValue.type.isUSVString() or
defaultValue.type.isByteString())
return ("static const %(char_t)s data[] = { %(data)s };\n" return ("static const %(char_t)s data[] = { %(data)s };\n"
"%(method)s(data, ArrayLength(data) - 1)") % { "%(method)s(data, ArrayLength(data) - 1)") % {
'char_t': "char" if defaultValue.type.isByteString() else "char16_t", 'char_t': "char" if defaultValue.type.isByteString() else "char16_t",
@ -4365,6 +4372,17 @@ def handleDefaultStringValue(defaultValue, method):
} }
def recordKeyType(recordType):
assert recordType.keyType.isString()
if recordType.keyType.isByteString():
return "nsCString"
return "nsString"
def recordKeyDeclType(recordType):
return CGGeneric(recordKeyType(recordType))
# If this function is modified, modify CGNativeMember.getArg and # If this function is modified, modify CGNativeMember.getArg and
# CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype # CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
# and holdertype we end up using, because it needs to be able to return the code # and holdertype we end up using, because it needs to be able to return the code
@ -4559,7 +4577,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declArgs = "cx" declArgs = "cx"
else: else:
assert (isMember in assert (isMember in
("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap")) ("Sequence", "Variadic", "Dictionary", "OwningUnion", "Record"))
# We'll get traced by the sequence or dictionary or union tracer # We'll get traced by the sequence or dictionary or union tracer
declType = CGGeneric("JSObject*") declType = CGGeneric("JSObject*")
declArgs = None declArgs = None
@ -4725,39 +4743,41 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
dealWithOptional=isOptional, dealWithOptional=isOptional,
holderArgs=holderArgs) holderArgs=holderArgs)
if type.isMozMap(): if type.isRecord():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
if failureCode is None: if failureCode is None:
notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n' notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode)) "%s" % (firstCap(sourceDescription), exceptionCode))
else: else:
notMozMap = failureCode notRecord = failureCode
nullable = type.nullable() nullable = type.nullable()
# Be very careful not to change "type": we need it later # Be very careful not to change "type": we need it later
if nullable: if nullable:
valueType = type.inner.inner recordType = type.inner
else: else:
valueType = type.inner recordType = type
valueType = recordType.inner
valueInfo = getJSToNativeConversionInfo( valueInfo = getJSToNativeConversionInfo(
valueType, descriptorProvider, isMember="MozMap", valueType, descriptorProvider, isMember="Record",
exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode, exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
isCallbackReturnValue=isCallbackReturnValue, isCallbackReturnValue=isCallbackReturnValue,
sourceDescription="value in %s" % sourceDescription, sourceDescription="value in %s" % sourceDescription,
nestingLevel=incrementNestingLevel()) nestingLevel=incrementNestingLevel())
if valueInfo.dealWithOptional: if valueInfo.dealWithOptional:
raise TypeError("Shouldn't have optional things in MozMap") raise TypeError("Shouldn't have optional things in record")
if valueInfo.holderType is not None: if valueInfo.holderType is not None:
raise TypeError("Shouldn't need holders for MozMap") raise TypeError("Shouldn't need holders for record")
typeName = CGTemplatedType("MozMap", valueInfo.declType) declType = CGTemplatedType("Record", [recordKeyDeclType(recordType),
mozMapType = typeName.define() valueInfo.declType])
typeName = declType.define()
if nullable: if nullable:
typeName = CGTemplatedType("Nullable", typeName) declType = CGTemplatedType("Nullable", declType)
mozMapRef = "${declName}.SetValue()" recordRef = "${declName}.SetValue()"
else: else:
mozMapRef = "${declName}" recordRef = "${declName}"
valueConversion = string.Template(valueInfo.template).substitute({ valueConversion = string.Template(valueInfo.template).substitute({
"val": "temp", "val": "temp",
@ -4770,68 +4790,124 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
"passedToJSImpl": "${passedToJSImpl}" "passedToJSImpl": "${passedToJSImpl}"
}) })
keyType = recordKeyType(recordType)
if recordType.keyType.isByteString():
keyConversionFunction = "ConvertJSValueToByteString"
hashKeyType = "nsCStringHashKey"
else:
hashKeyType = "nsStringHashKey"
if recordType.keyType.isDOMString():
keyConversionFunction = "ConvertJSValueToString"
else:
assert recordType.keyType.isUSVString()
keyConversionFunction = "ConvertJSValueToUSVString"
templateBody = fill( templateBody = fill(
""" """
${mozMapType} &mozMap = ${mozMapRef}; auto& recordEntries = ${recordRef}.Entries();
JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject()); JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx)); JS::AutoIdVector ids(cx);
if (!JS_Enumerate(cx, mozMapObj, &ids)) { // Keep skipping symbols until
// https://github.com/heycam/webidl/issues/294 is sorted out.
if (!js::GetPropertyKeys(cx, recordObj,
JSITER_OWNONLY | JSITER_HIDDEN, &ids)) {
$*{exceptionCode}
}
if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
JS_ReportOutOfMemory(cx);
$*{exceptionCode} $*{exceptionCode}
} }
JS::Rooted<JS::Value> propNameValue(cx); JS::Rooted<JS::Value> propNameValue(cx);
JS::Rooted<JS::Value> temp(cx); JS::Rooted<JS::Value> temp(cx);
JS::Rooted<jsid> curId(cx); JS::Rooted<jsid> curId(cx);
JS::Rooted<JS::Value> idVal(cx);
// Use a hashset to keep track of ids seen, to avoid
// introducing nasty O(N^2) behavior scanning for them all the
// time. Ideally we'd use a data structure with O(1) lookup
// _and_ ordering for the MozMap, but we don't have one lying
// around.
nsTHashtable<${hashKeyType}> idsSeen;
for (size_t i = 0; i < ids.length(); ++i) { 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]; curId = ids[i];
binding_detail::FakeString propName;
bool isSymbol; MOZ_ASSERT(!JSID_IS_SYMBOL(curId), "No symbols, we said!");
if (!ConvertIdToString(cx, curId, propName, isSymbol) ||
(!isSymbol && !JS_GetPropertyById(cx, mozMapObj, curId, &temp))) { JS::Rooted<JS::PropertyDescriptor> desc(cx);
if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
&desc)) {
$*{exceptionCode} $*{exceptionCode}
} }
if (isSymbol) {
if (!desc.object() /* == undefined in spec terms */ ||
!desc.enumerable()) {
continue; continue;
} }
${valueType}* slotPtr = mozMap.AddEntry(propName); idVal = js::IdToValue(curId);
if (!slotPtr) { ${keyType} propName;
JS_ReportOutOfMemory(cx); if (!${keyConversionFunction}(cx, idVal, propName)) {
$*{exceptionCode} $*{exceptionCode}
} }
${valueType}& slot = *slotPtr;
if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
$*{exceptionCode}
}
${typeName}::EntryType* entry;
if (idsSeen.Contains(propName)) {
// Find the existing entry.
auto idx = recordEntries.IndexOf(propName);
MOZ_ASSERT(idx != recordEntries.NoIndex,
"Why is it not found?");
// Now blow it away to make it look like it was just added
// to the array, because it's not obvious that it's
// safe to write to its already-initialized mValue via our
// normal codegen conversions. For example, the value
// could be a union and this would change its type, but
// codegen assumes we won't do that.
entry = recordEntries.ReconstructElementAt(idx);
} else {
// Safe to do an infallible append here, because we did a
// SetCapacity above to the right capacity.
entry = recordEntries.AppendElement();
idsSeen.PutEntry(propName);
}
entry->mKey = propName;
${valueType}& slot = entry->mValue;
$*{valueConversion} $*{valueConversion}
} }
""", """,
exceptionCode=exceptionCode, exceptionCode=exceptionCode,
mozMapType=mozMapType, recordRef=recordRef,
mozMapRef=mozMapRef, hashKeyType=hashKeyType,
keyType=keyType,
keyConversionFunction=keyConversionFunction,
typeName=typeName,
valueType=valueInfo.declType.define(), valueType=valueInfo.declType.define(),
valueConversion=valueConversion) valueConversion=valueConversion)
templateBody = wrapObjectTemplate(templateBody, type, templateBody = wrapObjectTemplate(templateBody, type,
"${declName}.SetNull();\n", "${declName}.SetNull();\n",
notMozMap) notRecord)
declType = typeName
declArgs = None declArgs = None
holderType = None holderType = None
holderArgs = None holderArgs = None
# MozMap arguments that might contain traceable things need # record arguments that might contain traceable things need
# to get traced # to get traced
if not isMember and isCallbackReturnValue: if not isMember and isCallbackReturnValue:
# Go ahead and just convert directly into our actual return value # Go ahead and just convert directly into our actual return value
declType = CGWrapper(declType, post="&") declType = CGWrapper(declType, post="&")
declArgs = "aRetVal" declArgs = "aRetVal"
elif not isMember and typeNeedsRooting(valueType): elif not isMember and typeNeedsRooting(valueType):
holderType = CGTemplatedType("MozMapRooter", valueInfo.declType) holderType = CGTemplatedType("RecordRooter",
# If our MozMap is nullable, this will set the Nullable to be [recordKeyDeclType(recordType),
valueInfo.declType])
# If our record is nullable, this will set the Nullable to be
# not-null, but that's ok because we make an explicit SetNull() call # not-null, but that's ok because we make an explicit SetNull() call
# on it as needed if our JS value is actually null. # on it as needed if our JS value is actually null.
holderArgs = "cx, &%s" % mozMapRef holderArgs = "cx, &%s" % recordRef
return JSToNativeConversionInfo(templateBody, declType=declType, return JSToNativeConversionInfo(templateBody, declType=declType,
declArgs=declArgs, declArgs=declArgs,
@ -4914,16 +4990,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else: else:
setDictionary = None setDictionary = None
mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes) recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
if len(mozMapMemberTypes) > 0: if len(recordMemberTypes) > 0:
assert len(mozMapMemberTypes) == 1 assert len(recordMemberTypes) == 1
name = getUnionMemberName(mozMapMemberTypes[0]) name = getUnionMemberName(recordMemberTypes[0])
mozMapObject = CGGeneric( recordObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" % "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name)) (unionArgumentObj, name))
names.append(name) names.append(name)
else: else:
mozMapObject = None recordObject = None
objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
if len(objectMemberTypes) > 0: if len(objectMemberTypes) > 0:
@ -4939,10 +5015,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else: else:
object = None object = None
hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or recordObject
if hasObjectTypes: if hasObjectTypes:
# "object" is not distinguishable from other types # "object" is not distinguishable from other types
assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject) assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or recordObject)
if sequenceObject or dateObject or callbackObject: if sequenceObject or dateObject or callbackObject:
# An object can be both an sequence object and a callback or # An object can be both an sequence object and a callback or
# dictionary, but we shouldn't have both in the union's members # dictionary, but we shouldn't have both in the union's members
@ -4962,9 +5038,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if dateObject: if dateObject:
templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n")) templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
if mozMapObject: if recordObject:
templateBody = CGList([templateBody, templateBody = CGList([templateBody,
CGIfWrapper(mozMapObject, "!done")]) CGIfWrapper(recordObject, "!done")])
templateBody = CGIfWrapper(templateBody, "${val}.isObject()") templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
else: else:
@ -5144,7 +5220,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if isinstance(defaultValue, IDLNullValue): if isinstance(defaultValue, IDLNullValue):
extraConditionForNull = "!(${haveValue}) || " extraConditionForNull = "!(${haveValue}) || "
else: else:
extraConditionForNull = "${haveValue} && " extraConditionForNull = "(${haveValue}) && "
else: else:
extraConditionForNull = "" extraConditionForNull = ""
templateBody = handleNull(templateBody, declLoc, templateBody = handleNull(templateBody, declLoc,
@ -5525,7 +5601,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
def getConversionCode(varName): def getConversionCode(varName):
normalizeCode = "" normalizeCode = ""
if type.isUSVString(): if type.isUSVString():
normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName normalizeCode = "NormalizeUSVString(%s);\n" % varName
conversionCode = fill(""" conversionCode = fill("""
if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) { if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
@ -5688,7 +5764,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
haveCallable = "${val}.isObject() && " + haveCallable haveCallable = "${val}.isObject() && " + haveCallable
if defaultValue is not None: if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue)) assert(isinstance(defaultValue, IDLNullValue))
haveCallable = "${haveValue} && " + haveCallable haveCallable = "(${haveValue}) && " + haveCallable
template = ( template = (
("if (%s) {\n" % haveCallable) + ("if (%s) {\n" % haveCallable) +
conversion + conversion +
@ -5700,7 +5776,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
haveObject = "${val}.isObject()" haveObject = "${val}.isObject()"
if defaultValue is not None: if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue)) assert(isinstance(defaultValue, IDLNullValue))
haveObject = "${haveValue} && " + haveObject haveObject = "(${haveValue}) && " + haveObject
template = CGIfElseWrapper(haveObject, template = CGIfElseWrapper(haveObject,
CGGeneric(conversion), CGGeneric(conversion),
CGGeneric("${declName} = nullptr;\n")).define() CGGeneric("${declName} = nullptr;\n")).define()
@ -5724,7 +5800,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
declArgs = None declArgs = None
if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"): if isMember in ("Variadic", "Sequence", "Dictionary", "Record"):
# Rooting is handled by the sequence and dictionary tracers. # Rooting is handled by the sequence and dictionary tracers.
declType = "JS::Value" declType = "JS::Value"
else: else:
@ -5768,8 +5844,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription) return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
if type.isDictionary(): if type.isDictionary():
# There are no nullable dictionaries # There are no nullable dictionary arguments or dictionary members
assert not type.nullable() or isCallbackReturnValue assert(not type.nullable() or isCallbackReturnValue or
(isMember and isMember != "Dictionary"))
# All optional dictionaries always have default values, so we # All optional dictionaries always have default values, so we
# should be able to assume not isOptional here. # should be able to assume not isOptional here.
assert not isOptional assert not isOptional
@ -6256,7 +6333,7 @@ def getMaybeWrapValueFuncForType(type):
sequenceWrapLevel = 0 sequenceWrapLevel = 0
mozMapWrapLevel = 0 recordWrapLevel = 0
def getWrapTemplateForType(type, descriptorProvider, result, successCode, def getWrapTemplateForType(type, descriptorProvider, result, successCode,
@ -6361,7 +6438,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if type is None or type.isVoid(): if type is None or type.isVoid():
return (setUndefined(), True) return (setUndefined(), True)
if (type.isSequence() or type.isMozMap()) and type.nullable(): if (type.isSequence() or type.isRecord()) and type.nullable():
# These are both wrapped in Nullable<> # These are both wrapped in Nullable<>
recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider, recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode, "%s.Value()" % result, successCode,
@ -6434,14 +6511,14 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
return (code, False) return (code, False)
if type.isMozMap(): if type.isRecord():
# Now do non-nullable MozMap. Our success code is just to break to # Now do non-nullable record. Our success code is just to break to
# where we define the property on the object. Note that we bump the # where we define the property on the object. Note that we bump the
# mozMapWrapLevel around this call so that nested MozMap conversions # recordWrapLevel around this call so that nested record conversions
# will use different temp value names. # will use different temp value names.
global mozMapWrapLevel global recordWrapLevel
valueName = "mozMapValue%d" % mozMapWrapLevel valueName = "recordValue%d" % recordWrapLevel
mozMapWrapLevel += 1 recordWrapLevel += 1
innerTemplate = wrapForType( innerTemplate = wrapForType(
type.inner, descriptorProvider, type.inner, descriptorProvider,
{ {
@ -6454,12 +6531,22 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
'obj': "returnObj", 'obj': "returnObj",
'typedArraysAreStructs': typedArraysAreStructs 'typedArraysAreStructs': typedArraysAreStructs
}) })
mozMapWrapLevel -= 1 recordWrapLevel -= 1
if type.keyType.isByteString():
# There is no length-taking JS_DefineProperty. So to keep
# things sane with embedded nulls, we want to byte-inflate
# to an nsAString. The only byte-inflation function we
# have around is AppendASCIItoUTF16, which luckily doesn't
# assert anything about the input being ASCII.
expandedKeyDecl = "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
keyName = "expandedKey"
else:
expandedKeyDecl = ""
keyName = "entry.mKey"
code = fill( code = fill(
""" """
nsTArray<nsString> keys;
${result}.GetKeys(keys);
JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx)); JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
if (!returnObj) { if (!returnObj) {
$*{exceptionCode} $*{exceptionCode}
@ -6467,15 +6554,17 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
// Scope for 'tmp' // Scope for 'tmp'
{ {
JS::Rooted<JS::Value> tmp(cx); JS::Rooted<JS::Value> tmp(cx);
for (size_t idx = 0; idx < keys.Length(); ++idx) { for (auto& entry : ${result}.Entries()) {
auto& ${valueName} = ${result}.Get(keys[idx]); auto& ${valueName} = entry.mValue;
// Control block to let us common up the JS_DefineUCProperty calls when there // Control block to let us common up the JS_DefineUCProperty calls when there
// are different ways to succeed at wrapping the value. // are different ways to succeed at wrapping the value.
do { do {
$*{innerTemplate} $*{innerTemplate}
} while (0); } while (0);
if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(), $*{expandedKeyDecl}
keys[idx].Length(), tmp, if (!JS_DefineUCProperty(cx, returnObj,
${keyName}.BeginReading(),
${keyName}.Length(), tmp,
JSPROP_ENUMERATE)) { JSPROP_ENUMERATE)) {
$*{exceptionCode} $*{exceptionCode}
} }
@ -6487,6 +6576,8 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
exceptionCode=exceptionCode, exceptionCode=exceptionCode,
valueName=valueName, valueName=valueName,
innerTemplate=innerTemplate, innerTemplate=innerTemplate,
expandedKeyDecl=expandedKeyDecl,
keyName=keyName,
set=setObject("*returnObj")) set=setObject("*returnObj"))
return (code, False) return (code, False)
@ -6770,7 +6861,7 @@ def typeMatchesLambda(type, func):
return False return False
if type.nullable(): if type.nullable():
return typeMatchesLambda(type.inner, func) return typeMatchesLambda(type.inner, func)
if type.isSequence() or type.isMozMap(): if type.isSequence() or type.isRecord():
return typeMatchesLambda(type.inner, func) return typeMatchesLambda(type.inner, func)
if type.isUnion(): if type.isUnion():
return any(typeMatchesLambda(t, func) for t in return any(typeMatchesLambda(t, func) for t in
@ -6866,20 +6957,21 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
if nullable: if nullable:
result = CGTemplatedType("Nullable", result) result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None return result, "ref", rooter, None, None
if returnType.isMozMap(): if returnType.isRecord():
nullable = returnType.nullable() nullable = returnType.nullable()
if nullable: if nullable:
returnType = returnType.inner returnType = returnType.inner
result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner, result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
descriptorProvider, descriptorProvider,
isMember="MozMap") isMember="Record")
# While we have our inner type, set up our rooter, if needed # While we have our inner type, set up our rooter, if needed
if not isMember and typeNeedsRooting(returnType): if not isMember and typeNeedsRooting(returnType):
rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" % rooter = CGGeneric("RecordRooter<%s> resultRooter(cx, &result);\n" %
result.define()) ("nsString, " + result.define()))
else: else:
rooter = None rooter = None
result = CGTemplatedType("MozMap", result) result = CGTemplatedType("Record", [recordKeyDeclType(returnType),
result])
if nullable: if nullable:
result = CGTemplatedType("Nullable", result) result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None return result, "ref", rooter, None, None
@ -6976,7 +7068,7 @@ class CGCallGenerator(CGThing):
return True return True
if a.type.isSequence(): if a.type.isSequence():
return True return True
if a.type.isMozMap(): if a.type.isRecord():
return True return True
# isObject() types are always a JS::Rooted, whether # isObject() types are always a JS::Rooted, whether
# nullable or not, and it turns out a const JS::Rooted # nullable or not, and it turns out a const JS::Rooted
@ -7138,7 +7230,7 @@ class MethodNotNewObjectError(Exception):
# nested sequences we don't use the same variable name to iterate over # nested sequences we don't use the same variable name to iterate over
# different sequences. # different sequences.
sequenceWrapLevel = 0 sequenceWrapLevel = 0
mapWrapLevel = 0 recordWrapLevel = 0
def wrapTypeIntoCurrentCompartment(type, value, isMember=True): def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
@ -7199,29 +7291,27 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue) wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
return wrapCode return wrapCode
if type.isMozMap(): if type.isRecord():
origValue = value
origType = type origType = type
if type.nullable(): if type.nullable():
type = type.inner type = type.inner
value = "%s.Value()" % value recordRef = "%s.Value()" % value
global mapWrapLevel else:
key = "mapName%d" % mapWrapLevel recordRef = value
mapWrapLevel += 1 global recordWrapLevel
entryRef = "mapEntry%d" % recordWrapLevel
recordWrapLevel += 1
wrapElement = wrapTypeIntoCurrentCompartment(type.inner, wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
"%s.Get(%sKeys[%sIndex])" % (value, key, key)) "%s.mValue" % entryRef)
mapWrapLevel -= 1 recordWrapLevel -= 1
if not wrapElement: if not wrapElement:
return None return None
wrapCode = CGWrapper(CGIndenter(wrapElement), wrapCode = CGWrapper(CGIndenter(wrapElement),
pre=(""" pre=("for (auto& %s : %s.Entries()) {\n" %
nsTArray<nsString> %sKeys; (entryRef, recordRef)),
%s.GetKeys(%sKeys);
for (uint32_t %sIndex = 0; %sIndex < %sKeys.Length(); ++%sIndex) {
""" % (key, value, key, key, key, key, key)),
post="}\n") post="}\n")
if origType.nullable(): if origType.nullable():
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue) wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % value)
return wrapCode return wrapCode
if type.isDictionary(): if type.isDictionary():
@ -8110,11 +8200,11 @@ class CGMethodCall(CGThing):
if distinguishingType(s).isSequence()) if distinguishingType(s).isSequence())
# Now append all the overloads that take a dictionary or callback # Now append all the overloads that take a dictionary or callback
# interface or MozMap. There should be only one of these! # interface or record. There should be only one of these!
genericObjectSigs = [ genericObjectSigs = [
s for s in possibleSignatures s for s in possibleSignatures
if (distinguishingType(s).isDictionary() or if (distinguishingType(s).isDictionary() or
distinguishingType(s).isMozMap() or distinguishingType(s).isRecord() or
distinguishingType(s).isCallbackInterface())] distinguishingType(s).isCallbackInterface())]
assert len(genericObjectSigs) <= 1 assert len(genericObjectSigs) <= 1
objectSigs.extend(genericObjectSigs) objectSigs.extend(genericObjectSigs)
@ -9408,7 +9498,7 @@ class CGMemberJITInfo(CGThing):
return "JSVAL_TYPE_UNDEFINED" return "JSVAL_TYPE_UNDEFINED"
if t.isSequence(): if t.isSequence():
return "JSVAL_TYPE_OBJECT" return "JSVAL_TYPE_OBJECT"
if t.isMozMap(): if t.isRecord():
return "JSVAL_TYPE_OBJECT" return "JSVAL_TYPE_OBJECT"
if t.isGeckoInterface(): if t.isGeckoInterface():
return "JSVAL_TYPE_OBJECT" return "JSVAL_TYPE_OBJECT"
@ -9669,17 +9759,22 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
# Flat member types have already unwrapped nullables. # Flat member types have already unwrapped nullables.
assert not type.nullable() assert not type.nullable()
if type.isSequence() or type.isMozMap(): if type.isSequence() or type.isRecord():
if type.isSequence(): if type.isSequence():
wrapperType = "Sequence" wrapperType = "Sequence"
else: else:
wrapperType = "MozMap" wrapperType = "Record"
# We don't use the returned template here, so it's OK to just pass no # We don't use the returned template here, so it's OK to just pass no
# sourceDescription. # sourceDescription.
elementInfo = getJSToNativeConversionInfo(type.inner, elementInfo = getJSToNativeConversionInfo(type.inner,
descriptorProvider, descriptorProvider,
isMember=wrapperType) isMember=wrapperType)
return CGTemplatedType(wrapperType, elementInfo.declType, if wrapperType == "Sequence":
innerType = elementInfo.declType
else:
innerType = [recordKeyDeclType(type), elementInfo.declType]
return CGTemplatedType(wrapperType, innerType,
isConst=True, isReference=True) isConst=True, isReference=True)
# Nested unions are unwrapped automatically into our flatMemberTypes. # Nested unions are unwrapped automatically into our flatMemberTypes.
@ -10040,10 +10135,10 @@ class CGUnionStruct(CGThing):
CGCase("e" + vars["name"], CGCase("e" + vars["name"],
CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" % CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" %
vars["name"]))) vars["name"])))
elif t.isMozMap(): elif t.isRecord():
traceCases.append( traceCases.append(
CGCase("e" + vars["name"], CGCase("e" + vars["name"],
CGGeneric("TraceMozMap(trc, mValue.m%s.Value());\n" % CGGeneric("TraceRecord(trc, mValue.m%s.Value());\n" %
vars["name"]))) vars["name"])))
else: else:
assert t.isSpiderMonkeyInterface() assert t.isSpiderMonkeyInterface()
@ -13172,8 +13267,8 @@ class CGDictionary(CGThing):
trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData) trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
if type.nullable(): if type.nullable():
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable) trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
elif type.isMozMap(): elif type.isRecord():
# If you implement this, add a MozMap<object> to # If you implement this, add a record<DOMString, object> to
# TestInterfaceJSDictionary and test it in test_bug1036214.html # TestInterfaceJSDictionary and test it in test_bug1036214.html
# to make sure we end up with the correct security properties. # to make sure we end up with the correct security properties.
assert False assert False
@ -13583,7 +13678,7 @@ class ForwardDeclarationBuilder:
# since we don't know which one we might want # since we don't know which one we might want
self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False)) self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False))
self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True)) self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True))
elif t.isMozMap(): elif t.isRecord():
self.forwardDeclareForType(t.inner, config) self.forwardDeclareForType(t.inner, config)
# Don't need to do anything for void, primitive, string, any or object. # Don't need to do anything for void, primitive, string, any or object.
# There may be some other cases we are missing. # There may be some other cases we are missing.
@ -14089,9 +14184,9 @@ class CGNativeMember(ClassMethod):
else: else:
returnCode = "aRetVal.SwapElements(${declName});\n" returnCode = "aRetVal.SwapElements(${declName});\n"
return "void", "", returnCode return "void", "", returnCode
if type.isMozMap(): if type.isRecord():
# If we want to handle MozMap-of-MozMap return values, we're # If we want to handle record-of-record return values, we're
# going to need to fix example codegen to not produce MozMap<void> # going to need to fix example codegen to not produce record<void>
# for the relevant argument... # for the relevant argument...
assert not isMember assert not isMember
# In this case we convert directly into our outparam to start with # In this case we convert directly into our outparam to start with
@ -14139,13 +14234,14 @@ class CGNativeMember(ClassMethod):
if nullable: if nullable:
type = CGTemplatedType("Nullable", type) type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal")) args.append(Argument("%s&" % type.define(), "aRetVal"))
elif returnType.isMozMap(): elif returnType.isRecord():
nullable = returnType.nullable() nullable = returnType.nullable()
if nullable: if nullable:
returnType = returnType.inner returnType = returnType.inner
# And now the actual underlying type # And now the actual underlying type
elementDecl = self.getReturnType(returnType.inner, True) elementDecl = self.getReturnType(returnType.inner, True)
type = CGTemplatedType("MozMap", CGGeneric(elementDecl)) type = CGTemplatedType("Record", [recordKeyDeclType(returnType),
CGGeneric(elementDecl)])
if nullable: if nullable:
type = CGTemplatedType("Nullable", type) type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal")) args.append(Argument("%s&" % type.define(), "aRetVal"))
@ -14206,7 +14302,7 @@ class CGNativeMember(ClassMethod):
Nullable as needed. Nullable as needed.
isMember can be false or one of the strings "Sequence", "Variadic", isMember can be false or one of the strings "Sequence", "Variadic",
"MozMap" "Record"
""" """
if type.isSequence(): if type.isSequence():
nullable = type.nullable() nullable = type.nullable()
@ -14217,13 +14313,13 @@ class CGNativeMember(ClassMethod):
decl = CGTemplatedType("Sequence", argType) decl = CGTemplatedType("Sequence", argType)
return decl.define(), True, True return decl.define(), True, True
if type.isMozMap(): if type.isRecord():
nullable = type.nullable() nullable = type.nullable()
if nullable: if nullable:
type = type.inner type = type.inner
elementType = type.inner elementType = type.inner
argType = self.getArgType(elementType, False, "MozMap")[0] argType = self.getArgType(elementType, False, "Record")[0]
decl = CGTemplatedType("MozMap", argType) decl = CGTemplatedType("Record", [recordKeyDeclType(type), argType])
return decl.define(), True, True return decl.define(), True, True
if type.isUnion(): if type.isUnion():

View File

@ -115,7 +115,7 @@ class Configuration(DescriptorProvider):
for (t, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks): for (t, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
while True: while True:
if t.isMozMap(): if t.isRecord():
t = t.inner t = t.inner
elif t.unroll() != t: elif t.unroll() != t:
t = t.unroll() t = t.unroll()

View File

@ -1,121 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/**
* Class for representing MozMap arguments. This is an nsTHashtable
* under the hood, but we don't want to leak that implementation
* detail.
*/
#ifndef mozilla_dom_MozMap_h
#define mozilla_dom_MozMap_h
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
namespace mozilla {
namespace dom {
namespace binding_detail {
template<typename DataType>
class MozMapEntry : public nsStringHashKey
{
public:
explicit MozMapEntry(const nsAString* aKeyTypePointer)
: nsStringHashKey(aKeyTypePointer)
{
}
// Move constructor so we can do MozMaps of MozMaps.
MozMapEntry(MozMapEntry<DataType>&& aOther)
: nsStringHashKey(aOther),
mData(Move(aOther.mData))
{
}
DataType mData;
};
} // namespace binding_detail
template<typename DataType>
class MozMap : protected nsTHashtable<binding_detail::MozMapEntry<DataType>>
{
public:
typedef typename binding_detail::MozMapEntry<DataType> EntryType;
typedef nsTHashtable<EntryType> Base;
typedef MozMap<DataType> SelfType;
MozMap()
{
}
// Move constructor so we can do MozMap of MozMap.
MozMap(SelfType&& aOther) :
Base(Move(aOther))
{
}
// The return value is only safe to use until an AddEntry call.
const DataType& Get(const nsAString& aKey) const
{
const EntryType* ent = this->GetEntry(aKey);
MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?");
return ent->mData;
}
DataType& Get(const nsAString& aKey)
{
EntryType* ent = this->GetEntry(aKey);
MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?");
return ent->mData;
}
// The return value is only safe to use until an AddEntry call.
const DataType* GetIfExists(const nsAString& aKey) const
{
const EntryType* ent = this->GetEntry(aKey);
if (!ent) {
return nullptr;
}
return &ent->mData;
}
void GetKeys(nsTArray<nsString>& aKeys) const {
for (auto iter = this->ConstIter(); !iter.Done(); iter.Next()) {
aKeys.AppendElement(iter.Get()->GetKey());
}
}
// XXXbz we expose this generic enumerator for tracing. Otherwise we'd end up
// with a dependency on BindingUtils.h here for the SequenceTracer bits.
typedef void (* Enumerator)(DataType* aValue, void* aClosure);
void EnumerateValues(Enumerator aEnumerator, void *aClosure)
{
for (auto iter = this->Iter(); !iter.Done(); iter.Next()) {
aEnumerator(&iter.Get()->mData, aClosure);
}
}
MOZ_MUST_USE
DataType* AddEntry(const nsAString& aKey)
{
EntryType* ent = this->PutEntry(aKey, fallible);
if (!ent) {
return nullptr;
}
return &ent->mData;
}
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MozMap_h

91
dom/bindings/Record.h Normal file
View File

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/**
* Class for representing record arguments. Basically an array under the hood.
*/
#ifndef mozilla_dom_Record_h
#define mozilla_dom_Record_h
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
namespace mozilla {
namespace dom {
namespace binding_detail {
template<typename KeyType, typename ValueType>
class RecordEntry
{
public:
RecordEntry()
{
}
// Move constructor so we can do Records of Records.
RecordEntry(RecordEntry<KeyType, ValueType>&& aOther)
: mKey(Move(aOther.mKey)),
mValue(Move(aOther.mValue))
{
}
KeyType mKey;
ValueType mValue;
};
} // namespace binding_detail
template<typename KeyType, typename ValueType>
class Record
{
public:
typedef typename binding_detail::RecordEntry<KeyType, ValueType> EntryType;
typedef Record<KeyType, ValueType> SelfType;
Record()
{
}
// Move constructor so we can do Record of Record.
Record(SelfType&& aOther) :
mEntries(Move(aOther.mEntries))
{
}
const nsTArray<EntryType>& Entries() const
{
return mEntries;
}
nsTArray<EntryType>& Entries()
{
return mEntries;
}
private:
nsTArray<EntryType> mEntries;
};
} // namespace dom
} // namespace mozilla
template<typename K, typename V>
class nsDefaultComparator<mozilla::dom::binding_detail::RecordEntry<K, V>, K>
{
public:
bool Equals(const mozilla::dom::binding_detail::RecordEntry<K, V>& aEntry,
const K& aKey) const
{
return aEntry.mKey == aKey;
}
};
#endif // mozilla_dom_Record_h

View File

@ -32,10 +32,10 @@ EXPORTS.mozilla.dom += [
'FakeString.h', 'FakeString.h',
'IterableIterator.h', 'IterableIterator.h',
'JSSlots.h', 'JSSlots.h',
'MozMap.h',
'NonRefcountedDOMObject.h', 'NonRefcountedDOMObject.h',
'Nullable.h', 'Nullable.h',
'PrimitiveConversions.h', 'PrimitiveConversions.h',
'Record.h',
'RootedDictionary.h', 'RootedDictionary.h',
'SimpleGlobalObject.h', 'SimpleGlobalObject.h',
'StructuredClone.h', 'StructuredClone.h',

View File

@ -1867,7 +1867,7 @@ class IDLDictionary(IDLObjectWithScope):
if (memberType.nullable() or if (memberType.nullable() or
memberType.isSequence() or memberType.isSequence() or
memberType.isMozMap()): memberType.isRecord()):
return typeContainsDictionary(memberType.inner, dictionary) return typeContainsDictionary(memberType.inner, dictionary)
if memberType.isDictionary(): if memberType.isDictionary():
@ -1988,7 +1988,7 @@ class IDLType(IDLObject):
'callback', 'callback',
'union', 'union',
'sequence', 'sequence',
'mozmap' 'record'
) )
def __init__(self, location, name): def __init__(self, location, name):
@ -2038,7 +2038,7 @@ class IDLType(IDLObject):
def isSequence(self): def isSequence(self):
return False return False
def isMozMap(self): def isRecord(self):
return False return False
def isArrayBuffer(self): def isArrayBuffer(self):
@ -2263,8 +2263,8 @@ class IDLNullableType(IDLParameterizedType):
def isSequence(self): def isSequence(self):
return self.inner.isSequence() return self.inner.isSequence()
def isMozMap(self): def isRecord(self):
return self.inner.isMozMap() return self.inner.isRecord()
def isArrayBuffer(self): def isArrayBuffer(self):
return self.inner.isArrayBuffer() return self.inner.isArrayBuffer()
@ -2321,8 +2321,10 @@ class IDLNullableType(IDLParameterizedType):
return self return self
def isDistinguishableFrom(self, other): def isDistinguishableFrom(self, other):
if (other.nullable() or (other.isUnion() and other.hasNullableType) or if (other.nullable() or
other.isDictionary()): other.isDictionary() or
(other.isUnion() and
(other.hasNullableType or other.hasDictionaryType()))):
# Can't tell which type null should become # Can't tell which type null should become
return False return False
return self.inner.isDistinguishableFrom(other) return self.inner.isDistinguishableFrom(other)
@ -2397,34 +2399,38 @@ class IDLSequenceType(IDLParameterizedType):
return (other.isPrimitive() or other.isString() or other.isEnum() or return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isDate() or other.isInterface() or other.isDate() or other.isInterface() or
other.isDictionary() or other.isDictionary() or
other.isCallback() or other.isMozMap()) other.isCallback() or other.isRecord())
class IDLMozMapType(IDLParameterizedType): class IDLRecordType(IDLParameterizedType):
def __init__(self, location, parameterType): def __init__(self, location, keyType, valueType):
assert not parameterType.isVoid() assert keyType.isString()
assert keyType.isComplete()
assert not valueType.isVoid()
IDLParameterizedType.__init__(self, location, valueType.name, valueType)
self.keyType = keyType
IDLParameterizedType.__init__(self, location, parameterType.name, parameterType)
# Need to set self.name up front if our inner type is already complete, # Need to set self.name up front if our inner type is already complete,
# since in that case our .complete() won't be called. # since in that case our .complete() won't be called.
if self.inner.isComplete(): if self.inner.isComplete():
self.name = self.inner.name + "MozMap" self.name = self.keyType.name + self.inner.name + "Record"
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, IDLMozMapType) and self.inner == other.inner return isinstance(other, IDLRecordType) and self.inner == other.inner
def __str__(self): def __str__(self):
return self.inner.__str__() + "MozMap" return self.keyType.__str__() + self.inner.__str__() + "Record"
def isMozMap(self): def isRecord(self):
return True return True
def tag(self): def tag(self):
return IDLType.Tags.mozmap return IDLType.Tags.record
def complete(self, scope): def complete(self, scope):
self.inner = self.inner.complete(scope) self.inner = self.inner.complete(scope)
self.name = self.inner.name + "MozMap" self.name = self.keyType.name + self.inner.name + "Record"
return self return self
def unroll(self): def unroll(self):
@ -2614,8 +2620,8 @@ class IDLTypedefType(IDLType):
def isSequence(self): def isSequence(self):
return self.inner.isSequence() return self.inner.isSequence()
def isMozMap(self): def isRecord(self):
return self.inner.isMozMap() return self.inner.isRecord()
def isDictionary(self): def isDictionary(self):
return self.inner.isDictionary() return self.inner.isDictionary()
@ -2798,7 +2804,7 @@ class IDLWrapperType(IDLType):
if self.isEnum(): if self.isEnum():
return (other.isPrimitive() or other.isInterface() or other.isObject() or return (other.isPrimitive() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate()) other.isSequence() or other.isRecord() or other.isDate())
if self.isDictionary() and other.nullable(): if self.isDictionary() and other.nullable():
return False return False
if (other.isPrimitive() or other.isString() or other.isEnum() or if (other.isPrimitive() or other.isString() or other.isEnum() or
@ -2820,7 +2826,7 @@ class IDLWrapperType(IDLType):
(self.isNonCallbackInterface() or (self.isNonCallbackInterface() or
other.isNonCallbackInterface())) other.isNonCallbackInterface()))
if (other.isDictionary() or other.isCallback() or if (other.isDictionary() or other.isCallback() or
other.isMozMap()): other.isRecord()):
return self.isNonCallbackInterface() return self.isNonCallbackInterface()
# Not much else |other| can be # Not much else |other| can be
@ -3030,17 +3036,17 @@ class IDLBuiltinType(IDLType):
return (other.isNumeric() or other.isString() or other.isEnum() or return (other.isNumeric() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate()) other.isSequence() or other.isRecord() or other.isDate())
if self.isNumeric(): if self.isNumeric():
return (other.isBoolean() or other.isString() or other.isEnum() or return (other.isBoolean() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate()) other.isSequence() or other.isRecord() or other.isDate())
if self.isString(): if self.isString():
return (other.isPrimitive() or other.isInterface() or return (other.isPrimitive() or other.isInterface() or
other.isObject() or other.isObject() or
other.isCallback() or other.isDictionary() or other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate()) other.isSequence() or other.isRecord() or other.isDate())
if self.isAny(): if self.isAny():
# Can't tell "any" apart from anything # Can't tell "any" apart from anything
return False return False
@ -3050,7 +3056,7 @@ class IDLBuiltinType(IDLType):
return (other.isPrimitive() or other.isString() or other.isEnum() or return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isInterface() or other.isCallback() or other.isInterface() or other.isCallback() or
other.isDictionary() or other.isSequence() or other.isDictionary() or other.isSequence() or
other.isMozMap()) other.isRecord())
if self.isVoid(): if self.isVoid():
return not other.isVoid() return not other.isVoid()
# Not much else we could be! # Not much else we could be!
@ -3058,7 +3064,7 @@ class IDLBuiltinType(IDLType):
# Like interfaces, but we know we're not a callback # Like interfaces, but we know we're not a callback
return (other.isPrimitive() or other.isString() or other.isEnum() or return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isCallback() or other.isDictionary() or other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate() or other.isSequence() or other.isRecord() or other.isDate() or
(other.isInterface() and ( (other.isInterface() and (
# ArrayBuffer is distinguishable from everything # ArrayBuffer is distinguishable from everything
# that's not an ArrayBuffer or a callback interface # that's not an ArrayBuffer or a callback interface
@ -3843,6 +3849,9 @@ class IDLConst(IDLInterfaceMember):
if type.isDictionary(): if type.isDictionary():
raise WebIDLError("A constant cannot be of a dictionary type", raise WebIDLError("A constant cannot be of a dictionary type",
[self.location]) [self.location])
if type.isRecord():
raise WebIDLError("A constant cannot be of a record type",
[self.location])
self.type = type self.type = type
self.value = value self.value = value
@ -3954,8 +3963,8 @@ class IDLAttribute(IDLInterfaceMember):
if self.type.isSequence() and not self.getExtendedAttribute("Cached"): if self.type.isSequence() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a sequence " raise WebIDLError("A non-cached attribute cannot be of a sequence "
"type", [self.location]) "type", [self.location])
if self.type.isMozMap() and not self.getExtendedAttribute("Cached"): if self.type.isRecord() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a MozMap " raise WebIDLError("A non-cached attribute cannot be of a record "
"type", [self.location]) "type", [self.location])
if self.type.isUnion(): if self.type.isUnion():
for f in self.type.unroll().flatMemberTypes: for f in self.type.unroll().flatMemberTypes:
@ -3971,11 +3980,11 @@ class IDLAttribute(IDLInterfaceMember):
"one of its member types's member " "one of its member types's member "
"types, and so on) is a sequence " "types, and so on) is a sequence "
"type", [self.location, f.location]) "type", [self.location, f.location])
if f.isMozMap(): if f.isRecord():
raise WebIDLError("An attribute cannot be of a union " raise WebIDLError("An attribute cannot be of a union "
"type if one of its member types (or " "type if one of its member types (or "
"one of its member types's member " "one of its member types's member "
"types, and so on) is a MozMap " "types, and so on) is a record "
"type", [self.location, f.location]) "type", [self.location, f.location])
if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"):
raise WebIDLError("An attribute with [PutForwards] must have an " raise WebIDLError("An attribute with [PutForwards] must have an "
@ -3989,7 +3998,7 @@ class IDLAttribute(IDLInterfaceMember):
def typeContainsChromeOnlyDictionaryMember(type): def typeContainsChromeOnlyDictionaryMember(type):
if (type.nullable() or if (type.nullable() or
type.isSequence() or type.isSequence() or
type.isMozMap()): type.isRecord()):
return typeContainsChromeOnlyDictionaryMember(type.inner) return typeContainsChromeOnlyDictionaryMember(type.inner)
if type.isUnion(): if type.isUnion():
@ -4035,10 +4044,10 @@ class IDLAttribute(IDLInterfaceMember):
[self.location, location]) [self.location, location])
if self.getExtendedAttribute("Frozen"): if self.getExtendedAttribute("Frozen"):
if (not self.type.isSequence() and not self.type.isDictionary() and if (not self.type.isSequence() and not self.type.isDictionary() and
not self.type.isMozMap()): not self.type.isRecord()):
raise WebIDLError("[Frozen] is only allowed on " raise WebIDLError("[Frozen] is only allowed on "
"sequence-valued, dictionary-valued, and " "sequence-valued, dictionary-valued, and "
"MozMap-valued attributes", "record-valued attributes",
[self.location]) [self.location])
if not self.type.unroll().isExposedInAllOf(self.exposureSet): if not self.type.unroll().isExposedInAllOf(self.exposureSet):
raise WebIDLError("Attribute returns a type that is not exposed " raise WebIDLError("Attribute returns a type that is not exposed "
@ -5147,7 +5156,7 @@ class Tokenizer(object):
"Promise": "PROMISE", "Promise": "PROMISE",
"required": "REQUIRED", "required": "REQUIRED",
"sequence": "SEQUENCE", "sequence": "SEQUENCE",
"MozMap": "MOZMAP", "record": "RECORD",
"short": "SHORT", "short": "SHORT",
"unsigned": "UNSIGNED", "unsigned": "UNSIGNED",
"void": "VOID", "void": "VOID",
@ -6276,7 +6285,7 @@ class Parser(Tokenizer):
| OCTET | OCTET
| OPTIONAL | OPTIONAL
| SEQUENCE | SEQUENCE
| MOZMAP | RECORD
| SETTER | SETTER
| SHORT | SHORT
| STATIC | STATIC
@ -6355,7 +6364,7 @@ class Parser(Tokenizer):
def p_NonAnyType(self, p): def p_NonAnyType(self, p):
""" """
NonAnyType : PrimitiveOrStringType Null NonAnyType : PrimitiveType Null
| ARRAYBUFFER Null | ARRAYBUFFER Null
| SHAREDARRAYBUFFER Null | SHAREDARRAYBUFFER Null
| OBJECT Null | OBJECT Null
@ -6371,6 +6380,12 @@ class Parser(Tokenizer):
p[0] = self.handleNullable(type, p[2]) p[0] = self.handleNullable(type, p[2])
def p_NonAnyTypeStringType(self, p):
"""
NonAnyType : StringType Null
"""
p[0] = self.handleNullable(p[1], p[2])
def p_NonAnyTypeSequenceType(self, p): def p_NonAnyTypeSequenceType(self, p):
""" """
NonAnyType : SEQUENCE LT Type GT Null NonAnyType : SEQUENCE LT Type GT Null
@ -6391,13 +6406,14 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3]) type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3])
p[0] = self.handleNullable(type, p[5]) p[0] = self.handleNullable(type, p[5])
def p_NonAnyTypeMozMapType(self, p): def p_NonAnyTypeRecordType(self, p):
""" """
NonAnyType : MOZMAP LT Type GT Null NonAnyType : RECORD LT StringType COMMA Type GT Null
""" """
innerType = p[3] keyType = p[3]
type = IDLMozMapType(self.getLocation(p, 1), innerType) valueType = p[5]
p[0] = self.handleNullable(type, p[5]) type = IDLRecordType(self.getLocation(p, 1), keyType, valueType)
p[0] = self.handleNullable(type, p[7])
def p_NonAnyTypeScopedName(self, p): def p_NonAnyTypeScopedName(self, p):
""" """
@ -6440,7 +6456,7 @@ class Parser(Tokenizer):
def p_ConstType(self, p): def p_ConstType(self, p):
""" """
ConstType : PrimitiveOrStringType Null ConstType : PrimitiveType Null
""" """
type = BuiltinTypes[p[1]] type = BuiltinTypes[p[1]]
p[0] = self.handleNullable(type, p[2]) p[0] = self.handleNullable(type, p[2])
@ -6454,69 +6470,75 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), identifier) type = IDLUnresolvedType(self.getLocation(p, 1), identifier)
p[0] = self.handleNullable(type, p[2]) p[0] = self.handleNullable(type, p[2])
def p_PrimitiveOrStringTypeUint(self, p): def p_PrimitiveTypeUint(self, p):
""" """
PrimitiveOrStringType : UnsignedIntegerType PrimitiveType : UnsignedIntegerType
""" """
p[0] = p[1] p[0] = p[1]
def p_PrimitiveOrStringTypeBoolean(self, p): def p_PrimitiveTypeBoolean(self, p):
""" """
PrimitiveOrStringType : BOOLEAN PrimitiveType : BOOLEAN
""" """
p[0] = IDLBuiltinType.Types.boolean p[0] = IDLBuiltinType.Types.boolean
def p_PrimitiveOrStringTypeByte(self, p): def p_PrimitiveTypeByte(self, p):
""" """
PrimitiveOrStringType : BYTE PrimitiveType : BYTE
""" """
p[0] = IDLBuiltinType.Types.byte p[0] = IDLBuiltinType.Types.byte
def p_PrimitiveOrStringTypeOctet(self, p): def p_PrimitiveTypeOctet(self, p):
""" """
PrimitiveOrStringType : OCTET PrimitiveType : OCTET
""" """
p[0] = IDLBuiltinType.Types.octet p[0] = IDLBuiltinType.Types.octet
def p_PrimitiveOrStringTypeFloat(self, p): def p_PrimitiveTypeFloat(self, p):
""" """
PrimitiveOrStringType : FLOAT PrimitiveType : FLOAT
""" """
p[0] = IDLBuiltinType.Types.float p[0] = IDLBuiltinType.Types.float
def p_PrimitiveOrStringTypeUnrestictedFloat(self, p): def p_PrimitiveTypeUnrestictedFloat(self, p):
""" """
PrimitiveOrStringType : UNRESTRICTED FLOAT PrimitiveType : UNRESTRICTED FLOAT
""" """
p[0] = IDLBuiltinType.Types.unrestricted_float p[0] = IDLBuiltinType.Types.unrestricted_float
def p_PrimitiveOrStringTypeDouble(self, p): def p_PrimitiveTypeDouble(self, p):
""" """
PrimitiveOrStringType : DOUBLE PrimitiveType : DOUBLE
""" """
p[0] = IDLBuiltinType.Types.double p[0] = IDLBuiltinType.Types.double
def p_PrimitiveOrStringTypeUnrestictedDouble(self, p): def p_PrimitiveTypeUnrestictedDouble(self, p):
""" """
PrimitiveOrStringType : UNRESTRICTED DOUBLE PrimitiveType : UNRESTRICTED DOUBLE
""" """
p[0] = IDLBuiltinType.Types.unrestricted_double p[0] = IDLBuiltinType.Types.unrestricted_double
def p_PrimitiveOrStringTypeDOMString(self, p): def p_StringType(self, p):
""" """
PrimitiveOrStringType : DOMSTRING StringType : BuiltinStringType
"""
p[0] = BuiltinTypes[p[1]]
def p_BuiltinStringTypeDOMString(self, p):
"""
BuiltinStringType : DOMSTRING
""" """
p[0] = IDLBuiltinType.Types.domstring p[0] = IDLBuiltinType.Types.domstring
def p_PrimitiveOrStringTypeBytestring(self, p): def p_BuiltinStringTypeBytestring(self, p):
""" """
PrimitiveOrStringType : BYTESTRING BuiltinStringType : BYTESTRING
""" """
p[0] = IDLBuiltinType.Types.bytestring p[0] = IDLBuiltinType.Types.bytestring
def p_PrimitiveOrStringTypeUSVString(self, p): def p_BuiltinStringTypeUSVString(self, p):
""" """
PrimitiveOrStringType : USVSTRING BuiltinStringType : USVSTRING
""" """
p[0] = IDLBuiltinType.Types.usvstring p[0] = IDLBuiltinType.Types.usvstring

View File

@ -25,7 +25,7 @@ NS_INTERFACE_MAP_END
// static // static
already_AddRefed<Headers> already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal, Headers::Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit, const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit,
ErrorResult& aRv) ErrorResult& aRv)
{ {
RefPtr<InternalHeaders> ih = new InternalHeaders(); RefPtr<InternalHeaders> ih = new InternalHeaders();
@ -39,8 +39,8 @@ Headers::Constructor(const GlobalObject& aGlobal,
ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv); ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv);
} else if (aInit.Value().IsByteStringSequenceSequence()) { } else if (aInit.Value().IsByteStringSequenceSequence()) {
ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv); ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.Value().IsByteStringMozMap()) { } else if (aInit.Value().IsByteStringByteStringRecord()) {
ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv); ih->Fill(aInit.Value().GetAsByteStringByteStringRecord(), aRv);
} }
if (aRv.Failed()) { if (aRv.Failed()) {
@ -53,7 +53,7 @@ Headers::Constructor(const GlobalObject& aGlobal,
// static // static
already_AddRefed<Headers> already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal, Headers::Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv) ErrorResult& aRv)
{ {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@ -62,7 +62,7 @@ Headers::Constructor(const GlobalObject& aGlobal,
/* static */ already_AddRefed<Headers> /* static */ already_AddRefed<Headers>
Headers::Create(nsIGlobalObject* aGlobal, Headers::Create(nsIGlobalObject* aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv) ErrorResult& aRv)
{ {
RefPtr<InternalHeaders> ih = new InternalHeaders(); RefPtr<InternalHeaders> ih = new InternalHeaders();
@ -72,8 +72,8 @@ Headers::Create(nsIGlobalObject* aGlobal,
ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv); ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv);
} else if (aInit.IsByteStringSequenceSequence()) { } else if (aInit.IsByteStringSequenceSequence()) {
ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv); ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.IsByteStringMozMap()) { } else if (aInit.IsByteStringByteStringRecord()) {
ih->Fill(aInit.GetAsByteStringMozMap(), aRv); ih->Fill(aInit.GetAsByteStringByteStringRecord(), aRv);
} }
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {

View File

@ -20,9 +20,9 @@ class ErrorResult;
namespace dom { namespace dom {
template<typename T> class MozMap; template<typename K, typename V> class Record;
class HeadersOrByteStringSequenceSequenceOrByteStringMozMap; class HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord;
class OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap; class OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord;
/** /**
* This Headers class is only used to represent the content facing Headers * This Headers class is only used to represent the content facing Headers
@ -57,17 +57,17 @@ public:
static already_AddRefed<Headers> static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal, Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit, const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<Headers> static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal, Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<Headers> static already_AddRefed<Headers>
Create(nsIGlobalObject* aGlobalObject, Create(nsIGlobalObject* aGlobalObject,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv); ErrorResult& aRv);
void Append(const nsACString& aName, const nsACString& aValue, void Append(const nsACString& aName, const nsACString& aValue,

View File

@ -314,12 +314,13 @@ InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& a
} }
void void
InternalHeaders::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv) InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv)
{ {
nsTArray<nsString> keys; for (auto& entry : aInit.Entries()) {
aInit.GetKeys(keys); Append(entry.mKey, entry.mValue, aRv);
for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) { if (aRv.Failed()) {
Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv); return;
}
} }
} }

View File

@ -20,7 +20,7 @@ class ErrorResult;
namespace dom { namespace dom {
template<typename T> class MozMap; template<typename K, typename V> class Record;
class HeadersEntry; class HeadersEntry;
class InternalHeaders final class InternalHeaders final
@ -113,7 +113,7 @@ public:
void Fill(const InternalHeaders& aInit, ErrorResult& aRv); void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv); void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv); void Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv);
bool HasOnlySimpleHeaders() const; bool HasOnlySimpleHeaders() const;

View File

@ -314,14 +314,6 @@ URLSearchParams::URLSearchParams(nsISupports* aParent,
{ {
} }
URLSearchParams::URLSearchParams(nsISupports* aParent,
const URLSearchParams& aOther)
: mParams(new URLParams(*aOther.mParams.get()))
, mParent(aParent)
, mObserver(nullptr)
{
}
URLSearchParams::~URLSearchParams() URLSearchParams::~URLSearchParams()
{ {
DeleteAll(); DeleteAll();
@ -335,34 +327,43 @@ URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
/* static */ already_AddRefed<URLSearchParams> /* static */ already_AddRefed<URLSearchParams>
URLSearchParams::Constructor(const GlobalObject& aGlobal, URLSearchParams::Constructor(const GlobalObject& aGlobal,
const nsAString& aInit, const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
ErrorResult& aRv) ErrorResult& aRv)
{ {
RefPtr<URLSearchParams> sp = RefPtr<URLSearchParams> sp =
new URLSearchParams(aGlobal.GetAsSupports(), nullptr); new URLSearchParams(aGlobal.GetAsSupports(), nullptr);
NS_ConvertUTF16toUTF8 input(aInit); if (aInit.IsUSVString()) {
NS_ConvertUTF16toUTF8 input(aInit.GetAsUSVString());
if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) { if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) {
sp->ParseInput(Substring(input, 1, input.Length() - 1)); sp->ParseInput(Substring(input, 1, input.Length() - 1));
} else {
sp->ParseInput(input);
}
} else if (aInit.IsUSVStringSequenceSequence()) {
const Sequence<Sequence<nsString>>& list =
aInit.GetAsUSVStringSequenceSequence();
for (uint32_t i = 0; i < list.Length(); ++i) {
const Sequence<nsString>& item = list[i];
if (item.Length() != 2) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return nullptr;
}
sp->Append(item[0], item[1]);
}
} else if (aInit.IsUSVStringUSVStringRecord()) {
const Record<nsString, nsString>& record =
aInit.GetAsUSVStringUSVStringRecord();
for (auto& entry : record.Entries()) {
sp->Append(entry.mKey, entry.mValue);
}
} else { } else {
sp->ParseInput(input); MOZ_CRASH("This should not happen.");
} }
return sp.forget(); return sp.forget();
} }
/* static */ already_AddRefed<URLSearchParams>
URLSearchParams::Constructor(const GlobalObject& aGlobal,
URLSearchParams& aInit,
ErrorResult& aRv)
{
RefPtr<URLSearchParams> sp =
new URLSearchParams(aGlobal.GetAsSupports(), aInit);
return sp.forget();
}
void void
URLSearchParams::ParseInput(const nsACString& aInput) URLSearchParams::ParseInput(const nsACString& aInput)
{ {

View File

@ -20,6 +20,7 @@ namespace mozilla {
namespace dom { namespace dom {
class URLSearchParams; class URLSearchParams;
class USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString;
class URLSearchParamsObserver : public nsISupports class URLSearchParamsObserver : public nsISupports
{ {
@ -43,14 +44,6 @@ public:
DeleteAll(); DeleteAll();
} }
explicit URLParams(const URLParams& aOther)
: mParams(aOther.mParams)
{}
URLParams(const URLParams&& aOther)
: mParams(Move(aOther.mParams))
{}
class ForEachIterator class ForEachIterator
{ {
public: public:
@ -144,9 +137,6 @@ public:
explicit URLSearchParams(nsISupports* aParent, explicit URLSearchParams(nsISupports* aParent,
URLSearchParamsObserver* aObserver=nullptr); URLSearchParamsObserver* aObserver=nullptr);
URLSearchParams(nsISupports* aParent,
const URLSearchParams& aOther);
// WebIDL methods // WebIDL methods
nsISupports* GetParentObject() const nsISupports* GetParentObject() const
{ {
@ -157,11 +147,8 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<URLSearchParams> static already_AddRefed<URLSearchParams>
Constructor(const GlobalObject& aGlobal, const nsAString& aInit, Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv); const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
static already_AddRefed<URLSearchParams>
Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
ErrorResult& aRv); ErrorResult& aRv);
void ParseInput(const nsACString& aInput); void ParseInput(const nsACString& aInput);

View File

@ -8,7 +8,7 @@
* http://fetch.spec.whatwg.org/#headers-class * http://fetch.spec.whatwg.org/#headers-class
*/ */
typedef (Headers or sequence<sequence<ByteString>> or MozMap<ByteString>) HeadersInit; typedef (Headers or sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit;
enum HeadersGuardEnum { enum HeadersGuardEnum {
"none", "none",

View File

@ -57,7 +57,7 @@ interface InstallTriggerImpl {
* A callback to call as each installation succeeds or fails * A callback to call as each installation succeeds or fails
* @return true if the installations were successfully started * @return true if the installations were successfully started
*/ */
boolean install(MozMap<(DOMString or InstallTriggerData)> installs, boolean install(record<DOMString, (DOMString or InstallTriggerData)> installs,
optional InstallTriggerCallback callback); optional InstallTriggerCallback callback);
/** /**

View File

@ -24,7 +24,7 @@ interface TestInterfaceJS : EventTarget {
any pingPongObjectOrString((object or DOMString) objOrString); any pingPongObjectOrString((object or DOMString) objOrString);
TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict); TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict);
long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong); long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
DOMString pingPongMap(MozMap<any> map); DOMString pingPongMap(record<DOMString, any> map);
long objectSequenceLength(sequence<object> seq); long objectSequenceLength(sequence<object> seq);
long anySequenceLength(sequence<any> seq); long anySequenceLength(sequence<any> seq);

View File

@ -13,8 +13,7 @@
* http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0. * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
*/ */
[Constructor(optional USVString init = ""), [Constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = ""),
Constructor(URLSearchParams init),
Exposed=(Window,Worker,WorkerDebugger,System)] Exposed=(Window,Worker,WorkerDebugger,System)]
interface URLSearchParams { interface URLSearchParams {
void append(USVString name, USVString value); void append(USVString name, USVString value);