Jacek Caban : mshtml: Added IHTMLElement4:: setAttributeNode implementation.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Mar 30 10:00:31 CDT 2016


Module: wine
Branch: master
Commit: 17fcc112ade167e602dc46981e8239b3ce576b51
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=17fcc112ade167e602dc46981e8239b3ce576b51

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Mar 30 14:39:57 2016 +0200

mshtml: Added IHTMLElement4::setAttributeNode implementation.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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);
 }
 




More information about the wine-cvs mailing list