-- v2: 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 | 11 ++ dlls/mshtml/htmlelem.c | 100 ++++++++++- dlls/mshtml/htmlform.c | 8 + dlls/mshtml/htmlframe.c | 21 +++ dlls/mshtml/htmlhead.c | 6 + dlls/mshtml/htmlimg.c | 14 ++ dlls/mshtml/htmlinput.c | 26 +++ dlls/mshtml/htmllink.c | 8 + dlls/mshtml/htmlobject.c | 9 + dlls/mshtml/htmlscript.c | 8 + dlls/mshtml/htmlselect.c | 20 +++ dlls/mshtml/htmlstyleelem.c | 6 + dlls/mshtml/htmltable.c | 26 +++ dlls/mshtml/htmltextarea.c | 10 ++ dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/tests/dom.c | 338 ++++++++++++++++++++++++++++++++++- 16 files changed, 606 insertions(+), 7 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 695cdaad0e2..3a6371f5e52 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1996,6 +1996,17 @@ HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) return *ret ? S_OK : E_OUTOFMEMORY; }
+BOOL dispex_builtin_is_method(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + HRESULT hres; + + hres = get_builtin_func(dispex->info, id, &func); + assert(SUCCEEDED(hres)); + + return func->func_disp_idx >= 0; +} + 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..d0bcb20b90a 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -7677,6 +7677,101 @@ 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) +{ + /* Builtin props (non-methods) that are not attributes; MUST be sorted by underlying dispid value. */ + static const DISPID nonattr_dispids[] = { + DISPID_IHTMLELEMENT_PARENTELEMENT, + DISPID_IHTMLELEMENT_CLASSNAME, + DISPID_IHTMLELEMENT_TAGNAME, + DISPID_IHTMLELEMENT2_CURRENTSTYLE, + DISPID_IHTMLELEMENT_OFFSETLEFT, + DISPID_IHTMLELEMENT_OFFSETTOP, + DISPID_IHTMLELEMENT_OFFSETWIDTH, + DISPID_IHTMLELEMENT_OFFSETHEIGHT, + DISPID_IHTMLELEMENT_OFFSETPARENT, + DISPID_IHTMLELEMENT_DOCUMENT, + DISPID_IHTMLELEMENT_SOURCEINDEX, + DISPID_IHTMLELEMENT_RECORDNUMBER, + DISPID_IHTMLELEMENT_INNERHTML, + DISPID_IHTMLELEMENT_INNERTEXT, + DISPID_IHTMLELEMENT_OUTERHTML, + DISPID_IHTMLELEMENT_OUTERTEXT, + DISPID_IHTMLELEMENT_PARENTTEXTEDIT, + DISPID_IHTMLELEMENT_ISTEXTEDIT, + DISPID_IHTMLELEMENT_FILTERS, + DISPID_IHTMLELEMENT_CHILDREN, + DISPID_IHTMLELEMENT_ALL, + DISPID_IHTMLELEMENT2_SCOPENAME, + DISPID_IHTMLDOMNODE_NODETYPE, + DISPID_IHTMLDOMNODE_PARENTNODE, + DISPID_IHTMLDOMNODE_CHILDNODES, + DISPID_IHTMLDOMNODE_ATTRIBUTES, + DISPID_IHTMLUNIQUENAME_UNIQUENUMBER, + DISPID_IHTMLUNIQUENAME_UNIQUEID, + DISPID_IHTMLELEMENT2_SCROLLHEIGHT, + DISPID_IHTMLELEMENT2_SCROLLWIDTH, + DISPID_IHTMLELEMENT2_SCROLLTOP, + DISPID_IHTMLELEMENT2_SCROLLLEFT, + DISPID_IHTMLELEMENT2_RUNTIMESTYLE, + DISPID_IHTMLELEMENT2_CANHAVECHILDREN, + DISPID_IHTMLDOMNODE_NODENAME, + DISPID_IHTMLDOMNODE_NODEVALUE, + DISPID_IHTMLDOMNODE_FIRSTCHILD, + DISPID_IHTMLDOMNODE_LASTCHILD, + DISPID_IHTMLDOMNODE_PREVIOUSSIBLING, + DISPID_IHTMLDOMNODE_NEXTSIBLING, + DISPID_IHTMLELEMENT2_BEHAVIORURNS, + DISPID_IHTMLELEMENT2_TAGURN, + DISPID_IHTMLELEMENT3_ISMULTILINE, + DISPID_IHTMLELEMENT3_CANHAVEHTML, + DISPID_IHTMLELEMENT3_ISCONTENTEDITABLE, + DISPID_IHTMLELEMENT3_ISDISABLED, + DISPID_IHTMLDOMNODE2_OWNERDOCUMENT, + DISPID_IHTMLDOMNODE3_LOCALNAME, + DISPID_IHTMLDOMNODE3_NAMESPACEURI, + DISPID_IHTMLDOMNODE3_PREFIX, + DISPID_IHTMLDOMNODE3_TEXTCONTENT, + DISPID_IELEMENTTRAVERSAL_FIRSTELEMENTCHILD, + DISPID_IELEMENTTRAVERSAL_LASTELEMENTCHILD, + DISPID_IELEMENTTRAVERSAL_PREVIOUSELEMENTSIBLING, + DISPID_IELEMENTTRAVERSAL_NEXTELEMENTSIBLING, + DISPID_IELEMENTTRAVERSAL_CHILDELEMENTCOUNT, + DISPID_IHTMLELEMENT2_CLIENTHEIGHT, + DISPID_IHTMLELEMENT2_CLIENTWIDTH, + DISPID_IHTMLELEMENT2_CLIENTTOP, + DISPID_IHTMLELEMENT2_CLIENTLEFT, + DISPID_IHTMLELEMENT2_READYSTATE, + DISPID_NEWENUM, + DISPID_COLLECTION + }; + unsigned i, a = 0, b = ARRAY_SIZE(nonattr_dispids); + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return TRUE; + + while(a < b) { + i = (a + b) / 2; + if(id == nonattr_dispids[i]) + return FALSE; + if(id <= nonattr_dispids[i]) b = i; + else a = i + 1; + } + + if(col->elem->node.vtbl->nonattr_dispids) { + const DISPID *p = col->elem->node.vtbl->nonattr_dispids; + do { + if(id == *p) + return FALSE; + } while(*++p != DISPID_UNKNOWN); + } + + if(dispex_builtin_is_method(&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 +7786,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 +7824,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..3f67b57385d 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"
@@ -880,9 +881,16 @@ static HRESULT HTMLFormElement_handle_event(DispatchEx *dispex, DOMEvent *event, return HTMLElement_handle_event(&This->element.node.event_target.dispex, event, prevent_default); }
+static const DISPID HTMLFormElement_nonattr_dispids[] = { + DISPID_IHTMLFORMELEMENT_ENCODING, + DISPID_IHTMLFORMELEMENT_ELEMENTS, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLFormElementImplVtbl = { .clsid = &CLSID_HTMLFormElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLFormElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index 48312b59a21..ab41bc5a46a 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" @@ -895,9 +896,19 @@ static HRESULT HTMLFrameElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid, id, lcid, flags, params, res, ei, caller); }
+static const DISPID HTMLFrameElement_nonattr_dispids[] = { + DISPID_IHTMLFRAMEBASE2_CONTENTWINDOW, + DISPID_IHTMLFRAMEELEMENT3_CONTENTDOCUMENT, + DISPID_IHTMLFRAMEELEMENT3_IE8_SRC, + DISPID_IHTMLFRAMEELEMENT3_IE8_LONGDESC, + DISPID_IHTMLFRAMEELEMENT3_IE8_FRAMEBORDER, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLFrameElementImplVtbl = { .clsid = &CLSID_HTMLFrameElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLFrameElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .get_document = HTMLFrameElement_get_document, @@ -1330,9 +1341,19 @@ static HRESULT HTMLIFrame_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD id, lcid, flags, params, res, ei, caller); }
+static const DISPID HTMLIFrame_nonattr_dispids[] = { + DISPID_IHTMLFRAMEBASE2_CONTENTWINDOW, + DISPID_IHTMLIFRAMEELEMENT3_CONTENTDOCUMENT, + DISPID_IHTMLIFRAMEELEMENT3_IE8_SRC, + DISPID_IHTMLIFRAMEELEMENT3_IE8_LONGDESC, + DISPID_IHTMLIFRAMEELEMENT3_IE8_FRAMEBORDER, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLIFrameImplVtbl = { .clsid = &CLSID_HTMLIFrame, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLIFrame_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .get_document = HTMLIFrame_get_document, diff --git a/dlls/mshtml/htmlhead.c b/dlls/mshtml/htmlhead.c index 2386f243599..e2f30da59e0 100644 --- a/dlls/mshtml/htmlhead.c +++ b/dlls/mshtml/htmlhead.c @@ -395,9 +395,15 @@ static void *HTMLMetaElement_query_interface(DispatchEx *dispex, REFIID riid) return HTMLElement_query_interface(&This->element.node.event_target.dispex, riid); }
+static const DISPID HTMLMetaElement_nonattr_dispids[] = { + DISPID_IHTMLMETAELEMENT_HTTPEQUIV, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLMetaElementImplVtbl = { .clsid = &CLSID_HTMLMetaElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLMetaElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col }; diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 40c2c2dd09b..9bfc659981a 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -646,9 +646,23 @@ static void HTMLImgElement_unlink(DispatchEx *dispex) unlink_ref(&This->nsimg); }
+static const DISPID HTMLImgElement_nonattr_dispids[] = { + DISPID_IHTMLIMGELEMENT_COMPLETE, + DISPID_IHTMLIMGELEMENT_MIMETYPE, + DISPID_IHTMLIMGELEMENT_FILESIZE, + DISPID_IHTMLIMGELEMENT_FILECREATEDDATE, + DISPID_IHTMLIMGELEMENT_FILEMODIFIEDDATE, + DISPID_IHTMLIMGELEMENT_FILEUPDATEDDATE, + DISPID_IHTMLIMGELEMENT_PROTOCOL, + DISPID_IHTMLIMGELEMENT_HREF, + DISPID_IHTMLIMGELEMENT_NAMEPROP, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLImgElementImplVtbl = { .clsid = &CLSID_HTMLImg, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLImgElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .get_readystate = HTMLImgElement_get_readystate, diff --git a/dlls/mshtml/htmlinput.c b/dlls/mshtml/htmlinput.c index ca0de3131e3..3ca70406673 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"
@@ -1260,9 +1261,20 @@ static void HTMLInputElement_unlink(DispatchEx *dispex) unlink_ref(&This->nsinput); }
+static const DISPID HTMLInputElement_nonattr_dispids[] = { + DISPID_IHTMLINPUTELEMENT_FORM, + DISPID_IHTMLINPUTELEMENT_STATUS, + DISPID_IHTMLINPUTELEMENT_DEFAULTCHECKED, + DISPID_IHTMLINPUTELEMENT_COMPLETE, + DISPID_IHTMLINPUTTEXTELEMENT2_SELECTIONSTART, + DISPID_IHTMLINPUTTEXTELEMENT2_SELECTIONEND, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLInputElementImplVtbl = { .clsid = &CLSID_HTMLInputElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLInputElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .put_disabled = HTMLInputElementImpl_put_disabled, @@ -1406,9 +1418,15 @@ static void *HTMLLabelElement_query_interface(DispatchEx *dispex, REFIID riid) return HTMLElement_query_interface(&This->element.node.event_target.dispex, riid); }
+static const DISPID HTMLLabelElement_nonattr_dispids[] = { + DISPID_IHTMLLABELELEMENT_HTMLFOR, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLLabelElementImplVtbl = { .clsid = &CLSID_HTMLLabelElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLLabelElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; @@ -1689,9 +1707,17 @@ static void HTMLButtonElement_unlink(DispatchEx *dispex) unlink_ref(&This->nsbutton); }
+static const DISPID HTMLButtonElement_nonattr_dispids[] = { + DISPID_IHTMLBUTTONELEMENT_FORM, + DISPID_IHTMLBUTTONELEMENT_VALUE, + DISPID_IHTMLBUTTONELEMENT_STATUS, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLButtonElementImplVtbl = { .clsid = &CLSID_HTMLButtonElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLButtonElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .put_disabled = HTMLButtonElementImpl_put_disabled, diff --git a/dlls/mshtml/htmllink.c b/dlls/mshtml/htmllink.c index 9ad66eef52e..84c39ace869 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"
@@ -361,9 +362,16 @@ static void HTMLLinkElement_unlink(DispatchEx *dispex) HTMLElement_unlink(dispex); unlink_ref(&This->nslink); } + +static const DISPID HTMLLinkElement_nonattr_dispids[] = { + DISPID_IHTMLLINKELEMENT_STYLESHEET, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLLinkElementImplVtbl = { .clsid = &CLSID_HTMLLinkElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLLinkElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .put_disabled = HTMLLinkElementImpl_put_disabled, diff --git a/dlls/mshtml/htmlobject.c b/dlls/mshtml/htmlobject.c index ca49708d54e..2888fd3553c 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"
@@ -653,9 +654,17 @@ static void HTMLObjectElement_unlink(DispatchEx *dispex) unlink_ref(&This->nsobject); }
+static const DISPID HTMLObjectElement_nonattr_dispids[] = { + DISPID_IHTMLOBJECTELEMENT_BASEHREF, + DISPID_IHTMLOBJECTELEMENT_FORM, + DISPID_IHTMLOBJECTELEMENT_ALTHTML, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLObjectElementImplVtbl = { .clsid = &CLSID_HTMLObjectElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLObjectElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .get_readystate = HTMLObjectElement_get_readystate, diff --git a/dlls/mshtml/htmlscript.c b/dlls/mshtml/htmlscript.c index 9e21d15ce26..bbda4fd56c9 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"
@@ -367,9 +368,16 @@ static void HTMLScriptElement_destructor(DispatchEx *dispex) HTMLElement_destructor(&This->element.node.event_target.dispex); }
+static const DISPID HTMLScriptElement_nonattr_dispids[] = { + DISPID_IHTMLSCRIPTELEMENT_HTMLFOR, + DISPID_IHTMLSCRIPTELEMENT_TEXT, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLScriptElementImplVtbl = { .clsid = &CLSID_HTMLScriptElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLScriptElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .get_readystate = HTMLScriptElement_get_readystate, diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index a126f977697..1f8753d23c6 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"
@@ -321,9 +322,18 @@ static void HTMLOptionElement_unlink(DispatchEx *dispex) unlink_ref(&This->nsoption); }
+static const DISPID HTMLOptionElement_nonattr_dispids[] = { + DISPID_IHTMLOPTIONELEMENT_DEFAULTSELECTED, + DISPID_IHTMLOPTIONELEMENT_TEXT, + DISPID_IHTMLOPTIONELEMENT_INDEX, + DISPID_IHTMLOPTIONELEMENT_FORM, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLOptionElementImplVtbl = { .clsid = &CLSID_HTMLOptionElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLOptionElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; @@ -1229,9 +1239,19 @@ static HRESULT HTMLSelectElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid return S_OK; }
+static const DISPID HTMLSelectElement_nonattr_dispids[] = { + DISPID_IHTMLSELECTELEMENT_FORM, + DISPID_IHTMLSELECTELEMENT_OPTIONS, + DISPID_IHTMLSELECTELEMENT_SELECTEDINDEX, + DISPID_IHTMLSELECTELEMENT_VALUE, + DISPID_IHTMLSELECTELEMENT_TYPE, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLSelectElementImplVtbl = { .clsid = &CLSID_HTMLSelectElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLSelectElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .put_disabled = HTMLSelectElementImpl_put_disabled, diff --git a/dlls/mshtml/htmlstyleelem.c b/dlls/mshtml/htmlstyleelem.c index d400f4980cb..7c8551c05ba 100644 --- a/dlls/mshtml/htmlstyleelem.c +++ b/dlls/mshtml/htmlstyleelem.c @@ -312,9 +312,15 @@ static void HTMLStyleElement_init_dispex_info(dispex_data_t *info, compat_mode_t dispex_info_add_interface(info, IHTMLStyleElement2_tid, NULL); }
+static const DISPID HTMLStyleElement_nonattr_dispids[] = { + DISPID_IHTMLSTYLEELEMENT_STYLESHEET, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLStyleElementImplVtbl = { .clsid = &CLSID_HTMLStyleElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLStyleElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; diff --git a/dlls/mshtml/htmltable.c b/dlls/mshtml/htmltable.c index 27e1d258b22..c1d56ad5b3a 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"
@@ -423,9 +424,15 @@ static void HTMLTableCell_unlink(DispatchEx *dispex) unlink_ref(&This->nscell); }
+static const DISPID HTMLTableCell_nonattr_dispids[] = { + DISPID_IHTMLTABLECELL_CELLINDEX, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLTableCellImplVtbl = { .clsid = &CLSID_HTMLTableCell, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLTableCell_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; @@ -805,9 +812,17 @@ static void HTMLTableRow_unlink(DispatchEx *dispex) unlink_ref(&This->nsrow); }
+static const DISPID HTMLTableRow_nonattr_dispids[] = { + DISPID_IHTMLTABLEROW_ROWINDEX, + DISPID_IHTMLTABLEROW_SECTIONROWINDEX, + DISPID_IHTMLTABLEROW_CELLS, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLTableRowImplVtbl = { .clsid = &CLSID_HTMLTableRow, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLTableRow_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; @@ -1656,9 +1671,20 @@ static const cpc_entry_t HTMLTable_cpc[] = { {NULL} };
+static const DISPID HTMLTable_nonattr_dispids[] = { + DISPID_IHTMLTABLE_ROWS, + DISPID_IHTMLTABLE_THEAD, + DISPID_IHTMLTABLE_TFOOT, + DISPID_IHTMLTABLE_TBODIES, + DISPID_IHTMLTABLE_CAPTION, + DISPID_IHTMLTABLE2_CELLS, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLTableImplVtbl = { .clsid = &CLSID_HTMLTable, .cpc_entries = HTMLTable_cpc, + .nonattr_dispids = HTMLTable_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, }; diff --git a/dlls/mshtml/htmltextarea.c b/dlls/mshtml/htmltextarea.c index e8a846047e8..9bb663f1014 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"
@@ -387,9 +388,18 @@ static void HTMLTextAreaElement_unlink(DispatchEx *dispex) unlink_ref(&This->nstextarea); }
+static const DISPID HTMLTextAreaElement_nonattr_dispids[] = { + DISPID_IHTMLTEXTAREAELEMENT_FORM, + DISPID_IHTMLTEXTAREAELEMENT_VALUE, + DISPID_IHTMLTEXTAREAELEMENT_TYPE, + DISPID_IHTMLTEXTAREAELEMENT_STATUS, + DISPID_UNKNOWN +}; + static const NodeImplVtbl HTMLTextAreaElementImplVtbl = { .clsid = &CLSID_HTMLTextAreaElement, .cpc_entries = HTMLElement_cpc, + .nonattr_dispids = HTMLTextAreaElement_nonattr_dispids, .clone = HTMLElement_clone, .get_attr_col = HTMLElement_get_attr_col, .put_disabled = HTMLTextAreaElementImpl_put_disabled, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4319c8b4725..bbc35adb8c4 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -649,6 +649,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_method(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); @@ -1007,6 +1008,7 @@ struct GeckoBrowser { typedef struct { const CLSID *clsid; const cpc_entry_t *cpc_entries; + const DISPID *nonattr_dispids; HRESULT (*clone)(HTMLDOMNode*,nsIDOMNode*,HTMLDOMNode**); HRESULT (*get_attr_col)(HTMLDOMNode*,HTMLAttributeCollection**); EventTarget *(*get_event_prop_target)(HTMLDOMNode*,int); 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 d0bcb20b90a..74c7477ab5e 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; }
@@ -7677,7 +7686,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) { /* Builtin props (non-methods) that are not attributes; MUST be sorted by underlying dispid value. */ static const DISPID nonattr_dispids[] = { @@ -7769,10 +7778,14 @@ static inline BOOL is_valid_attr_dispid(HTMLAttributeCollection *col, DISPID id) if(dispex_builtin_is_method(&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; @@ -7786,7 +7799,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++; @@ -7803,12 +7816,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;
@@ -7818,17 +7831,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; @@ -7926,7 +7939,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); @@ -7963,14 +7976,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; @@ -8022,7 +8035,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; }
@@ -8059,10 +8072,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)); @@ -8112,7 +8125,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; @@ -8197,7 +8210,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)) @@ -8293,7 +8306,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 bbc35adb8c4..d7b89d7d0a7 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 74c7477ab5e..fd7e99a7e4b 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)) { @@ -7843,28 +7855,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 fd7e99a7e4b..32a8b4390a3 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;
@@ -8314,6 +8337,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);
New version handles tag-specific element props, and uses a blacklist instead (of what's not an attribute), which should avoid regressions if we missed anything (as we used to treat every builtin as an attr before), plus it's shorter lists since most are attributes.
Note that we have to use some element specific lists, because some of them shared DISPIDs and would conflict otherwise, and some of those aren't attributes, while on other elements sharing same DISPID, they are.
Also, here's a diff to apply on top of second patch to test it on IE9 as well but it only works on Windows, as Wine is too broken right now so will have to wait.
```diff diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 1a0a829..56eb87a 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -3941,6 +3941,14 @@ static void test_attr_collection_builtins(IHTMLDocument2 *doc) 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 *generic_builtins_ie9[] = { + L"draggable", L"onabort", L"oncanplay", L"oncanplaythrough", L"onchange", L"ondurationchange", L"onemptied", L"onended", L"onerror", L"oninput", L"onload", + L"onloadeddata", L"onloadedmetadata", L"onloadstart", L"onlostpointercapture", L"onmscontentzoom", L"onmsgesturechange", L"onmsgesturedoubletap", + L"onmsgestureend", L"onmsgesturehold", L"onmsgesturestart", L"onmsgesturetap", L"onmsgotpointercapture", L"onmsinertiastart", L"onmspointerdown", + L"onmspointerenter", L"onmspointerhover", L"onmspointerleave", L"onmspointermove", L"onmspointerout", L"onmsregionupdate", L"onpause", L"onplay", L"onplaying", + L"onpointercancel", L"onpointerover", L"onpointerup", L"onprogress", L"onratechange", L"onreset", L"onseeked", L"onseeking", L"onselect", L"onstalled", + L"onsubmit", L"onsuspend", L"ontimeupdate", L"ontouchcancel", L"ontouchend", L"ontouchmove", L"ontouchstart", L"onvolumechange", L"onwaiting" + }; static const WCHAR *tags[] = { L"audio", NULL, L"b", L"cite", L"dateTime", NULL, @@ -4058,10 +4066,36 @@ static void test_attr_collection_builtins(IHTMLDocument2 *doc) L"ul", L"compact", L"type", NULL, NULL }; + static const WCHAR *tags_ie9[] = { + L"audio", L"autobuffer", L"autoplay", L"controls", L"loop", L"muted", L"onmsneedkey", L"preload", L"src", L"x-ms-playtodisabled", L"x-ms-playtopreferredsourceuri", L"x-ms-playtoprimary", NULL, + L"body", L"autofocus", L"onmessage", L"onorientationchange", L"onpagehide", L"onpageshow", L"onpopstate", L"onstorage", L"required", NULL, + L"button", L"autofocus", L"required", NULL, + L"caption", L"autofocus", L"required", NULL, + L"embed", L"autofocus", L"required", L"x-ms-playtodisabled", L"x-ms-playtopreferredsourceuri", L"x-ms-playtoprimary", NULL, + L"fieldset", L"autofocus", L"required", NULL, + L"form", L"novalidate", NULL, + L"frameset", L"autofocus", L"onhashchange", L"onmessage", L"onoffline", L"ononline", L"onorientationchange", L"onpagehide", L"onpageshow", L"onstorage", L"required", NULL, + L"iframe", L"allowfullscreen", NULL, + L"img", L"autofocus", L"crossOrigin", L"required", L"x-ms-playtodisabled", L"x-ms-playtopreferredsourceuri", L"x-ms-playtoprimary", NULL, + L"input", L"autofocus", L"list", L"max", L"min", L"multiple", L"pattern", L"placeholder", L"required", L"step", NULL, + L"legend", L"autofocus", L"required", NULL, + L"object", L"autofocus", L"required", L"x-ms-playtodisabled", L"x-ms-playtopreferredsourceuri", L"x-ms-playtoprimary", NULL, + L"script", L"async", NULL, + L"select", L"autofocus", L"required", NULL, + L"table", L"autofocus", L"required", NULL, + L"td", L"autofocus", L"required", NULL, + L"textarea", L"autofocus", L"maxLength", L"placeholder", L"required", NULL, + L"tr", L"autofocus", L"required", NULL, + L"video", L"autobuffer", L"autoplay", L"controls", L"height", L"loop", L"msStereo3DPackingMode", L"msStereo3DRenderModeatype", L"muted", L"onmsneedkey", L"onMSVideoFormatChange", + L"onMSVideoFrameStepCompleted", L"onMSVideoOptimalLayoutChanged", L"poster", L"preload", L"src", L"width", L"x-ms-playtodisabled", L"x-ms-playtopreferredsourceuri", L"x-ms-playtoprimary", NULL, + NULL + }; BOOLEAN found[ARRAY_SIZE(generic_builtins)]; + BOOLEAN found_ie9[ARRAY_SIZE(generic_builtins_ie9)]; BOOLEAN found_tag_specific[36]; + BOOLEAN found_tag_specific_ie9[20];
- const WCHAR **iter = tags, **iter_todo = tags_todo; + const WCHAR **iter = tags, **iter_todo = tags_todo, **iter_ie9 = tags_ie9; IHTMLAttributeCollection *attr_col; IHTMLDOMAttribute *attr; IHTMLElement *elem; @@ -4073,13 +4107,18 @@ static void test_attr_collection_builtins(IHTMLDocument2 *doc) BSTR bstr;
while(*iter) { - const WCHAR *tag = *iter++, **todos = NULL; + const WCHAR *tag = *iter++, **todos = NULL, **attrs_ie9 = NULL;
if(*iter_todo && !wcscmp(tag, *iter_todo)) { todos = ++iter_todo; while(*iter_todo++) {} }
+ if(compat_mode >= COMPAT_IE9 && *iter_ie9 && !wcscmp(tag, *iter_ie9)) { + attrs_ie9 = ++iter_ie9; + while(*iter_ie9++) {} + } + bstr = SysAllocString(tag); hres = IHTMLDocument2_createElement(doc, bstr, &elem); ok(hres == S_OK, "[%s] createElement failed: %08lx\n", wine_dbgstr_w(tag), hres); @@ -4101,7 +4140,9 @@ static void test_attr_collection_builtins(IHTMLDocument2 *doc) ok(hres == S_OK, "[%s] get_length failed: %08lx\n", wine_dbgstr_w(tag), hres);
memset(found, 0, sizeof(found)); + memset(found_ie9, 0, sizeof(found_ie9)); memset(found_tag_specific, 0, sizeof(found_tag_specific)); + memset(found_tag_specific_ie9, 0, sizeof(found_tag_specific_ie9)); for(i = 0; i < len; i++) { BOOL expected = FALSE;
@@ -4133,6 +4174,24 @@ static void test_attr_collection_builtins(IHTMLDocument2 *doc) break; } } + + if(compat_mode >= COMPAT_IE9) { + for(j = 0; j < ARRAY_SIZE(generic_builtins_ie9); j++) { + if(!wcscmp(bstr, generic_builtins_ie9[j])) { + found_ie9[j] = TRUE; + expected = TRUE; + break; + } + } + + for(j = 0; !expected && attrs_ie9 && attrs_ie9[j]; j++) { + if(!wcsicmp(bstr, attrs_ie9[j])) { + found_tag_specific_ie9[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); @@ -4155,6 +4214,13 @@ static void test_attr_collection_builtins(IHTMLDocument2 *doc) ok(found_tag_specific[i], "[%s] %s not in collection\n", wine_dbgstr_w(tag), wine_dbgstr_w(iter[i])); } iter += i + 1; + + if(compat_mode >= COMPAT_IE9) { + for(i = 0; i < ARRAY_SIZE(generic_builtins_ie9); i++) + ok(found_ie9[i], "[%s] %s not in collection\n", wine_dbgstr_w(tag), wine_dbgstr_w(generic_builtins_ie9[i])); + for(i = 0; attrs_ie9 && attrs_ie9[i]; i++) + ok(found_tag_specific_ie9[i], "[%s] %s not in collection\n", wine_dbgstr_w(tag), wine_dbgstr_w(attrs_ie9[i])); + } } }
@@ -12862,6 +12928,7 @@ START_TEST(dom) compat_mode = COMPAT_IE9; run_domtest(doc_blank_ie9, test_dom_elements); run_domtest(doc_blank_ie9, test_about_blank_storage); + run_domtest(doc_blank_ie9, test_attr_collection_builtins); compat_mode = COMPAT_NONE; } run_domtest(noscript_str, test_noscript); ```