Add codegen support for dictionaries, and implement Event bindings as a side-effect. Add a stub EventTarget to allow the build to complete.

This commit is contained in:
Josh Matthews 2013-05-08 13:35:07 -04:00
parent 597f7bdc6d
commit af2db0cf68
15 changed files with 712 additions and 103 deletions

View file

@ -116,13 +116,11 @@ DOMInterfaces = {
'ClientRect': [
{
'nativeType': 'ClientRect',
'pointerType': '@mut '
}],
'ClientRectList': [
{
'nativeType': 'ClientRectList',
'pointerType': '@mut '
}],
'CSS2Properties': {
@ -137,7 +135,6 @@ DOMInterfaces = {
'DOMParser': {
'nativeType': 'DOMParser',
'pointerType': '@mut '
},
'DOMSettableTokenList': [
@ -160,10 +157,9 @@ DOMInterfaces = {
'Event': [
{
'nativeType': 'Event_'
},
{
'workers': True,
}],
],
'EventListener': [
{
@ -174,16 +170,17 @@ DOMInterfaces = {
'EventTarget': [
{
'nativeType': 'nsDOMEventTargetHelper',
'hasInstanceInterface': 'nsIDOMEventTarget',
'concrete': False,
'prefable': True,
# 'nativeType': 'nsDOMEventTargetHelper',
# 'hasInstanceInterface': 'nsIDOMEventTarget',
# 'concrete': False,
# 'prefable': True,
},
{
'workers': True,
'headerFile': 'mozilla/dom/workers/bindings/EventTarget.h',
'concrete': False
}],
#{
# 'workers': True,
# 'headerFile': 'mozilla/dom/workers/bindings/EventTarget.h',
# 'concrete': False
#}
],
'FileList': [
{

View file

@ -506,7 +506,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
return template
return CGWrapper(
CGIndenter(CGGeneric(template)),
pre="if (${haveValue}) {\n",
pre="if ${haveValue} != 0 {\n",
post=("\n"
"} else {\n"
"%s;\n"
@ -1181,9 +1181,8 @@ for (uint32_t i = 0; i < length; ++i) {
# should be able to assume not isOptional here.
assert not isOptional
typeName = "" #XXXjdm unfinished
#typeName = CGDictionary.makeDictionaryName(type.inner,
# descriptorProvider.workers)
typeName = CGDictionary.makeDictionaryName(type.inner,
descriptorProvider.workers)
actualTypeName = typeName
selfRef = "${declName}"
@ -1192,20 +1191,20 @@ for (uint32_t i = 0; i < length; ++i) {
# If we're a member of something else, the const
# will come from the Optional or our container.
if not isMember:
declType = CGWrapper(declType, pre="const ")
selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef)
selfRef = "%s" % selfRef
# We do manual default value handling here, because we
# actually do want a jsval, and we only handle null anyway
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
val = "(${haveValue}) ? ${val} : JSVAL_NULL"
val = "if ${haveValue} { ${val} } else { JSVAL_NULL }"
else:
val = "${val}"
template = ("if (!%s.Init(cx, %s)) {\n"
" return false;\n"
"}" % (selfRef, val))
template = ("%s = %s::new();\n"
"if %s.Init(cx, %s) == 0 {\n"
" return 0;\n"
"}" % (selfRef, actualTypeName, selfRef, val))
return (template, declType, None, False)
@ -1238,10 +1237,10 @@ for (uint32_t i = 0; i < length; ++i) {
dataLoc = "${declName}"
#XXXjdm conversionBehavior should be used
template = (
"match JSValConvertible::from_jsval::<%s, %s>(${val}) {\n"
"match JSValConvertible::from_jsval::<%s>(${val}) {\n"
" None => return 0,\n"
" Some(v) => %s = v\n"
"}" % (typeName, typeName, dataLoc))
"}" % (typeName, dataLoc))
declType = CGGeneric(typeName)
if (defaultValue is not None and
# We already handled IDLNullValue, so just deal with the other ones
@ -1253,7 +1252,7 @@ for (uint32_t i = 0; i < length; ++i) {
assert(tag == IDLType.Tags.bool)
defaultStr = toStringBool(defaultValue.value)
template = CGWrapper(CGIndenter(CGGeneric(template)),
pre="if (${haveValue}) {\n",
pre="if ${haveValue} != 0 {\n",
post=("\n"
"} else {\n"
" %s = %s;\n"
@ -1305,7 +1304,7 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >")
declType = CGWrapper(mutableDeclType, pre="const ")
result.append(
CGList([CGGeneric("let "),
CGList([CGGeneric("let mut "),
CGGeneric(originalDeclName),
CGGeneric(": "),
declType,
@ -1349,19 +1348,19 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
def convertConstIDLValueToJSVal(value):
if isinstance(value, IDLNullValue):
return "JSVAL_NULL"
return "NullVal"
tag = value.type.tag()
if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
IDLType.Tags.uint16, IDLType.Tags.int32]:
return "INT_TO_JSVAL(%s)" % (value.value)
return "IntVal(%s)" % (value.value)
if tag == IDLType.Tags.uint32:
return "UINT_TO_JSVAL(%s)" % (value.value)
return "UintVal(%s)" % (value.value)
if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
return "DOUBLE_TO_JSVAL(%s)" % (value.value)
return "DoubleVal(%s)" % (value.value)
if tag == IDLType.Tags.bool:
return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
return "BoolVal(true)" if value.value else "BoolVal(false)"
if tag in [IDLType.Tags.float, IDLType.Tags.double]:
return "DOUBLE_TO_JSVAL(%s)" % (value.value)
return "DoubleVal(%s)" % (value.value)
raise TypeError("Const value of unhandled type: " + value.type)
class CGArgumentConverter(CGThing):
@ -1455,7 +1454,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
"""
if failureCode is None:
if not haveSuccessCode:
return "return " + wrapCall + ";"
return wrapCall + ";\n" + "return if *vp != 0 { 1 } else { 0 };"
failureCode = "return 0;"
str = ("if !%s {\n" +
CGIndenter(CGGeneric(failureCode)).define() + "\n" +
@ -1554,9 +1553,10 @@ for (uint32_t i = 0; i < length; ++i) {
if type.isString():
if type.nullable():
return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalPtr})" % result), False)
return (wrapAndSetPtr("*${jsvalPtr} = domstring_to_jsval(cx, &%s)" % result), False)
else:
return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr})" % result), False)
#XXXjdm Can we be smarter when we know it's not nullable?
return (wrapAndSetPtr("*${jsvalPtr} = domstring_to_jsval(cx, &%s)" % result), False)
if type.isEnum():
if type.nullable():
@ -1624,7 +1624,7 @@ if (!%(resultStr)s) {
return (setValue("RUST_UINT_TO_JSVAL(%s)" % result), True)
elif tag == IDLType.Tags.bool:
return (setValue("RUST_BOOLEAN_TO_JSVAL(%s)" % result), True)
return (setValue("RUST_BOOLEAN_TO_JSVAL(%s as JSBool)" % result), True)
else:
raise TypeError("Need to learn to wrap primitive: %s" % type)
@ -1688,7 +1688,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
result = CGWrapper(result, pre="Nullable<", post=">")
return result, False
if returnType.isString():
return CGGeneric("nsString"), True
return CGGeneric("DOMString"), False
if returnType.isEnum():
if returnType.nullable():
raise TypeError("We don't support nullable enum return values")
@ -2027,8 +2027,8 @@ class ConstDefiner(PropertyDefiner):
return decls + self.generatePrefableArray(
array, name,
' { &%s_name as *u8 as *libc::c_char, %s }',
' { 0, JSVAL_VOID }',
' ConstantSpec { name: &%s_name as *u8 as *libc::c_char, value: %s }',
' ConstantSpec { name: 0 as *libc::c_char, value: VoidVal }',
'ConstantSpec',
PropertyDefiner.getControllingPref, specData, doIdArrays)
@ -2302,7 +2302,7 @@ static InterfaceObjectClass: JSClass = {
0 as *u8, /* trace */
JSCLASS_NO_INTERNAL_MEMBERS
};
""" % (str_to_const_array("Function", ctorname, hasinstance, ctorname))
""" % (str_to_const_array("Function"), ctorname, hasinstance, ctorname)
class CGList(CGThing):
"""
@ -2480,21 +2480,19 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
//JSAutoCompartment ac(aCx, parent);
let global = JS_GetGlobalForObject(aCx, parent);
%s
let proto = GetProtoObject(aCx, global, global);
if proto.is_null() {
return ptr::null();
}
let cache = ptr::to_mut_unsafe_ptr(aObject.get_wrappercache());
%s
//NS_ADDREF(aObject);
(*cache).set_wrapper(obj);
return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
CreateBindingJSObject(self.descriptor, "parent"))
return obj;""" % (CreateBindingJSObject(self.descriptor, "parent"))
class CGWrapMethod(CGAbstractMethod):
def __init__(self, descriptor):
@ -2768,35 +2766,6 @@ class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
/* Get the interface object for this class. This will create the object as
needed. */""" + CGGetPerInterfaceObject.definition_body(self)
def CheckPref(descriptor, globalName, varName, retval, wrapperCache = None):
"""
Check whether bindings should be enabled for this descriptor. If not, set
varName to false and return retval.
"""
if not descriptor.prefable:
return ""
if wrapperCache:
wrapperCache = " %s->ClearIsDOMBinding();\n" % (wrapperCache)
else:
wrapperCache = ""
failureCode = (" %s = false;\n" +
" return %s;") % (varName, retval)
return """
{
XPCWrappedNativeScope* scope =
XPCWrappedNativeScope::FindInJSObjectScope(aCx, %s);
if (!scope) {
%s
}
if (!scope->ExperimentalBindingsEnabled()) {
%s%s
}
}
""" % (globalName, failureCode, wrapperCache, failureCode)
class CGDefineDOMInterfaceMethod(CGAbstractMethod):
"""
A method for resolve hooks to try to lazily define the interface object for
@ -2827,7 +2796,8 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
getter = "GetConstructorObject"
body = " let content = task_from_context(aCx);\n"
if self.descriptor.proxy:
#XXXjdm This self.descriptor.concrete check shouldn't be necessary
if not self.descriptor.concrete or self.descriptor.proxy:
body += """ let traps = ProxyTraps {
getPropertyDescriptor: getPropertyDescriptor,
getOwnPropertyDescriptor: getOwnPropertyDescriptor,
@ -2869,7 +2839,6 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
body = "" #XXXjdm xray stuff isn't necessary yet
return (body + " let global: *JSObject = JS_GetGlobalForObject(aCx, aReceiver);\n" +
CheckPref(self.descriptor, "global", "*aEnabled", "false") +
"""
*aEnabled = true;
return %s(aCx, global, aReceiver).is_not_null();""" % (getter))
@ -2903,6 +2872,9 @@ class CGCallGenerator(CGThing):
# This is a workaround for a bug in Apple's clang.
if a.type.isObject() and not a.type.nullable() and not a.optional:
name = "(JSObject&)" + name
#XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer
if a.type.isDictionary():
name = "&" + name
args.append(CGGeneric(name))
# Return values that go in outparams go here
@ -3149,7 +3121,7 @@ class CGSpecializedMethod(CGAbstractExternMethod):
self.method = method
name = method.identifier.name
args = [Argument('*JSContext', 'cx'), Argument('JSHandleObject', 'obj'),
Argument('*%s' % descriptor.nativeType, 'self'),
Argument('*mut %s' % descriptor.nativeType, 'self'),
Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')]
CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args)
@ -3165,7 +3137,7 @@ class CGGenericGetter(CGAbstractBindingMethod):
A class for generating the C++ code for an IDL attribute getter.
"""
def __init__(self, descriptor, lenientThis=False):
args = [Argument('*JSContext', 'cx'), Argument('uint', '_argc'),
args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
Argument('*JSVal', 'vp')]
if lenientThis:
name = "genericLenientGetter"
@ -3192,8 +3164,8 @@ class CGSpecializedGetter(CGAbstractExternMethod):
def __init__(self, descriptor, attr):
self.attr = attr
name = 'get_' + attr.identifier.name
args = [ Argument('*JSContext', '_cx'),
Argument('JSHandleObject', '_obj'),
args = [ Argument('*JSContext', 'cx'),
Argument('JSHandleObject', 'obj'),
Argument('*%s' % descriptor.nativeType, 'self'),
Argument('*mut JSVal', 'vp') ]
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
@ -3210,8 +3182,9 @@ class CGSpecializedGetter(CGAbstractExternMethod):
getter=True))
if resultOutParam or self.attr.type.nullable() or not infallible:
nativeName = "Get" + nativeName
return CGIndenter(CGGetterCall(self.attr.type, nativeName,
self.descriptor, self.attr)).define()
return CGWrapper(CGIndenter(CGGetterCall(self.attr.type, nativeName,
self.descriptor, self.attr)),
pre=" let obj = (*obj.unnamed);\n").define()
def infallibleForMember(member, type, descriptorProvider):
"""
@ -3356,7 +3329,7 @@ class CGXrayHelper(CGAbstractExternMethod):
consts = self.properties.consts
if consts.hasNonChromeOnly() or consts.hasChromeOnly():
constArgs = "Some(vec::zip_slice(%(consts)s, *const_ids))" % varNames
setup += "let const_ids = (*content).dom_static.const_ids.get(&(prototypes::id::ClientRect as uint));\n"
setup += "let const_ids = (*content).dom_static.constant_ids.get(&(prototypes::id::ClientRect as uint));\n"
else:
constArgs = "None"
constArgs = CGGeneric(constArgs)
@ -3372,7 +3345,7 @@ class CGXrayHelper(CGAbstractExternMethod):
class CGResolveProperty(CGXrayHelper):
def __init__(self, descriptor, properties):
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'wrapper'),
Argument('jsid', 'id'), Argument('bool', '_set'),
Argument('jsid', 'id'), Argument('bool', 'set'),
Argument('*mut JSPropertyDescriptor', 'desc')]
CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
properties)
@ -3469,7 +3442,7 @@ class CGProxyUnwrap(CGAbstractMethod):
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'),
Argument('*JSObject', '_receiver'), Argument('jsid', 'id'),
Argument('*JSObject', 'receiver'), Argument('jsid', 'id'),
Argument('*mut JSVal', 'vp')]
CGAbstractExternMethod.__init__(self, descriptor, "get", "JSBool", args)
self.descriptor = descriptor
@ -3530,7 +3503,7 @@ if !GetPropertyOnPrototype(cx, proxy, id, &mut found, cast::transmute(vp)) {
return 0;
}
if (found) {
if found {
return 1;
}
%s
@ -3542,7 +3515,7 @@ return 1;""" % (getIndexedOrExpando, getNamed)
class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', '_proxy')]
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy')]
CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*JSString", args)
self.descriptor = descriptor
def getBody(self):
@ -3617,7 +3590,7 @@ class CGClassConstructHook(CGAbstractExternMethod):
JS-visible constructor for our objects
"""
def __init__(self, descriptor):
args = [Argument('*JSContext', 'cx'), Argument('u32', '_argc'), Argument('*mut JSVal', 'vp')]
args = [Argument('*JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
'JSBool', args)
self._ctor = self.descriptor.interface.ctor()
@ -3709,7 +3682,7 @@ class CGClassFinalizeHook(CGAbstractClassHook):
A hook for finalize, used to release our native object.
"""
def __init__(self, descriptor):
args = [Argument('*JSFreeOp', '_fop'), Argument('*JSObject', 'obj')]
args = [Argument('*JSFreeOp', 'fop'), Argument('*JSObject', 'obj')]
CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
'void', args)
@ -3857,6 +3830,239 @@ class CGDescriptor(CGThing):
def define(self):
return self.cgRoot.define()
class CGDictionary(CGThing):
def __init__(self, dictionary, descriptorProvider):
self.dictionary = dictionary;
self.workers = descriptorProvider.workers
if all(CGDictionary(d, descriptorProvider).generatable for
d in CGDictionary.getDictionaryDependencies(dictionary)):
self.generatable = True
else:
self.generatable = False
# Nothing else to do here
return
# Getting a conversion template for interface types can fail
# if we don't have a relevant descriptor when self.workers is True.
# If that happens, just mark ourselves as not being
# generatable and move on.
try:
self.memberInfo = [
(member,
getJSToNativeConversionTemplate(member.type,
descriptorProvider,
isMember=True,
isOptional=(not member.defaultValue),
defaultValue=member.defaultValue))
for member in dictionary.members ]
except NoSuchDescriptorError, err:
if not self.workers:
raise err
self.generatable = False
def declare(self):
if not self.generatable:
return ""
d = self.dictionary
if d.parent:
inheritance = ": public %s " % self.makeClassName(d.parent) #XXXjdm
else:
inheritance = ""
memberDecls = [" %s: %s," %
(m[0].identifier.name, self.getMemberType(m))
for m in self.memberInfo]
return (string.Template(
"pub struct ${selfName} {\n" + #XXXjdm deal with inheritance
"\n".join(memberDecls) + "\n" +
# NOTE: jsids are per-runtime, so don't use them in workers
"\n".join(" //static jsid " +
self.makeIdName(m.identifier.name) + ";" for
m in d.members) + "\n"
"}").substitute( { "selfName": self.makeClassName(d),
"inheritance": inheritance }))
def define(self):
if not self.generatable:
return ""
d = self.dictionary
if d.parent:
initParent = ("// Per spec, we init the parent's members first\n"
"if (!%s::Init(cx, val)) {\n"
" return false;\n"
"}\n" % self.makeClassName(d.parent))
else:
initParent = ""
memberInits = [CGIndenter(self.getMemberConversion(m)).define()
for m in self.memberInfo]
idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
(m.identifier.name + "_id", m.identifier.name))
for m in d.members]
idinit = CGList(idinit, " ||\n")
idinit = CGWrapper(idinit, pre="if (",
post=(") {\n"
" return false;\n"
"}"),
reindent=True)
def defaultValue(ty):
if ty is "bool":
return "false"
elif ty in ["i32", "u32"]:
return "0"
elif ty is "nsString":
return "\"\""
elif ty.startswith("Optional"):
return "None"
else:
return "/* uh oh: %s */" % ty
return string.Template(
# NOTE: jsids are per-runtime, so don't use them in workers
("static initedIds: bool = false;\n" +
"\n".join("static %s: jsid = JSID_VOID;" %
self.makeIdName(m.identifier.name)
for m in d.members) + "\n"
"\n"
"impl ${selfName} {\n"
"fn new() -> ${selfName} {\n"
" ${selfName} {\n" +
"\n".join(" %s: %s," % (m[0].identifier.name, defaultValue(self.getMemberType(m))) for m in self.memberInfo) + "\n"
" }\n"
"}\n"
"\n"
"fn InitIds(cx: *JSContext) -> bool {\n"
" //MOZ_ASSERT(!initedIds);\n"
"/*${idInit}\n"
" initedIds = true;*/ //XXXjdm\n"
" return true;\n"
"}\n"
"\n" if not self.workers else "") +
"fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool\n"
"{\n"
" unsafe {\n" +
# NOTE: jsids are per-runtime, so don't use them in workers
(" if (!initedIds && !${selfName}::InitIds(cx)) {\n"
" return 0;\n"
" }\n" if not self.workers else "") +
"${initParent}"
" let mut found: JSBool = 0;\n"
" let temp: JSVal = JSVAL_NULL;\n"
" let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n"
" if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n"
" return 0; //XXXjdm throw properly here\n"
" //return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
" }\n"
"\n"
"${initMembers}\n"
" return 1;\n"
" }\n"
"}\n"
"}").substitute({
"selfName": self.makeClassName(d),
"initParent": CGIndenter(CGGeneric(initParent)).define(),
"initMembers": "\n\n".join(memberInits),
"idInit": CGIndenter(idinit).define(),
"isMainThread": toStringBool(not self.workers)
})
@staticmethod
def makeDictionaryName(dictionary, workers):
suffix = "Workers" if workers else ""
return dictionary.identifier.name + suffix
def makeClassName(self, dictionary):
return self.makeDictionaryName(dictionary, self.workers)
def getMemberType(self, memberInfo):
(member, (templateBody, declType,
holderType, dealWithOptional)) = memberInfo
# We can't handle having a holderType here
assert holderType is None
if dealWithOptional:
declType = CGWrapper(declType, pre="Optional< ", post=" >")
return declType.define()
def getMemberConversion(self, memberInfo):
(member, (templateBody, declType,
holderType, dealWithOptional)) = memberInfo
replacements = { "val": "temp",
"valPtr": "&temp",
"declName": ("self.%s" % member.identifier.name),
# We need a holder name for external interfaces, but
# it's scoped down to the conversion so we can just use
# anything we want.
"holderName": "holder"}
# We can't handle having a holderType here
assert holderType is None
if dealWithOptional:
replacements["declName"] = "(" + replacements["declName"] + ".Value())"
if member.defaultValue:
replacements["haveValue"] = "found"
# NOTE: jsids are per-runtime, so don't use them in workers
if True or self.workers: #XXXjdm hack until 'static mut' exists for global jsids
propName = member.identifier.name
propCheck = ('str::as_c_str("%s", |s| { JS_HasProperty(cx, RUST_JSVAL_TO_OBJECT(val), s, ptr::to_unsafe_ptr(&found)) })' %
propName)
propGet = ('str::as_c_str("%s", |s| { JS_GetProperty(cx, RUST_JSVAL_TO_OBJECT(val), s, ptr::to_unsafe_ptr(&temp)) })' %
propName)
else:
propId = self.makeIdName(member.identifier.name);
propCheck = ("JS_HasPropertyById(cx, RUST_JSVAL_TO_OBJECT(val), %s, ptr::to_unsafe_ptr(&found))" %
propId)
propGet = ("JS_GetPropertyById(cx, RUST_JSVAL_TO_OBJECT(val), %s, ptr::to_unsafe_ptr(&temp))" %
propId)
conversionReplacements = {
"prop": "(this->%s)" % member.identifier.name,
"convert": string.Template(templateBody).substitute(replacements),
"propCheck": propCheck,
"propGet": propGet
}
conversion = ("if isNull {\n"
" found = 0;\n"
"} else if ${propCheck} == 0 {\n"
" return 0;\n"
"}\n")
if member.defaultValue:
conversion += (
"if found != 0 {\n"
" if ${propGet} == 0 {\n"
" return 0;\n"
" }\n"
"}\n"
"${convert}")
else:
conversion += (
"if found != 0 {\n"
" ${prop}.Construct();\n"
" if ${propGet} == 0 {\n"
" return 0;\n"
" }\n"
"${convert}\n"
"}")
conversionReplacements["convert"] = CGIndenter(
CGGeneric(conversionReplacements["convert"])).define()
return CGGeneric(
string.Template(conversion).substitute(conversionReplacements)
)
@staticmethod
def makeIdName(name):
return name + "_id"
@staticmethod
def getDictionaryDependencies(dictionary):
deps = set();
if dictionary.parent:
deps.add(dictionary.parent)
for member in dictionary.members:
if member.type.isDictionary():
deps.add(member.type.unroll().inner)
return deps
class CGBindingRoot(CGThing):
"""
Root codegen class for binding generation. Instantiate the class, and call
@ -3880,6 +4086,35 @@ class CGBindingRoot(CGThing):
cgthings = [ fun(e) for e in config.getEnums(webIDLFile)
for fun in [makeEnum, makeEnumTypedef] ]
# Do codegen for all the dictionaries. We have to be a bit careful
# here, because we have to generate these in order from least derived
# to most derived so that class inheritance works out. We also have to
# generate members before the dictionary that contains them.
#
# XXXbz this will fail if we have two webidl files A and B such that A
# declares a dictionary which inherits from a dictionary in B and B
# declares a dictionary (possibly a different one!) that inherits from a
# dictionary in A. The good news is that I expect this to never happen.
reSortedDictionaries = []
dictionaries = set(dictionaries)
while len(dictionaries) != 0:
# Find the dictionaries that don't depend on anything else anymore
# and move them over.
toMove = [d for d in dictionaries if
len(CGDictionary.getDictionaryDependencies(d) &
dictionaries) == 0]
if len(toMove) == 0:
raise TypeError("Loop in dictionary dependency graph")
dictionaries = dictionaries - set(toMove)
reSortedDictionaries.extend(toMove)
dictionaries = reSortedDictionaries
#XXXjdm No codegen for workers right now.
#cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True))
# for d in dictionaries])
cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
for d in dictionaries])
# Do codegen for all the descriptors
cgthings.extend([CGDescriptor(x) for x in descriptors])
@ -3910,6 +4145,8 @@ class CGBindingRoot(CGThing):
'dom::htmlcollection::*', #XXXjdm
'dom::bindings::proxyhandler::*',
'dom::domparser::*', #XXXjdm
'dom::event::*', #XXXjdm
'dom::eventtarget::*', #XXXjdm
'content::content_task::task_from_context',
'dom::bindings::utils::EnumEntry',
],

View file

@ -134,12 +134,12 @@ class Descriptor(DescriptorProvider):
nativeTypeDefault = "nsIDOM" + ifaceName
else:
if self.workers:
nativeTypeDefault = "mozilla::dom::workers::" + ifaceName
nativeTypeDefault = "workers::" + ifaceName
else:
nativeTypeDefault = "mozilla::dom::" + ifaceName
nativeTypeDefault = ifaceName
self.nativeType = desc.get('nativeType', nativeTypeDefault)
self.pointerType = desc.get('pointerType', '~')
self.pointerType = desc.get('pointerType', '@mut ')
self.hasInstanceInterface = desc.get('hasInstanceInterface', None)
# Do something sane for JSObject

View file

@ -0,0 +1,80 @@
[Constructor(DOMString type, optional EventInit eventInitDict)]
interface Event {
readonly attribute DOMString type;
readonly attribute EventTarget? target;
readonly attribute EventTarget? currentTarget;
const unsigned short NONE = 0;
const unsigned short CAPTURING_PHASE = 1;
const unsigned short AT_TARGET = 2;
const unsigned short BUBBLING_PHASE = 3;
readonly attribute unsigned short eventPhase;
void stopPropagation();
void stopImmediatePropagation();
readonly attribute boolean bubbles;
readonly attribute boolean cancelable;
void preventDefault();
readonly attribute boolean defaultPrevented;
readonly attribute boolean isTrusted;
readonly attribute DOMTimeStamp timeStamp;
[Throws]
void initEvent(DOMString type, boolean bubbles, boolean cancelable);
};
/*// Mozilla specific legacy stuff.
partial interface Event {
const long MOUSEDOWN = 0x00000001;
const long MOUSEUP = 0x00000002;
const long MOUSEOVER = 0x00000004;
const long MOUSEOUT = 0x00000008;
const long MOUSEMOVE = 0x00000010;
const long MOUSEDRAG = 0x00000020;
const long CLICK = 0x00000040;
const long DBLCLICK = 0x00000080;
const long KEYDOWN = 0x00000100;
const long KEYUP = 0x00000200;
const long KEYPRESS = 0x00000400;
const long DRAGDROP = 0x00000800;
const long FOCUS = 0x00001000;
const long BLUR = 0x00002000;
const long SELECT = 0x00004000;
const long CHANGE = 0x00008000;
const long RESET = 0x00010000;
const long SUBMIT = 0x00020000;
const long SCROLL = 0x00040000;
const long LOAD = 0x00080000;
const long UNLOAD = 0x00100000;
const long XFER_DONE = 0x00200000;
const long ABORT = 0x00400000;
const long ERROR = 0x00800000;
const long LOCATE = 0x01000000;
const long MOVE = 0x02000000;
const long RESIZE = 0x04000000;
const long FORWARD = 0x08000000;
const long HELP = 0x10000000;
const long BACK = 0x20000000;
const long TEXT = 0x40000000;
const long ALT_MASK = 0x00000001;
const long CONTROL_MASK = 0x00000002;
const long SHIFT_MASK = 0x00000004;
const long META_MASK = 0x00000008;
readonly attribute EventTarget? originalTarget;
readonly attribute EventTarget? explicitOriginalTarget;
[ChromeOnly] readonly attribute boolean multipleActionsPrevented;
void preventBubble();
void preventCapture();
boolean getPreventDefault();
};*/
dictionary EventInit {
boolean bubbles = false;
boolean cancelable = false;
};

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://www.w3.org/TR/2012/WD-dom-20120105/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface EventTarget {
};

View file

@ -1,6 +1,8 @@
#include "ClientRectBinding.h"
#include "ClientRectListBinding.h"
#include "DOMParserBinding.h"
#include "EventBinding.h"
#include "EventTargetBinding.h"
#include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h"
@ -16,6 +18,8 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr);
REGISTER_PROTO(DOMParser, nullptr);
REGISTER_PROTO(Event, nullptr);
REGISTER_PROTO(EventTarget, nullptr);
REGISTER_PROTO(HTMLCollection, nullptr);
#undef REGISTER_PROTO

View file

@ -3,19 +3,40 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use js::jsapi::JSVal;
use js::glue::bindgen::{RUST_INT_TO_JSVAL, RUST_JSVAL_TO_INT};
use js::{JSVAL_FALSE, JSVAL_TRUE};
use js::glue::bindgen::{RUST_UINT_TO_JSVAL, RUST_JSVAL_TO_INT};
pub trait JSValConvertible<T> {
pub trait JSValConvertible {
fn to_jsval(&self) -> JSVal;
fn from_jsval(val: JSVal) -> Option<T>;
fn from_jsval(val: JSVal) -> Option<Self>;
}
impl JSValConvertible<u32> for u32 {
impl JSValConvertible for u32 {
fn to_jsval(&self) -> JSVal {
RUST_INT_TO_JSVAL(*self as i32)
RUST_UINT_TO_JSVAL(*self)
}
fn from_jsval(val: JSVal) -> Option<u32> {
Some(RUST_JSVAL_TO_INT(val) as u32)
}
}
impl JSValConvertible for bool {
fn to_jsval(&self) -> JSVal {
if *self {
JSVAL_TRUE
} else {
JSVAL_FALSE
}
}
fn from_jsval(val: JSVal) -> Option<bool> {
if val == JSVAL_TRUE {
Some(true)
} else if val == JSVAL_FALSE {
Some(false)
} else {
None
}
}
}

View file

@ -0,0 +1,55 @@
/* 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 content::content_task::{task_from_context, global_content};
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::bindings::codegen::EventBinding;
use dom::event::Event_;
use js::jsapi::{JSObject, JSContext, JSVal};
use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
pub impl Event_ {
pub fn init_wrapper(@mut self) {
let content = global_content();
let cx = content.compartment.get().cx.ptr;
let owner = content.window.get();
let cache = owner.get_wrappercache();
let scope = cache.get_wrapper();
self.wrap_object_shared(cx, scope);
}
}
impl CacheableWrapper for Event_ {
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;
EventBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for Event_ {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
unsafe { (*content).window.get() as @mut CacheableWrapper }
}
}
impl DerivedWrapper for Event_ {
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

@ -0,0 +1,55 @@
/* 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 content::content_task::{task_from_context, global_content};
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::bindings::codegen::EventTargetBinding;
use dom::eventtarget::EventTarget;
use js::jsapi::{JSObject, JSContext, JSVal};
use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
pub impl EventTarget {
pub fn init_wrapper(@mut self) {
let content = global_content();
let cx = content.compartment.get().cx.ptr;
let owner = content.window.get();
let cache = owner.get_wrappercache();
let scope = cache.get_wrapper();
self.wrap_object_shared(cx, scope);
}
}
impl CacheableWrapper for EventTarget {
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;
EventTargetBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for EventTarget {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
unsafe { (*content).window.get() as @mut CacheableWrapper }
}
}
impl DerivedWrapper for EventTarget {
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

@ -6,7 +6,8 @@ use js;
use js::rust::Compartment;
use js::{JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSVAL_NULL,
JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY,
JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER, JSPROP_SETTER};
JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER,
JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSNative,
JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
use js::jsapi::bindgen::{JS_ValueToString,
@ -327,9 +328,18 @@ pub struct JSNativeHolder {
propertyHooks: *NativePropertyHooks
}
pub enum ConstantVal {
IntVal(i32),
UintVal(u32),
DoubleVal(f64),
BoolVal(bool),
NullVal,
VoidVal
}
pub struct ConstantSpec {
name: *libc::c_char,
value: JSVal
value: ConstantVal
}
pub struct DOMClass {
@ -360,6 +370,8 @@ pub mod prototypes {
ClientRectList,
DOMParser,
HTMLCollection,
Event,
EventTarget,
_ID_Count
}
}
@ -492,8 +504,17 @@ fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) ->
if spec.name.is_null() {
return true;
}
let jsval = match spec.value {
NullVal => JSVAL_NULL,
IntVal(i) => RUST_INT_TO_JSVAL(i),
UintVal(u) => RUST_UINT_TO_JSVAL(u),
DoubleVal(d) => RUST_DOUBLE_TO_JSVAL(d),
BoolVal(b) if b => JSVAL_TRUE,
BoolVal(_) => JSVAL_FALSE,
VoidVal => JSVAL_VOID
};
if JS_DefineProperty(cx, obj, spec.name,
spec.value, ptr::null(),
jsval, ptr::null(),
ptr::null(),
JSPROP_ENUMERATE | JSPROP_READONLY |
JSPROP_PERMANENT) == 0 {
@ -543,7 +564,7 @@ pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) ->
}
pub fn initialize_global(global: *JSObject) {
let protoArray = @mut ([0 as *JSObject, ..4]); //XXXjdm prototypes::_ID_COUNT
let protoArray = @mut ([0 as *JSObject, ..6]); //XXXjdm prototypes::_ID_COUNT
unsafe {
//XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray);

View file

@ -2,8 +2,97 @@
* 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::eventtarget::EventTarget;
use dom::window::Window;
use dom::bindings::codegen::EventBinding;
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
pub enum Event {
ResizeEvent(uint, uint, comm::Chan<()>),
ReflowEvent
}
pub struct Event_ {
wrapper: WrapperCache,
type_: DOMString,
default_prevented: bool,
cancelable: bool,
bubbles: bool,
trusted: bool,
}
impl Event_ {
pub fn new(type_: DOMString) -> Event_ {
Event_ {
wrapper: WrapperCache::new(),
type_: type_,
default_prevented: false,
cancelable: true,
bubbles: true,
trusted: false
}
}
pub fn EventPhase(&self) -> u16 {
0
}
pub fn Type(&self) -> DOMString {
copy self.type_
}
pub fn GetTarget(&self) -> Option<@mut EventTarget> {
None
}
pub fn GetCurrentTarget(&self) -> Option<@mut EventTarget> {
None
}
pub fn DefaultPrevented(&self) -> bool {
self.default_prevented
}
pub fn PreventDefault(&mut self) {
self.default_prevented = true
}
pub fn StopPropagation(&mut self) {
}
pub fn StopImmediatePropagation(&mut self) {
}
pub fn Bubbles(&self) -> bool {
self.bubbles
}
pub fn Cancelable(&self) -> bool {
self.cancelable
}
pub fn TimeStamp(&self) -> u64 {
0
}
pub fn InitEvent(&mut self,
type_: DOMString,
bubbles: bool,
cancelable: bool,
_rv: &mut ErrorResult) {
self.type_ = type_;
self.cancelable = cancelable;
self.bubbles = bubbles;
}
pub fn IsTrusted(&self) -> bool {
self.trusted
}
pub fn Constructor(_global: @mut Window,
type_: DOMString,
_init: &EventBinding::EventInit,
_rv: &mut ErrorResult) -> @mut Event_ {
@mut Event_::new(type_)
}
}

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 EventTarget {
wrapper: WrapperCache
}
pub impl EventTarget {
fn new() -> ~EventTarget {
~EventTarget {
wrapper: WrapperCache::new()
}
}
}

View file

@ -449,4 +449,10 @@ pub fn define_bindings(compartment: @mut Compartment) {
assert!(codegen::DOMParserBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
assert!(codegen::EventBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
assert!(codegen::EventTargetBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
}

View file

@ -61,6 +61,8 @@ pub mod dom {
pub mod bindings {
pub mod document;
pub mod element;
pub mod event;
pub mod eventtarget;
pub mod node;
pub mod text;
pub mod utils;
@ -75,6 +77,8 @@ pub mod dom {
pub mod ClientRectBinding;
pub mod ClientRectListBinding;
pub mod DOMParserBinding;
pub mod EventBinding;
pub mod EventTargetBinding;
pub mod HTMLCollectionBinding;
}
}
@ -85,6 +89,7 @@ pub mod dom {
pub mod domparser;
pub mod element;
pub mod event;
pub mod eventtarget;
pub mod htmlcollection;
pub mod node;
pub mod window;

View file

@ -49,3 +49,11 @@ window.alert(DOMParser);
let parser = new DOMParser();
window.alert(parser);
//window.alert(parser.parseFromString("<html></html>", "text/html"));
window.alert("Event:");
window.alert(Event);
let ev = new Event("foopy");
window.alert(ev.type);
window.alert(ev.defaultPrevented);
ev.preventDefault();
window.alert(ev.defaultPrevented);