Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- include/mshtmdid.h | 12 +++++++++ include/mshtml.idl | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+)
diff --git a/include/mshtmdid.h b/include/mshtmdid.h index 31e7570..f56fc4d 100644 --- a/include/mshtmdid.h +++ b/include/mshtmdid.h @@ -141,6 +141,12 @@ #define DISPID_DOMSTORAGEEVENT (DISPID_DOMMESSAGEEVENT+25) #define DISPID_DOMBEFOREUNLOADEVENT (DISPID_DOMSTORAGEEVENT+25) #define DISPID_DOMDRAGEVENT (DISPID_DOMBEFOREUNLOADEVENT+25) +#define DISPID_DOMMSPOINTEREVENT (DISPID_DOMDRAGEVENT+25) +#define DISPID_DOMMSGESTUREEVENT (DISPID_DOMMSPOINTEREVENT+25) +#define DISPID_DOMMSTRANSITIONEVENT (DISPID_DOMMSGESTUREEVENT+25) +#define DISPID_DOMMSANIMATIONEVENT (DISPID_DOMMSTRANSITIONEVENT+25) +#define DISPID_DOMMSMANIPULATIONEVENT (DISPID_DOMMSANIMATIONEVENT+25) +#define DISPID_DOMPROGRESSEVENT (DISPID_DOMMSMANIPULATIONEVENT+25)
#define DISPID_DOMIMPLEMENTATION DISPID_NORMAL_FIRST #define DISPID_DOCUMENTCOMPATIBLEINFO DISPID_NORMAL_FIRST @@ -4704,6 +4710,12 @@ #define DISPID_IDOMMESSAGEEVENT_SOURCE DISPID_DOMMESSAGEEVENT+3 #define DISPID_IDOMMESSAGEEVENT_INITMESSAGEEVENT DISPID_DOMMESSAGEEVENT+4
+/* IDOMProgressEvent */ +#define DISPID_IDOMPROGRESSEVENT_LENGTHCOMPUTABLE DISPID_DOMPROGRESSEVENT+1 +#define DISPID_IDOMPROGRESSEVENT_LOADED DISPID_DOMPROGRESSEVENT+2 +#define DISPID_IDOMPROGRESSEVENT_TOTAL DISPID_DOMPROGRESSEVENT+3 +#define DISPID_IDOMPROGRESSEVENT_INITPROGRESSEVENT DISPID_DOMPROGRESSEVENT+4 + /* IHTMLControlElement */ #define DISPID_IHTMLCONTROLELEMENT_TABINDEX STDPROPID_XOBJ_TABINDEX #define DISPID_IHTMLCONTROLELEMENT_FOCUS (DISPID_SITE+0) diff --git a/include/mshtml.idl b/include/mshtml.idl index 162a969..afeb442 100644 --- a/include/mshtml.idl +++ b/include/mshtml.idl @@ -28495,6 +28495,68 @@ methods: [in] IHTMLWindow2 *source); }
+/***************************************************************************** + * IDOMProgressEvent interface + */ +[ + odl, + oleautomation, + dual, + uuid(3051071e-98b5-11cf-bb82-00aa00bdce0b) +] +interface IDOMProgressEvent : IDispatch +{ + [propget, id(DISPID_IDOMPROGRESSEVENT_LENGTHCOMPUTABLE)] + HRESULT lengthComputable([out, retval] VARIANT_BOOL *p); + + [propget, id(DISPID_IDOMPROGRESSEVENT_LOADED)] + HRESULT loaded([out, retval] ULONGLONG *p); + + [propget, id(DISPID_IDOMPROGRESSEVENT_TOTAL)] + HRESULT total([out, retval] ULONGLONG *p); + + [id(DISPID_IDOMPROGRESSEVENT_INITPROGRESSEVENT)] + HRESULT initProgressEvent( + [in] BSTR eventType, + [in] VARIANT_BOOL canBubble, + [in] VARIANT_BOOL cancelable, + [in] VARIANT_BOOL lengthComputableArg, + [in] ULONGLONG loadedArg, + [in] ULONGLONG totalArg); +}; + +/***************************************************************************** + * DispDOMProgressEvent dispinterface + */ +[ + hidden, + uuid(30590091-98b5-11cf-bb82-00aa00bdce0b) +] +dispinterface DispDOMProgressEvent +{ +properties: +methods: + WINE_IDOMEVENT_DISPINTERFACE_DECL; + + [propget, id(DISPID_IDOMPROGRESSEVENT_LENGTHCOMPUTABLE)] + VARIANT_BOOL lengthComputable(); + + [propget, id(DISPID_IDOMPROGRESSEVENT_LOADED)] + ULONGLONG loaded(); + + [propget, id(DISPID_IDOMPROGRESSEVENT_TOTAL)] + ULONGLONG total(); + + [id(DISPID_IDOMPROGRESSEVENT_INITPROGRESSEVENT)] + void initProgressEvent( + [in] BSTR eventType, + [in] VARIANT_BOOL canBubble, + [in] VARIANT_BOOL cancelable, + [in] VARIANT_BOOL lengthComputableArg, + [in] ULONGLONG loadedArg, + [in] ULONGLONG totalArg); +}; + /***************************************************************************** * IHTMLNamespaceCollection interface */
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 | 33 ++++++++ dlls/mshtml/xmlhttprequest.c | 116 +++++++++++++++++++++++++++++ 4 files changed, 152 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..bdcb9ef 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -1007,6 +1007,38 @@ 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); + IHTMLXMLHttpRequest_Release(xhr); + xhr = NULL; + + 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); + + hres = IHTMLXMLHttpRequest2_put_timeout(xhr2, -1); + ok(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 +1103,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..b9f6f1f 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_FAIL; + 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);
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=115284
Your paranoid android.
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w7u_adm (32 bit report) ===
mshtml: script.c:644: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1653322145104 expected 1653322145176"
=== w7u_2qxl (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w7u_adm (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w7u_el (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w8 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w8adm (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w864 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1507 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1809 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_tsign (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w864 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1507 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1809 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_2qxl (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_adm (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_tsign (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_en_AE_u8 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_ar (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_ja (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_zh_CN (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
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,
Instead of hardcoding it, which will be necessary as the amount of event types implemented grows.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f28dd63..c25b85f 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2373,6 +2373,26 @@ static BOOL check_event_iface(nsIDOMEvent *event, REFIID riid) return TRUE; }
+static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, dispex_static_data_t **dispex_data) +{ + 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; + *dispex_data = &DOMMessageEvent_dispex; + return &message_event->event; +} + +static const struct { + DOMEvent* (*proc)(nsIDOMEvent*,dispex_static_data_t**); + compat_mode_t min_mode; +} event_type_ctors[ARRAY_SIZE(event_types)] = { + [EVENT_TYPE_MESSAGE] = { message_event_ctor, COMPAT_MODE_QUIRKS }, +}; + static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id) { dispex_static_data_t *dispex_data = &DOMEvent_dispex; @@ -2389,16 +2409,11 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev 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) + }else if(event_id != EVENTID_LAST && event_type_ctors[event_info[event_id].type].proc && + compat_mode >= event_type_ctors[event_info[event_id].type].min_mode) { + event = event_type_ctors[event_info[event_id].type].proc(nsevent, &dispex_data); + if(!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 { event = heap_alloc_zero(sizeof(*event)); if(!event)
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding it, which will be necessary as the amount of event types implemented grows.
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/htmlevent.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f28dd63..c25b85f 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2373,6 +2373,26 @@ static BOOL check_event_iface(nsIDOMEvent *event, REFIID riid) return TRUE; }
+static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, dispex_static_data_t **dispex_data) +{
- 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;
- *dispex_data = &DOMMessageEvent_dispex;
- return &message_event->event;
+}
+static const struct {
- DOMEvent* (*proc)(nsIDOMEvent*,dispex_static_data_t**);
- compat_mode_t min_mode;
+} event_type_ctors[ARRAY_SIZE(event_types)] = {
- [EVENT_TYPE_MESSAGE] = { message_event_ctor, COMPAT_MODE_QUIRKS },
+};
While we may need something more generic at some point, this seems this patch series just uses it just for two event types and it's not clear we want to go in that direction. The way we handle DOMCustomEvent is probably better in cases where it's possible. At this point you leave out of generic mechanism, meaning that we will prefer to not use the new mechanism anyway. I'd suggest to wait for more problematic cases before having something like that.
Thanks,
Jacek
On 23/05/2022 19:06, Jacek Caban wrote:
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding it, which will be necessary as the amount of event types implemented grows.
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/htmlevent.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f28dd63..c25b85f 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2373,6 +2373,26 @@ static BOOL check_event_iface(nsIDOMEvent *event, REFIID riid) return TRUE; } +static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, dispex_static_data_t **dispex_data) +{ + 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; + *dispex_data = &DOMMessageEvent_dispex; + return &message_event->event; +}
+static const struct { + DOMEvent* (*proc)(nsIDOMEvent*,dispex_static_data_t**); + compat_mode_t min_mode; +} event_type_ctors[ARRAY_SIZE(event_types)] = { + [EVENT_TYPE_MESSAGE] = { message_event_ctor, COMPAT_MODE_QUIRKS }, +};
While we may need something more generic at some point, this seems this patch series just uses it just for two event types and it's not clear we want to go in that direction. The way we handle DOMCustomEvent is probably better in cases where it's possible. At this point you leave out of generic mechanism, meaning that we will prefer to not use the new mechanism anyway. I'd suggest to wait for more problematic cases before having something like that.
Do you mean checking for Gecko's interface? AFAIK there is no nsIDOMProgressEvent (it seems to have been removed?) so I can't do that.
So what should I do? Add it inline like for Message Event? I heavily dislike hardcoding checks but...
Thanks, Gabriel
On 5/23/22 19:38, Gabriel Ivăncescu wrote:
On 23/05/2022 19:06, Jacek Caban wrote:
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding it, which will be necessary as the amount of event types implemented grows.
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/htmlevent.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f28dd63..c25b85f 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2373,6 +2373,26 @@ static BOOL check_event_iface(nsIDOMEvent *event, REFIID riid) return TRUE; } +static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, dispex_static_data_t **dispex_data) +{ + 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; + *dispex_data = &DOMMessageEvent_dispex; + return &message_event->event; +}
+static const struct { + DOMEvent* (*proc)(nsIDOMEvent*,dispex_static_data_t**); + compat_mode_t min_mode; +} event_type_ctors[ARRAY_SIZE(event_types)] = { + [EVENT_TYPE_MESSAGE] = { message_event_ctor, COMPAT_MODE_QUIRKS }, +};
While we may need something more generic at some point, this seems this patch series just uses it just for two event types and it's not clear we want to go in that direction. The way we handle DOMCustomEvent is probably better in cases where it's possible. At this point you leave out of generic mechanism, meaning that we will prefer to not use the new mechanism anyway. I'd suggest to wait for more problematic cases before having something like that.
Do you mean checking for Gecko's interface? AFAIK there is no nsIDOMProgressEvent (it seems to have been removed?) so I can't do that.
Yes, I know, nsIDOMProgressEvent was removed from Gecko as part of upstream de-XPCOM efforts, but we could potentially bring it back if needed. And we may need it to properly implement IDOMMessageEvent at some point. Once we do, we will probably want this to not use event id-based constructor and rely on Gecko to provide that information instead.
So what should I do? Add it inline like for Message Event? I heavily dislike hardcoding checks but...
As above, having an array of two constructors covering only part of the problem that we potentially would like to get rid of in favour of another mechanism does not seem like an improvement. Please keep it simple.
Jacek
Instead of hardcoding each event, since there will be plenty more.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/xmlhttprequest.c | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index b9f6f1f..baef36e 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -94,12 +94,23 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) return S_OK; }
+#define EVENTS_LIST \ + X(readystatechange) \ + X(load) + +#undef X +#define X(event) EVENT_##event, +enum { EVENTS_LIST }; +#undef X +#define X(event) L"" #event, +static const WCHAR *events[] = { EVENTS_LIST }; +#undef X + typedef struct { nsIDOMEventListener nsIDOMEventListener_iface; LONG ref; HTMLXMLHttpRequest *xhr; - BOOL readystatechange_event; - BOOL load_event; + DWORD events_mask; } XMLHttpReqEventListener;
struct HTMLXMLHttpRequest { @@ -115,21 +126,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, events[i]); nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE); nsAString_Finish(&str); assert(nsres == NS_OK); @@ -941,18 +948,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; nsresult nsres; + DWORD event;
TRACE("(%p)\n", This);
switch(eid) { case EVENTID_READYSTATECHANGE: - type_name = L"readystatechange"; + event = EVENT_readystatechange; break; case EVENTID_LOAD: - type_name = L"load"; + event = EVENT_load; break; default: return; @@ -966,25 +973,21 @@ 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); + nsAString_InitDepend(&type_str, events[event]); 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(events[event]), 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 << event; }
static void HTMLXMLHttpRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode)
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding each event, since there will be plenty more.
What's an example of those missing ones?
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/xmlhttprequest.c | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index b9f6f1f..baef36e 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -94,12 +94,23 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) return S_OK; }
+#define EVENTS_LIST \
- X(readystatechange) \
- X(load)
+#undef X +#define X(event) EVENT_##event, +enum { EVENTS_LIST }; +#undef X +#define X(event) L"" #event, +static const WCHAR *events[] = { EVENTS_LIST }; +#undef X
You could avoid all those preprocessor directives by simply using an array of structs.
Jacek
On 23/05/2022 19:09, Jacek Caban wrote:
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding each event, since there will be plenty more.
What's an example of those missing ones?
It's not in this patch series, but IE10+ modes will additionally need:
abort, error, loadstart, loadend, progress
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/xmlhttprequest.c | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index b9f6f1f..baef36e 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -94,12 +94,23 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) return S_OK; } +#define EVENTS_LIST \ + X(readystatechange) \ + X(load)
+#undef X +#define X(event) EVENT_##event, +enum { EVENTS_LIST }; +#undef X +#define X(event) L"" #event, +static const WCHAR *events[] = { EVENTS_LIST }; +#undef X
You could avoid all those preprocessor directives by simply using an array of structs.
The problem is the first one is an enum, while second one is actual data, so I can't use a struct to unify this. I wanted to keep it easily in sync, but I can of course separate them without preprocessor if you prefer.
Hi Gabriel,
On 5/23/22 19:41, Gabriel Ivăncescu wrote:
On 23/05/2022 19:09, Jacek Caban wrote:
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding each event, since there will be plenty more.
What's an example of those missing ones?
It's not in this patch series, but IE10+ modes will additionally need:
abort, error, loadstart, loadend, progress
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/xmlhttprequest.c | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index b9f6f1f..baef36e 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -94,12 +94,23 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) return S_OK; } +#define EVENTS_LIST \ + X(readystatechange) \ + X(load)
+#undef X +#define X(event) EVENT_##event, +enum { EVENTS_LIST }; +#undef X +#define X(event) L"" #event, +static const WCHAR *events[] = { EVENTS_LIST }; +#undef X
You could avoid all those preprocessor directives by simply using an array of structs.
The problem is the first one is an enum, while second one is actual data, so I can't use a struct to unify this. I wanted to keep it easily in sync, but I can of course separate them without preprocessor if you prefer.
It doesn't sound too bad and you may always use something like C_ASSERT to make sure we don't forget to update one of its parts.
Generally, this could use more generic event code. Reasons for XMLHttpReqEventListener existance are mostly historical, we could for example have a more generic version of Gecko event listener that could be also used instead of htmlevent_listener. I left it separated while changing the code for IE9+ events mostly because it was simple enough. If this is going to need more duplication in the future, I think we should revisit that. That said, I'm generally fine with the approach for now, but I wouldn't plan on extending that much further in this direction.
Jacek
On 24/05/2022 18:35, Jacek Caban wrote:
Hi Gabriel,
On 5/23/22 19:41, Gabriel Ivăncescu wrote:
On 23/05/2022 19:09, Jacek Caban wrote:
Hi Gabriel,
On 5/23/22 17:22, Gabriel Ivăncescu wrote:
Instead of hardcoding each event, since there will be plenty more.
What's an example of those missing ones?
It's not in this patch series, but IE10+ modes will additionally need:
abort, error, loadstart, loadend, progress
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
dlls/mshtml/xmlhttprequest.c | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index b9f6f1f..baef36e 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -94,12 +94,23 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) return S_OK; } +#define EVENTS_LIST \ + X(readystatechange) \ + X(load)
+#undef X +#define X(event) EVENT_##event, +enum { EVENTS_LIST }; +#undef X +#define X(event) L"" #event, +static const WCHAR *events[] = { EVENTS_LIST }; +#undef X
You could avoid all those preprocessor directives by simply using an array of structs.
The problem is the first one is an enum, while second one is actual data, so I can't use a struct to unify this. I wanted to keep it easily in sync, but I can of course separate them without preprocessor if you prefer.
It doesn't sound too bad and you may always use something like C_ASSERT to make sure we don't forget to update one of its parts.
Generally, this could use more generic event code. Reasons for XMLHttpReqEventListener existance are mostly historical, we could for example have a more generic version of Gecko event listener that could be also used instead of htmlevent_listener. I left it separated while changing the code for IE9+ events mostly because it was simple enough. If this is going to need more duplication in the future, I think we should revisit that. That said, I'm generally fine with the approach for now, but I wouldn't plan on extending that much further in this direction.
Jacek
Hi Jacek,
Well with the event mask there will be almost no duplication at all (except the switch() case in the bind function, but that could probably be looked up in a table too, so all the event data is in the table). The point of the mask is to iterate through it, after all, and avoid any duplication there.
This patch is a good example of that; adding additional events requires no extra code except extending the list (macro now) or table (revised) with the new event. Is that not simple enough?
I don't know what else "extending much further" in this direction means though—do you have some examples of the more generic version of Gecko event listener you mentioned? Or how would it look like? I honestly don't know how else this could be handled, since I learned the code as I worked on it. :-)
IMO I think the mask with table is as simple as it gets when it comes to extending it: just add new entries to the table.
Thanks, Gabriel
Hi Gabriel,
On 5/24/22 20:06, Gabriel Ivăncescu wrote:
I don't know what else "extending much further" in this direction means though—do you have some examples of the more generic version of Gecko event listener you mentioned? Or how would it look like? I honestly don't know how else this could be handled, since I learned the code as I worked on it. :-)
Both event listeners essentially maintain a set of bound events (one uses event_vector for what your patch uses a bitmap) and, when requested, bind it if it didn't before. There is nothing really specific to XHR or nodes other than current implementation details.
Jacek
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 146 +++++++++++++++++++++++++++++++++++ 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 | 14 ++-- 6 files changed, 244 insertions(+), 23 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index c25b85f..27a117b 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} }; @@ -2281,6 +2285,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 @@ -2360,6 +2480,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; @@ -2386,11 +2519,24 @@ static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, dispex_static_data_t * return &message_event->event; }
+static DOMEvent *progress_event_ctor(nsIDOMEvent *nsevent, dispex_static_data_t **dispex_data) +{ + 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; + *dispex_data = &DOMProgressEvent_dispex; + return &progress_event->event; +} + static const struct { DOMEvent* (*proc)(nsIDOMEvent*,dispex_static_data_t**); compat_mode_t min_mode; } event_type_ctors[ARRAY_SIZE(event_types)] = { [EVENT_TYPE_MESSAGE] = { message_event_ctor, COMPAT_MODE_QUIRKS }, + [EVENT_TYPE_PROGRESS] = { progress_event_ctor, COMPAT_MODE_IE10 }, };
static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id) diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 5d53451..789d0b2 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 baef36e..7987d2d 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -96,7 +96,8 @@ static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p)
#define EVENTS_LIST \ X(readystatechange) \ - X(load) + X(load) \ + X(timeout)
#undef X #define X(event) EVENT_##event, @@ -819,18 +820,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 = { @@ -961,6 +962,9 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) case EVENTID_LOAD: event = EVENT_load; break; + case EVENTID_TIMEOUT: + event = EVENT_timeout; + break; default: return; }
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=115288
Your paranoid android.
=== w8 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_en_AE_u8 (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== 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)
=== w7u_2qxl (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w7u_adm (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w7u_el (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w8 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w8adm (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w864 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1507 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1809 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_tsign (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64 (32 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w864 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1507 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064v1809 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_2qxl (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_adm (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w1064_tsign (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_en_AE_u8 (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_ar (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_ja (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0
=== w10pro64_zh_CN (64 bit report) ===
mshtml: xmlhttprequest.c:1034: Test failed: put_timeout returned 80004005 xmlhttprequest.c:1037: Test failed: timeout = 0