From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 100 ++++++++++++++++++++++- dlls/mshtml/tests/documentmode.js | 128 ++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 2d64e020cec..18f566e70ed 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -4845,8 +4845,42 @@ static HRESULT WINAPI HTMLElement6_getAttributeNS(IHTMLElement6 *iface, VARIANT static HRESULT WINAPI HTMLElement6_setAttributeNS(IHTMLElement6 *iface, VARIANT *pvarNS, BSTR strAttributeName, VARIANT *pvarAttributeValue) { HTMLElement *This = impl_from_IHTMLElement6(iface); - FIXME("(%p)->(%s %s %s)\n", This, debugstr_variant(pvarNS), debugstr_w(strAttributeName), debugstr_variant(pvarAttributeValue)); - return E_NOTIMPL; + nsAString ns_str, name_str, value_str; + const PRUnichar *ns; + nsresult nsres; + HRESULT hres; + + TRACE("(%p)->(%s %s %s)\n", This, debugstr_variant(pvarNS), debugstr_w(strAttributeName), debugstr_variant(pvarAttributeValue)); + + hres = variant_to_nsstr(pvarNS, FALSE, &ns_str); + if(FAILED(hres)) + return hres; + nsAString_GetData(&ns_str, &ns); + if((!ns || !ns[0]) && wcschr(strAttributeName, ':')) { + /* FIXME: Return NamespaceError */ + return E_FAIL; + } + + if(!This->dom_element) { + FIXME("No dom_element\n"); + nsAString_Finish(&ns_str); + return E_NOTIMPL; + } + + hres = variant_to_nsstr(pvarAttributeValue, FALSE, &value_str); + if(FAILED(hres)) { + nsAString_Finish(&ns_str); + return hres; + } + + nsAString_InitDepend(&name_str, strAttributeName); + nsres = nsIDOMElement_SetAttributeNS(This->dom_element, &ns_str, &name_str, &value_str); + nsAString_Finish(&ns_str); + nsAString_Finish(&name_str); + nsAString_Finish(&value_str); + if(NS_FAILED(nsres)) + WARN("SetAttributeNS failed: %08lx\n", nsres); + return map_nsresult(nsres); }
static HRESULT WINAPI HTMLElement6_removeAttributeNS(IHTMLElement6 *iface, VARIANT *pvarNS, BSTR strAttributeName) @@ -6845,6 +6879,61 @@ static HRESULT IHTMLElement6_getAttributeNS_hook(DispatchEx *dispex, WORD flags, return hres; }
+static HRESULT IHTMLElement6_setAttributeNS_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + BOOL ns_conv = FALSE, val_conv = FALSE; + VARIANT args[3]; + HRESULT hres; + DISPPARAMS new_dp = { args, NULL, 3, 0 }; + + if(!(flags & DISPATCH_METHOD) || dp->cArgs < 3 || dp->cNamedArgs) + return S_FALSE; + + if(dispex_compat_mode(dispex) < COMPAT_MODE_IE10) + args[2] = dp->rgvarg[dp->cArgs - 1]; + else { + switch(V_VT(&dp->rgvarg[dp->cArgs - 1])) { + case VT_EMPTY: + case VT_BSTR: + case VT_NULL: + args[2] = dp->rgvarg[dp->cArgs - 1]; + break; + default: + hres = change_type(&args[2], &dp->rgvarg[dp->cArgs - 1], VT_BSTR, caller); + if(FAILED(hres)) + return hres; + ns_conv = TRUE; + break; + } + } + + switch(V_VT(&dp->rgvarg[dp->cArgs - 3])) { + case VT_EMPTY: + case VT_BSTR: + case VT_NULL: + if(!ns_conv) + return S_FALSE; + args[0] = dp->rgvarg[dp->cArgs - 3]; + break; + default: + hres = change_type(&args[0], &dp->rgvarg[dp->cArgs - 3], VT_BSTR, caller); + if(FAILED(hres)) { + if(ns_conv) + VariantClear(&args[2]); + return hres; + } + val_conv = TRUE; + break; + } + + args[1] = dp->rgvarg[dp->cArgs - 2]; + hres = dispex_call_builtin(dispex, DISPID_IHTMLELEMENT6_SETATTRIBUTENS, &new_dp, res, ei, caller); + if(ns_conv) VariantClear(&args[2]); + if(val_conv) VariantClear(&args[0]); + return hres; +} + static HRESULT IHTMLElement6_setAttribute_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { @@ -6876,8 +6965,13 @@ static HRESULT IHTMLElement6_setAttribute_hook(DispatchEx *dispex, WORD flags, D
void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { + static const dispex_hook_t elem6_ie9_hooks[] = { + {DISPID_IHTMLELEMENT6_SETATTRIBUTENS, IHTMLElement6_setAttributeNS_hook}, + {DISPID_UNKNOWN} + }; static const dispex_hook_t elem6_ie10_hooks[] = { {DISPID_IHTMLELEMENT6_GETATTRIBUTENS, IHTMLElement6_getAttributeNS_hook}, + {DISPID_IHTMLELEMENT6_SETATTRIBUTENS, IHTMLElement6_setAttributeNS_hook}, {DISPID_IHTMLELEMENT6_IE9_SETATTRIBUTE, IHTMLElement6_setAttribute_hook}, {DISPID_UNKNOWN} }; @@ -6895,7 +6989,7 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) dispex_info_add_interface(info, IElementSelector_tid, NULL);
if(mode >= COMPAT_MODE_IE9) { - dispex_info_add_interface(info, IHTMLElement6_tid, mode >= COMPAT_MODE_IE10 ? elem6_ie10_hooks : NULL); + dispex_info_add_interface(info, IHTMLElement6_tid, mode >= COMPAT_MODE_IE10 ? elem6_ie10_hooks : elem6_ie9_hooks); dispex_info_add_interface(info, IElementTraversal_tid, NULL); }
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 299d46e5727..9e7c3ac1d9d 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1408,6 +1408,134 @@ sync_test("elem_attr", function() { } });
+sync_test("elem_attrNS", function() { + var v = document.documentMode; + if(v < 9) return; /* not available */ + + var specialspace_ns = "http://www.mozilla.org/ns/specialspace"; + var svg_ns = "http://www.w3.org/2000/svg"; + + var elem = document.createElement("div"), r; + + elem.setAttributeNS(specialspace_ns, "spec:align", "left"); + r = elem.getAttribute("spec:align"); + ok(r === "left", "spec:align = " + r); + r = elem.getAttribute("align"); + ok(r === null, "align = " + r); + r = elem.getAttributeNS(null, "spec:align"); + ok(r === "", "null spec:align = " + r); + r = elem.getAttributeNS(null, "align"); + ok(r === "", "null align = " + r); + r = elem.getAttributeNS(svg_ns, "spec:align"); + ok(r === "", "svg spec:align = " + r); + r = elem.getAttributeNS(svg_ns, "align"); + ok(r === "", "svg align = " + r); + r = elem.getAttributeNS(specialspace_ns, "spec:align"); + ok(r === "", "specialspace spec:align = " + r); + r = elem.getAttributeNS(specialspace_ns, "align"); + ok(r === "left", "specialspace align = " + r); + + try { + elem.setAttributeNS(null, "spec:align", "right"); + ok(false, "expected exception setting qualified attr with null ns"); + }catch(ex) { + todo_wine. + ok(ex.message === "NamespaceError", "setAttributeNS(null, 'spec:align', 'right') threw " + ex.message); + } + try { + elem.setAttributeNS("", "spec:align", "right"); + ok(false, "expected exception setting qualified attr with empty ns"); + }catch(ex) { + todo_wine. + ok(ex.message === "NamespaceError", "setAttributeNS('', 'spec:align', 'right') threw " + ex.message); + } + elem.setAttributeNS(null, "align", "right"); + r = elem.getAttribute("spec:align"); + ok(r === "left", "spec:align (null) = " + r); + r = elem.getAttribute("align"); + ok(r === "right", "align (null) = " + r); + r = elem.getAttributeNS(null, "spec:align"); + ok(r === "", "null spec:align (null) = " + r); + r = elem.getAttributeNS(null, "align"); + ok(r === "right", "null align (null) = " + r); + r = elem.getAttributeNS(svg_ns, "spec:align"); + ok(r === "", "svg spec:align (null) = " + r); + r = elem.getAttributeNS(svg_ns, "align"); + ok(r === "", "svg align (null) = " + r); + r = elem.getAttributeNS(specialspace_ns, "spec:align"); + ok(r === "", "specialspace spec:align (null) = " + r); + r = elem.getAttributeNS(specialspace_ns, "align"); + ok(r === "left", "specialspace align (null) = " + r); + + elem.setAttribute("align", "center"); + r = elem.getAttributeNS(null, "spec:align"); + ok(r === "", "null spec:align (non-NS) = " + r); + r = elem.getAttributeNS(null, "align"); + ok(r === "center", "null align (non-NS) = " + r); + r = elem.getAttributeNS(svg_ns, "spec:align"); + ok(r === "", "svg spec:align (non-NS) = " + r); + r = elem.getAttributeNS(svg_ns, "align"); + ok(r === "", "svg align (non-NS) = " + r); + r = elem.getAttributeNS(specialspace_ns, "spec:align"); + ok(r === "", "specialspace spec:align (non-NS) = " + r); + r = elem.getAttributeNS(specialspace_ns, "align"); + ok(r === "left", "specialspace align (non-NS) = " + r); + + elem.setAttribute("emptynsattr", "none"); + elem.setAttributeNS("", "emptynsattr", "test"); + r = elem.getAttribute("emptynsattr"); + ok(r === "test", "emptynsattr without NS = " + r); + elem.setAttributeNS(null, "emptynsattr", "wine"); + r = elem.getAttribute("emptynsattr"); + ok(r === "wine", "emptynsattr without NS = " + r); + elem.setAttributeNS(specialspace_ns, "emptynsattr", "ns"); + r = elem.getAttribute("emptynsattr"); + ok(r === "wine", "emptynsattr without NS = " + r); + r = elem.getAttributeNS("", "emptynsattr"); + ok(r === "wine", "emptynsattr empty ns = " + r); + r = elem.getAttributeNS(null, "emptynsattr"); + ok(r === "wine", "emptynsattr null ns = " + r); + r = elem.getAttributeNS(specialspace_ns, "emptynsattr"); + ok(r === "ns", "emptynsattr specialspace ns = " + r); + + var ns = {}; + ns.toString = function() { return "toString namespace"; } + ns.valueOf = function() { return "valueOf namespace"; } + elem.setAttributeNS(ns, "foobar", "test"); + r = elem.getAttribute("foobar"); + ok(r === "test", "foobar without NS = " + r); + r = elem.getAttributeNS(ns, "foobar"); + ok(r === "test", "foobar = " + r); + r = elem.getAttributeNS("toString namespace", "foobar"); + ok(r === (v < 10 ? "" : "test"), "foobar (toString namespace) = " + r); + r = elem.getAttributeNS("valueOf namespace", "foobar"); + ok(r === (v < 10 ? "test" : ""), "foobar (valueOf namespace) = " + r); + + var arr = [3]; + elem.setAttributeNS(svg_ns, "testattr", arr); + r = elem.getAttributeNS(svg_ns, "testattr"); + ok(r === "3", "testattr = " + r); + ok(elem.testattr === undefined, "elem.testattr = " + elem.testattr); + + arr.toString = function() { return 42; } + elem.setAttributeNS(svg_ns, "testattr", arr); + r = elem.getAttributeNS(svg_ns, "testattr"); + ok(r === "42", "testattr with custom toString = " + r); + + arr.valueOf = function() { return "arrval"; } + elem.setAttributeNS(svg_ns, "testattr", arr); + r = elem.getAttributeNS(svg_ns, "testattr"); + ok(r === "42", "testattr with custom valueOf = " + r); + + elem.setAttributeNS(svg_ns, "boolattr", true); + r = elem.getAttributeNS(svg_ns, "boolattr"); + ok(r === "true", "boolattr = " + r); + + elem.setAttributeNS(svg_ns, "numattr", 13); + r = elem.getAttributeNS(svg_ns, "numattr"); + ok(r === "13", "numattr = " + r); +}); + sync_test("builtins_diffs", function() { var v = document.documentMode;