From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/function.c | 36 ++++++++++++++++++----- dlls/jscript/jscript.c | 6 ++-- dlls/jscript/jscript.h | 2 +- dlls/jscript/jsdisp.idl | 2 +- dlls/mshtml/dispex.c | 49 ++++++++++++++++++++++++++----- dlls/mshtml/tests/documentmode.js | 9 ++++++ 6 files changed, 85 insertions(+), 19 deletions(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 9f1f53a96ae..c6e8929770b 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -74,6 +74,7 @@ typedef struct { typedef struct { FunctionInstance function; IWineJSDispatchHost *host_iface; + DWORD req_flags; } HostConstructor;
typedef struct { @@ -1130,6 +1131,9 @@ static HRESULT HostConstructor_call(script_ctx_t *ctx, FunctionInstance *func, j HRESULT hres = S_OK; unsigned i;
+ if((flags & function->req_flags) != function->req_flags) + return E_UNEXPECTED; + flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; if(argc > ARRAYSIZE(buf) && !(dp.rgvarg = malloc(argc * sizeof(*dp.rgvarg)))) return E_OUTOFMEMORY; @@ -1159,8 +1163,13 @@ static HRESULT HostConstructor_call(script_ctx_t *ctx, FunctionInstance *func, j return hres; }
-static HRESULT HostConstructor_toString(FunctionInstance *function, jsstr_t **ret) +static HRESULT HostConstructor_toString(FunctionInstance *func, jsstr_t **ret) { + HostConstructor *function = (HostConstructor*)func; + + if(function->req_flags) + return native_function_string(L"create", ret); + *ret = jsstr_alloc(L"\nfunction() {\n [native code]\n}\n"); return *ret ? S_OK : E_OUTOFMEMORY; } @@ -1188,7 +1197,7 @@ static const function_vtbl_t HostConstructorVtbl = { };
HRESULT init_host_constructor(script_ctx_t *ctx, IWineJSDispatchHost *host_constr, IWineJSDispatch *prototype, - IWineJSDispatch **ret) + IWineJSDispatch *method, IWineJSDispatch **ret) { HostConstructor *function; HRESULT hres; @@ -1199,11 +1208,24 @@ HRESULT init_host_constructor(script_ctx_t *ctx, IWineJSDispatchHost *host_const return hres; function->host_iface = host_constr;
- hres = jsdisp_define_data_property(&function->function.dispex, L"prototype", PROPF_WRITABLE | PROPF_CONFIGURABLE, - jsval_disp((IDispatch *)prototype)); - if(FAILED(hres)) { - IWineJSDispatch_Free(&function->function.dispex.IWineJSDispatch_iface); - return hres; + if(!prototype) + function->req_flags = DISPATCH_METHOD; + else { + hres = jsdisp_define_data_property(&function->function.dispex, L"prototype", PROPF_WRITABLE | PROPF_CONFIGURABLE, + jsval_disp((IDispatch *)prototype)); + if(FAILED(hres)) { + IWineJSDispatch_Free(&function->function.dispex.IWineJSDispatch_iface); + return hres; + } + } + + if(method) { + hres = jsdisp_define_data_property(&function->function.dispex, L"create", PROPF_WRITABLE | PROPF_CONFIGURABLE, + jsval_disp((IDispatch *)method)); + if(FAILED(hres)) { + IWineJSDispatch_Free(&function->function.dispex.IWineJSDispatch_iface); + return hres; + } }
*ret = &function->function.dispex.IWineJSDispatch_iface; diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index c42109b4143..58a414b92b3 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -1458,11 +1458,11 @@ static HRESULT WINAPI WineJScript_InitHostObject(IWineJScript *iface, IWineJSDis return init_host_object(This->ctx, host_obj, prototype, flags, ret); }
-static HRESULT WINAPI WineJScript_InitHostConstructor(IWineJScript *iface, IWineJSDispatchHost *constr, - IWineJSDispatch *prototype, IWineJSDispatch **ret) +static HRESULT WINAPI WineJScript_InitHostConstructor(IWineJScript *iface, IWineJSDispatchHost *constr, IWineJSDispatch *prototype, + IWineJSDispatch *method, IWineJSDispatch **ret) { JScript *This = impl_from_IWineJScript(iface); - return init_host_constructor(This->ctx, constr, prototype, ret); + return init_host_constructor(This->ctx, constr, prototype, method, ret); }
static const IWineJScriptVtbl WineJScriptVtbl = { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index e9207c231d8..5df78fddd41 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -241,7 +241,7 @@ HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**); HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,UINT32,IWineJSDispatch**); -HRESULT init_host_constructor(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch**); +HRESULT init_host_constructor(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch*,IWineJSDispatch**);
HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index 5f1384bce78..9aff332e4a5 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -83,5 +83,5 @@ interface IWineJSDispatchHost : IDispatchEx interface IWineJScript : IUnknown { HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret); - HRESULT InitHostConstructor(IWineJSDispatchHost *constr, IWineJSDispatch *prototype, IWineJSDispatch **ret); + HRESULT InitHostConstructor(IWineJSDispatchHost *constr, IWineJSDispatch *prototype, IWineJSDispatch *method, IWineJSDispatch **ret); } diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 6a4ca42ba5b..5fbdee27728 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -135,6 +135,8 @@ PRIVATE_TID_LIST #undef XDIID };
+static void init_dispatch_from_desc(DispatchEx*,dispex_data_t*,HTMLInnerWindow*,DispatchEx*); + static HRESULT load_typelib(void) { WCHAR module_path[MAX_PATH + 3]; @@ -1875,6 +1877,43 @@ static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode return desc->info_cache[compat_mode]; }
+static HRESULT init_host_constructor(DispatchEx *dispex, HTMLInnerWindow *script_global) +{ + object_id_t id = dispex->info->desc->constructor_id; + DispatchEx *prototype; + DISPID dispid; + HRESULT hres; + + hres = get_prototype(script_global, id, &prototype); + if(FAILED(hres)) + return hres; + + hres = get_builtin_id(dispex->info, L"create", 0, &dispid); + if(SUCCEEDED(hres)) { + struct constructor *create = malloc(sizeof(*create)); + + if(!create) + return E_OUTOFMEMORY; + create->iface = constructor_from_DispatchEx(dispex)->iface; + create->window = script_global; + IHTMLWindow2_AddRef(&script_global->base.IHTMLWindow2_iface); + + init_dispatch_from_desc(&create->dispex, object_descriptors[id]->constructor_info->info_cache[dispex->info->compat_mode], + NULL, NULL); + + hres = IWineJScript_InitHostConstructor(script_global->jscript, &create->dispex.IWineJSDispatchHost_iface, + NULL, NULL, &create->dispex.jsdisp); + if(SUCCEEDED(hres)) + hres = IWineJScript_InitHostConstructor(script_global->jscript, &dispex->IWineJSDispatchHost_iface, + prototype->jsdisp, create->dispex.jsdisp, &dispex->jsdisp); + IWineJSDispatchHost_Release(&create->dispex.IWineJSDispatchHost_iface); + }else if(hres == DISP_E_UNKNOWNNAME) { + hres = IWineJScript_InitHostConstructor(script_global->jscript, &dispex->IWineJSDispatchHost_iface, + prototype->jsdisp, NULL, &dispex->jsdisp); + } + return hres; +} + static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global, DispatchEx *prototype) { HRESULT hres; @@ -1885,13 +1924,9 @@ static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global, if(!script_global->jscript) initialize_script_global(script_global); if(script_global->jscript && !dispex->jsdisp) { - if(dispex->info->desc->constructor_id) { - DispatchEx *prototype; - if(FAILED(hres = get_prototype(script_global, dispex->info->desc->constructor_id, &prototype))) - return; - hres = IWineJScript_InitHostConstructor(script_global->jscript, &dispex->IWineJSDispatchHost_iface, - prototype->jsdisp, &dispex->jsdisp); - }else + if(dispex->info->desc->constructor_id) + hres = init_host_constructor(dispex, script_global); + else hres = IWineJScript_InitHostObject(script_global->jscript, &dispex->IWineJSDispatchHost_iface, prototype ? prototype->jsdisp : NULL, dispex->info->desc->js_flags, &dispex->jsdisp); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 55df3d746e4..2f432d2e3e3 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -4012,4 +4012,13 @@ sync_test("constructors", function() { } ok(window.Image.prototype === window.HTMLImageElement.prototype, "Image.prototype != HTMLImageElement.prototype"); ok(window.Option.prototype === window.HTMLOptionElement.prototype, "Option.prototype != HTMLOptionElement.prototype"); + + ok(XMLHttpRequest.create() instanceof XMLHttpRequest, "XMLHttpRequest.create did not return XMLHttpRequest instance"); + ok(XMLHttpRequest.create.call(Object) instanceof XMLHttpRequest, "XMLHttpRequest.create with Object 'this' did not return XMLHttpRequest instance"); + try { + new XMLHttpRequest.create(); + ok(false, "new XMLHttpRequest.create() did not throw"); + }catch(e) { + ok(e.number === 0x0ffff - 0x80000000, "new XMLHttpRequest.create() threw " + e.number); + } });