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 = {