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 fcd8c969a01..3a08609d698 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -524,6 +524,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; @@ -4389,7 +4407,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; @@ -4413,13 +4431,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)) { @@ -7731,28 +7743,15 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, con
static inline 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 ---
This is a no-op to simplify the next patch slightly. --- dlls/mshtml/htmlattr.c | 8 ++++---- dlls/mshtml/mshtml_private.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 9b306eff406..4c8a567d9a0 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -37,7 +37,7 @@ static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *i return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface); }
-DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute, IHTMLDOMAttribute, impl_from_IHTMLDOMAttribute(iface)->dispex) +DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute, IHTMLDOMAttribute, impl_from_IHTMLDOMAttribute(iface)->node.event_target.dispex)
static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p) { @@ -147,7 +147,7 @@ static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute2(IHTMLDOMAttribute2 return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute2_iface); }
-DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute2, IHTMLDOMAttribute2, impl_from_IHTMLDOMAttribute2(iface)->dispex) +DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute2, IHTMLDOMAttribute2, impl_from_IHTMLDOMAttribute2(iface)->node.event_target.dispex)
static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p) { @@ -349,7 +349,7 @@ static const IHTMLDOMAttribute2Vtbl HTMLDOMAttribute2Vtbl = {
static inline HTMLDOMAttribute *impl_from_DispatchEx(DispatchEx *iface) { - return CONTAINING_RECORD(iface, HTMLDOMAttribute, dispex); + return CONTAINING_RECORD(iface, HTMLDOMAttribute, node.event_target.dispex); }
static void *HTMLDOMAttribute_query_interface(DispatchEx *dispex, REFIID riid) @@ -434,7 +434,7 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis ret->dispid = dispid; ret->elem = elem;
- init_dispatch(&ret->dispex, &Attr_dispex, doc->script_global, + init_dispatch(&ret->node.event_target.dispex, &Attr_dispex, doc->script_global, dispex_compat_mode(&doc->script_global->event_target.dispex));
/* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */ diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 95f7a5f4941..bb058b01854 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1323,7 +1323,8 @@ struct HTMLAttributeCollection { };
typedef struct { - DispatchEx dispex; + HTMLDOMNode node; + IHTMLDOMAttribute IHTMLDOMAttribute_iface; IHTMLDOMAttribute2 IHTMLDOMAttribute2_iface;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
We only use them for IE9+ modes because the legacy node-like attribute props are correct wrt the older compat modes.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlattr.c | 199 ++++++++++++++++++++++++++++-- dlls/mshtml/htmldoc.c | 17 ++- dlls/mshtml/htmlelem.c | 174 ++++++++++++++++++++------ dlls/mshtml/mshtml_private.h | 4 +- dlls/mshtml/tests/documentmode.js | 72 +++++++++++ 5 files changed, 416 insertions(+), 50 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 4c8a567d9a0..f3133c681f7 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -43,6 +43,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BS { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
+ if(This->node.nsnode) + return IHTMLDOMNode_get_nodeName(&This->node.IHTMLDOMNode_iface, p); + TRACE("(%p)->(%p)\n", This, p);
if(!This->elem) { @@ -63,6 +66,9 @@ static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, V HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); EXCEPINFO ei;
+ if(This->node.nsnode) + return IHTMLDOMNode_put_nodeValue(&This->node.IHTMLDOMNode_iface, v); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
if(!This->elem) @@ -76,6 +82,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, V { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
+ if(This->node.nsnode) + return IHTMLDOMNode_get_nodeValue(&This->node.IHTMLDOMNode_iface, p); + TRACE("(%p)->(%p)\n", This, p);
if(!This->elem) @@ -92,9 +101,16 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V BSTR name; nsresult nsres; HRESULT hres; + cpp_bool b;
TRACE("(%p)->(%p)\n", This, p);
+ if(This->node.nsnode) { + nsres = nsIDOMAttr_GetSpecified((nsIDOMAttr*)This->node.nsnode, &b); + *p = variant_bool(NS_SUCCEEDED(nsres) && b); + return S_OK; + } + if(!This->elem || !This->elem->dom_element) { FIXME("NULL This->elem\n"); return E_UNEXPECTED; @@ -152,19 +168,36 @@ DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute2, IHTMLDOMAttribute2, impl_from_IHTMLDOMA static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + nsAString nsstr; + nsresult nsres;
TRACE("(%p)->(%p)\n", This, p);
+ if(This->node.nsnode) { + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIDOMAttr_GetName((nsIDOMAttr*)This->node.nsnode, &nsstr); + return return_nsstr(nsres, &nsstr, p); + } + return IHTMLDOMAttribute_get_nodeName(&This->IHTMLDOMAttribute_iface, p); }
static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BSTR v) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + nsAString nsstr; + nsresult nsres; VARIANT var;
TRACE("(%p)->(%s)\n", This, debugstr_w(v));
+ if(This->node.nsnode) { + nsAString_InitDepend(&nsstr, v); + nsres = nsIDOMAttr_SetValue((nsIDOMAttr*)This->node.nsnode, &nsstr); + nsAString_Finish(&nsstr); + return NS_SUCCEEDED(nsres) ? S_OK : E_FAIL; + } + V_VT(&var) = VT_BSTR; V_BSTR(&var) = v; return IHTMLDOMAttribute_put_nodeValue(&This->IHTMLDOMAttribute_iface, var); @@ -173,11 +206,19 @@ static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BST static HRESULT WINAPI HTMLDOMAttribute2_get_value(IHTMLDOMAttribute2 *iface, BSTR *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + nsAString nsstr; + nsresult nsres; VARIANT val; HRESULT hres;
TRACE("(%p)->(%p)\n", This, p);
+ if(This->node.nsnode) { + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIDOMAttr_GetValue((nsIDOMAttr*)This->node.nsnode, &nsstr); + return return_nsstr(nsres, &nsstr, p); + } + V_VT(&val) = VT_EMPTY; if(This->elem) hres = get_elem_attr_value_by_dispid(This->elem, This->dispid, &val); @@ -208,7 +249,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V static HRESULT WINAPI HTMLDOMAttribute2_get_nodeType(IHTMLDOMAttribute2 *iface, LONG *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_nodeType(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
@@ -216,6 +262,9 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
+ if(This->node.nsnode) + return IHTMLDOMNode_get_parentNode(&This->node.IHTMLDOMNode_iface, p); + TRACE("(%p)->(%p)\n", This, p);
*p = NULL; @@ -225,49 +274,84 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface static HRESULT WINAPI HTMLDOMAttribute2_get_childNodes(IHTMLDOMAttribute2 *iface, IDispatch **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_childNodes(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_get_firstChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_firstChild(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_get_lastChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_lastChild(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_get_previousSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_previousSibling(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_get_nextSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_nextSibling(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_get_attributes(IHTMLDOMAttribute2 *iface, IDispatch **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_attributes(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_get_ownerDocument(IHTMLDOMAttribute2 *iface, IDispatch **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode2_get_ownerDocument(&This->node.IHTMLDOMNode2_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; }
@@ -275,7 +359,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_insertBefore(IHTMLDOMAttribute2 *iface, VARIANT refChild, IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_insertBefore(&This->node.IHTMLDOMNode_iface, newChild, refChild, node); + FIXME("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node); + return E_NOTIMPL; }
@@ -283,7 +372,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_replaceChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *oldChild, IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_replaceChild(&This->node.IHTMLDOMNode_iface, newChild, oldChild, node); + FIXME("(%p)->(%p %p %p)\n", This, newChild, oldChild, node); + return E_NOTIMPL; }
@@ -291,7 +385,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_removeChild(IHTMLDOMAttribute2 *iface, I IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_removeChild(&This->node.IHTMLDOMNode_iface, oldChild, node); + FIXME("(%p)->(%p %p)\n", This, oldChild, node); + return E_NOTIMPL; }
@@ -299,14 +398,24 @@ static HRESULT WINAPI HTMLDOMAttribute2_appendChild(IHTMLDOMAttribute2 *iface, I IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_appendChild(&This->node.IHTMLDOMNode_iface, newChild, node); + FIXME("(%p)->(%p %p)\n", This, newChild, node); + return E_NOTIMPL; }
static HRESULT WINAPI HTMLDOMAttribute2_hasChildNodes(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *fChildren) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_hasChildNodes(&This->node.IHTMLDOMNode_iface, fChildren); + FIXME("(%p)->(%p)\n", This, fChildren); + return E_NOTIMPL; }
@@ -314,7 +423,20 @@ static HRESULT WINAPI HTMLDOMAttribute2_cloneNode(IHTMLDOMAttribute2 *iface, VAR IHTMLDOMAttribute **clonedNode) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + HRESULT hres; + + if(This->node.nsnode) { + IHTMLDOMNode *cloned; + hres = IHTMLDOMNode_cloneNode(&This->node.IHTMLDOMNode_iface, fDeep, &cloned); + if(SUCCEEDED(hres)) { + hres = IHTMLDOMNode_QueryInterface(cloned, &IID_IHTMLDOMAttribute, (void**)clonedNode); + IHTMLDOMNode_Release(cloned); + } + return hres; + } + FIXME("(%p)->(%x %p)\n", This, fDeep, clonedNode); + return E_NOTIMPL; }
@@ -347,11 +469,46 @@ static const IHTMLDOMAttribute2Vtbl HTMLDOMAttribute2Vtbl = { HTMLDOMAttribute2_cloneNode };
+static inline HTMLDOMAttribute *impl_from_HTMLDOMNode(HTMLDOMNode *iface) +{ + return CONTAINING_RECORD(iface, HTMLDOMAttribute, node); +} + static inline HTMLDOMAttribute *impl_from_DispatchEx(DispatchEx *iface) { return CONTAINING_RECORD(iface, HTMLDOMAttribute, node.event_target.dispex); }
+static HRESULT HTMLDOMAttribute_clone(HTMLDOMNode *iface, nsIDOMNode *nsnode, HTMLDOMNode **ret) +{ + HTMLDOMAttribute *This = impl_from_HTMLDOMNode(iface); + HTMLDOMAttribute *new_attr; + nsIDOMAttr *nsattr; + nsresult nsres; + HRESULT hres; + + nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMAttr, (void**)&nsattr); + if(NS_FAILED(nsres)) { + ERR("no nsIDOMAttr iface\n"); + return E_FAIL; + } + + hres = HTMLDOMAttribute_Create(NULL, This->elem, This->dispid, This->node.doc, nsattr, &new_attr); + nsIDOMAttr_Release(nsattr); + if(FAILED(hres)) + return hres; + + *ret = &new_attr->node; + return S_OK; +} + +static const cpc_entry_t HTMLDOMAttribute_cpc[] = {{NULL}}; + +static const NodeImplVtbl HTMLDOMAttributeImplVtbl = { + .cpc_entries = HTMLDOMAttribute_cpc, + .clone = HTMLDOMAttribute_clone, +}; + static void *HTMLDOMAttribute_query_interface(DispatchEx *dispex, REFIID riid) { HTMLDOMAttribute *This = impl_from_DispatchEx(dispex); @@ -360,6 +517,8 @@ static void *HTMLDOMAttribute_query_interface(DispatchEx *dispex, REFIID riid) return &This->IHTMLDOMAttribute_iface; if(IsEqualGUID(&IID_IHTMLDOMAttribute2, riid)) return &This->IHTMLDOMAttribute2_iface; + if(This->node.nsnode) + return HTMLDOMNode_query_interface(&This->node.event_target.dispex, riid);
return NULL; } @@ -368,6 +527,8 @@ static void HTMLDOMAttribute_traverse(DispatchEx *dispex, nsCycleCollectionTrave { HTMLDOMAttribute *This = impl_from_DispatchEx(dispex);
+ if(This->node.nsnode) + HTMLDOMNode_traverse(&This->node.event_target.dispex, cb); if(This->elem) note_cc_edge((nsISupports*)&This->elem->node.IHTMLDOMNode_iface, "elem", cb); traverse_variant(&This->value, "value", cb); @@ -377,6 +538,8 @@ static void HTMLDOMAttribute_unlink(DispatchEx *dispex) { HTMLDOMAttribute *This = impl_from_DispatchEx(dispex);
+ if(This->node.nsnode) + HTMLDOMNode_unlink(&This->node.event_target.dispex); if(This->elem) { HTMLElement *elem = This->elem; This->elem = NULL; @@ -390,7 +553,11 @@ static void HTMLDOMAttribute_destructor(DispatchEx *dispex) HTMLDOMAttribute *This = impl_from_DispatchEx(dispex); VariantClear(&This->value); free(This->name); - free(This); + + if(This->node.nsnode) + HTMLDOMNode_destructor(&This->node.event_target.dispex); + else + free(This); }
static const dispex_static_data_vtbl_t HTMLDOMAttribute_dispex_vtbl = { @@ -400,6 +567,12 @@ static const dispex_static_data_vtbl_t HTMLDOMAttribute_dispex_vtbl = { .unlink = HTMLDOMAttribute_unlink };
+static void HTMLDOMAttribute_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode >= COMPAT_MODE_IE9) + HTMLDOMNode_init_dispex_info(info, mode); +} + static const tid_t HTMLDOMAttribute_iface_tids[] = { IHTMLDOMAttribute_tid, IHTMLDOMAttribute2_tid, @@ -411,6 +584,7 @@ dispex_static_data_t Attr_dispex = { .vtbl = &HTMLDOMAttribute_dispex_vtbl, .disp_tid = DispHTMLDOMAttribute_tid, .iface_tids = HTMLDOMAttribute_iface_tids, + .init_info = HTMLDOMAttribute_init_dispex_info, };
HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface) @@ -418,8 +592,8 @@ HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface) return iface->lpVtbl == &HTMLDOMAttributeVtbl ? impl_from_IHTMLDOMAttribute(iface) : NULL; }
-HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, - HTMLDocumentNode *doc, HTMLDOMAttribute **attr) +HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, HTMLDocumentNode *doc, + nsIDOMAttr *nsattr, HTMLDOMAttribute **attr) { HTMLAttributeCollection *col; HTMLDOMAttribute *ret; @@ -434,16 +608,14 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis ret->dispid = dispid; ret->elem = elem;
- init_dispatch(&ret->node.event_target.dispex, &Attr_dispex, doc->script_global, - dispex_compat_mode(&doc->script_global->event_target.dispex)); - - /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */ + /* For attributes attached to an element, (elem,dispid) pair should + be valid used for its operation if we don't have a proper node. */ if(elem) { IHTMLDOMNode_AddRef(&elem->node.IHTMLDOMNode_iface);
hres = HTMLElement_get_attr_col(&elem->node, &col); if(FAILED(hres)) { - IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface); + free(ret); return hres; } IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface); @@ -451,6 +623,17 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis list_add_tail(&elem->attrs->attrs, &ret->entry); }
+ /* If we have a nsattr, use proper node */ + if(nsattr) { + ret->node.vtbl = &HTMLDOMAttributeImplVtbl; + HTMLDOMNode_Init(doc, &ret->node, (nsIDOMNode*)nsattr, &Attr_dispex); + *attr = ret; + return S_OK; + } + + init_dispatch(&ret->node.event_target.dispex, &Attr_dispex, doc->script_global, + dispex_compat_mode(&doc->script_global->event_target.dispex)); + /* For detached attributes we may still do most operations if we have its name available. */ if(name) { ret->name = wcsdup(name); diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 6ae7ccb36e4..4c57e552d0e 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3006,12 +3006,27 @@ static HRESULT WINAPI HTMLDocument5_createAttribute(IHTMLDocument5 *iface, BSTR IHTMLDOMAttribute **ppattribute) { HTMLDocumentNode *This = impl_from_IHTMLDocument5(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; + nsresult nsres; + nsAString str; HRESULT hres;
TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrattrName), ppattribute);
- hres = HTMLDOMAttribute_Create(bstrattrName, NULL, 0, This, &attr); + if(dispex_compat_mode(&This->node.event_target.dispex) >= COMPAT_MODE_IE9) { + nsAString_InitDepend(&str, bstrattrName); + nsres = nsIDOMDocument_CreateAttribute(This->dom_document, &str, &nsattr); + nsAString_Finish(&str); + if(NS_FAILED(nsres)) { + ERR("CreateAttribute failed: %08lx\n", nsres); + return E_FAIL; + } + } + + hres = HTMLDOMAttribute_Create(bstrattrName, NULL, 0, This, nsattr, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres;
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 3a08609d698..d1a7451b6fa 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -524,18 +524,28 @@ HRESULT create_element(HTMLDocumentNode *doc, const WCHAR *tag, HTMLElement **re return hres; }
-static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPID dispid, LONG *pos) +static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPID dispid, nsIDOMAttr *nsattr, 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; + if(nsattr) { + LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { + if(iter->node.nsnode == (nsIDOMNode*)nsattr) { + ret = iter; + break; + } + i++; + } + }else { + LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { + if(iter->dispid == dispid) { + ret = iter; + break; + } + i++; } - i++; } if(pos) *pos = i; @@ -4407,6 +4417,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD IHTMLDOMAttribute **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement4(iface); + nsIDOMAttr *nsattr, *oldnsattr = NULL; HTMLDOMAttribute *attr, *replace; HTMLAttributeCollection *attrs; DISPID dispid; @@ -4423,17 +4434,48 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD return E_INVALIDARG; }
- hres = dispex_get_id(&This->node.event_target.dispex, attr->name, fdexNameCaseInsensitive | fdexNameEnsure, &dispid); - if(FAILED(hres)) - return hres; - hres = HTMLElement_get_attr_col(&This->node, &attrs); if(FAILED(hres)) return hres;
- replace = find_attr_in_list(attrs, dispid, NULL); + nsattr = (nsIDOMAttr*)attr->node.nsnode; + if(nsattr && !attrs->nsattrs) { + FIXME("Attribute has proper node but no NS collection for it.\n"); + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + return E_NOTIMPL; + } + + if(nsattr) { + if(NS_FAILED(nsIDOMMozNamedAttrMap_SetNamedItem(attrs->nsattrs, nsattr, &oldnsattr))) { + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + return E_FAIL; + } + replace = NULL; + if(oldnsattr) { + replace = find_attr_in_list(attrs, 0, oldnsattr, NULL); + nsIDOMAttr_Release(oldnsattr); + } + }else { + hres = dispex_get_id(&This->node.event_target.dispex, attr->name, fdexNameCaseInsensitive | fdexNameEnsure, &dispid); + if(FAILED(hres)) { + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + return hres; + } + replace = find_attr_in_list(attrs, dispid, NULL, NULL); + } + if(replace) { - hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value); + if(!nsattr) { + hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value); + if(FAILED(hres)) { + WARN("could not get attr value: %08lx\n", hres); + V_VT(&replace->value) = VT_EMPTY; + } + if(!replace->name) { + replace->name = attr->name; + attr->name = NULL; + } + } if(FAILED(hres)) { WARN("could not get attr value: %08lx\n", hres); V_VT(&replace->value) = VT_EMPTY; @@ -4456,10 +4498,12 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD
IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface);
- hres = set_elem_attr_value_by_dispid(This, dispid, &attr->value); - if(FAILED(hres)) - WARN("Could not set attribute value: %08lx\n", hres); - VariantClear(&attr->value); + if(!nsattr) { + hres = set_elem_attr_value_by_dispid(This, dispid, &attr->value); + if(FAILED(hres)) + WARN("Could not set attribute value: %08lx\n", hres); + VariantClear(&attr->value); + }
*ppretAttribute = replace ? &replace->IHTMLDOMAttribute_iface : NULL; return S_OK; @@ -7688,12 +7732,28 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters return S_OK; }
-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, DISPID *dispid, nsIDOMAttr **nsattr) { DISPID id = start; + UINT32 length; LONG len = -1; HRESULT hres;
+ if(This->nsattrs) { + id++; + if(dispid) { + *dispid = id + *idx; + if(!nsattr) + return S_OK; + if(NS_FAILED(nsIDOMMozNamedAttrMap_Item(This->nsattrs, *dispid, nsattr))) + return E_FAIL; + return *nsattr ? S_OK : DISP_E_UNKNOWNNAME; + } + nsIDOMMozNamedAttrMap_GetLength(This->nsattrs, &length); + *idx = (length > id) ? length - id : 0; + return S_OK; + } + FIXME("filter non-enumerable attributes out\n");
while(1) { @@ -7717,13 +7777,15 @@ 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, DISPID *dispid, nsIDOMAttr **nsattr) { - return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid); + return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid, nsattr); }
-static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHAR *name, DISPID *id) +static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHAR *name, DISPID *id, nsIDOMAttr **nsattr) { + nsAString nsstr; + nsresult nsres; HRESULT hres;
if(name[0]>='0' && name[0]<='9') { @@ -7732,21 +7794,31 @@ 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, id, nsattr); if(SUCCEEDED(hres)) return hres; } }
+ if(This->nsattrs) { + nsAString_InitDepend(&nsstr, name); + *nsattr = NULL; + nsres = nsIDOMMozNamedAttrMap_GetNamedItem(This->nsattrs, &nsstr, nsattr); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres)) + return E_FAIL; + return *nsattr ? S_OK : DISP_E_UNKNOWNNAME; + } + return dispex_get_id(&This->elem->node.event_target.dispex, name, fdexNameCaseInsensitive, id); }
-static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) +static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, nsIDOMAttr *nsattr, LONG *list_pos, HTMLDOMAttribute **attr) { HRESULT hres;
- if(!(*attr = find_attr_in_list(This, id, list_pos))) { - hres = HTMLDOMAttribute_Create(NULL, This->elem, id, This->elem->node.doc, attr); + if(!(*attr = find_attr_in_list(This, id, nsattr, list_pos))) { + hres = HTMLDOMAttribute_Create(NULL, This->elem, id, This->elem->node.doc, nsattr, attr); if(FAILED(hres)) return hres; } @@ -7820,6 +7892,7 @@ static HRESULT WINAPI HTMLAttributeCollectionEnum_Next(IEnumVARIANT *iface, ULON HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface); DISPID tmp, dispid = This->iter_dispid; HTMLDOMAttribute *attr; + nsIDOMAttr *nsattr; LONG rel_index = 0; HRESULT hres; ULONG i; @@ -7827,10 +7900,13 @@ 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); + nsattr = NULL; + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, dispid, &tmp, &nsattr); if(SUCCEEDED(hres)) { dispid = tmp; - hres = get_domattr(This->col, dispid, NULL, &attr); + hres = get_domattr(This->col, dispid, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); } else if(hres == DISP_E_UNKNOWNNAME) break; @@ -7865,14 +7941,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, NULL, 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, &dispid, NULL); if(FAILED(hres)) return hres; This->iter += remaining; @@ -7926,7 +8002,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, NULL, NULL); return hres; }
@@ -7956,6 +8032,7 @@ static HRESULT WINAPI HTMLAttributeCollection__newEnum(IHTMLAttributeCollection static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *iface, VARIANT *name, IDispatch **ppItem) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; DISPID id; HRESULT hres; @@ -7964,10 +8041,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), &id, &nsattr); 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), &id, &nsattr); break; default: FIXME("unsupported name %s\n", debugstr_variant(name)); @@ -7978,7 +8055,9 @@ static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *ifa if(FAILED(hres)) return hres;
- hres = get_domattr(This, id, NULL, &attr); + hres = get_domattr(This, id, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres;
@@ -8011,13 +8090,14 @@ static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollec IHTMLDOMAttribute **newretNode) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; DISPID id; HRESULT hres;
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, &id, &nsattr); if(hres == DISP_E_UNKNOWNNAME) { *newretNode = NULL; return S_OK; @@ -8025,7 +8105,9 @@ static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollec return hres; }
- hres = get_domattr(This, id, NULL, &attr); + hres = get_domattr(This, id, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres;
@@ -8096,19 +8178,22 @@ static HRESULT WINAPI HTMLAttributeCollection3_removeNamedItem(IHTMLAttributeCol static HRESULT WINAPI HTMLAttributeCollection3_item(IHTMLAttributeCollection3 *iface, LONG index, IHTMLDOMAttribute **ppNodeOut) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; DISPID id; HRESULT hres;
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, &id, &nsattr); if(hres == DISP_E_UNKNOWNNAME) return E_INVALIDARG; if(FAILED(hres)) return hres;
- hres = get_domattr(This, id, NULL, &attr); + hres = get_domattr(This, id, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres;
@@ -8165,6 +8250,8 @@ static void HTMLAttributeCollection_traverse(DispatchEx *dispex, nsCycleCollecti note_cc_edge((nsISupports*)&attr->IHTMLDOMAttribute_iface, "attr", cb); if(This->elem) note_cc_edge((nsISupports*)&This->elem->node.IHTMLDOMNode_iface, "elem", cb); + if(This->nsattrs) + note_cc_edge((nsISupports*)This->nsattrs, "nsattrs", cb); }
static void HTMLAttributeCollection_unlink(DispatchEx *dispex) @@ -8181,6 +8268,7 @@ static void HTMLAttributeCollection_unlink(DispatchEx *dispex) This->elem = NULL; IHTMLDOMNode_Release(&elem->node.IHTMLDOMNode_iface); } + unlink_ref(&This->nsattrs); }
static void HTMLAttributeCollection_destructor(DispatchEx *dispex) @@ -8192,17 +8280,20 @@ static void HTMLAttributeCollection_destructor(DispatchEx *dispex) static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, const WCHAR *name, DWORD flags, DISPID *dispid) { HTMLAttributeCollection *This = HTMLAttributeCollection_from_DispatchEx(dispex); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; LONG pos; HRESULT hres;
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, dispid, &nsattr); if(FAILED(hres)) return hres;
- hres = get_domattr(This, *dispid, &pos, &attr); + hres = get_domattr(This, *dispid, nsattr, &pos, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres; IHTMLDOMAttribute_Release(&attr->IHTMLDOMAttribute_iface); @@ -8272,6 +8363,7 @@ dispex_static_data_t NamedNodeMap_dispex = { HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **ac) { HTMLElement *This = impl_from_HTMLDOMNode(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex);
if(This->attrs) { IHTMLAttributeCollection_AddRef(&This->attrs->IHTMLAttributeCollection_iface); @@ -8290,8 +8382,10 @@ HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **a IHTMLDOMNode_AddRef(&This->node.IHTMLDOMNode_iface); This->attrs->elem = This; list_init(&This->attrs->attrs); - init_dispatch(&This->attrs->dispex, &NamedNodeMap_dispex, This->node.doc->script_global, - dispex_compat_mode(&This->node.event_target.dispex)); + init_dispatch(&This->attrs->dispex, &NamedNodeMap_dispex, This->node.doc->script_global, compat_mode); + + if(compat_mode >= COMPAT_MODE_IE9 && This->dom_element) + nsIDOMElement_GetAttributes(This->dom_element, &This->attrs->nsattrs);
*ac = This->attrs; IHTMLAttributeCollection_AddRef(&This->attrs->IHTMLAttributeCollection_iface); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index bb058b01854..94f64bdb7ca 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1318,11 +1318,13 @@ struct HTMLAttributeCollection { IHTMLAttributeCollection2 IHTMLAttributeCollection2_iface; IHTMLAttributeCollection3 IHTMLAttributeCollection3_iface;
+ nsIDOMMozNamedAttrMap *nsattrs; HTMLElement *elem; struct list attrs; };
typedef struct { + /* valid only when attribute nodes are used (node.nsnode) */ HTMLDOMNode node;
IHTMLDOMAttribute IHTMLDOMAttribute_iface; @@ -1340,7 +1342,7 @@ typedef struct {
HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute*);
-HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLElement*,DISPID,HTMLDocumentNode*,HTMLDOMAttribute**); +HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLElement*,DISPID,HTMLDocumentNode*,nsIDOMAttr*,HTMLDOMAttribute**);
HRESULT HTMLElement_Create(HTMLDocumentNode*,nsIDOMNode*,BOOL,HTMLElement**); HRESULT HTMLCommentElement_Create(HTMLDocumentNode*,nsIDOMNode*,HTMLElement**); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 164f5e2bce4..6cd970e9000 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -571,6 +571,77 @@ sync_test("elem_props", function() { test_exposed("fileSize", v < 11); });
+sync_test("attr_props", function() { + var elem = document.createElement("style"), attr; + var v = document.documentMode; + elem.setAttribute("id", "test"); + elem.setAttribute("test", "wine"); + elem.setAttribute("z-index", "foobar"); + + function test_exposed(prop, expect) { + if(expect) + ok(prop in attr, prop + " not found in attribute."); + else + ok(!(prop in attr), prop + " found in attribute."); + } + + function test_attr(expando, specified, expando_todo) { + var r = attr.expando; + todo_wine_if(expando_todo). + ok(r === expando, attr.name + " attr.expando = " + r); + r = attr.specified; + ok(r === specified, attr.name + " attr.specified = " + r); + } + + attr = elem.getAttributeNode("id"); + test_exposed("appendChild", true); + test_exposed("attributes", true); + test_exposed("childNodes", true); + test_exposed("cloneNode", true); + test_exposed("compareDocumentPosition", v >= 9); + test_exposed("expando", true); + test_exposed("firstChild", true); + test_exposed("hasChildNodes", true); + test_exposed("insertBefore", true); + test_exposed("isDefaultNamespace", v >= 9); + test_exposed("isEqualNode", v >= 9); + test_exposed("isSameNode", v >= 9); + test_exposed("isSupported", v >= 9); + test_exposed("lastChild", true); + test_exposed("localName", v >= 9); + test_exposed("lookupNamespaceURI", v >= 9); + test_exposed("lookupPrefix", v >= 9); + test_exposed("name", true); + test_exposed("namespaceURI", v >= 9); + test_exposed("nextSibling", true); + test_exposed("nodeName", true); + test_exposed("nodeType", true); + test_exposed("nodeValue", true); + test_exposed("ownerDocument", true); + test_exposed("parentNode", true); + test_exposed("prefix", v >= 9); + test_exposed("previousSibling", true); + test_exposed("removeChild", true); + test_exposed("replaceChild", true); + test_exposed("specified", true); + test_exposed("textContent", v >= 9); + test_exposed("value", true); + test_attr(false, true); + + attr = elem.getAttributeNode("test"); + test_attr(true, true, v >= 9); + + attr = elem.getAttributeNode("z-index"); + test_attr(true, true, v >= 9); + + attr = elem.getAttributeNode("tabIndex"); + if(v < 8) + test_attr(false, false); + else + todo_wine_if(v === 8). + ok(attr === null, "tabIndex attr not null."); +}); + sync_test("doc_props", function() { function test_exposed(prop, expect, is_todo) { var ok_ = is_todo ? todo_wine.ok : ok; @@ -3766,6 +3837,7 @@ sync_test("prototype props", function() { test_own_props(constr.prototype, name, props, todos, flaky); }
+ check(Attr, [ "expando", "name", "ownerElement", "specified", "value" ], [ "ownerElement" ]); check(CharacterData, [ "appendData", "data", "deleteData", "insertData", "length", "replaceData", "substringData" ]); check(Comment, [ "text" ]); check(CSSStyleDeclaration, [
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 27 +++++++++++++++++++++++++++ dlls/mshtml/htmlelem.c | 21 +++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 7 +++---- 4 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 77eec049912..e9ef3ea9f98 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -701,6 +701,33 @@ dispex_prop_type_t get_dispid_type(DISPID id) return DISPEXPROP_BUILTIN; }
+BOOL is_custom_attribute(DispatchEx *dispex, const WCHAR *name) +{ + compat_mode_t compat_mode = dispex->info->compat_mode; + const dispex_data_t *info = dispex->info; + func_info_t **funcs = info->name_table; + DWORD a, b, i; + int c; + + assert(compat_mode >= COMPAT_MODE_IE9); + + for(;;) { + info = object_descriptors[info->desc->prototype_id]->prototype_info[compat_mode - COMPAT_MODE_IE9]; + funcs = info->name_table; + + for(a = 0, b = info->name_cnt; a < b;) { + i = (a + b) / 2; + c = wcsicmp(funcs[i]->name, name); + if(!c) + return (funcs[i]->func_disp_idx >= 0); + if(c > 0) b = i; + else a = i + 1; + } + if(!info->desc->prototype_id) + return DISP_E_UNKNOWNNAME; + } +} + static HRESULT variant_copy(VARIANT *dest, VARIANT *src) { if(V_VT(src) == VT_BSTR && !V_BSTR(src)) { diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index d1a7451b6fa..f988d394b45 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -552,6 +552,24 @@ static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPI return ret; }
+static DISPID get_dispid_for_nsattr(HTMLElement *elem, nsIDOMAttr *nsattr) +{ + DISPID dispid = 0; + nsAString nsstr; + + nsAString_InitDepend(&nsstr, NULL); + if(SUCCEEDED(nsIDOMAttr_GetName(nsattr, &nsstr))) { + const PRUnichar *name; + nsAString_GetData(&nsstr, &name); + + /* Supply a dummy non-builtin dispid so it can be checked for expando */ + if(is_custom_attribute(&elem->node.event_target.dispex, name)) + dispid = MSHTML_DISPID_CUSTOM_MIN; + nsAString_Finish(&nsstr); + } + return dispid; +} + typedef struct { DispatchEx dispex; IHTMLRect IHTMLRect_iface; @@ -4450,6 +4468,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); return E_FAIL; } + dispid = get_dispid_for_nsattr(This, nsattr); replace = NULL; if(oldnsattr) { replace = find_attr_in_list(attrs, 0, oldnsattr, NULL); @@ -7818,6 +7837,8 @@ static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, nsID HRESULT hres;
if(!(*attr = find_attr_in_list(This, id, nsattr, list_pos))) { + if(nsattr) + id = get_dispid_for_nsattr(This->elem, nsattr); hres = HTMLDOMAttribute_Create(NULL, This->elem, id, This->elem->node.doc, nsattr, attr); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 94f64bdb7ca..bc262292829 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -622,6 +622,7 @@ void dispex_props_unlink(DispatchEx*); HRESULT change_type(VARIANT*,VARIANT*,VARTYPE,IServiceProvider*); HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**); HRESULT get_dispids(tid_t,DWORD*,DISPID**); +BOOL is_custom_attribute(DispatchEx*,const WCHAR*); HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*); HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*); void release_typelib(void); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 6cd970e9000..6e0c4dcb549 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -585,9 +585,8 @@ sync_test("attr_props", function() { ok(!(prop in attr), prop + " found in attribute."); }
- function test_attr(expando, specified, expando_todo) { + function test_attr(expando, specified) { var r = attr.expando; - todo_wine_if(expando_todo). ok(r === expando, attr.name + " attr.expando = " + r); r = attr.specified; ok(r === specified, attr.name + " attr.specified = " + r); @@ -629,10 +628,10 @@ sync_test("attr_props", function() { test_attr(false, true);
attr = elem.getAttributeNode("test"); - test_attr(true, true, v >= 9); + test_attr(true, true);
attr = elem.getAttributeNode("z-index"); - test_attr(true, true, v >= 9); + test_attr(true, true);
attr = elem.getAttributeNode("tabIndex"); if(v < 8)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/tests/documentmode.js | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index f3133c681f7..deb58b9eb64 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -112,8 +112,8 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V }
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/documentmode.js b/dlls/mshtml/tests/documentmode.js index 6e0c4dcb549..282365d7c1e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -639,6 +639,9 @@ sync_test("attr_props", function() { else todo_wine_if(v === 8). ok(attr === null, "tabIndex attr not null."); + + attr = document.createAttribute("winetest"); + test_attr(false, v >= 9); });
sync_test("doc_props", function() {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 21 +++++++++++++++++++++ dlls/mshtml/htmlelem.c | 5 ++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 2 +- 4 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index e9ef3ea9f98..103a8f7718b 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1816,6 +1816,27 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return call_builtin_function(dispex, func, dp, res, ei, caller); }
+BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func)) || func->func_disp_idx < 0) + return FALSE; + + if(dispex->dynamic_data && dispex->dynamic_data->func_disps) { + func_obj_entry_t *entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + + if(entry->func_obj && (V_VT(&entry->val) != VT_DISPATCH || + V_DISPATCH(&entry->val) != (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface)) + return FALSE; + } + + return TRUE; +} + static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) { func_obj_entry_t *entry; diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index f988d394b45..cb510ea15ae 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -7829,7 +7829,10 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, con return *nsattr ? S_OK : DISP_E_UNKNOWNNAME; }
- 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); + if(FAILED(hres)) + return hres; + return dispex_is_builtin_method(&This->elem->node.event_target.dispex, *id) ? DISP_E_UNKNOWNNAME : S_OK; }
static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, nsIDOMAttr *nsattr, LONG *list_pos, HTMLDOMAttribute **attr) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index bc262292829..fab7aeae6de 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -631,6 +631,7 @@ const void *dispex_get_vtbl(DispatchEx*); void dispex_info_add_interface(dispex_data_t*,tid_t,const dispex_hook_t*); void dispex_info_add_dispids(dispex_data_t*,tid_t,const DISPID*); compat_mode_t dispex_compat_mode(DispatchEx*); +BOOL dispex_is_builtin_method(DispatchEx*,DISPID); HRESULT dispex_to_string(DispatchEx*,BSTR*); HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 282365d7c1e..e3bff0e296f 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -295,7 +295,7 @@ sync_test("builtin_toString", function() { if(!localStorage) win_skip("localStorage is buggy and not available, skipping");
test("attribute", document.createAttribute("class"), "Attr"); - if(false /* todo_wine */) test("attributes", e.attributes, "NamedNodeMap"); + test("attributes", e.attributes, "NamedNodeMap"); test("childNodes", document.body.childNodes, "NodeList"); if(clientRects) test("clientRect", clientRects[0], "ClientRect"); if(clientRects) test("clientRects", clientRects, "ClientRectList");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
'expando' returns TRUE on non-builtin attributes (builtin attributes are only the builtin accessors, not methods), while 'specified' always returns TRUE on any non-builtin attribute as long as it has a user-defined value (e.g. for builtin methods, their slot must be non-default), which is an extension to just checking the dynamic props.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 40 +++++++++++++++++++++++++++++++ dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/mshtml_private.h | 2 ++ dlls/mshtml/tests/documentmode.js | 4 ++++ 4 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 103a8f7718b..cec42a9446c 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1816,6 +1816,22 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return call_builtin_function(dispex, func, dp, res, ei, caller); }
+BOOL dispex_is_builtin_attribute(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(id == DISPID_VALUE) + return TRUE; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + return func->func_disp_idx < 0; +} + BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) { func_info_t *func; @@ -1837,6 +1853,30 @@ BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) return TRUE; }
+BOOL dispex_is_builtin_value(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + if(func->func_disp_idx < 0) + return TRUE; + + if(dispex->dynamic_data && dispex->dynamic_data->func_disps) { + func_obj_entry_t *entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + + if(entry->func_obj && (V_VT(&entry->val) != VT_DISPATCH || + V_DISPATCH(&entry->val) != (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface)) + return FALSE; + } + + return TRUE; +} + static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) { func_obj_entry_t *entry; diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index deb58b9eb64..473ad96165f 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -116,7 +116,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V return S_OK; }
- if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) { + if(!dispex_is_builtin_value(&This->elem->node.event_target.dispex, This->dispid)) { *p = VARIANT_TRUE; return S_OK; } @@ -242,7 +242,7 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V
TRACE("(%p)->(%p)\n", This, p);
- *p = variant_bool(This->elem && get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN); + *p = variant_bool(This->elem && !dispex_is_builtin_attribute(&This->elem->node.event_target.dispex, This->dispid)); return S_OK; }
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index fab7aeae6de..3fef723019c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -631,7 +631,9 @@ const void *dispex_get_vtbl(DispatchEx*); void dispex_info_add_interface(dispex_data_t*,tid_t,const dispex_hook_t*); void dispex_info_add_dispids(dispex_data_t*,tid_t,const DISPID*); compat_mode_t dispex_compat_mode(DispatchEx*); +BOOL dispex_is_builtin_attribute(DispatchEx*,DISPID);; BOOL dispex_is_builtin_method(DispatchEx*,DISPID); +BOOL dispex_is_builtin_value(DispatchEx*,DISPID); HRESULT dispex_to_string(DispatchEx*,BSTR*); HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index e3bff0e296f..392a6367dbc 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -577,6 +577,7 @@ sync_test("attr_props", function() { elem.setAttribute("id", "test"); elem.setAttribute("test", "wine"); elem.setAttribute("z-index", "foobar"); + elem.setAttribute("removeAttribute", "funcattr");
function test_exposed(prop, expect) { if(expect) @@ -633,6 +634,9 @@ sync_test("attr_props", function() { attr = elem.getAttributeNode("z-index"); test_attr(true, true);
+ attr = elem.getAttributeNode("removeAttribute"); + test_attr(true, true); + attr = elem.getAttributeNode("tabIndex"); if(v < 8) test_attr(false, false);
Jacek Caban (@jacek) commented about dlls/mshtml/htmlattr.c:
BSTR name; nsresult nsres; HRESULT hres;
cpp_bool b;
TRACE("(%p)->(%p)\n", This, p);
if(This->node.nsnode) {
nsres = nsIDOMAttr_GetSpecified((nsIDOMAttr*)This->node.nsnode, &b);
Please avoid casts like this. The usual approach for similar node types is to store a member like `nsIDOMAttr *dom_attr` in `HTMLDOMAttribute`.
This change would also use better patch splitting. For instance, you could first introduce the `dom_attr` member and incrementally use it in places like this. Once those are updated, you could convert the object into a fully-fledged MSHTML node.
Also, those changes are not currently covered by tests. We could probably run `test_attr` from `dom.c` in IE11 or IE9 mode.
Jacek Caban (@jacek) commented about dlls/mshtml/htmlelem.c:
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;
- if(nsattr) {
LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) {
if(iter->node.nsnode == (nsIDOMNode*)nsattr) {
ret = iter;
break;
}
i++;
}
When you have `nsattr`, you could simply use `get_node()` to retrieve the corresponding `HTMLDOMAttribute`.
More generally, in standard compatibility modes, it would be nice if we could rely on mechanisms like this or `nsIDOMMozNamedAttrMap` for most tasks instead of using the list.
On Fri Dec 6 12:22:50 2024 +0000, Jacek Caban wrote:
Please avoid casts like this. The usual approach for similar node types is to store a member like `nsIDOMAttr *dom_attr` in `HTMLDOMAttribute`. This change would also use better patch splitting. For instance, you could first introduce the `dom_attr` member and incrementally use it in places like this. Once those are updated, you could convert the object into a fully-fledged MSHTML node. Also, those changes are not currently covered by tests. We could probably run `test_attr` from `dom.c` in IE11 or IE9 mode.
Won't splitting it introduce temporary regressions? Some of them will use gecko attributes, while the others will use mshtml attributes, and so will be out of sync?
On Fri Dec 6 16:25:59 2024 +0000, Gabriel Ivăncescu wrote:
Won't splitting it introduce temporary regressions? Some of them will use gecko attributes, while the others will use mshtml attributes, and so will be out of sync?
Looks like IHTMLDOMNode is not an exposed interface in IE9+ either, even though it utilizes the methods from the node prototype, what should I do? Should I just mark it todo_wine for now?
On Fri Dec 6 17:20:58 2024 +0000, Gabriel Ivăncescu wrote:
Looks like IHTMLDOMNode is not an exposed interface in IE9+ either, even though it utilizes the methods from the node prototype, what should I do? Should I just mark it todo_wine for now?
Maybe it could use a separate similar to how `HTMLEventObj` is not the same as `DOMEvent`. I don't know, sounds like it needs more testing.
On Fri Dec 6 17:36:22 2024 +0000, Jacek Caban wrote:
Maybe it could use a separate similar to how `HTMLEventObj` is not the same as `DOMEvent`. I don't know, sounds like it needs more testing.
Yeah but what I'm saying is that the node prototype methods called on Attribute Nodes will then fail, so we have to expose it for that.
On Fri Dec 6 12:22:51 2024 +0000, Jacek Caban wrote:
When you have `nsattr`, you could simply use `get_node()` to retrieve the corresponding `HTMLDOMAttribute`. More generally, in standard compatibility modes, it would be nice if we could rely on mechanisms like this or `nsIDOMMozNamedAttrMap` for most tasks instead of using the list.
Testing with dom.c makes it look like it's more complicated than that. It appears the builtin props are still in effect in most cases (although not all of them, for some reason), so I guess I need to rework this and probably not go fully with gecko nodes…