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, [