-- v3: mshtml: Implement 'specified' for detached attributes. mshtml: Detach attribute nodes when removing the attribute from the element. mshtml: Use a helper function to find an attribute in the collection's list. mshtml: Use a BSTR to store the detached attribute's name. mshtml: Don't include non-specified attributes in getAttributeNode from mshtml: Only allow a specific set of builtin props as attributes. mshtml: Use HasAttribute instead of GetAttributeNode when checking if
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlattr.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 1a95c1b482e..ff6173aacdb 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -87,9 +87,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, V static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, VARIANT_BOOL *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - nsIDOMAttr *nsattr; nsAString nsname; nsresult nsres; + cpp_bool r;
TRACE("(%p)->(%p)\n", This, p);
@@ -105,19 +105,10 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V
/* FIXME: This is not exactly right, we have some attributes that don't map directly to Gecko attributes. */ nsAString_InitDepend(&nsname, dispex_builtin_prop_name(&This->elem->node.event_target.dispex, This->dispid)); - nsres = nsIDOMElement_GetAttributeNode(This->elem->dom_element, &nsname, &nsattr); + nsres = nsIDOMElement_HasAttribute(This->elem->dom_element, &nsname, &r); nsAString_Finish(&nsname); - if(NS_FAILED(nsres)) - return E_FAIL;
- /* If the Gecko attribute node can be found, we know that the attribute is specified. - There is no point in calling GetSpecified */ - if(nsattr) { - nsIDOMAttr_Release(nsattr); - *p = VARIANT_TRUE; - }else { - *p = VARIANT_FALSE; - } + *p = variant_bool(NS_SUCCEEDED(nsres) && r); return S_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Surprisingly, this applies even in IE9+ modes when using IHTMLElement4's methods, but we can't test that yet because it's too broken in wine.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 20 ++- dlls/mshtml/htmlelem.c | 89 ++++++++- dlls/mshtml/htmlform.c | 23 ++- dlls/mshtml/htmlframe.c | 54 ++++-- dlls/mshtml/htmlhead.c | 19 +- dlls/mshtml/htmlimg.c | 17 +- dlls/mshtml/htmlinput.c | 70 +++++--- dlls/mshtml/htmllink.c | 20 ++- dlls/mshtml/htmlnode.c | 36 +++- dlls/mshtml/htmlobject.c | 23 ++- dlls/mshtml/htmlscript.c | 22 ++- dlls/mshtml/htmlselect.c | 46 +++-- dlls/mshtml/htmlstyleelem.c | 6 +- dlls/mshtml/htmltable.c | 67 +++++-- dlls/mshtml/htmltextarea.c | 23 ++- dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/tests/dom.c | 338 ++++++++++++++++++++++++++++++++++- 17 files changed, 746 insertions(+), 129 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 695cdaad0e2..60138ea511a 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -62,6 +62,7 @@ typedef struct { SHORT func_disp_idx; USHORT argc; USHORT default_value_cnt; + BOOLEAN noattr; VARTYPE prop_vt; VARTYPE *arg_types; func_arg_info_t *arg_info; @@ -282,7 +283,7 @@ static BOOL is_arg_type_supported(VARTYPE vt) }
static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti, - dispex_hook_invoke_t hook, const WCHAR *name_override) + dispex_hook_invoke_t hook, const WCHAR *name_override, BOOL noattr) { func_info_t *info; BSTR name; @@ -333,6 +334,7 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, info->func_disp_idx = -1; info->prop_vt = VT_EMPTY; info->hook = hook; + info->noattr = noattr; }else { SysFreeString(name); } @@ -342,6 +344,7 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc,
info->func_disp_idx = data->func_disp_cnt++; info->argc = desc->cParams; + info->noattr = TRUE;
assert(info->argc < MAX_ARGS); assert(desc->funckind == FUNC_DISPATCH); @@ -480,9 +483,9 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp } }
- if(!hook || hook->invoke || hook->name) { + if(!hook || hook->invoke || hook->name || hook->noattr) { add_func_info(data, tid, funcdesc, disp_typeinfo ? disp_typeinfo : typeinfo, - hook ? hook->invoke : NULL, hook ? hook->name : NULL); + hook ? hook->invoke : NULL, hook ? hook->name : NULL, hook ? hook->noattr : FALSE); }
ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc); @@ -1996,6 +1999,17 @@ HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) return *ret ? S_OK : E_OUTOFMEMORY; }
+BOOL dispex_builtin_is_noattr(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + HRESULT hres; + + hres = get_builtin_func(dispex->info, id, &func); + assert(SUCCEEDED(hres)); + + return func->noattr; +} + static inline DispatchEx *impl_from_IWineJSDispatchHost(IWineJSDispatchHost *iface) { return CONTAINING_RECORD(iface, DispatchEx, IWineJSDispatchHost_iface); diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index fcc6394c0d2..0e78347881a 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6667,6 +6667,14 @@ static HRESULT IHTMLElement6_setAttribute_hook(DispatchEx *dispex, WORD flags, D return hres; }
+static const dispex_hook_t elem_traversal_noattr_hooks[] = { + {DISPID_IELEMENTTRAVERSAL_FIRSTELEMENTCHILD, .noattr = TRUE}, + {DISPID_IELEMENTTRAVERSAL_LASTELEMENTCHILD, .noattr = TRUE}, + {DISPID_IELEMENTTRAVERSAL_PREVIOUSELEMENTSIBLING, .noattr = TRUE}, + {DISPID_IELEMENTTRAVERSAL_NEXTELEMENTSIBLING, .noattr = TRUE}, + {DISPID_IELEMENTTRAVERSAL_CHILDELEMENTCOUNT, .noattr = TRUE} +}; + void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { static const dispex_hook_t elem6_ie9_hooks[] = { @@ -6699,10 +6707,33 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode)
/* IE9+ */ {DISPID_IHTMLELEMENT_TOSTRING, NULL}, + + /* Common for all modes */ + {DISPID_IHTMLELEMENT_PARENTELEMENT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_CLASSNAME, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_TAGNAME, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OFFSETLEFT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OFFSETTOP, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OFFSETWIDTH, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OFFSETHEIGHT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OFFSETPARENT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_DOCUMENT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_SOURCEINDEX, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_RECORDNUMBER, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_INNERHTML, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_INNERTEXT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OUTERHTML, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_OUTERTEXT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_PARENTTEXTEDIT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_ISTEXTEDIT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_FILTERS, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_CHILDREN, .noattr = TRUE}, + {DISPID_IHTMLELEMENT_ALL, .noattr = TRUE}, {DISPID_UNKNOWN} }; const dispex_hook_t *const elem_ie10_hooks = elem_ie11_hooks + 10; const dispex_hook_t *const elem_ie9_hooks = elem_ie10_hooks + 2; + const dispex_hook_t *const elem_hooks = elem_ie9_hooks + 1; static const dispex_hook_t elem2_ie11_hooks[] = { {DISPID_IHTMLELEMENT2_ONLOSECAPTURE}, {DISPID_IHTMLELEMENT2_ONPROPERTYCHANGE}, @@ -6730,10 +6761,28 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) {DISPID_IHTMLELEMENT2_SETEXPRESSION, NULL}, {DISPID_IHTMLELEMENT2_GETEXPRESSION, NULL}, {DISPID_IHTMLELEMENT2_REMOVEEXPRESSION, NULL}, + + /* Common for all modes */ + {DISPID_IHTMLELEMENT2_CURRENTSTYLE, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_SCOPENAME, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_SCROLLHEIGHT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_SCROLLWIDTH, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_SCROLLTOP, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_SCROLLLEFT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_RUNTIMESTYLE, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_CANHAVECHILDREN, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_BEHAVIORURNS, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_TAGURN, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_CLIENTHEIGHT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_CLIENTWIDTH, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_CLIENTTOP, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_CLIENTLEFT, .noattr = TRUE}, + {DISPID_IHTMLELEMENT2_READYSTATE, .noattr = TRUE}, {DISPID_UNKNOWN} }; const dispex_hook_t *const elem2_ie10_hooks = elem2_ie11_hooks + 15; const dispex_hook_t *const elem2_ie9_hooks = elem2_ie10_hooks + 4; + const dispex_hook_t *const elem2_hooks = elem2_ie9_hooks + 3; static const dispex_hook_t elem3_ie11_hooks[] = { {DISPID_IHTMLELEMENT3_ONLAYOUTCOMPLETE}, {DISPID_IHTMLELEMENT3_ONMOVE}, @@ -6746,9 +6795,17 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode)
/* IE9+ */ {DISPID_IHTMLELEMENT3_ONPAGE}, + + /* Common for all modes */ + {DISPID_IHTMLELEMENT3_ISMULTILINE, .noattr = TRUE}, + {DISPID_IHTMLELEMENT3_CANHAVEHTML, .noattr = TRUE}, + {DISPID_IHTMLELEMENT3_ISCONTENTEDITABLE, .noattr = TRUE}, + {DISPID_IHTMLELEMENT3_ISDISABLED, .noattr = TRUE}, + {DISPID_UNKNOWN} }; const dispex_hook_t *const elem3_ie9_hooks = elem3_ie11_hooks + 8; + const dispex_hook_t *const elem3_hooks = elem3_ie9_hooks + 1; static const dispex_hook_t elem7_ie11_hooks[] = { {DISPID_IHTMLELEMENT7_ONMSPOINTERHOVER},
@@ -6763,18 +6820,22 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) {DISPID_UNKNOWN} }; const dispex_hook_t *const elem7_ie10_hooks = elem7_ie11_hooks + 1; + static const dispex_hook_t unique_name_noattr_hooks[] = { + {DISPID_IHTMLUNIQUENAME_UNIQUENUMBER, .noattr = TRUE}, + {DISPID_IHTMLUNIQUENAME_UNIQUEID, .noattr = TRUE} + };
HTMLDOMNode_init_dispex_info(info, mode);
dispex_info_add_interface(info, IHTMLElement2_tid, mode >= COMPAT_MODE_IE11 ? elem2_ie11_hooks : mode >= COMPAT_MODE_IE10 ? elem2_ie10_hooks : - mode >= COMPAT_MODE_IE9 ? elem2_ie9_hooks : NULL); + mode >= COMPAT_MODE_IE9 ? elem2_ie9_hooks : elem2_hooks); if(mode >= COMPAT_MODE_IE8) dispex_info_add_interface(info, IElementSelector_tid, NULL);
if(mode >= COMPAT_MODE_IE9) { dispex_info_add_interface(info, IHTMLElement6_tid, mode >= COMPAT_MODE_IE10 ? elem6_ie10_hooks : elem6_ie9_hooks); - dispex_info_add_interface(info, IElementTraversal_tid, NULL); + dispex_info_add_interface(info, IElementTraversal_tid, elem_traversal_noattr_hooks); }
if(mode >= COMPAT_MODE_IE10) @@ -6785,13 +6846,13 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) }
dispex_info_add_interface(info, IHTMLElement3_tid, mode >= COMPAT_MODE_IE11 ? elem3_ie11_hooks : - mode >= COMPAT_MODE_IE9 ? elem3_ie9_hooks : NULL); + mode >= COMPAT_MODE_IE9 ? elem3_ie9_hooks : elem3_hooks); dispex_info_add_interface(info, IHTMLElement_tid, mode >= COMPAT_MODE_IE11 ? elem_ie11_hooks : mode >= COMPAT_MODE_IE10 ? elem_ie10_hooks : - mode >= COMPAT_MODE_IE9 ? elem_ie9_hooks : NULL); + mode >= COMPAT_MODE_IE9 ? elem_ie9_hooks : elem_hooks); dispex_info_add_interface(info, IHTMLElement4_tid, NULL); dispex_info_add_interface(info, IHTMLDOMNode_tid, NULL); - dispex_info_add_interface(info, IHTMLUniqueName_tid, NULL); + dispex_info_add_interface(info, IHTMLUniqueName_tid, unique_name_noattr_hooks); }
static const event_target_vtbl_t HTMLElement_event_target_vtbl = { @@ -7407,7 +7468,7 @@ static void Element_init_dispex_info(dispex_data_t *info, compat_mode_t mode) dispex_info_add_dispids(info, IHTMLElement_tid, elem_dispids); dispex_info_add_dispids(info, IHTMLElement4_tid, elem4_dispids); dispex_info_add_interface(info, IElementSelector_tid, NULL); - dispex_info_add_interface(info, IElementTraversal_tid, NULL); + dispex_info_add_interface(info, IElementTraversal_tid, elem_traversal_noattr_hooks); }
dispex_static_data_t Element_dispex = { @@ -7677,6 +7738,17 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters return S_OK; }
+static inline BOOL is_valid_attr_dispid(HTMLAttributeCollection *col, DISPID id) +{ + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return TRUE; + + if(dispex_builtin_is_noattr(&col->elem->node.event_target.dispex, id)) + return FALSE; + + return TRUE; +} + static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, DISPID *dispid) { DISPID id = start; @@ -7691,6 +7763,8 @@ static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LO return hres; else if(hres == S_FALSE) break; + else if(!is_valid_attr_dispid(This, id)) + continue;
len++; if(len == *idx) @@ -7727,7 +7801,8 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, con } }
- return dispex_get_id(&This->elem->node.event_target.dispex, name, fdexNameCaseInsensitive, id); + hres = dispex_get_id(&This->elem->node.event_target.dispex, name, fdexNameCaseInsensitive, id); + return (FAILED(hres) || is_valid_attr_dispid(This, *id)) ? hres : DISP_E_UNKNOWNNAME; }
static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 49c8b72e883..1af2e942c81 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -887,6 +888,20 @@ static const NodeImplVtbl HTMLFormElementImplVtbl = { .get_attr_col = HTMLElement_get_attr_col, };
+static void HTMLFormElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLFORMELEMENT_ENCODING, .noattr = TRUE}, + {DISPID_IHTMLFORMELEMENT_ELEMENTS, .noattr = TRUE}, + {DISPID_NEWENUM, .noattr = TRUE}, + {DISPID_COLLECTION, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLFormElement_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLFormElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -902,18 +917,12 @@ static const event_target_vtbl_t HTMLFormElement_event_target_vtbl = { .handle_event = HTMLFormElement_handle_event };
-static const tid_t HTMLFormElement_iface_tids[] = { - IHTMLFormElement_tid, - 0 -}; - dispex_static_data_t HTMLFormElement_dispex = { .id = OBJID_HTMLFormElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLFormElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLFormElement_tid, - .iface_tids = HTMLFormElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLFormElement_init_dispex_info, };
HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index 48312b59a21..d5aab3c7fcf 100644 --- a/dlls/mshtml/htmlframe.c +++ b/dlls/mshtml/htmlframe.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "mshtml_private.h" #include "binding.h" @@ -905,6 +906,25 @@ static const NodeImplVtbl HTMLFrameElementImplVtbl = { .bind_to_tree = HTMLFrameElement_bind_to_tree, };
+static void HTMLFrameElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t base2_hooks[] = { + {DISPID_IHTMLFRAMEBASE2_CONTENTWINDOW, .noattr = TRUE}, + {DISPID_IHTMLFRAMEBASE2_READYSTATE, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLFRAMEELEMENT3_CONTENTDOCUMENT, .noattr = TRUE}, + {DISPID_IHTMLFRAMEELEMENT3_IE8_LONGDESC, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLFrameBase_tid, NULL); + dispex_info_add_interface(info, IHTMLFrameBase2_tid, base2_hooks); + dispex_info_add_interface(info, IHTMLFrameElement3_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLFrameElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -920,20 +940,12 @@ static const event_target_vtbl_t HTMLFrameElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLFrameElement_iface_tids[] = { - IHTMLFrameBase_tid, - IHTMLFrameBase2_tid, - IHTMLFrameElement3_tid, - 0 -}; - dispex_static_data_t HTMLFrameElement_dispex = { .id = OBJID_HTMLFrameElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLFrameElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLFrameElement_tid, - .iface_tids = HTMLFrameElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLFrameElement_init_dispex_info, };
HRESULT HTMLFrameElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1340,6 +1352,25 @@ static const NodeImplVtbl HTMLIFrameImplVtbl = { .bind_to_tree = HTMLIFrame_bind_to_tree, };
+static void HTMLIFrameElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t base2_hooks[] = { + {DISPID_IHTMLFRAMEBASE2_CONTENTWINDOW, .noattr = TRUE}, + {DISPID_IHTMLFRAMEBASE2_READYSTATE, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLIFRAMEELEMENT3_CONTENTDOCUMENT, .noattr = TRUE}, + {DISPID_IHTMLIFRAMEELEMENT3_IE8_LONGDESC, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLFrameBase_tid, NULL); + dispex_info_add_interface(info, IHTMLFrameBase2_tid, base2_hooks); + dispex_info_add_interface(info, IHTMLIFrameElement3_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLIFrameElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -1356,11 +1387,8 @@ static const event_target_vtbl_t HTMLIFrameElement_event_target_vtbl = { };
static const tid_t HTMLIFrameElement_iface_tids[] = { - IHTMLFrameBase_tid, - IHTMLFrameBase2_tid, IHTMLIFrameElement_tid, IHTMLIFrameElement2_tid, - IHTMLIFrameElement3_tid, 0 };
@@ -1370,7 +1398,7 @@ dispex_static_data_t HTMLIFrameElement_dispex = { .vtbl = &HTMLIFrameElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLIFrame_tid, .iface_tids = HTMLIFrameElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLIFrameElement_init_dispex_info, };
HRESULT HTMLIFrame_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlhead.c b/dlls/mshtml/htmlhead.c index 2386f243599..79ba13b5e83 100644 --- a/dlls/mshtml/htmlhead.c +++ b/dlls/mshtml/htmlhead.c @@ -402,6 +402,17 @@ static const NodeImplVtbl HTMLMetaElementImplVtbl = { .get_attr_col = HTMLElement_get_attr_col };
+static void HTMLMetaElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLMETAELEMENT_HTTPEQUIV, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLMetaElement_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLMetaElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -414,18 +425,12 @@ static const event_target_vtbl_t HTMLMetaElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLMetaElement_iface_tids[] = { - IHTMLMetaElement_tid, - 0 -}; - dispex_static_data_t HTMLMetaElement_dispex = { .id = OBJID_HTMLMetaElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLMetaElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLMetaElement_tid, - .iface_tids = HTMLMetaElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLMetaElement_init_dispex_info, };
HRESULT HTMLMetaElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 40c2c2dd09b..21f6d5138ff 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -670,12 +670,25 @@ static void HTMLImgElement_init_dispex_info(dispex_data_t *info, compat_mode_t m { static const dispex_hook_t img_ie11_hooks[] = { {DISPID_IHTMLIMGELEMENT_FILESIZE, NULL}, + + /* Common for all modes */ + {DISPID_IHTMLIMGELEMENT_READYSTATE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_COMPLETE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_MIMETYPE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_FILESIZE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_FILECREATEDDATE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_FILEMODIFIEDDATE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_FILEUPDATEDDATE, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_PROTOCOL, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_HREF, .noattr = TRUE}, + {DISPID_IHTMLIMGELEMENT_NAMEPROP, .noattr = TRUE}, {DISPID_UNKNOWN} }; + const dispex_hook_t *const img_hooks = img_ie11_hooks + 1;
- HTMLElement_init_dispex_info(info, mode); + dispex_info_add_interface(info, IHTMLImgElement_tid, mode >= COMPAT_MODE_IE11 ? img_ie11_hooks : img_hooks);
- dispex_info_add_interface(info, IHTMLImgElement_tid, mode >= COMPAT_MODE_IE11 ? img_ie11_hooks : NULL); + HTMLElement_init_dispex_info(info, mode); }
dispex_static_data_t HTMLImageElement_dispex = { diff --git a/dlls/mshtml/htmlinput.c b/dlls/mshtml/htmlinput.c index ca0de3131e3..779085e4107 100644 --- a/dlls/mshtml/htmlinput.c +++ b/dlls/mshtml/htmlinput.c @@ -25,6 +25,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -1270,6 +1271,27 @@ static const NodeImplVtbl HTMLInputElementImplVtbl = { .is_text_edit = HTMLInputElement_is_text_edit };
+static void HTMLInputElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t input_hooks[] = { + {DISPID_IHTMLINPUTELEMENT_READYSTATE, .noattr = TRUE}, + {DISPID_IHTMLINPUTELEMENT_FORM, .noattr = TRUE}, + {DISPID_IHTMLINPUTELEMENT_STATUS, .noattr = TRUE}, + {DISPID_IHTMLINPUTELEMENT_DEFAULTCHECKED, .noattr = TRUE}, + {DISPID_IHTMLINPUTELEMENT_COMPLETE, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t inputtext_hooks[] = { + {DISPID_IHTMLINPUTTEXTELEMENT2_SELECTIONSTART, .noattr = TRUE}, + {DISPID_IHTMLINPUTTEXTELEMENT2_SELECTIONEND, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLInputElement_tid, input_hooks); + dispex_info_add_interface(info, IHTMLInputTextElement2_tid, inputtext_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLInputElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -1282,18 +1304,12 @@ static const event_target_vtbl_t HTMLInputElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLInputElement_iface_tids[] = { - IHTMLInputElement_tid, - IHTMLInputTextElement2_tid, - 0 -}; dispex_static_data_t HTMLInputElement_dispex = { .id = OBJID_HTMLInputElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLInputElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLInputElement_tid, - .iface_tids = HTMLInputElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLInputElement_init_dispex_info, };
HRESULT HTMLInputElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1413,6 +1429,17 @@ static const NodeImplVtbl HTMLLabelElementImplVtbl = { .get_attr_col = HTMLElement_get_attr_col, };
+static void HTMLLabelElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t label_hooks[] = { + {DISPID_IHTMLLABELELEMENT_HTMLFOR, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLLabelElement_tid, label_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLLabelElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -1425,18 +1452,12 @@ static const event_target_vtbl_t HTMLLabelElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLLabelElement_iface_tids[] = { - IHTMLLabelElement_tid, - 0 -}; - dispex_static_data_t HTMLLabelElement_dispex = { .id = OBJID_HTMLLabelElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLLabelElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLLabelElement_tid, - .iface_tids = HTMLLabelElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLLabelElement_init_dispex_info, };
HRESULT HTMLLabelElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1699,6 +1720,19 @@ static const NodeImplVtbl HTMLButtonElementImplVtbl = { .is_text_edit = HTMLButtonElement_is_text_edit };
+static void HTMLButtonElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t button_hooks[] = { + {DISPID_IHTMLBUTTONELEMENT_FORM, .noattr = TRUE}, + {DISPID_IHTMLBUTTONELEMENT_VALUE, .noattr = TRUE}, + {DISPID_IHTMLBUTTONELEMENT_STATUS, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLButtonElement_tid, button_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLButtonElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -1711,18 +1745,12 @@ static const event_target_vtbl_t HTMLButtonElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLButtonElement_iface_tids[] = { - IHTMLButtonElement_tid, - 0 -}; - dispex_static_data_t HTMLButtonElement_dispex = { .id = OBJID_HTMLButtonElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLButtonElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLButtonElement_tid, - .iface_tids = HTMLButtonElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLButtonElement_init_dispex_info, };
HRESULT HTMLButtonElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmllink.c b/dlls/mshtml/htmllink.c index 9ad66eef52e..f7e1ae4c42b 100644 --- a/dlls/mshtml/htmllink.c +++ b/dlls/mshtml/htmllink.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -370,6 +371,18 @@ static const NodeImplVtbl HTMLLinkElementImplVtbl = { .get_disabled = HTMLLinkElementImpl_get_disabled, };
+static void HTMLLinkElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t link_hooks[] = { + {DISPID_IHTMLLINKELEMENT_STYLESHEET, .noattr = TRUE}, + {DISPID_IHTMLLINKELEMENT_READYSTATE, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLLinkElement_tid, link_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLLinkElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -382,17 +395,12 @@ static const event_target_vtbl_t HTMLLinkElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLLinkElement_iface_tids[] = { - IHTMLLinkElement_tid, - 0 -}; dispex_static_data_t HTMLLinkElement_dispex = { .id = OBJID_HTMLLinkElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLLinkElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLLinkElement_tid, - .iface_tids = HTMLLinkElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLLinkElement_init_dispex_info, };
HRESULT HTMLLinkElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index 84c3e669109..3ace6fcdf7c 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -1296,15 +1296,43 @@ void HTMLDOMNode_init_dispex_info(dispex_data_t *info, compat_mode_t mode) {DISPID_IHTMLDOMNODE_REMOVENODE, NULL}, {DISPID_IHTMLDOMNODE_REPLACENODE, NULL}, {DISPID_IHTMLDOMNODE_SWAPNODE, NULL}, + + /* Common for all modes */ + {DISPID_IHTMLDOMNODE_NODETYPE, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_PARENTNODE, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_CHILDNODES, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_ATTRIBUTES, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_NODENAME, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_NODEVALUE, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_FIRSTCHILD, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_LASTCHILD, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_PREVIOUSSIBLING, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE_NEXTSIBLING, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + const dispex_hook_t *const hooks = ie9_hooks + 3; + static const dispex_hook_t node2_hooks[] = { + {DISPID_IHTMLDOMNODE2_OWNERDOCUMENT, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t node3_hooks[] = { + {DISPID_IHTMLDOMNODE3_LOCALNAME, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE3_NAMESPACEURI, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE3_PREFIX, .noattr = TRUE}, + {DISPID_IHTMLDOMNODE3_TEXTCONTENT, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t priv_hooks[] = { + {DISPID_IHTMLELEMENT6_IE9_HASATTRIBUTES, .noattr = TRUE}, {DISPID_UNKNOWN} };
- dispex_info_add_interface(info, IHTMLDOMNode_tid, mode >= COMPAT_MODE_IE9 ? ie9_hooks : NULL); - dispex_info_add_interface(info, IHTMLDOMNode2_tid, NULL); + dispex_info_add_interface(info, IHTMLDOMNode_tid, mode >= COMPAT_MODE_IE9 ? ie9_hooks : hooks); + dispex_info_add_interface(info, IHTMLDOMNode2_tid, node2_hooks);
if(mode >= COMPAT_MODE_IE9) { - dispex_info_add_interface(info, IHTMLDOMNode3_tid, NULL); - dispex_info_add_interface(info, IWineHTMLDOMNodePrivate_tid, NULL); + dispex_info_add_interface(info, IHTMLDOMNode3_tid, node3_hooks); + dispex_info_add_interface(info, IWineHTMLDOMNodePrivate_tid, priv_hooks); }
EventTarget_init_dispex_info(info, mode); diff --git a/dlls/mshtml/htmlobject.c b/dlls/mshtml/htmlobject.c index ca49708d54e..f24f39deb74 100644 --- a/dlls/mshtml/htmlobject.c +++ b/dlls/mshtml/htmlobject.c @@ -25,6 +25,7 @@ #include "winuser.h" #include "winreg.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -661,6 +662,20 @@ static const NodeImplVtbl HTMLObjectElementImplVtbl = { .get_readystate = HTMLObjectElement_get_readystate, };
+static void HTMLObjectElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLOBJECTELEMENT_BASEHREF, .noattr = TRUE}, + {DISPID_IHTMLOBJECTELEMENT_FORM, .noattr = TRUE}, + {DISPID_IHTMLOBJECTELEMENT_ALTHTML, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLObjectElement2_tid, hooks); + dispex_info_add_interface(info, IHTMLObjectElement_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLObjectElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -676,18 +691,12 @@ static const event_target_vtbl_t HTMLObjectElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLObjectElement_iface_tids[] = { - IHTMLObjectElement2_tid, - IHTMLObjectElement_tid, - 0 -}; dispex_static_data_t HTMLObjectElement_dispex = { .id = OBJID_HTMLObjectElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLObjectElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLObjectElement_tid, - .iface_tids = HTMLObjectElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLObjectElement_init_dispex_info, };
HRESULT HTMLObjectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlscript.c b/dlls/mshtml/htmlscript.c index 9e21d15ce26..45f0808975a 100644 --- a/dlls/mshtml/htmlscript.c +++ b/dlls/mshtml/htmlscript.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -376,6 +377,19 @@ static const NodeImplVtbl HTMLScriptElementImplVtbl = { .bind_to_tree = HTMLScriptElement_bind_to_tree, };
+static void HTMLScriptElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLSCRIPTELEMENT_HTMLFOR, .noattr = TRUE}, + {DISPID_IHTMLSCRIPTELEMENT_TEXT, .noattr = TRUE}, + {DISPID_IHTMLSCRIPTELEMENT_READYSTATE, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLScriptElement_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLScriptElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -408,18 +422,12 @@ HRESULT script_elem_from_nsscript(nsIDOMHTMLScriptElement *nsscript, HTMLScriptE return S_OK; }
-static const tid_t HTMLScriptElement_iface_tids[] = { - IHTMLScriptElement_tid, - 0 -}; - dispex_static_data_t HTMLScriptElement_dispex = { .id = OBJID_HTMLScriptElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLScriptElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLScriptElement_tid, - .iface_tids = HTMLScriptElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLScriptElement_init_dispex_info, };
HRESULT HTMLScriptElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index a126f977697..97a47e38762 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -328,6 +329,20 @@ static const NodeImplVtbl HTMLOptionElementImplVtbl = { .get_attr_col = HTMLElement_get_attr_col, };
+static void HTMLOptionElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t option_hooks[] = { + {DISPID_IHTMLOPTIONELEMENT_DEFAULTSELECTED, .noattr = TRUE}, + {DISPID_IHTMLOPTIONELEMENT_TEXT, .noattr = TRUE}, + {DISPID_IHTMLOPTIONELEMENT_INDEX, .noattr = TRUE}, + {DISPID_IHTMLOPTIONELEMENT_FORM, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLOptionElement_tid, option_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLOptionElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -340,17 +355,12 @@ static const event_target_vtbl_t HTMLOptionElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLOptionElement_iface_tids[] = { - IHTMLOptionElement_tid, - 0 -}; dispex_static_data_t HTMLOptionElement_dispex = { .id = OBJID_HTMLOptionElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLOptionElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLOptionElement_tid, - .iface_tids = HTMLOptionElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLOptionElement_init_dispex_info, };
HRESULT HTMLOptionElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1238,6 +1248,22 @@ static const NodeImplVtbl HTMLSelectElementImplVtbl = { .get_disabled = HTMLSelectElementImpl_get_disabled, };
+static void HTMLSelectElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t select_hooks[] = { + {DISPID_IHTMLSELECTELEMENT_FORM, .noattr = TRUE}, + {DISPID_IHTMLSELECTELEMENT_OPTIONS, .noattr = TRUE}, + {DISPID_IHTMLSELECTELEMENT_SELECTEDINDEX, .noattr = TRUE}, + {DISPID_IHTMLSELECTELEMENT_VALUE, .noattr = TRUE}, + {DISPID_IHTMLSELECTELEMENT_TYPE, .noattr = TRUE}, + {DISPID_COLLECTION, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLSelectElement_tid, select_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLSelectElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -1253,18 +1279,12 @@ static const event_target_vtbl_t HTMLSelectElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLSelectElement_tids[] = { - IHTMLSelectElement_tid, - 0 -}; - dispex_static_data_t HTMLSelectElement_dispex = { .id = OBJID_HTMLSelectElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLSelectElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLSelectElement_tid, - .iface_tids = HTMLSelectElement_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLSelectElement_init_dispex_info, };
HRESULT HTMLSelectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlstyleelem.c b/dlls/mshtml/htmlstyleelem.c index d400f4980cb..4c3a222471e 100644 --- a/dlls/mshtml/htmlstyleelem.c +++ b/dlls/mshtml/htmlstyleelem.c @@ -302,11 +302,15 @@ static void HTMLStyleElement_init_dispex_info(dispex_data_t *info, compat_mode_t {DISPID_IHTMLSTYLEELEMENT_STYLESHEET, NULL}, {DISPID_UNKNOWN} }; + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLSTYLEELEMENT_STYLESHEET, .noattr = TRUE}, + {DISPID_UNKNOWN} + };
HTMLElement_init_dispex_info(info, mode);
dispex_info_add_interface(info, IHTMLStyleElement_tid, - mode >= COMPAT_MODE_IE11 ? ie11_hooks : NULL); + mode >= COMPAT_MODE_IE11 ? ie11_hooks : hooks);
if(mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLStyleElement2_tid, NULL); diff --git a/dlls/mshtml/htmltable.c b/dlls/mshtml/htmltable.c index 27e1d258b22..26b14c72cfa 100644 --- a/dlls/mshtml/htmltable.c +++ b/dlls/mshtml/htmltable.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -430,17 +431,22 @@ static const NodeImplVtbl HTMLTableCellImplVtbl = { .get_attr_col = HTMLElement_get_attr_col, };
-static const tid_t HTMLTableDataCellElement_iface_tids[] = { - IHTMLTableCell_tid, - 0 -}; +static void HTMLTableCellElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLTABLECELL_CELLINDEX, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLTableCell_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +}
dispex_static_data_t HTMLTableCellElement_dispex = { .id = OBJID_HTMLTableCellElement, .prototype_id = OBJID_HTMLElement, .disp_tid = DispHTMLTableCell_tid, - .iface_tids = HTMLTableDataCellElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLTableCellElement_init_dispex_info, };
static const event_target_vtbl_t HTMLTableDataCellElement_event_target_vtbl = { @@ -460,8 +466,7 @@ dispex_static_data_t HTMLTableDataCellElement_dispex = { .prototype_id = OBJID_HTMLTableCellElement, .vtbl = &HTMLTableDataCellElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLTableCell_tid, - .iface_tids = HTMLTableDataCellElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLTableCellElement_init_dispex_info, };
HRESULT HTMLTableCell_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -812,6 +817,19 @@ static const NodeImplVtbl HTMLTableRowImplVtbl = { .get_attr_col = HTMLElement_get_attr_col, };
+static void HTMLTableRowElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLTABLEROW_ROWINDEX, .noattr = TRUE}, + {DISPID_IHTMLTABLEROW_SECTIONROWINDEX, .noattr = TRUE}, + {DISPID_IHTMLTABLEROW_CELLS, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLTableRow_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLTableRowElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -824,18 +842,12 @@ static const event_target_vtbl_t HTMLTableRowElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLTableRowElement_iface_tids[] = { - IHTMLTableRow_tid, - 0 -}; - dispex_static_data_t HTMLTableRowElement_dispex = { .id = OBJID_HTMLTableRowElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLTableRowElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLTableRow_tid, - .iface_tids = HTMLTableRowElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLTableRowElement_init_dispex_info, };
HRESULT HTMLTableRow_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1663,6 +1675,27 @@ static const NodeImplVtbl HTMLTableImplVtbl = { .get_attr_col = HTMLElement_get_attr_col, };
+static void HTMLTableElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t table_hooks[] = { + {DISPID_IHTMLTABLE_ROWS, .noattr = TRUE}, + {DISPID_IHTMLTABLE_THEAD, .noattr = TRUE}, + {DISPID_IHTMLTABLE_TFOOT, .noattr = TRUE}, + {DISPID_IHTMLTABLE_TBODIES, .noattr = TRUE}, + {DISPID_IHTMLTABLE_CAPTION, .noattr = TRUE}, + {DISPID_IHTMLTABLE_READYSTATE, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t table2_hooks[] = { + {DISPID_IHTMLTABLE2_CELLS, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLTable_tid, table_hooks); + dispex_info_add_interface(info, IHTMLTable2_tid, table2_hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLTableElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -1676,8 +1709,6 @@ static const event_target_vtbl_t HTMLTableElement_event_target_vtbl = { };
static const tid_t HTMLTableElement_iface_tids[] = { - IHTMLTable_tid, - IHTMLTable2_tid, IHTMLTable3_tid, 0 }; @@ -1688,7 +1719,7 @@ dispex_static_data_t HTMLTableElement_dispex = { .vtbl = &HTMLTableElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLTable_tid, .iface_tids = HTMLTableElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLTableElement_init_dispex_info, };
HRESULT HTMLTable_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmltextarea.c b/dlls/mshtml/htmltextarea.c index e8a846047e8..3eb714b7b08 100644 --- a/dlls/mshtml/htmltextarea.c +++ b/dlls/mshtml/htmltextarea.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h"
#include "wine/debug.h"
@@ -397,6 +398,20 @@ static const NodeImplVtbl HTMLTextAreaElementImplVtbl = { .is_text_edit = HTMLTextAreaElement_is_text_edit };
+static void HTMLTextAreaElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLTEXTAREAELEMENT_FORM, .noattr = TRUE}, + {DISPID_IHTMLTEXTAREAELEMENT_VALUE, .noattr = TRUE}, + {DISPID_IHTMLTEXTAREAELEMENT_TYPE, .noattr = TRUE}, + {DISPID_IHTMLTEXTAREAELEMENT_STATUS, .noattr = TRUE}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLTextAreaElement_tid, hooks); + + HTMLElement_init_dispex_info(info, mode); +} + static const event_target_vtbl_t HTMLTextAreaElement_event_target_vtbl = { { HTMLELEMENT_DISPEX_VTBL_ENTRIES, @@ -409,18 +424,12 @@ static const event_target_vtbl_t HTMLTextAreaElement_event_target_vtbl = { .handle_event = HTMLElement_handle_event };
-static const tid_t HTMLTextAreaElement_iface_tids[] = { - IHTMLTextAreaElement_tid, - 0 -}; - dispex_static_data_t HTMLTextAreaElement_dispex = { .id = OBJID_HTMLTextAreaElement, .prototype_id = OBJID_HTMLElement, .vtbl = &HTMLTextAreaElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLTextAreaElement_tid, - .iface_tids = HTMLTextAreaElement_iface_tids, - .init_info = HTMLElement_init_dispex_info, + .init_info = HTMLTextAreaElement_init_dispex_info, };
HRESULT HTMLTextAreaElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4319c8b4725..4eac921223f 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -548,6 +548,7 @@ typedef struct { DISPID dispid; dispex_hook_invoke_t invoke; const WCHAR *name; + BOOL noattr; } dispex_hook_t;
struct DispatchEx { @@ -649,6 +650,7 @@ HRESULT dispex_prop_name(DispatchEx *dispex, DISPID id, BSTR *ret); HRESULT dispex_define_property(DispatchEx *dispex, const WCHAR *name, DWORD flags, VARIANT *v, DISPID *id); HRESULT dispex_index_prop_desc(DispatchEx*,DISPID,struct property_info*); const WCHAR *dispex_builtin_prop_name(DispatchEx *dispex, DISPID id); +BOOL dispex_builtin_is_noattr(DispatchEx *dispex, DISPID id); IWineJSDispatchHost *dispex_outer_iface(DispatchEx *dispex); HRESULT get_constructor(HTMLInnerWindow *script_global, object_id_t id, DispatchEx **ret); HRESULT get_prototype(HTMLInnerWindow *script_global, object_id_t id, DispatchEx **ret); diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 9eb7bac9a11..1a0a8295fd1 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -3794,18 +3794,20 @@ static void test_attr_collection_disp(IDispatch *disp)
static void test_attr_collection(IHTMLElement *elem) { - static const WCHAR testW[] = {'t','e','s','t',0}; - - IHTMLDOMNode *node; - IDispatch *disp, *attr; IHTMLAttributeCollection *attr_col; - BSTR name = SysAllocString(testW); + IDispatch *disp, *attr; IEnumVARIANT *enum_var; + DISPPARAMS dp = { 0 }; + LONG i, len, checked; + IDispatchEx *dispex; + IHTMLDOMNode *node; IUnknown *enum_unk; VARIANT id, val; - LONG i, len, checked; + DISPID dispid; ULONG fetched; + EXCEPINFO ei; HRESULT hres; + BSTR name;
hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLDOMNode, (void**)&node); ok(hres == S_OK, "QueryInterface failed: %08lx\n", hres); @@ -3822,11 +3824,31 @@ static void test_attr_collection(IHTMLElement *elem) hres = IDispatch_QueryInterface(disp, &IID_IHTMLAttributeCollection, (void**)&attr_col); ok(hres == S_OK, "QueryInterface failed: %08lx\n", hres);
+ hres = IUnknown_QueryInterface(elem, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "QueryInterface failed: %08lx\n", hres); + + name = SysAllocString(L"attributes"); + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(name); + + VariantInit(&val); + hres = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dp, &val, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&val) == VT_DISPATCH, "V_VT(attributes) = %d\n", V_VT(&val)); + ok(V_DISPATCH(&val) != NULL, "V_DISPATCH(attributes) == NULL\n"); + + ok(iface_cmp((IUnknown*)attr_col, (IUnknown*)V_DISPATCH(&val)), "attr_col != attr_col from disp\n"); + IDispatchEx_Release(dispex); + VariantClear(&val); + hres = IHTMLAttributeCollection_get_length(attr_col, &i); ok(hres == S_OK, "get_length failed: %08lx\n", hres); + ok(i > 3, "length = %ld\n", i);
V_VT(&val) = VT_I4; V_I4(&val) = 1; + name = SysAllocString(L"test"); hres = IHTMLElement_setAttribute(elem, name, val, 0); ok(hres == S_OK, "setAttribute failed: %08lx\n", hres); SysFreeString(name); @@ -3892,6 +3914,250 @@ static void test_attr_collection(IHTMLElement *elem) IHTMLAttributeCollection_Release(attr_col); }
+static void test_attr_collection_builtins(IHTMLDocument2 *doc) +{ + static const WCHAR *generic_builtins[] = { + L"accessKey", L"aria-activedescendant", L"aria-atomic", L"aria-autocomplete", L"aria-busy", L"aria-checked", L"aria-controls", L"aria-describedby", + L"aria-disabled", L"aria-dropeffect", L"aria-expanded", L"aria-flowto", L"aria-grabbed", L"aria-haspopup", L"aria-hidden", L"aria-invalid", L"aria-label", + L"aria-labelledby", L"aria-level", L"aria-live", L"aria-multiline", L"aria-multiselectable", L"aria-orientation", L"aria-owns", L"aria-posinset", + L"aria-pressed", L"aria-readonly", L"aria-relevant", L"aria-required", L"aria-secret", L"aria-selected", L"aria-setsize", L"aria-sort", L"aria-valuemax", + L"aria-valuemin", L"aria-valuenow", L"aria-valuetext", L"class", L"contentEditable", L"dataFld", L"dataFormatAs", L"dataSrc", L"dir", L"disabled", + L"hideFocus", L"id", L"implementation", L"lang", L"language", L"onactivate", L"onafterupdate", L"onbeforeactivate", L"onbeforecopy", L"onbeforecut", + L"onbeforedeactivate", L"onbeforeeditfocus", L"onbeforepaste", L"onbeforeupdate", L"onblur", L"oncellchange", L"onclick", L"oncontextmenu", L"oncontrolselect", + L"oncopy", L"oncuechange", L"oncut", L"ondataavailable", L"ondatasetchanged", L"ondatasetcomplete", L"ondblclick", L"ondeactivate", L"ondrag", L"ondragend", + L"ondragenter", L"ondragleave", L"ondragover", L"ondragstart", L"ondrop", L"onerrorupdate", L"onfilterchange", L"onfocus", L"onfocusin", L"onfocusout", + L"onhelp", L"oninvalid", L"onkeydown", L"onkeypress", L"onkeyup", L"onlayoutcomplete", L"onlosecapture", L"onmousedown", L"onmouseenter", L"onmouseleave", + L"onmousemove", L"onmouseout", L"onmouseover", L"onmouseup", L"onmousewheel", L"onmove", L"onmoveend", L"onmovestart", L"onmsanimationend", + L"onmsanimationiteration", L"onmsanimationstart", L"onmsmanipulationstatechanged", L"onmstransitionend", L"onmstransitionstart", L"onpage", L"onpaste", + L"onpropertychange", L"onreadystatechange", L"onresize", L"onresizeend", L"onresizestart", L"onrowenter", L"onrowexit", L"onrowsdelete", L"onrowsinserted", + L"onscroll", L"onselectstart", L"role", L"spellcheck", L"style", L"tabIndex", L"title", L"x-ms-acceleratorkey", L"x-ms-aria-flowfrom" + }; + static const WCHAR *generic_builtins_todo[] = { + L"aria-activedescendant", L"aria-atomic", L"aria-autocomplete", L"aria-busy", L"aria-checked", L"aria-controls", L"aria-describedby", L"aria-disabled", + L"aria-dropeffect", L"aria-expanded", L"aria-flowto", L"aria-grabbed", L"aria-haspopup", L"aria-hidden", L"aria-invalid", L"aria-label", L"aria-labelledby", + L"aria-level", L"aria-live", L"aria-multiline", L"aria-multiselectable", L"aria-orientation", L"aria-owns", L"aria-posinset", L"aria-pressed", L"aria-readonly", + L"aria-relevant", L"aria-required", L"aria-secret", L"aria-selected", L"aria-setsize", L"aria-sort", L"aria-valuemax", L"aria-valuemin", L"aria-valuenow", + L"aria-valuetext", L"class", L"dataFld", L"dataFormatAs", L"dataSrc", L"implementation", L"oncuechange", L"oninvalid", L"onmouseenter", L"onmsanimationend", + L"onmsanimationiteration", L"onmsanimationstart", L"onmsmanipulationstatechanged", L"onmstransitionend", L"onmstransitionstart", L"role", L"spellcheck", + L"x-ms-acceleratorkey", L"x-ms-aria-flowfrom" + }; + static const WCHAR *tags[] = { + L"audio", NULL, + L"b", L"cite", L"dateTime", NULL, + L"base", L"href", L"target", NULL, + L"basefont", L"color", L"face", L"size", NULL, + L"body", L"aLink", L"background", L"bgColor", L"bgProperties", L"bottomMargin", L"leftMargin", L"link", L"noWrap", L"onafterprint", L"onbeforeprint", L"onbeforeunload", + L"onhashchange", L"onload", L"onoffline", L"ononline", L"onselect", L"onunload", L"rightMargin", L"scroll", L"text", L"topMargin", L"vLink", NULL, + L"br", L"clear", NULL, + L"button", L"formaction", L"formenctype", L"formmethod", L"formnovalidate", L"formtarget", L"name", L"type", NULL, + L"caption", L"align", L"vAlign", NULL, + L"center", L"cite", L"clear", L"width", NULL, + L"code", L"cite", L"dateTime", NULL, + L"col", L"align", L"bgColor", L"ch", L"chOff", L"span", L"vAlign", L"width", NULL, + L"dd", L"noWrap", NULL, + L"dir", L"compact", L"type", NULL, + L"div", L"align", L"nofocusrect", L"noWrap", NULL, + L"dl", L"compact", NULL, + L"dt", L"noWrap", NULL, + L"embed", L"align", L"codeBase", L"height", L"hidden", L"name", L"palette", L"pluginspage", L"src", L"type", L"units", L"width", NULL, + L"fieldset", L"align", NULL, + L"font", L"color", L"face", L"size", NULL, + L"form", L"accept-charset", L"action", L"encType", L"method", L"name", L"onreset", L"onsubmit", L"target", NULL, + L"frame", L"allowTransparency", L"border", L"borderColor", L"frameBorder", L"frameSpacing", L"longDesc", L"marginHeight", L"marginWidth", L"name", L"noResize", L"onload", L"scrolling", L"src", NULL, + L"frameset", L"border", L"borderColor", L"cols", L"frameBorder", L"frameSpacing", L"name", L"onafterprint", L"onbeforeprint", L"onbeforeunload", L"onload", L"onunload", L"rows", NULL, + L"h1", L"align", L"cite", L"clear", L"width", NULL, + L"head", L"profile", NULL, + L"hr", L"align", L"color", L"noShade", L"SIZE", L"width", NULL, + L"html", L"version", NULL, + L"i", L"cite", L"dateTime", NULL, + L"iframe", L"align", L"allowTransparency", L"border", L"frameBorder", L"frameSpacing", L"height", L"hspace", L"longDesc", L"marginHeight", L"marginWidth", + L"name", L"noResize", L"onload", L"scrolling", L"src", L"vspace", L"width", NULL, + L"img", L"align", L"alt", L"border", L"dynsrc", L"height", L"hspace", L"isMap", L"longDesc", L"loop", L"lowsrc", L"name", + L"onabort", L"onerror", L"onload", L"src", L"start", L"useMap", L"vrml", L"vspace", L"width", NULL, + L"input", L"accept", L"align", L"alt", L"border", L"cache", L"checked", L"dynsrc", L"formaction", L"formenctype", L"formmethod", L"formnovalidate", L"formtarget", + L"height", L"hspace", L"indeterminate", L"loop", L"lowsrc", L"maxLength", L"name", L"onabort", L"onchange", L"onerror", L"onload", L"onselect", L"readOnly", + L"size", L"src", L"start", L"type", L"useMap", L"value", L"vrml", L"vspace", L"width", NULL, + L"label", L"for", NULL, + L"legend", L"align", NULL, + L"li", L"type", L"value", NULL, + L"link", L"charset", L"href", L"hreflang", L"media", L"onerror", L"onload", L"rel", L"rev", L"target", L"type", NULL, + L"map", L"name", NULL, + L"meta", L"charset", L"content", L"http-equiv", L"name", L"scheme", L"url", NULL, + L"noscript", NULL, + L"object", L"align", L"alt", L"archive", L"border", L"classid", L"code", L"codeBase", L"codeType", L"data", L"declare", L"height", + L"hspace", L"name", L"object", L"onerror", L"standby", L"type", L"useMap", L"vspace", L"width", NULL, + L"ol", L"compact", L"start", L"type", NULL, + L"option", L"label", L"selected", L"value", NULL, + L"p", L"align", L"cite", L"clear", L"width", NULL, + L"param", L"name", L"type", L"value", L"valueType", NULL, + L"pre", L"cite", L"clear", L"width", NULL, + L"q", L"cite", L"dateTime", NULL, + L"script", L"charset", L"defer", L"event", L"for", L"onerror", L"src", L"type", NULL, + L"select", L"align", L"multiple", L"name", L"onchange", L"size", NULL, + L"span", L"cite", L"dateTime", L"nofocusrect", NULL, + L"style", L"media", L"onerror", L"onload", L"type", NULL, + L"table", L"align", L"background", L"bgColor", L"border", L"borderColor", L"borderColorDark", L"borderColorLight", L"cellPadding", L"cellSpacing", + L"cols", L"dataPageSize", L"frame", L"height", L"rules", L"summary", L"width", NULL, + L"tbody", L"align", L"bgColor", L"ch", L"chOff", L"vAlign", NULL, + L"td", L"abbr", L"align", L"axis", L"background", L"bgColor", L"borderColor", L"borderColorDark", L"borderColorLight", L"ch", L"chOff", + L"colSpan", L"headers", L"height", L"noWrap", L"rowSpan", L"scope", L"vAlign", L"width", NULL, + L"textarea", L"cols", L"name", L"onchange", L"onselect", L"readOnly", L"rows", L"wrap", NULL, + L"tr", L"align", L"bgColor", L"borderColor", L"borderColorDark", L"borderColorLight", L"ch", L"chOff", L"height", L"vAlign", NULL, + L"ul", L"compact", L"type", NULL, + L"video", NULL, + L"winetest", NULL, + NULL + }; + static const WCHAR *tags_todo[] = { + L"b", L"cite", L"dateTime", NULL, + L"base", L"href", L"target", NULL, + L"basefont", L"color", L"face", L"size", NULL, + L"body", L"onhashchange", L"onoffline", L"ononline", NULL, + L"br", L"clear", NULL, + L"button", L"formaction", L"formenctype", L"formmethod", L"formnovalidate", L"formtarget", NULL, + L"caption", L"align", L"vAlign", NULL, + L"center", L"cite", L"clear", L"width", NULL, + L"code", L"cite", L"dateTime", NULL, + L"col", L"align", L"bgColor", L"ch", L"chOff", L"span", L"vAlign", L"width", NULL, + L"dd", L"noWrap", NULL, + L"dir", L"compact", L"type", NULL, + L"div", L"align", L"nofocusrect", L"noWrap", NULL, + L"dl", L"compact", NULL, + L"dt", L"noWrap", NULL, + L"embed", L"align", L"codeBase", L"type", NULL, + L"fieldset", L"align", NULL, + L"font", L"color", L"face", L"size", NULL, + L"form", L"accept-charset", L"encType", NULL, + L"frame", L"borderColor", L"longDesc", NULL, + L"frameset", L"border", L"borderColor", L"cols", L"frameBorder", L"frameSpacing", L"name", L"onafterprint", L"onbeforeprint", L"onbeforeunload", L"onload", L"onunload", L"rows", NULL, + L"h1", L"align", L"cite", L"clear", L"width", NULL, + L"hr", L"align", L"color", L"noShade", L"SIZE", L"width", NULL, + L"i", L"cite", L"dateTime", NULL, + L"iframe", L"longDesc", NULL, + L"img", L"longDesc", NULL, + L"input", L"accept", L"cache", L"dynsrc", L"formaction", L"formenctype", L"formmethod", L"formnovalidate", L"formtarget", L"useMap", NULL, + L"label", L"for", NULL, + L"legend", L"align", NULL, + L"li", L"type", L"value", NULL, + L"link", L"charset", L"hreflang", L"target", NULL, + L"map", L"name", NULL, + L"meta", L"http-equiv", L"scheme", NULL, + L"object", L"alt", L"archive", L"border", L"classid", L"data", L"declare", L"object", L"standby", L"useMap", NULL, + L"ol", L"compact", L"start", L"type", NULL, + L"option", L"label", NULL, + L"p", L"align", L"cite", L"clear", L"width", NULL, + L"param", L"name", L"type", L"value", L"valueType", NULL, + L"pre", L"cite", L"clear", L"width", NULL, + L"q", L"cite", L"dateTime", NULL, + L"script", L"charset", L"for", NULL, + L"select", L"align", NULL, + L"span", L"cite", L"dateTime", L"nofocusrect", NULL, + L"tbody", L"align", L"bgColor", L"ch", L"chOff", L"vAlign", NULL, + L"td", L"abbr", L"axis", L"ch", L"chOff", L"headers", L"scope", NULL, + L"tr", L"ch", L"chOff", L"height", NULL, + L"ul", L"compact", L"type", NULL, + NULL + }; + BOOLEAN found[ARRAY_SIZE(generic_builtins)]; + BOOLEAN found_tag_specific[36]; + + const WCHAR **iter = tags, **iter_todo = tags_todo; + IHTMLAttributeCollection *attr_col; + IHTMLDOMAttribute *attr; + IHTMLElement *elem; + IHTMLDOMNode *node; + IDispatch *disp; + LONG i, j, len; + HRESULT hres; + VARIANT id; + BSTR bstr; + + while(*iter) { + const WCHAR *tag = *iter++, **todos = NULL; + + if(*iter_todo && !wcscmp(tag, *iter_todo)) { + todos = ++iter_todo; + while(*iter_todo++) {} + } + + bstr = SysAllocString(tag); + hres = IHTMLDocument2_createElement(doc, bstr, &elem); + ok(hres == S_OK, "[%s] createElement failed: %08lx\n", wine_dbgstr_w(tag), hres); + SysFreeString(bstr); + + hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLDOMNode, (void**)&node); + ok(hres == S_OK, "[%s] Could not get IHTMLDOMNode iface: %08lx\n", wine_dbgstr_w(tag), hres); + IHTMLElement_Release(elem); + + hres = IHTMLDOMNode_get_attributes(node, &disp); + ok(hres == S_OK, "[%s] get_attributes failed: %08lx\n", wine_dbgstr_w(tag), hres); + IHTMLDOMNode_Release(node); + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLAttributeCollection, (void**)&attr_col); + ok(hres == S_OK, "[%s] Could not get IHTMLAttributeCollection iface: %08lx\n", wine_dbgstr_w(tag), hres); + IDispatch_Release(disp); + + hres = IHTMLAttributeCollection_get_length(attr_col, &len); + ok(hres == S_OK, "[%s] get_length failed: %08lx\n", wine_dbgstr_w(tag), hres); + + memset(found, 0, sizeof(found)); + memset(found_tag_specific, 0, sizeof(found_tag_specific)); + for(i = 0; i < len; i++) { + BOOL expected = FALSE; + + V_VT(&id) = VT_I4; + V_I4(&id) = i; + hres = IHTMLAttributeCollection_item(attr_col, &id, &disp); + ok(hres == S_OK, "[%s:%ld] item failed: %08lx\n", wine_dbgstr_w(tag), i, hres); + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLDOMAttribute, (void**)&attr); + ok(hres == S_OK, "[%s:%ld] Could not get IHTMLDOMAttribute iface: %08lx\n", wine_dbgstr_w(tag), i, hres); + IDispatch_Release(disp); + + hres = IHTMLDOMAttribute_get_nodeName(attr, &bstr); + ok(hres == S_OK, "[%s:%ld] get_nodeName failed: %08lx\n", wine_dbgstr_w(tag), i, hres); + IHTMLDOMAttribute_Release(attr); + + for(j = 0; j < ARRAY_SIZE(generic_builtins); j++) { + if(!wcscmp(bstr, generic_builtins[j])) { + found[j] = TRUE; + expected = TRUE; + break; + } + } + if(!expected) { + for(j = 0; iter[j]; j++) { + if(!wcsicmp(bstr, iter[j])) { + found_tag_specific[j] = TRUE; + expected = TRUE; + break; + } + } + } + ok(expected, "[%s] %s is in collection but not in expected list\n", wine_dbgstr_w(tag), wine_dbgstr_w(bstr)); + SysFreeString(bstr); + } + IHTMLAttributeCollection_Release(attr_col); + + for(i = 0; i < ARRAY_SIZE(generic_builtins); i++) { + for(j = 0; !found[i] && j < ARRAY_SIZE(generic_builtins_todo); j++) + if(!wcscmp(generic_builtins[i], generic_builtins_todo[j])) + break; + todo_wine_if(!found[i] && j < ARRAY_SIZE(generic_builtins_todo)) + ok(found[i], "[%s] %s not in collection\n", wine_dbgstr_w(tag), wine_dbgstr_w(generic_builtins[i])); + } + + for(i = 0; iter[i]; i++) { + for(j = 0; !found_tag_specific[i] && todos && todos[j]; j++) + if(!wcscmp(iter[i], todos[j])) + break; + todo_wine_if(!found_tag_specific[i] && todos && todos[j]) + ok(found_tag_specific[i], "[%s] %s not in collection\n", wine_dbgstr_w(tag), wine_dbgstr_w(iter[i])); + } + iter += i + 1; + } +} + #define test_elem_id(e,i) _test_elem_id(__LINE__,e,i) static void _test_elem_id(unsigned line, IUnknown *unk, const WCHAR *exid) { @@ -5116,6 +5382,24 @@ static void _link_put_href(unsigned line, IHTMLElement *elem, const WCHAR *v) _test_link_href(line, elem, v); }
+#define elem_has_attr(a,b) _elem_has_attr(__LINE__,a,b) +static BOOL _elem_has_attr(unsigned line, IUnknown *unk, const WCHAR *attr_name) +{ + BSTR str = SysAllocString(attr_name); + IHTMLElement6 *elem; + VARIANT_BOOL b; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement6, (void**)&elem); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLElement6: %08lx\n", hres); + hres = IHTMLElement6_hasAttribute(elem, str, &b); + ok_(__FILE__,line)(hres == S_OK, "hasAttribute failed: %08lx\n", hres); + IHTMLElement6_Release(elem); + SysFreeString(str); + + return b != VARIANT_FALSE; +} + #define get_elem_doc(e) _get_elem_doc(__LINE__,e) static IHTMLDocument2 *_get_elem_doc(unsigned line, IUnknown *unk) { @@ -10076,8 +10360,31 @@ static void test_attr_node(IHTMLDOMAttribute *test_attr, IHTMLDocument2 *doc)
static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) { + static const WCHAR *elem_attr_props[] = { + L"accessKey", L"contentEditable", L"dir", L"disabled", L"hideFocus", L"id", L"lang", L"language", L"onactivate", L"onafterupdate", L"onbeforeactivate", + L"onbeforecopy", L"onbeforecut", L"onbeforedeactivate", L"onbeforeeditfocus", L"onbeforepaste", L"onbeforeupdate", L"onblur", L"oncellchange", L"onclick", + L"oncontextmenu", L"oncontrolselect", L"oncopy", L"oncut", L"ondataavailable", L"ondatasetchanged", L"ondatasetcomplete", L"ondblclick", L"ondeactivate", + L"ondrag", L"ondragend", L"ondragenter", L"ondragleave", L"ondragover", L"ondragstart", L"ondrop", L"onerrorupdate", L"onfilterchange", L"onfocus", + L"onfocusin", L"onfocusout", L"onhelp", L"onkeydown", L"onkeypress", L"onkeyup", L"onlayoutcomplete", L"onlosecapture", L"onmousedown", L"onmouseleave", + L"onmousemove", L"onmouseout", L"onmouseover", L"onmouseup", L"onmousewheel", L"onmove", L"onmoveend", L"onmovestart", L"onpage", L"onpaste", + L"onpropertychange", L"onreadystatechange", L"onresize", L"onresizeend", L"onresizestart", L"onrowenter", L"onrowexit", L"onrowsdelete", + L"onrowsinserted", L"onscroll", L"onselectstart", L"style", L"tabIndex", L"title" + }; + static const WCHAR *elem_noattr_props[] = { + L"addBehavior", L"all", L"applyElement", L"attachEvent", L"attributes", L"behaviorUrns", L"blur", L"canHaveHTML", L"childNodes", L"children", L"className", + L"clearAttributes", L"click", L"clientHeight", L"clientLeft", L"clientTop", L"clientWidth", L"componentFromPoint", L"contains", L"createControlRange", + L"currentStyle", L"detachEvent", L"document", L"doScroll", L"dragDrop", L"filters", L"fireEvent", L"firstChild", L"focus", L"getAdjacentText", L"getAttribute", + L"getAttributeNode", L"getBoundingClientRect", L"getClientRects", L"getElementsByTagName", L"getExpression", L"innerHTML", L"innerText", L"insertAdjacentElement", + L"insertAdjacentHTML", L"insertAdjacentText", L"isContentEditable", L"isDisabled", L"isMultiLine", L"isTextEdit", L"lastChild", L"mergeAttributes", L"nextSibling", + L"nodeName", L"nodeName", L"nodeType", L"nodeValue", L"normalize", L"offsetHeight", L"offsetLeft", L"offsetParent", L"offsetTop", L"offsetWidth", L"outerHTML", + L"outerText", L"ownerDocument", L"parentElement", L"parentNode", L"parentTextEdit", L"previousSibling", L"readyState", L"recordNumber", L"removeAttribute", + L"removeAttributeNode", L"removeBehavior", L"removeExpression", L"replaceAdjacentText", L"runtimeStyle", L"scopeName", L"scrollHeight", L"scrollIntoView", + L"scrollLeft", L"scrollTop", L"scrollWidth", L"setActive", L"setAttribute", L"setAttributeNode", L"setExpression", L"sourceIndex", L"tagName", L"tagUrn", + L"toString", L"uniqueID", L"uniqueNumber" + }; IHTMLDOMAttribute *attr, *attr2, *attr3; IHTMLElement4 *elem4; + unsigned i; VARIANT v; HRESULT hres;
@@ -10165,6 +10472,24 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_attr_specified(attr, VARIANT_FALSE); test_attr_expando(attr, VARIANT_FALSE); test_attr_node(attr, doc); + + for(i = 0; i < ARRAY_SIZE(elem_attr_props); i++) { + BOOL has_attr = elem_has_attr((IUnknown*)elem, elem_attr_props[i]); + + attr = get_elem_attr_node((IUnknown*)elem, elem_attr_props[i], TRUE); + test_attr_specified(attr, has_attr ? VARIANT_TRUE : VARIANT_FALSE); + test_attr_expando(attr, VARIANT_FALSE); + IHTMLDOMAttribute_Release(attr); + } + for(i = 0; i < ARRAY_SIZE(elem_noattr_props); i++) { + get_elem_attr_node((IUnknown*)elem, elem_noattr_props[i], FALSE); + } + + ok(elem_has_attr((IUnknown*)elem, L"emptyattr"), "elem does not have emptyattr"); + attr = get_elem_attr_node((IUnknown*)elem, L"emptyattr", TRUE); + test_attr_specified(attr, VARIANT_TRUE); + test_attr_expando(attr, VARIANT_TRUE); + test_attr_node(attr, doc); IHTMLDOMAttribute_Release(attr);
/* Test created, detached attribute. */ @@ -12532,6 +12857,7 @@ START_TEST(dom) run_domtest(elem_test2_str, test_elems2); run_domtest(doc_blank, test_dom_elements); run_domtest(doc_blank, test_about_blank_storage); + run_domtest(doc_blank, test_attr_collection_builtins); if(is_ie9plus) { compat_mode = COMPAT_IE9; run_domtest(doc_blank_ie9, test_dom_elements);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 63 ++++++++++++++++----------- dlls/mshtml/tests/dom.c | 95 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 129 insertions(+), 29 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 0e78347881a..12cd75f7286 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -47,6 +47,8 @@ typedef struct { } tag_desc_t;
static HRESULT HTMLElement_Ctor(HTMLDocumentNode*,nsIDOMElement*,HTMLElement**); +static HRESULT get_attr_dispid_by_name(HTMLAttributeCollection*,const WCHAR*,BOOL,DISPID*); +static HRESULT get_domattr(HTMLAttributeCollection*,DISPID,LONG*,HTMLDOMAttribute**);
static const tag_desc_t tag_descs[] = { {L"A", HTMLAnchorElement_Create}, @@ -4717,21 +4719,28 @@ static HRESULT WINAPI HTMLElement6_removeAttribute(IHTMLElement6 *iface, BSTR st static HRESULT WINAPI HTMLElement6_getAttributeNode(IHTMLElement6 *iface, BSTR strAttributeName, IHTMLDOMAttribute2 **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement6(iface); - IHTMLDOMAttribute *attr; + HTMLAttributeCollection *attrs; + HTMLDOMAttribute *attr; HRESULT hres; + DISPID id;
- WARN("(%p)->(%s %p) forwarding to IHTMLElement4\n", This, debugstr_w(strAttributeName), ppretAttribute); + TRACE("(%p)->(%s %p)\n", This, debugstr_w(strAttributeName), ppretAttribute);
- hres = IHTMLElement4_getAttributeNode(&This->IHTMLElement4_iface, strAttributeName, &attr); + hres = HTMLElement_get_attr_col(&This->node, &attrs); if(FAILED(hres)) return hres;
- if(attr) { - hres = IHTMLDOMAttribute_QueryInterface(attr, &IID_IHTMLDOMAttribute2, (void**)ppretAttribute); - IHTMLDOMAttribute_Release(attr); - }else { + hres = get_attr_dispid_by_name(attrs, strAttributeName, TRUE, &id); + if(hres == S_OK) { + hres = get_domattr(attrs, id, NULL, &attr); + if(hres == S_OK) + *ppretAttribute = &attr->IHTMLDOMAttribute2_iface; + }else if(hres == DISP_E_UNKNOWNNAME) { *ppretAttribute = NULL; + hres = S_OK; } + + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); return hres; }
@@ -7738,7 +7747,7 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters return S_OK; }
-static inline BOOL is_valid_attr_dispid(HTMLAttributeCollection *col, DISPID id) +static inline BOOL is_valid_attr_dispid(HTMLAttributeCollection *col, DISPID id, BOOL specified_only) { if(get_dispid_type(id) != DISPEXPROP_BUILTIN) return TRUE; @@ -7746,10 +7755,14 @@ static inline BOOL is_valid_attr_dispid(HTMLAttributeCollection *col, DISPID id) if(dispex_builtin_is_noattr(&col->elem->node.event_target.dispex, id)) return FALSE;
+ if(specified_only) + return !!element_has_attribute(col->elem, dispex_builtin_prop_name(&col->elem->node.event_target.dispex, id)); + return TRUE; }
-static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, DISPID *dispid) +static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, + BOOL specified_only, DISPID *dispid) { DISPID id = start; LONG len = -1; @@ -7763,7 +7776,7 @@ static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LO return hres; else if(hres == S_FALSE) break; - else if(!is_valid_attr_dispid(This, id)) + else if(!is_valid_attr_dispid(This, id, specified_only)) continue;
len++; @@ -7780,12 +7793,12 @@ static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LO return S_OK; }
-static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid) +static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, BOOL specified_only, DISPID *dispid) { - return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid); + return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, specified_only, dispid); }
-static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHAR *name, DISPID *id) +static HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHAR *name, BOOL specified_only, DISPID *id) { HRESULT hres;
@@ -7795,17 +7808,17 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, con
idx = wcstoul(name, &end_ptr, 10); if(!*end_ptr) { - hres = get_attr_dispid_by_idx(This, &idx, id); + hres = get_attr_dispid_by_idx(This, &idx, specified_only, id); if(SUCCEEDED(hres)) return hres; } }
hres = dispex_get_id(&This->elem->node.event_target.dispex, name, fdexNameCaseInsensitive, id); - return (FAILED(hres) || is_valid_attr_dispid(This, *id)) ? hres : DISP_E_UNKNOWNNAME; + return (FAILED(hres) || is_valid_attr_dispid(This, *id, specified_only)) ? hres : DISP_E_UNKNOWNNAME; }
-static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) +static HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) { HTMLDOMAttribute *iter; LONG pos = 0; @@ -7903,7 +7916,7 @@ static HRESULT WINAPI HTMLAttributeCollectionEnum_Next(IEnumVARIANT *iface, ULON TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched);
for(i = 0; i < celt; i++) { - hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, dispid, &tmp); + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, dispid, FALSE, &tmp); if(SUCCEEDED(hres)) { dispid = tmp; hres = get_domattr(This->col, dispid, NULL, &attr); @@ -7940,14 +7953,14 @@ static HRESULT WINAPI HTMLAttributeCollectionEnum_Skip(IEnumVARIANT *iface, ULON return S_OK;
rel_index = -1; - hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, NULL); + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, FALSE, NULL); if(FAILED(hres)) return hres; remaining = min(celt, rel_index);
if(remaining) { rel_index = remaining - 1; - hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, &dispid); + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, FALSE, &dispid); if(FAILED(hres)) return hres; This->iter_dispid = dispid; @@ -7999,7 +8012,7 @@ static HRESULT WINAPI HTMLAttributeCollection_get_length(IHTMLAttributeCollectio TRACE("(%p)->(%p)\n", This, p);
*p = -1; - hres = get_attr_dispid_by_idx(This, p, NULL); + hres = get_attr_dispid_by_idx(This, p, FALSE, NULL); return hres; }
@@ -8036,10 +8049,10 @@ static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *ifa
switch(V_VT(name)) { case VT_I4: - hres = get_attr_dispid_by_idx(This, &V_I4(name), &id); + hres = get_attr_dispid_by_idx(This, &V_I4(name), FALSE, &id); break; case VT_BSTR: - hres = get_attr_dispid_by_name(This, V_BSTR(name), &id); + hres = get_attr_dispid_by_name(This, V_BSTR(name), FALSE, &id); break; default: FIXME("unsupported name %s\n", debugstr_variant(name)); @@ -8089,7 +8102,7 @@ static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollec
TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrName), newretNode);
- hres = get_attr_dispid_by_name(This, bstrName, &id); + hres = get_attr_dispid_by_name(This, bstrName, FALSE, &id); if(hres == DISP_E_UNKNOWNNAME) { *newretNode = NULL; return S_OK; @@ -8174,7 +8187,7 @@ static HRESULT WINAPI HTMLAttributeCollection3_item(IHTMLAttributeCollection3 *i
TRACE("(%p)->(%ld %p)\n", This, index, ppNodeOut);
- hres = get_attr_dispid_by_idx(This, &index, &id); + hres = get_attr_dispid_by_idx(This, &index, FALSE, &id); if(hres == DISP_E_UNKNOWNNAME) return E_INVALIDARG; if(FAILED(hres)) @@ -8270,7 +8283,7 @@ static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, const WCHA
TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(name), flags, dispid);
- hres = get_attr_dispid_by_name(This, name, dispid); + hres = get_attr_dispid_by_name(This, name, FALSE, dispid); if(FAILED(hres)) return hres;
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 1a0a8295fd1..9f3cbf35fdb 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -2088,10 +2088,10 @@ static void _test_comment_text(unsigned line, IUnknown *unk, const WCHAR *extext }
#define create_attr(a,b) _create_attr(__LINE__,a,b) -static IHTMLDOMAttribute *_create_attr(unsigned line, IUnknown *unk, const char *name) +static IHTMLDOMAttribute *_create_attr(unsigned line, IUnknown *unk, const WCHAR *name) { IHTMLDocument5 *doc = _get_htmldoc5_iface(line, unk); - BSTR str = SysAllocString(L"Test"); + BSTR str = SysAllocString(name); IHTMLDOMAttribute *attr; HRESULT hres;
@@ -5442,6 +5442,78 @@ static IHTMLDOMAttribute *_get_elem_attr_node(unsigned line, IUnknown *unk, cons return attr; }
+#define get_elem6_attr_node(a,b,c) _get_elem6_attr_node(__LINE__,a,b,c) +static IHTMLDOMAttribute *_get_elem6_attr_node(unsigned line, IUnknown *unk, const WCHAR *attr_name, BOOL expect_success) +{ + BSTR str = SysAllocString(attr_name); + IHTMLDOMAttribute2 *attr2; + IHTMLDOMAttribute *attr; + IHTMLElement6 *elem; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement6, (void**)&elem); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLElement6: %08lx\n", hres); + + attr = (void*)0xdeadbeef; + hres = IHTMLElement6_getAttributeNode(elem, str, &attr2); + ok_(__FILE__,line)(hres == S_OK, "getAttributeNode failed: %08lx\n", hres); + if(expect_success) { + ok_(__FILE__,line)(attr2 != NULL, "attr = NULL\n"); + hres = IHTMLDOMAttribute2_QueryInterface(attr2, &IID_IHTMLDOMAttribute, (void**)&attr); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLDOMAttribute: %08lx\n", hres); + IHTMLDOMAttribute2_Release(attr2); + }else { + ok_(__FILE__,line)(!attr2, "attr = %p\n", attr2); + attr = NULL; + } + + IHTMLElement6_Release(elem); + SysFreeString(str); + return attr; +} + +#define get_elem_attr_node_via_disp(a,b,c) _get_elem_attr_node_via_disp(__LINE__,a,b,c) +static IHTMLDOMAttribute *_get_elem_attr_node_via_disp(unsigned line, IUnknown *unk, const WCHAR *attr_name, BOOL expect_success) +{ + IHTMLDOMAttribute *attr = NULL; + DISPPARAMS dp = { 0 }; + IDispatchEx *dispex; + VARIANT var, arg; + EXCEPINFO ei; + HRESULT hres; + DISPID id; + BSTR str; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line)(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + str = SysAllocString(L"getAttributeNode"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id); + ok_(__FILE__,line)(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(str); + + dp.cArgs = 1; + dp.rgvarg = &arg; + V_VT(&arg) = VT_BSTR; + V_BSTR(&arg) = SysAllocString(attr_name); + + VariantInit(&var); + hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, DISPATCH_METHOD, &dp, &var, &ei, NULL); + ok_(__FILE__,line)(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + if(!expect_success) + ok_(__FILE__,line)(V_VT(&var) == VT_NULL, "V_VT(var) = %d\n", V_VT(&var)); + else { + ok_(__FILE__,line)(V_VT(&var) == VT_DISPATCH, "V_VT(var) = %d\n", V_VT(&var)); + ok_(__FILE__,line)(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLDOMAttribute, (void**)&attr); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLDOMAttribute: %08lx\n", hres); + } + IDispatchEx_Release(dispex); + VariantClear(&arg); + VariantClear(&var); + return attr; +} + #define get_attr_node_value(a,b,c) _get_attr_node_value(__LINE__,a,b,c) static void _get_attr_node_value(unsigned line, IHTMLDOMAttribute *attr, VARIANT *v, VARTYPE vt) { @@ -10480,9 +10552,14 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_attr_specified(attr, has_attr ? VARIANT_TRUE : VARIANT_FALSE); test_attr_expando(attr, VARIANT_FALSE); IHTMLDOMAttribute_Release(attr); + attr = get_elem6_attr_node((IUnknown*)elem, elem_attr_props[i], has_attr); + if(attr) IHTMLDOMAttribute_Release(attr); + attr = get_elem_attr_node_via_disp((IUnknown*)elem, elem_attr_props[i], TRUE); + if(attr) IHTMLDOMAttribute_Release(attr); } for(i = 0; i < ARRAY_SIZE(elem_noattr_props); i++) { get_elem_attr_node((IUnknown*)elem, elem_noattr_props[i], FALSE); + get_elem6_attr_node((IUnknown*)elem, elem_noattr_props[i], FALSE); }
ok(elem_has_attr((IUnknown*)elem, L"emptyattr"), "elem does not have emptyattr"); @@ -10492,8 +10569,18 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_attr_node(attr, doc); IHTMLDOMAttribute_Release(attr);
+ attr = get_elem6_attr_node((IUnknown*)elem, L"emptyattr", TRUE); + test_attr_specified(attr, VARIANT_TRUE); + test_attr_expando(attr, VARIANT_TRUE); + IHTMLDOMAttribute_Release(attr); + + attr = get_elem_attr_node_via_disp((IUnknown*)elem, L"emptyattr", TRUE); + test_attr_specified(attr, VARIANT_TRUE); + test_attr_expando(attr, VARIANT_TRUE); + IHTMLDOMAttribute_Release(attr); + /* Test created, detached attribute. */ - attr = create_attr((IUnknown*)doc, "Test"); + attr = create_attr((IUnknown*)doc, L"Test");
test_disp((IUnknown*)attr, &DIID_DispHTMLDOMAttribute, NULL, L"[object]"); test_ifaces((IUnknown*)attr, attr_iids); @@ -10536,7 +10623,7 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) ok(iface_cmp((IUnknown*)attr2, (IUnknown*)attr), "attr2 != attr\n"); IHTMLDOMAttribute_Release(attr2);
- attr3 = create_attr((IUnknown*)doc, "Test"); + attr3 = create_attr((IUnknown*)doc, L"Test"); put_attr_value(attr3, L"replace test");
hres = IHTMLElement4_setAttributeNode(elem4, attr3, &attr2);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlattr.c | 6 +++--- dlls/mshtml/mshtml_private.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index ff6173aacdb..d1cf1742382 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -51,7 +51,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BS return E_FAIL; }
- *p = SysAllocString(This->name); + *p = SysAllocStringLen(This->name, SysStringLen(This->name)); return *p ? S_OK : E_OUTOFMEMORY; }
@@ -528,7 +528,7 @@ static void HTMLDOMAttribute_destructor(DispatchEx *dispex) { HTMLDOMAttribute *This = impl_from_DispatchEx(dispex); VariantClear(&This->value); - free(This->name); + SysFreeString(This->name); free(This); }
@@ -600,7 +600,7 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis
/* For detached attributes we may still do most operations if we have its name available. */ if(name) { - ret->name = wcsdup(name); + ret->name = SysAllocString(name); if(!ret->name) { IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface); return E_OUTOFMEMORY; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4eac921223f..fe18f01e553 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1343,7 +1343,7 @@ typedef struct { /* value is valid only for detached attributes (when elem == NULL). */ VARIANT value; /* name must be valid for detached attributes */ - WCHAR *name; + BSTR name;
HTMLDocumentNode *doc; HTMLElement *elem;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 43 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 12cd75f7286..62f10cfa8ce 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -527,6 +527,24 @@ HRESULT create_element(HTMLDocumentNode *doc, const WCHAR *tag, HTMLElement **re return hres; }
+static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPID dispid, LONG *pos) +{ + HTMLDOMAttribute *iter, *ret = NULL; + struct list *list = &attrs->attrs; + unsigned i = 0; + + LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { + if(iter->dispid == dispid) { + ret = iter; + break; + } + i++; + } + if(pos) + *pos = i; + return ret; +} + typedef struct { DispatchEx dispex; IHTMLRect IHTMLRect_iface; @@ -4392,7 +4410,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD IHTMLDOMAttribute **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement4(iface); - HTMLDOMAttribute *attr, *iter, *replace = NULL; + HTMLDOMAttribute *attr, *replace; HTMLAttributeCollection *attrs; DISPID dispid; HRESULT hres; @@ -4416,13 +4434,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD if(FAILED(hres)) return hres;
- LIST_FOR_EACH_ENTRY(iter, &attrs->attrs, HTMLDOMAttribute, entry) { - if(iter->dispid == dispid) { - replace = iter; - break; - } - } - + replace = find_attr_in_list(attrs, dispid, NULL); if(replace) { hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value); if(FAILED(hres)) { @@ -7820,28 +7832,15 @@ static HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHA
static HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) { - HTMLDOMAttribute *iter; - LONG pos = 0; HRESULT hres;
- *attr = NULL; - LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) { - if(iter->dispid == id) { - *attr = iter; - break; - } - pos++; - } - - if(!*attr) { + if(!(*attr = find_attr_in_list(This, id, list_pos))) { hres = HTMLDOMAttribute_Create(NULL, This->elem, id, This->elem->node.doc, attr); if(FAILED(hres)) return hres; }
IHTMLDOMAttribute_AddRef(&(*attr)->IHTMLDOMAttribute_iface); - if(list_pos) - *list_pos = pos; return S_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 25 ++++++++++ dlls/mshtml/tests/dom.c | 107 +++++++++++++++++++++++++++++++++++----- 2 files changed, 120 insertions(+), 12 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 62f10cfa8ce..e095178748a 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1333,6 +1333,9 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(strAttributeName), lFlags, pfSuccess);
if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) { + HTMLAttributeCollection *attrs; + HTMLDOMAttribute *attr; + hres = dispex_get_id(&This->node.event_target.dispex, translate_attr_name(strAttributeName, compat_mode), lFlags & ATTRFLAG_CASESENSITIVE ? fdexNameCaseSensitive : fdexNameCaseInsensitive, &id); if(hres == DISP_E_UNKNOWNNAME) { @@ -1342,6 +1345,26 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA if(FAILED(hres)) return hres;
+ hres = HTMLElement_get_attr_col(&This->node, &attrs); + if(FAILED(hres)) + return hres; + attr = find_attr_in_list(attrs, id, NULL); + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + + if(attr) { + hres = get_elem_attr_value_by_dispid(This, id, &attr->value); + if(FAILED(hres)) + return hres; + if(!attr->name) { + hres = dispex_prop_name(&This->node.event_target.dispex, id, &attr->name); + if(FAILED(hres)) + return hres; + } + attr->elem = NULL; + list_remove(&attr->entry); + IHTMLDOMNode_Release(&This->node.IHTMLDOMNode_iface); + } + if(id == DISPID_IHTMLELEMENT_STYLE) { IHTMLStyle *style;
@@ -8291,6 +8314,8 @@ static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, const WCHA return hres; IHTMLDOMAttribute_Release(&attr->IHTMLDOMAttribute_iface);
+ /* Even though this breaks DISPID rules where the same name must return the same DISPID, because the pos can change + * as attributes are removed (and re-added), it's how native works (see test_attr_collection_disp in tests). */ *dispid = MSHTML_DISPID_CUSTOM_MIN+pos; return S_OK; } diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 9f3cbf35fdb..cc5aad660a1 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -3745,39 +3745,42 @@ static LONG test_attr_collection_attr(IDispatch *attr, LONG i) return ret; }
-static void test_attr_collection_disp(IDispatch *disp) +static void test_attr_collection_disp(IDispatch *disp, LONG len, IHTMLElement *elem) { + DISPID dispid, dispid2, dispid_attr1, dispid_attr2, dispid_attr3; IDispatchEx *dispex; IHTMLDOMAttribute *attr; DISPPARAMS dp = {NULL, NULL, 0, 0}; + VARIANT_BOOL vbool; + WCHAR buf[11]; VARIANT var; EXCEPINFO ei; - DISPID id; - BSTR bstr; HRESULT hres; + BSTR bstr;
hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); ok(hres == S_OK, "QueryInterface failed: %08lx\n", hres);
- bstr = SysAllocString(L"0"); - hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); + swprintf(buf, ARRAY_SIZE(buf), L"%lu", len - 2); + bstr = SysAllocString(buf); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); SysFreeString(bstr);
VariantInit(&var); - hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); + hres = IDispatchEx_InvokeEx(dispex, dispid, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var)); ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); VariantClear(&var);
bstr = SysAllocString(L"attr1"); - hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid_attr1); ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); SysFreeString(bstr);
VariantInit(&var); - hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); + hres = IDispatchEx_InvokeEx(dispex, dispid_attr1, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var)); ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); @@ -3789,6 +3792,72 @@ static void test_attr_collection_disp(IDispatch *disp) IHTMLDOMAttribute_Release(attr); VariantClear(&var);
+ bstr = SysAllocString(L"attr2"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid_attr2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(bstr); + + bstr = SysAllocString(L"attr3"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid_attr3); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(bstr); + + ok(dispid == dispid_attr1 || dispid == dispid_attr2 || dispid == dispid_attr3, + "indexed dispid isn't one of the attr dispids\n"); + + bstr = SysAllocString(L"attr1"); + hres = IHTMLElement_removeAttribute(elem, bstr, 0, &vbool); + ok(hres == S_OK, "removeAttribute failed: %08lx\n", hres); + ok(vbool == VARIANT_TRUE, "removeAttribute returned %x\n", vbool); + SysFreeString(bstr); + + hres = IDispatchEx_GetMemberName(dispex, dispid_attr1, &bstr); + ok(hres == S_OK, "GetMemberName failed: %08lx\n", hres); + ok(wcscmp(bstr, L"attr1"), "GetMemberName still returned attr1 after removal\n"); + SysFreeString(bstr); + + bstr = SysAllocString(buf); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid2); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(dispid, "indexed dispid is not the same after removal\n"); + SysFreeString(bstr); + + bstr = SysAllocString(L"attr2"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(dispid == dispid_attr2, "dispid != dispid_attr2\n"); + SysFreeString(bstr); + + bstr = SysAllocString(L"attr1"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID returned: %08lx\n", hres); + SysFreeString(bstr); + + bstr = SysAllocString(L"added_attr"); + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(L"test"); + hres = IHTMLElement_setAttribute(elem, bstr, var, 0); + ok(hres == S_OK, "setAttribute failed: %08lx\n", hres); + + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(dispid != dispid_attr1, "added attr dispid == dispid_attr1\n"); + ok(dispid != dispid_attr2, "added attr dispid == dispid_attr2\n"); + ok(dispid != dispid_attr3, "added attr dispid == dispid_attr3\n"); + SysFreeString(bstr); + + bstr = SysAllocString(L"attr1"); + hres = IHTMLElement_setAttribute(elem, bstr, var, 0); + ok(hres == S_OK, "setAttribute failed: %08lx\n", hres); + VariantClear(&var); + + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + ok(dispid != dispid_attr1, "attr1 after re-added dispid == dispid_attr1\n"); + ok(dispid != dispid_attr2, "attr1 after re-added dispid == dispid_attr2\n"); + ok(dispid != dispid_attr3, "attr1 after re-added dispid == dispid_attr3\n"); + SysFreeString(bstr); + IDispatchEx_Release(dispex); }
@@ -3908,7 +3977,7 @@ static void test_attr_collection(IHTMLElement *elem) ok(hres == E_INVALIDARG, "item failed: %08lx\n", hres); VariantClear(&id);
- test_attr_collection_disp(disp); + test_attr_collection_disp(disp, len, elem);
IDispatch_Release(disp); IHTMLAttributeCollection_Release(attr_col); @@ -10456,9 +10525,11 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) }; IHTMLDOMAttribute *attr, *attr2, *attr3; IHTMLElement4 *elem4; + VARIANT_BOOL vbool; + HRESULT hres; unsigned i; VARIANT v; - HRESULT hres; + BSTR bstr;
get_elem_attr_node((IUnknown*)elem, L"noattr", FALSE);
@@ -10572,6 +10643,20 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) attr = get_elem6_attr_node((IUnknown*)elem, L"emptyattr", TRUE); test_attr_specified(attr, VARIANT_TRUE); test_attr_expando(attr, VARIANT_TRUE); + + bstr = SysAllocString(L"emptyattr"); + hres = IHTMLElement_removeAttribute(elem, bstr, 0, &vbool); + ok(hres == S_OK, "removeAttribute failed: %08lx\n", hres); + ok(vbool == VARIANT_TRUE, "removeAttribute returned %x\n", vbool); + test_attr_expando(attr, VARIANT_FALSE); + SysFreeString(bstr); + + elem4 = get_elem4_iface((IUnknown*)elem); + hres = IHTMLElement4_setAttributeNode(elem4, attr, &attr2); + ok(hres == S_OK, "setAttributeNode failed: %08lx\n", hres); + ok(!attr2, "attr2 != NULL\n"); + test_attr_specified(attr, VARIANT_TRUE); + test_attr_expando(attr, VARIANT_TRUE); IHTMLDOMAttribute_Release(attr);
attr = get_elem_attr_node_via_disp((IUnknown*)elem, L"emptyattr", TRUE); @@ -10609,8 +10694,6 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) SysFreeString(V_BSTR(&v)); test_attr_value(attr, L"testing");
- elem4 = get_elem4_iface((IUnknown*)elem); - hres = IHTMLElement4_setAttributeNode(elem4, attr, &attr2); ok(hres == S_OK, "setAttributeNode failed: %08lx\n", hres); ok(!attr2, "attr2 != NULL\n");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/tests/dom.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index d1cf1742382..8307ab8f3f1 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -94,8 +94,8 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V TRACE("(%p)->(%p)\n", This, p);
if(!This->elem || !This->elem->dom_element) { - FIXME("NULL This->elem\n"); - return E_UNEXPECTED; + *p = VARIANT_FALSE; + return S_OK; }
if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index cc5aad660a1..f1d61ae4bde 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -10648,6 +10648,7 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) hres = IHTMLElement_removeAttribute(elem, bstr, 0, &vbool); ok(hres == S_OK, "removeAttribute failed: %08lx\n", hres); ok(vbool == VARIANT_TRUE, "removeAttribute returned %x\n", vbool); + test_attr_specified(attr, VARIANT_FALSE); test_attr_expando(attr, VARIANT_FALSE); SysFreeString(bstr);
@@ -10672,6 +10673,7 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_no_iface((IUnknown*)attr, &IID_IHTMLDOMNode);
test_attr_node_name(attr, L"Test"); + test_attr_specified(attr, VARIANT_FALSE); test_attr_expando(attr, VARIANT_FALSE);
get_attr_node_value(attr, &v, VT_EMPTY);