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 | 48 +++++++++++++++++++++++++++++ 7 files changed, 163 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 d281929e09e..d7c8b667724 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2901,6 +2901,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 7d61ba0d74f..d014c34ba7c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -638,6 +638,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 a49387f1ed0..2316f539702 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..62daa58a383 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2594,6 +2594,54 @@ sync_test("functions scope", function() { })(); });
+sync_test("perf toJSON", function() { + var json, objs = [ performance.timing ]; + var non_props = [ "constructor" ]; + + for(var i = 0; i < objs.length; i++) { + var desc, prop, proto = Object.getPrototypeOf(objs[i]), props = Object.getOwnPropertyNames(proto); + var name = Object.prototype.toString.call(objs[i]).slice(8, -1); + + Object.defineProperty(objs[i], "foobar", {writable: true, enumerable: true, configurable: true, value: 1}); + Object.defineProperty(proto, "barfoo", {writable: true, enumerable: true, configurable: true, value: 3}); + json = objs[i].toJSON(); + + ok(Object.getPrototypeOf(json) === Object.prototype, "prototype of " + name + ".toJSON() != Object.prototype"); + ok(typeof json === "object", "typeof " + name + ".toJSON() != object"); + + for(var j = 0; j < non_props.length; j++) { + var idx = props.indexOf(non_props[j]); + if(idx !== -1) + props.splice(idx, 1); + } + + for(var j = 0; j < props.length; j++) { + if(typeof(proto[props[j]]) === "function") + ok(!(props[j] in json), props[j] + " in " + name + ".toJSON()"); + else { + test_own_data_prop_desc(json, props[j], true, true, true); + prop = props[j]; + } + } + + for(var j = 0; j < non_props.length; j++) + ok(!json.hasOwnProperty(non_props[j]), non_props[j] + " in " + name + ".toJSON()"); + ok(!("foobar" in json), "foobar in " + name + ".toJSON()"); + ok(!("barfoo" in json), "barfoo in " + name + ".toJSON()"); + + delete objs[i].foobar; + delete proto.barfoo; + + // test delete a builtin from the prototype and toJSON after + desc = Object.getOwnPropertyDescriptor(proto, prop); + delete proto[prop]; + ok(!(prop in objs[i]), prop + " in " + name + " after delete"); + json = objs[i].toJSON(); + ok(json.hasOwnProperty(prop), name + ".toJSON() does not have " + prop + " after delete"); + Object.defineProperty(proto, prop, desc); + } +}); + sync_test("console", function() { var except