gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / mshtml / htmlelemcol.c
blob8ebe741c309a84657517ff50896915b0c0e80168
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;
40 } HTMLElementCollection;
42 typedef struct {
43 IEnumVARIANT IEnumVARIANT_iface;
45 LONG ref;
47 ULONG iter;
48 HTMLElementCollection *col;
49 } HTMLElementCollectionEnum;
51 typedef struct {
52 HTMLElement **buf;
53 DWORD len;
54 DWORD size;
55 } elem_vector_t;
57 /* FIXME: Handle it better way */
58 static inline HTMLElement *elem_from_HTMLDOMNode(HTMLDOMNode *iface)
60 return CONTAINING_RECORD(iface, HTMLElement, node);
63 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement**,DWORD,compat_mode_t);
65 static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem)
67 if(buf->len == buf->size) {
68 buf->size <<= 1;
69 buf->buf = realloc(buf->buf, buf->size * sizeof(HTMLElement*));
72 buf->buf[buf->len++] = elem;
75 static void elem_vector_normalize(elem_vector_t *buf)
77 if(!buf->len) {
78 free(buf->buf);
79 buf->buf = NULL;
80 }else if(buf->size > buf->len) {
81 buf->buf = realloc(buf->buf, buf->len*sizeof(HTMLElement*));
84 buf->size = buf->len;
87 static inline BOOL is_elem_node(nsIDOMNode *node)
89 UINT16 type=0;
91 nsIDOMNode_GetNodeType(node, &type);
93 return type == ELEMENT_NODE || type == COMMENT_NODE;
96 static inline HTMLElementCollectionEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
98 return CONTAINING_RECORD(iface, HTMLElementCollectionEnum, IEnumVARIANT_iface);
101 static HRESULT WINAPI HTMLElementCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
103 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
105 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
107 if(IsEqualGUID(riid, &IID_IUnknown)) {
108 *ppv = &This->IEnumVARIANT_iface;
109 }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
110 *ppv = &This->IEnumVARIANT_iface;
111 }else {
112 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid));
113 *ppv = NULL;
114 return E_NOINTERFACE;
117 IUnknown_AddRef((IUnknown*)*ppv);
118 return S_OK;
121 static ULONG WINAPI HTMLElementCollectionEnum_AddRef(IEnumVARIANT *iface)
123 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
124 LONG ref = InterlockedIncrement(&This->ref);
126 TRACE("(%p) ref=%ld\n", This, ref);
128 return ref;
131 static ULONG WINAPI HTMLElementCollectionEnum_Release(IEnumVARIANT *iface)
133 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
134 LONG ref = InterlockedDecrement(&This->ref);
136 TRACE("(%p) ref=%ld\n", This, ref);
138 if(!ref) {
139 IHTMLElementCollection_Release(&This->col->IHTMLElementCollection_iface);
140 free(This);
143 return ref;
146 static HRESULT WINAPI HTMLElementCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
148 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
149 ULONG fetched = 0;
151 TRACE("(%p)->(%ld %p %p)\n", This, celt, rgVar, pCeltFetched);
153 while(This->iter+fetched < This->col->len && fetched < celt) {
154 V_VT(rgVar+fetched) = VT_DISPATCH;
155 V_DISPATCH(rgVar+fetched) = (IDispatch*)&This->col->elems[This->iter+fetched]->IHTMLElement_iface;
156 IDispatch_AddRef(V_DISPATCH(rgVar+fetched));
157 fetched++;
160 This->iter += fetched;
161 if(pCeltFetched)
162 *pCeltFetched = fetched;
163 return fetched == celt ? S_OK : S_FALSE;
166 static HRESULT WINAPI HTMLElementCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
168 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
170 TRACE("(%p)->(%ld)\n", This, celt);
172 if(This->iter + celt > This->col->len) {
173 This->iter = This->col->len;
174 return S_FALSE;
177 This->iter += celt;
178 return S_OK;
181 static HRESULT WINAPI HTMLElementCollectionEnum_Reset(IEnumVARIANT *iface)
183 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
185 TRACE("(%p)->()\n", This);
187 This->iter = 0;
188 return S_OK;
191 static HRESULT WINAPI HTMLElementCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
193 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
194 FIXME("(%p)->(%p)\n", This, ppEnum);
195 return E_NOTIMPL;
198 static const IEnumVARIANTVtbl HTMLElementCollectionEnumVtbl = {
199 HTMLElementCollectionEnum_QueryInterface,
200 HTMLElementCollectionEnum_AddRef,
201 HTMLElementCollectionEnum_Release,
202 HTMLElementCollectionEnum_Next,
203 HTMLElementCollectionEnum_Skip,
204 HTMLElementCollectionEnum_Reset,
205 HTMLElementCollectionEnum_Clone
208 static inline HTMLElementCollection *impl_from_IHTMLElementCollection(IHTMLElementCollection *iface)
210 return CONTAINING_RECORD(iface, HTMLElementCollection, IHTMLElementCollection_iface);
213 static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface,
214 REFIID riid, void **ppv)
216 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
217 return IDispatchEx_QueryInterface(&This->dispex.IDispatchEx_iface, riid, ppv);
220 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface)
222 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
223 return IDispatchEx_AddRef(&This->dispex.IDispatchEx_iface);
226 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
228 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
229 return IDispatchEx_Release(&This->dispex.IDispatchEx_iface);
232 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface,
233 UINT *pctinfo)
235 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
236 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
239 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface,
240 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
242 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
243 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
246 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface,
247 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
249 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
250 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
251 lcid, rgDispId);
254 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface,
255 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
256 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
258 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
259 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
260 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
263 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface,
264 BSTR *String)
266 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
268 TRACE("(%p)->(%p)\n", This, String);
270 return dispex_to_string(&This->dispex, String);
273 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface,
274 LONG v)
276 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
277 FIXME("(%p)->(%ld)\n", This, v);
278 return E_NOTIMPL;
281 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface,
282 LONG *p)
284 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
286 TRACE("(%p)->(%p)\n", This, p);
288 *p = This->len;
289 return S_OK;
292 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface,
293 IUnknown **p)
295 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
296 HTMLElementCollectionEnum *ret;
298 TRACE("(%p)->(%p)\n", This, p);
300 ret = malloc(sizeof(*ret));
301 if(!ret)
302 return E_OUTOFMEMORY;
304 ret->IEnumVARIANT_iface.lpVtbl = &HTMLElementCollectionEnumVtbl;
305 ret->ref = 1;
306 ret->iter = 0;
308 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
309 ret->col = This;
311 *p = (IUnknown*)&ret->IEnumVARIANT_iface;
312 return S_OK;
315 static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name)
317 BSTR elem_id;
318 HRESULT hres;
320 hres = IHTMLElement_get_id(&elem->IHTMLElement_iface, &elem_id);
321 if(FAILED(hres)){
322 WARN("IHTMLElement_get_id failed: 0x%08lx\n", hres);
323 return FALSE;
326 if(elem_id && !wcscmp(elem_id, name)) {
327 SysFreeString(elem_id);
328 return TRUE;
331 SysFreeString(elem_id);
332 return FALSE;
335 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
337 const PRUnichar *str;
338 nsAString nsstr;
339 BOOL ret = FALSE;
340 nsresult nsres;
342 if(!elem->dom_element)
343 return FALSE;
345 nsAString_Init(&nsstr, NULL);
346 nsIDOMElement_GetId(elem->dom_element, &nsstr);
347 nsAString_GetData(&nsstr, &str);
348 if(!wcsicmp(str, name)) {
349 nsAString_Finish(&nsstr);
350 return TRUE;
353 nsres = get_elem_attr_value(elem->dom_element, L"name", &nsstr, &str);
354 if(NS_SUCCEEDED(nsres)) {
355 ret = !wcsicmp(str, name);
356 nsAString_Finish(&nsstr);
359 return ret;
362 static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret)
364 if(idx < This->len) {
365 *ret = (IDispatch*)&This->elems[idx]->node.event_target.dispex.IDispatchEx_iface;
366 IDispatch_AddRef(*ret);
369 return S_OK;
372 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface,
373 VARIANT name, VARIANT index, IDispatch **pdisp)
375 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
376 HRESULT hres = S_OK;
378 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
380 *pdisp = NULL;
382 switch(V_VT(&name)) {
383 case VT_I4:
384 case VT_INT:
385 if(V_I4(&name) < 0)
386 return dispex_compat_mode(&This->dispex) < COMPAT_MODE_IE9 ? E_INVALIDARG : S_OK;
387 hres = get_item_idx(This, V_I4(&name), pdisp);
388 break;
390 case VT_UI4:
391 case VT_UINT:
392 hres = get_item_idx(This, V_UINT(&name), pdisp);
393 break;
395 case VT_BSTR: {
396 DWORD i;
398 if(V_VT(&index) == VT_I4) {
399 LONG idx = V_I4(&index);
401 if(idx < 0)
402 return E_INVALIDARG;
404 for(i=0; i<This->len; i++) {
405 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--)
406 break;
409 if(i != This->len) {
410 *pdisp = (IDispatch*)&This->elems[i]->IHTMLElement_iface;
411 IDispatch_AddRef(*pdisp);
413 }else {
414 elem_vector_t buf = {NULL, 0, 8};
416 buf.buf = malloc(buf.size * sizeof(HTMLElement*));
418 for(i=0; i<This->len; i++) {
419 if(is_elem_name(This->elems[i], V_BSTR(&name))) {
420 node_addref(&This->elems[i]->node);
421 elem_vector_add(&buf, This->elems[i]);
425 if(buf.len > 1) {
426 elem_vector_normalize(&buf);
427 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len,
428 dispex_compat_mode(&This->dispex));
429 }else {
430 if(buf.len == 1) {
431 /* Already AddRef-ed */
432 *pdisp = (IDispatch*)&buf.buf[0]->IHTMLElement_iface;
435 free(buf.buf);
438 break;
441 default:
442 FIXME("Unsupported name %s\n", debugstr_variant(&name));
443 hres = E_NOTIMPL;
446 if(SUCCEEDED(hres))
447 TRACE("returning %p\n", *pdisp);
448 return hres;
451 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface,
452 VARIANT tagName, IDispatch **pdisp)
454 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
455 DWORD i;
456 nsAString tag_str;
457 const PRUnichar *tag;
458 elem_vector_t buf = {NULL, 0, 8};
460 if(V_VT(&tagName) != VT_BSTR) {
461 WARN("Invalid arg\n");
462 return DISP_E_MEMBERNOTFOUND;
465 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp);
467 buf.buf = malloc(buf.size * sizeof(HTMLElement*));
469 nsAString_Init(&tag_str, NULL);
471 for(i=0; i<This->len; i++) {
472 if(!This->elems[i]->dom_element)
473 continue;
475 nsIDOMElement_GetTagName(This->elems[i]->dom_element, &tag_str);
476 nsAString_GetData(&tag_str, &tag);
478 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1,
479 V_BSTR(&tagName), -1) == CSTR_EQUAL) {
480 node_addref(&This->elems[i]->node);
481 elem_vector_add(&buf, This->elems[i]);
485 nsAString_Finish(&tag_str);
486 elem_vector_normalize(&buf);
488 TRACE("found %ld tags\n", buf.len);
490 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len,
491 dispex_compat_mode(&This->dispex));
492 return S_OK;
495 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
496 HTMLElementCollection_QueryInterface,
497 HTMLElementCollection_AddRef,
498 HTMLElementCollection_Release,
499 HTMLElementCollection_GetTypeInfoCount,
500 HTMLElementCollection_GetTypeInfo,
501 HTMLElementCollection_GetIDsOfNames,
502 HTMLElementCollection_Invoke,
503 HTMLElementCollection_toString,
504 HTMLElementCollection_put_length,
505 HTMLElementCollection_get_length,
506 HTMLElementCollection_get__newEnum,
507 HTMLElementCollection_item,
508 HTMLElementCollection_tags
511 static inline HTMLElementCollection *impl_from_DispatchEx(DispatchEx *iface)
513 return CONTAINING_RECORD(iface, HTMLElementCollection, dispex);
516 static void *HTMLElementCollection_query_interface(DispatchEx *dispex, REFIID riid)
518 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
520 if(IsEqualGUID(&IID_IHTMLElementCollection, riid))
521 return &This->IHTMLElementCollection_iface;
523 return NULL;
526 static void HTMLElementCollection_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb)
528 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
529 unsigned i;
531 for(i = 0; i < This->len; i++)
532 note_cc_edge((nsISupports*)&This->elems[i]->node.IHTMLDOMNode_iface, "elem", cb);
535 static void HTMLElementCollection_unlink(DispatchEx *dispex)
537 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
538 unsigned i, len = This->len;
540 if(len) {
541 This->len = 0;
542 for(i = 0; i < len; i++)
543 node_release(&This->elems[i]->node);
544 free(This->elems);
548 static void HTMLElementCollection_destructor(DispatchEx *dispex)
550 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
551 free(This);
554 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN
556 static HRESULT HTMLElementCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
558 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
559 WCHAR *ptr;
560 DWORD idx=0;
562 if(!*name)
563 return DISP_E_UNKNOWNNAME;
565 for(ptr = name; *ptr && is_digit(*ptr); ptr++)
566 idx = idx*10 + (*ptr-'0');
568 if(*ptr) {
569 /* the name contains alpha characters, so search by name & id */
570 for(idx = 0; idx < This->len; ++idx) {
571 if(is_elem_id(This->elems[idx], name) ||
572 is_elem_name(This->elems[idx], name))
573 break;
577 if(idx >= This->len)
578 return DISP_E_UNKNOWNNAME;
580 *dispid = DISPID_ELEMCOL_0 + idx;
581 TRACE("ret %lx\n", *dispid);
582 return S_OK;
585 static HRESULT HTMLElementCollection_get_name(DispatchEx *dispex, DISPID id, BSTR *name)
587 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
588 DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
589 WCHAR buf[11];
590 UINT len;
592 if(idx >= This->len)
593 return DISP_E_MEMBERNOTFOUND;
595 len = swprintf(buf, ARRAY_SIZE(buf), L"%u", idx);
596 return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY;
599 static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
600 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
602 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
603 DWORD idx;
605 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
607 idx = id - DISPID_ELEMCOL_0;
608 if(idx >= This->len)
609 return DISP_E_MEMBERNOTFOUND;
611 switch(flags) {
612 case DISPATCH_PROPERTYGET:
613 V_VT(res) = VT_DISPATCH;
614 V_DISPATCH(res) = (IDispatch*)&This->elems[idx]->IHTMLElement_iface;
615 IHTMLElement_AddRef(&This->elems[idx]->IHTMLElement_iface);
616 break;
617 default:
618 FIXME("unimplemented flags %x\n", flags);
619 return E_NOTIMPL;
622 return S_OK;
625 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
626 .query_interface = HTMLElementCollection_query_interface,
627 .destructor = HTMLElementCollection_destructor,
628 .traverse = HTMLElementCollection_traverse,
629 .unlink = HTMLElementCollection_unlink,
630 .get_dispid = HTMLElementCollection_get_dispid,
631 .get_name = HTMLElementCollection_get_name,
632 .invoke = HTMLElementCollection_invoke,
635 static const tid_t HTMLElementCollection_iface_tids[] = {
636 IHTMLElementCollection_tid,
640 static dispex_static_data_t HTMLElementCollection_dispex = {
641 "HTMLCollection",
642 &HTMLElementColection_dispex_vtbl,
643 DispHTMLElementCollection_tid,
644 HTMLElementCollection_iface_tids
647 static void create_all_list(HTMLDOMNode *elem, elem_vector_t *buf)
649 nsIDOMNodeList *nsnode_list;
650 nsIDOMNode *iter;
651 UINT32 list_len = 0, i;
652 nsresult nsres;
653 HRESULT hres;
655 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list);
656 if(NS_FAILED(nsres)) {
657 ERR("GetChildNodes failed: %08lx\n", nsres);
658 return;
661 nsIDOMNodeList_GetLength(nsnode_list, &list_len);
663 for(i=0; i<list_len; i++) {
664 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
665 if(NS_FAILED(nsres)) {
666 ERR("Item failed: %08lx\n", nsres);
667 continue;
670 if(is_elem_node(iter)) {
671 HTMLDOMNode *node;
673 hres = get_node(iter, TRUE, &node);
674 if(FAILED(hres)) {
675 FIXME("get_node failed: %08lx\n", hres);
676 nsIDOMNode_Release(iter);
677 continue;
680 elem_vector_add(buf, elem_from_HTMLDOMNode(node));
681 create_all_list(node, buf);
684 nsIDOMNode_Release(iter);
687 nsIDOMNodeList_Release(nsnode_list);
690 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root)
692 elem_vector_t buf = {NULL, 0, 8};
694 buf.buf = malloc(buf.size * sizeof(HTMLElement*));
696 if(include_root) {
697 node_addref(node);
698 elem_vector_add(&buf, elem_from_HTMLDOMNode(node));
700 create_all_list(node, &buf);
701 elem_vector_normalize(&buf);
703 return HTMLElementCollection_Create(buf.buf, buf.len,
704 dispex_compat_mode(&node->event_target.dispex));
707 IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList *nslist, compat_mode_t compat_mode)
709 UINT32 length = 0, i;
710 HTMLDOMNode *node;
711 elem_vector_t buf;
712 HRESULT hres;
714 nsIDOMNodeList_GetLength(nslist, &length);
716 buf.len = 0;
717 buf.size = length;
718 if(length) {
719 nsIDOMNode *nsnode;
721 buf.buf = malloc(buf.size * sizeof(HTMLElement*));
723 for(i=0; i<length; i++) {
724 nsIDOMNodeList_Item(nslist, i, &nsnode);
725 if(is_elem_node(nsnode)) {
726 hres = get_node(nsnode, TRUE, &node);
727 if(FAILED(hres))
728 continue;
729 buf.buf[buf.len++] = elem_from_HTMLDOMNode(node);
731 nsIDOMNode_Release(nsnode);
734 elem_vector_normalize(&buf);
735 }else {
736 buf.buf = NULL;
739 return HTMLElementCollection_Create(buf.buf, buf.len, compat_mode);
742 IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection *nscol, compat_mode_t compat_mode)
744 UINT32 length = 0, i;
745 elem_vector_t buf;
746 HTMLDOMNode *node;
747 HRESULT hres = S_OK;
749 if(nscol)
750 nsIDOMHTMLCollection_GetLength(nscol, &length);
752 buf.len = buf.size = length;
753 if(buf.len) {
754 nsIDOMNode *nsnode;
756 buf.buf = malloc(buf.size * sizeof(HTMLElement*));
758 for(i=0; i<length; i++) {
759 nsIDOMHTMLCollection_Item(nscol, i, &nsnode);
760 hres = get_node(nsnode, TRUE, &node);
761 nsIDOMNode_Release(nsnode);
762 if(FAILED(hres))
763 break;
764 buf.buf[i] = elem_from_HTMLDOMNode(node);
766 }else {
767 buf.buf = NULL;
770 if(FAILED(hres)) {
771 free(buf.buf);
772 return NULL;
775 return HTMLElementCollection_Create(buf.buf, buf.len, compat_mode);
778 HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret)
780 elem_vector_t buf = {NULL, 0, 8};
781 nsIDOMNode *parent_node, *iter;
782 UINT16 parent_type;
783 HTMLDOMNode *node;
784 nsresult nsres;
785 unsigned i, j;
786 HRESULT hres;
788 iter = elem->node.nsnode;
789 nsIDOMNode_AddRef(iter);
791 /* Find document or document fragment parent. */
792 while(1) {
793 nsres = nsIDOMNode_GetParentNode(iter, &parent_node);
794 nsIDOMNode_Release(iter);
795 assert(nsres == NS_OK);
796 if(!parent_node)
797 break;
799 nsres = nsIDOMNode_GetNodeType(parent_node, &parent_type);
800 assert(nsres == NS_OK);
802 if(parent_type != ELEMENT_NODE) {
803 if(parent_type != DOCUMENT_NODE && parent_type != DOCUMENT_FRAGMENT_NODE)
804 FIXME("Unexpected parent_type %d\n", parent_type);
805 break;
808 iter = parent_node;
811 if(!parent_node) {
812 *ret = -1;
813 return S_OK;
816 hres = get_node(parent_node, TRUE, &node);
817 nsIDOMNode_Release(parent_node);
818 if(FAILED(hres))
819 return hres;
821 /* Create all children collection and find the element in it.
822 * This could be optimized if we ever find the reason. */
823 buf.buf = malloc(buf.size * sizeof(*buf.buf));
824 if(!buf.buf) {
825 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
826 return E_OUTOFMEMORY;
829 create_all_list(node, &buf);
831 for(i=0; i < buf.len; i++) {
832 if(buf.buf[i] == elem)
833 break;
835 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
837 for(j = 0; j < buf.len; j++)
838 IHTMLDOMNode_Release(&buf.buf[j]->node.IHTMLDOMNode_iface);
839 free(buf.buf);
841 if(i == buf.len) {
842 FIXME("The element is not in parent's child list?\n");
843 return E_UNEXPECTED;
846 *ret = i;
847 return S_OK;
850 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len,
851 compat_mode_t compat_mode)
853 HTMLElementCollection *ret = calloc(1, sizeof(HTMLElementCollection));
855 if (!ret)
856 return NULL;
858 ret->IHTMLElementCollection_iface.lpVtbl = &HTMLElementCollectionVtbl;
859 ret->elems = elems;
860 ret->len = len;
862 init_dispatch(&ret->dispex, &HTMLElementCollection_dispex, compat_mode);
864 TRACE("ret=%p len=%ld\n", ret, len);
866 return &ret->IHTMLElementCollection_iface;