Functions declared as function statements have an associated local_ref and can be changed from within themselves by using their name (by literally changing the local variable), while function expressions can not.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/engine.c | 6 ++++-- dlls/mshtml/tests/es5.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index c483f2a..73b9d86 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -587,7 +587,8 @@ static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_ scope->obj = to_disp(scope->jsobj); }
- if (scope == frame->base_scope && func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5) + if (scope == frame->base_scope && func->name && func->local_ref == INVALID_LOCAL_REF && + ctx->version >= SCRIPTLANGUAGEVERSION_ES5) jsdisp_propput_name(scope->jsobj, func->name, jsval_obj(jsdisp_addref(frame->function_instance)));
index = scope->scope_index; @@ -716,7 +717,8 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re }
/* ECMA-262 5.1 Edition 13 */ - if(func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && !wcscmp(identifier, func->name)) { + if(func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && + func->local_ref == INVALID_LOCAL_REF && !wcscmp(identifier, func->name)) { TRACE("returning a function from scope chain\n"); ret->type = EXPRVAL_JSVAL; ret->u.val = jsval_obj(jsdisp_addref(scope->frame->function_instance)); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index e8ee713..43a6ce7 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1691,6 +1691,34 @@ sync_test("functions scope", function() { func_outer(o); func(); ok(ret === o, "ret != o"); + + func_outer = function g() { + var g2 = g; + g = 10; + ok(g !== 10, "g was redefined to 10"); + g = function() {}; + ok(g === g2, "g !== g2: " + g); + } + func_outer(); + + function h() { + h = 1; + ok(h === 1, "h was not redefined: " + h); + } + h(); + ok(h === 1, "h = " + h); + + function h2() { return function() { h2 = 2; }; } + h2()(); + ok(h2 === 2, "h2 = " + h2); + + (function e() { + var f = e; + ok(typeof(f) === "function", "f = " + f); + (function () { e = 1; })(); + e = 2; + ok(f === e, "f != e"); + })(); });
sync_test("console", function() {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlstylesheet.c | 152 ++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/dom.c | 27 +++++++ 2 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index 2d16f4a..2d76e37 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -50,6 +50,15 @@ struct HTMLStyleSheetsCollection { nsIDOMStyleSheetList *nslist; };
+typedef struct { + IEnumVARIANT IEnumVARIANT_iface; + + LONG ref; + + ULONG iter; + HTMLStyleSheetsCollection *col; +} HTMLStyleSheetsCollectionEnum; + struct HTMLStyleSheetRulesCollection { DispatchEx dispex; IHTMLStyleSheetRulesCollection IHTMLStyleSheetRulesCollection_iface; @@ -479,6 +488,130 @@ static HRESULT create_style_sheet_rules_collection(nsIDOMCSSRuleList *nslist, co return S_OK; }
+static inline HTMLStyleSheetsCollectionEnum *HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, HTMLStyleSheetsCollectionEnum, IEnumVARIANT_iface); +} + +static HRESULT WINAPI HTMLStyleSheetsCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_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 HTMLStyleSheetsCollectionEnum_AddRef(IEnumVARIANT *iface) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI HTMLStyleSheetsCollectionEnum_Release(IEnumVARIANT *iface) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + IHTMLStyleSheetsCollection_Release(&This->col->IHTMLStyleSheetsCollection_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI HTMLStyleSheetsCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(iface); + VARIANT index; + HRESULT hres; + ULONG num, i; + UINT32 len; + + TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); + + nsIDOMStyleSheetList_GetLength(This->col->nslist, &len); + num = min(len - This->iter, celt); + V_VT(&index) = VT_I4; + + for(i = 0; i < num; i++) { + V_I4(&index) = This->iter + i; + hres = IHTMLStyleSheetsCollection_item(&This->col->IHTMLStyleSheetsCollection_iface, &index, &rgVar[i]); + if(FAILED(hres)) { + while(i--) + VariantClear(&rgVar[i]); + return hres; + } + } + + This->iter += num; + if(pCeltFetched) + *pCeltFetched = num; + return num == celt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI HTMLStyleSheetsCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(iface); + UINT32 len; + + TRACE("(%p)->(%lu)\n", This, celt); + + nsIDOMStyleSheetList_GetLength(This->col->nslist, &len); + if(This->iter + celt > len) { + This->iter = len; + return S_FALSE; + } + + This->iter += celt; + return S_OK; +} + +static HRESULT WINAPI HTMLStyleSheetsCollectionEnum_Reset(IEnumVARIANT *iface) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(iface); + + TRACE("(%p)->()\n", This); + + This->iter = 0; + return S_OK; +} + +static HRESULT WINAPI HTMLStyleSheetsCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + HTMLStyleSheetsCollectionEnum *This = HTMLStyleSheetsCollectionEnum_from_IEnumVARIANT(iface); + FIXME("(%p)->(%p)\n", This, ppEnum); + return E_NOTIMPL; +} + +static const IEnumVARIANTVtbl HTMLStyleSheetsCollectionEnumVtbl = { + HTMLStyleSheetsCollectionEnum_QueryInterface, + HTMLStyleSheetsCollectionEnum_AddRef, + HTMLStyleSheetsCollectionEnum_Release, + HTMLStyleSheetsCollectionEnum_Next, + HTMLStyleSheetsCollectionEnum_Skip, + HTMLStyleSheetsCollectionEnum_Reset, + HTMLStyleSheetsCollectionEnum_Clone +}; + static inline HTMLStyleSheetsCollection *impl_from_IHTMLStyleSheetsCollection(IHTMLStyleSheetsCollection *iface) { return CONTAINING_RECORD(iface, HTMLStyleSheetsCollection, IHTMLStyleSheetsCollection_iface); @@ -586,8 +719,23 @@ static HRESULT WINAPI HTMLStyleSheetsCollection_get__newEnum(IHTMLStyleSheetsCol IUnknown **p) { HTMLStyleSheetsCollection *This = impl_from_IHTMLStyleSheetsCollection(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLStyleSheetsCollectionEnum *ret; + + TRACE("(%p)->(%p)\n", This, p); + + ret = heap_alloc(sizeof(*ret)); + if(!ret) + return E_OUTOFMEMORY; + + ret->IEnumVARIANT_iface.lpVtbl = &HTMLStyleSheetsCollectionEnumVtbl; + ret->ref = 1; + ret->iter = 0; + + HTMLStyleSheetsCollection_AddRef(&This->IHTMLStyleSheetsCollection_iface); + ret->col = This; + + *p = (IUnknown*)&ret->IEnumVARIANT_iface; + return S_OK; }
static HRESULT WINAPI HTMLStyleSheetsCollection_item(IHTMLStyleSheetsCollection *iface, diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 4af0e9b..73b9831 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -8577,7 +8577,10 @@ static void test_stylesheet(IDispatch *disp) static void test_stylesheets(IHTMLDocument2 *doc) { IHTMLStyleSheetsCollection *col = NULL; + IEnumVARIANT *enum_var; + IUnknown *enum_unk; VARIANT idx, res; + ULONG fetched; LONG len = 0; HRESULT hres;
@@ -8611,6 +8614,30 @@ static void test_stylesheets(IHTMLDocument2 *doc) ok(V_VT(&res) == VT_EMPTY, "V_VT(res) = %d\n", V_VT(&res)); VariantClear(&res);
+ hres = IHTMLStyleSheetsCollection_get__newEnum(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); + + fetched = 0; + V_VT(&res) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &res, &fetched); + ok(hres == S_OK, "Next failed: %08lx\n", hres); + ok(fetched == 1, "fetched = %lu\n", fetched); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(res) = %d\n", V_VT(&res)); + ok(V_DISPATCH(&res) != NULL, "V_DISPATCH(&res) == NULL\n"); + test_disp2((IUnknown*)V_DISPATCH(&res), &DIID_DispHTMLStyleSheet, &IID_IHTMLStyleSheet, NULL, L"[object]"); + VariantClear(&res); + + fetched = 0; + V_VT(&res) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &res, &fetched); + ok(hres == S_FALSE, "Next failed: %08lx\n", hres); + ok(fetched == 0, "fetched = %lu\n", fetched); + IEnumVARIANT_Release(enum_var); + IHTMLStyleSheetsCollection_Release(col); }
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 152 +++++++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/dom.c | 27 +++++++ 2 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 47c1827..9ed2249 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -781,6 +781,139 @@ typedef struct { nsIDOMClientRectList *rect_list; } HTMLRectCollection;
+typedef struct { + IEnumVARIANT IEnumVARIANT_iface; + + LONG ref; + + ULONG iter; + HTMLRectCollection *col; +} HTMLRectCollectionEnum; + +static inline HTMLRectCollectionEnum *HTMLRectCollectionEnum_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, HTMLRectCollectionEnum, IEnumVARIANT_iface); +} + +static HRESULT WINAPI HTMLRectCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_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 HTMLRectCollectionEnum_AddRef(IEnumVARIANT *iface) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_from_IEnumVARIANT(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI HTMLRectCollectionEnum_Release(IEnumVARIANT *iface) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_from_IEnumVARIANT(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + IHTMLRectCollection_Release(&This->col->IHTMLRectCollection_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI HTMLRectCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_from_IEnumVARIANT(iface); + VARIANT index; + HRESULT hres; + ULONG num, i; + UINT32 len; + + TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); + + nsIDOMClientRectList_GetLength(This->col->rect_list, &len); + num = min(len - This->iter, celt); + V_VT(&index) = VT_I4; + + for(i = 0; i < num; i++) { + V_I4(&index) = This->iter + i; + hres = IHTMLRectCollection_item(&This->col->IHTMLRectCollection_iface, &index, &rgVar[i]); + if(FAILED(hres)) { + while(i--) + VariantClear(&rgVar[i]); + return hres; + } + } + + This->iter += num; + if(pCeltFetched) + *pCeltFetched = num; + return num == celt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI HTMLRectCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_from_IEnumVARIANT(iface); + UINT32 len; + + TRACE("(%p)->(%lu)\n", This, celt); + + nsIDOMClientRectList_GetLength(This->col->rect_list, &len); + if(This->iter + celt > len) { + This->iter = len; + return S_FALSE; + } + + This->iter += celt; + return S_OK; +} + +static HRESULT WINAPI HTMLRectCollectionEnum_Reset(IEnumVARIANT *iface) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_from_IEnumVARIANT(iface); + + TRACE("(%p)->()\n", This); + + This->iter = 0; + return S_OK; +} + +static HRESULT WINAPI HTMLRectCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + HTMLRectCollectionEnum *This = HTMLRectCollectionEnum_from_IEnumVARIANT(iface); + FIXME("(%p)->(%p)\n", This, ppEnum); + return E_NOTIMPL; +} + +static const IEnumVARIANTVtbl HTMLRectCollectionEnumVtbl = { + HTMLRectCollectionEnum_QueryInterface, + HTMLRectCollectionEnum_AddRef, + HTMLRectCollectionEnum_Release, + HTMLRectCollectionEnum_Next, + HTMLRectCollectionEnum_Skip, + HTMLRectCollectionEnum_Reset, + HTMLRectCollectionEnum_Clone +}; + static inline HTMLRectCollection *impl_from_IHTMLRectCollection(IHTMLRectCollection *iface) { return CONTAINING_RECORD(iface, HTMLRectCollection, IHTMLRectCollection_iface); @@ -883,8 +1016,23 @@ static HRESULT WINAPI HTMLRectCollection_get_length(IHTMLRectCollection *iface, static HRESULT WINAPI HTMLRectCollection_get__newEnum(IHTMLRectCollection *iface, IUnknown **p) { HTMLRectCollection *This = impl_from_IHTMLRectCollection(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLRectCollectionEnum *ret; + + TRACE("(%p)->(%p)\n", This, p); + + ret = heap_alloc(sizeof(*ret)); + if(!ret) + return E_OUTOFMEMORY; + + ret->IEnumVARIANT_iface.lpVtbl = &HTMLRectCollectionEnumVtbl; + ret->ref = 1; + ret->iter = 0; + + HTMLRectCollection_AddRef(&This->IHTMLRectCollection_iface); + ret->col = This; + + *p = (IUnknown*)&ret->IEnumVARIANT_iface; + return S_OK; }
static HRESULT WINAPI HTMLRectCollection_item(IHTMLRectCollection *iface, VARIANT *index, VARIANT *result) diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 73b9831..00c1577 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -5229,8 +5229,11 @@ static void test_elem_bounding_client_rect(IUnknown *unk) { IHTMLRectCollection *rects; IHTMLRect *rect, *rect2; + IEnumVARIANT *enum_var; IHTMLElement2 *elem2; + IUnknown *enum_unk; VARIANT v, index; + ULONG fetched; LONG l; HRESULT hres;
@@ -5285,6 +5288,30 @@ static void test_elem_bounding_client_rect(IUnknown *unk) test_disp((IUnknown*)V_DISPATCH(&v), &IID_IHTMLRect, NULL, L"[object]"); VariantClear(&v);
+ hres = IHTMLRectCollection_get__newEnum(rects, &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); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_OK, "Next failed: %08lx\n", hres); + ok(fetched == 1, "fetched = %lu\n", fetched); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) == NULL\n"); + test_disp((IUnknown*)V_DISPATCH(&v), &IID_IHTMLRect, NULL, L"[object]"); + VariantClear(&v); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_FALSE, "Next failed: %08lx\n", hres); + ok(fetched == 0, "fetched = %lu\n", fetched); + IEnumVARIANT_Release(enum_var); + IHTMLRectCollection_Release(rects); IHTMLElement2_Release(elem2); }
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlform.c | 157 +++++++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/dom.c | 39 +++++++++- 2 files changed, 193 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 45ff19a..18b56ae 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -41,6 +41,15 @@ struct HTMLFormElement { nsIDOMHTMLFormElement *nsform; };
+typedef struct { + IEnumVARIANT IEnumVARIANT_iface; + + LONG ref; + + ULONG iter; + HTMLFormElement *elem; +} HTMLFormElementEnum; + HRESULT return_nsform(nsresult nsres, nsIDOMHTMLFormElement *form, IHTMLFormElement **p) { nsIDOMNode *form_node; @@ -108,6 +117,135 @@ static HRESULT htmlform_item(HTMLFormElement *This, int i, IDispatch **ret) return S_OK; }
+static inline HTMLFormElementEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, HTMLFormElementEnum, IEnumVARIANT_iface); +} + +static HRESULT WINAPI HTMLFormElementEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + HTMLFormElementEnum *This = impl_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 HTMLFormElementEnum_AddRef(IEnumVARIANT *iface) +{ + HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI HTMLFormElementEnum_Release(IEnumVARIANT *iface) +{ + HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + IHTMLFormElement_Release(&This->elem->IHTMLFormElement_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI HTMLFormElementEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface); + nsresult nsres; + HRESULT hres; + ULONG num, i; + LONG len; + + TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); + + nsres = nsIDOMHTMLFormElement_GetLength(This->elem->nsform, &len); + if(NS_FAILED(nsres)) + return E_FAIL; + num = min(len - This->iter, celt); + + for(i = 0; i < num; i++) { + hres = htmlform_item(This->elem, This->iter + i, &V_DISPATCH(&rgVar[i])); + if(FAILED(hres)) { + while(i--) + VariantClear(&rgVar[i]); + return hres; + } + V_VT(&rgVar[i]) = VT_DISPATCH; + } + + This->iter += num; + if(pCeltFetched) + *pCeltFetched = num; + return num == celt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI HTMLFormElementEnum_Skip(IEnumVARIANT *iface, ULONG celt) +{ + HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface); + nsresult nsres; + LONG len; + + TRACE("(%p)->(%lu)\n", This, celt); + + nsres = nsIDOMHTMLFormElement_GetLength(This->elem->nsform, &len); + if(NS_FAILED(nsres)) + return E_FAIL; + + if(This->iter + celt > len) { + This->iter = len; + return S_FALSE; + } + + This->iter += celt; + return S_OK; +} + +static HRESULT WINAPI HTMLFormElementEnum_Reset(IEnumVARIANT *iface) +{ + HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface); + + TRACE("(%p)->()\n", This); + + This->iter = 0; + return S_OK; +} + +static HRESULT WINAPI HTMLFormElementEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface); + FIXME("(%p)->(%p)\n", This, ppEnum); + return E_NOTIMPL; +} + +static const IEnumVARIANTVtbl HTMLFormElementEnumVtbl = { + HTMLFormElementEnum_QueryInterface, + HTMLFormElementEnum_AddRef, + HTMLFormElementEnum_Release, + HTMLFormElementEnum_Next, + HTMLFormElementEnum_Skip, + HTMLFormElementEnum_Reset, + HTMLFormElementEnum_Clone +}; + static inline HTMLFormElement *impl_from_IHTMLFormElement(IHTMLFormElement *iface) { return CONTAINING_RECORD(iface, HTMLFormElement, IHTMLFormElement_iface); @@ -545,8 +683,23 @@ static HRESULT WINAPI HTMLFormElement_get_length(IHTMLFormElement *iface, LONG * static HRESULT WINAPI HTMLFormElement__newEnum(IHTMLFormElement *iface, IUnknown **p) { HTMLFormElement *This = impl_from_IHTMLFormElement(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLFormElementEnum *ret; + + TRACE("(%p)->(%p)\n", This, p); + + ret = heap_alloc(sizeof(*ret)); + if(!ret) + return E_OUTOFMEMORY; + + ret->IEnumVARIANT_iface.lpVtbl = &HTMLFormElementEnumVtbl; + ret->ref = 1; + ret->iter = 0; + + HTMLFormElement_AddRef(&This->IHTMLFormElement_iface); + ret->elem = This; + + *p = (IUnknown*)&ret->IEnumVARIANT_iface; + return S_OK; }
static HRESULT WINAPI HTMLFormElement_item(IHTMLFormElement *iface, VARIANT name, diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 00c1577..bd4b772 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -5504,7 +5504,10 @@ static void test_form_item(IHTMLElement *elem) { IHTMLFormElement *form = get_form_iface((IUnknown*)elem); IDispatch *disp, *disp2; - VARIANT name, index; + IEnumVARIANT *enum_var; + VARIANT name, index, v; + IUnknown *enum_unk; + ULONG fetched; HRESULT hres;
V_VT(&index) = VT_EMPTY; @@ -5543,6 +5546,40 @@ static void test_form_item(IHTMLElement *elem) ok(iface_cmp((IUnknown*)disp, (IUnknown*)disp2), "disp != disp2\n"); IDispatch_Release(disp2); IDispatch_Release(disp); + + hres = IHTMLFormElement_get__newEnum(form, &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); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_OK, "Next failed: %08lx\n", hres); + ok(fetched == 1, "fetched = %lu\n", fetched); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) == NULL\n"); + test_disp((IUnknown*)V_DISPATCH(&v), &DIID_DispHTMLTextAreaElement, &CLSID_HTMLTextAreaElement, NULL); + VariantClear(&v); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_OK, "Next failed: %08lx\n", hres); + ok(fetched == 1, "fetched = %lu\n", fetched); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) == NULL\n"); + test_disp((IUnknown*)V_DISPATCH(&v), &DIID_DispHTMLInputElement, &CLSID_HTMLInputElement, NULL); + VariantClear(&v); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_FALSE, "Next failed: %08lx\n", hres); + ok(fetched == 0, "fetched = %lu\n", fetched); + IEnumVARIANT_Release(enum_var); }
static void test_create_option_elem(IHTMLDocument2 *doc)
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlselect.c | 157 ++++++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/dom.c | 39 +++++++++- 2 files changed, 193 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 44981a5..ae6543a 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -674,6 +674,15 @@ struct HTMLSelectElement { nsIDOMHTMLSelectElement *nsselect; };
+typedef struct { + IEnumVARIANT IEnumVARIANT_iface; + + LONG ref; + + ULONG iter; + HTMLSelectElement *elem; +} HTMLSelectElementEnum; + static inline HTMLSelectElement *impl_from_IHTMLSelectElement(IHTMLSelectElement *iface) { return CONTAINING_RECORD(iface, HTMLSelectElement, IHTMLSelectElement_iface); @@ -714,6 +723,135 @@ static HRESULT htmlselect_item(HTMLSelectElement *This, int i, IDispatch **ret) return S_OK; }
+static inline HTMLSelectElementEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, HTMLSelectElementEnum, IEnumVARIANT_iface); +} + +static HRESULT WINAPI HTMLSelectElementEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + HTMLSelectElementEnum *This = impl_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 HTMLSelectElementEnum_AddRef(IEnumVARIANT *iface) +{ + HTMLSelectElementEnum *This = impl_from_IEnumVARIANT(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI HTMLSelectElementEnum_Release(IEnumVARIANT *iface) +{ + HTMLSelectElementEnum *This = impl_from_IEnumVARIANT(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + IHTMLSelectElement_Release(&This->elem->IHTMLSelectElement_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI HTMLSelectElementEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + HTMLSelectElementEnum *This = impl_from_IEnumVARIANT(iface); + nsresult nsres; + HRESULT hres; + ULONG num, i; + UINT32 len; + + TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); + + nsres = nsIDOMHTMLSelectElement_GetLength(This->elem->nsselect, &len); + if(NS_FAILED(nsres)) + return E_FAIL; + num = min(len - This->iter, celt); + + for(i = 0; i < num; i++) { + hres = htmlselect_item(This->elem, This->iter + i, &V_DISPATCH(&rgVar[i])); + if(FAILED(hres)) { + while(i--) + VariantClear(&rgVar[i]); + return hres; + } + V_VT(&rgVar[i]) = VT_DISPATCH; + } + + This->iter += num; + if(pCeltFetched) + *pCeltFetched = num; + return num == celt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI HTMLSelectElementEnum_Skip(IEnumVARIANT *iface, ULONG celt) +{ + HTMLSelectElementEnum *This = impl_from_IEnumVARIANT(iface); + nsresult nsres; + UINT32 len; + + TRACE("(%p)->(%lu)\n", This, celt); + + nsres = nsIDOMHTMLSelectElement_GetLength(This->elem->nsselect, &len); + if(NS_FAILED(nsres)) + return E_FAIL; + + if(This->iter + celt > len) { + This->iter = len; + return S_FALSE; + } + + This->iter += celt; + return S_OK; +} + +static HRESULT WINAPI HTMLSelectElementEnum_Reset(IEnumVARIANT *iface) +{ + HTMLSelectElementEnum *This = impl_from_IEnumVARIANT(iface); + + TRACE("(%p)->()\n", This); + + This->iter = 0; + return S_OK; +} + +static HRESULT WINAPI HTMLSelectElementEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + HTMLSelectElementEnum *This = impl_from_IEnumVARIANT(iface); + FIXME("(%p)->(%p)\n", This, ppEnum); + return E_NOTIMPL; +} + +static const IEnumVARIANTVtbl HTMLSelectElementEnumVtbl = { + HTMLSelectElementEnum_QueryInterface, + HTMLSelectElementEnum_AddRef, + HTMLSelectElementEnum_Release, + HTMLSelectElementEnum_Next, + HTMLSelectElementEnum_Skip, + HTMLSelectElementEnum_Reset, + HTMLSelectElementEnum_Clone +}; + static HRESULT WINAPI HTMLSelectElement_QueryInterface(IHTMLSelectElement *iface, REFIID riid, void **ppv) { @@ -1117,8 +1255,23 @@ static HRESULT WINAPI HTMLSelectElement_get_length(IHTMLSelectElement *iface, LO static HRESULT WINAPI HTMLSelectElement_get__newEnum(IHTMLSelectElement *iface, IUnknown **p) { HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLSelectElementEnum *ret; + + TRACE("(%p)->(%p)\n", This, p); + + ret = heap_alloc(sizeof(*ret)); + if(!ret) + return E_OUTOFMEMORY; + + ret->IEnumVARIANT_iface.lpVtbl = &HTMLSelectElementEnumVtbl; + ret->ref = 1; + ret->iter = 0; + + HTMLSelectElement_AddRef(&This->IHTMLSelectElement_iface); + ret->elem = This; + + *p = (IUnknown*)&ret->IEnumVARIANT_iface; + return S_OK; }
static HRESULT WINAPI HTMLSelectElement_item(IHTMLSelectElement *iface, VARIANT name, diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index bd4b772..0f5120a 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -5425,7 +5425,10 @@ static IHTMLElement *get_doc_elem_by_id(IHTMLDocument2 *doc, const WCHAR *id) static void test_select_elem(IHTMLSelectElement *select) { IDispatch *disp, *disp2; - VARIANT name, index; + VARIANT name, index, v; + IEnumVARIANT *enum_var; + IUnknown *enum_unk; + ULONG fetched; HRESULT hres;
test_select_type(select, L"select-one"); @@ -5495,6 +5498,40 @@ static void test_select_elem(IHTMLSelectElement *select) IDispatch_Release(disp2); IDispatch_Release(disp);
+ hres = IHTMLSelectElement_get__newEnum(select, &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); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_OK, "Next failed: %08lx\n", hres); + ok(fetched == 1, "fetched = %lu\n", fetched); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) == NULL\n"); + test_disp((IUnknown*)V_DISPATCH(&v), &DIID_DispHTMLOptionElement, &CLSID_HTMLOptionElement, NULL); + VariantClear(&v); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_OK, "Next failed: %08lx\n", hres); + ok(fetched == 1, "fetched = %lu\n", fetched); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) == NULL\n"); + test_disp((IUnknown*)V_DISPATCH(&v), &DIID_DispHTMLOptionElement, &CLSID_HTMLOptionElement, NULL); + VariantClear(&v); + + fetched = 0; + V_VT(&v) = VT_ERROR; + hres = IEnumVARIANT_Next(enum_var, 1, &v, &fetched); + ok(hres == S_FALSE, "Next failed: %08lx\n", hres); + ok(fetched == 0, "fetched = %lu\n", fetched); + IEnumVARIANT_Release(enum_var); + test_select_multiple(select, VARIANT_FALSE); test_select_set_multiple(select, VARIANT_TRUE); test_select_remove(select);
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
So that they don't have to be forward declared in next patch.
dlls/mshtml/htmlelem.c | 176 ++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 88 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 9ed2249..ea5c65b 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -7578,6 +7578,94 @@ 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) +{ + IDispatchEx *dispex = &This->elem->node.event_target.dispex.IDispatchEx_iface; + DISPID id = DISPID_STARTENUM; + LONG len = -1; + HRESULT hres; + + FIXME("filter non-enumerable attributes out\n"); + + while(1) { + hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, id, &id); + if(FAILED(hres)) + return hres; + else if(hres == S_FALSE) + break; + + len++; + if(len == *idx) + break; + } + + if(dispid) { + *dispid = id; + return *idx==len ? S_OK : DISP_E_UNKNOWNNAME; + } + + *idx = len+1; + return S_OK; +} + +static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BSTR name, DISPID *id) +{ + HRESULT hres; + + if(name[0]>='0' && name[0]<='9') { + WCHAR *end_ptr; + LONG idx; + + idx = wcstoul(name, &end_ptr, 10); + if(!*end_ptr) { + hres = get_attr_dispid_by_idx(This, &idx, id); + if(SUCCEEDED(hres)) + return hres; + } + } + + if(!This->elem) { + WARN("NULL elem\n"); + return E_UNEXPECTED; + } + + hres = IDispatchEx_GetDispID(&This->elem->node.event_target.dispex.IDispatchEx_iface, + name, fdexNameCaseInsensitive, id); + return hres; +} + +static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) +{ + HTMLDOMAttribute *iter; + LONG pos = 0; + HRESULT hres; + + *attr = NULL; + LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) { + if(iter->dispid == id) { + *attr = iter; + break; + } + pos++; + } + + if(!*attr) { + if(!This->elem) { + WARN("NULL elem\n"); + return E_UNEXPECTED; + } + + hres = HTMLDOMAttribute_Create(NULL, This->elem, id, dispex_compat_mode(&This->elem->node.event_target.dispex), attr); + if(FAILED(hres)) + return hres; + } + + IHTMLDOMAttribute_AddRef(&(*attr)->IHTMLDOMAttribute_iface); + if(list_pos) + *list_pos = pos; + return S_OK; +} + /* interface IHTMLAttributeCollection */ static inline HTMLAttributeCollection *impl_from_IHTMLAttributeCollection(IHTMLAttributeCollection *iface) { @@ -7672,94 +7760,6 @@ static HRESULT WINAPI HTMLAttributeCollection_Invoke(IHTMLAttributeCollection *i wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); }
-static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid) -{ - IDispatchEx *dispex = &This->elem->node.event_target.dispex.IDispatchEx_iface; - DISPID id = DISPID_STARTENUM; - LONG len = -1; - HRESULT hres; - - FIXME("filter non-enumerable attributes out\n"); - - while(1) { - hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, id, &id); - if(FAILED(hres)) - return hres; - else if(hres == S_FALSE) - break; - - len++; - if(len == *idx) - break; - } - - if(dispid) { - *dispid = id; - return *idx==len ? S_OK : DISP_E_UNKNOWNNAME; - } - - *idx = len+1; - return S_OK; -} - -static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BSTR name, DISPID *id) -{ - HRESULT hres; - - if(name[0]>='0' && name[0]<='9') { - WCHAR *end_ptr; - LONG idx; - - idx = wcstoul(name, &end_ptr, 10); - if(!*end_ptr) { - hres = get_attr_dispid_by_idx(This, &idx, id); - if(SUCCEEDED(hres)) - return hres; - } - } - - if(!This->elem) { - WARN("NULL elem\n"); - return E_UNEXPECTED; - } - - hres = IDispatchEx_GetDispID(&This->elem->node.event_target.dispex.IDispatchEx_iface, - name, fdexNameCaseInsensitive, id); - return hres; -} - -static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) -{ - HTMLDOMAttribute *iter; - LONG pos = 0; - HRESULT hres; - - *attr = NULL; - LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) { - if(iter->dispid == id) { - *attr = iter; - break; - } - pos++; - } - - if(!*attr) { - if(!This->elem) { - WARN("NULL elem\n"); - return E_UNEXPECTED; - } - - hres = HTMLDOMAttribute_Create(NULL, This->elem, id, dispex_compat_mode(&This->elem->node.event_target.dispex), attr); - if(FAILED(hres)) - return hres; - } - - IHTMLDOMAttribute_AddRef(&(*attr)->IHTMLDOMAttribute_iface); - if(list_pos) - *list_pos = pos; - return S_OK; -} - static HRESULT WINAPI HTMLAttributeCollection_get_length(IHTMLAttributeCollection *iface, LONG *p) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Cache the current iterator's DISPID and obtain the next one relatively from it to avoid excessively iterating through them from the beginning, on every single element obtained.
dlls/mshtml/htmlelem.c | 183 +++++++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/dom.c | 133 ++++++++++++++++++----------- 2 files changed, 265 insertions(+), 51 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index ea5c65b..d911d0a 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -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) diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 0f5120a..1b1e677 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -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);
Signed-off-by: Jacek Caban jacek@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=112512
Your paranoid android.
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS