The mapping between DISPID and index into props has to be adjusted since the value_prop (props[0]) is now gone.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
All !prop->name checks have been removed since there are no props without a name anymore. I also removed redundant prop->type == PROP_DELETED checks after get_prop, since get_prop already checks that, and it touched the same code.
dlls/jscript/dispex.c | 81 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 42 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index a00e36b..8937136 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -80,16 +80,19 @@ static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop)
static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop) { - return prop - This->props; + /* don't overlap with DISPID_VALUE */ + return prop - This->props + 1; }
static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) { - if(id < 0 || id >= This->prop_cnt) + DWORD idx = id - 1; + + if(idx >= This->prop_cnt) return NULL; - fix_protref_prop(This, &This->props[id]); + fix_protref_prop(This, &This->props[idx]);
- return This->props[id].type == PROP_DELETED ? NULL : &This->props[id]; + return This->props[idx].type == PROP_DELETED ? NULL : &This->props[idx]; }
static inline BOOL is_function_prop(dispex_prop_t *prop) @@ -189,7 +192,7 @@ static inline HRESULT resize_props(jsdisp_t *This) This->props[i].bucket_next = ~0; }
- for(i=1; i<This->prop_cnt; i++) { + for(i=0; i<This->prop_cnt; i++) { props = This->props+i;
bucket = get_props_idx(This, props->hash); @@ -547,26 +550,22 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
switch(prop->type) { case PROP_BUILTIN: { + vdisp_t vthis; + if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) { WARN("%s is not a constructor\n", debugstr_w(prop->name)); return E_INVALIDARG; }
- if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) { - vdisp_t vthis; + if(This->builtin_info->class != JSCLASS_FUNCTION && prop->u.p->invoke != JSGlobal_eval) + flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; + if(jsthis) + set_disp(&vthis, jsthis); + else + set_jsdisp(&vthis, This); + hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r); + vdisp_release(&vthis);
- if(This->builtin_info->class != JSCLASS_FUNCTION && prop->u.p->invoke != JSGlobal_eval) - flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - if(jsthis) - set_disp(&vthis, jsthis); - else - set_jsdisp(&vthis, This); - hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r); - vdisp_release(&vthis); - }else { - /* Function object calls are special case */ - hres = Function_invoke(This, jsthis, flags, argc, argv, r); - } return hres; } case PROP_PROTREF: @@ -629,8 +628,6 @@ static HRESULT fill_protrefs(jsdisp_t *This) fill_protrefs(This->prototype);
for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - if(!iter->name) - continue; hres = find_prop_name(This, iter->hash, iter->name, &prop); if(FAILED(hres)) return hres; @@ -1422,7 +1419,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC
for (prop = This->props, end = prop + This->prop_cnt; prop != end; prop++) { - if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + if (prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) continue;
/* If two identifiers differ only by case, the TypeInfo fails */ @@ -1477,7 +1474,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC typevar = typeinfo->vars; for (prop = This->props; prop != end; prop++) { - if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + if (prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) continue;
if (is_function_prop(prop)) @@ -1572,12 +1569,10 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc V_VT(pvarRes) = VT_EMPTY;
prop = get_prop(This, id); - if(!prop || prop->type == PROP_DELETED) { + if(!prop && id != DISPID_VALUE) { TRACE("invalid id\n"); return DISP_E_MEMBERNOTFOUND; } - if(id == DISPID_VALUE && wFlags & (DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT)) - prop = NULL;
enter_script(This->ctx, &ei);
@@ -1594,7 +1589,11 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(FAILED(hres)) break;
- hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); + if(prop) + hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); + else + hres = jsdisp_call_value(This, get_this(pdp), wFlags, argc, argv, pvarRes ? &r : NULL); + if(argv != buf) heap_free(argv); if(SUCCEEDED(hres) && pvarRes) { @@ -1738,7 +1737,7 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BS TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
prop = get_prop(This, id); - if(!prop || !prop->name || prop->type == PROP_DELETED) + if(!prop) return DISP_E_MEMBERNOTFOUND;
*pbstrName = SysAllocString(prop->name); @@ -1751,11 +1750,12 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BS static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) { jsdisp_t *This = impl_from_IDispatchEx(iface); - HRESULT hres; + HRESULT hres = S_FALSE;
TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
- hres = jsdisp_next_prop(This, id, JSDISP_ENUM_ALL, pid); + if(id != DISPID_VALUE) + hres = jsdisp_next_prop(This, id, JSDISP_ENUM_ALL, pid); if(hres == S_FALSE) *pid = DISPID_STARTENUM; return hres; @@ -1807,6 +1807,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b dispex->ref = 1; dispex->builtin_info = builtin_info; dispex->extensible = TRUE; + dispex->prop_cnt = 0;
dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4)); if(!dispex->props) @@ -1821,14 +1822,6 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b if(prototype) jsdisp_addref(prototype);
- dispex->prop_cnt = 1; - if(builtin_info->value_prop.invoke || builtin_info->value_prop.getter) { - dispex->props[0].type = PROP_BUILTIN; - dispex->props[0].u.p = &builtin_info->value_prop; - }else { - dispex->props[0].type = PROP_DELETED; - } - script_addref(ctx); dispex->ctx = ctx;
@@ -2446,6 +2439,7 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_type, DISPID *ret) { dispex_prop_t *iter; + DWORD idx = id - 1; HRESULT hres;
if(id == DISPID_STARTENUM && enum_type == JSDISP_ENUM_ALL) { @@ -2454,11 +2448,14 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty return hres; }
- if(id + 1 < 0 || id+1 >= obj->prop_cnt) + if(id == DISPID_STARTENUM) + idx = -1; + + if(idx + 1 >= obj->prop_cnt) return S_FALSE;
- for(iter = &obj->props[id + 1]; iter < obj->props + obj->prop_cnt; iter++) { - if(!iter->name || iter->type == PROP_DELETED) + for(iter = &obj->props[idx + 1]; iter < obj->props + obj->prop_cnt; iter++) { + if(iter->type == PROP_DELETED) continue; if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF) continue; @@ -2765,7 +2762,7 @@ HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r) { dispex_prop_t *prop = get_prop(obj, id);
- if(!prop || !prop->name || prop->type == PROP_DELETED) + if(!prop) return DISP_E_MEMBERNOTFOUND;
*r = jsstr_alloc(prop->name);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/array.c | 15 +++------------ dlls/jscript/bool.c | 4 ++-- dlls/jscript/date.c | 13 +++---------- dlls/jscript/dispex.c | 6 +++--- dlls/jscript/enumerator.c | 6 +++--- dlls/jscript/error.c | 4 ++-- dlls/jscript/function.c | 6 +++--- dlls/jscript/global.c | 2 +- dlls/jscript/jscript.c | 2 +- dlls/jscript/jscript.h | 3 +-- dlls/jscript/json.c | 2 +- dlls/jscript/jsregexp.c | 6 +++--- dlls/jscript/math.c | 2 +- dlls/jscript/number.c | 14 ++------------ dlls/jscript/object.c | 20 +++----------------- dlls/jscript/set.c | 8 ++++---- dlls/jscript/string.c | 16 +++------------- dlls/jscript/vbarray.c | 2 +- 18 files changed, 40 insertions(+), 91 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 7941031..5f61f99 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1222,15 +1222,6 @@ static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi return S_OK; }
-static HRESULT Array_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - ArrayInstance *array = array_from_jsdisp(jsthis); - - TRACE("\n"); - - return array_join(ctx, &array->dispex, array->length, L",", 1, r); -} - static void Array_destructor(jsdisp_t *dispex) { heap_free(dispex); @@ -1279,7 +1270,7 @@ static const builtin_prop_t Array_props[] = {
static const builtin_info_t Array_info = { JSCLASS_ARRAY, - {NULL, NULL,0, Array_get_value}, + NULL, ARRAY_SIZE(Array_props), Array_props, Array_destructor, @@ -1292,7 +1283,7 @@ static const builtin_prop_t ArrayInst_props[] = {
static const builtin_info_t ArrayInst_info = { JSCLASS_ARRAY, - {NULL, NULL,0, Array_get_value}, + NULL, ARRAY_SIZE(ArrayInst_props), ArrayInst_props, Array_destructor, @@ -1397,7 +1388,7 @@ static const builtin_prop_t ArrayConstr_props[] = {
static const builtin_info_t ArrayConstr_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(ArrayConstr_props), ArrayConstr_props, NULL, diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c index 44a8b72..184d8d0 100644 --- a/dlls/jscript/bool.c +++ b/dlls/jscript/bool.c @@ -114,7 +114,7 @@ static const builtin_prop_t Bool_props[] = {
static const builtin_info_t Bool_info = { JSCLASS_BOOLEAN, - {NULL, Bool_value, 0}, + Bool_value, ARRAY_SIZE(Bool_props), Bool_props, NULL, @@ -123,7 +123,7 @@ static const builtin_info_t Bool_info = {
static const builtin_info_t BoolInst_info = { JSCLASS_BOOLEAN, - {NULL, Bool_value, 0}, + Bool_value, 0, NULL, NULL, NULL diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index 96d366c..b130c83 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -1846,13 +1846,6 @@ static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi return S_OK; }
-static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - TRACE("\n"); - - return dateobj_to_string(date_from_jsdisp(jsthis), r); -} - static const builtin_prop_t Date_props[] = { {L"getDate", Date_getDate, PROPF_METHOD}, {L"getDay", Date_getDay, PROPF_METHOD}, @@ -1903,7 +1896,7 @@ static const builtin_prop_t Date_props[] = {
static const builtin_info_t Date_info = { JSCLASS_DATE, - {NULL, NULL,0, Date_get_value}, + NULL, ARRAY_SIZE(Date_props), Date_props, NULL, @@ -1912,7 +1905,7 @@ static const builtin_info_t Date_info = {
static const builtin_info_t DateInst_info = { JSCLASS_DATE, - {NULL, NULL,0, Date_get_value}, + NULL, 0, NULL, NULL, NULL @@ -2440,7 +2433,7 @@ static const builtin_prop_t DateConstr_props[] = {
static const builtin_info_t DateConstr_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(DateConstr_props), DateConstr_props, NULL, diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 8937136..3b4e970 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1830,7 +1830,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b
static const builtin_info_t dispex_info = { JSCLASS_NONE, - {NULL, NULL, 0}, + NULL, 0, NULL, NULL, NULL @@ -1981,14 +1981,14 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsig }else { vdisp_t vdisp;
- if(!jsfunc->builtin_info->value_prop.invoke) { + if(!jsfunc->builtin_info->call) { WARN("Not a function\n"); return JS_E_FUNCTION_EXPECTED; }
set_disp(&vdisp, jsthis); flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r); + hres = jsfunc->builtin_info->call(jsfunc->ctx, &vdisp, flags, argc, argv, r); vdisp_release(&vdisp); } return hres; diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index dea1940..038b474 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -180,7 +180,7 @@ static const builtin_prop_t Enumerator_props[] = {
static const builtin_info_t Enumerator_info = { JSCLASS_ENUMERATOR, - {NULL, NULL, 0}, + NULL, ARRAY_SIZE(Enumerator_props), Enumerator_props, NULL, @@ -189,7 +189,7 @@ static const builtin_info_t Enumerator_info = {
static const builtin_info_t EnumeratorInst_info = { JSCLASS_ENUMERATOR, - {NULL, NULL, 0, NULL}, + NULL, 0, NULL, Enumerator_destructor, @@ -317,7 +317,7 @@ static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD fl
static const builtin_info_t EnumeratorConstr_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, 0, NULL, NULL, diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index bb9e5a2..49adaeb 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -136,7 +136,7 @@ static const builtin_prop_t Error_props[] = {
static const builtin_info_t Error_info = { JSCLASS_ERROR, - {NULL, Error_value, 0}, + Error_value, ARRAY_SIZE(Error_props), Error_props, NULL, @@ -145,7 +145,7 @@ static const builtin_info_t Error_info = {
static const builtin_info_t ErrorInst_info = { JSCLASS_ERROR, - {NULL, Error_value, 0}, + Error_value, 0, NULL, NULL, diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 318d6be..3eef1aa 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -172,7 +172,7 @@ static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
static const builtin_info_t Arguments_info = { JSCLASS_ARGUMENTS, - {NULL, Arguments_value, 0}, + Arguments_value, 0, NULL, Arguments_destructor, NULL, @@ -545,7 +545,7 @@ static const builtin_prop_t Function_props[] = {
static const builtin_info_t Function_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(Function_props), Function_props, Function_destructor, @@ -559,7 +559,7 @@ static const builtin_prop_t FunctionInst_props[] = {
static const builtin_info_t FunctionInst_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(FunctionInst_props), FunctionInst_props, Function_destructor, diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 2665bec..c9a00d1 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -904,7 +904,7 @@ static const builtin_prop_t JSGlobal_props[] = {
static const builtin_info_t JSGlobal_info = { JSCLASS_GLOBAL, - {NULL, NULL, 0}, + NULL, ARRAY_SIZE(JSGlobal_props), JSGlobal_props, NULL, diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 9148451..160269c 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -112,7 +112,7 @@ HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item) { static const builtin_info_t disp_info = { JSCLASS_GLOBAL, - {NULL, NULL, 0}, + NULL, 0, NULL, NULL, NULL diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 69897cd..c192ec7 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -232,7 +232,7 @@ typedef struct {
typedef struct { jsclass_t class; - builtin_prop_t value_prop; + builtin_invoke_t call; DWORD props_cnt; const builtin_prop_t *props; void (*destructor)(jsdisp_t*); @@ -340,7 +340,6 @@ HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DE HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT Function_get_value(script_ctx_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN; struct _function_code_t *Function_get_code(jsdisp_t*) DECLSPEC_HIDDEN; -#define DEFAULT_FUNCTION_VALUE {NULL, Function_value,0, Function_get_value}
HRESULT throw_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; jsdisp_t *create_builtin_error(script_ctx_t *ctx) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index f2fbb80..d3896ca 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -839,7 +839,7 @@ static const builtin_prop_t JSON_props[] = {
static const builtin_info_t JSON_info = { JSCLASS_JSON, - {NULL, NULL, 0}, + NULL, ARRAY_SIZE(JSON_props), JSON_props, NULL, diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index f80452d..cb6c051 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -563,7 +563,7 @@ static const builtin_prop_t RegExp_props[] = {
static const builtin_info_t RegExp_info = { JSCLASS_REGEXP, - {NULL, RegExp_value, 0}, + RegExp_value, ARRAY_SIZE(RegExp_props), RegExp_props, RegExp_destructor, @@ -580,7 +580,7 @@ static const builtin_prop_t RegExpInst_props[] = {
static const builtin_info_t RegExpInst_info = { JSCLASS_REGEXP, - {NULL, RegExp_value, 0}, + RegExp_value, ARRAY_SIZE(RegExpInst_props), RegExpInst_props, RegExp_destructor, @@ -952,7 +952,7 @@ static const builtin_prop_t RegExpConstr_props[] = {
static const builtin_info_t RegExpConstr_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(RegExpConstr_props), RegExpConstr_props, NULL, diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c index 475b9b2..c65bbaf 100644 --- a/dlls/jscript/math.c +++ b/dlls/jscript/math.c @@ -492,7 +492,7 @@ static const builtin_prop_t Math_props[] = {
static const builtin_info_t Math_info = { JSCLASS_MATH, - {NULL, NULL, 0}, + NULL, ARRAY_SIZE(Math_props), Math_props, NULL, diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index 3c96532..410f27b 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -494,16 +494,6 @@ static HRESULT Number_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un return S_OK; }
-static HRESULT Number_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - NumberInstance *number = number_from_jsdisp(jsthis); - - TRACE("(%p)\n", number); - - *r = jsval_number(number->value); - return S_OK; -} - static const builtin_prop_t Number_props[] = { {L"toExponential", Number_toExponential, PROPF_METHOD|1}, {L"toFixed", Number_toFixed, PROPF_METHOD}, @@ -515,7 +505,7 @@ static const builtin_prop_t Number_props[] = {
static const builtin_info_t Number_info = { JSCLASS_NUMBER, - {NULL, NULL,0, Number_get_value}, + NULL, ARRAY_SIZE(Number_props), Number_props, NULL, @@ -524,7 +514,7 @@ static const builtin_info_t Number_info = {
static const builtin_info_t NumberInst_info = { JSCLASS_NUMBER, - {NULL, NULL,0, Number_get_value}, + NULL, 0, NULL, NULL, NULL diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 89684f5..24692f8 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -243,20 +243,6 @@ static HRESULT Object_set_proto_(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t va return jsdisp_change_prototype(jsthis, proto); }
-static HRESULT Object_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - jsstr_t *ret; - - TRACE("\n"); - - ret = jsstr_alloc(L"[object Object]"); - if(!ret) - return E_OUTOFMEMORY; - - *r = jsval_string(ret); - return S_OK; -} - static void Object_destructor(jsdisp_t *dispex) { heap_free(dispex); @@ -274,7 +260,7 @@ static const builtin_prop_t Object_props[] = {
static const builtin_info_t Object_info = { JSCLASS_OBJECT, - {NULL, NULL,0, Object_get_value}, + NULL, ARRAY_SIZE(Object_props), Object_props, Object_destructor, @@ -283,7 +269,7 @@ static const builtin_info_t Object_info = {
static const builtin_info_t ObjectInst_info = { JSCLASS_OBJECT, - {NULL, NULL,0, Object_get_value}, + NULL, 0, NULL, Object_destructor, NULL @@ -889,7 +875,7 @@ static const builtin_prop_t ObjectConstr_props[] = {
static const builtin_info_t ObjectConstr_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(ObjectConstr_props), ObjectConstr_props, NULL, diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 8f355f4..5ae41d8 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -89,7 +89,7 @@ static const builtin_prop_t Set_props[] = {
static const builtin_info_t Set_prototype_info = { JSCLASS_SET, - {NULL, Set_value, 0}, + Set_value, ARRAY_SIZE(Set_props), Set_props, NULL, @@ -98,7 +98,7 @@ static const builtin_info_t Set_prototype_info = {
static const builtin_info_t Set_info = { JSCLASS_SET, - {NULL, Set_value, 0}, + Set_value, 0, NULL, NULL, NULL @@ -414,7 +414,7 @@ static const builtin_prop_t Map_props[] = {
static const builtin_info_t Map_prototype_info = { JSCLASS_OBJECT, - {NULL, Map_value, 0}, + Map_value, ARRAY_SIZE(Map_prototype_props), Map_prototype_props, NULL, @@ -423,7 +423,7 @@ static const builtin_info_t Map_prototype_info = {
static const builtin_info_t Map_info = { JSCLASS_MAP, - {NULL, Map_value, 0}, + Map_value, ARRAY_SIZE(Map_props), Map_props, Map_destructor, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 4f6d8cd..5958216 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1493,16 +1493,6 @@ static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla return E_NOTIMPL; }
-static HRESULT String_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - StringInstance *This = string_from_jsdisp(jsthis); - - TRACE("\n"); - - *r = jsval_string(jsstr_addref(This->str)); - return S_OK; -} - static void String_destructor(jsdisp_t *dispex) { StringInstance *This = string_from_jsdisp(dispex); @@ -1579,7 +1569,7 @@ static const builtin_prop_t String_props[] = {
static const builtin_info_t String_info = { JSCLASS_STRING, - {NULL, NULL,0, String_get_value}, + NULL, ARRAY_SIZE(String_props), String_props, String_destructor, @@ -1592,7 +1582,7 @@ static const builtin_prop_t StringInst_props[] = {
static const builtin_info_t StringInst_info = { JSCLASS_STRING, - {NULL, NULL,0, String_get_value}, + NULL, ARRAY_SIZE(StringInst_props), StringInst_props, String_destructor, @@ -1710,7 +1700,7 @@ static const builtin_prop_t StringConstr_props[] = {
static const builtin_info_t StringConstr_info = { JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, + Function_value, ARRAY_SIZE(StringConstr_props), StringConstr_props, NULL, diff --git a/dlls/jscript/vbarray.c b/dlls/jscript/vbarray.c index 69a77f1..41faa20 100644 --- a/dlls/jscript/vbarray.c +++ b/dlls/jscript/vbarray.c @@ -251,7 +251,7 @@ static const builtin_prop_t VBArray_props[] = {
static const builtin_info_t VBArray_info = { JSCLASS_VBARRAY, - {NULL, VBArray_value, 0}, + VBArray_value, ARRAY_SIZE(VBArray_props), VBArray_props, VBArray_destructor,
Some javascript libraries such as prototype.js use this (by setting to an array) to examine setAttribute quirks.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/nsembed.c | 3 +- dlls/mshtml/tests/documentmode.js | 77 +++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index 4224d6a..25ad92d 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -1013,7 +1013,8 @@ HRESULT variant_to_nsstr(VARIANT *v, BOOL hex_int, nsAString *nsstr) nsAString_Init(nsstr, buf); break;
- case VT_R8: { + case VT_R8: + case VT_DISPATCH: { VARIANT strv; HRESULT hres;
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 041025c..08fcde4 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1088,6 +1088,72 @@ sync_test("elem_attr", function() { r = elem.getAttribute("className"); ok(r === "cls3", "className attr = " + r);
+ var arr = [3]; + elem.setAttribute("testattr", arr); + r = elem.getAttribute("testattr"); + ok(r === (v < 8 ? arr : "3"), "testattr = " + r); + todo_wine_if(v === 8). + ok(elem.testattr === (v < 9 ? arr : undefined), "elem.testattr = " + elem.testattr); + r = elem.removeAttribute("testattr"); + ok(r === (v < 9 ? true : undefined), "testattr removeAttribute returned " + r); + ok(elem.testattr === undefined, "removed testattr = " + elem.testattr); + + arr[0] = 9; + elem.setAttribute("testattr", "string"); + elem.testattr = arr; + r = elem.getAttribute("testattr"); + todo_wine_if(v === 8). + ok(r === (v < 8 ? arr : (v < 9 ? "9" : "string")), "testattr = " + r); + ok(elem.testattr === arr, "elem.testattr = " + elem.testattr); + arr[0] = 3; + r = elem.getAttribute("testattr"); + todo_wine_if(v === 8). + ok(r === (v < 8 ? arr : (v < 9 ? "3" : "string")), "testattr = " + r); + ok(elem.testattr === arr, "elem.testattr = " + elem.testattr); + r = elem.removeAttribute("testattr"); + ok(r === (v < 9 ? true : undefined), "testattr removeAttribute returned " + r); + todo_wine_if(v === 8). + ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr = " + elem.testattr); + + arr.toString = function() { return 42; } + elem.testattr = arr; + r = elem.getAttribute("testattr"); + todo_wine_if(v === 8). + ok(r === (v < 8 ? arr : (v < 9 ? "42" : null)), "testattr with custom toString = " + r); + elem.setAttribute("testattr", arr); + r = elem.getAttribute("testattr"); + ok(r === (v < 8 ? arr : "42"), "testattr after setAttribute with custom toString = " + r); + ok(elem.testattr === arr, "elem.testattr after setAttribute with custom toString = " + elem.testattr); + r = elem.removeAttribute("testattr"); + ok(r === (v < 9 ? true : undefined), "testattr removeAttribute with custom toString returned " + r); + todo_wine_if(v === 8). + ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr with custom toString = " + elem.testattr); + + arr.valueOf = function() { return "arrval"; } + elem.testattr = arr; + r = elem.getAttribute("testattr"); + todo_wine_if(v === 8). + ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); + elem.setAttribute("testattr", arr); + r = elem.getAttribute("testattr"); + todo_wine_if(v >= 10). + ok(r === (v < 8 ? arr : (v < 10 ? "arrval" : "42")), "testattr after setAttribute with custom valueOf = " + r); + ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); + r = elem.removeAttribute("testattr"); + ok(r === (v < 9 ? true : undefined), "testattr removeAttribute with custom valueOf returned " + r); + todo_wine_if(v === 8). + ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr with custom valueOf = " + elem.testattr); + delete arr.valueOf; + delete arr.toString; + + elem.setAttribute("id", arr); + r = elem.getAttribute("id"); + todo_wine_if(v >= 8 && v < 10). + ok(r === (v < 8 || v >= 10 ? "3" : "[object]"), "id = " + r); + r = elem.removeAttribute("id"); + ok(r === (v < 9 ? true : undefined), "id removeAttribute returned " + r); + ok(elem.id === "", "removed id = " + elem.id); + var func = function() { }; elem.onclick = func; ok(elem.onclick === func, "onclick = " + elem.onclick); @@ -1136,6 +1202,17 @@ sync_test("elem_attr", function() { todo_wine_if(v >= 8). ok(elem.onclick === null, "removed onclick = " + elem.onclick);
+ elem.setAttribute("ondblclick", arr); + r = elem.getAttribute("ondblclick"); + todo_wine_if(v >= 8 && v < 10). + ok(r === (v < 8 ? arr : (v < 10 ? "[object]" : "3")), "ondblclick = " + r); + r = elem.removeAttribute("ondblclick"); + ok(r === (v < 8 ? false : (v < 9 ? true : undefined)), "ondblclick removeAttribute returned " + r); + r = Object.prototype.toString.call(elem.ondblclick); + todo_wine_if(v >= 9). + ok(r === (v < 8 ? "[object Array]" : (v < 9 ? "[object Object]" : (v < 11 ? "[object Null]" : "[object Function]"))), + "removed ondblclick Object.toString returned " + r); + elem.setAttribute("ondblclick", "string"); r = elem.getAttribute("ondblclick"); ok(r === "string", "ondblclick string = " + r);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102715
Your paranoid android.
=== w10pro64 (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 3 ++- dlls/jscript/jscript.h | 3 ++- dlls/mshtml/script.c | 5 ++++- dlls/mshtml/tests/documentmode.js | 1 - 4 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 3b4e970..f9cd4ca 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1608,7 +1608,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(prop) hres = prop_get(This, prop, &r); else { - hres = to_primitive(This->ctx, jsval_obj(This), &r, NO_HINT); + hres = to_primitive(This->ctx, jsval_obj(This), &r, + This->ctx->version > SCRIPTLANGUAGEVERSION_ES5 ? HINT_STRING : NO_HINT); if(hres == JS_E_TO_PRIMITIVE) hres = DISP_E_MEMBERNOTFOUND; } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index c192ec7..47ca3da 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -45,7 +45,8 @@ * This is Wine jscript extension for ES5 and ES6 compatible mode. Allowed only in HTML mode. */ #define SCRIPTLANGUAGEVERSION_ES5 0x102 -#define SCRIPTLANGUAGEVERSION_ES6 0x103 +#define SCRIPTLANGUAGEVERSION_ES5b 0x103 +#define SCRIPTLANGUAGEVERSION_ES6 0x104
typedef struct _jsval_t jsval_t; typedef struct _jsstr_t jsstr_t; diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 28e07a5..cc6a25b 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -65,7 +65,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); /* See jscript.h in jscript.dll. */ #define SCRIPTLANGUAGEVERSION_HTML 0x400 #define SCRIPTLANGUAGEVERSION_ES5 0x102 -#define SCRIPTLANGUAGEVERSION_ES6 0x103 +#define SCRIPTLANGUAGEVERSION_ES5b 0x103 +#define SCRIPTLANGUAGEVERSION_ES6 0x104
struct ScriptHost { IActiveScriptSite IActiveScriptSite_iface; @@ -156,6 +157,8 @@ static BOOL init_script_engine(ScriptHost *script_host) if(IsEqualGUID(&script_host->guid, &CLSID_JScript)) { if(compat_mode >= COMPAT_MODE_IE11) script_mode = SCRIPTLANGUAGEVERSION_ES6; + else if(compat_mode >= COMPAT_MODE_IE10) + script_mode = SCRIPTLANGUAGEVERSION_ES5b; else if(compat_mode >= COMPAT_MODE_IE9) script_mode = SCRIPTLANGUAGEVERSION_ES5; script_mode |= SCRIPTLANGUAGEVERSION_HTML; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 08fcde4..c2fd8bd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1136,7 +1136,6 @@ sync_test("elem_attr", function() { ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); - todo_wine_if(v >= 10). ok(r === (v < 8 ? arr : (v < 10 ? "arrval" : "42")), "testattr after setAttribute with custom valueOf = " + r); ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); r = elem.removeAttribute("testattr");
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102716
Your paranoid android.
=== w1064_tsign (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w1064_tsign (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
Hi Gabriel,
On 11/25/21 3:00 PM, Gabriel Ivăncescu wrote:
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 08fcde4..c2fd8bd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1136,7 +1136,6 @@ sync_test("elem_attr", function() { ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr");
- todo_wine_if(v >= 10). ok(r === (v < 8 ? arr : (v < 10 ? "arrval" : "42")), "testattr after setAttribute with custom valueOf = " + r); ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); r = elem.removeAttribute("testattr");
This test seems too little to back such change. For example, another likely explanation for the observed behaviour is that setAttribute does explicit conversion to string with proper hints.
Thanks,
Jacek
On 25/11/2021 22:11, Jacek Caban wrote:
Hi Gabriel,
On 11/25/21 3:00 PM, Gabriel Ivăncescu wrote:
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 08fcde4..c2fd8bd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1136,7 +1136,6 @@ sync_test("elem_attr", function() { ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); - todo_wine_if(v >= 10). ok(r === (v < 8 ? arr : (v < 10 ? "arrval" : "42")), "testattr after setAttribute with custom valueOf = " + r); ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); r = elem.removeAttribute("testattr");
This test seems too little to back such change. For example, another likely explanation for the observed behaviour is that setAttribute does explicit conversion to string with proper hints.
How should I do that? Looking up toString like I had originally, or something else? Or do I need an internal interface? (in which case, I'll have to integrate it somehow to the proxy patches...)
Thanks, Gabriel
On 11/26/21 12:52 PM, Gabriel Ivăncescu wrote:
On 25/11/2021 22:11, Jacek Caban wrote:
Hi Gabriel,
On 11/25/21 3:00 PM, Gabriel Ivăncescu wrote:
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 08fcde4..c2fd8bd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1136,7 +1136,6 @@ sync_test("elem_attr", function() { ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); - todo_wine_if(v >= 10). ok(r === (v < 8 ? arr : (v < 10 ? "arrval" : "42")), "testattr after setAttribute with custom valueOf = " + r); ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); r = elem.removeAttribute("testattr");
This test seems too little to back such change. For example, another likely explanation for the observed behaviour is that setAttribute does explicit conversion to string with proper hints.
How should I do that? Looking up toString like I had originally, or something else? Or do I need an internal interface? (in which case, I'll have to integrate it somehow to the proxy patches...)
As I suggested earlier, look at IVariantChangeType. change_type() should already do what you need. The only problem is that you don't have a caller context in setAttribute(). It's, however, available to hooks, so maybe we could do the conversion in a hook.
Thanks,
Jacek
On 26/11/2021 17:37, Jacek Caban wrote:
On 11/26/21 12:52 PM, Gabriel Ivăncescu wrote:
On 25/11/2021 22:11, Jacek Caban wrote:
Hi Gabriel,
On 11/25/21 3:00 PM, Gabriel Ivăncescu wrote:
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 08fcde4..c2fd8bd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1136,7 +1136,6 @@ sync_test("elem_attr", function() { ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); - todo_wine_if(v >= 10). ok(r === (v < 8 ? arr : (v < 10 ? "arrval" : "42")), "testattr after setAttribute with custom valueOf = " + r); ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); r = elem.removeAttribute("testattr");
This test seems too little to back such change. For example, another likely explanation for the observed behaviour is that setAttribute does explicit conversion to string with proper hints.
How should I do that? Looking up toString like I had originally, or something else? Or do I need an internal interface? (in which case, I'll have to integrate it somehow to the proxy patches...)
As I suggested earlier, look at IVariantChangeType. change_type() should already do what you need. The only problem is that you don't have a caller context in setAttribute(). It's, however, available to hooks, so maybe we could do the conversion in a hook.
Thanks,
Jacek
Ah, I see now, thanks for the pointer, that makes sense.
For the rest of the series, I think I'll postpone the patches that use the generic hooks though, I've discovered some interesting things with quirks/compat constructors and prototypes (which aren't in jscript but aim to "emulate" it somehow), and I believe now that those behaviors are some side-effect of that.
I'm not sure yet if it works that way, but it might make the implementation cleaner, so I'll refactor it after the proxy patches. I'll try to see if I can just get the other parts in (like the stringifying for get/setAttribute) without breaking existing tests, to avoid piling too many...
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index d54f729..e8d108f 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -4005,7 +4005,7 @@ static HRESULT WINAPI HTMLElement3_put_contentEditable(IHTMLElement3 *iface, BST return E_NOTIMPL; }
- nsAString_InitDepend(&str, v); + nsAString_InitDepend(&str, v[0] ? v : L"inherit"); nsres = nsIDOMHTMLElement_SetContentEditable(This->html_element, &str); nsAString_Finish(&str);
For non-builtin props, getAttribute retrieves the stringified value of the prop. For builtins, however, getAttribute returns null unless they were set to a string.
Note that setAttribute stringifies the value if it's a builtin, and this works even for read-only builtins (unlike in previous modes).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
I'm testing for/htmlFor since prototype.js also uses it for translations, but it doesn't seem to be affected here.
Unfortunately this patch can't be split without introducing temporary bad behavior and failing tests. It does, however, add a lot more tests to it as well.
dlls/mshtml/dispex.c | 10 ++ dlls/mshtml/htmlelem.c | 117 ++++++++++++++--- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 207 +++++++++++++++++++++++++++--- 4 files changed, 303 insertions(+), 32 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 4605fda..c30a44e 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1412,6 +1412,16 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD return hres; }
+BOOL is_readonly_builtin(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + return !func->put_vtbl_off; +} + HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) { switch(get_dispid_type(id)) { diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index e8d108f..cff6e4b 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1086,18 +1086,60 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr VARIANT AttributeValue, LONG lFlags) { HTMLElement *This = impl_from_IHTMLElement(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex); + VARIANT val = AttributeValue; + BOOL needs_free = FALSE; DISPID dispid; HRESULT hres;
TRACE("(%p)->(%s %s %08x)\n", This, debugstr_w(strAttributeName), debugstr_variant(&AttributeValue), lFlags);
- if(This->dom_element && dispex_compat_mode(&This->node.event_target.dispex) >= COMPAT_MODE_IE8) { + /* class and className are special case in IE8, behave like IE9 */ + if(compat_mode == COMPAT_MODE_IE8 && !wcsnicmp(strAttributeName, L"class", 5) && + (!strAttributeName[5] || !wcsicmp(strAttributeName + 5, L"Name"))) + compat_mode = COMPAT_MODE_IE9; + + if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) { + hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, strAttributeName, + (lFlags&ATTRFLAG_CASESENSITIVE ? fdexNameCaseSensitive : fdexNameCaseInsensitive) | fdexNameEnsure, &dispid); + if(FAILED(hres)) + return hres; + + if(compat_mode >= COMPAT_MODE_IE8 && get_dispid_type(dispid) == DISPEXPROP_BUILTIN) { + if(V_VT(&val) != VT_BSTR && V_VT(&val) != VT_NULL) { + LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT); + + V_VT(&val) = VT_EMPTY; + hres = VariantChangeTypeEx(&val, &AttributeValue, lcid, 0, VT_BSTR); + if(FAILED(hres)) + return hres; + + if(V_BSTR(&val)) + needs_free = TRUE; + else + V_VT(&val) = VT_NULL; + } + } + + /* style is special case */ + if(compat_mode == COMPAT_MODE_IE8 && dispid == DISPID_IHTMLELEMENT_STYLE) + compat_mode = COMPAT_MODE_IE9; + } + + if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) { + hres = set_elem_attr_value_by_dispid(This, dispid, &val); + if(FAILED(hres) && compat_mode < COMPAT_MODE_IE8) + goto done; + }else + hres = E_FAIL; + + if(hres == E_FAIL && This->dom_element) { nsAString name_str, value_str; nsresult nsres;
- hres = variant_to_nsstr(&AttributeValue, FALSE, &value_str); + hres = variant_to_nsstr(&val, FALSE, &value_str); if(FAILED(hres)) - return hres; + goto done;
nsAString_InitDepend(&name_str, strAttributeName); nsres = nsIDOMElement_SetAttribute(This->dom_element, &name_str, &value_str); @@ -1105,15 +1147,13 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr nsAString_Finish(&value_str); if(NS_FAILED(nsres)) WARN("SetAttribute failed: %08x\n", nsres); - return map_nsresult(nsres); + hres = map_nsresult(nsres); }
- hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, strAttributeName, - (lFlags&ATTRFLAG_CASESENSITIVE ? fdexNameCaseSensitive : fdexNameCaseInsensitive) | fdexNameEnsure, &dispid); - if(FAILED(hres)) - return hres; - - return set_elem_attr_value_by_dispid(This, dispid, &AttributeValue); +done: + if(needs_free) + SysFreeString(V_BSTR(&val)); + return hres; }
HRESULT get_elem_attr_value_by_dispid(HTMLElement *elem, DISPID dispid, VARIANT *ret) @@ -1156,6 +1196,9 @@ static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttr LONG lFlags, VARIANT *AttributeValue) { HTMLElement *This = impl_from_IHTMLElement(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex); + nsAString name_str, value_str; + nsresult nsres; DISPID dispid; HRESULT hres;
@@ -1164,10 +1207,12 @@ static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttr if(lFlags & ~(ATTRFLAG_CASESENSITIVE|ATTRFLAG_ASSTRING)) FIXME("Unsupported flags %x\n", lFlags);
- if(This->dom_element && dispex_compat_mode(&This->node.event_target.dispex) >= COMPAT_MODE_IE8) { - nsAString name_str, value_str; - nsresult nsres; + /* class and className are special case in IE8, behave like IE9 */ + if(compat_mode == COMPAT_MODE_IE8 && !wcsnicmp(strAttributeName, L"class", 5) && + (!strAttributeName[5] || !wcsicmp(strAttributeName + 5, L"Name"))) + compat_mode = COMPAT_MODE_IE9;
+ if(This->dom_element && compat_mode >= COMPAT_MODE_IE9) { nsAString_InitDepend(&name_str, strAttributeName); nsAString_InitDepend(&value_str, NULL); nsres = nsIDOMElement_GetAttribute(This->dom_element, &name_str, &value_str); @@ -1187,8 +1232,38 @@ static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttr return hres; }
+ if(This->dom_element && compat_mode >= COMPAT_MODE_IE8 && get_dispid_type(dispid) == DISPEXPROP_BUILTIN) { + if(is_readonly_builtin(&This->node.event_target.dispex, dispid)) { + nsAString_InitDepend(&name_str, strAttributeName); + nsAString_InitDepend(&value_str, NULL); + nsres = nsIDOMElement_GetAttribute(This->dom_element, &name_str, &value_str); + nsAString_Finish(&name_str); + return return_nsstr_variant(nsres, &value_str, 0, AttributeValue); + } + + hres = get_elem_attr_value_by_dispid(This, dispid, AttributeValue); + if(SUCCEEDED(hres) && V_VT(AttributeValue) != VT_BSTR) { + VariantClear(AttributeValue); + V_VT(AttributeValue) = VT_NULL; + } + return hres; + } + hres = get_elem_attr_value_by_dispid(This, dispid, AttributeValue); - if(SUCCEEDED(hres) && (lFlags & ATTRFLAG_ASSTRING)) + if(FAILED(hres)) + return hres; + + if(compat_mode >= COMPAT_MODE_IE8 && V_VT(AttributeValue) != VT_BSTR && V_VT(AttributeValue) != VT_NULL) { + LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT); + + hres = VariantChangeTypeEx(AttributeValue, AttributeValue, lcid, 0, VT_BSTR); + if(FAILED(hres)) { + VariantClear(AttributeValue); + return hres; + } + if(!V_BSTR(AttributeValue)) + V_VT(AttributeValue) = VT_NULL; + }else if(lFlags & ATTRFLAG_ASSTRING) hres = attr_value_to_string(AttributeValue); return hres; } @@ -1197,16 +1272,23 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA LONG lFlags, VARIANT_BOOL *pfSuccess) { HTMLElement *This = impl_from_IHTMLElement(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex); DISPID id; HRESULT hres;
TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(strAttributeName), lFlags, pfSuccess);
- if(dispex_compat_mode(&This->node.event_target.dispex) >= COMPAT_MODE_IE8) { + /* class and className are special case in IE8, behave like IE9 */ + if(compat_mode == COMPAT_MODE_IE8 && !wcsnicmp(strAttributeName, L"class", 5) && + (!strAttributeName[5] || !wcsicmp(strAttributeName + 5, L"Name"))) + compat_mode = COMPAT_MODE_IE9; + + if(compat_mode >= COMPAT_MODE_IE8) { *pfSuccess = element_has_attribute(This, strAttributeName); if(*pfSuccess) return element_remove_attribute(This, strAttributeName); - return S_OK; + if(compat_mode >= COMPAT_MODE_IE9) + return S_OK; }
hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, strAttributeName, @@ -6463,6 +6545,9 @@ static HRESULT HTMLElement_populate_props(DispatchEx *dispex) nsresult nsres; HRESULT hres;
+ if(dispex_compat_mode(dispex) >= COMPAT_MODE_IE9) + return S_OK; + if(!This->dom_element) return S_FALSE;
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5cf53bb..101f005 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -396,6 +396,7 @@ const void *dispex_get_vtbl(DispatchEx*) DECLSPEC_HIDDEN; void dispex_info_add_interface(dispex_data_t*,tid_t,const dispex_hook_t*) DECLSPEC_HIDDEN; compat_mode_t dispex_compat_mode(DispatchEx*) DECLSPEC_HIDDEN; HRESULT dispex_to_string(DispatchEx*,BSTR*) DECLSPEC_HIDDEN; +BOOL is_readonly_builtin(DispatchEx*,DISPID) DECLSPEC_HIDDEN;
typedef enum { DISPEXPROP_CUSTOM, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index c2fd8bd..27e6431 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -518,9 +518,7 @@ sync_test("createElement_inline_attr", function() { for(var i = 0; i < tags.length; i++) { e = document.createElement("<" + tags[i] + " test='a"' abcd=""b"">"); ok(e.tagName === tags[i].toUpperCase(), "<" + tags[i] + " test="a" abcd="b">.tagName returned " + e.tagName); - todo_wine_if(v == 8). ok(e.test === "a"", "<" + tags[i] + " test='a"' abcd=""b"">.test returned " + e.test); - todo_wine_if(v == 8). ok(e.abcd === ""b"", "<" + tags[i] + " test='a"' abcd=""b"">.abcd returned " + e.abcd); } }else { @@ -1063,6 +1061,13 @@ sync_test("elem_attr", function() { var v = document.documentMode; var elem = document.createElement("div"), r;
+ function test_exposed(prop, expect) { + if(expect) + ok(prop in elem, prop + " is not exposed from elem"); + else + ok(!(prop in elem), prop + " is exposed from elem"); + } + r = elem.getAttribute("class"); ok(r === null, "class attr = " + r); r = elem.getAttribute("className"); @@ -1088,11 +1093,37 @@ sync_test("elem_attr", function() { r = elem.getAttribute("className"); ok(r === "cls3", "className attr = " + r);
+ elem.htmlFor = "for"; + r = elem.getAttribute("for"); + ok(r === null, "for attr = " + r); + r = elem.getAttribute("htmlFor"); + ok(r === (v < 9 ? "for" : null), "htmlFor attr = " + r); + + elem.setAttribute("for", "for2"); + ok(elem.htmlFor === "for", "elem.htmlFor = " + elem.htmlFor); + r = elem.getAttribute("for"); + ok(r === "for2", "for attr = " + r); + r = elem.getAttribute("htmlFor"); + ok(r === (v < 9 ? "for" : null), "htmlFor attr = " + r); + + elem.setAttribute("htmlFor", "for3"); + ok(elem.htmlFor === (v < 9 ? "for3" : "for"), "elem.htmlFor = " + elem.htmlFor); + r = elem.getAttribute("for"); + ok(r === "for2", "for attr = " + r); + r = elem.getAttribute("htmlFor"); + ok(r === "for3", "htmlFor attr = " + r); + + elem.setAttribute("testattr", "test"); + test_exposed("class", v < 8); + test_exposed("className", true); + test_exposed("for", v < 9); + test_exposed("htmlFor", true); + test_exposed("testattr", v < 9); + var arr = [3]; elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); ok(r === (v < 8 ? arr : "3"), "testattr = " + r); - todo_wine_if(v === 8). ok(elem.testattr === (v < 9 ? arr : undefined), "elem.testattr = " + elem.testattr); r = elem.removeAttribute("testattr"); ok(r === (v < 9 ? true : undefined), "testattr removeAttribute returned " + r); @@ -1102,23 +1133,19 @@ sync_test("elem_attr", function() { elem.setAttribute("testattr", "string"); elem.testattr = arr; r = elem.getAttribute("testattr"); - todo_wine_if(v === 8). ok(r === (v < 8 ? arr : (v < 9 ? "9" : "string")), "testattr = " + r); ok(elem.testattr === arr, "elem.testattr = " + elem.testattr); arr[0] = 3; r = elem.getAttribute("testattr"); - todo_wine_if(v === 8). ok(r === (v < 8 ? arr : (v < 9 ? "3" : "string")), "testattr = " + r); ok(elem.testattr === arr, "elem.testattr = " + elem.testattr); r = elem.removeAttribute("testattr"); ok(r === (v < 9 ? true : undefined), "testattr removeAttribute returned " + r); - todo_wine_if(v === 8). ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr = " + elem.testattr);
arr.toString = function() { return 42; } elem.testattr = arr; r = elem.getAttribute("testattr"); - todo_wine_if(v === 8). ok(r === (v < 8 ? arr : (v < 9 ? "42" : null)), "testattr with custom toString = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); @@ -1126,13 +1153,11 @@ sync_test("elem_attr", function() { ok(elem.testattr === arr, "elem.testattr after setAttribute with custom toString = " + elem.testattr); r = elem.removeAttribute("testattr"); ok(r === (v < 9 ? true : undefined), "testattr removeAttribute with custom toString returned " + r); - todo_wine_if(v === 8). ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr with custom toString = " + elem.testattr);
arr.valueOf = function() { return "arrval"; } elem.testattr = arr; r = elem.getAttribute("testattr"); - todo_wine_if(v === 8). ok(r === (v < 8 ? arr : (v < 9 ? "arrval" : null)), "testattr with custom valueOf = " + r); elem.setAttribute("testattr", arr); r = elem.getAttribute("testattr"); @@ -1140,7 +1165,6 @@ sync_test("elem_attr", function() { ok(elem.testattr === arr, "elem.testattr after setAttribute with custom valueOf = " + elem.testattr); r = elem.removeAttribute("testattr"); ok(r === (v < 9 ? true : undefined), "testattr removeAttribute with custom valueOf returned " + r); - todo_wine_if(v === 8). ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr with custom valueOf = " + elem.testattr); delete arr.valueOf; delete arr.toString; @@ -1166,7 +1190,6 @@ sync_test("elem_attr", function() { elem.onclick_test = func; ok(elem.onclick_test === func, "onclick_test = " + elem.onclick_test); r = elem.getAttribute("onclick_test"); - todo_wine_if(v === 8). ok(r === (v < 8 ? func : (v < 9 ? func.toString() : null)), "onclick_test attr = " + r);
elem.setAttribute("onclick", "test"); @@ -1176,11 +1199,11 @@ sync_test("elem_attr", function() { ok(r === (v < 9 ? true : undefined), "removeAttribute after setAttribute returned " + r);
/* IE11 returns an empty function, which we can't check directly */ - todo_wine_if(v >= 8). + todo_wine_if(v >= 9). ok((v < 11) ? (elem.onclick === null) : (elem.onclick !== func), "removed onclick after setAttribute = " + elem.onclick);
r = Object.prototype.toString.call(elem.onclick); - todo_wine_if(v >= 8 && v < 11). + todo_wine_if(v >= 9 && v < 11). ok(r === (v < 9 ? "[object Object]" : (v < 11 ? "[object Null]" : "[object Function]")), "removed onclick after setAttribute Object.toString returned " + r);
@@ -1190,15 +1213,13 @@ sync_test("elem_attr", function() { elem.onclick = func; ok(elem.onclick === func, "onclick = " + elem.onclick); r = elem.getAttribute("onclick"); - todo_wine_if(v === 8). ok(r === (v < 8 ? func : (v < 9 ? null : "string")), "onclick attr = " + r); elem.onclick = "test"; r = elem.getAttribute("onclick"); - todo_wine_if(v === 8). ok(r === (v < 9 ? "test" : "string"), "onclick attr = " + r); r = elem.removeAttribute("onclick"); ok(r === (v < 9 ? true : undefined), "removeAttribute returned " + r); - todo_wine_if(v >= 8). + todo_wine_if(v >= 9). ok(elem.onclick === null, "removed onclick = " + elem.onclick);
elem.setAttribute("ondblclick", arr); @@ -1218,6 +1239,160 @@ sync_test("elem_attr", function() { r = elem.removeAttribute("ondblclick"); ok(r === (v < 9 ? true : undefined), "ondblclick string removeAttribute returned " + r); ok(elem.ondblclick === null, "removed ondblclick string = " + elem.ondblclick); + + if(v < 9) { + var props = [ + [ "contentEditable", "inherit", "true" ], + [ "dir", "", "ltr" ], + [ "id", "" ], + [ "lang", "" ], + [ "language", "" ], + [ "onbeforeactivate" ], + [ "onblur" ], + [ "oncontextmenu" ], + [ "ondataavailable" ], + [ "ondrag" ], + [ "ondragstart" ], + [ "onfocus" ], + [ "onfocusin" ], + [ "onfocusout" ], + [ "onhelp" ], + [ "onkeydown" ], + [ "onkeypress" ], + [ "onkeyup" ], + [ "onmousedown" ], + [ "onmousemove" ], + [ "onmouseout" ], + [ "onmouseover" ], + [ "onmouseup" ], + [ "onmousewheel" ], + [ "onpaste" ], + [ "onreadystatechange" ], + [ "onresize" ], + [ "onscroll" ], + [ "onselectstart" ], + [ "title", "" ] + ]; + + for(var i = 0; i < props.length; i++) { + var name = props[i][0]; + var val = props[i].length > 2 ? props[i][2] : "test"; + + r = elem.getAttribute(name); + todo_wine_if(v === 8 && props[i][0].substring(0, 2) !== "on"). + ok(r === (v < 8 && props[i].length > 1 ? props[i][1] : null), name + " attr before set = " + r); + eval("elem." + name + " = "" + val + ""; r = elem." + name + ";"); + ok(r === val, "elem." + name + " = " + r); + + r = elem.getAttribute(name); + ok(r === val, name + " attr = " + r); + r = elem.removeAttribute(name); + ok(r === true, "removeAttribute('" + name + "') returned " + r); + eval("r = elem." + name + ";"); + ok(r === (props[i].length > 1 ? props[i][1] : null), "removed elem." + name + " = " + r); + + elem.setAttribute(name, val); + r = elem.getAttribute(name); + ok(r === val, name + " attr after setAttribute = " + r); + eval("r = elem." + name + ";"); + ok(r === val, "elem." + name + " after setAttribute = " + r); + } + + /* read-only props */ + props = [ + "all", + "attributes", + "childNodes", + "children", + "clientHeight", + "clientLeft", + "clientTop", + "clientWidth", + "currentStyle", + "document", + "filters", + "firstChild", + "lastChild", + "nextSibling", + "nodeName", + "nodeType", + "offsetHeight", + "offsetLeft", + "offsetParent", + "offsetTop", + "offsetWidth", + "ownerDocument", + "parentElement", + "parentNode", + "previousSibling", + "readyState", + "runtimeStyle", + "sourceIndex", + "tagName", + "uniqueID", + "uniqueNumber" + ]; + + for(var i = 0; i < props.length; i++) { + var name = props[i], prop; + + try { + eval("elem." + name + " = "test";"); + ok(false, "expected exception setting elem." + name); + }catch(ex) { } + + r = elem.getAttribute(name); + eval("prop = elem." + name + ";"); + + if(v < 8) + ok(""+r === ""+prop, name + " attr = " + r); + else + ok(r === null, name + " attr = " + r); + r = elem.removeAttribute(name); + ok(r === false, "removeAttribute('" + name + "') returned " + r); + + try { + elem.setAttribute(name, "string"); + ok(v >= 8, "expected exception calling setAttribute('" + name + "')"); + }catch(ex) { + ok(v < 8, "did not expect exception calling setAttribute('" + name + "')"); + } + if(v >= 8) { + r = elem.getAttribute(name); + ok(r === "string", name + " attr after setAttribute = " + r); + eval("r = elem." + name + ";"); + todo_wine. + ok(r === "string", "elem." + name + " after setAttribute = " + r); + + r = elem.removeAttribute(name); + ok(r === true, "removeAttribute('" + name + "') after setAttribute returned " + r); + eval("r = elem." + name + ";"); + ok(""+r === ""+prop, name + " attr = " + r); + } + } + + /* style is special case */ + try { + elem.style = "opacity: 1.0"; + ok(false, "expected exception setting elem.style"); + }catch(ex) { } + + var style = elem.style; + r = elem.getAttribute("style"); + ok(r === (v < 8 ? style : null), "style attr = " + r); + r = elem.removeAttribute("style"); + ok(r === true, "removeAttribute('style') returned " + r); + r = elem.style; + ok(r === style, "removed elem.style = " + r); + r = elem.getAttribute("style"); + todo_wine_if(v === 8). + ok(r === (v < 8 ? style : null), "style attr after removal = " + r); + elem.setAttribute("style", "opacity: 1.0"); + r = elem.getAttribute("style"); + ok(r === (v < 8 ? style : "opacity: 1.0"), "style attr after setAttribute = " + r); + r = elem.style; + ok(r === style, "elem.style after setAttribute = " + r); + } });
sync_test("__proto__", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102718
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 2 +- dlls/mshtml/htmlelem.c | 15 +++++++++++++-- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 2 -- 4 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index c30a44e..e626f70 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1007,7 +1007,7 @@ static HRESULT get_builtin_func(dispex_data_t *data, DISPID id, func_info_t **re return DISP_E_UNKNOWNNAME; }
-static HRESULT get_builtin_id(DispatchEx *This, BSTR name, DWORD grfdex, DISPID *ret) +HRESULT get_builtin_id(DispatchEx *This, BSTR name, DWORD grfdex, DISPID *ret) { int min, max, n, c;
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index cff6e4b..bf899cd 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1087,8 +1087,8 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr { HTMLElement *This = impl_from_IHTMLElement(iface); compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex); + BOOL needs_free = FALSE, object_str = FALSE; VARIANT val = AttributeValue; - BOOL needs_free = FALSE; DISPID dispid; HRESULT hres;
@@ -1106,7 +1106,9 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr return hres;
if(compat_mode >= COMPAT_MODE_IE8 && get_dispid_type(dispid) == DISPEXPROP_BUILTIN) { - if(V_VT(&val) != VT_BSTR && V_VT(&val) != VT_NULL) { + if(V_VT(&val) == VT_DISPATCH && compat_mode < COMPAT_MODE_IE10) { + object_str = TRUE; + }else if(V_VT(&val) != VT_BSTR && V_VT(&val) != VT_NULL) { LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
V_VT(&val) = VT_EMPTY; @@ -1124,6 +1126,15 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr /* style is special case */ if(compat_mode == COMPAT_MODE_IE8 && dispid == DISPID_IHTMLELEMENT_STYLE) compat_mode = COMPAT_MODE_IE9; + }else if(V_VT(&val) == VT_DISPATCH && compat_mode < COMPAT_MODE_IE10) { + object_str = get_builtin_id(&This->node.event_target.dispex, strAttributeName, fdexNameCaseInsensitive, &dispid) == S_OK; + } + + if(object_str) { + if(!(V_BSTR(&val) = SysAllocString(L"[object]"))) + return E_OUTOFMEMORY; + V_VT(&val) = VT_BSTR; + needs_free = TRUE; }
if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) { diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 101f005..cc5779b 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -384,6 +384,7 @@ extern void (__cdecl *note_cc_edge)(nsISupports*,const char*,nsCycleCollectionTr void init_dispatch(DispatchEx*,IUnknown*,dispex_static_data_t*,compat_mode_t) DECLSPEC_HIDDEN; void release_dispex(DispatchEx*) DECLSPEC_HIDDEN; BOOL dispex_query_interface(DispatchEx*,REFIID,void**) DECLSPEC_HIDDEN; +HRESULT get_builtin_id(DispatchEx*,BSTR,DWORD,DISPID*) DECLSPEC_HIDDEN; HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**) DECLSPEC_HIDDEN; HRESULT get_dispids(tid_t,DWORD*,DISPID**) DECLSPEC_HIDDEN; HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 27e6431..dc1f1bb 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1171,7 +1171,6 @@ sync_test("elem_attr", function() {
elem.setAttribute("id", arr); r = elem.getAttribute("id"); - todo_wine_if(v >= 8 && v < 10). ok(r === (v < 8 || v >= 10 ? "3" : "[object]"), "id = " + r); r = elem.removeAttribute("id"); ok(r === (v < 9 ? true : undefined), "id removeAttribute returned " + r); @@ -1224,7 +1223,6 @@ sync_test("elem_attr", function() {
elem.setAttribute("ondblclick", arr); r = elem.getAttribute("ondblclick"); - todo_wine_if(v >= 8 && v < 10). ok(r === (v < 8 ? arr : (v < 10 ? "[object]" : "3")), "ondblclick = " + r); r = elem.removeAttribute("ondblclick"); ok(r === (v < 8 ? false : (v < 9 ? true : undefined)), "ondblclick removeAttribute returned " + r);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102719
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
If an attribute was set over a read-only builtin, reading the prop gives the attribute's value string, until it is removed, at which point it reverts back to retrieving the prop's value.
Hooks have to be used, though, because some builtins return non-string values (such as clientWidth returning integer value), so we need to override them.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This extends the hook callbacks with name, as well as the init_info method so that it optionally returns a structure that contains generic hooks for all read-only builtin props (and in next patch, for read-write builtins).
dlls/mshtml/dispex.c | 26 +++++++++++++-- dlls/mshtml/htmldoc.c | 3 +- dlls/mshtml/htmlelem.c | 54 ++++++++++++++++++++++++++++++- dlls/mshtml/htmlevent.c | 11 ++++--- dlls/mshtml/htmlnode.c | 4 +-- dlls/mshtml/htmlstyle.c | 3 +- dlls/mshtml/htmlstyle.h | 2 +- dlls/mshtml/htmlstyleelem.c | 6 ++-- dlls/mshtml/htmlstylesheet.c | 3 +- dlls/mshtml/htmlwindow.c | 4 +-- dlls/mshtml/mshtml_private.h | 20 ++++++++---- dlls/mshtml/tests/documentmode.js | 2 -- dlls/mshtml/xmlhttprequest.c | 9 +++--- 13 files changed, 114 insertions(+), 33 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index e626f70..846a678 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -470,11 +470,12 @@ static int __cdecl func_name_cmp(const void *p1, const void *p2)
static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_mode_t compat_mode) { + const generic_prop_hooks_t *prop_hooks = NULL; const tid_t *tid; dispex_data_t *data; - DWORD i; ITypeInfo *dti; HRESULT hres; + DWORD i, j;
if(desc->disp_tid) { hres = get_typeinfo(desc->disp_tid, &dti); @@ -503,7 +504,7 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ list_add_tail(&dispex_data_list, &data->entry);
if(desc->init_info) - desc->init_info(data, compat_mode); + prop_hooks = desc->init_info(data, compat_mode);
for(tid = desc->iface_tids; *tid; tid++) { hres = process_interface(data, *tid, dti, NULL); @@ -519,6 +520,25 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ return data; }
+ if(prop_hooks) { + for(i = 0; i < data->func_cnt; i++) { + func_info_t *func = &data->funcs[i]; + + if(func->hook || func->func_disp_idx != -1) + continue; + + if(prop_hooks->exclude_list) { + for(j = 0; prop_hooks->exclude_list[j] != DISPID_UNKNOWN; j++) + if(prop_hooks->exclude_list[j] == func->id) + break; + if(prop_hooks->exclude_list[j] == func->id) + continue; + } + + func->hook = func->put_vtbl_off ? NULL : prop_hooks->ro_prop_hook; + } + } +
data->funcs = heap_realloc(data->funcs, data->func_cnt * sizeof(func_info_t)); qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp); @@ -1365,7 +1385,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD return hres;
if(func->hook) { - hres = func->hook(This, lcid, flags, dp, res, ei, caller); + hres = func->hook(This, func->name, lcid, flags, dp, res, ei, caller); if(hres != S_FALSE) return hres; } diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index d2caaef..1a02fc7 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5628,7 +5628,7 @@ static const tid_t HTMLDocumentNode_iface_tids[] = { 0 };
-static void HTMLDocumentNode_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +static const generic_prop_hooks_t *HTMLDocumentNode_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { HTMLDOMNode_init_dispex_info(info, mode);
@@ -5646,6 +5646,7 @@ static void HTMLDocumentNode_init_dispex_info(dispex_data_t *info, compat_mode_t dispex_info_add_interface(info, IHTMLDocument6_tid, NULL); dispex_info_add_interface(info, IHTMLDocument3_tid, NULL); } + return NULL; }
static dispex_static_data_t HTMLDocumentNode_dispex = { diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index bf899cd..b87e23d 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1325,6 +1325,9 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA if(FAILED(hres)) return hres;
+ if(compat_mode >= COMPAT_MODE_IE8) + element_remove_attribute(This, strAttributeName); + *pfSuccess = VARIANT_TRUE; return S_OK; } @@ -6681,13 +6684,60 @@ static IHTMLEventObj *HTMLElement_set_current_event(DispatchEx *dispex, IHTMLEve return default_set_current_event(This->node.doc->window, event); }
-void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +static HRESULT ie8_ro_prop_hook(DispatchEx *dispex, BSTR name, LCID lcid, WORD flags, + DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + HTMLElement *This = impl_from_DispatchEx(dispex); + nsAString name_str, val_str; + const PRUnichar *val; + nsresult nsres; + cpp_bool b; + + if(flags != DISPATCH_PROPERTYGET || !res || !This->dom_element) + return S_FALSE; + + nsAString_InitDepend(&name_str, name); + nsres = nsIDOMElement_HasAttribute(This->dom_element, &name_str, &b); + if(NS_FAILED(nsres) || !b) { + nsAString_Finish(&name_str); + return S_FALSE; + } + + nsAString_Init(&val_str, NULL); + nsres = nsIDOMElement_GetAttribute(This->dom_element, &name_str, &val_str); + nsAString_Finish(&name_str); + if(NS_FAILED(nsres)) { + nsAString_Finish(&val_str); + return S_FALSE; + } + + nsAString_GetData(&val_str, &val); + V_BSTR(res) = SysAllocString(val); + nsAString_Finish(&val_str); + + if(!V_BSTR(res)) + return E_OUTOFMEMORY; + V_VT(res) = VT_BSTR; + + return S_OK; +} + +const generic_prop_hooks_t *HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { static const dispex_hook_t elem2_ie11_hooks[] = { {DISPID_IHTMLELEMENT2_DOSCROLL, NULL}, {DISPID_IHTMLELEMENT2_READYSTATE, NULL}, {DISPID_UNKNOWN} }; + static const DISPID ie8_prop_hooks_exclude_list[] = { + DISPID_IHTMLELEMENT_CLASSNAME, + DISPID_IHTMLELEMENT_STYLE, + DISPID_UNKNOWN + }; + static const generic_prop_hooks_t ie8_prop_hooks = { + ie8_ro_prop_hook, + ie8_prop_hooks_exclude_list + };
HTMLDOMNode_init_dispex_info(info, mode);
@@ -6706,6 +6756,8 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) dispex_info_add_interface(info, IHTMLElement7_tid, NULL); dispex_info_add_interface(info, IWineHTMLElementPrivate_tid, NULL); } + + return (mode == COMPAT_MODE_IE8) ? &ie8_prop_hooks : NULL; }
static const tid_t HTMLElement_iface_tids[] = { diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 3f545bb..84cd0b1 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -3314,8 +3314,8 @@ static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent * return dispatch_event_object(This, event, DISPATCH_STANDARD, result); }
-static HRESULT IEventTarget_addEventListener_hook(DispatchEx *dispex, LCID lcid, WORD flags, - DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT IEventTarget_addEventListener_hook(DispatchEx *dispex, BSTR name, LCID lcid, + WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { /* If only two arguments were given, implicitly set capture to false */ if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) { @@ -3335,8 +3335,8 @@ static HRESULT IEventTarget_addEventListener_hook(DispatchEx *dispex, LCID lcid, return S_FALSE; /* fallback to default */ }
-static HRESULT IEventTarget_removeEventListener_hook(DispatchEx *dispex, LCID lcid, WORD flags, - DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT IEventTarget_removeEventListener_hook(DispatchEx *dispex, BSTR name, LCID lcid, + WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { /* If only two arguments were given, implicitly set capture to false */ if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) { @@ -3413,7 +3413,7 @@ HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv) return E_NOINTERFACE; }
-void EventTarget_init_dispex_info(dispex_data_t *dispex_info, compat_mode_t compat_mode) +const generic_prop_hooks_t *EventTarget_init_dispex_info(dispex_data_t *dispex_info, compat_mode_t compat_mode) { static const dispex_hook_t IEventTarget_hooks[] = { {DISPID_IEVENTTARGET_ADDEVENTLISTENER, IEventTarget_addEventListener_hook}, @@ -3423,6 +3423,7 @@ void EventTarget_init_dispex_info(dispex_data_t *dispex_info, compat_mode_t comp
if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(dispex_info, IEventTarget_tid, IEventTarget_hooks); + return NULL; }
static int event_id_cmp(const void *key, const struct wine_rb_entry *entry) diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index 996c28c..3d977b2 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -1432,12 +1432,12 @@ static HRESULT HTMLDOMNode_clone(HTMLDOMNode *This, nsIDOMNode *nsnode, HTMLDOMN return create_node(This->doc, nsnode, ret); }
-void HTMLDOMNode_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +const generic_prop_hooks_t *HTMLDOMNode_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { if(mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLDOMNode3_tid, NULL);
- EventTarget_init_dispex_info(info, mode); + return EventTarget_init_dispex_info(info, mode); }
static const cpc_entry_t HTMLDOMNode_cpc[] = {{NULL}}; diff --git a/dlls/mshtml/htmlstyle.c b/dlls/mshtml/htmlstyle.c index 2cbd8a5..e3a5da8 100644 --- a/dlls/mshtml/htmlstyle.c +++ b/dlls/mshtml/htmlstyle.c @@ -9983,12 +9983,13 @@ static HRESULT CSSStyle_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, D return DISP_E_UNKNOWNNAME; }
-void CSSStyle_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +const generic_prop_hooks_t *CSSStyle_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { if(mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLCSSStyleDeclaration_tid, NULL); if(mode >= COMPAT_MODE_IE10) dispex_info_add_interface(info, IHTMLCSSStyleDeclaration2_tid, NULL); + return NULL; }
const dispex_static_data_vtbl_t CSSStyle_dispex_vtbl = { diff --git a/dlls/mshtml/htmlstyle.h b/dlls/mshtml/htmlstyle.h index 25f87c8..59fc281 100644 --- a/dlls/mshtml/htmlstyle.h +++ b/dlls/mshtml/htmlstyle.h @@ -155,7 +155,7 @@ HRESULT create_computed_style(nsIDOMCSSStyleDeclaration*,compat_mode_t,IHTMLCSSS void init_css_style(CSSStyle*,nsIDOMCSSStyleDeclaration*,style_qi_t, dispex_static_data_t*,compat_mode_t) DECLSPEC_HIDDEN;
-void CSSStyle_init_dispex_info(dispex_data_t *info, compat_mode_t mode) DECLSPEC_HIDDEN; +const generic_prop_hooks_t *CSSStyle_init_dispex_info(dispex_data_t *info, compat_mode_t mode) DECLSPEC_HIDDEN; extern const dispex_static_data_vtbl_t CSSStyle_dispex_vtbl DECLSPEC_HIDDEN;
HRESULT get_style_property(CSSStyle*,styleid_t,BSTR*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlstyleelem.c b/dlls/mshtml/htmlstyleelem.c index cf57547..82ef2d7 100644 --- a/dlls/mshtml/htmlstyleelem.c +++ b/dlls/mshtml/htmlstyleelem.c @@ -420,21 +420,21 @@ static void HTMLStyleElement_unlink(HTMLDOMNode *iface) } }
-static void HTMLStyleElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +static const generic_prop_hooks_t *HTMLStyleElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { static const dispex_hook_t ie11_hooks[] = { {DISPID_IHTMLSTYLEELEMENT_READYSTATE, NULL}, {DISPID_IHTMLSTYLEELEMENT_STYLESHEET, NULL}, {DISPID_UNKNOWN} }; - - HTMLElement_init_dispex_info(info, mode); + const generic_prop_hooks_t *prop_hooks = HTMLElement_init_dispex_info(info, mode);
dispex_info_add_interface(info, IHTMLStyleElement_tid, mode >= COMPAT_MODE_IE11 ? ie11_hooks : NULL);
if(mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLStyleElement2_tid, NULL); + return prop_hooks; }
static const NodeImplVtbl HTMLStyleElementImplVtbl = { diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index c31c780..4f38c12 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -1140,10 +1140,11 @@ static const IHTMLStyleSheet4Vtbl HTMLStyleSheet4Vtbl = { HTMLStyleSheet4_deleteRule, };
-static void HTMLStyleSheet_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +static const generic_prop_hooks_t *HTMLStyleSheet_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { if(mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLStyleSheet4_tid, NULL); + return NULL; }
static const tid_t HTMLStyleSheet_iface_tids[] = { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 635b046..7298b03 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3734,7 +3734,7 @@ static void HTMLWindow_bind_event(DispatchEx *dispex, eventid_t eid) ensure_doc_nsevent_handler(This->doc, NULL, eid); }
-static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +static const generic_prop_hooks_t *HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); @@ -3744,7 +3744,7 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL);
dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); - EventTarget_init_dispex_info(info, compat_mode); + return EventTarget_init_dispex_info(info, compat_mode); }
static IHTMLEventObj *HTMLWindow_set_current_event(DispatchEx *dispex, IHTMLEventObj *event) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index cc5779b..0676a34 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -319,6 +319,9 @@ typedef struct dispex_dynamic_data_t dispex_dynamic_data_t;
typedef struct DispatchEx DispatchEx;
+typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,BSTR,LCID,WORD,DISPPARAMS*, + VARIANT*,EXCEPINFO*,IServiceProvider*); + typedef struct { HRESULT (*value)(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); HRESULT (*get_dispid)(DispatchEx*,BSTR,DWORD,DISPID*); @@ -327,19 +330,22 @@ typedef struct { HRESULT (*populate_props)(DispatchEx*); } dispex_static_data_vtbl_t;
+typedef struct { + dispex_hook_invoke_t ro_prop_hook; + + const DISPID *exclude_list; +} generic_prop_hooks_t; + typedef struct { const WCHAR *name; const dispex_static_data_vtbl_t *vtbl; const tid_t disp_tid; const tid_t* const iface_tids; - void (*init_info)(dispex_data_t*,compat_mode_t); + const generic_prop_hooks_t* (*init_info)(dispex_data_t*,compat_mode_t); dispex_data_t *info_cache[COMPAT_MODE_CNT]; dispex_data_t *delayed_init_info; } dispex_static_data_t;
-typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*, - EXCEPINFO*,IServiceProvider*); - typedef struct { DISPID dispid; dispex_hook_invoke_t invoke; @@ -1132,18 +1138,18 @@ void HTMLElement_Init(HTMLElement*,HTMLDocumentNode*,nsIDOMElement*,dispex_stati
void EventTarget_Init(EventTarget*,IUnknown*,dispex_static_data_t*,compat_mode_t) DECLSPEC_HIDDEN; HRESULT EventTarget_QI(EventTarget*,REFIID,void**) DECLSPEC_HIDDEN; -void EventTarget_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN; +const generic_prop_hooks_t *EventTarget_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN;
HRESULT HTMLDOMNode_QI(HTMLDOMNode*,REFIID,void**) DECLSPEC_HIDDEN; void HTMLDOMNode_destructor(HTMLDOMNode*) DECLSPEC_HIDDEN; -void HTMLDOMNode_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN; +const generic_prop_hooks_t *HTMLDOMNode_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN;
HRESULT HTMLElement_QI(HTMLDOMNode*,REFIID,void**) DECLSPEC_HIDDEN; void HTMLElement_destructor(HTMLDOMNode*) DECLSPEC_HIDDEN; HRESULT HTMLElement_clone(HTMLDOMNode*,nsIDOMNode*,HTMLDOMNode**) DECLSPEC_HIDDEN; HRESULT HTMLElement_get_attr_col(HTMLDOMNode*,HTMLAttributeCollection**) DECLSPEC_HIDDEN; HRESULT HTMLElement_handle_event(HTMLDOMNode*,DWORD,nsIDOMEvent*,BOOL*) DECLSPEC_HIDDEN; -void HTMLElement_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN; +const generic_prop_hooks_t *HTMLElement_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN;
HRESULT get_node(nsIDOMNode*,BOOL,HTMLDOMNode**) DECLSPEC_HIDDEN; HRESULT get_element(nsIDOMElement*,HTMLElement**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index dc1f1bb..bdd0a4a 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1359,7 +1359,6 @@ sync_test("elem_attr", function() { r = elem.getAttribute(name); ok(r === "string", name + " attr after setAttribute = " + r); eval("r = elem." + name + ";"); - todo_wine. ok(r === "string", "elem." + name + " after setAttribute = " + r);
r = elem.removeAttribute(name); @@ -1383,7 +1382,6 @@ sync_test("elem_attr", function() { r = elem.style; ok(r === style, "removed elem.style = " + r); r = elem.getAttribute("style"); - todo_wine_if(v === 8). ok(r === (v < 8 ? style : null), "style attr after removal = " + r); elem.setAttribute("style", "opacity: 1.0"); r = elem.getAttribute("style"); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 56e18d0..8b9cdde 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -475,8 +475,8 @@ static HRESULT WINAPI HTMLXMLHttpRequest_abort(IHTMLXMLHttpRequest *iface) return S_OK; }
-static HRESULT HTMLXMLHttpRequest_open_hook(DispatchEx *dispex, LCID lcid, WORD flags, - DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLXMLHttpRequest_open_hook(DispatchEx *dispex, BSTR name, LCID lcid, + WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { /* If only two arguments were given, implicitly set async to false */ if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) { @@ -870,15 +870,16 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) This->event_listener->load_event = TRUE; }
-static void HTMLXMLHttpRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +static const generic_prop_hooks_t *HTMLXMLHttpRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { static const dispex_hook_t xhr_hooks[] = { {DISPID_IHTMLXMLHTTPREQUEST_OPEN, HTMLXMLHttpRequest_open_hook}, {DISPID_UNKNOWN} }; + const generic_prop_hooks_t *prop_hooks = EventTarget_init_dispex_info(info, compat_mode);
- EventTarget_init_dispex_info(info, compat_mode); dispex_info_add_interface(info, IHTMLXMLHttpRequest_tid, compat_mode >= COMPAT_MODE_IE10 ? xhr_hooks : NULL); + return prop_hooks; }
static event_target_vtbl_t HTMLXMLHttpRequest_event_target_vtbl = {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102720
Your paranoid android.
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w7u_el (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1637867063875 expected 1637867063938"
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 2 +- dlls/mshtml/htmlelem.c | 57 ++++++++++++++++++++++++++----- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 1 - 4 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 846a678..b9d43e8 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -535,7 +535,7 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ continue; }
- func->hook = func->put_vtbl_off ? NULL : prop_hooks->ro_prop_hook; + func->hook = func->put_vtbl_off ? prop_hooks->rw_prop_hook : prop_hooks->ro_prop_hook; } }
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index b87e23d..d8ed0ac 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1212,6 +1212,7 @@ static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttr nsresult nsres; DISPID dispid; HRESULT hres; + cpp_bool b;
TRACE("(%p)->(%s %08x %p)\n", This, debugstr_w(strAttributeName), lFlags, AttributeValue);
@@ -1244,18 +1245,26 @@ static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttr }
if(This->dom_element && compat_mode >= COMPAT_MODE_IE8 && get_dispid_type(dispid) == DISPEXPROP_BUILTIN) { + nsAString_InitDepend(&name_str, strAttributeName); + if(is_readonly_builtin(&This->node.event_target.dispex, dispid)) { - nsAString_InitDepend(&name_str, strAttributeName); nsAString_InitDepend(&value_str, NULL); nsres = nsIDOMElement_GetAttribute(This->dom_element, &name_str, &value_str); nsAString_Finish(&name_str); return return_nsstr_variant(nsres, &value_str, 0, AttributeValue); }
- hres = get_elem_attr_value_by_dispid(This, dispid, AttributeValue); - if(SUCCEEDED(hres) && V_VT(AttributeValue) != VT_BSTR) { - VariantClear(AttributeValue); + nsres = nsIDOMElement_HasAttribute(This->dom_element, &name_str, &b); + nsAString_Finish(&name_str); + if(NS_SUCCEEDED(nsres) && b) { + hres = get_elem_attr_value_by_dispid(This, dispid, AttributeValue); + if(SUCCEEDED(hres) && V_VT(AttributeValue) != VT_BSTR) { + VariantClear(AttributeValue); + V_VT(AttributeValue) = VT_NULL; + } + }else { V_VT(AttributeValue) = VT_NULL; + hres = S_OK; } return hres; } @@ -1284,6 +1293,7 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA { HTMLElement *This = impl_from_IHTMLElement(iface); compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex); + VARIANT_BOOL tmp; DISPID id; HRESULT hres;
@@ -1296,10 +1306,12 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA
if(compat_mode >= COMPAT_MODE_IE8) { *pfSuccess = element_has_attribute(This, strAttributeName); - if(*pfSuccess) - return element_remove_attribute(This, strAttributeName); if(compat_mode >= COMPAT_MODE_IE9) - return S_OK; + return *pfSuccess ? element_remove_attribute(This, strAttributeName) : S_OK; + + /* remove the prop without influencing the return value */ + if(*pfSuccess) + pfSuccess = &tmp; }
hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, strAttributeName, @@ -1332,7 +1344,10 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA return S_OK; }
- return remove_attribute(&This->node.event_target.dispex, id, pfSuccess); + hres = remove_attribute(&This->node.event_target.dispex, id, pfSuccess); + if(compat_mode >= COMPAT_MODE_IE8) + element_remove_attribute(This, strAttributeName); + return hres; }
static HRESULT WINAPI HTMLElement_put_className(IHTMLElement *iface, BSTR v) @@ -6722,6 +6737,31 @@ static HRESULT ie8_ro_prop_hook(DispatchEx *dispex, BSTR name, LCID lcid, WORD f return S_OK; }
+static HRESULT ie8_rw_prop_hook(DispatchEx *dispex, BSTR name, LCID lcid, WORD flags, + DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + HTMLElement *This = impl_from_DispatchEx(dispex); + nsAString name_str, val_str; + nsresult nsres; + cpp_bool b; + + if(flags != DISPATCH_PROPERTYPUT || dp->cArgs != 1 || dp->cNamedArgs > 1 || V_VT(dp->rgvarg) != VT_BSTR || + (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT) || !This->dom_element) + return S_FALSE; + + /* make sure attribute is set if it doesn't exist, for getAttribute checks */ + nsAString_InitDepend(&name_str, name); + nsres = nsIDOMElement_HasAttribute(This->dom_element, &name_str, &b); + if(NS_SUCCEEDED(nsres) && !b) { + nsAString_InitDepend(&val_str, L""); + nsIDOMElement_SetAttribute(This->dom_element, &name_str, &val_str); + nsAString_Finish(&val_str); + } + nsAString_Finish(&name_str); + + return S_FALSE; +} + const generic_prop_hooks_t *HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { static const dispex_hook_t elem2_ie11_hooks[] = { @@ -6736,6 +6776,7 @@ const generic_prop_hooks_t *HTMLElement_init_dispex_info(dispex_data_t *info, co }; static const generic_prop_hooks_t ie8_prop_hooks = { ie8_ro_prop_hook, + ie8_rw_prop_hook, ie8_prop_hooks_exclude_list };
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 0676a34..46da4a1 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -332,6 +332,7 @@ typedef struct {
typedef struct { dispex_hook_invoke_t ro_prop_hook; + dispex_hook_invoke_t rw_prop_hook;
const DISPID *exclude_list; } generic_prop_hooks_t; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index bdd0a4a..6b3b9f3 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1277,7 +1277,6 @@ sync_test("elem_attr", function() { var val = props[i].length > 2 ? props[i][2] : "test";
r = elem.getAttribute(name); - todo_wine_if(v === 8 && props[i][0].substring(0, 2) !== "on"). ok(r === (v < 8 && props[i].length > 1 ? props[i][1] : null), name + " attr before set = " + r); eval("elem." + name + " = "" + val + ""; r = elem." + name + ";"); ok(r === val, "elem." + name + " = " + r);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102721
Your paranoid android.
=== w10pro64_he (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 8 ++++++-- dlls/mshtml/tests/documentmode.js | 1 - 2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index b9d43e8..c586fb3 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1500,9 +1500,13 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) if(FAILED(hres)) { VARIANT *ref; hres = dispex_get_dprop_ref(This, func->name, FALSE, &ref); - if(FAILED(hres) || V_VT(ref) != VT_BSTR) + if(FAILED(hres) || V_VT(ref) != VT_BSTR) { *success = VARIANT_FALSE; - else + if(dispex_compat_mode(This) >= COMPAT_MODE_IE8) { + V_VT(&var) = VT_NULL; + builtin_propput(This, func, &dp, NULL); + } + }else VariantClear(ref); } return S_OK; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 6b3b9f3..b658324 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1183,7 +1183,6 @@ sync_test("elem_attr", function() { ok(r === (v < 8 ? func : null), "onclick attr = " + r); r = elem.removeAttribute("onclick"); ok(r === (v < 9 ? false : undefined), "removeAttribute returned " + r); - todo_wine_if(v === 8). ok(elem.onclick === (v != 8 ? func : null), "removed onclick = " + elem.onclick);
elem.onclick_test = func;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102722
Your paranoid android.
=== w1064_tsign (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_he (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w7u_el (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1637873127104 expected 1637873127167"
This has to be special cased for Object_toString because null is otherwise replaced by the global object for any other case.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/function.c | 10 ++++++++++ dlls/jscript/jscript.h | 1 + dlls/jscript/object.c | 2 +- dlls/mshtml/tests/documentmode.js | 2 +- dlls/mshtml/tests/es5.js | 1 - 5 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 3eef1aa..c0eb847 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -604,6 +604,16 @@ static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, ID
if(this_disp) set_disp(&vthis, this_disp); + else if(function->proc == Object_toString && ctx->version >= SCRIPTLANGUAGEVERSION_ES5) { + jsstr_t *ret; + if(!r) + return S_OK; + ret = jsstr_alloc(L"[object Null]"); + if(!ret) + return E_OUTOFMEMORY; + *r = jsval_string(ret); + return S_OK; + } else set_disp(&vthis, lookup_global_host(ctx));
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 47ca3da..e5891a2 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -515,6 +515,7 @@ BOOL bool_obj_value(jsdisp_t*) DECLSPEC_HIDDEN; unsigned array_get_length(jsdisp_t*) DECLSPEC_HIDDEN;
HRESULT JSGlobal_eval(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT Object_toString(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
static inline BOOL is_class(jsdisp_t *jsdisp, jsclass_t class) { diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 24692f8..c008469 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -24,7 +24,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
-static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsdisp; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index b658324..23dfa8b 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1226,7 +1226,7 @@ sync_test("elem_attr", function() { r = elem.removeAttribute("ondblclick"); ok(r === (v < 8 ? false : (v < 9 ? true : undefined)), "ondblclick removeAttribute returned " + r); r = Object.prototype.toString.call(elem.ondblclick); - todo_wine_if(v >= 9). + todo_wine_if(v >= 11). ok(r === (v < 8 ? "[object Array]" : (v < 9 ? "[object Object]" : (v < 11 ? "[object Null]" : "[object Function]"))), "removed ondblclick Object.toString returned " + r);
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 58b0d43..84b5f36 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -797,7 +797,6 @@ sync_test("toString", function() { todo_wine. ok(tmp === "[object Window]", "toString.call(null) = " + tmp); tmp = Object.prototype.toString.call(null); - todo_wine. ok(tmp === "[object Null]", "toString.call(null) = " + tmp); tmp = Object.prototype.toString.call(undefined); todo_wine.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102723
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE