Bug 1463015: Part 1 - Allow using WebIDL Window/WindowProxy types in XPIDL. r?nika
WindowProxy currently can't be used in XPIDL at all. It's a non-concrete class
which maps to a native type with an abstract interface that WebIDL can convert
to and from but XPIDL can't.
Window can be used, to some extent, but it requires using the
nsGlobalWindowInner type rather than nsPIDOMWindowInner, which maps better to
existing code.
This solution is not ideal, since it adds special cases for Window interfaces.
The only alternative I can think of, though, would require writing a lot of
complex type-detection templates like we use for WebIDL, which would be harder
to maintain and less efficient. Given that I don't expect us to have many
other special cases like this in the future, I don't think that's worth the
effort and maintenance burden.
MozReview-Commit-ID: 8ta74tjozV3
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1309,29 +1309,31 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::WebrtcGlobalInformation',
'headerFile': 'WebrtcGlobalInformation.h',
'wrapperCache': False,
'concrete': False,
},
'Window': {
'nativeType': 'nsGlobalWindowInner',
+ 'xpidlNativeType': 'nsPIDOMWindowInner',
'headerFile': 'nsGlobalWindow.h',
'binaryNames': {
'postMessage': 'postMessageMoz',
},
'implicitJSContext': [
'createImageBitmap',
'requestIdleCallback'
],
},
'WindowProxy': {
'nativeType': 'nsPIDOMWindowOuter',
'headerFile': 'nsPIDOMWindow.h',
+ 'xpidlName': 'Window',
'concrete': False
},
'WindowRoot': {
'nativeType': 'nsWindowRoot'
},
'WorkerDebuggerGlobalScope': {
--- a/xpcom/idl-parser/xpidl/jsonxpt.py
+++ b/xpcom/idl-parser/xpidl/jsonxpt.py
@@ -78,16 +78,17 @@ def get_type(type, calltype, iid_is=None
'tag': 'TD_INTERFACE_TYPE',
'name': type.name,
}
if isinstance(type, xpidl.WebIDL):
return {
'tag': 'TD_DOMOBJECT',
'name': type.name,
+ 'xpidlName': type.xpidlName,
'native': type.native,
'headerFile': type.headerFile,
}
if isinstance(type, xpidl.Native):
if type.specialtype:
return {
'tag': TypeMap[type.specialtype]
--- a/xpcom/idl-parser/xpidl/xpidl.py
+++ b/xpcom/idl-parser/xpidl/xpidl.py
@@ -585,23 +585,25 @@ class WebIDL(object):
# interfaces.
# TODO: More explicit compile-time checks?
assert parent.webidlconfig is not None, \
"WebIDL declarations require passing webidlconfig to resolve."
# Resolve our native name according to the WebIDL configs.
config = parent.webidlconfig.get(self.name, {})
- self.native = config.get('nativeType')
+ self.native = config.get('xpidlNativeType') or config.get('nativeType')
if self.native is None:
self.native = "mozilla::dom::%s" % self.name
self.headerFile = config.get('headerFile')
if self.headerFile is None:
self.headerFile = self.native.replace('::', '/') + '.h'
+ self.xpidlName = config.get('xpidlName') or self.name
+
parent.setName(self)
def isScriptable(self):
return True # All DOM objects are script exposed.
def nativeType(self, calltype):
return "%s %s" % (self.native, calltype != 'in' and '* *' or '*')
--- a/xpcom/reflect/xptinfo/xptcodegen.py
+++ b/xpcom/reflect/xptinfo/xptcodegen.py
@@ -223,17 +223,17 @@ def link_to_cpp(interfaces, fd):
if idx is None:
idx = domobject_cache[do['name']] = len(domobjects)
includes.add(do['headerFile'])
domobjects.append(nsXPTDOMObjectInfo(
"%d = %s" % (idx, do['name']),
# These methods are defined at the top of the generated file.
mUnwrap="UnwrapDOMObject<mozilla::dom::prototypes::id::%s, %s>" %
- (do['name'], do['native']),
+ (do['xpidlName'], do['native']),
mWrap="WrapDOMObject<%s>" % do['native'],
mCleanup="CleanupDOMObject<%s>" % do['native'],
))
return idx
def lower_string(s):
if s in strings:
@@ -468,22 +468,63 @@ template<mozilla::dom::prototypes::ID Pr
static nsresult UnwrapDOMObject(JS::HandleValue aHandle, void** aObj)
{
RefPtr<T> p;
nsresult rv = mozilla::dom::UnwrapObject<PrototypeID, T>(aHandle, p);
p.forget(aObj);
return rv;
}
+// DOM Window bindings require some special casing. They're one of the few
+// cases where we use abstract rather than concrete types for DOM objects,
+// and while the WebIDL binding generator handles them transparently, we
+// need to treat them specially here.
+template<>
+nsresult UnwrapDOMObject<mozilla::dom::prototypes::id::Window, nsPIDOMWindowOuter>(JS::HandleValue aHandle, void** aObj)
+{
+ RefPtr<nsGlobalWindowInner> win;
+ nsresult rv = UNWRAP_OBJECT(Window, aHandle, win);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsPIDOMWindowOuter> outer = win->GetOuterWindow();
+ outer.forget(aObj);
+ }
+ return rv;
+}
+
+template<>
+nsresult UnwrapDOMObject<mozilla::dom::prototypes::id::Window, nsPIDOMWindowInner>(JS::HandleValue aHandle, void** aObj)
+{
+ RefPtr<nsGlobalWindowInner> win;
+ nsresult rv = UNWRAP_OBJECT(Window, aHandle, win);
+ if (NS_SUCCEEDED(rv)) {
+ *aObj = win.forget().take()->AsInner();
+ }
+ return rv;
+}
+
template<typename T>
static bool WrapDOMObject(JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle)
{
return mozilla::dom::GetOrCreateDOMReflector(aCx, reinterpret_cast<T*>(aObj), aHandle);
}
+template<>
+bool WrapDOMObject<nsPIDOMWindowOuter>(JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle)
+{
+ auto window = reinterpret_cast<nsPIDOMWindowOuter*>(aObj);
+ return mozilla::dom::GetOrCreateDOMReflector(aCx, static_cast<nsGlobalWindowOuter*>(window), aHandle);
+}
+
+template<>
+bool WrapDOMObject<nsPIDOMWindowInner>(JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle)
+{
+ auto window = reinterpret_cast<nsPIDOMWindowInner*>(aObj);
+ return mozilla::dom::GetOrCreateDOMReflector(aCx, static_cast<nsGlobalWindowInner*>(window), aHandle);
+}
+
template<typename T>
static void CleanupDOMObject(void* aObj)
{
RefPtr<T> p = already_AddRefed<T>(reinterpret_cast<T*>(aObj));
}
namespace xpt {
namespace detail {