Bug 1463015: Part 1 - Allow using WebIDL Window/WindowProxy types in XPIDL. r?nika draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 20 May 2018 14:35:05 -0700
changeset 797545 94d227e7222e6a8e971955a25cf4ee562ee001bf
parent 797531 a97ee65471569f6e285cdf998b13d1b241099b37
child 797546 3a780c628a2f4df31094b86e323e414d777e52d6
push id110512
push usermaglione.k@gmail.com
push dateSun, 20 May 2018 22:52:08 +0000
reviewersnika
bugs1463015
milestone62.0a1
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
dom/bindings/Bindings.conf
xpcom/idl-parser/xpidl/jsonxpt.py
xpcom/idl-parser/xpidl/xpidl.py
xpcom/reflect/xptinfo/xptcodegen.py
--- 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 {