[MSHTML] Fix 3 MSVC warnings about HTML*Element_handle_event()
[reactos.git] / dll / win32 / mshtml / htmlelemcol.c
1 /*
2 * Copyright 2006-2008 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "mshtml_private.h"
20
21 typedef struct {
22 DispatchEx dispex;
23 IHTMLElementCollection IHTMLElementCollection_iface;
24
25 HTMLElement **elems;
26 DWORD len;
27
28 LONG ref;
29 } HTMLElementCollection;
30
31 typedef struct {
32 IEnumVARIANT IEnumVARIANT_iface;
33
34 LONG ref;
35
36 ULONG iter;
37 HTMLElementCollection *col;
38 } HTMLElementCollectionEnum;
39
40 typedef struct {
41 HTMLElement **buf;
42 DWORD len;
43 DWORD size;
44 } elem_vector_t;
45
46 /* FIXME: Handle it better way */
47 static inline HTMLElement *elem_from_HTMLDOMNode(HTMLDOMNode *iface)
48 {
49 return CONTAINING_RECORD(iface, HTMLElement, node);
50 }
51
52 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len);
53
54 static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem)
55 {
56 if(buf->len == buf->size) {
57 buf->size <<= 1;
58 buf->buf = heap_realloc(buf->buf, buf->size*sizeof(HTMLElement*));
59 }
60
61 buf->buf[buf->len++] = elem;
62 }
63
64 static void elem_vector_normalize(elem_vector_t *buf)
65 {
66 if(!buf->len) {
67 heap_free(buf->buf);
68 buf->buf = NULL;
69 }else if(buf->size > buf->len) {
70 buf->buf = heap_realloc(buf->buf, buf->len*sizeof(HTMLElement*));
71 }
72
73 buf->size = buf->len;
74 }
75
76 static inline BOOL is_elem_node(nsIDOMNode *node)
77 {
78 UINT16 type=0;
79
80 nsIDOMNode_GetNodeType(node, &type);
81
82 return type == ELEMENT_NODE || type == COMMENT_NODE;
83 }
84
85 static inline HTMLElementCollectionEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
86 {
87 return CONTAINING_RECORD(iface, HTMLElementCollectionEnum, IEnumVARIANT_iface);
88 }
89
90 static HRESULT WINAPI HTMLElementCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
91 {
92 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
93
94 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
95
96 if(IsEqualGUID(riid, &IID_IUnknown)) {
97 *ppv = &This->IEnumVARIANT_iface;
98 }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
99 *ppv = &This->IEnumVARIANT_iface;
100 }else {
101 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid));
102 *ppv = NULL;
103 return E_NOINTERFACE;
104 }
105
106 IUnknown_AddRef((IUnknown*)*ppv);
107 return S_OK;
108 }
109
110 static ULONG WINAPI HTMLElementCollectionEnum_AddRef(IEnumVARIANT *iface)
111 {
112 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
113 LONG ref = InterlockedIncrement(&This->ref);
114
115 TRACE("(%p) ref=%d\n", This, ref);
116
117 return ref;
118 }
119
120 static ULONG WINAPI HTMLElementCollectionEnum_Release(IEnumVARIANT *iface)
121 {
122 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
123 LONG ref = InterlockedDecrement(&This->ref);
124
125 TRACE("(%p) ref=%d\n", This, ref);
126
127 if(!ref) {
128 IHTMLElementCollection_Release(&This->col->IHTMLElementCollection_iface);
129 heap_free(This);
130 }
131
132 return ref;
133 }
134
135 static HRESULT WINAPI HTMLElementCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
136 {
137 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
138 ULONG fetched = 0;
139
140 TRACE("(%p)->(%d %p %p)\n", This, celt, rgVar, pCeltFetched);
141
142 while(This->iter+fetched < This->col->len && fetched < celt) {
143 V_VT(rgVar+fetched) = VT_DISPATCH;
144 V_DISPATCH(rgVar+fetched) = (IDispatch*)&This->col->elems[This->iter+fetched]->IHTMLElement_iface;
145 IDispatch_AddRef(V_DISPATCH(rgVar+fetched));
146 fetched++;
147 }
148
149 This->iter += fetched;
150 if(pCeltFetched)
151 *pCeltFetched = fetched;
152 return fetched == celt ? S_OK : S_FALSE;
153 }
154
155 static HRESULT WINAPI HTMLElementCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
156 {
157 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
158
159 TRACE("(%p)->(%d)\n", This, celt);
160
161 if(This->iter + celt > This->col->len) {
162 This->iter = This->col->len;
163 return S_FALSE;
164 }
165
166 This->iter += celt;
167 return S_OK;
168 }
169
170 static HRESULT WINAPI HTMLElementCollectionEnum_Reset(IEnumVARIANT *iface)
171 {
172 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
173
174 TRACE("(%p)->()\n", This);
175
176 This->iter = 0;
177 return S_OK;
178 }
179
180 static HRESULT WINAPI HTMLElementCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
181 {
182 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface);
183 FIXME("(%p)->(%p)\n", This, ppEnum);
184 return E_NOTIMPL;
185 }
186
187 static const IEnumVARIANTVtbl HTMLElementCollectionEnumVtbl = {
188 HTMLElementCollectionEnum_QueryInterface,
189 HTMLElementCollectionEnum_AddRef,
190 HTMLElementCollectionEnum_Release,
191 HTMLElementCollectionEnum_Next,
192 HTMLElementCollectionEnum_Skip,
193 HTMLElementCollectionEnum_Reset,
194 HTMLElementCollectionEnum_Clone
195 };
196
197 static inline HTMLElementCollection *impl_from_IHTMLElementCollection(IHTMLElementCollection *iface)
198 {
199 return CONTAINING_RECORD(iface, HTMLElementCollection, IHTMLElementCollection_iface);
200 }
201
202 static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface,
203 REFIID riid, void **ppv)
204 {
205 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
206
207 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
208
209 if(IsEqualGUID(&IID_IUnknown, riid)) {
210 *ppv = &This->IHTMLElementCollection_iface;
211 }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) {
212 *ppv = &This->IHTMLElementCollection_iface;
213 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
214 return *ppv ? S_OK : E_NOINTERFACE;
215 }else {
216 *ppv = NULL;
217 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid));
218 return E_NOINTERFACE;
219 }
220
221 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
222 return S_OK;
223 }
224
225 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface)
226 {
227 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
228 LONG ref = InterlockedIncrement(&This->ref);
229
230 TRACE("(%p) ref=%d\n", This, ref);
231
232 return ref;
233 }
234
235 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
236 {
237 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
238 LONG ref = InterlockedDecrement(&This->ref);
239
240 TRACE("(%p) ref=%d\n", This, ref);
241
242 if(!ref) {
243 unsigned i;
244
245 for(i=0; i < This->len; i++)
246 node_release(&This->elems[i]->node);
247 heap_free(This->elems);
248
249 release_dispex(&This->dispex);
250 heap_free(This);
251 }
252
253 return ref;
254 }
255
256 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface,
257 UINT *pctinfo)
258 {
259 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
260 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
261 }
262
263 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface,
264 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
265 {
266 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
267 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
268 }
269
270 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface,
271 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
272 {
273 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
274 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
275 lcid, rgDispId);
276 }
277
278 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface,
279 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
280 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
281 {
282 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
283 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
284 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
285 }
286
287 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface,
288 BSTR *String)
289 {
290 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
291 FIXME("(%p)->(%p)\n", This, String);
292 return E_NOTIMPL;
293 }
294
295 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface,
296 LONG v)
297 {
298 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
299 FIXME("(%p)->(%d)\n", This, v);
300 return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface,
304 LONG *p)
305 {
306 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
307
308 TRACE("(%p)->(%p)\n", This, p);
309
310 *p = This->len;
311 return S_OK;
312 }
313
314 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface,
315 IUnknown **p)
316 {
317 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
318 HTMLElementCollectionEnum *ret;
319
320 TRACE("(%p)->(%p)\n", This, p);
321
322 ret = heap_alloc(sizeof(*ret));
323 if(!ret)
324 return E_OUTOFMEMORY;
325
326 ret->IEnumVARIANT_iface.lpVtbl = &HTMLElementCollectionEnumVtbl;
327 ret->ref = 1;
328 ret->iter = 0;
329
330 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
331 ret->col = This;
332
333 *p = (IUnknown*)&ret->IEnumVARIANT_iface;
334 return S_OK;
335 }
336
337 static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name)
338 {
339 BSTR elem_id;
340 HRESULT hres;
341
342 hres = IHTMLElement_get_id(&elem->IHTMLElement_iface, &elem_id);
343 if(FAILED(hres)){
344 WARN("IHTMLElement_get_id failed: 0x%08x\n", hres);
345 return FALSE;
346 }
347
348 if(elem_id && !strcmpW(elem_id, name)) {
349 SysFreeString(elem_id);
350 return TRUE;
351 }
352
353 SysFreeString(elem_id);
354 return FALSE;
355 }
356
357 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
358 {
359 const PRUnichar *str;
360 nsAString nsstr;
361 BOOL ret = FALSE;
362 nsresult nsres;
363
364 static const PRUnichar nameW[] = {'n','a','m','e',0};
365
366 if(!elem->nselem)
367 return FALSE;
368
369 nsAString_Init(&nsstr, NULL);
370 nsIDOMHTMLElement_GetId(elem->nselem, &nsstr);
371 nsAString_GetData(&nsstr, &str);
372 if(!strcmpiW(str, name)) {
373 nsAString_Finish(&nsstr);
374 return TRUE;
375 }
376
377 nsres = get_elem_attr_value(elem->nselem, nameW, &nsstr, &str);
378 if(NS_SUCCEEDED(nsres)) {
379 ret = !strcmpiW(str, name);
380 nsAString_Finish(&nsstr);
381 }
382
383 return ret;
384 }
385
386 static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret)
387 {
388 if(idx < This->len) {
389 *ret = (IDispatch*)This->elems[idx];
390 IDispatch_AddRef(*ret);
391 }
392
393 return S_OK;
394 }
395
396 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface,
397 VARIANT name, VARIANT index, IDispatch **pdisp)
398 {
399 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
400 HRESULT hres = S_OK;
401
402 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
403
404 *pdisp = NULL;
405
406 switch(V_VT(&name)) {
407 case VT_I4:
408 case VT_INT:
409 if(V_I4(&name) < 0)
410 return E_INVALIDARG;
411 hres = get_item_idx(This, V_I4(&name), pdisp);
412 break;
413
414 case VT_UI4:
415 case VT_UINT:
416 hres = get_item_idx(This, V_UINT(&name), pdisp);
417 break;
418
419 case VT_BSTR: {
420 DWORD i;
421
422 if(V_VT(&index) == VT_I4) {
423 LONG idx = V_I4(&index);
424
425 if(idx < 0)
426 return E_INVALIDARG;
427
428 for(i=0; i<This->len; i++) {
429 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--)
430 break;
431 }
432
433 if(i != This->len) {
434 *pdisp = (IDispatch*)&This->elems[i]->IHTMLElement_iface;
435 IDispatch_AddRef(*pdisp);
436 }
437 }else {
438 elem_vector_t buf = {NULL, 0, 8};
439
440 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
441
442 for(i=0; i<This->len; i++) {
443 if(is_elem_name(This->elems[i], V_BSTR(&name))) {
444 node_addref(&This->elems[i]->node);
445 elem_vector_add(&buf, This->elems[i]);
446 }
447 }
448
449 if(buf.len > 1) {
450 elem_vector_normalize(&buf);
451 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len);
452 }else {
453 if(buf.len == 1) {
454 /* Already AddRef-ed */
455 *pdisp = (IDispatch*)&buf.buf[0]->IHTMLElement_iface;
456 }
457
458 heap_free(buf.buf);
459 }
460 }
461 break;
462 }
463
464 default:
465 FIXME("Unsupported name %s\n", debugstr_variant(&name));
466 hres = E_NOTIMPL;
467 }
468
469 if(SUCCEEDED(hres))
470 TRACE("returning %p\n", *pdisp);
471 return hres;
472 }
473
474 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface,
475 VARIANT tagName, IDispatch **pdisp)
476 {
477 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
478 DWORD i;
479 nsAString tag_str;
480 const PRUnichar *tag;
481 elem_vector_t buf = {NULL, 0, 8};
482
483 if(V_VT(&tagName) != VT_BSTR) {
484 WARN("Invalid arg\n");
485 return DISP_E_MEMBERNOTFOUND;
486 }
487
488 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp);
489
490 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
491
492 nsAString_Init(&tag_str, NULL);
493
494 for(i=0; i<This->len; i++) {
495 if(!This->elems[i]->nselem)
496 continue;
497
498 nsIDOMHTMLElement_GetTagName(This->elems[i]->nselem, &tag_str);
499 nsAString_GetData(&tag_str, &tag);
500
501 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1,
502 V_BSTR(&tagName), -1) == CSTR_EQUAL) {
503 node_addref(&This->elems[i]->node);
504 elem_vector_add(&buf, This->elems[i]);
505 }
506 }
507
508 nsAString_Finish(&tag_str);
509 elem_vector_normalize(&buf);
510
511 TRACE("fount %d tags\n", buf.len);
512
513 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len);
514 return S_OK;
515 }
516
517 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
518 HTMLElementCollection_QueryInterface,
519 HTMLElementCollection_AddRef,
520 HTMLElementCollection_Release,
521 HTMLElementCollection_GetTypeInfoCount,
522 HTMLElementCollection_GetTypeInfo,
523 HTMLElementCollection_GetIDsOfNames,
524 HTMLElementCollection_Invoke,
525 HTMLElementCollection_toString,
526 HTMLElementCollection_put_length,
527 HTMLElementCollection_get_length,
528 HTMLElementCollection_get__newEnum,
529 HTMLElementCollection_item,
530 HTMLElementCollection_tags
531 };
532
533 static inline HTMLElementCollection *impl_from_DispatchEx(DispatchEx *iface)
534 {
535 return CONTAINING_RECORD(iface, HTMLElementCollection, dispex);
536 }
537
538 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN
539
540 static HRESULT HTMLElementCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
541 {
542 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
543 WCHAR *ptr;
544 DWORD idx=0;
545
546 if(!*name)
547 return DISP_E_UNKNOWNNAME;
548
549 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
550 idx = idx*10 + (*ptr-'0');
551
552 if(*ptr) {
553 /* the name contains alpha characters, so search by name & id */
554 for(idx = 0; idx < This->len; ++idx) {
555 if(is_elem_id(This->elems[idx], name) ||
556 is_elem_name(This->elems[idx], name))
557 break;
558 }
559 }
560
561 if(idx >= This->len)
562 return DISP_E_UNKNOWNNAME;
563
564 *dispid = DISPID_ELEMCOL_0 + idx;
565 TRACE("ret %x\n", *dispid);
566 return S_OK;
567 }
568
569 static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
570 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
571 {
572 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
573 DWORD idx;
574
575 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
576
577 idx = id - DISPID_ELEMCOL_0;
578 if(idx >= This->len)
579 return DISP_E_UNKNOWNNAME;
580
581 switch(flags) {
582 case DISPATCH_PROPERTYGET:
583 V_VT(res) = VT_DISPATCH;
584 V_DISPATCH(res) = (IDispatch*)&This->elems[idx]->IHTMLElement_iface;
585 IHTMLElement_AddRef(&This->elems[idx]->IHTMLElement_iface);
586 break;
587 default:
588 FIXME("unimplemented flags %x\n", flags);
589 return E_NOTIMPL;
590 }
591
592 return S_OK;
593 }
594
595 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
596 NULL,
597 HTMLElementCollection_get_dispid,
598 HTMLElementCollection_invoke,
599 NULL
600 };
601
602 static const tid_t HTMLElementCollection_iface_tids[] = {
603 IHTMLElementCollection_tid,
604 0
605 };
606
607 static dispex_static_data_t HTMLElementCollection_dispex = {
608 &HTMLElementColection_dispex_vtbl,
609 DispHTMLElementCollection_tid,
610 NULL,
611 HTMLElementCollection_iface_tids
612 };
613
614 static void create_all_list(HTMLDocumentNode *doc, HTMLDOMNode *elem, elem_vector_t *buf)
615 {
616 nsIDOMNodeList *nsnode_list;
617 nsIDOMNode *iter;
618 UINT32 list_len = 0, i;
619 nsresult nsres;
620 HRESULT hres;
621
622 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list);
623 if(NS_FAILED(nsres)) {
624 ERR("GetChildNodes failed: %08x\n", nsres);
625 return;
626 }
627
628 nsIDOMNodeList_GetLength(nsnode_list, &list_len);
629 if(!list_len)
630 return;
631
632 for(i=0; i<list_len; i++) {
633 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
634 if(NS_FAILED(nsres)) {
635 ERR("Item failed: %08x\n", nsres);
636 continue;
637 }
638
639 if(is_elem_node(iter)) {
640 HTMLDOMNode *node;
641
642 hres = get_node(doc, iter, TRUE, &node);
643 if(FAILED(hres)) {
644 FIXME("get_node failed: %08x\n", hres);
645 continue;
646 }
647
648 elem_vector_add(buf, elem_from_HTMLDOMNode(node));
649 create_all_list(doc, node, buf);
650 }
651 }
652 }
653
654 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root)
655 {
656 elem_vector_t buf = {NULL, 0, 8};
657
658 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
659
660 if(include_root) {
661 node_addref(node);
662 elem_vector_add(&buf, elem_from_HTMLDOMNode(node));
663 }
664 create_all_list(node->doc, node, &buf);
665 elem_vector_normalize(&buf);
666
667 return HTMLElementCollection_Create(buf.buf, buf.len);
668 }
669
670 IHTMLElementCollection *create_collection_from_nodelist(HTMLDocumentNode *doc, nsIDOMNodeList *nslist)
671 {
672 UINT32 length = 0, i;
673 HTMLDOMNode *node;
674 elem_vector_t buf;
675 HRESULT hres;
676
677 nsIDOMNodeList_GetLength(nslist, &length);
678
679 buf.len = 0;
680 buf.size = length;
681 if(length) {
682 nsIDOMNode *nsnode;
683
684 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
685
686 for(i=0; i<length; i++) {
687 nsIDOMNodeList_Item(nslist, i, &nsnode);
688 if(is_elem_node(nsnode)) {
689 hres = get_node(doc, nsnode, TRUE, &node);
690 if(FAILED(hres))
691 continue;
692 buf.buf[buf.len++] = elem_from_HTMLDOMNode(node);
693 }
694 nsIDOMNode_Release(nsnode);
695 }
696
697 elem_vector_normalize(&buf);
698 }else {
699 buf.buf = NULL;
700 }
701
702 return HTMLElementCollection_Create(buf.buf, buf.len);
703 }
704
705 IHTMLElementCollection *create_collection_from_htmlcol(HTMLDocumentNode *doc, nsIDOMHTMLCollection *nscol)
706 {
707 UINT32 length = 0, i;
708 elem_vector_t buf;
709 HTMLDOMNode *node;
710 HRESULT hres = S_OK;
711
712 nsIDOMHTMLCollection_GetLength(nscol, &length);
713
714 buf.len = buf.size = length;
715 if(buf.len) {
716 nsIDOMNode *nsnode;
717
718 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
719
720 for(i=0; i<length; i++) {
721 nsIDOMHTMLCollection_Item(nscol, i, &nsnode);
722 hres = get_node(doc, nsnode, TRUE, &node);
723 nsIDOMNode_Release(nsnode);
724 if(FAILED(hres))
725 break;
726 buf.buf[i] = elem_from_HTMLDOMNode(node);
727 }
728 }else {
729 buf.buf = NULL;
730 }
731
732 if(FAILED(hres)) {
733 heap_free(buf.buf);
734 return NULL;
735 }
736
737 return HTMLElementCollection_Create(buf.buf, buf.len);
738 }
739
740 HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret)
741 {
742 elem_vector_t buf = {NULL, 0, 8};
743 nsIDOMNode *parent_node, *iter;
744 UINT16 parent_type;
745 HTMLDOMNode *node;
746 int i;
747 nsresult nsres;
748 HRESULT hres;
749
750 iter = elem->node.nsnode;
751 nsIDOMNode_AddRef(iter);
752
753 /* Find document or document fragment parent. */
754 while(1) {
755 nsres = nsIDOMNode_GetParentNode(iter, &parent_node);
756 nsIDOMNode_Release(iter);
757 assert(nsres == NS_OK);
758 if(!parent_node)
759 break;
760
761 nsres = nsIDOMNode_GetNodeType(parent_node, &parent_type);
762 assert(nsres == NS_OK);
763
764 if(parent_type != ELEMENT_NODE) {
765 if(parent_type != DOCUMENT_NODE && parent_type != DOCUMENT_FRAGMENT_NODE)
766 FIXME("Unexpected parent_type %d\n", parent_type);
767 break;
768 }
769
770 iter = parent_node;
771 }
772
773 if(!parent_node) {
774 *ret = -1;
775 return S_OK;
776 }
777
778 hres = get_node(elem->node.doc, parent_node, TRUE, &node);
779 nsIDOMNode_Release(parent_node);
780 if(FAILED(hres))
781 return hres;
782
783
784 /* Create all children collection and find the element in it.
785 * This could be optimized if we ever find the reason. */
786 buf.buf = heap_alloc(buf.size*sizeof(*buf.buf));
787 if(!buf.buf) {
788 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
789 return E_OUTOFMEMORY;
790 }
791
792 create_all_list(elem->node.doc, node, &buf);
793
794 for(i=0; i < buf.len; i++) {
795 if(buf.buf[i] == elem)
796 break;
797 }
798 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
799 heap_free(buf.buf);
800 if(i == buf.len) {
801 FIXME("The element is not in parent's child list?\n");
802 return E_UNEXPECTED;
803 }
804
805 *ret = i;
806 return S_OK;
807 }
808
809 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len)
810 {
811 HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection));
812
813 if (!ret)
814 return NULL;
815
816 ret->IHTMLElementCollection_iface.lpVtbl = &HTMLElementCollectionVtbl;
817 ret->ref = 1;
818 ret->elems = elems;
819 ret->len = len;
820
821 init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLElementCollection_iface,
822 &HTMLElementCollection_dispex);
823
824 TRACE("ret=%p len=%d\n", ret, len);
825
826 return &ret->IHTMLElementCollection_iface;
827 }