ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / mshtml / htmlelemcol.c
blob385bd9038b2b8686dce7e0bac75bc6af5d74d3f2
1 /*
2 * Copyright 2006-2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34 typedef struct {
35 DispatchEx dispex;
36 IHTMLElementCollection IHTMLElementCollection_iface;
38 HTMLElement **elems;
39 DWORD len;
41 LONG ref;
42 } HTMLElementCollection;
44 typedef struct {
45 IEnumVARIANT IEnumVARIANT_iface;
47 LONG ref;
49 ULONG iter;
50 HTMLElementCollection *col;
51 } HTMLElementCollectionEnum;
53 typedef struct {
54 HTMLElement **buf;
55 DWORD len;
56 DWORD size;
57 } elem_vector_t;
59 /* FIXME: Handle it better way */
60 static inline HTMLElement *elem_from_HTMLDOMNode(HTMLDOMNode *iface)
62 return CONTAINING_RECORD(iface, HTMLElement, node);
65 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement**,DWORD,compat_mode_t);
67 static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem)
69 if(buf->len == buf->size) {
70 buf->size <<= 1;
71 buf->buf = heap_realloc(buf->buf, buf->size*sizeof(HTMLElement*));
74 buf->buf[buf->len++] = elem;
77 static void elem_vector_normalize(elem_vector_t *buf)
79 if(!buf->len) {
80 heap_free(buf->buf);
81 buf->buf = NULL;
82 }else if(buf->size > buf->len) {
83 buf->buf = heap_realloc(buf->buf, buf->len*sizeof(HTMLElement*));
86 buf->size = buf->len;
89 static inline BOOL is_elem_node(nsIDOMNode *node)
91 UINT16 type=0;
93 nsIDOMNode_GetNodeType(node, &type);
95 return type == ELEMENT_NODE || type == COMMENT_NODE;
98 static inline HTMLElementCollectionEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
100 return CONTAINING_RECORD(iface, HTMLElementCollectionEnum, IEnumVARIANT_iface);
103 static HRESULT WINAPI HTMLElementCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
105 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
107 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
109 if(IsEqualGUID(riid, &IID_IUnknown)) {
110 *ppv = &This->IEnumVARIANT_iface;
111 }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
112 *ppv = &This->IEnumVARIANT_iface;
113 }else {
114 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid));
115 *ppv = NULL;
116 return E_NOINTERFACE;
119 IUnknown_AddRef((IUnknown*)*ppv);
120 return S_OK;
123 static ULONG WINAPI HTMLElementCollectionEnum_AddRef(IEnumVARIANT *iface)
125 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
126 LONG ref = InterlockedIncrement(&This->ref);
128 TRACE("(%p) ref=%ld\n", This, ref);
130 return ref;
133 static ULONG WINAPI HTMLElementCollectionEnum_Release(IEnumVARIANT *iface)
135 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
136 LONG ref = InterlockedDecrement(&This->ref);
138 TRACE("(%p) ref=%ld\n", This, ref);
140 if(!ref) {
141 IHTMLElementCollection_Release(&This->col->IHTMLElementCollection_iface);
142 heap_free(This);
145 return ref;
148 static HRESULT WINAPI HTMLElementCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
150 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
151 ULONG fetched = 0;
153 TRACE("(%p)->(%ld %p %p)\n", This, celt, rgVar, pCeltFetched);
155 while(This->iter+fetched < This->col->len && fetched < celt) {
156 V_VT(rgVar+fetched) = VT_DISPATCH;
157 V_DISPATCH(rgVar+fetched) = (IDispatch*)&This->col->elems[This->iter+fetched]->IHTMLElement_iface;
158 IDispatch_AddRef(V_DISPATCH(rgVar+fetched));
159 fetched++;
162 This->iter += fetched;
163 if(pCeltFetched)
164 *pCeltFetched = fetched;
165 return fetched == celt ? S_OK : S_FALSE;
168 static HRESULT WINAPI HTMLElementCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
170 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
172 TRACE("(%p)->(%ld)\n", This, celt);
174 if(This->iter + celt > This->col->len) {
175 This->iter = This->col->len;
176 return S_FALSE;
179 This->iter += celt;
180 return S_OK;
183 static HRESULT WINAPI HTMLElementCollectionEnum_Reset(IEnumVARIANT *iface)
185 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
187 TRACE("(%p)->()\n", This);
189 This->iter = 0;
190 return S_OK;
193 static HRESULT WINAPI HTMLElementCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
195 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
196 FIXME("(%p)->(%p)\n", This, ppEnum);
197 return E_NOTIMPL;
200 static const IEnumVARIANTVtbl HTMLElementCollectionEnumVtbl = {
201 HTMLElementCollectionEnum_QueryInterface,
202 HTMLElementCollectionEnum_AddRef,
203 HTMLElementCollectionEnum_Release,
204 HTMLElementCollectionEnum_Next,
205 HTMLElementCollectionEnum_Skip,
206 HTMLElementCollectionEnum_Reset,
207 HTMLElementCollectionEnum_Clone
210 static inline HTMLElementCollection *impl_from_IHTMLElementCollection(IHTMLElementCollection *iface)
212 return CONTAINING_RECORD(iface, HTMLElementCollection, IHTMLElementCollection_iface);
215 static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface,
216 REFIID riid, void **ppv)
218 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
220 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
222 if(IsEqualGUID(&IID_IUnknown, riid)) {
223 *ppv = &This->IHTMLElementCollection_iface;
224 }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) {
225 *ppv = &This->IHTMLElementCollection_iface;
226 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
227 return *ppv ? S_OK : E_NOINTERFACE;
228 }else {
229 *ppv = NULL;
230 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid));
231 return E_NOINTERFACE;
234 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
235 return S_OK;
238 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface)
240 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
241 LONG ref = InterlockedIncrement(&This->ref);
243 TRACE("(%p) ref=%ld\n", This, ref);
245 return ref;
248 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
250 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
251 LONG ref = InterlockedDecrement(&This->ref);
253 TRACE("(%p) ref=%ld\n", This, ref);
255 if(!ref) {
256 unsigned i;
258 for(i=0; i < This->len; i++)
259 node_release(&This->elems[i]->node);
260 heap_free(This->elems);
262 release_dispex(&This->dispex);
263 heap_free(This);
266 return ref;
269 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface,
270 UINT *pctinfo)
272 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
273 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
276 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface,
277 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
279 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
280 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
283 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface,
284 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
286 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
287 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
288 lcid, rgDispId);
291 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface,
292 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
293 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
295 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
296 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
297 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
300 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface,
301 BSTR *String)
303 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
305 TRACE("(%p)->(%p)\n", This, String);
307 return dispex_to_string(&This->dispex, String);
310 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface,
311 LONG v)
313 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
314 FIXME("(%p)->(%ld)\n", This, v);
315 return E_NOTIMPL;
318 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface,
319 LONG *p)
321 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
323 TRACE("(%p)->(%p)\n", This, p);
325 *p = This->len;
326 return S_OK;
329 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface,
330 IUnknown **p)
332 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
333 HTMLElementCollectionEnum *ret;
335 TRACE("(%p)->(%p)\n", This, p);
337 ret = heap_alloc(sizeof(*ret));
338 if(!ret)
339 return E_OUTOFMEMORY;
341 ret->IEnumVARIANT_iface.lpVtbl = &HTMLElementCollectionEnumVtbl;
342 ret->ref = 1;
343 ret->iter = 0;
345 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
346 ret->col = This;
348 *p = (IUnknown*)&ret->IEnumVARIANT_iface;
349 return S_OK;
352 static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name)
354 BSTR elem_id;
355 HRESULT hres;
357 hres = IHTMLElement_get_id(&elem->IHTMLElement_iface, &elem_id);
358 if(FAILED(hres)){
359 WARN("IHTMLElement_get_id failed: 0x%08lx\n", hres);
360 return FALSE;
363 if(elem_id && !wcscmp(elem_id, name)) {
364 SysFreeString(elem_id);
365 return TRUE;
368 SysFreeString(elem_id);
369 return FALSE;
372 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
374 const PRUnichar *str;
375 nsAString nsstr;
376 BOOL ret = FALSE;
377 nsresult nsres;
379 if(!elem->dom_element)
380 return FALSE;
382 nsAString_Init(&nsstr, NULL);
383 nsIDOMElement_GetId(elem->dom_element, &nsstr);
384 nsAString_GetData(&nsstr, &str);
385 if(!wcsicmp(str, name)) {
386 nsAString_Finish(&nsstr);
387 return TRUE;
390 nsres = get_elem_attr_value(elem->dom_element, L"name", &nsstr, &str);
391 if(NS_SUCCEEDED(nsres)) {
392 ret = !wcsicmp(str, name);
393 nsAString_Finish(&nsstr);
396 return ret;
399 static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret)
401 if(idx < This->len) {
402 *ret = (IDispatch*)&This->elems[idx]->node.event_target.dispex.IDispatchEx_iface;
403 IDispatch_AddRef(*ret);
406 return S_OK;
409 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface,
410 VARIANT name, VARIANT index, IDispatch **pdisp)
412 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
413 HRESULT hres = S_OK;
415 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
417 *pdisp = NULL;
419 switch(V_VT(&name)) {
420 case VT_I4:
421 case VT_INT:
422 if(V_I4(&name) < 0)
423 return dispex_compat_mode(&This->dispex) < COMPAT_MODE_IE9 ? E_INVALIDARG : S_OK;
424 hres = get_item_idx(This, V_I4(&name), pdisp);
425 break;
427 case VT_UI4:
428 case VT_UINT:
429 hres = get_item_idx(This, V_UINT(&name), pdisp);
430 break;
432 case VT_BSTR: {
433 DWORD i;
435 if(V_VT(&index) == VT_I4) {
436 LONG idx = V_I4(&index);
438 if(idx < 0)
439 return E_INVALIDARG;
441 for(i=0; i<This->len; i++) {
442 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--)
443 break;
446 if(i != This->len) {
447 *pdisp = (IDispatch*)&This->elems[i]->IHTMLElement_iface;
448 IDispatch_AddRef(*pdisp);
450 }else {
451 elem_vector_t buf = {NULL, 0, 8};
453 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
455 for(i=0; i<This->len; i++) {
456 if(is_elem_name(This->elems[i], V_BSTR(&name))) {
457 node_addref(&This->elems[i]->node);
458 elem_vector_add(&buf, This->elems[i]);
462 if(buf.len > 1) {
463 elem_vector_normalize(&buf);
464 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len,
465 dispex_compat_mode(&This->dispex));
466 }else {
467 if(buf.len == 1) {
468 /* Already AddRef-ed */
469 *pdisp = (IDispatch*)&buf.buf[0]->IHTMLElement_iface;
472 heap_free(buf.buf);
475 break;
478 default:
479 FIXME("Unsupported name %s\n", debugstr_variant(&name));
480 hres = E_NOTIMPL;
483 if(SUCCEEDED(hres))
484 TRACE("returning %p\n", *pdisp);
485 return hres;
488 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface,
489 VARIANT tagName, IDispatch **pdisp)
491 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
492 DWORD i;
493 nsAString tag_str;
494 const PRUnichar *tag;
495 elem_vector_t buf = {NULL, 0, 8};
497 if(V_VT(&tagName) != VT_BSTR) {
498 WARN("Invalid arg\n");
499 return DISP_E_MEMBERNOTFOUND;
502 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp);
504 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
506 nsAString_Init(&tag_str, NULL);
508 for(i=0; i<This->len; i++) {
509 if(!This->elems[i]->dom_element)
510 continue;
512 nsIDOMElement_GetTagName(This->elems[i]->dom_element, &tag_str);
513 nsAString_GetData(&tag_str, &tag);
515 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1,
516 V_BSTR(&tagName), -1) == CSTR_EQUAL) {
517 node_addref(&This->elems[i]->node);
518 elem_vector_add(&buf, This->elems[i]);
522 nsAString_Finish(&tag_str);
523 elem_vector_normalize(&buf);
525 TRACE("found %ld tags\n", buf.len);
527 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len,
528 dispex_compat_mode(&This->dispex));
529 return S_OK;
532 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
533 HTMLElementCollection_QueryInterface,
534 HTMLElementCollection_AddRef,
535 HTMLElementCollection_Release,
536 HTMLElementCollection_GetTypeInfoCount,
537 HTMLElementCollection_GetTypeInfo,
538 HTMLElementCollection_GetIDsOfNames,
539 HTMLElementCollection_Invoke,
540 HTMLElementCollection_toString,
541 HTMLElementCollection_put_length,
542 HTMLElementCollection_get_length,
543 HTMLElementCollection_get__newEnum,
544 HTMLElementCollection_item,
545 HTMLElementCollection_tags
548 static inline HTMLElementCollection *impl_from_DispatchEx(DispatchEx *iface)
550 return CONTAINING_RECORD(iface, HTMLElementCollection, dispex);
553 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN
555 static HRESULT HTMLElementCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
557 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
558 WCHAR *ptr;
559 DWORD idx=0;
561 if(!*name)
562 return DISP_E_UNKNOWNNAME;
564 for(ptr = name; *ptr && is_digit(*ptr); ptr++)
565 idx = idx*10 + (*ptr-'0');
567 if(*ptr) {
568 /* the name contains alpha characters, so search by name & id */
569 for(idx = 0; idx < This->len; ++idx) {
570 if(is_elem_id(This->elems[idx], name) ||
571 is_elem_name(This->elems[idx], name))
572 break;
576 if(idx >= This->len)
577 return DISP_E_UNKNOWNNAME;
579 *dispid = DISPID_ELEMCOL_0 + idx;
580 TRACE("ret %lx\n", *dispid);
581 return S_OK;
584 static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
585 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
587 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
588 DWORD idx;
590 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
592 idx = id - DISPID_ELEMCOL_0;
593 if(idx >= This->len)
594 return DISP_E_UNKNOWNNAME;
596 switch(flags) {
597 case DISPATCH_PROPERTYGET:
598 V_VT(res) = VT_DISPATCH;
599 V_DISPATCH(res) = (IDispatch*)&This->elems[idx]->IHTMLElement_iface;
600 IHTMLElement_AddRef(&This->elems[idx]->IHTMLElement_iface);
601 break;
602 default:
603 FIXME("unimplemented flags %x\n", flags);
604 return E_NOTIMPL;
607 return S_OK;
610 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
611 NULL,
612 HTMLElementCollection_get_dispid,
613 HTMLElementCollection_invoke,
614 NULL
617 static const tid_t HTMLElementCollection_iface_tids[] = {
618 IHTMLElementCollection_tid,
622 static dispex_static_data_t HTMLElementCollection_dispex = {
623 L"HTMLCollection",
624 &HTMLElementColection_dispex_vtbl,
625 DispHTMLElementCollection_tid,
626 HTMLElementCollection_iface_tids
629 static void create_all_list(HTMLDOMNode *elem, elem_vector_t *buf)
631 nsIDOMNodeList *nsnode_list;
632 nsIDOMNode *iter;
633 UINT32 list_len = 0, i;
634 nsresult nsres;
635 HRESULT hres;
637 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list);
638 if(NS_FAILED(nsres)) {
639 ERR("GetChildNodes failed: %08lx\n", nsres);
640 return;
643 nsIDOMNodeList_GetLength(nsnode_list, &list_len);
644 if(!list_len)
645 return;
647 for(i=0; i<list_len; i++) {
648 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
649 if(NS_FAILED(nsres)) {
650 ERR("Item failed: %08lx\n", nsres);
651 continue;
654 if(is_elem_node(iter)) {
655 HTMLDOMNode *node;
657 hres = get_node(iter, TRUE, &node);
658 if(FAILED(hres)) {
659 FIXME("get_node failed: %08lx\n", hres);
660 continue;
663 elem_vector_add(buf, elem_from_HTMLDOMNode(node));
664 create_all_list(node, buf);
669 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root)
671 elem_vector_t buf = {NULL, 0, 8};
673 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
675 if(include_root) {
676 node_addref(node);
677 elem_vector_add(&buf, elem_from_HTMLDOMNode(node));
679 create_all_list(node, &buf);
680 elem_vector_normalize(&buf);
682 return HTMLElementCollection_Create(buf.buf, buf.len,
683 dispex_compat_mode(&node->event_target.dispex));
686 IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList *nslist, compat_mode_t compat_mode)
688 UINT32 length = 0, i;
689 HTMLDOMNode *node;
690 elem_vector_t buf;
691 HRESULT hres;
693 nsIDOMNodeList_GetLength(nslist, &length);
695 buf.len = 0;
696 buf.size = length;
697 if(length) {
698 nsIDOMNode *nsnode;
700 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
702 for(i=0; i<length; i++) {
703 nsIDOMNodeList_Item(nslist, i, &nsnode);
704 if(is_elem_node(nsnode)) {
705 hres = get_node(nsnode, TRUE, &node);
706 if(FAILED(hres))
707 continue;
708 buf.buf[buf.len++] = elem_from_HTMLDOMNode(node);
710 nsIDOMNode_Release(nsnode);
713 elem_vector_normalize(&buf);
714 }else {
715 buf.buf = NULL;
718 return HTMLElementCollection_Create(buf.buf, buf.len, compat_mode);
721 IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection *nscol, compat_mode_t compat_mode)
723 UINT32 length = 0, i;
724 elem_vector_t buf;
725 HTMLDOMNode *node;
726 HRESULT hres = S_OK;
728 if(nscol)
729 nsIDOMHTMLCollection_GetLength(nscol, &length);
731 buf.len = buf.size = length;
732 if(buf.len) {
733 nsIDOMNode *nsnode;
735 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
737 for(i=0; i<length; i++) {
738 nsIDOMHTMLCollection_Item(nscol, i, &nsnode);
739 hres = get_node(nsnode, TRUE, &node);
740 nsIDOMNode_Release(nsnode);
741 if(FAILED(hres))
742 break;
743 buf.buf[i] = elem_from_HTMLDOMNode(node);
745 }else {
746 buf.buf = NULL;
749 if(FAILED(hres)) {
750 heap_free(buf.buf);
751 return NULL;
754 return HTMLElementCollection_Create(buf.buf, buf.len, compat_mode);
757 HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret)
759 elem_vector_t buf = {NULL, 0, 8};
760 nsIDOMNode *parent_node, *iter;
761 UINT16 parent_type;
762 HTMLDOMNode *node;
763 int i;
764 nsresult nsres;
765 HRESULT hres;
767 iter = elem->node.nsnode;
768 nsIDOMNode_AddRef(iter);
770 /* Find document or document fragment parent. */
771 while(1) {
772 nsres = nsIDOMNode_GetParentNode(iter, &parent_node);
773 nsIDOMNode_Release(iter);
774 assert(nsres == NS_OK);
775 if(!parent_node)
776 break;
778 nsres = nsIDOMNode_GetNodeType(parent_node, &parent_type);
779 assert(nsres == NS_OK);
781 if(parent_type != ELEMENT_NODE) {
782 if(parent_type != DOCUMENT_NODE && parent_type != DOCUMENT_FRAGMENT_NODE)
783 FIXME("Unexpected parent_type %d\n", parent_type);
784 break;
787 iter = parent_node;
790 if(!parent_node) {
791 *ret = -1;
792 return S_OK;
795 hres = get_node(parent_node, TRUE, &node);
796 nsIDOMNode_Release(parent_node);
797 if(FAILED(hres))
798 return hres;
800 /* Create all children collection and find the element in it.
801 * This could be optimized if we ever find the reason. */
802 buf.buf = heap_alloc(buf.size*sizeof(*buf.buf));
803 if(!buf.buf) {
804 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
805 return E_OUTOFMEMORY;
808 create_all_list(node, &buf);
810 for(i=0; i < buf.len; i++) {
811 if(buf.buf[i] == elem)
812 break;
814 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
815 heap_free(buf.buf);
816 if(i == buf.len) {
817 FIXME("The element is not in parent's child list?\n");
818 return E_UNEXPECTED;
821 *ret = i;
822 return S_OK;
825 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len,
826 compat_mode_t compat_mode)
828 HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection));
830 if (!ret)
831 return NULL;
833 ret->IHTMLElementCollection_iface.lpVtbl = &HTMLElementCollectionVtbl;
834 ret->ref = 1;
835 ret->elems = elems;
836 ret->len = len;
838 init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLElementCollection_iface,
839 &HTMLElementCollection_dispex, compat_mode);
841 TRACE("ret=%p len=%ld\n", ret, len);
843 return &ret->IHTMLElementCollection_iface;