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);