Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 2 + dlls/mshtml/tests/xmlhttprequest.c | 36 +++++++++ dlls/mshtml/xmlhttprequest.c | 116 +++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 930ab3b..5574272 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -265,6 +265,7 @@ typedef struct EventTarget EventTarget; XIID(IHTMLWindow6) \ XIID(IHTMLWindow7) \ XIID(IHTMLXMLHttpRequest) \ + XIID(IHTMLXMLHttpRequest2) \ XIID(IHTMLXMLHttpRequestFactory) \ XIID(IOmHistory) \ XIID(IOmNavigator) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5f10447..8503523 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -397,6 +397,8 @@ sync_test("xhr_props", function() { test_exposed("addEventListener", v >= 9); test_exposed("removeEventListener", v >= 9); test_exposed("dispatchEvent", v >= 9); + test_exposed("ontimeout", true); + test_exposed("timeout", true); });
sync_test("stylesheet_props", function() { diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 868035d..6aef9f5 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -1007,6 +1007,41 @@ static void test_xhr_post(IHTMLDocument2 *doc) xhr = NULL; }
+static void test_timeout(IHTMLDocument2 *doc) +{ + IHTMLXMLHttpRequest2 *xhr2; + LONG timeout; + HRESULT hres; + + create_xmlhttprequest(doc); + if(!xhr) + return; + + hres = IHTMLXMLHttpRequest_QueryInterface(xhr, &IID_IHTMLXMLHttpRequest2, (void**)&xhr2); + ok(hres == S_OK, "QueryInterface(IHTMLXMLHttpRequest2) failed: %08lx\n", hres); + + hres = IHTMLXMLHttpRequest2_get_timeout(xhr2, NULL); + ok(hres == E_POINTER, "get_timeout returned %08lx\n", hres); + hres = IHTMLXMLHttpRequest2_get_timeout(xhr2, &timeout); + ok(hres == S_OK, "get_timeout returned %08lx\n", hres); + ok(timeout == 0, "timeout = %ld\n", timeout); + + /* Some Windows versions only allow setting timeout after open() */ + xhr_open(L"http://test.winehq.org/tests/post.php", L"POST", TRUE); + IHTMLXMLHttpRequest_Release(xhr); + xhr = NULL; + + hres = IHTMLXMLHttpRequest2_put_timeout(xhr2, -1); + ok(hres == E_INVALIDARG || broken(hres == E_FAIL), "put_timeout returned %08lx\n", hres); + hres = IHTMLXMLHttpRequest2_put_timeout(xhr2, 1337); + ok(hres == S_OK, "put_timeout returned %08lx\n", hres); + hres = IHTMLXMLHttpRequest2_get_timeout(xhr2, &timeout); + ok(hres == S_OK, "get_timeout returned %08lx\n", hres); + ok(timeout == 1337, "timeout = %ld\n", timeout); + + IHTMLXMLHttpRequest2_Release(xhr2); +} + static IHTMLDocument2 *create_doc_from_url(const WCHAR *start_url) { BSTR url; @@ -1071,6 +1106,7 @@ START_TEST(xmlhttprequest) test_async_xhr(doc, large_page_url, NULL); test_async_xhr_abort(doc, large_page_url); test_xhr_post(doc); + test_timeout(doc); IHTMLDocument2_Release(doc); } SysFreeString(content_type); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 1721959..066b94b 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -105,6 +105,7 @@ typedef struct { struct HTMLXMLHttpRequest { EventTarget event_target; IHTMLXMLHttpRequest IHTMLXMLHttpRequest_iface; + IHTMLXMLHttpRequest2 IHTMLXMLHttpRequest2_iface; IProvideClassInfo2 IProvideClassInfo2_iface; LONG ref; nsIXMLHttpRequest *nsxhr; @@ -236,6 +237,8 @@ static HRESULT WINAPI HTMLXMLHttpRequest_QueryInterface(IHTMLXMLHttpRequest *ifa *ppv = &This->IHTMLXMLHttpRequest_iface; }else if(IsEqualGUID(&IID_IHTMLXMLHttpRequest, riid)) { *ppv = &This->IHTMLXMLHttpRequest_iface; + }else if(IsEqualGUID(&IID_IHTMLXMLHttpRequest2, riid)) { + *ppv = &This->IHTMLXMLHttpRequest2_iface; }else if(IsEqualGUID(&IID_IProvideClassInfo, riid)) { *ppv = &This->IProvideClassInfo2_iface; }else if(IsEqualGUID(&IID_IProvideClassInfo2, riid)) { @@ -726,6 +729,117 @@ static const IHTMLXMLHttpRequestVtbl HTMLXMLHttpRequestVtbl = { HTMLXMLHttpRequest_setRequestHeader };
+static inline HTMLXMLHttpRequest *impl_from_IHTMLXMLHttpRequest2(IHTMLXMLHttpRequest2 *iface) +{ + return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IHTMLXMLHttpRequest2_iface); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_QueryInterface(IHTMLXMLHttpRequest2 *iface, REFIID riid, void **ppv) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IHTMLXMLHttpRequest_QueryInterface(&This->IHTMLXMLHttpRequest_iface, riid, ppv); +} + +static ULONG WINAPI HTMLXMLHttpRequest2_AddRef(IHTMLXMLHttpRequest2 *iface) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IHTMLXMLHttpRequest_AddRef(&This->IHTMLXMLHttpRequest_iface); +} + +static ULONG WINAPI HTMLXMLHttpRequest2_Release(IHTMLXMLHttpRequest2 *iface) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IHTMLXMLHttpRequest_Release(&This->IHTMLXMLHttpRequest_iface); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_GetTypeInfoCount(IHTMLXMLHttpRequest2 *iface, UINT *pctinfo) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IDispatchEx_GetTypeInfoCount(&This->event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_GetTypeInfo(IHTMLXMLHttpRequest2 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IDispatchEx_GetTypeInfo(&This->event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_GetIDsOfNames(IHTMLXMLHttpRequest2 *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IDispatchEx_GetIDsOfNames(&This->event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_Invoke(IHTMLXMLHttpRequest2 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + return IDispatchEx_Invoke(&This->event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_put_timeout(IHTMLXMLHttpRequest2 *iface, LONG v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + + TRACE("(%p)->(%ld)\n", This, v); + + if(v < 0) + return E_INVALIDARG; + return map_nsresult(nsIXMLHttpRequest_SetTimeout(This->nsxhr, v)); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_get_timeout(IHTMLXMLHttpRequest2 *iface, LONG *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + nsresult nsres; + UINT32 timeout; + + TRACE("(%p)->(%p)\n", This, p); + + if(!p) + return E_POINTER; + + nsres = nsIXMLHttpRequest_GetTimeout(This->nsxhr, &timeout); + *p = timeout; + return map_nsresult(nsres); +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_put_ontimeout(IHTMLXMLHttpRequest2 *iface, VARIANT v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXMLHttpRequest2_get_ontimeout(IHTMLXMLHttpRequest2 *iface, VARIANT *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static const IHTMLXMLHttpRequest2Vtbl HTMLXMLHttpRequest2Vtbl = { + HTMLXMLHttpRequest2_QueryInterface, + HTMLXMLHttpRequest2_AddRef, + HTMLXMLHttpRequest2_Release, + HTMLXMLHttpRequest2_GetTypeInfoCount, + HTMLXMLHttpRequest2_GetTypeInfo, + HTMLXMLHttpRequest2_GetIDsOfNames, + HTMLXMLHttpRequest2_Invoke, + HTMLXMLHttpRequest2_put_timeout, + HTMLXMLHttpRequest2_get_timeout, + HTMLXMLHttpRequest2_put_ontimeout, + HTMLXMLHttpRequest2_get_ontimeout +}; + static inline HTMLXMLHttpRequest *impl_from_IProvideClassInfo2(IProvideClassInfo2 *iface) { return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IProvideClassInfo2_iface); @@ -895,6 +1009,7 @@ static event_target_vtbl_t HTMLXMLHttpRequest_event_target_vtbl = { };
static const tid_t HTMLXMLHttpRequest_iface_tids[] = { + IHTMLXMLHttpRequest2_tid, 0 }; static dispex_static_data_t HTMLXMLHttpRequest_dispex = { @@ -1013,6 +1128,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor ret->nsxhr = nsxhr;
ret->IHTMLXMLHttpRequest_iface.lpVtbl = &HTMLXMLHttpRequestVtbl; + ret->IHTMLXMLHttpRequest2_iface.lpVtbl = &HTMLXMLHttpRequest2Vtbl; ret->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl; EventTarget_Init(&ret->event_target, (IUnknown*)&ret->IHTMLXMLHttpRequest_iface, &HTMLXMLHttpRequest_dispex, This->window->doc->document_mode);
Since they're already sorted (except for DOMContentLoaded because of case sensitivity).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 27 ++++++++++++++++++--------- dlls/mshtml/htmlevent.h | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index fe34336..f28dd63 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -105,7 +105,10 @@ typedef struct { #define EVENT_MOUSE_TO_RELATED 0x0100 #define EVENT_MOUSE_FROM_RELATED 0x0200
+/* Keep these sorted case sensitively */ static const event_info_t event_info[] = { + {L"DOMContentLoaded", EVENT_TYPE_EVENT, 0, + EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"abort", EVENT_TYPE_EVENT, DISPID_EVMETH_ONABORT, EVENT_BIND_TO_TARGET}, {L"animationend", EVENT_TYPE_EVENT, DISPID_EVPROP_ONANIMATIONEND, @@ -128,8 +131,6 @@ static const event_info_t event_info[] = { EVENT_FIXME | EVENT_BUBBLES}, {L"dblclick", EVENT_TYPE_MOUSE, DISPID_EVMETH_ONDBLCLICK, EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE}, - {L"DOMContentLoaded", EVENT_TYPE_EVENT, 0, - EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"drag", EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAG, EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"dragstart", EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAGSTART, @@ -192,11 +193,15 @@ C_ASSERT(ARRAY_SIZE(event_info) == EVENTID_LAST);
static eventid_t str_to_eid(const WCHAR *str) { - int i; + unsigned i, a = 0, b = ARRAY_SIZE(event_info); + int c;
- for(i=0; i < ARRAY_SIZE(event_info); i++) { - if(!wcscmp(event_info[i].name, str)) + while(a < b) { + i = (a + b) / 2; + if(!(c = wcscmp(event_info[i].name, str))) return i; + if(c > 0) b = i; + else a = i + 1; }
return EVENTID_LAST; @@ -204,14 +209,18 @@ static eventid_t str_to_eid(const WCHAR *str)
static eventid_t attr_to_eid(const WCHAR *str) { - int i; + unsigned i, a = 0, b = ARRAY_SIZE(event_info); + int c;
if((str[0] != 'o' && str[0] != 'O') || (str[1] != 'n' && str[1] != 'N')) return EVENTID_LAST;
- for(i=0; i < ARRAY_SIZE(event_info); i++) { - if(!wcscmp(event_info[i].name, str+2) && event_info[i].dispid) - return i; + while(a < b) { + i = (a + b) / 2; + if(!(c = wcscmp(event_info[i].name, str+2))) + return event_info[i].dispid ? i : EVENTID_LAST; + if(c > 0) b = i; + else a = i + 1; }
return EVENTID_LAST; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 7f62bd6..5d53451 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -17,6 +17,7 @@ */
typedef enum { + EVENTID_DOMCONTENTLOADED, EVENTID_ABORT, EVENTID_ANIMATIONEND, EVENTID_ANIMATIONSTART, @@ -28,7 +29,6 @@ typedef enum { EVENTID_CONTEXTMENU, EVENTID_DATAAVAILABLE, EVENTID_DBLCLICK, - EVENTID_DOMCONTENTLOADED, EVENTID_DRAG, EVENTID_DRAGSTART, EVENTID_ERROR,
Signed-off-by: Jacek Caban jacek@codeweavers.com
Instead of hardcoding each event, since there will be plenty more.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 5 ++++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/xmlhttprequest.c | 51 ++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 29 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f28dd63..92fa489 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -226,6 +226,11 @@ static eventid_t attr_to_eid(const WCHAR *str) return EVENTID_LAST; }
+const WCHAR *get_event_name(eventid_t eid) +{ + return event_info[eid].name; +} + static listener_container_t *get_listener_container(EventTarget *event_target, const WCHAR *type, BOOL alloc) { const event_target_vtbl_t *vtbl; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 5d53451..d49b06d 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -93,6 +93,7 @@ typedef struct DOMEvent { BOOL no_event_obj; } DOMEvent;
+const WCHAR *get_event_name(eventid_t) DECLSPEC_HIDDEN; void check_event_attr(HTMLDocumentNode*,nsIDOMElement*) DECLSPEC_HIDDEN; void release_event_target(EventTarget*) DECLSPEC_HIDDEN; HRESULT set_event_handler(EventTarget*,eventid_t,VARIANT*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 066b94b..c9f7149 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -94,12 +94,16 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) return S_OK; }
+static const eventid_t events[] = { + EVENTID_READYSTATECHANGE, + EVENTID_LOAD, +}; + typedef struct { nsIDOMEventListener nsIDOMEventListener_iface; LONG ref; HTMLXMLHttpRequest *xhr; - BOOL readystatechange_event; - BOOL load_event; + DWORD events_mask; } XMLHttpReqEventListener;
struct HTMLXMLHttpRequest { @@ -115,21 +119,17 @@ struct HTMLXMLHttpRequest { static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) { nsIDOMEventTarget *event_target; + DWORD events_mask, i; nsAString str; nsresult nsres;
nsres = nsIXMLHttpRequest_QueryInterface(event_listener->xhr->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target); assert(nsres == NS_OK);
- if(event_listener->readystatechange_event) { - nsAString_InitDepend(&str, L"onreadystatechange"); - nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE); - nsAString_Finish(&str); - assert(nsres == NS_OK); - } - - if(event_listener->load_event) { - nsAString_InitDepend(&str, L"load"); + for(events_mask = event_listener->events_mask, i = 0; events_mask; events_mask >>= 1, i++) { + if(!(events_mask & 1)) + continue; + nsAString_InitDepend(&str, get_event_name(events[i])); nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE); nsAString_Finish(&str); assert(nsres == NS_OK); @@ -941,22 +941,18 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) { HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex); nsIDOMEventTarget *nstarget; - const WCHAR *type_name; nsAString type_str; + const WCHAR *name; nsresult nsres; + unsigned i;
TRACE("(%p)\n", This);
- switch(eid) { - case EVENTID_READYSTATECHANGE: - type_name = L"readystatechange"; - break; - case EVENTID_LOAD: - type_name = L"load"; - break; - default: + for(i = 0; i < ARRAY_SIZE(events); i++) + if(eid == events[i]) + break; + if(i >= ARRAY_SIZE(events)) return; - }
if(!This->event_listener) { This->event_listener = heap_alloc(sizeof(*This->event_listener)); @@ -966,25 +962,22 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl; This->event_listener->ref = 1; This->event_listener->xhr = This; - This->event_listener->readystatechange_event = FALSE; - This->event_listener->load_event = FALSE; + This->event_listener->events_mask = 0; }
nsres = nsIXMLHttpRequest_QueryInterface(This->nsxhr, &IID_nsIDOMEventTarget, (void**)&nstarget); assert(nsres == NS_OK);
- nsAString_InitDepend(&type_str, type_name); + name = get_event_name(events[i]); + nsAString_InitDepend(&type_str, name); nsres = nsIDOMEventTarget_AddEventListener(nstarget, &type_str, &This->event_listener->nsIDOMEventListener_iface, FALSE, TRUE, 2); nsAString_Finish(&type_str); if(NS_FAILED(nsres)) - ERR("AddEventListener(%s) failed: %08lx\n", debugstr_w(type_name), nsres); + ERR("AddEventListener(%s) failed: %08lx\n", debugstr_w(name), nsres);
nsIDOMEventTarget_Release(nstarget);
- if(eid == EVENTID_READYSTATECHANGE) - This->event_listener->readystatechange_event = TRUE; - else - This->event_listener->load_event = TRUE; + This->event_listener->events_mask |= 1 << i; }
static void HTMLXMLHttpRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode)
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 142 +++++++++++++++++++++++++++++++++++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/tests/script.c | 69 ++++++++++++----- dlls/mshtml/tests/xhr.js | 35 ++++++++- dlls/mshtml/xmlhttprequest.c | 9 ++- 6 files changed, 236 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 92fa489..49392bf 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -67,6 +67,7 @@ typedef enum { EVENT_TYPE_FOCUS, EVENT_TYPE_DRAG, EVENT_TYPE_MESSAGE, + EVENT_TYPE_PROGRESS, EVENT_TYPE_CLIPBOARD } event_type_t;
@@ -78,6 +79,7 @@ static const WCHAR *event_types[] = { L"Event", /* FIXME */ L"Event", /* FIXME */ L"Event", /* FIXME */ + L"ProgressEvent", L"Event" /* FIXME */ };
@@ -185,6 +187,8 @@ static const event_info_t event_info[] = { EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"submit", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSUBMIT, EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE}, + {L"timeout", EVENT_TYPE_PROGRESS, DISPID_EVPROP_TIMEOUT, + EVENT_BIND_TO_TARGET}, {L"unload", EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD, EVENT_FIXME} }; @@ -2286,6 +2290,122 @@ static void DOMMessageEvent_destroy(DOMEvent *event) heap_free(message_event->data); }
+typedef struct { + DOMEvent event; + IDOMProgressEvent IDOMProgressEvent_iface; +} DOMProgressEvent; + +static inline DOMProgressEvent *impl_from_IDOMProgressEvent(IDOMProgressEvent *iface) +{ + return CONTAINING_RECORD(iface, DOMProgressEvent, IDOMProgressEvent_iface); +} + +static HRESULT WINAPI DOMProgressEvent_QueryInterface(IDOMProgressEvent *iface, REFIID riid, void **ppv) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDOMEvent_QueryInterface(&This->event.IDOMEvent_iface, riid, ppv); +} + +static ULONG WINAPI DOMProgressEvent_AddRef(IDOMProgressEvent *iface) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDOMEvent_AddRef(&This->event.IDOMEvent_iface); +} + +static ULONG WINAPI DOMProgressEvent_Release(IDOMProgressEvent *iface) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDOMEvent_Release(&This->event.IDOMEvent_iface); +} + +static HRESULT WINAPI DOMProgressEvent_GetTypeInfoCount(IDOMProgressEvent *iface, UINT *pctinfo) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDispatchEx_GetTypeInfoCount(&This->event.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI DOMProgressEvent_GetTypeInfo(IDOMProgressEvent *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDispatchEx_GetTypeInfo(&This->event.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI DOMProgressEvent_GetIDsOfNames(IDOMProgressEvent *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDispatchEx_GetIDsOfNames(&This->event.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI DOMProgressEvent_Invoke(IDOMProgressEvent *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + return IDispatchEx_Invoke(&This->event.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI DOMProgressEvent_get_lengthComputable(IDOMProgressEvent *iface, VARIANT_BOOL *p) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMProgressEvent_get_loaded(IDOMProgressEvent *iface, ULONGLONG *p) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMProgressEvent_get_total(IDOMProgressEvent *iface, ULONGLONG *p) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMProgressEvent_initProgressEvent(IDOMProgressEvent *iface, BSTR type, VARIANT_BOOL can_bubble, + VARIANT_BOOL cancelable, VARIANT_BOOL lengthComputable, + ULONGLONG loaded, ULONGLONG total) +{ + DOMProgressEvent *This = impl_from_IDOMProgressEvent(iface); + FIXME("(%p)->(%s %x %x %x %s %s)\n", This, debugstr_w(type), can_bubble, cancelable, lengthComputable, + wine_dbgstr_longlong(loaded), wine_dbgstr_longlong(total)); + return E_NOTIMPL; +} + +static const IDOMProgressEventVtbl DOMProgressEventVtbl = { + DOMProgressEvent_QueryInterface, + DOMProgressEvent_AddRef, + DOMProgressEvent_Release, + DOMProgressEvent_GetTypeInfoCount, + DOMProgressEvent_GetTypeInfo, + DOMProgressEvent_GetIDsOfNames, + DOMProgressEvent_Invoke, + DOMProgressEvent_get_lengthComputable, + DOMProgressEvent_get_loaded, + DOMProgressEvent_get_total, + DOMProgressEvent_initProgressEvent +}; + +static DOMProgressEvent *DOMProgressEvent_from_DOMEvent(DOMEvent *event) +{ + return CONTAINING_RECORD(event, DOMProgressEvent, event); +} + +static void *DOMProgressEvent_query_interface(DOMEvent *event, REFIID riid) +{ + DOMProgressEvent *This = DOMProgressEvent_from_DOMEvent(event); + if(IsEqualGUID(&IID_IDOMProgressEvent, riid)) + return &This->IDOMProgressEvent_iface; + return NULL; +} + static const tid_t DOMEvent_iface_tids[] = { IDOMEvent_tid, 0 @@ -2365,6 +2485,19 @@ dispex_static_data_t DOMMessageEvent_dispex = { DOMMessageEvent_iface_tids };
+static const tid_t DOMProgressEvent_iface_tids[] = { + IDOMEvent_tid, + IDOMProgressEvent_tid, + 0 +}; + +dispex_static_data_t DOMProgressEvent_dispex = { + L"ProgressEvent", + NULL, + DispDOMProgressEvent_tid, + DOMProgressEvent_iface_tids +}; + static BOOL check_event_iface(nsIDOMEvent *event, REFIID riid) { nsISupports *iface; @@ -2404,6 +2537,15 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev 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) diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index d49b06d..58dbc43 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -56,6 +56,7 @@ typedef enum { EVENTID_SELECTIONCHANGE, EVENTID_SELECTSTART, EVENTID_SUBMIT, + EVENTID_TIMEOUT, EVENTID_UNLOAD, EVENTID_LAST } eventid_t; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5574272..ad1fca0 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -89,6 +89,7 @@ typedef struct EventTarget EventTarget; XDIID(DispDOMKeyboardEvent) \ XDIID(DispDOMMessageEvent) \ XDIID(DispDOMMouseEvent) \ + XDIID(DispDOMProgressEvent) \ XDIID(DispDOMUIEvent) \ XDIID(DispHTMLAnchorElement) \ XDIID(DispHTMLAreaElement) \ @@ -150,6 +151,7 @@ typedef struct EventTarget EventTarget; XIID(IDOMKeyboardEvent) \ XIID(IDOMMessageEvent) \ XIID(IDOMMouseEvent) \ + XIID(IDOMProgressEvent) \ XIID(IDOMUIEvent) \ XIID(IDocumentEvent) \ XIID(IDocumentRange) \ diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index da31c4d..401e130 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -3046,11 +3046,23 @@ typedef struct { IStream *stream; char *data; ULONG size; + LONG delay; char *ptr;
IUri *uri; } ProtocolHandler;
+static DWORD WINAPI delay_proc(void *arg) +{ + PROTOCOLDATA protocol_data = {PI_FORCE_ASYNC}; + ProtocolHandler *protocol_handler = arg; + + Sleep(protocol_handler->delay); + protocol_handler->delay = -1; + IInternetProtocolSink_Switch(protocol_handler->sink, &protocol_data); + return 0; +} + static void report_data(ProtocolHandler *This) { IServiceProvider *service_provider; @@ -3061,27 +3073,36 @@ static void report_data(ProtocolHandler *This)
static const WCHAR emptyW[] = {0};
- hres = IInternetProtocolSink_QueryInterface(This->sink, &IID_IServiceProvider, (void**)&service_provider); - ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + if(This->delay >= 0) { + hres = IInternetProtocolSink_QueryInterface(This->sink, &IID_IServiceProvider, (void**)&service_provider); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres);
- hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, &IID_IHttpNegotiate, (void**)&http_negotiate); - IServiceProvider_Release(service_provider); - ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08lx\n", hres); + hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, &IID_IHttpNegotiate, (void**)&http_negotiate); + IServiceProvider_Release(service_provider); + ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08lx\n", hres);
- hres = IUri_GetDisplayUri(This->uri, &url); - ok(hres == S_OK, "Failed to get display uri: %08lx\n", hres); - hres = IHttpNegotiate_BeginningTransaction(http_negotiate, url, emptyW, 0, &addl_headers); - ok(hres == S_OK, "BeginningTransaction failed: %08lx\n", hres); - SysFreeString(url); + hres = IUri_GetDisplayUri(This->uri, &url); + ok(hres == S_OK, "Failed to get display uri: %08lx\n", hres); + hres = IHttpNegotiate_BeginningTransaction(http_negotiate, url, emptyW, 0, &addl_headers); + ok(hres == S_OK, "BeginningTransaction failed: %08lx\n", hres); + SysFreeString(url);
- CoTaskMemFree(addl_headers); + CoTaskMemFree(addl_headers);
- headers = SysAllocString(L"HTTP/1.1 200 OK\r\n\r\n"); - hres = IHttpNegotiate_OnResponse(http_negotiate, 200, headers, NULL, NULL); - ok(hres == S_OK, "OnResponse failed: %08lx\n", hres); - SysFreeString(headers); + headers = SysAllocString(L"HTTP/1.1 200 OK\r\n\r\n"); + hres = IHttpNegotiate_OnResponse(http_negotiate, 200, headers, NULL, NULL); + ok(hres == S_OK, "OnResponse failed: %08lx\n", hres); + SysFreeString(headers);
- IHttpNegotiate_Release(http_negotiate); + IHttpNegotiate_Release(http_negotiate); + + if(This->delay) { + IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); + QueueUserWorkItem(delay_proc, This, 0); + return; + } + } + This->delay = 0;
hres = IInternetProtocolSink_ReportData(This->sink, BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, This->size, This->size); @@ -3250,6 +3271,12 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA
static HRESULT WINAPI Protocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason, DWORD dwOptions) { + ProtocolHandler *This = impl_from_IInternetProtocolEx(iface); + if(This->delay > 0) { + ok(hrReason == E_ABORT, "Abort hrReason = %08lx\n", hrReason); + ok(dwOptions == 0, "Abort dwOptions = %lx\n", dwOptions); + return S_OK; + } trace("Abort(%08lx %lx)\n", hrReason, dwOptions); return E_NOTIMPL; } @@ -3322,8 +3349,8 @@ static HRESULT WINAPI ProtocolEx_StartEx(IInternetProtocolEx *iface, IUri *uri, { ProtocolHandler *This = impl_from_IInternetProtocolEx(iface); BOOL block = FALSE; + BSTR path, query; DWORD bindf; - BSTR path; HRSRC src; HRESULT hres;
@@ -3391,6 +3418,13 @@ static HRESULT WINAPI ProtocolEx_StartEx(IInternetProtocolEx *iface, IUri *uri, if(FAILED(hres)) return hres;
+ hres = IUri_GetQuery(uri, &query); + if(SUCCEEDED(hres)) { + if(!lstrcmpW(query, L"?delay")) + This->delay = 1000; + SysFreeString(query); + } + IInternetProtocolSink_AddRef(This->sink = pOIProtSink); IUri_AddRef(This->uri = uri);
@@ -3723,6 +3757,7 @@ static void run_js_tests(void) init_protocol_handler();
run_script_as_http_with_mode("xhr.js", NULL, "9"); + run_script_as_http_with_mode("xhr.js", NULL, "10"); run_script_as_http_with_mode("xhr.js", NULL, "11"); run_script_as_http_with_mode("dom.js", NULL, "11"); run_script_as_http_with_mode("es5.js", NULL, "11"); diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index cb7e461..6228f73 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -28,6 +28,7 @@ function test_xhr() { if(complete_cnt++) next_test(); } + xhr.ontimeout = function() { ok(false, "ontimeout called"); } var onload_func = xhr.onload = function() { ok(xhr.statusText === "OK", "statusText = " + xhr.statusText); if(complete_cnt++) @@ -40,6 +41,38 @@ function test_xhr() { xhr.send("Testing..."); }
+function test_timeout() { + var xhr = new XMLHttpRequest(); + var v = document.documentMode; + + xhr.onreadystatechange = function() { + if(xhr.readyState != 4) + return; + todo_wine_if(v < 10). + ok(v >= 10, "onreadystatechange called"); + } + xhr.onload = function() { ok(false, "onload called"); } + xhr.ontimeout = function(e) { + var r = Object.prototype.toString.call(e); + todo_wine. + ok(r === ("[object " + (v < 10 ? "Event" : "ProgressEvent") + "]"), "Object.toString = " + r); + var props = [ "initProgressEvent", "lengthComputable", "loaded", "total" ]; + for(r = 0; r < props.length; r++) { + if(v < 10) + ok(!(props[r] in e), props[r] + " is available"); + else + ok(props[r] in e, props[r] + " not available"); + } + next_test(); + } + + xhr.open("POST", "echo.php?delay", true); + xhr.setRequestHeader("X-Test", "True"); + xhr.timeout = 10; + xhr.send("Timeout Test"); +} + var tests = [ - test_xhr + test_xhr, + test_timeout ]; diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index c9f7149..966dc8d 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -97,6 +97,7 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) static const eventid_t events[] = { EVENTID_READYSTATECHANGE, EVENTID_LOAD, + EVENTID_TIMEOUT, };
typedef struct { @@ -812,18 +813,18 @@ static HRESULT WINAPI HTMLXMLHttpRequest2_put_ontimeout(IHTMLXMLHttpRequest2 *if { HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface);
- FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
- return E_NOTIMPL; + return set_event_handler(&This->event_target, EVENTID_TIMEOUT, &v); }
static HRESULT WINAPI HTMLXMLHttpRequest2_get_ontimeout(IHTMLXMLHttpRequest2 *iface, VARIANT *p) { HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest2(iface);
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
- return E_NOTIMPL; + return get_event_handler(&This->event_target, EVENTID_TIMEOUT, p); }
static const IHTMLXMLHttpRequest2Vtbl HTMLXMLHttpRequest2Vtbl = {
Signed-off-by: Jacek Caban jacek@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=115497
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w8 (32 bit report) ===
Report validation errors: mshtml:script crashed (c0000409)
=== w8adm (32 bit report) ===
Report validation errors: mshtml:script crashed (c0000409)
=== w864 (32 bit report) ===
Report validation errors: mshtml:script crashed (c0000409)
=== w864 (64 bit report) ===
Report validation errors: mshtml:script crashed (c0000409)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=115494
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w7u_adm (32 bit report) ===
mshtml: script.c:644: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1653497560460 expected 1653497560512"