From: Gabriel Ivăncescu gabrielopcode@gmail.com
Based on a patch by Jacek Caban.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 40 +++++++++++++++++++------- dlls/jscript/function.c | 12 ++++---- dlls/jscript/jscript.h | 7 ++--- dlls/jscript/jsdisp.idl | 7 +++-- dlls/mshtml/dispex.c | 60 ++++++++++++++++++++++++++------------- dlls/mshtml/htmldoc.c | 2 +- dlls/mshtml/htmlstorage.c | 2 +- dlls/mshtml/htmlwindow.c | 8 +++--- dlls/mshtml/pluginhost.c | 2 +- dlls/mshtml/tests/es5.js | 30 +++++++++++++++++++- 10 files changed, 120 insertions(+), 50 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index a99f09776e2..91fa2c00cf4 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -270,23 +270,41 @@ static dispex_prop_t *lookup_dispex_prop(jsdisp_t *obj, unsigned hash, const WCH
static HRESULT update_external_prop(jsdisp_t *obj, dispex_prop_t *prop, const struct property_info *desc) { - if(desc->func_iid) { + HRESULT hres; + + if(!desc->iid) { + prop->type = PROP_EXTERN; + prop->u.id = desc->id; + }else if(desc->flags & PROPF_METHOD) { jsdisp_t *func; - HRESULT hres;
- hres = create_host_function(obj->ctx, desc, &func); + hres = create_host_function(obj->ctx, desc, DISPATCH_METHOD, &func); if(FAILED(hres)) return hres;
prop->type = PROP_JSVAL; - prop->flags = desc->flags; prop->u.val = jsval_obj(func); - return S_OK; + }else { + jsdisp_t *getter, *setter = NULL; + + hres = create_host_function(obj->ctx, desc, DISPATCH_PROPERTYGET, &getter); + if(FAILED(hres)) + return hres; + + if(desc->flags & PROPF_WRITABLE) { + hres = create_host_function(obj->ctx, desc, DISPATCH_PROPERTYPUT, &setter); + if(FAILED(hres)) { + jsdisp_release(getter); + return hres; + } + } + + prop->type = PROP_ACCESSOR; + prop->u.accessor.getter = getter; + prop->u.accessor.setter = setter; }
- prop->type = PROP_EXTERN; - prop->flags = desc->flags; - prop->u.id = desc->id; + prop->flags = desc->flags & PROPF_ALL; return S_OK; }
@@ -469,13 +487,14 @@ HRESULT jsdisp_index_lookup(jsdisp_t *obj, const WCHAR *name, unsigned length, s } if(*ptr) return DISP_E_UNKNOWNNAME; + desc->id = idx; desc->flags = PROPF_ENUMERABLE; if(obj->builtin_info->prop_put) desc->flags |= PROPF_WRITABLE; desc->name = NULL; desc->index = idx; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
@@ -483,13 +502,14 @@ HRESULT jsdisp_next_index(jsdisp_t *obj, unsigned length, unsigned id, struct pr { if(id + 1 == length) return S_FALSE; + desc->id = id + 1; desc->flags = PROPF_ENUMERABLE; if(obj->builtin_info->prop_put) desc->flags |= PROPF_WRITABLE; desc->name = NULL; desc->index = desc->id; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 11be56dd809..5330bbae21f 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -68,6 +68,7 @@ typedef struct { const WCHAR *name; UINT32 id; UINT32 iid; + UINT32 flags; } HostFunction;
typedef struct { @@ -1022,8 +1023,8 @@ static HRESULT HostFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsva
if(SUCCEEDED(hres)) { V_VT(&retv) = VT_EMPTY; - hres = IWineJSDispatchHost_CallFunction(obj, function->id, function->iid, &dp, r ? &retv : NULL, &ei, - &ctx->jscaller->IServiceProvider_iface); + hres = IWineJSDispatchHost_CallFunction(obj, function->id, function->iid, function->flags, &dp, + r ? &retv : NULL, &ei, &ctx->jscaller->IServiceProvider_iface); if(hres == DISP_E_EXCEPTION) handle_dispatch_exception(ctx, &ei); if(SUCCEEDED(hres) && r) { @@ -1068,7 +1069,7 @@ static const function_vtbl_t HostFunctionVtbl = { HostFunction_gc_traverse };
-HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc, jsdisp_t **ret) +HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc, DWORD flags, jsdisp_t **ret) { HostFunction *function; HRESULT hres; @@ -1083,7 +1084,8 @@ HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc
function->name = desc->name; function->id = desc->id; - function->iid = desc->func_iid; + function->iid = desc->iid; + function->flags = flags; *ret = &function->function.dispex; return S_OK; } @@ -1104,7 +1106,7 @@ static HRESULT HostConstructor_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, { HostConstructor *constr = (HostConstructor*)jsdisp; HRESULT hres = IWineJSDispatchHost_LookupProperty(constr->host_iface, name, flags, desc); - assert(hres != S_OK || desc->func_iid); /* external properties are not allowed */ + assert(hres != S_OK || (desc->flags & PROPF_METHOD)); /* external properties are not allowed */ return hres; }
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 3d3d0f8a6c9..e9207c231d8 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -76,12 +76,9 @@ typedef struct jsdisp_t jsdisp_t; extern HINSTANCE jscript_hinstance ; HRESULT get_dispatch_typeinfo(ITypeInfo**);
-#define PROPF_ARGMASK 0x00ff -#define PROPF_METHOD 0x0100 -#define PROPF_CONSTR 0x0200 - #define PROPF_ALL (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE)
+#define PROPF_ARGMASK 0x000000ff #define PROPF_VERSION_MASK 0x01ff0000 #define PROPF_VERSION_SHIFT 16 #define PROPF_HTML (SCRIPTLANGUAGEVERSION_HTML << PROPF_VERSION_SHIFT) @@ -281,7 +278,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons jsdisp_t*,jsdisp_t**); HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**); -HRESULT create_host_function(script_ctx_t*,const struct property_info*,jsdisp_t**); +HRESULT create_host_function(script_ctx_t*,const struct property_info*,DWORD,jsdisp_t**); HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*);
HRESULT Function_value(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index bae00d40a3d..051f819e817 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -27,9 +27,12 @@ struct property_info UINT32 flags; const WCHAR *name; UINT32 index; - UINT32 func_iid; + UINT32 iid; };
+const unsigned int PROPF_METHOD = 0x0100; +const unsigned int PROPF_CONSTR = 0x0200; + const unsigned int PROPF_ENUMERABLE = 0x0400; const unsigned int PROPF_WRITABLE = 0x0800; const unsigned int PROPF_CONFIGURABLE = 0x1000; @@ -65,7 +68,7 @@ interface IWineJSDispatchHost : IDispatchEx HRESULT SetProperty(DISPID id, LCID lcid, VARIANT *v, EXCEPINFO *ei, IServiceProvider *caller); HRESULT DeleteProperty(DISPID id); HRESULT ConfigureProperty(DISPID id, UINT32 flags); - HRESULT CallFunction(DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT CallFunction(DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); HRESULT Construct(LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); HRESULT GetOuterDispatch(IWineJSDispatchHost **ret); HRESULT ToString(BSTR *str); diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 35f4be50ea8..9d69f413d44 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -285,10 +285,6 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, BSTR name; HRESULT hres;
- /* FIXME: Expose non-function properties from prototypes too (requires support for accessor properties). */ - if(data->is_prototype && !(desc->invkind & DISPATCH_METHOD)) - return; - if(name_override) name = SysAllocString(name_override); else if(desc->wFuncFlags & FUNCFLAG_FRESTRICTED) @@ -1054,7 +1050,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI } }
- hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, ¶ms, res, ei, caller); + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller);
fail: while(argc--) @@ -1081,7 +1077,7 @@ static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIA if(FAILED(hres)) return CTL_E_ILLEGALFUNCTIONCALL;
- hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, ¶ms, res, ei, caller); + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); IWineJSDispatchHost_Release(this_iface); return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; } @@ -1158,7 +1154,7 @@ static HRESULT function_get_prop_desc(DispatchEx *dispex, DISPID id, struct prop desc->id = id; desc->flags = 0; desc->name = function_props[idx].name; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
@@ -2526,7 +2522,7 @@ HRESULT dispex_index_prop_desc(DispatchEx *dispex, DISPID id, struct property_in desc->flags |= PROPF_ENUMERABLE; desc->name = NULL; desc->index = id - MSHTML_DISPID_CUSTOM_MIN; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
@@ -2543,14 +2539,22 @@ static HRESULT get_host_property_descriptor(DispatchEx *This, DISPID id, struct hres = get_builtin_func(This->info, id, &func); if(FAILED(hres)) return hres; - desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; + desc->flags = PROPF_CONFIGURABLE; desc->name = func->name; - if(func->func_disp_idx < 0) { - if(func->func_disp_idx == -1) - desc->flags |= PROPF_ENUMERABLE; - desc->func_iid = 0; + if(func->func_disp_idx >= 0) { + desc->iid = func->tid; + desc->flags |= PROPF_METHOD | PROPF_WRITABLE; }else { - desc->func_iid = func->tid; + if(func->func_disp_idx == -1) + desc->flags |= PROPF_ENUMERABLE; + if(This->info->is_prototype) { + desc->iid = func->tid; + if(func->put_vtbl_off) + desc->flags |= PROPF_WRITABLE; + }else { + desc->flags |= PROPF_WRITABLE; + desc->iid = 0; + } } break; } @@ -2558,7 +2562,7 @@ static HRESULT get_host_property_descriptor(DispatchEx *This, DISPID id, struct dynamic_prop_t *prop = &This->dynamic_data->props[id - DISPID_DYNPROP_0]; desc->flags = prop->flags & PROPF_PUBLIC_MASK; desc->name = prop->name; - desc->func_iid = 0; + desc->iid = 0; break; } case DISPEXPROP_CUSTOM: @@ -2645,19 +2649,35 @@ static HRESULT WINAPI JSDispatchHost_ConfigureProperty(IWineJSDispatchHost *ifac return S_OK; }
-static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, - EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DWORD flags, + DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); func_info_t *func; HRESULT hres;
- TRACE("%s (%p)->(%lx %x %p %p %p %p)\n", This->info->name, This, id, iid, dp, ret, ei, caller); + TRACE("%s (%p)->(%lx %x %lx %p %p %p %p)\n", This->info->name, This, id, iid, flags, dp, ret, ei, caller);
hres = get_builtin_func(This->info, id, &func); - if(FAILED(hres) || func->tid != iid || func->func_disp_idx < 0) + if(FAILED(hres) || func->tid != iid) return E_UNEXPECTED; - return call_builtin_function(This, func, dp, ret, ei, caller); + + switch(flags) { + case DISPATCH_METHOD: + assert(func->func_disp_idx >= 0); + return call_builtin_function(This, func, dp, ret, ei, caller); + case DISPATCH_PROPERTYGET: + assert(func->get_vtbl_off); + return builtin_propget(This, func, dp, ret, ei, caller); + case DISPATCH_PROPERTYPUT: + assert(func->put_vtbl_off); + if(ret) + V_VT(ret) = VT_EMPTY; + return builtin_propput(This, func, dp, ei, caller); + default: + assert(0); + return E_FAIL; + } }
static HRESULT WINAPI JSDispatchHost_Construct(IWineJSDispatchHost *iface, LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 260264642b2..70bc028f3a0 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5530,7 +5530,7 @@ static HRESULT HTMLDocumentNode_get_prop_desc(DispatchEx *dispex, DISPID id, str desc->name = This->elem_vars[idx]; desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 2ce8b951c20..8fb5679089a 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -1274,7 +1274,7 @@ static HRESULT HTMLStorage_get_prop_desc(DispatchEx *dispex, DISPID id, struct p desc->name = This->props[id - MSHTML_DISPID_CUSTOM_MIN]; desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index ccb593724d4..a4039ce08bc 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3473,13 +3473,13 @@ static HRESULT WINAPI WindowDispEx_ConfigureProperty(IWineJSDispatchHost *iface, return IWineJSDispatchHost_ConfigureProperty(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id, flags); }
-static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, - EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, + VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) { HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IWineJSDispatchHost_CallFunction(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, - id, iid, dp, ret, ei, caller); + id, iid, flags, dp, ret, ei, caller); }
static HRESULT WINAPI WindowDispEx_Construct(IWineJSDispatchHost *iface, LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, @@ -3981,7 +3981,7 @@ HRESULT HTMLWindow_get_prop_desc(DispatchEx *dispex, DISPID id, struct property_ desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; if(prop->type == GLOBAL_DISPEXVAR) desc->flags |= PROPF_ENUMERABLE; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
diff --git a/dlls/mshtml/pluginhost.c b/dlls/mshtml/pluginhost.c index 5479e25b0b8..c4a580ea4eb 100644 --- a/dlls/mshtml/pluginhost.c +++ b/dlls/mshtml/pluginhost.c @@ -835,7 +835,7 @@ HRESULT HTMLPluginContainer_get_prop_desc(DispatchEx *dispex, DISPID id, struct desc->id = id; desc->flags = 0; desc->name = plugin_container->props[id - MSHTML_DISPID_CUSTOM_MIN]->name; - desc->func_iid = 0; + desc->iid = 0; return S_OK; }
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 7496ea4c395..18b106e2a82 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2661,6 +2661,20 @@ sync_test("screen", function() { ok(Object.isFrozen(o) === false, "Object.isFrozen(o) = " + Object.isFrozen(o)); ok(Object.isSealed(o) === true, "Object.isSealed(o) = " + Object.isSealed(o));
+ ok(!o.hasOwnProperty("width"), 'o.hasOwnProperty("width") = ' + o.hasOwnProperty("width")); + ok(Screen.prototype.hasOwnProperty("width"), + 'Screen.prototype.hasOwnProperty("width") = ' + Screen.prototype.hasOwnProperty("width")); + + var desc = Object.getOwnPropertyDescriptor(Screen.prototype, "width"); + ok(!("value" in desc), "width prop: value is in desc"); + ok(!("writable" in desc), "width prop: writable is in desc"); + ok(desc.enumerable === true, "width prop: enumerable = " + desc.enumerable); + ok(desc.configurable === true, "width prop: configurable = " + desc.configurable); + ok(Object.getPrototypeOf(desc.get) === Function.prototype, "width prop: get not a function: " + desc.get); + ok("set" in desc, "width prop: set is not in desc"); + ok(desc.set === undefined, "width prop: set not undefined: " + desc.set); + ok(desc.get.call(o) === o.width, "width prop: get.call() not same as o.width: " + desc.get.call(o) + ", expected " + o.width); + o.prop2 = 3; ok(!("prop2" in o), "o.prop2 = " + o.prop2);
@@ -2672,7 +2686,7 @@ sync_test("screen", function() { });
sync_test("builtin_func", function() { - var o = document.implementation; + var o = document.implementation, r; var f = o.hasFeature;
ok(f instanceof Function, "f is not an instance of Function"); @@ -2681,6 +2695,20 @@ sync_test("builtin_func", function() { ok(f.length === 0, "f.length = " + f.length); ok(f.call(o, "test", 1) === false, 'f.call(o, "test", 1) = ' + f.call(o, "test", 1)); ok("" + f === "\nfunction hasFeature() {\n [native code]\n}\n", "f = " + f); + + o = document.body; + var desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Object.getPrototypeOf(o)), "innerHTML"); + ok(!("value" in desc), "innerHTML prop: value is in desc"); + ok(!("writable" in desc), "innerHTML prop: writable is in desc"); + ok(desc.enumerable === true, "innerHTML prop: enumerable = " + desc.enumerable); + ok(desc.configurable === true, "innerHTML prop: configurable = " + desc.configurable); + ok(Object.getPrototypeOf(desc.get) === Function.prototype, "innerHTML prop: get not a function: " + desc.get); + ok(Object.getPrototypeOf(desc.set) === Function.prototype, "innerHTML prop: set not a function: " + desc.set); + r = desc.set.call(o, '<div id="winetest"></div>'); + ok(r === undefined, "innerHTML prop: setter returned " + r); + r = desc.get.call(o); + ok(r === '<div id="winetest"></div>', "innerHTML prop: getter returned " + r); + ok(r === o.innerHTML, "innerHTML prop: getter not same as o.innerHTML: " + r + ", expected " + o.innerHTML); });
async_test("script_global", function() {