From: Gabriel Ivăncescu gabrielopcode@gmail.com
'expando' returns TRUE on non-builtin attributes (builtin attributes are only the builtin accessors, not methods), while 'specified' always returns TRUE on any non-builtin attribute as long as it has a user-defined value (e.g. for builtin methods, their slot must be non-default), which is an extension to just checking the dynamic props.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 40 +++++++++++++++++++++++++++++++ dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/mshtml_private.h | 2 ++ dlls/mshtml/tests/documentmode.js | 4 ++++ 4 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 103a8f7718b..cec42a9446c 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1816,6 +1816,22 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return call_builtin_function(dispex, func, dp, res, ei, caller); }
+BOOL dispex_is_builtin_attribute(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(id == DISPID_VALUE) + return TRUE; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + return func->func_disp_idx < 0; +} + BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) { func_info_t *func; @@ -1837,6 +1853,30 @@ BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) return TRUE; }
+BOOL dispex_is_builtin_value(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + if(func->func_disp_idx < 0) + return TRUE; + + if(dispex->dynamic_data && dispex->dynamic_data->func_disps) { + func_obj_entry_t *entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + + if(entry->func_obj && (V_VT(&entry->val) != VT_DISPATCH || + V_DISPATCH(&entry->val) != (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface)) + return FALSE; + } + + return TRUE; +} + static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) { func_obj_entry_t *entry; diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index deb58b9eb64..473ad96165f 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -116,7 +116,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V return S_OK; }
- if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) { + if(!dispex_is_builtin_value(&This->elem->node.event_target.dispex, This->dispid)) { *p = VARIANT_TRUE; return S_OK; } @@ -242,7 +242,7 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V
TRACE("(%p)->(%p)\n", This, p);
- *p = variant_bool(This->elem && get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN); + *p = variant_bool(This->elem && !dispex_is_builtin_attribute(&This->elem->node.event_target.dispex, This->dispid)); return S_OK; }
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index fab7aeae6de..3fef723019c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -631,7 +631,9 @@ const void *dispex_get_vtbl(DispatchEx*); void dispex_info_add_interface(dispex_data_t*,tid_t,const dispex_hook_t*); void dispex_info_add_dispids(dispex_data_t*,tid_t,const DISPID*); compat_mode_t dispex_compat_mode(DispatchEx*); +BOOL dispex_is_builtin_attribute(DispatchEx*,DISPID);; BOOL dispex_is_builtin_method(DispatchEx*,DISPID); +BOOL dispex_is_builtin_value(DispatchEx*,DISPID); HRESULT dispex_to_string(DispatchEx*,BSTR*); HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index e3bff0e296f..392a6367dbc 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -577,6 +577,7 @@ sync_test("attr_props", function() { elem.setAttribute("id", "test"); elem.setAttribute("test", "wine"); elem.setAttribute("z-index", "foobar"); + elem.setAttribute("removeAttribute", "funcattr");
function test_exposed(prop, expect) { if(expect) @@ -633,6 +634,9 @@ sync_test("attr_props", function() { attr = elem.getAttributeNode("z-index"); test_attr(true, true);
+ attr = elem.getAttributeNode("removeAttribute"); + test_attr(true, true); + attr = elem.getAttributeNode("tabIndex"); if(v < 8) test_attr(false, false);