mshtml: Implement enumerator for HTMLAttributeCollection.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
201cc01d72
commit
1c4e53dbce
|
@ -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);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
IHTMLDOMAttribute_Release(dom_attr);
|
||||
SysFreeString(name);
|
||||
VariantClear(&val);
|
||||
}
|
||||
ok(checked==5, "invalid number of specified attributes (%ld)\n", checked);
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue