Dawn.node: Make cts inheritance test pass

We can't make GPUDevice (C++) inherit from EventTarget (JS)
but we can set the prototype chain so that
`someGPUDevice instanceof EventTarget` returns true.

Bug: 419128706
Change-Id: Ief3541041b801cdf6d3d9df3227e0395aab0d084
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/245854
Commit-Queue: Gregg Tavares <gman@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/node/ManualConstructors.cpp b/src/dawn/node/ManualConstructors.cpp
index 9bfd9f7..8cd2494 100644
--- a/src/dawn/node/ManualConstructors.cpp
+++ b/src/dawn/node/ManualConstructors.cpp
@@ -54,6 +54,9 @@
     Napi::Object global = env.Global();
     DOMException_ctor = Napi::Persistent(global.Get("DOMException").As<Napi::Function>());
 
+    // Lookup the EventTarget class
+    EventTarget_ctor = Napi::Persistent(global.Get("EventTarget").As<Napi::Function>());
+
     // Define GPUUncapturedErrorEvent as a JavaScript object because it
     // must inherit from Event otherwise it can not be passed to an EventTarget
     // and this is apparently impossible in Napi if it's a C++ based object.
diff --git a/src/dawn/node/ManualConstructors.h b/src/dawn/node/ManualConstructors.h
index b7641b4..2f58858 100644
--- a/src/dawn/node/ManualConstructors.h
+++ b/src/dawn/node/ManualConstructors.h
@@ -39,6 +39,7 @@
     Napi::FunctionReference GPUUncapturedErrorEvent_ctor;
     Napi::FunctionReference GPUPipelineError_ctor;
     Napi::FunctionReference DOMException_ctor;
+    Napi::FunctionReference EventTarget_ctor;
 };
 
 }  // namespace wgpu::interop
diff --git a/src/dawn/node/interop/Browser.idl b/src/dawn/node/interop/Browser.idl
index 886b3f6..89803c1 100644
--- a/src/dawn/node/interop/Browser.idl
+++ b/src/dawn/node/interop/Browser.idl
@@ -49,7 +49,7 @@
 typedef(EventListenerInterface or EventListenerCallback) EventListener;
 typedef EventListenerCallback? EventHandler;
 
-[LegacyNoInterfaceObject] interface EventTarget {
+[LegacyNoInterfaceObject] [ManualImplementation] interface EventTarget {
   undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);
   undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
   boolean dispatchEvent(Event event);
diff --git a/src/dawn/node/interop/WebGPU.cpp.tmpl b/src/dawn/node/interop/WebGPU.cpp.tmpl
index d65fab2..d14cd6e 100644
--- a/src/dawn/node/interop/WebGPU.cpp.tmpl
+++ b/src/dawn/node/interop/WebGPU.cpp.tmpl
@@ -70,10 +70,7 @@
 
 {{ range $ := .Declarations}}
 {{-        if IsDictionary $}}{{template "Dictionary" $}}
-{{-   else if IsInterface  $}}
-{{-     if not (HasAnnotation $ "ManualImplementation")}}
-  {{template "Interface"  $}}
-{{-     end}}
+{{-   else if IsInterface  $}}{{template "Interface"  $}}
 {{-   else if IsEnum       $}}{{template "Enum"       $}}
 {{-   end}}
 {{- end}}
@@ -425,6 +422,7 @@
 {{- define "Interface"}}
 {{$.Name}}::{{$.Name}}() = default;
 
+{{-  if not (HasAnnotation $ "ManualImplementation")}}
 {{$.Name}}* {{$.Name}}::Unwrap(Napi::Object object) {
   auto* wrappers = Wrappers::For(object.Env());
   if (!object.InstanceOf(wrappers->{{$.Name}}_ctor.Value())) {
@@ -453,6 +451,7 @@
 
   return Interface<{{$.Name}}>(object);
 }
+{{-  end}}
 
 {{$.Name}}::~{{$.Name}}() = default;
 {{ end}}
diff --git a/src/dawn/node/interop/WebGPU.h.tmpl b/src/dawn/node/interop/WebGPU.h.tmpl
index e6dfbb5..e177489 100644
--- a/src/dawn/node/interop/WebGPU.h.tmpl
+++ b/src/dawn/node/interop/WebGPU.h.tmpl
@@ -140,6 +140,7 @@
 // interface {{$.Name}}
 class {{$.Name}} {{- if $.Inherits }} : public virtual {{$.Inherits}}{{end}} {
 public:
+{{-  if not (HasAnnotation $ "ManualImplementation")}}
   static Interface<{{$.Name}}> Bind(Napi::Env, std::unique_ptr<{{$.Name}}>&&);
   static {{$.Name}}* Unwrap(Napi::Object);
 
@@ -147,7 +148,7 @@
   static inline Interface<{{$.Name}}> Create(Napi::Env env, ARGS&& ... args) {
     return Bind(env, std::make_unique<T>(std::forward<ARGS>(args)...));
   }
-
+{{-  end}}
   virtual ~{{$.Name}}() {{- if $.Inherits }} override{{end}};
   {{$.Name}}();
 {{-  if $s := SetlikeOf $}}
diff --git a/src/dawn/node/test.mjs b/src/dawn/node/test.mjs
index 1c72cba..3694720d 100644
--- a/src/dawn/node/test.mjs
+++ b/src/dawn/node/test.mjs
@@ -12,6 +12,14 @@
 const dawnNodePath = join(__dirname, '..', '..', '..', 'out', 'active', 'dawn.node');
 const { create, globals } = require(dawnNodePath);
 
+// Save these before they might get replaced by the following assignment
+const globalsBeforeGlobalAssignment = {
+  DOMException,
+  EventTarget,
+  Error,
+  Event,
+};
+
 Object.assign(globalThis, globals);
 
 const assert = {
@@ -48,6 +56,14 @@
     await new Promise(r => setTimeout(r, 1000));
   })
 
+  await describe('global tests', async () => {
+    // Check that these globals were not replaced when we added dawn.node's globals
+    assert.ok(() => globalsBeforeGlobalAssignment.EventTarget === EventTarget);
+    assert.ok(() => globalsBeforeGlobalAssignment.Event === Event);
+    assert.ok(() => globalsBeforeGlobalAssignment.Error === Error);
+    assert.ok(() => globalsBeforeGlobalAssignment.DOMException === DOMException);
+  });
+
   await describe('device tests', async () => {
 
     await it('basic device tests', () => {