mshtml: Reset builtin function props to their default values when deleted.

The previous tests bailed out too early on IE8, and did not test builtin
props. Also added todos for tests that we did not even test because of
returning early.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2024-11-13 19:32:43 +02:00 committed by Alexandre Julliard
parent e3258e7620
commit 12755eeb1c
Notes: Alexandre Julliard 2024-11-14 23:12:21 +01:00
Approved-by: Jacek Caban (@jacek)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/wine/merge_requests/6721
2 changed files with 80 additions and 29 deletions

View file

@ -1764,6 +1764,26 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp,
return call_builtin_function(dispex, func, dp, res, ei, caller); return call_builtin_function(dispex, func, dp, res, ei, caller);
} }
static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func)
{
func_obj_entry_t *entry;
if(!dispex->dynamic_data || !dispex->dynamic_data->func_disps ||
!dispex->dynamic_data->func_disps[func->func_disp_idx].func_obj)
return VARIANT_FALSE;
entry = dispex->dynamic_data->func_disps + func->func_disp_idx;
if(V_VT(&entry->val) == VT_DISPATCH &&
V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface)
return VARIANT_FALSE;
VariantClear(&entry->val);
V_VT(&entry->val) = VT_DISPATCH;
V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface;
IDispatch_AddRef(V_DISPATCH(&entry->val));
return VARIANT_TRUE;
}
HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success)
{ {
switch(get_dispid_type(id)) { switch(get_dispid_type(id)) {
@ -1793,26 +1813,7 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success)
/* For builtin functions, we set their value to the original function. */ /* For builtin functions, we set their value to the original function. */
if(func->func_disp_idx >= 0) { if(func->func_disp_idx >= 0) {
func_obj_entry_t *entry; *success = reset_builtin_func(This, func);
if(!This->dynamic_data || !This->dynamic_data->func_disps
|| !This->dynamic_data->func_disps[func->func_disp_idx].func_obj) {
*success = VARIANT_FALSE;
return S_OK;
}
entry = This->dynamic_data->func_disps + func->func_disp_idx;
if(V_VT(&entry->val) == VT_DISPATCH
&& V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface) {
*success = VARIANT_FALSE;
return S_OK;
}
VariantClear(&entry->val);
V_VT(&entry->val) = VT_DISPATCH;
V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface;
IDispatch_AddRef(V_DISPATCH(&entry->val));
*success = VARIANT_TRUE;
return S_OK; return S_OK;
} }
*success = VARIANT_TRUE; *success = VARIANT_TRUE;
@ -2304,7 +2305,8 @@ static HRESULT dispex_prop_delete(DispatchEx *dispex, DISPID id)
return E_NOTIMPL; return E_NOTIMPL;
} }
if(is_dynamic_dispid(id)) { switch(get_dispid_type(id)) {
case DISPEXPROP_DYNAMIC: {
DWORD idx = id - DISPID_DYNPROP_0; DWORD idx = id - DISPID_DYNPROP_0;
dynamic_prop_t *prop; dynamic_prop_t *prop;
@ -2316,6 +2318,24 @@ static HRESULT dispex_prop_delete(DispatchEx *dispex, DISPID id)
prop->flags |= DYNPROP_DELETED; prop->flags |= DYNPROP_DELETED;
return S_OK; return S_OK;
} }
case DISPEXPROP_BUILTIN: {
func_info_t *func;
HRESULT hres;
if(!ensure_real_info(dispex))
return E_OUTOFMEMORY;
hres = get_builtin_func(dispex->info, id, &func);
if(FAILED(hres))
return hres;
if(func->func_disp_idx >= 0)
reset_builtin_func(dispex, func);
return S_OK;
}
default:
break;
}
return S_OK; return S_OK;
} }

View file

@ -1301,7 +1301,7 @@ sync_test("navigator", function() {
sync_test("delete_prop", function() { sync_test("delete_prop", function() {
var v = document.documentMode; var v = document.documentMode;
var obj = document.createElement("div"), r, obj2; var obj = document.createElement("div"), r, obj2, func, prop;
obj.prop1 = true; obj.prop1 = true;
r = false; r = false;
@ -1317,6 +1317,40 @@ sync_test("delete_prop", function() {
ok(!r, "got an unexpected exception"); ok(!r, "got an unexpected exception");
ok(!("prop1" in obj), "prop1 is still in obj"); ok(!("prop1" in obj), "prop1 is still in obj");
/* builtin properties don't throw any exception, but are not really deleted */
r = (delete obj.tagName);
ok(r, "delete returned " + r);
ok("tagName" in obj, "tagName deleted from obj");
ok(obj.tagName === "DIV", "tagName = " + obj.tagName);
prop = obj.id;
r = (delete obj.id);
ok(r, "delete returned " + r);
ok("id" in obj, "id deleted from obj");
ok(obj.id === prop, "id = " + obj.id);
obj.id = "1234";
ok(obj.id === "1234", "id after set to 1234 = " + obj.id);
r = (delete obj.id);
ok(r, "delete returned " + r);
ok("id" in obj, "id deleted from obj");
ok(obj.id === "1234", "id = " + obj.id);
/* builtin functions get reset to their original values */
func = function() { }
prop = obj.setAttribute;
r = (delete obj.setAttribute);
ok(r, "delete returned " + r);
ok("setAttribute" in obj, "setAttribute deleted from obj");
ok(obj.setAttribute === prop, "setAttribute = " + obj.setAttribute);
obj.setAttribute = func;
ok(obj.setAttribute === func, "setAttribute after set to func = " + obj.setAttribute);
r = (delete obj.setAttribute);
ok(r, "delete returned " + r);
ok("setAttribute" in obj, "setAttribute deleted from obj");
ok(obj.setAttribute === prop, "setAttribute = " + obj.setAttribute);
/* again, this time prop1 does not exist */ /* again, this time prop1 does not exist */
r = false; r = false;
try { try {
@ -1326,7 +1360,6 @@ sync_test("delete_prop", function() {
} }
if(v < 9) { if(v < 9) {
ok(r, "did not get an expected exception"); ok(r, "did not get an expected exception");
return;
}else { }else {
ok(!r, "got an unexpected exception"); ok(!r, "got an unexpected exception");
ok(!("prop1" in obj), "prop1 is still in obj"); ok(!("prop1" in obj), "prop1 is still in obj");
@ -1337,12 +1370,6 @@ sync_test("delete_prop", function() {
ok("className" in obj, "className deleted from obj"); ok("className" in obj, "className deleted from obj");
ok(obj.className === "", "className = " + obj.className); ok(obj.className === "", "className = " + obj.className);
/* builtin propertiles don't throw any exception, but are not really deleted */
r = (delete obj.tagName);
ok(r, "delete returned " + r);
ok("tagName" in obj, "tagName deleted from obj");
ok(obj.tagName === "DIV", "tagName = " + obj.tagName);
obj = document.querySelectorAll("*"); obj = document.querySelectorAll("*");
ok("0" in obj, "0 is not in obj"); ok("0" in obj, "0 is not in obj");
obj2 = obj[0]; obj2 = obj[0];
@ -1362,6 +1389,7 @@ sync_test("delete_prop", function() {
r = true; r = true;
} }
if(v < 9) { if(v < 9) {
todo_wine.
ok(r, "did not get an expected exception"); ok(r, "did not get an expected exception");
}else { }else {
ok(!r, "got an unexpected globalprop1 exception"); ok(!r, "got an unexpected globalprop1 exception");
@ -1377,6 +1405,7 @@ sync_test("delete_prop", function() {
r = true; r = true;
} }
if(v < 9) { if(v < 9) {
todo_wine.
ok(r, "did not get an expected globalprop2 exception"); ok(r, "did not get an expected globalprop2 exception");
}else { }else {
ok(!r, "got an unexpected exception"); ok(!r, "got an unexpected exception");
@ -1393,7 +1422,9 @@ sync_test("delete_prop", function() {
r = true; r = true;
} }
if(v < 9) { if(v < 9) {
todo_wine.
ok(r, "did not get an expected exception"); ok(r, "did not get an expected exception");
todo_wine.
ok("globalprop3" in obj, "globalprop3 is not in obj"); ok("globalprop3" in obj, "globalprop3 is not in obj");
}else { }else {
ok(!r, "got an unexpected globalprop3 exception"); ok(!r, "got an unexpected globalprop3 exception");