Implement WebIDL method overloads. Fixes #540.

This commit is contained in:
Josh Matthews 2013-06-27 18:41:06 +01:00
parent 213d9a011a
commit eb95d82fe6
11 changed files with 281 additions and 74 deletions

View file

@ -92,9 +92,10 @@ DOMInterfaces = {
{ {
'headerFile': 'nsIDOMFile.h', 'headerFile': 'nsIDOMFile.h',
}, },
{ #{
'workers': True, # 'workers': True,
}], #}
],
'CanvasRenderingContext2D': [ 'CanvasRenderingContext2D': [
{ {
@ -199,9 +200,10 @@ DOMInterfaces = {
'FormData': [ 'FormData': [
{ {
}, },
{ #{
'workers': True, # 'workers': True,
}], #}
],
'HTMLCollection': [ 'HTMLCollection': [
{ {

View file

@ -0,0 +1,2 @@
interface Blob {
};

View file

@ -122,6 +122,15 @@ class CastableObjectUnwrapper():
# } # }
#}""").substitute(self.substitution) #}""").substitute(self.substitution)
class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
"""
As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
"""
def __init__(self, descriptor, source, target):
CastableObjectUnwrapper.__init__(self, descriptor, source, target,
"return Throw<%s>(cx, rv);" %
toStringBool(not descriptor.workers))
class CGThing(): class CGThing():
""" """
Abstract base class for things that spit out code. Abstract base class for things that spit out code.
@ -154,9 +163,10 @@ class CGMethodCall(CGThing):
requiredArgs -= 1 requiredArgs -= 1
return requiredArgs return requiredArgs
def getPerSignatureCall(signature, argConversionStartsAt=0): def getPerSignatureCall(signature, argConversionStartsAt=0, signatureIndex=0):
return CGPerSignatureCall(signature[0], argsPre, signature[1], return CGPerSignatureCall(signature[0], argsPre, signature[1],
nativeMethodName, static, descriptor, nativeMethodName + '_'*signatureIndex,
static, descriptor,
method, argConversionStartsAt) method, argConversionStartsAt)
@ -201,15 +211,12 @@ class CGMethodCall(CGThing):
signature[1][argCount].optional and signature[1][argCount].optional and
(argCount+1) in allowedArgCounts and (argCount+1) in allowedArgCounts and
len(method.signaturesForArgCount(argCount+1)) == 1): len(method.signaturesForArgCount(argCount+1)) == 1):
#XXXjdm unfinished argCountCases.append(
pass CGCase(str(argCount), None, True))
#argCountCases.append(
# CGCase(str(argCount), None, True))
else: else:
pass pass
#XXXjdm unfinished argCountCases.append(
#argCountCases.append( CGCase(str(argCount), getPerSignatureCall(signature)))
# CGCase(str(argCount), getPerSignatureCall(signature)))
continue continue
distinguishingIndex = method.distinguishingIndexForArgCount(argCount) distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
@ -225,14 +232,14 @@ class CGMethodCall(CGThing):
# Doesn't matter which of the possible signatures we use, since # Doesn't matter which of the possible signatures we use, since
# they all have the same types up to that point; just use # they all have the same types up to that point; just use
# possibleSignatures[0] # possibleSignatures[0]
caseBody = [CGGeneric("JS::Value* argv_start = JS_ARGV(cx, vp);")] caseBody = [CGGeneric("let argv_start = JS_ARGV(cx, cast::transmute(vp));")]
caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i], caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i],
i, "argv_start", "argc", i, "argv_start", "argc",
descriptor) for i in descriptor) for i in
range(0, distinguishingIndex) ]) range(0, distinguishingIndex) ])
# Select the right overload from our set. # Select the right overload from our set.
distinguishingArg = "argv_start[%d]" % distinguishingIndex distinguishingArg = "(*argv_start.offset(%d))" % distinguishingIndex
def pickFirstSignature(condition, filterLambda): def pickFirstSignature(condition, filterLambda):
sigs = filter(filterLambda, possibleSignatures) sigs = filter(filterLambda, possibleSignatures)
@ -240,11 +247,13 @@ class CGMethodCall(CGThing):
if len(sigs) > 0: if len(sigs) > 0:
if condition is None: if condition is None:
caseBody.append( caseBody.append(
getPerSignatureCall(sigs[0], distinguishingIndex)) getPerSignatureCall(sigs[0], distinguishingIndex,
possibleSignatures.index(sigs[0])))
else: else:
caseBody.append(CGGeneric("if (" + condition + ") {")) caseBody.append(CGGeneric("if " + condition + " {"))
caseBody.append(CGIndenter( caseBody.append(CGIndenter(
getPerSignatureCall(sigs[0], distinguishingIndex))) getPerSignatureCall(sigs[0], distinguishingIndex,
possibleSignatures.index(sigs[0]))))
caseBody.append(CGGeneric("}")) caseBody.append(CGGeneric("}"))
return True return True
return False return False
@ -276,10 +285,10 @@ class CGMethodCall(CGThing):
# also allow the unwrapping test to skip having to do codegen # also allow the unwrapping test to skip having to do codegen
# for the null-or-undefined case, which we already handled # for the null-or-undefined case, which we already handled
# above. # above.
caseBody.append(CGGeneric("if (%s.isObject()) {" % caseBody.append(CGGeneric("if JSVAL_IS_OBJECT(%s) {" %
(distinguishingArg))) (distinguishingArg)))
for sig in interfacesSigs: for sig in interfacesSigs:
caseBody.append(CGIndenter(CGGeneric("do {"))); caseBody.append(CGIndenter(CGGeneric("loop {")));
type = sig[1][distinguishingIndex].type type = sig[1][distinguishingIndex].type
# The argument at index distinguishingIndex can't possibly # The argument at index distinguishingIndex can't possibly
@ -303,7 +312,7 @@ class CGMethodCall(CGThing):
# distinguishingIndex. # distinguishingIndex.
caseBody.append(CGIndenter( caseBody.append(CGIndenter(
getPerSignatureCall(sig, distinguishingIndex + 1), 4)) getPerSignatureCall(sig, distinguishingIndex + 1), 4))
caseBody.append(CGIndenter(CGGeneric("} while (0);"))) caseBody.append(CGIndenter(CGGeneric("}")))
caseBody.append(CGGeneric("}")) caseBody.append(CGGeneric("}"))
@ -354,22 +363,21 @@ class CGMethodCall(CGThing):
caseBody.append(CGGeneric("return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" % caseBody.append(CGGeneric("return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" %
toStringBool(not descriptor.workers))) toStringBool(not descriptor.workers)))
#XXXjdm unfinished argCountCases.append(CGCase(str(argCount),
#argCountCases.append(CGCase(str(argCount), CGList(caseBody, "\n")))
# CGList(caseBody, "\n")))
overloadCGThings = [] overloadCGThings = []
overloadCGThings.append( overloadCGThings.append(
CGGeneric("unsigned argcount = NS_MIN(argc, %du);" % CGGeneric("let argcount = argc.min(&%d);" %
maxArgCount)) maxArgCount))
#XXXjdm unfinished
#overloadCGThings.append(
# CGSwitch("argcount",
# argCountCases,
# CGGeneric("return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" % methodName)))
overloadCGThings.append( overloadCGThings.append(
CGGeneric('MOZ_NOT_REACHED("We have an always-returning default case");\n' CGSwitch("argcount",
'return false;')) argCountCases,
CGGeneric("return 0; //XXXjdm throw stuff\n//return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" % methodName)))
#XXXjdm Avoid unreachable statement warnings
#overloadCGThings.append(
# CGGeneric('fail!("We have an always-returning default case");\n'
# 'return 0;'))
self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings, "\n")), self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings, "\n")),
pre="\n") pre="\n")
@ -492,11 +500,11 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
def onFailureNotAnObject(failureCode): def onFailureNotAnObject(failureCode):
return CGWrapper(CGGeneric( return CGWrapper(CGGeneric(
failureCode or failureCode or
'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n") 'return 0; //XXXjdm return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n")
def onFailureBadType(failureCode, typeName): def onFailureBadType(failureCode, typeName):
return CGWrapper(CGGeneric( return CGWrapper(CGGeneric(
failureCode or failureCode or
'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n") 'return 0; //XXXjdm return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n")
# A helper function for handling default values. Takes a template # A helper function for handling default values. Takes a template
# body and the C++ code to set the default value and wraps the # body and the C++ code to set the default value and wraps the
@ -529,7 +537,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
# Handle the non-object cases by wrapping up the whole # Handle the non-object cases by wrapping up the whole
# thing in an if cascade. # thing in an if cascade.
templateBody = ( templateBody = (
"if (${val}.isObject()) {\n" + "if JSVAL_IS_OBJECT(${val}) {\n" +
CGIndenter(CGGeneric(templateBody)).define() + "\n") CGIndenter(CGGeneric(templateBody)).define() + "\n")
if type.nullable(): if type.nullable():
templateBody += ( templateBody += (
@ -580,7 +588,8 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
str(type.location)) str(type.location))
(elementTemplate, elementDeclType, (elementTemplate, elementDeclType,
elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate( elementHolderType, dealWithOptional,
initialValue) = getJSToNativeConversionTemplate(
elementType, descriptorProvider, isMember=True) elementType, descriptorProvider, isMember=True)
if dealWithOptional: if dealWithOptional:
raise TypeError("Shouldn't have optional things in sequences") raise TypeError("Shouldn't have optional things in sequences")
@ -635,7 +644,7 @@ for (uint32_t i = 0; i < length; ++i) {
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
type, type,
"const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define()) "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define())
return (templateBody, typeName, None, isOptional) return (templateBody, typeName, None, isOptional, None)
if type.isUnion(): if type.isUnion():
if isMember: if isMember:
@ -848,7 +857,7 @@ for (uint32_t i = 0; i < length; ++i) {
extraConditionForNull=valueMissing) extraConditionForNull=valueMissing)
templateBody = CGList([constructDecl, templateBody], "\n") templateBody = CGList([constructDecl, templateBody], "\n")
return templateBody.define(), declType, holderType, False return templateBody.define(), declType, holderType, False, None
if type.isGeckoInterface(): if type.isGeckoInterface():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -886,7 +895,7 @@ for (uint32_t i = 0; i < length; ++i) {
if forceOwningType: if forceOwningType:
declType = "OwningNonNull<" + typeName + ">" declType = "OwningNonNull<" + typeName + ">"
else: else:
declType = "NonNull<" + typeName + ">" declType = descriptor.pointerType + typeName
templateBody = "" templateBody = ""
if descriptor.castable: if descriptor.castable:
@ -902,16 +911,14 @@ for (uint32_t i = 0; i < length; ++i) {
if failureCode is not None: if failureCode is not None:
templateBody += str(CastableObjectUnwrapper( templateBody += str(CastableObjectUnwrapper(
descriptor, descriptor,
"&${val}.toObject()", "JSVAL_TO_OBJECT(${val})",
"${declName}", "${declName}",
failureCode)) failureCode))
else: else:
pass templateBody += str(FailureFatalCastableObjectUnwrapper(
#XXXjdm unfinished descriptor,
#templateBody += str(FailureFatalCastableObjectUnwrapper( "JSVAL_TO_OBJECT(${val})",
# descriptor, "${declName}"))
# "&${val}.toObject()",
# "${declName}"))
elif descriptor.interface.isCallback() and False: elif descriptor.interface.isCallback() and False:
#XXXjdm unfinished #XXXjdm unfinished
templateBody += str(CallbackObjectUnwrapper( templateBody += str(CallbackObjectUnwrapper(
@ -962,7 +969,7 @@ for (uint32_t i = 0; i < length; ++i) {
declType = CGGeneric(declType) declType = CGGeneric(declType)
if holderType is not None: if holderType is not None:
holderType = CGGeneric(holderType) holderType = CGGeneric(holderType)
return (templateBody, declType, holderType, isOptional) return (templateBody, declType, holderType, isOptional, None)
if type.isSpiderMonkeyInterface(): if type.isSpiderMonkeyInterface():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1018,7 +1025,7 @@ for (uint32_t i = 0; i < length; ++i) {
if holderType is not None: if holderType is not None:
holderType = CGGeneric(holderType) holderType = CGGeneric(holderType)
# We handle all the optional stuff ourselves; no need for caller to do it. # We handle all the optional stuff ourselves; no need for caller to do it.
return (template, CGGeneric(declType), holderType, False) return (template, CGGeneric(declType), holderType, False, None)
if type.isString(): if type.isString():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1040,17 +1047,21 @@ for (uint32_t i = 0; i < length; ++i) {
raise TypeError("We don't support [TreatUndefinedAs=Missing]") raise TypeError("We don't support [TreatUndefinedAs=Missing]")
undefinedBehavior = treatAs[treatUndefinedAs] undefinedBehavior = treatAs[treatUndefinedAs]
def getConversionCode(varName): def getConversionCode(varName, isOptional=False):
#XXXjdm support nullBehavior and undefinedBehavior
#conversionCode = ( #conversionCode = (
# "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n" # "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
# " return false;\n" # " return false;\n"
# "}" % (nullBehavior, undefinedBehavior, varName)) # "}" % (nullBehavior, undefinedBehavior, varName))
strval = "str(strval.get())"
if isOptional:
strval = "Some(%s)" % strval
conversionCode = ( conversionCode = (
"let strval = jsval_to_str(cx, ${val});\n" "let strval = jsval_to_str(cx, ${val});\n"
"if strval.is_err() {\n" "if strval.is_err() {\n"
" return 0;\n" " return 0;\n"
"}\n" "}\n"
"%s = str(strval.get());" % varName) "%s = %s;" % (varName, strval))
if defaultValue is None: if defaultValue is None:
return conversionCode return conversionCode
@ -1075,20 +1086,22 @@ for (uint32_t i = 0; i < length; ++i) {
"%s\n" "%s\n"
" ${declName} = str;\n" " ${declName} = str;\n"
"}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(), "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(),
declType, None, isOptional) declType, None, isOptional, None)
if isOptional: if isOptional:
declType = "Option<DOMString>" declType = "Option<DOMString>"
initialValue = "None"
else: else:
declType = "DOMString" declType = "DOMString"
initialValue = None
return ( return (
"%s\n" % "%s\n" %
#"const_cast<%s&>(${declName}) = &${holderName};" % #"const_cast<%s&>(${declName}) = &${holderName};" %
(getConversionCode("${declName}")), (getConversionCode("${declName}", isOptional)),
CGGeneric(declType), None, #CGGeneric("FakeDependentString"), CGGeneric(declType), None, #CGGeneric("FakeDependentString"),
# No need to deal with Optional here; we have handled it already False,
False) initialValue)
if type.isEnum(): if type.isEnum():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1123,7 +1136,7 @@ for (uint32_t i = 0; i < length; ++i) {
# ("${declName} = %sValues::%s" % # ("${declName} = %sValues::%s" %
# (enum, # (enum,
# getEnumValueName(defaultValue.value)))) # getEnumValueName(defaultValue.value))))
return (template, CGGeneric(enum), None, isOptional) return (template, CGGeneric(enum), None, isOptional, None)
if type.isCallback(): if type.isCallback():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1143,7 +1156,7 @@ for (uint32_t i = 0; i < length; ++i) {
"} else {\n" "} else {\n"
" ${declName} = NULL;\n" " ${declName} = NULL;\n"
"}" % haveCallable, "}" % haveCallable,
CGGeneric("JSObject*"), None, isOptional) CGGeneric("JSObject*"), None, isOptional, None)
if type.isAny(): if type.isAny():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1154,7 +1167,7 @@ for (uint32_t i = 0; i < length; ++i) {
templateBody = "${declName} = ${val};" templateBody = "${declName} = ${val};"
templateBody = handleDefaultNull(templateBody, templateBody = handleDefaultNull(templateBody,
"${declName} = JS::NullValue()") "${declName} = JS::NullValue()")
return (templateBody, CGGeneric("JS::Value"), None, isOptional) return (templateBody, CGGeneric("JS::Value"), None, isOptional, None)
if type.isObject(): if type.isObject():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1170,7 +1183,7 @@ for (uint32_t i = 0; i < length; ++i) {
declType = CGGeneric("JSObject*") declType = CGGeneric("JSObject*")
else: else:
declType = CGGeneric("NonNull<JSObject>") declType = CGGeneric("NonNull<JSObject>")
return (template, declType, None, isOptional) return (template, declType, None, isOptional, None)
if type.isDictionary(): if type.isDictionary():
if failureCode is not None: if failureCode is not None:
@ -1206,7 +1219,7 @@ for (uint32_t i = 0; i < length; ++i) {
" return 0;\n" " return 0;\n"
"}" % (selfRef, actualTypeName, selfRef, val)) "}" % (selfRef, actualTypeName, selfRef, val))
return (template, declType, None, False) return (template, declType, None, False, None)
if not type.isPrimitive(): if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % str(type)) raise TypeError("Need conversion for argument type '%s'" % str(type))
@ -1258,7 +1271,7 @@ for (uint32_t i = 0; i < length; ++i) {
" %s = %s;\n" " %s = %s;\n"
"}" % (dataLoc, defaultStr))).define() "}" % (dataLoc, defaultStr))).define()
return (template, declType, None, isOptional) return (template, declType, None, isOptional, None)
def instantiateJSToNativeConversionTemplate(templateTuple, replacements, def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
argcAndIndex=None): argcAndIndex=None):
@ -1271,7 +1284,7 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
replace ${argc} and ${index}, where ${index} is the index of this replace ${argc} and ${index}, where ${index} is the index of this
argument (0-based) and ${argc} is the total number of arguments. argument (0-based) and ${argc} is the total number of arguments.
""" """
(templateBody, declType, holderType, dealWithOptional) = templateTuple (templateBody, declType, holderType, dealWithOptional, initialValue) = templateTuple
if dealWithOptional and argcAndIndex is None: if dealWithOptional and argcAndIndex is None:
raise TypeError("Have to deal with optional things, but don't know how") raise TypeError("Have to deal with optional things, but don't know how")
@ -1303,12 +1316,14 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
(declType.define(), originalDeclName)) (declType.define(), originalDeclName))
mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >") mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >")
declType = CGWrapper(mutableDeclType, pre="const ") declType = CGWrapper(mutableDeclType, pre="const ")
result.append( newDecl = [CGGeneric("let mut "),
CGList([CGGeneric("let mut "),
CGGeneric(originalDeclName), CGGeneric(originalDeclName),
CGGeneric(": "), CGGeneric(": "),
declType, declType]
CGGeneric(";")])) if initialValue:
newDecl.append(CGGeneric(" = " + initialValue))
newDecl.append(CGGeneric(";"))
result.append(CGList(newDecl))
conversion = CGGeneric( conversion = CGGeneric(
string.Template(templateBody).substitute(replacements) string.Template(templateBody).substitute(replacements)
@ -3020,6 +3035,51 @@ class CGPerSignatureCall(CGThing):
def define(self): def define(self):
return (self.cgRoot.define() + "\n" + self.wrap_return_value()) return (self.cgRoot.define() + "\n" + self.wrap_return_value())
class CGSwitch(CGList):
"""
A class to generate code for a switch statement.
Takes three constructor arguments: an expression, a list of cases,
and an optional default.
Each case is a CGCase. The default is a CGThing for the body of
the default case, if any.
"""
def __init__(self, expression, cases, default=None):
CGList.__init__(self, [CGIndenter(c) for c in cases], "\n")
self.prepend(CGWrapper(CGGeneric(expression),
pre="match ", post=" {"));
if default is not None:
self.append(
CGIndenter(
CGWrapper(
CGIndenter(default),
pre="_ => {\n",
post="\n}"
)
)
)
self.append(CGGeneric("}"))
class CGCase(CGList):
"""
A class to generate code for a case statement.
Takes three constructor arguments: an expression, a CGThing for
the body (allowed to be None if there is no body), and an optional
argument (defaulting to False) for whether to fall through.
"""
def __init__(self, expression, body, fallThrough=False):
CGList.__init__(self, [], "\n")
self.append(CGWrapper(CGGeneric(expression), post=" => {"))
bodyList = CGList([body], "\n")
if fallThrough:
raise TypeError("fall through required but unsupported")
#bodyList.append(CGGeneric('fail!("fall through unsupported"); /* Fall through */'))
self.append(CGIndenter(bodyList));
self.append(CGGeneric("}"))
class CGGetterCall(CGPerSignatureCall): class CGGetterCall(CGPerSignatureCall):
""" """
A class to generate a native object getter call for a particular IDL A class to generate a native object getter call for a particular IDL
@ -3976,7 +4036,7 @@ class CGDictionary(CGThing):
def getMemberType(self, memberInfo): def getMemberType(self, memberInfo):
(member, (templateBody, declType, (member, (templateBody, declType,
holderType, dealWithOptional)) = memberInfo holderType, dealWithOptional, initialValue)) = memberInfo
# We can't handle having a holderType here # We can't handle having a holderType here
assert holderType is None assert holderType is None
if dealWithOptional: if dealWithOptional:
@ -3985,7 +4045,7 @@ class CGDictionary(CGThing):
def getMemberConversion(self, memberInfo): def getMemberConversion(self, memberInfo):
(member, (templateBody, declType, (member, (templateBody, declType,
holderType, dealWithOptional)) = memberInfo holderType, dealWithOptional, initialValue)) = memberInfo
replacements = { "val": "temp", replacements = { "val": "temp",
"valPtr": "&temp", "valPtr": "&temp",
"declName": ("self.%s" % member.identifier.name), "declName": ("self.%s" % member.identifier.name),
@ -4138,6 +4198,7 @@ class CGBindingRoot(CGThing):
'dom::document::Document', #XXXjdm 'dom::document::Document', #XXXjdm
'dom::bindings::utils::*', 'dom::bindings::utils::*',
'dom::bindings::conversions::*', 'dom::bindings::conversions::*',
'dom::blob::*', #XXXjdm
'dom::clientrect::*', #XXXjdm 'dom::clientrect::*', #XXXjdm
'dom::clientrectlist::*', #XXXjdm 'dom::clientrectlist::*', #XXXjdm
'dom::htmlcollection::*', #XXXjdm 'dom::htmlcollection::*', #XXXjdm
@ -4145,6 +4206,7 @@ class CGBindingRoot(CGThing):
'dom::domparser::*', #XXXjdm 'dom::domparser::*', #XXXjdm
'dom::event::*', #XXXjdm 'dom::event::*', #XXXjdm
'dom::eventtarget::*', #XXXjdm 'dom::eventtarget::*', #XXXjdm
'dom::formdata::*', #XXXjdm
'script_task::task_from_context', 'script_task::task_from_context',
'dom::bindings::utils::EnumEntry', 'dom::bindings::utils::EnumEntry',
'dom::node::ScriptView', 'dom::node::ScriptView',
@ -4152,7 +4214,8 @@ class CGBindingRoot(CGThing):
'std::libc', 'std::libc',
'std::ptr', 'std::ptr',
'std::vec', 'std::vec',
'std::str' 'std::str',
'std::num',
], ],
[], [],
curr) curr)

View file

@ -0,0 +1,14 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://xhr.spec.whatwg.org
*/
/*[Constructor(optional HTMLFormElement form)]*/
interface FormData {
void append(DOMString name, Blob value, optional DOMString filename);
void append(DOMString name, DOMString value);
};

View file

@ -1,8 +1,10 @@
#include "BlobBinding.h"
#include "ClientRectBinding.h" #include "ClientRectBinding.h"
#include "ClientRectListBinding.h" #include "ClientRectListBinding.h"
#include "DOMParserBinding.h" #include "DOMParserBinding.h"
#include "EventBinding.h" #include "EventBinding.h"
#include "EventTargetBinding.h" #include "EventTargetBinding.h"
#include "FormDataBinding.h"
#include "HTMLCollectionBinding.h" #include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h" #include "nsScriptNameSpaceManager.h"
@ -15,11 +17,13 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
#define REGISTER_PROTO(_dom_class, _pref_check) \ #define REGISTER_PROTO(_dom_class, _pref_check) \
aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface, _pref_check); aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface, _pref_check);
REGISTER_PROTO(Blob, nullptr);
REGISTER_PROTO(ClientRect, nullptr); REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr); REGISTER_PROTO(ClientRectList, nullptr);
REGISTER_PROTO(DOMParser, nullptr); REGISTER_PROTO(DOMParser, nullptr);
REGISTER_PROTO(Event, nullptr); REGISTER_PROTO(Event, nullptr);
REGISTER_PROTO(EventTarget, nullptr); REGISTER_PROTO(EventTarget, nullptr);
REGISTER_PROTO(FormData, nullptr);
REGISTER_PROTO(HTMLCollection, nullptr); REGISTER_PROTO(HTMLCollection, nullptr);
#undef REGISTER_PROTO #undef REGISTER_PROTO

View file

@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::bindings::codegen::FormDataBinding;
use dom::formdata::FormData;
use script_task::{task_from_context, global_script_context};
use js::jsapi::{JSObject, JSContext, JSVal};
use js::glue::RUST_OBJECT_TO_JSVAL;
use std::cast;
impl FormData {
pub fn init_wrapper(@mut self) {
let script_context = global_script_context();
let cx = script_context.js_compartment.cx.ptr;
let owner = script_context.root_frame.get_ref().window;
let cache = owner.get_wrappercache();
let scope = cache.get_wrapper();
self.wrap_object_shared(cx, scope);
}
}
impl CacheableWrapper for FormData {
fn get_wrappercache(&mut self) -> &mut WrapperCache {
unsafe {
cast::transmute(&self.wrapper)
}
}
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
FormDataBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for FormData {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let script_context = task_from_context(cx);
unsafe {
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
}
}
}
impl DerivedWrapper for FormData {
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
fail!(~"nyi")
}
fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
let obj = self.wrap_object_shared(cx, scope);
if obj.is_null() {
return 0;
} else {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
return 1;
}
}
}

View file

@ -380,6 +380,7 @@ pub mod prototypes {
HTMLCollection, HTMLCollection,
Event, Event,
EventTarget, EventTarget,
FormData,
_ID_Count _ID_Count
} }
} }
@ -582,7 +583,7 @@ pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) ->
} }
pub fn initialize_global(global: *JSObject) { pub fn initialize_global(global: *JSObject) {
let protoArray = @mut ([0 as *JSObject, ..6]); //XXXjdm prototypes::_ID_COUNT let protoArray = @mut ([0 as *JSObject, ..7]); //XXXjdm prototypes::_ID_COUNT
unsafe { unsafe {
//XXXjdm we should be storing the box pointer instead of the inner //XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray); let box = squirrel_away(protoArray);

View file

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{WrapperCache};
pub struct Blob {
wrapper: WrapperCache
}
impl Blob {
pub fn new() -> @mut Blob {
@mut Blob {
wrapper: WrapperCache::new()
}
}
}

View file

@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{WrapperCache, DOMString, str};
use dom::blob::Blob;
use std::hashmap::HashMap;
enum FormDatum {
StringData(DOMString),
BlobData { blob: @mut Blob, name: DOMString }
}
pub struct FormData {
data: HashMap<~str, FormDatum>,
wrapper: WrapperCache
}
impl FormData {
pub fn new() -> @mut FormData {
@mut FormData {
data: HashMap::new(),
wrapper: WrapperCache::new()
}
}
pub fn Append(&mut self, name: DOMString, value: @mut Blob, filename: Option<DOMString>) {
let blob = BlobData {
blob: value,
name: filename.get_or_default(str(~"default"))
};
self.data.insert(name.to_str(), blob);
}
pub fn Append_(&mut self, name: DOMString, value: DOMString) {
self.data.insert(name.to_str(), StringData(value));
}
}

View file

@ -38,6 +38,7 @@ pub mod dom {
pub mod clientrectlist; pub mod clientrectlist;
pub mod domparser; pub mod domparser;
pub mod htmlcollection; pub mod htmlcollection;
pub mod formdata;
pub mod codegen { pub mod codegen {
pub mod ClientRectBinding; pub mod ClientRectBinding;
pub mod ClientRectListBinding; pub mod ClientRectListBinding;
@ -45,8 +46,10 @@ pub mod dom {
pub mod EventBinding; pub mod EventBinding;
pub mod EventTargetBinding; pub mod EventTargetBinding;
pub mod HTMLCollectionBinding; pub mod HTMLCollectionBinding;
pub mod FormDataBinding;
} }
} }
pub mod blob;
pub mod characterdata; pub mod characterdata;
pub mod clientrect; pub mod clientrect;
pub mod clientrectlist; pub mod clientrectlist;
@ -55,6 +58,7 @@ pub mod dom {
pub mod element; pub mod element;
pub mod event; pub mod event;
pub mod eventtarget; pub mod eventtarget;
pub mod formdata;
pub mod htmlcollection; pub mod htmlcollection;
pub mod node; pub mod node;
pub mod window; pub mod window;

@ -1 +1 @@
Subproject commit 9e623124ee5508faac2666fae20c025ff6c52472 Subproject commit af080e2ab3ca871a6e77339eb752e59b3903b068