Bug 895495. Add a faster way to create JS-implemented WebIDL objects from chrome. r=mccr8

This adds a Interface._create(targetWindow, chromeObj) static method
that lets a JS-implemented WebIDL object implementing Interface be
created in the window targetWindow using chromeObj as its JS
implementation.
This commit is contained in:
Boris Zbarsky 2013-07-23 10:09:19 -04:00
Родитель 276a31d596
Коммит c25761a19b
1 изменённых файлов: 74 добавлений и 17 удалений

Просмотреть файл

@ -1068,7 +1068,7 @@ class CGClassConstructor(CGAbstractStaticMethod):
def generate_code(self):
preamble = """
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
JS::Rooted<JSObject*> obj(cx, &args.callee());
"""
name = self._ctor.identifier.name
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
@ -1090,7 +1090,7 @@ class CGConstructNavigatorObjectHelper(CGAbstractStaticMethod):
CGAbstractStaticMethod.__init__(self, descriptor, name, rtype, args)
def definition_body(self):
return genConstructorBody(self.descriptor)
return CGIndenter(CGGeneric(genConstructorBody(self.descriptor))).define()
class CGConstructNavigatorObject(CGAbstractMethod):
"""
@ -1485,6 +1485,15 @@ class MethodDefiner(PropertyDefiner):
self.chrome.append(toStringDesc)
else:
self.regular.append(toStringDesc)
elif (descriptor.interface.isJSImplemented() and
descriptor.interface.hasInterfaceObject()):
self.chrome.append({"name": '_create',
"nativeName": ("%s::_Create" %
descriptor.name),
"methodInfo": False,
"length": 2,
"flags": "0",
"condition": MemberCondition(None, None) })
if static:
if not descriptor.interface.hasInterfaceObject():
@ -8438,7 +8447,11 @@ class CGBindingRoot(CGThing):
requiresContentUtils = any(d.interface.hasInterfaceObject() for d in descriptors)
def descriptorHasChromeOnly(desc):
return (any(isChromeOnly(a) for a in desc.interface.members) or
desc.interface.getExtendedAttribute("ChromeOnly") is not None)
desc.interface.getExtendedAttribute("ChromeOnly") is not None or
# JS-implemented interfaces with an interface object get a
# chromeonly _create method.
(desc.interface.isJSImplemented() and
desc.interface.hasInterfaceObject()))
hasChromeOnly = any(descriptorHasChromeOnly(d) for d in descriptors)
# XXXkhuey ugly hack but this is going away soon.
isEventTarget = webIDLFile.endswith("EventTarget.webidl")
@ -9240,20 +9253,20 @@ class CGJSImplMethod(CGNativeMember):
args = args[2:]
constructorArgs = [arg.name for arg in args]
initCall = """
// Wrap the object before calling __Init so that __DOM_IMPL__ is available.
nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(window);
JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject());
JS::Rooted<JS::Value> wrappedVal(cx);
if (!WrapNewBindingObject(cx, scopeObj, impl, &wrappedVal)) {
MOZ_ASSERT(JS_IsExceptionPending(cx));
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
// Initialize the object with the constructor arguments.
impl->mImpl->__Init(%s);
if (aRv.Failed()) {
return nullptr;
}""" % (", ".join(constructorArgs))
// Wrap the object before calling __Init so that __DOM_IMPL__ is available.
nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(window);
JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject());
JS::Rooted<JS::Value> wrappedVal(cx);
if (!WrapNewBindingObject(cx, scopeObj, impl, &wrappedVal)) {
MOZ_ASSERT(JS_IsExceptionPending(cx));
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
// Initialize the object with the constructor arguments.
impl->mImpl->__Init(%s);
if (aRv.Failed()) {
return nullptr;
}""" % (", ".join(constructorArgs))
else:
initCall = ""
return genConstructorBody(self.descriptor, initCall)
@ -9396,6 +9409,15 @@ class CGJSImplClass(CGBindingImplClass):
baseConstructors=baseConstructors,
body=constructorBody)
self.methodDecls.append(
ClassMethod("_Create",
"JSBool",
[Argument("JSContext*", "cx"),
Argument("unsigned", "argc"),
Argument("JS::Value*", "vp")],
static=True,
body=self.getCreateFromExistingBody()))
CGClass.__init__(self, descriptor.name,
bases=baseClasses,
constructors=[constructor],
@ -9427,6 +9449,41 @@ class CGJSImplClass(CGBindingImplClass):
def getGetParentObjectBody(self):
return "return mParent;"
def getCreateFromExistingBody(self):
# XXXbz we could try to get parts of this (e.g. the argument
# conversions) auto-generated by somehow creating an IDLMethod and
# adding it to our interface, but we'd still need to special-case the
# implementation slightly to have it not try to forward to the JS
# object...
return string.Template(
"JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n"
"if (args.length() < 2) {\n"
' return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${ifaceName}._create");\n'
"}\n"
"if (!args[0].isObject()) {\n"
' return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of ${ifaceName}._create");\n'
"}\n"
"if (!args[1].isObject()) {\n"
' return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 2 of ${ifaceName}._create");\n'
"}\n"
"\n"
"// GlobalObject will go through wrappers as needed for us, and\n"
"// is simpler than the right UnwrapArg incantation.\n"
"GlobalObject global(cx, &args[0].toObject());\n"
"if (global.Failed()) {\n"
" return false;\n"
"}\n"
"nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());\n"
"if (!window) {\n"
' return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of ${ifaceName}._create");\n'
"}\n"
"JS::Rooted<JSObject*> arg(cx, &args[1].toObject());\n"
"nsRefPtr<${implName}> impl = new ${implName}(arg, window);\n"
"return WrapNewBindingObject(cx, arg, impl, args.rval());").substitute({
"ifaceName": self.descriptor.interface.identifier.name,
"implName": self.descriptor.name
})
def isJSImplementedDescriptor(descriptorProvider):
return (isinstance(descriptorProvider, Descriptor) and
descriptorProvider.interface.isJSImplemented())