Revert r66580 and r66579.
[reactos.git] / reactos / 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 if(IsEqualGUID(&IID_IUnknown, riid)) {
208 *ppv = &This->IHTMLElementCollection_iface;
209 }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) {
210 *ppv = &This->IHTMLElementCollection_iface;
211 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
212 return *ppv ? S_OK : E_NOINTERFACE;
213 }else {
214 *ppv = NULL;
215 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid));
216 return E_NOINTERFACE;
217 }
218
219 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
220 return S_OK;
221 }
222
223 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface)
224 {
225 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
226 LONG ref = InterlockedIncrement(&This->ref);
227
228 TRACE("(%p) ref=%d\n", This, ref);
229
230 return ref;
231 }
232
233 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
234 {
235 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
236 LONG ref = InterlockedDecrement(&This->ref);
237
238 TRACE("(%p) ref=%d\n", This, ref);
239
240 if(!ref) {
241 unsigned i;
242
243 for(i=0; i < This->len; i++)
244 node_release(&This->elems[i]->node);
245 heap_free(This->elems);
246
247 release_dispex(&This->dispex);
248 heap_free(This);
249 }
250
251 return ref;
252 }
253
254 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface,
255 UINT *pctinfo)
256 {
257 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
258 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
259 }
260
261 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface,
262 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
263 {
264 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
265 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
266 }
267
268 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface,
269 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
270 {
271 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
272 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
273 lcid, rgDispId);
274 }
275
276 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface,
277 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
278 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
279 {
280 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
281 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
282 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
283 }
284
285 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface,
286 BSTR *String)
287 {
288 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
289 FIXME("(%p)->(%p)\n", This, String);
290 return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface,
294 LONG v)
295 {
296 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
297 FIXME("(%p)->(%d)\n", This, v);
298 return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface,
302 LONG *p)
303 {
304 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
305
306 TRACE("(%p)->(%p)\n", This, p);
307
308 *p = This->len;
309 return S_OK;
310 }
311
312 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface,
313 IUnknown **p)
314 {
315 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
316 HTMLElementCollectionEnum *ret;
317
318 TRACE("(%p)->(%p)\n", This, p);
319
320 ret = heap_alloc(sizeof(*ret));
321 if(!ret)
322 return E_OUTOFMEMORY;
323
324 ret->IEnumVARIANT_iface.lpVtbl = &HTMLElementCollectionEnumVtbl;
325 ret->ref = 1;
326 ret->iter = 0;
327
328 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface);
329 ret->col = This;
330
331 *p = (IUnknown*)&ret->IEnumVARIANT_iface;
332 return S_OK;
333 }
334
335 static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name)
336 {
337 BSTR elem_id;
338 HRESULT hres;
339
340 hres = IHTMLElement_get_id(&elem->IHTMLElement_iface, &elem_id);
341 if(FAILED(hres)){
342 WARN("IHTMLElement_get_id failed: 0x%08x\n", hres);
343 return FALSE;
344 }
345
346 if(elem_id && !strcmpW(elem_id, name)) {
347 SysFreeString(elem_id);
348 return TRUE;
349 }
350
351 SysFreeString(elem_id);
352 return FALSE;
353 }
354
355 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
356 {
357 const PRUnichar *str;
358 nsAString nsstr;
359 BOOL ret = FALSE;
360 nsresult nsres;
361
362 static const PRUnichar nameW[] = {'n','a','m','e',0};
363
364 if(!elem->nselem)
365 return FALSE;
366
367 nsAString_Init(&nsstr, NULL);
368 nsIDOMHTMLElement_GetId(elem->nselem, &nsstr);
369 nsAString_GetData(&nsstr, &str);
370 if(!strcmpiW(str, name)) {
371 nsAString_Finish(&nsstr);
372 return TRUE;
373 }
374
375 nsres = get_elem_attr_value(elem->nselem, nameW, &nsstr, &str);
376 if(NS_SUCCEEDED(nsres)) {
377 ret = !strcmpiW(str, name);
378 nsAString_Finish(&nsstr);
379 }
380
381 return ret;
382 }
383
384 static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret)
385 {
386 if(idx < This->len) {
387 *ret = (IDispatch*)This->elems[idx];
388 IDispatch_AddRef(*ret);
389 }
390
391 return S_OK;
392 }
393
394 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface,
395 VARIANT name, VARIANT index, IDispatch **pdisp)
396 {
397 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
398 HRESULT hres = S_OK;
399
400 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
401
402 *pdisp = NULL;
403
404 switch(V_VT(&name)) {
405 case VT_I4:
406 if(V_I4(&name) < 0)
407 return E_INVALIDARG;
408 hres = get_item_idx(This, V_I4(&name), pdisp);
409 break;
410
411 case VT_UINT:
412 hres = get_item_idx(This, V_UINT(&name), pdisp);
413 break;
414
415 case VT_BSTR: {
416 DWORD i;
417
418 if(V_VT(&index) == VT_I4) {
419 LONG idx = V_I4(&index);
420
421 if(idx < 0)
422 return E_INVALIDARG;
423
424 for(i=0; i<This->len; i++) {
425 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--)
426 break;
427 }
428
429 if(i != This->len) {
430 *pdisp = (IDispatch*)&This->elems[i]->IHTMLElement_iface;
431 IDispatch_AddRef(*pdisp);
432 }
433 }else {
434 elem_vector_t buf = {NULL, 0, 8};
435
436 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
437
438 for(i=0; i<This->len; i++) {
439 if(is_elem_name(This->elems[i], V_BSTR(&name))) {
440 node_addref(&This->elems[i]->node);
441 elem_vector_add(&buf, This->elems[i]);
442 }
443 }
444
445 if(buf.len > 1) {
446 elem_vector_normalize(&buf);
447 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len);
448 }else {
449 if(buf.len == 1) {
450 /* Already AddRef-ed */
451 *pdisp = (IDispatch*)&buf.buf[0]->IHTMLElement_iface;
452 }
453
454 heap_free(buf.buf);
455 }
456 }
457 break;
458 }
459
460 default:
461 FIXME("Unsupported name %s\n", debugstr_variant(&name));
462 hres = E_NOTIMPL;
463 }
464
465 if(SUCCEEDED(hres))
466 TRACE("returning %p\n", *pdisp);
467 return hres;
468 }
469
470 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface,
471 VARIANT tagName, IDispatch **pdisp)
472 {
473 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface);
474 DWORD i;
475 nsAString tag_str;
476 const PRUnichar *tag;
477 elem_vector_t buf = {NULL, 0, 8};
478
479 if(V_VT(&tagName) != VT_BSTR) {
480 WARN("Invalid arg\n");
481 return DISP_E_MEMBERNOTFOUND;
482 }
483
484 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp);
485
486 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
487
488 nsAString_Init(&tag_str, NULL);
489
490 for(i=0; i<This->len; i++) {
491 if(!This->elems[i]->nselem)
492 continue;
493
494 nsIDOMHTMLElement_GetTagName(This->elems[i]->nselem, &tag_str);
495 nsAString_GetData(&tag_str, &tag);
496
497 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1,
498 V_BSTR(&tagName), -1) == CSTR_EQUAL) {
499 node_addref(&This->elems[i]->node);
500 elem_vector_add(&buf, This->elems[i]);
501 }
502 }
503
504 nsAString_Finish(&tag_str);
505 elem_vector_normalize(&buf);
506
507 TRACE("fount %d tags\n", buf.len);
508
509 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len);
510 return S_OK;
511 }
512
513 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
514 HTMLElementCollection_QueryInterface,
515 HTMLElementCollection_AddRef,
516 HTMLElementCollection_Release,
517 HTMLElementCollection_GetTypeInfoCount,
518 HTMLElementCollection_GetTypeInfo,
519 HTMLElementCollection_GetIDsOfNames,
520 HTMLElementCollection_Invoke,
521 HTMLElementCollection_toString,
522 HTMLElementCollection_put_length,
523 HTMLElementCollection_get_length,
524 HTMLElementCollection_get__newEnum,
525 HTMLElementCollection_item,
526 HTMLElementCollection_tags
527 };
528
529 static inline HTMLElementCollection *impl_from_DispatchEx(DispatchEx *iface)
530 {
531 return CONTAINING_RECORD(iface, HTMLElementCollection, dispex);
532 }
533
534 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN
535
536 static HRESULT HTMLElementCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
537 {
538 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
539 WCHAR *ptr;
540 DWORD idx=0;
541
542 if(!*name)
543 return DISP_E_UNKNOWNNAME;
544
545 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
546 idx = idx*10 + (*ptr-'0');
547
548 if(*ptr) {
549 /* the name contains alpha characters, so search by name & id */
550 for(idx = 0; idx < This->len; ++idx) {
551 if(is_elem_id(This->elems[idx], name) ||
552 is_elem_name(This->elems[idx], name))
553 break;
554 }
555 }
556
557 if(idx >= This->len)
558 return DISP_E_UNKNOWNNAME;
559
560 *dispid = DISPID_ELEMCOL_0 + idx;
561 TRACE("ret %x\n", *dispid);
562 return S_OK;
563 }
564
565 static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
566 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
567 {
568 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
569 DWORD idx;
570
571 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
572
573 idx = id - DISPID_ELEMCOL_0;
574 if(idx >= This->len)
575 return DISP_E_UNKNOWNNAME;
576
577 switch(flags) {
578 case DISPATCH_PROPERTYGET:
579 V_VT(res) = VT_DISPATCH;
580 V_DISPATCH(res) = (IDispatch*)&This->elems[idx]->IHTMLElement_iface;
581 IHTMLElement_AddRef(&This->elems[idx]->IHTMLElement_iface);
582 break;
583 default:
584 FIXME("unimplemented flags %x\n", flags);
585 return E_NOTIMPL;
586 }
587
588 return S_OK;
589 }
590
591 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
592 NULL,
593 HTMLElementCollection_get_dispid,
594 HTMLElementCollection_invoke,
595 NULL
596 };
597
598 static const tid_t HTMLElementCollection_iface_tids[] = {
599 IHTMLElementCollection_tid,
600 0
601 };
602
603 static dispex_static_data_t HTMLElementCollection_dispex = {
604 &HTMLElementColection_dispex_vtbl,
605 DispHTMLElementCollection_tid,
606 NULL,
607 HTMLElementCollection_iface_tids
608 };
609
610 static void create_all_list(HTMLDocumentNode *doc, HTMLDOMNode *elem, elem_vector_t *buf)
611 {
612 nsIDOMNodeList *nsnode_list;
613 nsIDOMNode *iter;
614 UINT32 list_len = 0, i;
615 nsresult nsres;
616 HRESULT hres;
617
618 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list);
619 if(NS_FAILED(nsres)) {
620 ERR("GetChildNodes failed: %08x\n", nsres);
621 return;
622 }
623
624 nsIDOMNodeList_GetLength(nsnode_list, &list_len);
625 if(!list_len)
626 return;
627
628 for(i=0; i<list_len; i++) {
629 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
630 if(NS_FAILED(nsres)) {
631 ERR("Item failed: %08x\n", nsres);
632 continue;
633 }
634
635 if(is_elem_node(iter)) {
636 HTMLDOMNode *node;
637
638 hres = get_node(doc, iter, TRUE, &node);
639 if(FAILED(hres)) {
640 FIXME("get_node failed: %08x\n", hres);
641 continue;
642 }
643
644 elem_vector_add(buf, elem_from_HTMLDOMNode(node));
645 create_all_list(doc, node, buf);
646 }
647 }
648 }
649
650 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root)
651 {
652 elem_vector_t buf = {NULL, 0, 8};
653
654 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
655
656 if(include_root) {
657 node_addref(node);
658 elem_vector_add(&buf, elem_from_HTMLDOMNode(node));
659 }
660 create_all_list(node->doc, node, &buf);
661 elem_vector_normalize(&buf);
662
663 return HTMLElementCollection_Create(buf.buf, buf.len);
664 }
665
666 IHTMLElementCollection *create_collection_from_nodelist(HTMLDocumentNode *doc, nsIDOMNodeList *nslist)
667 {
668 UINT32 length = 0, i;
669 HTMLDOMNode *node;
670 elem_vector_t buf;
671 HRESULT hres;
672
673 nsIDOMNodeList_GetLength(nslist, &length);
674
675 buf.len = 0;
676 buf.size = length;
677 if(length) {
678 nsIDOMNode *nsnode;
679
680 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
681
682 for(i=0; i<length; i++) {
683 nsIDOMNodeList_Item(nslist, i, &nsnode);
684 if(is_elem_node(nsnode)) {
685 hres = get_node(doc, nsnode, TRUE, &node);
686 if(FAILED(hres))
687 continue;
688 buf.buf[buf.len++] = elem_from_HTMLDOMNode(node);
689 }
690 nsIDOMNode_Release(nsnode);
691 }
692
693 elem_vector_normalize(&buf);
694 }else {
695 buf.buf = NULL;
696 }
697
698 return HTMLElementCollection_Create(buf.buf, buf.len);
699 }
700
701 IHTMLElementCollection *create_collection_from_htmlcol(HTMLDocumentNode *doc, nsIDOMHTMLCollection *nscol)
702 {
703 UINT32 length = 0, i;
704 elem_vector_t buf;
705 HTMLDOMNode *node;
706 HRESULT hres = S_OK;
707
708 nsIDOMHTMLCollection_GetLength(nscol, &length);
709
710 buf.len = buf.size = length;
711 if(buf.len) {
712 nsIDOMNode *nsnode;
713
714 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
715
716 for(i=0; i<length; i++) {
717 nsIDOMHTMLCollection_Item(nscol, i, &nsnode);
718 hres = get_node(doc, nsnode, TRUE, &node);
719 nsIDOMNode_Release(nsnode);
720 if(FAILED(hres))
721 break;
722 buf.buf[i] = elem_from_HTMLDOMNode(node);
723 }
724 }else {
725 buf.buf = NULL;
726 }
727
728 if(FAILED(hres)) {
729 heap_free(buf.buf);
730 return NULL;
731 }
732
733 return HTMLElementCollection_Create(buf.buf, buf.len);
734 }
735
736 HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret)
737 {
738 elem_vector_t buf = {NULL, 0, 8};
739 nsIDOMNode *parent_node, *iter;
740 UINT16 parent_type;
741 HTMLDOMNode *node;
742 int i;
743 nsresult nsres;
744 HRESULT hres;
745
746 iter = elem->node.nsnode;
747 nsIDOMNode_AddRef(iter);
748
749 /* Find document or document fragment parent. */
750 while(1) {
751 nsres = nsIDOMNode_GetParentNode(iter, &parent_node);
752 nsIDOMNode_Release(iter);
753 assert(nsres == NS_OK);
754 if(!parent_node)
755 break;
756
757 nsres = nsIDOMNode_GetNodeType(parent_node, &parent_type);
758 assert(nsres == NS_OK);
759
760 if(parent_type != ELEMENT_NODE) {
761 if(parent_type != DOCUMENT_NODE && parent_type != DOCUMENT_FRAGMENT_NODE)
762 FIXME("Unexpected parent_type %d\n", parent_type);
763 break;
764 }
765
766 iter = parent_node;
767 }
768
769 if(!parent_node) {
770 *ret = -1;
771 return S_OK;
772 }
773
774 hres = get_node(elem->node.doc, parent_node, TRUE, &node);
775 nsIDOMNode_Release(parent_node);
776 if(FAILED(hres))
777 return hres;
778
779
780 /* Create all children collection and find the element in it.
781 * This could be optimized if we ever find the reason. */
782 buf.buf = heap_alloc(buf.size*sizeof(*buf.buf));
783 if(!buf.buf) {
784 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
785 return E_OUTOFMEMORY;
786 }
787
788 create_all_list(elem->node.doc, node, &buf);
789
790 for(i=0; i < buf.len; i++) {
791 if(buf.buf[i] == elem)
792 break;
793 }
794 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface);
795 heap_free(buf.buf);
796 if(i == buf.len) {
797 FIXME("The element is not in parent's child list?\n");
798 return E_UNEXPECTED;
799 }
800
801 *ret = i;
802 return S_OK;
803 }
804
805 static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len)
806 {
807 HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection));
808
809 ret->IHTMLElementCollection_iface.lpVtbl = &HTMLElementCollectionVtbl;
810 ret->ref = 1;
811 ret->elems = elems;
812 ret->len = len;
813
814 init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLElementCollection_iface,
815 &HTMLElementCollection_dispex);
816
817 TRACE("ret=%p len=%d\n", ret, len);
818
819 return &ret->IHTMLElementCollection_iface;
820 }