Module: wine
Branch: master
Commit: 17fcc112ade167e602dc46981e8239b3ce576b51
URL:
http://source.winehq.org/git/wine.git/?a=commit;h=17fcc112ade167e602dc46981…
Author: Jacek Caban <jacek(a)codeweavers.com>
Date: Wed Mar 30 14:39:57 2016 +0200
mshtml: Added IHTMLElement4::setAttributeNode implementation.
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard(a)winehq.org>
---
dlls/mshtml/htmlattr.c | 5 +++
dlls/mshtml/htmlelem.c | 96 ++++++++++++++++++++++++++++++++++++--------
dlls/mshtml/mshtml_private.h | 7 +++-
dlls/mshtml/tests/dom.c | 55 ++++++++++++++++++++++++-
4 files changed, 143 insertions(+), 20 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c
index 7a11245..e994eec 100644
--- a/dlls/mshtml/htmlattr.c
+++ b/dlls/mshtml/htmlattr.c
@@ -491,6 +491,11 @@ static dispex_static_data_t HTMLDOMAttribute_dispex = {
HTMLDOMAttribute_iface_tids
};
+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,
HTMLDOMAttribute **attr)
{
HTMLAttributeCollection *col;
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c
index c7090e6..0329f1b 100644
--- a/dlls/mshtml/htmlelem.c
+++ b/dlls/mshtml/htmlelem.c
@@ -612,14 +612,27 @@ static HRESULT WINAPI HTMLElement_Invoke(IHTMLElement *iface, DISPID
dispIdMembe
wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
+static HRESULT set_elem_attr_value_by_dispid(HTMLElement *elem, DISPID dispid, VARIANT
*v)
+{
+ DISPID propput_dispid = DISPID_PROPERTYPUT;
+ DISPPARAMS dp = {v, &propput_dispid, 1, 1};
+ EXCEPINFO ei;
+
+ if(dispid == DISPID_IHTMLELEMENT_STYLE) {
+ TRACE("Ignoring call on style attribute\n");
+ return S_OK;
+ }
+
+ return IDispatchEx_InvokeEx(&elem->node.event_target.dispex.IDispatchEx_iface,
dispid,
+ LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, NULL);
+}
+
static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR
strAttributeName,
VARIANT AttributeValue, LONG lFlags)
{
HTMLElement *This = impl_from_IHTMLElement(iface);
+ DISPID dispid;
HRESULT hres;
- DISPID dispid, dispidNamed = DISPID_PROPERTYPUT;
- DISPPARAMS dispParams;
- EXCEPINFO excep;
TRACE("(%p)->(%s %s %08x)\n", This, debugstr_w(strAttributeName),
debugstr_variant(&AttributeValue), lFlags);
@@ -628,18 +641,7 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface,
BSTR strAttr
if(FAILED(hres))
return hres;
- if(dispid == DISPID_IHTMLELEMENT_STYLE) {
- TRACE("Ignoring call on style attribute\n");
- return S_OK;
- }
-
- dispParams.cArgs = 1;
- dispParams.cNamedArgs = 1;
- dispParams.rgdispidNamedArgs = &dispidNamed;
- dispParams.rgvarg = &AttributeValue;
-
- return IDispatchEx_InvokeEx(&This->node.event_target.dispex.IDispatchEx_iface,
dispid,
- LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dispParams, NULL,
&excep, NULL);
+ return set_elem_attr_value_by_dispid(This, dispid, &AttributeValue);
}
HRESULT get_elem_attr_value_by_dispid(HTMLElement *elem, DISPID dispid, VARIANT *ret)
@@ -3718,8 +3720,68 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4
*iface, IHTMLD
IHTMLDOMAttribute **ppretAttribute)
{
HTMLElement *This = impl_from_IHTMLElement4(iface);
- FIXME("(%p)->(%p %p)\n", This, pattr, ppretAttribute);
- return E_NOTIMPL;
+ HTMLDOMAttribute *attr, *iter, *replace = NULL;
+ HTMLAttributeCollection *attrs;
+ DISPID dispid;
+ HRESULT hres;
+
+ TRACE("(%p)->(%p %p)\n", This, pattr, ppretAttribute);
+
+ attr = unsafe_impl_from_IHTMLDOMAttribute(pattr);
+ if(!attr)
+ return E_INVALIDARG;
+
+ if(attr->elem) {
+ WARN("Tried to set already attached attribute.\n");
+ return E_INVALIDARG;
+ }
+
+ hres =
IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface,
+ attr->name, fdexNameCaseInsensitive|fdexNameEnsure, &dispid);
+ if(FAILED(hres))
+ return hres;
+
+ hres = HTMLElement_get_attr_col(&This->node, &attrs);
+ if(FAILED(hres))
+ return hres;
+
+ LIST_FOR_EACH_ENTRY(iter, &attrs->attrs, HTMLDOMAttribute, entry) {
+ if(iter->dispid == dispid) {
+ replace = iter;
+ break;
+ }
+ }
+
+ if(replace) {
+ hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value);
+ if(FAILED(hres)) {
+ WARN("could not get attr value: %08x\n", hres);
+ V_VT(&replace->value) = VT_EMPTY;
+ }
+ if(!replace->name) {
+ replace->name = attr->name;
+ attr->name = NULL;
+ }
+ list_add_head(&replace->entry, &attr->entry);
+ list_remove(&replace->entry);
+ replace->elem = NULL;
+ }else {
+ list_add_tail(&attrs->attrs, &attr->entry);
+ }
+
+ IHTMLDOMAttribute_AddRef(&attr->IHTMLDOMAttribute_iface);
+ attr->elem = This;
+ attr->dispid = dispid;
+
+ 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: %08x\n", hres);
+ VariantClear(&attr->value);
+
+ *ppretAttribute = replace ? &replace->IHTMLDOMAttribute_iface : NULL;
+ return S_OK;
}
static HRESULT WINAPI HTMLElement4_removeAttributeNode(IHTMLElement4 *iface,
IHTMLDOMAttribute *pattr,
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 611cb8b..37c33d5 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -943,15 +943,18 @@ typedef struct {
LONG ref;
- /* name and value are valid only for detached attributes (when elem == NULL). */
- WCHAR *name;
+ /* value is valid only for detached attributes (when elem == NULL). */
VARIANT value;
+ /* name must be valid for detached attributes */
+ WCHAR *name;
HTMLElement *elem;
DISPID dispid;
struct list entry;
} HTMLDOMAttribute;
+HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute*)
DECLSPEC_HIDDEN;
+
HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLElement*,DISPID,HTMLDOMAttribute**)
DECLSPEC_HIDDEN;
HRESULT HTMLElement_Create(HTMLDocumentNode*,nsIDOMNode*,BOOL,HTMLElement**)
DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c
index 6d6a1e8..dcff793 100644
--- a/dlls/mshtml/tests/dom.c
+++ b/dlls/mshtml/tests/dom.c
@@ -8524,8 +8524,10 @@ static void test_elems(IHTMLDocument2 *doc)
static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem)
{
- IHTMLDOMAttribute *attr, *attr2;
+ IHTMLDOMAttribute *attr, *attr2, *attr3;
+ IHTMLElement4 *elem4;
VARIANT v;
+ HRESULT hres;
get_elem_attr_node((IUnknown*)elem, "noattr", FALSE);
@@ -8636,6 +8638,57 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem)
SysFreeString(V_BSTR(&v));
test_attr_value(attr, "testing");
+ elem4 = get_elem4_iface((IUnknown*)elem);
+
+ hres = IHTMLElement4_setAttributeNode(elem4, attr, &attr2);
+ ok(hres == S_OK, "setAttributeNode failed: %08x\n", hres);
+ ok(!attr2, "attr2 != NULL\n");
+
+ test_elem_attr(elem, "Test", "testing");
+ put_attr_value(attr, "new value");
+ test_elem_attr(elem, "Test", "new value");
+
+ attr2 = get_elem_attr_node((IUnknown*)elem, "Test", TRUE);
+ ok(iface_cmp((IUnknown*)attr2, (IUnknown*)attr), "attr2 != attr\n");
+ IHTMLDOMAttribute_Release(attr2);
+
+ attr3 = create_attr((IUnknown*)doc, "Test");
+ put_attr_value(attr3, "replace test");
+
+ hres = IHTMLElement4_setAttributeNode(elem4, attr3, &attr2);
+ ok(hres == S_OK, "setAttributeNode failed: %08x\n", hres);
+ ok(iface_cmp((IUnknown*)attr2, (IUnknown*)attr), "attr2 != attr\n");
+ IHTMLDOMAttribute_Release(attr2);
+
+ test_elem_attr(elem, "Test", "replace test");
+ test_attr_value(attr, "new value");
+ test_attr_value(attr3, "replace test");
+
+ attr2 = get_elem_attr_node((IUnknown*)elem, "Test", TRUE);
+ ok(iface_cmp((IUnknown*)attr2, (IUnknown*)attr3), "attr2 != attr3\n");
+ IHTMLDOMAttribute_Release(attr2);
+
+ put_attr_value(attr, "new value2");
+ test_elem_attr(elem, "Test", "replace test");
+ test_attr_value(attr, "new value2");
+ test_attr_value(attr3, "replace test");
+
+ put_attr_value(attr3, "new replace value");
+ test_elem_attr(elem, "Test", "new replace value");
+ test_attr_value(attr, "new value2");
+ test_attr_value(attr3, "new replace value");
+
+ /* Attached attributes cause errors. */
+ hres = IHTMLElement4_setAttributeNode(elem4, attr3, &attr2);
+ ok(hres == E_INVALIDARG, "setAttributeNode failed: %08x, expected
E_INVALIDARG\n", hres);
+ IHTMLDOMAttribute_Release(attr3);
+
+ attr2 = get_elem_attr_node((IUnknown*)elem, "id", TRUE);
+ hres = IHTMLElement4_setAttributeNode(elem4, attr2, &attr3);
+ ok(hres == E_INVALIDARG, "setAttributeNode failed: %08x, expected
E_INVALIDARG\n", hres);
+ IHTMLDOMAttribute_Release(attr2);
+
+ IHTMLElement4_Release(elem4);
IHTMLDOMAttribute_Release(attr);
}