From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 13 ++++++++ dlls/jscript/jsdisp.idl | 1 + dlls/mshtml/dispex.c | 42 +++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/omnavigator.c | 6 ++-- dlls/mshtml/tests/dom.c | 60 ++++++++++++++++++++++++++++++++++++ dlls/mshtml/tests/es5.js | 41 ++++++++++++++++++++++++ 7 files changed, 162 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 79aea60de9c..75089655356 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2304,6 +2304,18 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IWineJSDispatch *iface, IUnk return E_NOTIMPL; }
+static HRESULT WINAPI WineJSDispatch_CreateObject(IWineJSDispatch *iface, IWineJSDispatch **obj) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + jsdisp_t *jsdisp; + HRESULT hres; + + hres = create_object(This->ctx, NULL, &jsdisp); + if(SUCCEEDED(hres)) + *obj = &jsdisp->IWineJSDispatch_iface; + return hres; +} + static void WINAPI WineJSDispatch_Free(IWineJSDispatch *iface) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); @@ -2342,6 +2354,7 @@ static IWineJSDispatchVtbl DispatchExVtbl = { DispatchEx_GetNameSpaceParent, WineJSDispatch_Free, WineJSDispatch_GetScriptGlobal, + WineJSDispatch_CreateObject, };
jsdisp_t *as_jsdisp(IDispatch *disp) diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index f01ea95ce48..9e57a0836f2 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -45,6 +45,7 @@ interface IWineJSDispatch : IDispatchEx { void Free(); HRESULT GetScriptGlobal(IWineJSDispatchHost **ret); + HRESULT CreateObject(IWineJSDispatch **obj); }
[ diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 2bd2a1b9c63..8b0f7b9cc92 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2428,6 +2428,48 @@ static IWineJSDispatchHostVtbl JSDispatchHostVtbl = { JSDispatchHost_ToString, };
+HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, VARIANT *ret) +{ + func_info_t *func, *end; + IWineJSDispatch *json; + HRESULT hres; + VARIANT var; + DISPID id; + DISPPARAMS dp = { 0 }, put_dp = { &var, &propput_dispid, 1, 1 }; + + if(!dispex->jsdisp) + return E_UNEXPECTED; + + hres = IWineJSDispatch_CreateObject(dispex->jsdisp, &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; + if(!func->hook || (hres = func->hook(dispex, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL)) == S_FALSE) + hres = builtin_propget(dispex, func, &dp, &var); + + if(SUCCEEDED(hres)) { + hres = IWineJSDispatch_GetDispID(json, func->name, fdexNameEnsure | fdexNameCaseSensitive, &id); + if(SUCCEEDED(hres)) { + hres = IWineJSDispatch_InvokeEx(json, id, 0, DISPATCH_PROPERTYPUT, &put_dp, NULL, NULL, NULL); + } + 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 5f329733c0d..638b23e1379 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -503,6 +503,7 @@ HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**); HRESULT get_dispids(tid_t,DWORD*,DISPID**); HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*); HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*); +HRESULT dispex_builtin_props_to_json(DispatchEx*,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 ab6d0548172..ccbd9c95538 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -1439,8 +1439,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, p); }
static const IHTMLPerformanceTimingVtbl HTMLPerformanceTimingVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 8383f167cdd..65b9e3aa21c 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>" @@ -11217,6 +11227,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;
@@ -12220,6 +12278,8 @@ START_TEST(dom) run_domtest(emptydiv_str, test_docfrag); run_domtest(doc_blank, test_replacechild_elems); run_domtest(doctype_str, test_doctype); + run_domtest(doc_blank, test_quirks_mode_perf_toJSON); + run_domtest(doc_blank_ie8, test_quirks_mode_perf_toJSON);
test_quirks_mode(); test_document_mode_lock(); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index f2e025ec864..b8a5198718b 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2433,6 +2433,47 @@ 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()"); + todo_wine. + 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]]; + todo_wine. + 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"); + if(desc /* todo_wine */) Object.defineProperty(Object.getPrototypeOf(obj), tests[i][1], desc); + } +}); + sync_test("console", function() { var except