Commit 1c4e53db authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

mshtml: Implement enumerator for HTMLAttributeCollection.

parent 201cc01d
......@@ -7578,10 +7578,10 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters
return S_OK;
}
static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid)
static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, DISPID *dispid)
{
IDispatchEx *dispex = &This->elem->node.event_target.dispex.IDispatchEx_iface;
DISPID id = DISPID_STARTENUM;
DISPID id = start;
LONG len = -1;
HRESULT hres;
......@@ -7608,6 +7608,11 @@ static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx,
return S_OK;
}
static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid)
{
return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid);
}
static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BSTR name, DISPID *id)
{
HRESULT hres;
......@@ -7666,6 +7671,160 @@ static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG
return S_OK;
}
typedef struct {
IEnumVARIANT IEnumVARIANT_iface;
LONG ref;
ULONG iter;
DISPID iter_dispid;
HTMLAttributeCollection *col;
} HTMLAttributeCollectionEnum;
static inline HTMLAttributeCollectionEnum *HTMLAttributeCollectionEnum_from_IEnumVARIANT(IEnumVARIANT *iface)
{
return CONTAINING_RECORD(iface, HTMLAttributeCollectionEnum, IEnumVARIANT_iface);
}
static HRESULT WINAPI HTMLAttributeCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
if(IsEqualGUID(riid, &IID_IUnknown)) {
*ppv = &This->IEnumVARIANT_iface;
}else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
*ppv = &This->IEnumVARIANT_iface;
}else {
FIXME("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
static ULONG WINAPI HTMLAttributeCollectionEnum_AddRef(IEnumVARIANT *iface)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%ld\n", This, ref);
return ref;
}
static ULONG WINAPI HTMLAttributeCollectionEnum_Release(IEnumVARIANT *iface)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%ld\n", This, ref);
if(!ref) {
IHTMLAttributeCollection_Release(&This->col->IHTMLAttributeCollection_iface);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI HTMLAttributeCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
DISPID tmp, dispid = This->iter_dispid;
HTMLDOMAttribute *attr;
LONG rel_index = 0;
HRESULT hres;
ULONG i;
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);
if(SUCCEEDED(hres)) {
dispid = tmp;
hres = get_domattr(This->col, dispid, NULL, &attr);
}
else if(hres == DISP_E_UNKNOWNNAME)
break;
if(FAILED(hres)) {
while(i--)
VariantClear(&rgVar[i]);
return hres;
}
V_VT(&rgVar[i]) = VT_DISPATCH;
V_DISPATCH(&rgVar[i]) = (IDispatch*)&attr->IHTMLDOMAttribute_iface;
}
This->iter += i;
This->iter_dispid = dispid;
if(pCeltFetched)
*pCeltFetched = i;
return i == celt ? S_OK : S_FALSE;
}
static HRESULT WINAPI HTMLAttributeCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
LONG remaining, rel_index;
DISPID dispid;
HRESULT hres;
TRACE("(%p)->(%lu)\n", This, celt);
if(!celt)
return S_OK;
rel_index = -1;
hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, 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);
if(FAILED(hres))
return hres;
This->iter += remaining;
This->iter_dispid = dispid;
}
return celt > remaining ? S_FALSE : S_OK;
}
static HRESULT WINAPI HTMLAttributeCollectionEnum_Reset(IEnumVARIANT *iface)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
TRACE("(%p)->()\n", This);
This->iter = 0;
This->iter_dispid = DISPID_STARTENUM;
return S_OK;
}
static HRESULT WINAPI HTMLAttributeCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
{
HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface);
FIXME("(%p)->(%p)\n", This, ppEnum);
return E_NOTIMPL;
}
static const IEnumVARIANTVtbl HTMLAttributeCollectionEnumVtbl = {
HTMLAttributeCollectionEnum_QueryInterface,
HTMLAttributeCollectionEnum_AddRef,
HTMLAttributeCollectionEnum_Release,
HTMLAttributeCollectionEnum_Next,
HTMLAttributeCollectionEnum_Skip,
HTMLAttributeCollectionEnum_Reset,
HTMLAttributeCollectionEnum_Clone
};
/* interface IHTMLAttributeCollection */
static inline HTMLAttributeCollection *impl_from_IHTMLAttributeCollection(IHTMLAttributeCollection *iface)
{
......@@ -7775,8 +7934,24 @@ static HRESULT WINAPI HTMLAttributeCollection_get_length(IHTMLAttributeCollectio
static HRESULT WINAPI HTMLAttributeCollection__newEnum(IHTMLAttributeCollection *iface, IUnknown **p)
{
HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
FIXME("(%p)->(%p)\n", This, p);
return E_NOTIMPL;
HTMLAttributeCollectionEnum *ret;
TRACE("(%p)->(%p)\n", This, p);
ret = heap_alloc(sizeof(*ret));
if(!ret)
return E_OUTOFMEMORY;
ret->IEnumVARIANT_iface.lpVtbl = &HTMLAttributeCollectionEnumVtbl;
ret->ref = 1;
ret->iter = 0;
ret->iter_dispid = DISPID_STARTENUM;
HTMLAttributeCollection_AddRef(&This->IHTMLAttributeCollection_iface);
ret->col = This;
*p = (IUnknown*)&ret->IEnumVARIANT_iface;
return S_OK;
}
static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *iface, VARIANT *name, IDispatch **ppItem)
......
......@@ -3636,6 +3636,61 @@ static void _test_attr_parent(unsigned line, IHTMLDOMAttribute *attr)
IHTMLDOMAttribute2_Release(attr2);
}
static LONG test_attr_collection_attr(IDispatch *attr, LONG i)
{
IHTMLDOMAttribute *dom_attr;
LONG ret = 1;
HRESULT hres;
VARIANT val;
BSTR name;
hres = IDispatch_QueryInterface(attr, &IID_IHTMLDOMAttribute, (void**)&dom_attr);
ok(hres == S_OK, "%ld) QueryInterface failed: %08lx\n", i, hres);
hres = IHTMLDOMAttribute_get_nodeName(dom_attr, &name);
ok(hres == S_OK, "%ld) get_nodeName failed: %08lx\n", i, hres);
if(!lstrcmpW(name, L"id")) {
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "id: V_VT(&val) = %d\n", V_VT(&val));
ok(!lstrcmpW(V_BSTR(&val), L"attr"), "id: V_BSTR(&val) = %s\n", wine_dbgstr_w(V_BSTR(&val)));
test_attr_expando(dom_attr, VARIANT_FALSE);
test_attr_value(dom_attr, L"attr");
} else if(!lstrcmpW(name, L"attr1")) {
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "attr1: V_VT(&val) = %d\n", V_VT(&val));
ok(!lstrcmpW(V_BSTR(&val), L"attr1"), "attr1: V_BSTR(&val) = %s\n", wine_dbgstr_w(V_BSTR(&val)));
test_attr_expando(dom_attr, VARIANT_TRUE);
test_attr_value(dom_attr, L"attr1");
} else if(!lstrcmpW(name, L"attr2")) {
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "attr2: V_VT(&val) = %d\n", V_VT(&val));
ok(!V_BSTR(&val), "attr2: V_BSTR(&val) != NULL\n");
test_attr_value(dom_attr, L"");
} else if(!lstrcmpW(name, L"attr3")) {
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "attr3: V_VT(&val) = %d\n", V_VT(&val));
ok(!lstrcmpW(V_BSTR(&val), L"attr3"), "attr3: V_BSTR(&val) = %s\n", wine_dbgstr_w(V_BSTR(&val)));
test_attr_value(dom_attr, L"attr3");
} else if(!lstrcmpW(name, L"test")) {
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_I4, "test: V_VT(&val) = %d\n", V_VT(&val));
ok(V_I4(&val) == 1, "test: V_I4(&val) = %ld\n", V_I4(&val));
test_attr_value(dom_attr, L"1");
} else
ret = 0;
IHTMLDOMAttribute_Release(dom_attr);
SysFreeString(name);
VariantClear(&val);
return ret;
}
static void test_attr_collection_disp(IDispatch *disp)
{
IDispatchEx *dispex;
......@@ -3689,11 +3744,13 @@ static void test_attr_collection(IHTMLElement *elem)
IHTMLDOMNode *node;
IDispatch *disp, *attr;
IHTMLDOMAttribute *dom_attr;
IHTMLAttributeCollection *attr_col;
BSTR name = SysAllocString(testW);
IEnumVARIANT *enum_var;
IUnknown *enum_unk;
VARIANT id, val;
LONG i, len, checked;
ULONG fetched;
HRESULT hres;
hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLDOMNode, (void**)&node);
......@@ -3724,6 +3781,13 @@ static void test_attr_collection(IHTMLElement *elem)
ok(hres == S_OK, "get_length failed: %08lx\n", hres);
ok(len == i+1, "get_length returned %ld, expected %ld\n", len, i+1);
hres = IHTMLAttributeCollection_get__newEnum(attr_col, &enum_unk);
ok(hres == S_OK, "_newEnum failed: %08lx\n", hres);
hres = IUnknown_QueryInterface(enum_unk, &IID_IEnumVARIANT, (void**)&enum_var);
IUnknown_Release(enum_unk);
ok(hres == S_OK, "Could not get IEnumVARIANT iface: %08lx\n", hres);
checked = 0;
for(i=0; i<len; i++) {
V_VT(&id) = VT_I4;
......@@ -3731,58 +3795,33 @@ static void test_attr_collection(IHTMLElement *elem)
hres = IHTMLAttributeCollection_item(attr_col, &id, &attr);
ok(hres == S_OK, "%ld) item failed: %08lx\n", i, hres);
hres = IDispatch_QueryInterface(attr, &IID_IHTMLDOMAttribute, (void**)&dom_attr);
ok(hres == S_OK, "%ld) QueryInterface failed: %08lx\n", i, hres);
checked += test_attr_collection_attr(attr, i);
IDispatch_Release(attr);
}
ok(checked==5, "invalid number of specified attributes (%ld)\n", checked);
hres = IHTMLDOMAttribute_get_nodeName(dom_attr, &name);
ok(hres == S_OK, "%ld) get_nodeName failed: %08lx\n", i, hres);
if(!lstrcmpW(name, L"id")) {
checked++;
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "id: V_VT(&val) = %d\n", V_VT(&val));
ok(!lstrcmpW(V_BSTR(&val), L"attr"), "id: V_BSTR(&val) = %s\n", wine_dbgstr_w(V_BSTR(&val)));
test_attr_expando(dom_attr, VARIANT_FALSE);
test_attr_value(dom_attr, L"attr");
} else if(!lstrcmpW(name, L"attr1")) {
checked++;
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "attr1: V_VT(&val) = %d\n", V_VT(&val));
ok(!lstrcmpW(V_BSTR(&val), L"attr1"), "attr1: V_BSTR(&val) = %s\n", wine_dbgstr_w(V_BSTR(&val)));
test_attr_expando(dom_attr, VARIANT_TRUE);
test_attr_value(dom_attr, L"attr1");
} else if(!lstrcmpW(name, L"attr2")) {
checked++;
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "attr2: V_VT(&val) = %d\n", V_VT(&val));
ok(!V_BSTR(&val), "attr2: V_BSTR(&val) != NULL\n");
test_attr_value(dom_attr, L"");
} else if(!lstrcmpW(name, L"attr3")) {
checked++;
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_BSTR, "attr3: V_VT(&val) = %d\n", V_VT(&val));
ok(!lstrcmpW(V_BSTR(&val), L"attr3"), "attr3: V_BSTR(&val) = %s\n", wine_dbgstr_w(V_BSTR(&val)));
test_attr_value(dom_attr, L"attr3");
} else if(!lstrcmpW(name, L"test")) {
checked++;
hres = IHTMLDOMAttribute_get_nodeValue(dom_attr, &val);
ok(hres == S_OK, "%ld) get_nodeValue failed: %08lx\n", i, hres);
ok(V_VT(&val) == VT_I4, "test: V_VT(&val) = %d\n", V_VT(&val));
ok(V_I4(&val) == 1, "test: V_I4(&val) = %ld\n", V_I4(&val));
test_attr_value(dom_attr, L"1");
}
checked = 0;
for(i=0; i<len; i++) {
fetched = 0;
V_VT(&val) = VT_ERROR;
hres = IEnumVARIANT_Next(enum_var, 1, &val, &fetched);
ok(hres == S_OK, "Next failed: %08lx\n", hres);
ok(fetched == 1, "fetched = %lu\n", fetched);
ok(V_VT(&val) == VT_DISPATCH, "V_VT(val) = %d\n", V_VT(&val));
ok(V_DISPATCH(&val) != NULL, "V_DISPATCH(&val) == NULL\n");
IHTMLDOMAttribute_Release(dom_attr);
SysFreeString(name);
VariantClear(&val);
checked += test_attr_collection_attr(V_DISPATCH(&val), i);
IDispatch_Release(V_DISPATCH(&val));
}
ok(checked==5, "invalid number of specified attributes (%ld)\n", checked);
fetched = 0;
V_VT(&val) = VT_ERROR;
hres = IEnumVARIANT_Next(enum_var, 1, &val, &fetched);
ok(hres == S_FALSE, "Next failed: %08lx\n", hres);
ok(fetched == 0, "fetched = %lu\n", fetched);
IEnumVARIANT_Release(enum_var);
V_I4(&id) = len;
hres = IHTMLAttributeCollection_item(attr_col, &id, &attr);
ok(hres == E_INVALIDARG, "item failed: %08lx\n", hres);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment