Jacek Caban : mshtml: Added support for binding XHR events.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Jul 2 07:18:06 CDT 2015


Module: wine
Branch: master
Commit: 8d85da757a7f1ab36d11078cb08ea84511190fd2
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=8d85da757a7f1ab36d11078cb08ea84511190fd2

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Jul  1 17:38:17 2015 +0200

mshtml: Added support for binding XHR events.

---

 dlls/mshtml/htmlevent.c            |   6 +-
 dlls/mshtml/htmlevent.h            |   3 +
 dlls/mshtml/tests/xmlhttprequest.c |   2 +-
 dlls/mshtml/xmlhttprequest.c       | 135 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 140 insertions(+), 6 deletions(-)

diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 254b864..ad016b9 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -256,7 +256,7 @@ static eventid_t attr_to_eid(LPCWSTR str)
     return EVENTID_LAST;
 }
 
-typedef struct {
+struct HTMLEventObj {
     DispatchEx dispex;
     IHTMLEventObj IHTMLEventObj_iface;
 
@@ -268,7 +268,7 @@ typedef struct {
     VARIANT return_value;
     BOOL prevent_default;
     BOOL cancel_bubble;
-} HTMLEventObj;
+};
 
 static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface)
 {
@@ -966,7 +966,7 @@ static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
     return FALSE;
 }
 
-static void call_event_handlers(HTMLDocumentNode *doc, HTMLEventObj *event_obj, EventTarget *event_target,
+void call_event_handlers(HTMLDocumentNode *doc, HTMLEventObj *event_obj, EventTarget *event_target,
         ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj)
 {
     event_target_t *data = get_event_target_data(event_target, FALSE);
diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h
index 4579617f..fefc749 100644
--- a/dlls/mshtml/htmlevent.h
+++ b/dlls/mshtml/htmlevent.h
@@ -67,6 +67,9 @@ HRESULT create_event_obj(IHTMLEventObj**) DECLSPEC_HIDDEN;
 void bind_target_event(HTMLDocumentNode*,EventTarget*,const WCHAR*,IDispatch*) DECLSPEC_HIDDEN;
 HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode*,eventid_t) DECLSPEC_HIDDEN;
 
+typedef struct HTMLEventObj HTMLEventObj;
+void call_event_handlers(HTMLDocumentNode*,HTMLEventObj*,EventTarget*,ConnectionPointContainer*,eventid_t,IDispatch*);
+
 void init_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN;
 void release_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN;
 void add_nsevent_listener(HTMLDocumentNode*,nsIDOMNode*,LPCWSTR) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c
index cf5f674..d3f682c 100644
--- a/dlls/mshtml/tests/xmlhttprequest.c
+++ b/dlls/mshtml/tests/xmlhttprequest.c
@@ -504,7 +504,7 @@ static void test_async_xhr(IHTMLDocument2 *doc, const char *xml_url)
     SET_EXPECT(xmlhttprequest_onreadystatechange_opened);
     hres = IHTMLXMLHttpRequest_open(xhr, method, url, vbool, vempty, vempty);
     ok(hres == S_OK, "open failed: %08x\n", hres);
-    todo_wine CHECK_CALLED(xmlhttprequest_onreadystatechange_opened);
+    CHECK_CALLED(xmlhttprequest_onreadystatechange_opened);
 
     SysFreeString(method);
     SysFreeString(url);
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c
index 6f417a5..1432b2c 100644
--- a/dlls/mshtml/xmlhttprequest.c
+++ b/dlls/mshtml/xmlhttprequest.c
@@ -60,14 +60,117 @@ static HRESULT variant_to_nsastr(VARIANT var, nsAString *ret)
     }
 }
 
-/* IHTMLXMLHttpRequest */
+typedef struct XMLHttpReqEventListener XMLHttpReqEventListener;
+
 typedef struct {
     EventTarget event_target;
     IHTMLXMLHttpRequest IHTMLXMLHttpRequest_iface;
     LONG ref;
     nsIXMLHttpRequest *nsxhr;
+    XMLHttpReqEventListener *event_listener;
 } HTMLXMLHttpRequest;
 
+struct XMLHttpReqEventListener {
+    nsIDOMEventListener nsIDOMEventListener_iface;
+    LONG ref;
+    HTMLXMLHttpRequest *xhr;
+};
+
+static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener)
+{
+    nsIDOMEventTarget *event_target;
+    nsAString str;
+    nsresult nsres;
+
+    static const WCHAR readystatechangeW[] =
+        {'o','n','r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
+
+    nsres = nsIXMLHttpRequest_QueryInterface(event_listener->xhr->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target);
+    assert(nsres == NS_OK);
+
+    nsAString_InitDepend(&str, readystatechangeW);
+    nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE);
+    nsAString_Finish(&str);
+    nsIDOMEventTarget_Release(event_target);
+
+    event_listener->xhr->event_listener = NULL;
+    event_listener->xhr = NULL;
+    nsIDOMEventListener_Release(&event_listener->nsIDOMEventListener_iface);
+}
+
+
+static inline XMLHttpReqEventListener *impl_from_nsIDOMEventListener(nsIDOMEventListener *iface)
+{
+    return CONTAINING_RECORD(iface, XMLHttpReqEventListener, nsIDOMEventListener_iface);
+}
+
+static nsresult NSAPI XMLHttpReqEventListener_QueryInterface(nsIDOMEventListener *iface,
+        nsIIDRef riid, void **result)
+{
+    XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
+
+    if(IsEqualGUID(&IID_nsISupports, riid)) {
+        TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
+        *result = &This->nsIDOMEventListener_iface;
+    }else if(IsEqualGUID(&IID_nsIDOMEventListener, riid)) {
+        TRACE("(%p)->(IID_nsIDOMEventListener %p)\n", This, result);
+        *result = &This->nsIDOMEventListener_iface;
+    }else {
+        *result = NULL;
+        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
+        return NS_NOINTERFACE;
+    }
+
+    nsIDOMEventListener_AddRef(&This->nsIDOMEventListener_iface);
+    return NS_OK;
+}
+
+static nsrefcnt NSAPI XMLHttpReqEventListener_AddRef(nsIDOMEventListener *iface)
+{
+    XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    return ref;
+}
+
+static nsrefcnt NSAPI XMLHttpReqEventListener_Release(nsIDOMEventListener *iface)
+{
+    XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    if(!ref) {
+        assert(!This->xhr);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static nsresult NSAPI XMLHttpReqEventListener_HandleEvent(nsIDOMEventListener *iface, nsIDOMEvent *event)
+{
+    XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
+
+    TRACE("(%p)\n", This);
+
+    if(!This->xhr)
+        return NS_OK;
+
+    call_event_handlers(NULL, NULL, &This->xhr->event_target, NULL, EVENTID_READYSTATECHANGE,
+            (IDispatch*)&This->xhr->IHTMLXMLHttpRequest_iface);
+    return NS_OK;
+}
+
+static const nsIDOMEventListenerVtbl XMLHttpReqEventListenerVtbl = {
+    XMLHttpReqEventListener_QueryInterface,
+    XMLHttpReqEventListener_AddRef,
+    XMLHttpReqEventListener_Release,
+    XMLHttpReqEventListener_HandleEvent
+};
+
 static inline HTMLXMLHttpRequest *impl_from_IHTMLXMLHttpRequest(IHTMLXMLHttpRequest *iface)
 {
     return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IHTMLXMLHttpRequest_iface);
@@ -115,6 +218,8 @@ static ULONG WINAPI HTMLXMLHttpRequest_Release(IHTMLXMLHttpRequest *iface)
     TRACE("(%p) ref=%d\n", This, ref);
 
     if(!ref) {
+        if(This->event_listener)
+            detach_xhr_event_listener(This->event_listener);
         release_dispex(&This->event_target.dispex);
         nsIXMLHttpRequest_Release(This->nsxhr);
         heap_free(This);
@@ -357,10 +462,36 @@ static inline HTMLXMLHttpRequest *impl_from_DispatchEx(DispatchEx *iface)
 static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, int eid)
 {
     HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
+    nsIDOMEventTarget *nstarget;
+    nsAString type_str;
+    nsresult nsres;
+
+    static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
 
-    FIXME("(%p)\n", This);
+    TRACE("(%p)\n", This);
 
     assert(eid == EVENTID_READYSTATECHANGE);
+
+    if(This->event_listener)
+        return;
+
+    This->event_listener = heap_alloc(sizeof(*This->event_listener));
+    if(!This->event_listener)
+        return;
+
+    This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl;
+    This->event_listener->ref = 1;
+    This->event_listener->xhr = This;
+
+    nsres = nsIXMLHttpRequest_QueryInterface(This->nsxhr, &IID_nsIDOMEventTarget, (void**)&nstarget);
+    assert(nsres == NS_OK);
+
+    nsAString_InitDepend(&type_str, readystatechangeW);
+    nsres = nsIDOMEventTarget_AddEventListener(nstarget, &type_str, &This->event_listener->nsIDOMEventListener_iface, FALSE, TRUE, 2);
+    nsAString_Finish(&type_str);
+    nsIDOMEventTarget_Release(nstarget);
+    if(NS_FAILED(nsres))
+        ERR("AddEventListener failed: %08x\n", nsres);
 }
 
 static dispex_static_data_vtbl_t HTMLXMLHttpRequest_dispex_vtbl = {




More information about the wine-cvs mailing list