From: Gabriel Ivăncescu gabrielopcode@gmail.com
'expando' returns TRUE on non-builtin attributes (builtin attributes are only the builtin props, 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 | 37 +++++++++++++++++++++++++++++++ dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/mshtml_private.h | 2 ++ dlls/mshtml/tests/documentmode.js | 2 +- 4 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index eee1c851cf4..16bd4613806 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1875,6 +1875,43 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) } }
+BOOL is_builtin_attribute(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; + + return func->func_disp_idx < 0; +} + +BOOL 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 dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode_t compat_mode) { if(!desc->info_cache[compat_mode]) { diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 634293a75b2..1e6ffed6de8 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -115,7 +115,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V return S_OK; }
- if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) { + if(!is_builtin_value(&This->elem->node.event_target.dispex, This->dispid)) { *p = VARIANT_TRUE; return S_OK; } @@ -251,7 +251,7 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V return hres; }
- *p = variant_bool(This->elem && get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN); + *p = variant_bool(This->elem && !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 b002c94a2f2..9f1055be75a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -630,6 +630,8 @@ HRESULT change_type(VARIANT*,VARIANT*,VARTYPE,IServiceProvider*); HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**); HRESULT get_dispids(tid_t,DWORD*,DISPID**); HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*); +BOOL is_builtin_attribute(DispatchEx*,DISPID); +BOOL is_builtin_value(DispatchEx*,DISPID); HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*); void release_typelib(void); HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 06f5d588a4a..6fcc526f7e3 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -660,7 +660,7 @@ sync_test("attr_props", function() { test_attr(true, true);
attr = elem.getAttributeNode("removeAttribute"); - ok(attr !== null, "removeAttribute attr = null"); + test_attr(true, true);
attr = elem.getAttributeNode("offsetLeft"); if(v < 8)