From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 65 +++++++++++++++++----------- dlls/mshtml/tests/dom.c | 95 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 130 insertions(+), 30 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 621bc705da3..b3ebfbb4007 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -47,6 +47,8 @@ typedef struct { } tag_desc_t;
static HRESULT HTMLElement_Ctor(HTMLDocumentNode*,nsIDOMElement*,HTMLElement**); +static HRESULT get_attr_dispid_by_name(HTMLAttributeCollection*,const WCHAR*,BOOL,DISPID*); +static HRESULT get_domattr(HTMLAttributeCollection*,DISPID,LONG*,HTMLDOMAttribute**);
static const tag_desc_t tag_descs[] = { {L"A", HTMLAnchorElement_Create}, @@ -4717,21 +4719,28 @@ static HRESULT WINAPI HTMLElement6_removeAttribute(IHTMLElement6 *iface, BSTR st static HRESULT WINAPI HTMLElement6_getAttributeNode(IHTMLElement6 *iface, BSTR strAttributeName, IHTMLDOMAttribute2 **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement6(iface); - IHTMLDOMAttribute *attr; + HTMLAttributeCollection *attrs; + HTMLDOMAttribute *attr; HRESULT hres; + DISPID id;
- WARN("(%p)->(%s %p) forwarding to IHTMLElement4\n", This, debugstr_w(strAttributeName), ppretAttribute); + TRACE("(%p)->(%s %p)\n", This, debugstr_w(strAttributeName), ppretAttribute);
- hres = IHTMLElement4_getAttributeNode(&This->IHTMLElement4_iface, strAttributeName, &attr); + hres = HTMLElement_get_attr_col(&This->node, &attrs); if(FAILED(hres)) return hres;
- if(attr) { - hres = IHTMLDOMAttribute_QueryInterface(attr, &IID_IHTMLDOMAttribute2, (void**)ppretAttribute); - IHTMLDOMAttribute_Release(attr); - }else { + hres = get_attr_dispid_by_name(attrs, strAttributeName, TRUE, &id); + if(hres == S_OK) { + hres = get_domattr(attrs, id, NULL, &attr); + if(hres == S_OK) + *ppretAttribute = &attr->IHTMLDOMAttribute2_iface; + }else if(hres == DISP_E_UNKNOWNNAME) { *ppretAttribute = NULL; + hres = S_OK; } + + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); return hres; }
@@ -7677,7 +7686,7 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters return S_OK; }
-static inline BOOL is_valid_attr_dispid(DISPID id) +static inline BOOL is_valid_attr_dispid(HTMLAttributeCollection *col, DISPID id, BOOL specified_only) { /* Builtin props that can be treated as attributes; MUST be sorted by underlying dispid value. */ static const DISPID attr_dispids[] = { @@ -7815,8 +7824,11 @@ static inline BOOL is_valid_attr_dispid(DISPID id)
while(a < b) { i = (a + b) / 2; - if(id == attr_dispids[i]) + if(id == attr_dispids[i]) { + if(specified_only) + return !!element_has_attribute(col->elem, dispex_builtin_prop_name(&col->elem->node.event_target.dispex, id)); return TRUE; + } if(id <= attr_dispids[i]) b = i; else a = i + 1; } @@ -7824,7 +7836,8 @@ static inline BOOL is_valid_attr_dispid(DISPID id) return FALSE; }
-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, + BOOL specified_only, DISPID *dispid) { DISPID id = start; LONG len = -1; @@ -7838,7 +7851,7 @@ static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LO return hres; else if(hres == S_FALSE) break; - else if(!is_valid_attr_dispid(id)) + else if(!is_valid_attr_dispid(This, id, specified_only)) continue;
len++; @@ -7855,12 +7868,12 @@ 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, BOOL specified_only, DISPID *dispid) { - return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid); + return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, specified_only, dispid); }
-static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHAR *name, DISPID *id) +static HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, const WCHAR *name, BOOL specified_only, DISPID *id) { HRESULT hres;
@@ -7870,17 +7883,17 @@ 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, specified_only, id); if(SUCCEEDED(hres)) return hres; } }
hres = dispex_get_id(&This->elem->node.event_target.dispex, name, fdexNameCaseInsensitive, id); - return (FAILED(hres) || is_valid_attr_dispid(*id)) ? hres : DISP_E_UNKNOWNNAME; + return (FAILED(hres) || is_valid_attr_dispid(This, *id, specified_only)) ? hres : DISP_E_UNKNOWNNAME; }
-static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) +static HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) { HTMLDOMAttribute *iter; LONG pos = 0; @@ -7978,7 +7991,7 @@ 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); + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, dispid, FALSE, &tmp); if(SUCCEEDED(hres)) { dispid = tmp; hres = get_domattr(This->col, dispid, NULL, &attr); @@ -8015,14 +8028,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, FALSE, 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, FALSE, &dispid); if(FAILED(hres)) return hres; This->iter_dispid = dispid; @@ -8074,7 +8087,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, FALSE, NULL); return hres; }
@@ -8111,10 +8124,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), FALSE, &id); 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), FALSE, &id); break; default: FIXME("unsupported name %s\n", debugstr_variant(name)); @@ -8164,7 +8177,7 @@ static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollec
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, FALSE, &id); if(hres == DISP_E_UNKNOWNNAME) { *newretNode = NULL; return S_OK; @@ -8249,7 +8262,7 @@ static HRESULT WINAPI HTMLAttributeCollection3_item(IHTMLAttributeCollection3 *i
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, FALSE, &id); if(hres == DISP_E_UNKNOWNNAME) return E_INVALIDARG; if(FAILED(hres)) @@ -8345,7 +8358,7 @@ static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, const WCHA
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, FALSE, dispid); if(FAILED(hres)) return hres;
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index b67ed183d67..d696902423d 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -2088,10 +2088,10 @@ static void _test_comment_text(unsigned line, IUnknown *unk, const WCHAR *extext }
#define create_attr(a,b) _create_attr(__LINE__,a,b) -static IHTMLDOMAttribute *_create_attr(unsigned line, IUnknown *unk, const char *name) +static IHTMLDOMAttribute *_create_attr(unsigned line, IUnknown *unk, const WCHAR *name) { IHTMLDocument5 *doc = _get_htmldoc5_iface(line, unk); - BSTR str = SysAllocString(L"Test"); + BSTR str = SysAllocString(name); IHTMLDOMAttribute *attr; HRESULT hres;
@@ -5176,6 +5176,78 @@ static IHTMLDOMAttribute *_get_elem_attr_node(unsigned line, IUnknown *unk, cons return attr; }
+#define get_elem6_attr_node(a,b,c) _get_elem6_attr_node(__LINE__,a,b,c) +static IHTMLDOMAttribute *_get_elem6_attr_node(unsigned line, IUnknown *unk, const WCHAR *attr_name, BOOL expect_success) +{ + BSTR str = SysAllocString(attr_name); + IHTMLDOMAttribute2 *attr2; + IHTMLDOMAttribute *attr; + IHTMLElement6 *elem; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement6, (void**)&elem); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLElement6: %08lx\n", hres); + + attr = (void*)0xdeadbeef; + hres = IHTMLElement6_getAttributeNode(elem, str, &attr2); + ok_(__FILE__,line)(hres == S_OK, "getAttributeNode failed: %08lx\n", hres); + if(expect_success) { + ok_(__FILE__,line)(attr2 != NULL, "attr = NULL\n"); + hres = IHTMLDOMAttribute2_QueryInterface(attr2, &IID_IHTMLDOMAttribute, (void**)&attr); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLDOMAttribute: %08lx\n", hres); + IHTMLDOMAttribute2_Release(attr2); + }else { + ok_(__FILE__,line)(!attr2, "attr = %p\n", attr2); + attr = NULL; + } + + IHTMLElement6_Release(elem); + SysFreeString(str); + return attr; +} + +#define get_elem_attr_node_via_disp(a,b,c) _get_elem_attr_node_via_disp(__LINE__,a,b,c) +static IHTMLDOMAttribute *_get_elem_attr_node_via_disp(unsigned line, IUnknown *unk, const WCHAR *attr_name, BOOL expect_success) +{ + IHTMLDOMAttribute *attr = NULL; + DISPPARAMS dp = { 0 }; + IDispatchEx *dispex; + VARIANT var, arg; + EXCEPINFO ei; + HRESULT hres; + DISPID id; + BSTR str; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line)(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + str = SysAllocString(L"getAttributeNode"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id); + ok_(__FILE__,line)(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(str); + + dp.cArgs = 1; + dp.rgvarg = &arg; + V_VT(&arg) = VT_BSTR; + V_BSTR(&arg) = SysAllocString(attr_name); + + VariantInit(&var); + hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, DISPATCH_METHOD, &dp, &var, &ei, NULL); + ok_(__FILE__,line)(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + if(!expect_success) + ok_(__FILE__,line)(V_VT(&var) == VT_NULL, "V_VT(var) = %d\n", V_VT(&var)); + else { + ok_(__FILE__,line)(V_VT(&var) == VT_DISPATCH, "V_VT(var) = %d\n", V_VT(&var)); + ok_(__FILE__,line)(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLDOMAttribute, (void**)&attr); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLDOMAttribute: %08lx\n", hres); + } + IDispatchEx_Release(dispex); + VariantClear(&arg); + VariantClear(&var); + return attr; +} + #define get_attr_node_value(a,b,c) _get_attr_node_value(__LINE__,a,b,c) static void _get_attr_node_value(unsigned line, IHTMLDOMAttribute *attr, VARIANT *v, VARTYPE vt) { @@ -10214,9 +10286,14 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_attr_specified(attr, has_attr ? VARIANT_TRUE : VARIANT_FALSE); test_attr_expando(attr, VARIANT_FALSE); IHTMLDOMAttribute_Release(attr); + attr = get_elem6_attr_node((IUnknown*)elem, elem_attr_props[i], has_attr); + if(attr) IHTMLDOMAttribute_Release(attr); + attr = get_elem_attr_node_via_disp((IUnknown*)elem, elem_attr_props[i], TRUE); + if(attr) IHTMLDOMAttribute_Release(attr); } for(i = 0; i < ARRAY_SIZE(elem_noattr_props); i++) { get_elem_attr_node((IUnknown*)elem, elem_noattr_props[i], FALSE); + get_elem6_attr_node((IUnknown*)elem, elem_noattr_props[i], FALSE); }
ok(elem_has_attr((IUnknown*)elem, L"emptyattr"), "elem does not have emptyattr"); @@ -10226,8 +10303,18 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) test_attr_node(attr, doc); IHTMLDOMAttribute_Release(attr);
+ attr = get_elem6_attr_node((IUnknown*)elem, L"emptyattr", TRUE); + test_attr_specified(attr, VARIANT_TRUE); + test_attr_expando(attr, VARIANT_TRUE); + IHTMLDOMAttribute_Release(attr); + + attr = get_elem_attr_node_via_disp((IUnknown*)elem, L"emptyattr", TRUE); + test_attr_specified(attr, VARIANT_TRUE); + test_attr_expando(attr, VARIANT_TRUE); + IHTMLDOMAttribute_Release(attr); + /* Test created, detached attribute. */ - attr = create_attr((IUnknown*)doc, "Test"); + attr = create_attr((IUnknown*)doc, L"Test");
test_disp((IUnknown*)attr, &DIID_DispHTMLDOMAttribute, NULL, L"[object]"); test_ifaces((IUnknown*)attr, attr_iids); @@ -10270,7 +10357,7 @@ static void test_attr(IHTMLDocument2 *doc, IHTMLElement *elem) ok(iface_cmp((IUnknown*)attr2, (IUnknown*)attr), "attr2 != attr\n"); IHTMLDOMAttribute_Release(attr2);
- attr3 = create_attr((IUnknown*)doc, "Test"); + attr3 = create_attr((IUnknown*)doc, L"Test"); put_attr_value(attr3, L"replace test");
hres = IHTMLElement4_setAttributeNode(elem4, attr3, &attr2);