From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/omnavigator.c | 46 ++++++++++++++++++---------- dlls/mshtml/tests/documentmode.js | 50 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 15 deletions(-)
diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 942bd5bbe70..1bd370bcffd 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -1708,15 +1709,20 @@ static const dispex_static_data_vtbl_t HTMLPerformanceTiming_dispex_vtbl = { .unlink = HTMLPerformanceTiming_unlink };
-static const tid_t PerformanceTiming_iface_tids[] = { - IHTMLPerformanceTiming_tid, - 0 -}; +static void PerformanceTiming_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCETIMING_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformanceTiming_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t PerformanceTiming_dispex = { .id = OBJID_PerformanceTiming, .vtbl = &HTMLPerformanceTiming_dispex_vtbl, .disp_tid = IHTMLPerformanceTiming_tid, - .iface_tids = PerformanceTiming_iface_tids, + .init_info = PerformanceTiming_init_dispex_info, };
typedef struct { @@ -1829,15 +1835,20 @@ static const dispex_static_data_vtbl_t HTMLPerformanceNavigation_dispex_vtbl = { .unlink = HTMLPerformanceNavigation_unlink };
-static const tid_t PerformanceNavigation_iface_tids[] = { - IHTMLPerformanceNavigation_tid, - 0 -}; +static void PerformanceNavigation_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCENAVIGATION_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformanceNavigation_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t PerformanceNavigation_dispex = { .id = OBJID_PerformanceNavigation, .vtbl = &HTMLPerformanceNavigation_dispex_vtbl, .disp_tid = IHTMLPerformanceNavigation_tid, - .iface_tids = PerformanceNavigation_iface_tids, + .init_info = PerformanceNavigation_init_dispex_info, };
typedef struct { @@ -1992,15 +2003,20 @@ static const dispex_static_data_vtbl_t HTMLPerformance_dispex_vtbl = { .unlink = HTMLPerformance_unlink };
-static const tid_t Performance_iface_tids[] = { - IHTMLPerformance_tid, - 0 -}; +static void Performance_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCE_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformance_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t Performance_dispex = { .id = OBJID_Performance, .vtbl = &HTMLPerformance_dispex_vtbl, .disp_tid = IHTMLPerformance_tid, - .iface_tids = Performance_iface_tids, + .init_info = Performance_init_dispex_info, };
HRESULT create_performance(HTMLInnerWindow *window, IHTMLPerformance **ret) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index dd228ee1bae..b05837ab21c 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1008,6 +1008,56 @@ sync_test("domimpl_props", function() { test_exposed("createHTMLDocument", v >= 9); });
+sync_test("perf_props", function() { + var obj = window.performance, name = "Performance"; + var v = document.documentMode; + + function test_exposed(prop, expect) { + if(expect) + ok(prop in obj, prop + " not found in " + name + "."); + else + ok(!(prop in obj), prop + " found in " + name + "."); + } + + test_exposed("navigation", true); + test_exposed("timing", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); + + obj = window.performance.navigation, name = "PerformanceNavigation"; + + test_exposed("redirectCount", true); + test_exposed("type", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); + + obj = window.performance.timing, name = "PerformanceTiming"; + + test_exposed("connectEnd", true); + test_exposed("connectStart", true); + test_exposed("domComplete", true); + test_exposed("domContentLoadedEventEnd", true); + test_exposed("domContentLoadedEventStart", true); + test_exposed("domInteractive", true); + test_exposed("domLoading", true); + test_exposed("domainLookupEnd", true); + test_exposed("domainLookupStart", true); + test_exposed("fetchStart", true); + test_exposed("loadEventEnd", true); + test_exposed("loadEventStart", true); + test_exposed("msFirstPaint", true); + test_exposed("navigationStart", true); + test_exposed("redirectEnd", true); + test_exposed("redirectStart", true); + test_exposed("requestStart", true); + test_exposed("responseEnd", true); + test_exposed("responseStart", true); + test_exposed("unloadEventEnd", true); + test_exposed("unloadEventStart", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); +}); + sync_test("xhr_props", function() { var xhr = new XMLHttpRequest();
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 3 +-- dlls/mshtml/htmlstyle.c | 3 +-- dlls/mshtml/mshtml_private.h | 1 + 3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index d281929e09e..de95a4bdd35 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -34,6 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
#define MAX_ARGS 16
+DISPID propput_dispid = DISPID_PROPERTYPUT; static ExternalCycleCollectionParticipant dispex_ccp;
static CRITICAL_SECTION cs_dispex_static_data; @@ -2277,8 +2278,6 @@ HRESULT dispex_prop_get(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *r, EX
HRESULT dispex_prop_put(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *v, EXCEPINFO *ei, IServiceProvider *caller) { - static DISPID propput_dispid = DISPID_PROPERTYPUT; - switch(get_dispid_type(id)) { case DISPEXPROP_CUSTOM: { DISPPARAMS dp = { .cArgs = 1, .rgvarg = v, .cNamedArgs = 1, .rgdispidNamedArgs = &propput_dispid }; diff --git a/dlls/mshtml/htmlstyle.c b/dlls/mshtml/htmlstyle.c index 3fa8954dbb6..0e709493782 100644 --- a/dlls/mshtml/htmlstyle.c +++ b/dlls/mshtml/htmlstyle.c @@ -2894,13 +2894,12 @@ static HRESULT WINAPI HTMLStyle_setAttribute(IHTMLStyle *iface, BSTR strAttribut if(hres == S_OK) { VARIANT ret; - DISPID dispidNamed = DISPID_PROPERTYPUT; DISPPARAMS params;
params.cArgs = 1; params.rgvarg = &AttributeValue; params.cNamedArgs = 1; - params.rgdispidNamedArgs = &dispidNamed; + params.rgdispidNamedArgs = &propput_dispid;
hres = HTMLStyle_Invoke(iface, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, NULL); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7d61ba0d74f..60e07f29121 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -546,6 +546,7 @@ ALL_OBJECTS #undef X
extern dispex_static_data_t *object_descriptors[OBJID_LAST]; +extern DISPID propput_dispid;
typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,WORD,DISPPARAMS*,VARIANT*, EXCEPINFO*,IServiceProvider*);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/jscript.c | 13 ++++++++ dlls/jscript/jsdisp.idl | 1 + dlls/mshtml/dispex.c | 36 ++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/omnavigator.c | 6 ++-- dlls/mshtml/tests/dom.c | 60 ++++++++++++++++++++++++++++++++++++ dlls/mshtml/tests/es5.js | 39 +++++++++++++++++++++++ 7 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index a7f468a677a..b65b95b1e0f 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -1465,6 +1465,18 @@ static HRESULT WINAPI WineJScript_InitHostConstructor(IWineJScript *iface, IWine return init_host_constructor(This->ctx, constr, method_name, ret); }
+static HRESULT WINAPI WineJScript_CreateObject(IWineJScript *iface, IWineJSDispatch **ret) +{ + JScript *This = impl_from_IWineJScript(iface); + jsdisp_t *jsdisp; + HRESULT hres; + + hres = create_object(This->ctx, NULL, &jsdisp); + if(SUCCEEDED(hres)) + *ret = &jsdisp->IWineJSDispatch_iface; + return hres; +} + static HRESULT WINAPI WineJScript_FillGlobals(IWineJScript *iface, IWineJSDispatchHost *script_global) { JScript *This = impl_from_IWineJScript(iface); @@ -1477,6 +1489,7 @@ static const IWineJScriptVtbl WineJScriptVtbl = { WineJScript_Release, WineJScript_InitHostObject, WineJScript_InitHostConstructor, + WineJScript_CreateObject, WineJScript_FillGlobals, };
diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index abef1f32f61..22349ecb50c 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -87,5 +87,6 @@ interface IWineJScript : IUnknown { HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret); HRESULT InitHostConstructor(IWineJSDispatchHost *constr, const WCHAR *method_name, IWineJSDispatch **ret); + HRESULT CreateObject(IWineJSDispatch **ret); HRESULT FillGlobals(IWineJSDispatchHost *script_global); } diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index de95a4bdd35..ab5972a2a9b 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2900,6 +2900,42 @@ static IWineJSDispatchHostVtbl JSDispatchHostVtbl = { JSDispatchHost_ToString, };
+HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, HTMLInnerWindow *window, VARIANT *ret) +{ + func_info_t *func, *end; + IWineJSDispatch *json; + HRESULT hres; + VARIANT var; + DISPPARAMS dp = { 0 }; + + if(!window->jscript) + return E_UNEXPECTED; + + hres = IWineJScript_CreateObject(window->jscript, &json); + if(FAILED(hres)) + return hres; + + for(func = dispex->info->funcs, end = func + dispex->info->func_cnt; func < end; func++) { + if(func->func_disp_idx != -1) + continue; + hres = builtin_propget(dispex, func, &dp, &var, NULL, NULL); + if(SUCCEEDED(hres)) { + hres = IWineJSDispatch_DefineProperty(json, func->name, PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, &var); + VariantClear(&var); + } + if(FAILED(hres)) { + IWineJSDispatch_Release(json); + return hres; + } + } + + if(ret) { + V_VT(ret) = VT_DISPATCH; + V_DISPATCH(ret) = (IDispatch*)json; + } + return hres; +} + static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) { DispatchEx *This = impl_from_IWineJSDispatchHost(p); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 60e07f29121..03417270980 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -639,6 +639,7 @@ HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*); BOOL is_builtin_attribute(DispatchEx*,DISPID); BOOL is_builtin_value(DispatchEx*,DISPID); HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*); +HRESULT dispex_builtin_props_to_json(DispatchEx*,HTMLInnerWindow*,VARIANT*); void release_typelib(void); HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**); const void *dispex_get_vtbl(DispatchEx*); diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 1bd370bcffd..0c23dffeeec 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -1627,8 +1627,10 @@ static HRESULT WINAPI HTMLPerformanceTiming_toString(IHTMLPerformanceTiming *ifa static HRESULT WINAPI HTMLPerformanceTiming_toJSON(IHTMLPerformanceTiming *iface, VARIANT *p) { HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return dispex_builtin_props_to_json(&This->dispex, This->window, p); }
static const IHTMLPerformanceTimingVtbl HTMLPerformanceTimingVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 17b4f63711d..f93da5fc159 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -52,6 +52,16 @@ static enum { static const char doc_blank[] = "<html></html>";
+static const char doc_blank_ie8[] = + "<!DOCTYPE html>\n" + "<html>" + " <head>" + " <meta http-equiv="x-ua-compatible" content="IE=8" />" + " </head>" + " <body>" + " </body>" + "</html>"; + static const char doc_blank_ie9[] = "<!DOCTYPE html>\n" "<html>" @@ -12219,6 +12229,54 @@ static void test_quirks_mode_offsetHeight(IHTMLDocument2 *doc) IHTMLElement_Release(elem); }
+static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) +{ + IHTMLPerformanceTiming *timing; + IHTMLPerformance *perf; + DISPPARAMS dp = { 0 }; + IHTMLWindow2 *window; + IDispatchEx *dispex; + DISPID dispid; + HRESULT hres; + VARIANT var; + BSTR bstr; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "QueryInterface(IID_IDispatchEx) failed: %08lx\n", hres); + IHTMLWindow2_Release(window); + + bstr = SysAllocString(L"performance"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID(performance) failed: %08lx\n", hres); + SysFreeString(bstr); + + V_VT(&var) = VT_EMPTY; + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL); + ok(hres == S_OK, "InvokeEx(performance) failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(performance) = %d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(performance) = NULL\n"); + IDispatchEx_Release(dispex); + + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLPerformance, (void**)&perf); + ok(hres == S_OK, "QueryInterface(IID_IHTMLPerformance) failed: %08lx\n", hres); + ok(perf != NULL, "performance is NULL\n"); + VariantClear(&var); + + hres = IHTMLPerformance_get_timing(perf, &timing); + ok(hres == S_OK, "get_timing failed: %08lx\n", hres); + ok(timing != NULL, "performance.timing is NULL\n"); + + hres = IHTMLPerformanceTiming_toJSON(timing, &var); + ok(hres == E_UNEXPECTED, "timing.toJSON() failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(timing.toJSON()) = %d\n", V_VT(&var)); + IHTMLPerformanceTiming_Release(timing); + + IHTMLPerformance_Release(perf); +} + static IHTMLDocument2 *notif_doc; static BOOL doc_complete;
@@ -13638,6 +13696,8 @@ START_TEST(dom) run_domtest(frameset_str, test_frameset); run_domtest(emptydiv_str, test_docfrag); run_domtest(doc_blank, test_replacechild_elems); + run_domtest(doc_blank, test_quirks_mode_perf_toJSON); + run_domtest(doc_blank_ie8, test_quirks_mode_perf_toJSON); run_domtest(doctype_str, test_doctype); run_domtest(case_insens_str, test_case_insens); if(is_ie9plus) { diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 3dfb6458655..0664719a650 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2594,6 +2594,45 @@ sync_test("functions scope", function() { })(); });
+sync_test("perf toJSON", function() { + var tests = [ + [ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd", + "domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart", + "fetchStart", "loadEventEnd", "loadEventStart", "msFirstPaint", "navigationStart", "redirectEnd", + "redirectStart", "requestStart", "responseEnd", "responseStart", "unloadEventEnd", "unloadEventStart" ] + ]; + + for(var i = 0; i < tests.length; i++) { + var desc, name = tests[i][0], obj = eval("window." + name), json; + + Object.defineProperty(obj, "foobar", {writable: true, enumerable: true, configurable: true, value: 1}); + Object.defineProperty(Object.getPrototypeOf(obj), "barfoo", {writable: true, enumerable: true, configurable: true, value: 3}); + json = obj.toJSON(); + + ok(Object.getPrototypeOf(json) === Object.prototype, "prototype of " + name + ".toJSON() != Object.prototype"); + ok(typeof json === "object", "typeof " + name + ".toJSON() != object"); + for(var j = 1; j < tests[i].length; j++) { + desc = Object.getOwnPropertyDescriptor(json, tests[i][j]); + ok(json.hasOwnProperty(tests[i][j]), name + ".toJSON() does not have " + tests[i][j]); + ok(desc.writable === true, name + ".toJSON()." + tests[i][j] + " not writable"); + ok(desc.enumerable === true, name + ".toJSON()." + tests[i][j] + " not enumerable"); + ok(desc.configurable === true, name + ".toJSON()." + tests[i][j] + " not configurable"); + } + ok(!("foobar" in json), "foobar in " + name + ".toJSON()"); + ok(!("barfoo" in json), "barfoo in " + name + ".toJSON()"); + + delete obj.foobar; + delete Object.getPrototypeOf(obj).barfoo; + + desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), tests[i][1]); + delete Object.getPrototypeOf(obj)[tests[i][1]]; + ok(!(tests[i][1] in obj), tests[i][1] + " in " + name + " after delete"); + json = obj.toJSON(); + ok(json.hasOwnProperty(tests[i][1]), name + ".toJSON() does not have " + tests[i][1] + " after delete"); + Object.defineProperty(Object.getPrototypeOf(obj), tests[i][1], desc); + } +}); + sync_test("console", function() { var except
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/omnavigator.c | 6 ++++-- dlls/mshtml/tests/dom.c | 10 ++++++++++ dlls/mshtml/tests/es5.js | 1 + 3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 0c23dffeeec..b9edfd54d3e 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -1774,8 +1774,10 @@ static HRESULT WINAPI HTMLPerformanceNavigation_toString(IHTMLPerformanceNavigat static HRESULT WINAPI HTMLPerformanceNavigation_toJSON(IHTMLPerformanceNavigation *iface, VARIANT *p) { HTMLPerformanceNavigation *This = impl_from_IHTMLPerformanceNavigation(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return dispex_builtin_props_to_json(&This->dispex, This->window, p); }
static const IHTMLPerformanceNavigationVtbl HTMLPerformanceNavigationVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index f93da5fc159..9778a5b1ad8 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -12231,6 +12231,7 @@ static void test_quirks_mode_offsetHeight(IHTMLDocument2 *doc)
static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) { + IHTMLPerformanceNavigation *nav; IHTMLPerformanceTiming *timing; IHTMLPerformance *perf; DISPPARAMS dp = { 0 }; @@ -12265,6 +12266,15 @@ static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) ok(perf != NULL, "performance is NULL\n"); VariantClear(&var);
+ hres = IHTMLPerformance_get_navigation(perf, &nav); + ok(hres == S_OK, "get_navigation failed: %08lx\n", hres); + ok(nav != NULL, "performance.navigation is NULL\n"); + + hres = IHTMLPerformanceNavigation_toJSON(nav, &var); + ok(hres == E_UNEXPECTED, "navigation.toJSON() failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(navigation.toJSON()) = %d\n", V_VT(&var)); + IHTMLPerformanceNavigation_Release(nav); + hres = IHTMLPerformance_get_timing(perf, &timing); ok(hres == S_OK, "get_timing failed: %08lx\n", hres); ok(timing != NULL, "performance.timing is NULL\n"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 0664719a650..91d930601dc 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2596,6 +2596,7 @@ sync_test("functions scope", function() {
sync_test("perf toJSON", function() { var tests = [ + [ "performance.navigation", "redirectCount", "type" ], [ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd", "domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart", "fetchStart", "loadEventEnd", "loadEventStart", "msFirstPaint", "navigationStart", "redirectEnd",
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 17 ++++++++++++++++- dlls/mshtml/omnavigator.c | 6 ++++-- dlls/mshtml/tests/dom.c | 4 ++++ dlls/mshtml/tests/es5.js | 1 + 4 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index ab5972a2a9b..100aa0d35c6 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2902,10 +2902,12 @@ static IWineJSDispatchHostVtbl JSDispatchHostVtbl = {
HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, HTMLInnerWindow *window, VARIANT *ret) { + IWineJSDispatchHost *subdispex_iface; func_info_t *func, *end; IWineJSDispatch *json; HRESULT hres; VARIANT var; + DISPID id; DISPPARAMS dp = { 0 };
if(!window->jscript) @@ -2920,7 +2922,20 @@ HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, HTMLInnerWindow *window continue; hres = builtin_propget(dispex, func, &dp, &var, NULL, NULL); if(SUCCEEDED(hres)) { - hres = IWineJSDispatch_DefineProperty(json, func->name, PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, &var); + if(V_VT(&var) == VT_DISPATCH && + SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IWineJSDispatchHost, (void**)&subdispex_iface))) { + if(subdispex_iface->lpVtbl == &JSDispatchHostVtbl) { + DispatchEx *subdispex = impl_from_IWineJSDispatchHost(subdispex_iface); + + if(SUCCEEDED(get_builtin_id(subdispex->info, L"toJSON", fdexNameCaseSensitive, &id))) { + VariantClear(&var); + hres = dispex_call_builtin(subdispex, id, &dp, &var, NULL, NULL); + } + } + IWineJSDispatchHost_Release(subdispex_iface); + } + if(SUCCEEDED(hres)) + hres = IWineJSDispatch_DefineProperty(json, func->name, PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, &var); VariantClear(&var); } if(FAILED(hres)) { diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index b9edfd54d3e..11146766ccf 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -1938,8 +1938,10 @@ static HRESULT WINAPI HTMLPerformance_toString(IHTMLPerformance *iface, BSTR *st static HRESULT WINAPI HTMLPerformance_toJSON(IHTMLPerformance *iface, VARIANT *var) { HTMLPerformance *This = impl_from_IHTMLPerformance(iface); - FIXME("(%p)->(%p)\n", This, var); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, var); + + return dispex_builtin_props_to_json(&This->dispex, This->window, var); }
static const IHTMLPerformanceVtbl HTMLPerformanceVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 9778a5b1ad8..7250ffea636 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -12266,6 +12266,10 @@ static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) ok(perf != NULL, "performance is NULL\n"); VariantClear(&var);
+ hres = IHTMLPerformance_toJSON(perf, &var); + ok(hres == E_UNEXPECTED, "toJSON() returned: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(toJSON()) = %d\n", V_VT(&var)); + hres = IHTMLPerformance_get_navigation(perf, &nav); ok(hres == S_OK, "get_navigation failed: %08lx\n", hres); ok(nav != NULL, "performance.navigation is NULL\n"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 91d930601dc..bf52913d078 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2596,6 +2596,7 @@ sync_test("functions scope", function() {
sync_test("perf toJSON", function() { var tests = [ + [ "performance", "navigation", "timing" ], [ "performance.navigation", "redirectCount", "type" ], [ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd", "domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart",
Jacek Caban (@jacek) commented about dlls/mshtml/dispex.c:
continue; hres = builtin_propget(dispex, func, &dp, &var, NULL, NULL); if(SUCCEEDED(hres)) {
hres = IWineJSDispatch_DefineProperty(json, func->name, PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, &var);
if(V_VT(&var) == VT_DISPATCH &&
SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IWineJSDispatchHost, (void**)&subdispex_iface))) {
if(subdispex_iface->lpVtbl == &JSDispatchHostVtbl) {
DispatchEx *subdispex = impl_from_IWineJSDispatchHost(subdispex_iface);
if(SUCCEEDED(get_builtin_id(subdispex->info, L"toJSON", fdexNameCaseSensitive, &id))) {
VariantClear(&var);
hres = dispex_call_builtin(subdispex, id, &dp, &var, NULL, NULL);
}
}
IWineJSDispatchHost_Release(subdispex_iface);
}
Do we need that? Usually, it's `stringify`'s responsibility to call `toJSON` on each object property.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
})();
});
+sync_test("perf toJSON", function() {
- var tests = [
[ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd",
"domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart",
"fetchStart", "loadEventEnd", "loadEventStart", "msFirstPaint", "navigationStart", "redirectEnd",
"redirectStart", "requestStart", "responseEnd", "responseStart", "unloadEventEnd", "unloadEventStart" ]
- ];
- for(var i = 0; i < tests.length; i++) {
var desc, name = tests[i][0], obj = eval("window." + name), json;
Please don't use `eval` like this, ideally at all. You could just unquote the string in the first place.
Those tests could use more clean up. The whole array is not really needed, you could just use `getOwnPropertyNames` on the prototype. It would be nice to have `test_own_props`-based test in `documentmode.js`. We could then just depend on it doing the right thing here.
Jacek Caban (@jacek) commented about dlls/mshtml/dispex.c:
#define MAX_ARGS 16
+DISPID propput_dispid = DISPID_PROPERTYPUT;
I think that two usages like that don't justify a global variable, let's skip it.
On Thu Sep 4 17:44:47 2025 +0000, Jacek Caban wrote:
Do we need that? Usually, it's `stringify`'s responsibility to call `toJSON` on each object property.
Yeah, I've tested this more and wrote tests to confirm, I actually don't even call `stringify` in the tests at all so I don't see how it can be involved. (also, had to fix a bug with former one which didn't work either)
On Thu Sep 4 17:44:48 2025 +0000, Jacek Caban wrote:
Please don't use `eval` like this, ideally at all. You could just unquote the string in the first place. Those tests could use more clean up. The whole array is not really needed, you could just use `getOwnPropertyNames` on the prototype. It would be nice to have `test_own_props`-based test in `documentmode.js`. We could then just depend on it doing the right thing here.
Oh I just used eval to be able to obtain its name as well, but I guess I'll just extract it from the toString like in the `prototype props` test in `documentmode.js`. I couldn't use window[prop] either since some of them are nested.
I got rid of the array, but `getOwnPropertyNames` brings its own can of worms, not sure if it's better but here it is. Specifically it has some props that aren't part of the JSON object (e.g. `constructor` and methods but also some internal ones) which I had to skip. But I also wrote tests for the prototype props since we were missing, which also unveils those internal ones in ALL CAPS.
Overall the tests should be way more encompassing now and fixed a couple of broken things.