From 79c46d470daa8e3c55707da4f20688acced7b81f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= <gabrielopcode@gmail.com>
Date: Mon, 25 Jul 2022 21:54:04 +0300
Subject: [PATCH] mshtml: Use a table to construct the different event types by
 their interface.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Avoids hardcoding as the amount of events grows to become more manageable,
which will also be used for the existing hardcoded "special" events (UI,
Mouse, Keyboard).

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
---
 dlls/mshtml/htmlevent.c | 125 ++++++++++++++++++++++++----------------
 dlls/mshtml/nsiface.idl |  14 +++++
 2 files changed, 88 insertions(+), 51 deletions(-)

diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 0f6525af86a..f5e889712c0 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -2299,6 +2299,7 @@ static void DOMMessageEvent_destroy(DOMEvent *event)
 typedef struct {
     DOMEvent event;
     IDOMProgressEvent IDOMProgressEvent_iface;
+    nsIDOMProgressEvent *nsevent;
 } DOMProgressEvent;
 
 static inline DOMProgressEvent *impl_from_IDOMProgressEvent(IDOMProgressEvent *iface)
@@ -2412,6 +2413,12 @@ static void *DOMProgressEvent_query_interface(DOMEvent *event, REFIID riid)
     return NULL;
 }
 
+static void DOMProgressEvent_destroy(DOMEvent *event)
+{
+    DOMProgressEvent *This = DOMProgressEvent_from_DOMEvent(event);
+    nsIDOMProgressEvent_Release(This->nsevent);
+}
+
 static const tid_t DOMEvent_iface_tids[] = {
     IDOMEvent_tid,
     0
@@ -2504,64 +2511,20 @@ dispex_static_data_t DOMProgressEvent_dispex = {
     DOMProgressEvent_iface_tids
 };
 
-static BOOL check_event_iface(nsIDOMEvent *event, REFIID riid)
-{
-    nsISupports *iface;
-    nsresult nsres;
-
-    nsres = nsIDOMEvent_QueryInterface(event, riid, (void**)&iface);
-    if(NS_FAILED(nsres))
-        return FALSE;
-
-    nsISupports_Release(iface);
-    return TRUE;
-}
-
-static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id)
+static void *event_ctor(unsigned size, dispex_static_data_t *dispex_data, void *(*query_interface)(DOMEvent*,REFIID),
+        void (*destroy)(DOMEvent*), nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode)
 {
-    dispex_static_data_t *dispex_data = &DOMEvent_dispex;
-    DOMEvent *event = NULL;
+    DOMEvent *event = heap_alloc_zero(size);
     nsresult nsres;
 
-    if(check_event_iface(nsevent, &IID_nsIDOMCustomEvent)) {
-        DOMCustomEvent *custom_event = heap_alloc_zero(sizeof(*custom_event));
-        if(!custom_event)
-            return NULL;
-
-        custom_event->IDOMCustomEvent_iface.lpVtbl = &DOMCustomEventVtbl;
-        custom_event->event.query_interface = DOMCustomEvent_query_interface;
-        custom_event->event.destroy = DOMCustomEvent_destroy;
-        event = &custom_event->event;
-        dispex_data = &DOMCustomEvent_dispex;
-    }else if(event_id == EVENTID_MESSAGE) {
-        DOMMessageEvent *message_event = heap_alloc_zero(sizeof(*message_event));
-        if(!message_event)
-            return NULL;
-
-        message_event->IDOMMessageEvent_iface.lpVtbl = &DOMMessageEventVtbl;
-        message_event->event.query_interface = DOMMessageEvent_query_interface;
-        message_event->event.destroy = DOMMessageEvent_destroy;
-        event = &message_event->event;
-        dispex_data = &DOMMessageEvent_dispex;
-    }else if(event_info[event_id].type == EVENT_TYPE_PROGRESS && compat_mode >= COMPAT_MODE_IE10) {
-        DOMProgressEvent *progress_event = heap_alloc_zero(sizeof(*progress_event));
-        if(!progress_event)
-            return NULL;
-
-        progress_event->IDOMProgressEvent_iface.lpVtbl = &DOMProgressEventVtbl;
-        progress_event->event.query_interface = DOMProgressEvent_query_interface;
-        event = &progress_event->event;
-        dispex_data = &DOMProgressEvent_dispex;
-    }else {
-        event = heap_alloc_zero(sizeof(*event));
-        if(!event)
-            return NULL;
-    }
-
+    if(!event)
+        return NULL;
     event->IDOMEvent_iface.lpVtbl = &DOMEventVtbl;
     event->IDOMUIEvent_iface.lpVtbl = &DOMUIEventVtbl;
     event->IDOMMouseEvent_iface.lpVtbl = &DOMMouseEventVtbl;
     event->IDOMKeyboardEvent_iface.lpVtbl = &DOMKeyboardEventVtbl;
+    event->query_interface = query_interface;
+    event->destroy = destroy;
     event->ref = 1;
     event->event_id = event_id;
     if(event_id != EVENTID_LAST) {
@@ -2599,6 +2562,66 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev
     return event;
 }
 
+static DOMEvent *custom_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode)
+{
+    DOMCustomEvent *custom_event = event_ctor(sizeof(DOMCustomEvent), &DOMCustomEvent_dispex,
+            DOMCustomEvent_query_interface, DOMCustomEvent_destroy, nsevent, event_id, compat_mode);
+    if(!custom_event) return NULL;
+    custom_event->IDOMCustomEvent_iface.lpVtbl = &DOMCustomEventVtbl;
+    nsIDOMCustomEvent_Release(iface);
+    return &custom_event->event;
+}
+
+static DOMEvent *progress_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode)
+{
+    DOMProgressEvent *progress_event;
+
+    if(compat_mode < COMPAT_MODE_IE10)
+        return event_ctor(sizeof(DOMEvent), &DOMEvent_dispex, NULL, NULL, nsevent, event_id, compat_mode);
+
+    if(!(progress_event = event_ctor(sizeof(DOMProgressEvent), &DOMProgressEvent_dispex,
+            DOMProgressEvent_query_interface, DOMProgressEvent_destroy, nsevent, event_id, compat_mode)))
+        return NULL;
+    progress_event->IDOMProgressEvent_iface.lpVtbl = &DOMProgressEventVtbl;
+    progress_event->nsevent = iface;
+    return &progress_event->event;
+}
+
+static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id)
+{
+    static const struct {
+        REFIID iid;
+        DOMEvent *(*ctor)(void *iface, nsIDOMEvent *nsevent, eventid_t, compat_mode_t);
+    } types_table[] = {
+        { &IID_nsIDOMCustomEvent,       custom_event_ctor },
+        { &IID_nsIDOMProgressEvent,     progress_event_ctor },
+    };
+    DOMEvent *event;
+    unsigned i;
+
+    if(event_id == EVENTID_MESSAGE) {
+        DOMMessageEvent *message_event = event_ctor(sizeof(DOMMessageEvent), &DOMMessageEvent_dispex,
+                DOMMessageEvent_query_interface, DOMMessageEvent_destroy, nsevent, event_id, compat_mode);
+        if(!message_event)
+            return NULL;
+        message_event->IDOMMessageEvent_iface.lpVtbl = &DOMMessageEventVtbl;
+        return &message_event->event;
+    }
+
+    for(i = 0; i < ARRAY_SIZE(types_table); i++) {
+        void *iface;
+        nsresult nsres = nsIDOMEvent_QueryInterface(nsevent, types_table[i].iid, &iface);
+        if(NS_SUCCEEDED(nsres)) {
+            /* Transfer the iface ownership to the ctor on success */
+            if(!(event = types_table[i].ctor(iface, nsevent, event_id, compat_mode)))
+                nsISupports_Release(iface);
+            return event;
+        }
+    }
+
+    return event_ctor(sizeof(DOMEvent), &DOMEvent_dispex, NULL, NULL, nsevent, event_id, compat_mode);
+}
+
 HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, compat_mode_t compat_mode, DOMEvent **ret_event)
 {
     eventid_t event_id = EVENTID_LAST;
diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl
index cad48f725c6..c4b479b16e3 100644
--- a/dlls/mshtml/nsiface.idl
+++ b/dlls/mshtml/nsiface.idl
@@ -3304,6 +3304,20 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
     nsresult GetKey(nsAString *aKey);
 }
 
+[
+    object,
+    uuid(e0682338-4c3f-4d3a-9487-d7492ea76335),
+    local
+]
+interface nsIDOMProgressEvent : nsISupports
+{
+    nsresult GetLengthComputable(bool *aLengthComputable);
+    nsresult GetLoaded(uint64_t *aLoaded);
+    nsresult GetTotal(uint64_t *aTotal);
+    nsresult InitProgressEvent(const nsAString *typeArg, bool canBubbleArg, bool cancelableArg,
+             bool lengthComputableArg, uint64_t loadedArg, uint64_t totalArg);
+}
+
 [
     object,
     uuid(5be16b03-36f9-4ca8-b2c5-0daadf3cd1b3),
-- 
GitLab