shell32: autocomplete: Make SetOptions handle setting the ACO_AUTOSUGGEST after Init...
[wine] / dlls / mshtml / htmlelem.c
1 /*
2  * Copyright 2006 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
20 #include <stdarg.h>
21
22 #define COBJMACROS
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "ole2.h"
29 #include "shlwapi.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 static IHTMLElementCollection *HTMLElementCollection_Create(IUnknown*,HTMLElement**,DWORD);
39
40 typedef struct {
41     HTMLElement **buf;
42     DWORD len;
43     DWORD size;
44 } elem_vector;
45
46 static void elem_vector_add(elem_vector *buf, HTMLElement *elem)
47 {
48     if(buf->len == buf->size) {
49         buf->size <<= 1;
50         buf->buf = heap_realloc(buf->buf, buf->size*sizeof(HTMLElement**));
51     }
52
53     buf->buf[buf->len++] = elem;
54 }
55
56 static void elem_vector_normalize(elem_vector *buf)
57 {
58     if(!buf->len) {
59         heap_free(buf->buf);
60         buf->buf = NULL;
61     }else if(buf->size > buf->len) {
62         buf->buf = heap_realloc(buf->buf, buf->len*sizeof(HTMLElement**));
63     }
64
65     buf->size = buf->len;
66 }
67
68 static BOOL is_elem_node(nsIDOMNode *node)
69 {
70     PRUint16 type=0;
71
72     nsIDOMNode_GetNodeType(node, &type);
73
74     return type == ELEMENT_NODE || type == COMMENT_NODE;
75 }
76
77 #define HTMLELEM_THIS(iface) DEFINE_THIS(HTMLElement, HTMLElement, iface)
78
79 #define HTMLELEM_NODE_THIS(iface) DEFINE_THIS2(HTMLElement, node, iface)
80
81 static HRESULT WINAPI HTMLElement_QueryInterface(IHTMLElement *iface,
82                                                  REFIID riid, void **ppv)
83 {
84     HTMLElement *This = HTMLELEM_THIS(iface);
85
86     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(&This->node), riid, ppv);
87 }
88
89 static ULONG WINAPI HTMLElement_AddRef(IHTMLElement *iface)
90 {
91     HTMLElement *This = HTMLELEM_THIS(iface);
92
93     return IHTMLDOMNode_AddRef(HTMLDOMNODE(&This->node));
94 }
95
96 static ULONG WINAPI HTMLElement_Release(IHTMLElement *iface)
97 {
98     HTMLElement *This = HTMLELEM_THIS(iface);
99
100     return IHTMLDOMNode_Release(HTMLDOMNODE(&This->node));
101 }
102
103 static HRESULT WINAPI HTMLElement_GetTypeInfoCount(IHTMLElement *iface, UINT *pctinfo)
104 {
105     HTMLElement *This = HTMLELEM_THIS(iface);
106     return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->node.dispex), pctinfo);
107 }
108
109 static HRESULT WINAPI HTMLElement_GetTypeInfo(IHTMLElement *iface, UINT iTInfo,
110                                               LCID lcid, ITypeInfo **ppTInfo)
111 {
112     HTMLElement *This = HTMLELEM_THIS(iface);
113     return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->node.dispex), iTInfo, lcid, ppTInfo);
114 }
115
116 static HRESULT WINAPI HTMLElement_GetIDsOfNames(IHTMLElement *iface, REFIID riid,
117                                                 LPOLESTR *rgszNames, UINT cNames,
118                                                 LCID lcid, DISPID *rgDispId)
119 {
120     HTMLElement *This = HTMLELEM_THIS(iface);
121     return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->node.dispex), riid, rgszNames, cNames, lcid, rgDispId);
122 }
123
124 static HRESULT WINAPI HTMLElement_Invoke(IHTMLElement *iface, DISPID dispIdMember,
125                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
126                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
127 {
128     HTMLElement *This = HTMLELEM_THIS(iface);
129     return IDispatchEx_Invoke(DISPATCHEX(&This->node.dispex), dispIdMember, riid, lcid,
130             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
131 }
132
133 static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttributeName,
134                                                VARIANT AttributeValue, LONG lFlags)
135 {
136     HTMLElement *This = HTMLELEM_THIS(iface);
137     nsAString attr_str;
138     nsAString value_str;
139     nsresult nsres;
140     HRESULT hres;
141     VARIANT AttributeValueChanged;
142
143     WARN("(%p)->(%s . %08x)\n", This, debugstr_w(strAttributeName), lFlags);
144
145     if(!This->nselem) {
146         FIXME("NULL nselem\n");
147         return E_NOTIMPL;
148     }
149
150     VariantInit(&AttributeValueChanged);
151
152     hres = VariantChangeType(&AttributeValueChanged, &AttributeValue, 0, VT_BSTR);
153     if (FAILED(hres)) {
154         WARN("couldn't convert input attribute value %d to VT_BSTR\n", V_VT(&AttributeValue));
155         return hres;
156     }
157
158     nsAString_Init(&attr_str, strAttributeName);
159     nsAString_Init(&value_str, V_BSTR(&AttributeValueChanged));
160
161     TRACE("setting %s to %s\n", debugstr_w(strAttributeName),
162         debugstr_w(V_BSTR(&AttributeValueChanged)));
163
164     nsres = nsIDOMHTMLElement_SetAttribute(This->nselem, &attr_str, &value_str);
165     nsAString_Finish(&attr_str);
166     nsAString_Finish(&value_str);
167
168     if(NS_SUCCEEDED(nsres)) {
169         hres = S_OK;
170     }else {
171         ERR("SetAttribute failed: %08x\n", nsres);
172         hres = E_FAIL;
173     }
174
175     return hres;
176 }
177
178 static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttributeName,
179                                                LONG lFlags, VARIANT *AttributeValue)
180 {
181     HTMLElement *This = HTMLELEM_THIS(iface);
182     nsAString attr_str;
183     nsAString value_str;
184     const PRUnichar *value;
185     nsresult nsres;
186     HRESULT hres = S_OK;
187
188     WARN("(%p)->(%s %08x %p)\n", This, debugstr_w(strAttributeName), lFlags, AttributeValue);
189
190     if(!This->nselem) {
191         FIXME("NULL nselem\n");
192         V_VT(AttributeValue) = VT_NULL;
193         return S_OK;
194     }
195
196     V_VT(AttributeValue) = VT_NULL;
197
198     nsAString_Init(&attr_str, strAttributeName);
199     nsAString_Init(&value_str, NULL);
200
201     nsres = nsIDOMHTMLElement_GetAttribute(This->nselem, &attr_str, &value_str);
202     nsAString_Finish(&attr_str);
203
204     if(NS_SUCCEEDED(nsres)) {
205         static const WCHAR wszSRC[] = {'s','r','c',0};
206         nsAString_GetData(&value_str, &value);
207         if(!strcmpiW(strAttributeName, wszSRC))
208         {
209             WCHAR buffer[256];
210             DWORD len;
211             BSTR bstrBaseUrl;
212             hres = IHTMLDocument2_get_URL(HTMLDOC(This->node.doc), &bstrBaseUrl);
213             if(SUCCEEDED(hres)) {
214                 hres = CoInternetCombineUrl(bstrBaseUrl, value,
215                                             URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
216                                             buffer, sizeof(buffer)/sizeof(WCHAR), &len, 0);
217                 SysFreeString(bstrBaseUrl);
218                 if(SUCCEEDED(hres)) {
219                     V_VT(AttributeValue) = VT_BSTR;
220                     V_BSTR(AttributeValue) = SysAllocString(buffer);
221                     TRACE("attr_value=%s\n", debugstr_w(V_BSTR(AttributeValue)));
222                 }
223             }
224         }else if(*value) {
225             V_VT(AttributeValue) = VT_BSTR;
226             V_BSTR(AttributeValue) = SysAllocString(value);
227             TRACE("attr_value=%s\n", debugstr_w(V_BSTR(AttributeValue)));
228         }
229     }else {
230         ERR("GetAttribute failed: %08x\n", nsres);
231         hres = E_FAIL;
232     }
233
234     nsAString_Finish(&value_str);
235
236     return hres;
237 }
238
239 static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strAttributeName,
240                                                   LONG lFlags, VARIANT_BOOL *pfSuccess)
241 {
242     HTMLElement *This = HTMLELEM_THIS(iface);
243     FIXME("(%p)->()\n", This);
244     return E_NOTIMPL;
245 }
246
247 static HRESULT WINAPI HTMLElement_put_className(IHTMLElement *iface, BSTR v)
248 {
249     HTMLElement *This = HTMLELEM_THIS(iface);
250     nsAString classname_str;
251     nsresult nsres;
252
253     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
254
255     if(!This->nselem) {
256         FIXME("NULL nselem\n");
257         return E_NOTIMPL;
258     }
259
260     nsAString_Init(&classname_str, v);
261     nsres = nsIDOMHTMLElement_SetClassName(This->nselem, &classname_str);
262     nsAString_Finish(&classname_str);
263     if(NS_FAILED(nsres))
264         ERR("SetClassName failed: %08x\n", nsres);
265
266     return S_OK;
267 }
268
269 static HRESULT WINAPI HTMLElement_get_className(IHTMLElement *iface, BSTR *p)
270 {
271     HTMLElement *This = HTMLELEM_THIS(iface);
272     nsAString class_str;
273     nsresult nsres;
274     HRESULT hres = S_OK;
275
276     TRACE("(%p)->(%p)\n", This, p);
277
278     if(!This->nselem) {
279         FIXME("NULL nselem\n");
280         return E_NOTIMPL;
281     }
282
283     nsAString_Init(&class_str, NULL);
284     nsres = nsIDOMHTMLElement_GetClassName(This->nselem, &class_str);
285
286     if(NS_SUCCEEDED(nsres)) {
287         const PRUnichar *class;
288         nsAString_GetData(&class_str, &class);
289         *p = *class ? SysAllocString(class) : NULL;
290     }else {
291         ERR("GetClassName failed: %08x\n", nsres);
292         hres = E_FAIL;
293     }
294
295     nsAString_Finish(&class_str);
296
297     TRACE("className=%s\n", debugstr_w(*p));
298     return hres;
299 }
300
301 static HRESULT WINAPI HTMLElement_put_id(IHTMLElement *iface, BSTR v)
302 {
303     HTMLElement *This = HTMLELEM_THIS(iface);
304     nsAString id_str;
305     nsresult nsres;
306
307     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
308
309     if(!This->nselem) {
310         FIXME("nselem == NULL\n");
311         return S_OK;
312     }
313
314     nsAString_Init(&id_str, v);
315     nsres = nsIDOMHTMLElement_SetId(This->nselem, &id_str);
316     nsAString_Finish(&id_str);
317     if(NS_FAILED(nsres))
318         ERR("SetId failed: %08x\n", nsres);
319
320     return S_OK;
321 }
322
323 static HRESULT WINAPI HTMLElement_get_id(IHTMLElement *iface, BSTR *p)
324 {
325     HTMLElement *This = HTMLELEM_THIS(iface);
326     const PRUnichar *id;
327     nsAString id_str;
328     nsresult nsres;
329
330     TRACE("(%p)->(%p)\n", This, p);
331
332     *p = NULL;
333
334     if(!This->nselem)
335         return S_OK;
336
337     nsAString_Init(&id_str, NULL);
338     nsres = nsIDOMHTMLElement_GetId(This->nselem, &id_str);
339     nsAString_GetData(&id_str, &id);
340
341     if(NS_FAILED(nsres))
342         ERR("GetId failed: %08x\n", nsres);
343     else if(*id)
344         *p = SysAllocString(id);
345
346     nsAString_Finish(&id_str);
347     return S_OK;
348 }
349
350 static HRESULT WINAPI HTMLElement_get_tagName(IHTMLElement *iface, BSTR *p)
351 {
352     HTMLElement *This = HTMLELEM_THIS(iface);
353     const PRUnichar *tag;
354     nsAString tag_str;
355     nsresult nsres;
356
357     TRACE("(%p)->(%p)\n", This, p);
358
359     if(!This->nselem) {
360         static const WCHAR comment_tagW[] = {'!',0};
361
362         WARN("NULL nselem, assuming comment\n");
363
364         *p = SysAllocString(comment_tagW);
365         return S_OK;
366     }
367
368     nsAString_Init(&tag_str, NULL);
369     nsres = nsIDOMHTMLElement_GetTagName(This->nselem, &tag_str);
370     if(NS_SUCCEEDED(nsres)) {
371         nsAString_GetData(&tag_str, &tag);
372         *p = SysAllocString(tag);
373     }else {
374         ERR("GetTagName failed: %08x\n", nsres);
375         *p = NULL;
376     }
377     nsAString_Finish(&tag_str);
378
379     return S_OK;
380 }
381
382 static HRESULT WINAPI HTMLElement_get_parentElement(IHTMLElement *iface, IHTMLElement **p)
383 {
384     HTMLElement *This = HTMLELEM_THIS(iface);
385     IHTMLDOMNode *node;
386     HRESULT hres;
387
388     TRACE("(%p)->(%p)\n", This, p);
389
390     hres = IHTMLDOMNode_get_parentNode(HTMLDOMNODE(&This->node), &node);
391     if(FAILED(hres))
392         return hres;
393
394     hres = IHTMLDOMNode_QueryInterface(node, &IID_IHTMLElement, (void**)p);
395     IHTMLDOMNode_Release(node);
396     if(FAILED(hres))
397         *p = NULL;
398
399     return S_OK;
400 }
401
402 static HRESULT WINAPI HTMLElement_get_style(IHTMLElement *iface, IHTMLStyle **p)
403 {
404     HTMLElement *This = HTMLELEM_THIS(iface);
405     nsIDOMElementCSSInlineStyle *nselemstyle;
406     nsIDOMCSSStyleDeclaration *nsstyle;
407     nsresult nsres;
408
409     TRACE("(%p)->(%p)\n", This, p);
410
411     if(!This->nselem) {
412         FIXME("NULL nselem\n");
413         return E_NOTIMPL;
414     }
415
416     nsres = nsIDOMHTMLElement_QueryInterface(This->nselem, &IID_nsIDOMElementCSSInlineStyle,
417                                              (void**)&nselemstyle);
418     if(NS_FAILED(nsres)) {
419         ERR("Coud not get nsIDOMCSSStyleDeclaration interface: %08x\n", nsres);
420         return E_FAIL;
421     }
422
423     nsres = nsIDOMElementCSSInlineStyle_GetStyle(nselemstyle, &nsstyle);
424     nsIDOMElementCSSInlineStyle_Release(nselemstyle);
425     if(NS_FAILED(nsres)) {
426         ERR("GetStyle failed: %08x\n", nsres);
427         return E_FAIL;
428     }
429
430     /* FIXME: Store style instead of creating a new instance in each call */
431     *p = HTMLStyle_Create(nsstyle);
432
433     nsIDOMCSSStyleDeclaration_Release(nsstyle);
434     return S_OK;
435 }
436
437 static HRESULT WINAPI HTMLElement_put_onhelp(IHTMLElement *iface, VARIANT v)
438 {
439     HTMLElement *This = HTMLELEM_THIS(iface);
440     FIXME("(%p)->()\n", This);
441     return E_NOTIMPL;
442 }
443
444 static HRESULT WINAPI HTMLElement_get_onhelp(IHTMLElement *iface, VARIANT *p)
445 {
446     HTMLElement *This = HTMLELEM_THIS(iface);
447     FIXME("(%p)->(%p)\n", This, p);
448     return E_NOTIMPL;
449 }
450
451 static HRESULT WINAPI HTMLElement_put_onclick(IHTMLElement *iface, VARIANT v)
452 {
453     HTMLElement *This = HTMLELEM_THIS(iface);
454
455     TRACE("(%p)->()\n", This);
456
457     return set_node_event(&This->node, EVENTID_CLICK, &v);
458 }
459
460 static HRESULT WINAPI HTMLElement_get_onclick(IHTMLElement *iface, VARIANT *p)
461 {
462     HTMLElement *This = HTMLELEM_THIS(iface);
463     FIXME("(%p)->(%p)\n", This, p);
464     return E_NOTIMPL;
465 }
466
467 static HRESULT WINAPI HTMLElement_put_ondblclick(IHTMLElement *iface, VARIANT v)
468 {
469     HTMLElement *This = HTMLELEM_THIS(iface);
470     FIXME("(%p)->()\n", This);
471     return E_NOTIMPL;
472 }
473
474 static HRESULT WINAPI HTMLElement_get_ondblclick(IHTMLElement *iface, VARIANT *p)
475 {
476     HTMLElement *This = HTMLELEM_THIS(iface);
477     FIXME("(%p)->(%p)\n", This, p);
478     return E_NOTIMPL;
479 }
480
481 static HRESULT WINAPI HTMLElement_put_onkeydown(IHTMLElement *iface, VARIANT v)
482 {
483     HTMLElement *This = HTMLELEM_THIS(iface);
484     FIXME("(%p)->()\n", This);
485     return E_NOTIMPL;
486 }
487
488 static HRESULT WINAPI HTMLElement_get_onkeydown(IHTMLElement *iface, VARIANT *p)
489 {
490     HTMLElement *This = HTMLELEM_THIS(iface);
491     FIXME("(%p)->(%p)\n", This, p);
492     return E_NOTIMPL;
493 }
494
495 static HRESULT WINAPI HTMLElement_put_onkeyup(IHTMLElement *iface, VARIANT v)
496 {
497     HTMLElement *This = HTMLELEM_THIS(iface);
498
499     TRACE("(%p)->()\n", This);
500
501     return set_node_event(&This->node, EVENTID_KEYUP, &v);
502 }
503
504 static HRESULT WINAPI HTMLElement_get_onkeyup(IHTMLElement *iface, VARIANT *p)
505 {
506     HTMLElement *This = HTMLELEM_THIS(iface);
507     FIXME("(%p)->(%p)\n", This, p);
508     return E_NOTIMPL;
509 }
510
511 static HRESULT WINAPI HTMLElement_put_onkeypress(IHTMLElement *iface, VARIANT v)
512 {
513     HTMLElement *This = HTMLELEM_THIS(iface);
514     FIXME("(%p)->()\n", This);
515     return E_NOTIMPL;
516 }
517
518 static HRESULT WINAPI HTMLElement_get_onkeypress(IHTMLElement *iface, VARIANT *p)
519 {
520     HTMLElement *This = HTMLELEM_THIS(iface);
521     FIXME("(%p)->(%p)\n", This, p);
522     return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI HTMLElement_put_onmouseout(IHTMLElement *iface, VARIANT v)
526 {
527     HTMLElement *This = HTMLELEM_THIS(iface);
528     FIXME("(%p)->()\n", This);
529     return E_NOTIMPL;
530 }
531
532 static HRESULT WINAPI HTMLElement_get_onmouseout(IHTMLElement *iface, VARIANT *p)
533 {
534     HTMLElement *This = HTMLELEM_THIS(iface);
535     FIXME("(%p)->(%p)\n", This, p);
536     return E_NOTIMPL;
537 }
538
539 static HRESULT WINAPI HTMLElement_put_onmouseover(IHTMLElement *iface, VARIANT v)
540 {
541     HTMLElement *This = HTMLELEM_THIS(iface);
542     FIXME("(%p)->()\n", This);
543     return E_NOTIMPL;
544 }
545
546 static HRESULT WINAPI HTMLElement_get_onmouseover(IHTMLElement *iface, VARIANT *p)
547 {
548     HTMLElement *This = HTMLELEM_THIS(iface);
549     FIXME("(%p)->(%p)\n", This, p);
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI HTMLElement_put_onmousemove(IHTMLElement *iface, VARIANT v)
554 {
555     HTMLElement *This = HTMLELEM_THIS(iface);
556     FIXME("(%p)->()\n", This);
557     return E_NOTIMPL;
558 }
559
560 static HRESULT WINAPI HTMLElement_get_onmousemove(IHTMLElement *iface, VARIANT *p)
561 {
562     HTMLElement *This = HTMLELEM_THIS(iface);
563     FIXME("(%p)->(%p)\n", This, p);
564     return E_NOTIMPL;
565 }
566
567 static HRESULT WINAPI HTMLElement_put_onmousedown(IHTMLElement *iface, VARIANT v)
568 {
569     HTMLElement *This = HTMLELEM_THIS(iface);
570     FIXME("(%p)->()\n", This);
571     return E_NOTIMPL;
572 }
573
574 static HRESULT WINAPI HTMLElement_get_onmousedown(IHTMLElement *iface, VARIANT *p)
575 {
576     HTMLElement *This = HTMLELEM_THIS(iface);
577     FIXME("(%p)->(%p)\n", This, p);
578     return E_NOTIMPL;
579 }
580
581 static HRESULT WINAPI HTMLElement_put_onmouseup(IHTMLElement *iface, VARIANT v)
582 {
583     HTMLElement *This = HTMLELEM_THIS(iface);
584     FIXME("(%p)->()\n", This);
585     return E_NOTIMPL;
586 }
587
588 static HRESULT WINAPI HTMLElement_get_onmouseup(IHTMLElement *iface, VARIANT *p)
589 {
590     HTMLElement *This = HTMLELEM_THIS(iface);
591     FIXME("(%p)->(%p)\n", This, p);
592     return E_NOTIMPL;
593 }
594
595 static HRESULT WINAPI HTMLElement_get_document(IHTMLElement *iface, IDispatch **p)
596 {
597     HTMLElement *This = HTMLELEM_THIS(iface);
598     FIXME("(%p)->(%p)\n", This, p);
599     return E_NOTIMPL;
600 }
601
602 static HRESULT WINAPI HTMLElement_put_title(IHTMLElement *iface, BSTR v)
603 {
604     HTMLElement *This = HTMLELEM_THIS(iface);
605     nsAString title_str;
606     nsresult nsres;
607
608     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
609
610     nsAString_Init(&title_str, v);
611     nsres = nsIDOMHTMLElement_SetTitle(This->nselem, &title_str);
612     nsAString_Finish(&title_str);
613     if(NS_FAILED(nsres))
614         ERR("SetTitle failed: %08x\n", nsres);
615
616     return S_OK;
617 }
618
619 static HRESULT WINAPI HTMLElement_get_title(IHTMLElement *iface, BSTR *p)
620 {
621     HTMLElement *This = HTMLELEM_THIS(iface);
622     nsAString title_str;
623     nsresult nsres;
624
625     TRACE("(%p)->(%p)\n", This, p);
626
627     nsAString_Init(&title_str, NULL);
628     nsres = nsIDOMHTMLElement_GetTitle(This->nselem, &title_str);
629     if(NS_SUCCEEDED(nsres)) {
630         const PRUnichar *title;
631
632         nsAString_GetData(&title_str, &title);
633         *p = *title ? SysAllocString(title) : NULL;
634     }else {
635         ERR("GetTitle failed: %08x\n", nsres);
636         return E_FAIL;
637     }
638
639     return S_OK;
640 }
641
642 static HRESULT WINAPI HTMLElement_put_language(IHTMLElement *iface, BSTR v)
643 {
644     HTMLElement *This = HTMLELEM_THIS(iface);
645     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
646     return E_NOTIMPL;
647 }
648
649 static HRESULT WINAPI HTMLElement_get_language(IHTMLElement *iface, BSTR *p)
650 {
651     HTMLElement *This = HTMLELEM_THIS(iface);
652     FIXME("(%p)->(%p)\n", This, p);
653     return E_NOTIMPL;
654 }
655
656 static HRESULT WINAPI HTMLElement_put_onselectstart(IHTMLElement *iface, VARIANT v)
657 {
658     HTMLElement *This = HTMLELEM_THIS(iface);
659     FIXME("(%p)->()\n", This);
660     return E_NOTIMPL;
661 }
662
663 static HRESULT WINAPI HTMLElement_get_onselectstart(IHTMLElement *iface, VARIANT *p)
664 {
665     HTMLElement *This = HTMLELEM_THIS(iface);
666     FIXME("(%p)->(%p)\n", This, p);
667     return E_NOTIMPL;
668 }
669
670 static HRESULT WINAPI HTMLElement_scrollIntoView(IHTMLElement *iface, VARIANT varargStart)
671 {
672     HTMLElement *This = HTMLELEM_THIS(iface);
673     FIXME("(%p)->()\n", This);
674     return E_NOTIMPL;
675 }
676
677 static HRESULT WINAPI HTMLElement_contains(IHTMLElement *iface, IHTMLElement *pChild,
678                                            VARIANT_BOOL *pfResult)
679 {
680     HTMLElement *This = HTMLELEM_THIS(iface);
681     FIXME("(%p)->(%p %p)\n", This, pChild, pfResult);
682     return E_NOTIMPL;
683 }
684
685 static HRESULT WINAPI HTMLElement_get_sourceIndex(IHTMLElement *iface, long *p)
686 {
687     HTMLElement *This = HTMLELEM_THIS(iface);
688     FIXME("(%p)->(%p)\n", This, p);
689     return E_NOTIMPL;
690 }
691
692 static HRESULT WINAPI HTMLElement_get_recordNumber(IHTMLElement *iface, VARIANT *p)
693 {
694     HTMLElement *This = HTMLELEM_THIS(iface);
695     FIXME("(%p)->(%p)\n", This, p);
696     return E_NOTIMPL;
697 }
698
699 static HRESULT WINAPI HTMLElement_put_lang(IHTMLElement *iface, BSTR v)
700 {
701     HTMLElement *This = HTMLELEM_THIS(iface);
702     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
703     return E_NOTIMPL;
704 }
705
706 static HRESULT WINAPI HTMLElement_get_lang(IHTMLElement *iface, BSTR *p)
707 {
708     HTMLElement *This = HTMLELEM_THIS(iface);
709     FIXME("(%p)->(%p)\n", This, p);
710     return E_NOTIMPL;
711 }
712
713 static HRESULT WINAPI HTMLElement_get_offsetLeft(IHTMLElement *iface, long *p)
714 {
715     HTMLElement *This = HTMLELEM_THIS(iface);
716     FIXME("(%p)->(%p)\n", This, p);
717     return E_NOTIMPL;
718 }
719
720 static HRESULT WINAPI HTMLElement_get_offsetTop(IHTMLElement *iface, long *p)
721 {
722     HTMLElement *This = HTMLELEM_THIS(iface);
723     nsIDOMNSHTMLElement *nselem;
724     PRInt32 top = 0;
725     nsresult nsres;
726
727     TRACE("(%p)->(%p)\n", This, p);
728
729     nsres = nsIDOMHTMLElement_QueryInterface(This->nselem, &IID_nsIDOMNSHTMLElement, (void**)&nselem);
730     if(NS_FAILED(nsres)) {
731         ERR("Could not get nsIDOMNSHTMLElement: %08x\n", nsres);
732         return E_FAIL;
733     }
734
735     nsres = nsIDOMNSHTMLElement_GetOffsetTop(nselem, &top);
736     nsIDOMNSHTMLElement_Release(nselem);
737     if(NS_FAILED(nsres)) {
738         ERR("GetOffsetTop failed: %08x\n", nsres);
739         return E_FAIL;
740     }
741
742     *p = top;
743     return S_OK;
744 }
745
746 static HRESULT WINAPI HTMLElement_get_offsetWidth(IHTMLElement *iface, long *p)
747 {
748     HTMLElement *This = HTMLELEM_THIS(iface);
749     FIXME("(%p)->(%p)\n", This, p);
750     return E_NOTIMPL;
751 }
752
753 static HRESULT WINAPI HTMLElement_get_offsetHeight(IHTMLElement *iface, long *p)
754 {
755     HTMLElement *This = HTMLELEM_THIS(iface);
756     nsIDOMNSHTMLElement *nselem;
757     PRInt32 offset = 0;
758     nsresult nsres;
759
760     TRACE("(%p)->(%p)\n", This, p);
761
762     nsres = nsIDOMHTMLElement_QueryInterface(This->nselem, &IID_nsIDOMNSHTMLElement, (void**)&nselem);
763     if(NS_FAILED(nsres)) {
764         ERR("Could not get nsIDOMNSHTMLElement: %08x\n", nsres);
765         return E_FAIL;
766     }
767
768     nsres = nsIDOMNSHTMLElement_GetOffsetHeight(nselem, &offset);
769     nsIDOMNSHTMLElement_Release(nselem);
770     if(NS_FAILED(nsres)) {
771         ERR("GetOffsetHeight failed: %08x\n", nsres);
772         return E_FAIL;
773     }
774
775     *p = offset;
776     return S_OK;
777 }
778
779 static HRESULT WINAPI HTMLElement_get_offsetParent(IHTMLElement *iface, IHTMLElement **p)
780 {
781     HTMLElement *This = HTMLELEM_THIS(iface);
782     FIXME("(%p)->(%p)\n", This, p);
783     return E_NOTIMPL;
784 }
785
786 static HRESULT WINAPI HTMLElement_put_innerHTML(IHTMLElement *iface, BSTR v)
787 {
788     HTMLElement *This = HTMLELEM_THIS(iface);
789     nsIDOMNSHTMLElement *nselem;
790     nsAString html_str;
791     nsresult nsres;
792
793     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
794
795     if(!This->nselem) {
796         FIXME("NULL nselem\n");
797         return E_NOTIMPL;
798     }
799
800     nsres = nsIDOMHTMLElement_QueryInterface(This->nselem, &IID_nsIDOMNSHTMLElement, (void**)&nselem);
801     if(NS_FAILED(nsres)) {
802         ERR("Could not get nsIDOMNSHTMLElement: %08x\n", nsres);
803         return E_FAIL;
804     }
805
806     nsAString_Init(&html_str, v);
807     nsres = nsIDOMNSHTMLElement_SetInnerHTML(nselem, &html_str);
808     nsAString_Finish(&html_str);
809
810     if(NS_FAILED(nsres)) {
811         FIXME("SetInnerHtml failed %08x\n", nsres);
812         return E_FAIL;
813     }
814
815     return S_OK;
816 }
817
818 static HRESULT WINAPI HTMLElement_get_innerHTML(IHTMLElement *iface, BSTR *p)
819 {
820     HTMLElement *This = HTMLELEM_THIS(iface);
821     FIXME("(%p)->(%p)\n", This, p);
822     return E_NOTIMPL;
823 }
824
825 static HRESULT WINAPI HTMLElement_put_innerText(IHTMLElement *iface, BSTR v)
826 {
827     HTMLElement *This = HTMLELEM_THIS(iface);
828     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
829     return E_NOTIMPL;
830 }
831
832 static HRESULT WINAPI HTMLElement_get_innerText(IHTMLElement *iface, BSTR *p)
833 {
834     HTMLElement *This = HTMLELEM_THIS(iface);
835     FIXME("(%p)->(%p)\n", This, p);
836     return E_NOTIMPL;
837 }
838
839 static HRESULT WINAPI HTMLElement_put_outerHTML(IHTMLElement *iface, BSTR v)
840 {
841     HTMLElement *This = HTMLELEM_THIS(iface);
842     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
843     return E_NOTIMPL;
844 }
845
846 static HRESULT WINAPI HTMLElement_get_outerHTML(IHTMLElement *iface, BSTR *p)
847 {
848     HTMLElement *This = HTMLELEM_THIS(iface);
849     FIXME("(%p)->(%p)\n", This, p);
850     return E_NOTIMPL;
851 }
852
853 static HRESULT WINAPI HTMLElement_put_outerText(IHTMLElement *iface, BSTR v)
854 {
855     HTMLElement *This = HTMLELEM_THIS(iface);
856     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
857     return E_NOTIMPL;
858 }
859
860 static HRESULT WINAPI HTMLElement_get_outerText(IHTMLElement *iface, BSTR *p)
861 {
862     HTMLElement *This = HTMLELEM_THIS(iface);
863     FIXME("(%p)->(%p)\n", This, p);
864     return E_NOTIMPL;
865 }
866
867 static HRESULT HTMLElement_InsertAdjacentNode(HTMLElement *This, BSTR where, nsIDOMNode *nsnode)
868 {
869     static const WCHAR wszBeforeBegin[] = {'b','e','f','o','r','e','B','e','g','i','n',0};
870     static const WCHAR wszAfterBegin[] = {'a','f','t','e','r','B','e','g','i','n',0};
871     static const WCHAR wszBeforeEnd[] = {'b','e','f','o','r','e','E','n','d',0};
872     static const WCHAR wszAfterEnd[] = {'a','f','t','e','r','E','n','d',0};
873     nsresult nsres;
874
875     if(!This->nselem) {
876         FIXME("NULL nselem\n");
877         return E_NOTIMPL;
878     }
879
880     if (!strcmpiW(where, wszBeforeBegin))
881     {
882         nsIDOMNode *unused;
883         nsIDOMNode *parent;
884         nsres = nsIDOMNode_GetParentNode(This->nselem, &parent);
885         if (!parent) return E_INVALIDARG;
886         nsres = nsIDOMNode_InsertBefore(parent, nsnode,
887                                         (nsIDOMNode *)This->nselem, &unused);
888         if (unused) nsIDOMNode_Release(unused);
889         nsIDOMNode_Release(parent);
890     }
891     else if (!strcmpiW(where, wszAfterBegin))
892     {
893         nsIDOMNode *unused;
894         nsIDOMNode *first_child;
895         nsIDOMNode_GetFirstChild(This->nselem, &first_child);
896         nsres = nsIDOMNode_InsertBefore(This->nselem, nsnode, first_child, &unused);
897         if (unused) nsIDOMNode_Release(unused);
898         if (first_child) nsIDOMNode_Release(first_child);
899     }
900     else if (!strcmpiW(where, wszBeforeEnd))
901     {
902         nsIDOMNode *unused;
903         nsres = nsIDOMNode_AppendChild(This->nselem, nsnode, &unused);
904         if (unused) nsIDOMNode_Release(unused);
905     }
906     else if (!strcmpiW(where, wszAfterEnd))
907     {
908         nsIDOMNode *unused;
909         nsIDOMNode *next_sibling;
910         nsIDOMNode *parent;
911         nsIDOMNode_GetParentNode(This->nselem, &parent);
912         if (!parent) return E_INVALIDARG;
913
914         nsIDOMNode_GetNextSibling(This->nselem, &next_sibling);
915         if (next_sibling)
916         {
917             nsres = nsIDOMNode_InsertBefore(parent, nsnode, next_sibling, &unused);
918             nsIDOMNode_Release(next_sibling);
919         }
920         else
921             nsres = nsIDOMNode_AppendChild(parent, nsnode, &unused);
922         nsIDOMNode_Release(parent);
923         if (unused) nsIDOMNode_Release(unused);
924     }
925     else
926     {
927         ERR("invalid where: %s\n", debugstr_w(where));
928         return E_INVALIDARG;
929     }
930
931     if (NS_FAILED(nsres))
932         return E_FAIL;
933     else
934         return S_OK;
935 }
936
937 static HRESULT WINAPI HTMLElement_insertAdjacentHTML(IHTMLElement *iface, BSTR where,
938                                                      BSTR html)
939 {
940     HTMLElement *This = HTMLELEM_THIS(iface);
941     nsresult nsres;
942     nsIDOMDocument *nsdoc;
943     nsIDOMDocumentRange *nsdocrange;
944     nsIDOMRange *range;
945     nsIDOMNSRange *nsrange;
946     nsIDOMNode *nsnode;
947     nsAString ns_html;
948     HRESULT hr;
949
950     TRACE("(%p)->(%s %s)\n", This, debugstr_w(where), debugstr_w(html));
951
952     nsres = nsIWebNavigation_GetDocument(This->node.doc->nscontainer->navigation, &nsdoc);
953     if(NS_FAILED(nsres))
954     {
955         ERR("GetDocument failed: %08x\n", nsres);
956         return E_FAIL;
957     }
958
959     nsres = nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMDocumentRange, (void **)&nsdocrange);
960     nsIDOMDocument_Release(nsdoc);
961     if(NS_FAILED(nsres))
962     {
963         ERR("getting nsIDOMDocumentRange failed: %08x\n", nsres);
964         return E_FAIL;
965     }
966     nsres = nsIDOMDocumentRange_CreateRange(nsdocrange, &range);
967     nsIDOMDocumentRange_Release(nsdocrange);
968     if(NS_FAILED(nsres))
969     {
970         ERR("CreateRange failed: %08x\n", nsres);
971         return E_FAIL;
972     }
973
974     nsIDOMRange_SetStartBefore(range, (nsIDOMNode *)This->nselem);
975
976     nsIDOMRange_QueryInterface(range, &IID_nsIDOMNSRange, (void **)&nsrange);
977     nsIDOMRange_Release(range);
978     if(NS_FAILED(nsres))
979     {
980         ERR("getting nsIDOMNSRange failed: %08x\n", nsres);
981         return E_FAIL;
982     }
983
984     nsAString_Init(&ns_html, html);
985
986     nsres = nsIDOMNSRange_CreateContextualFragment(nsrange, &ns_html, (nsIDOMDocumentFragment **)&nsnode);
987     nsIDOMNSRange_Release(nsrange);
988     nsAString_Finish(&ns_html);
989
990     if(NS_FAILED(nsres) || !nsnode)
991     {
992         ERR("CreateTextNode failed: %08x\n", nsres);
993         return E_FAIL;
994     }
995
996     hr = HTMLElement_InsertAdjacentNode(This, where, nsnode);
997     nsIDOMNode_Release(nsnode);
998
999     return hr;
1000 }
1001
1002 static HRESULT WINAPI HTMLElement_insertAdjacentText(IHTMLElement *iface, BSTR where,
1003                                                      BSTR text)
1004 {
1005     HTMLElement *This = HTMLELEM_THIS(iface);
1006     nsresult nsres;
1007     nsIDOMDocument *nsdoc;
1008     nsIDOMNode *nsnode;
1009     nsAString ns_text;
1010     HRESULT hr;
1011
1012     TRACE("(%p)->(%s %s)\n", This, debugstr_w(where), debugstr_w(text));
1013
1014     nsres = nsIWebNavigation_GetDocument(This->node.doc->nscontainer->navigation, &nsdoc);
1015     if(NS_FAILED(nsres) || !nsdoc)
1016     {
1017         ERR("GetDocument failed: %08x\n", nsres);
1018         return E_FAIL;
1019     }
1020
1021     nsAString_Init(&ns_text, text);
1022
1023     nsres = nsIDOMDocument_CreateTextNode(nsdoc, &ns_text, (nsIDOMText **)&nsnode);
1024     nsIDOMDocument_Release(nsdoc);
1025     nsAString_Finish(&ns_text);
1026
1027     if(NS_FAILED(nsres) || !nsnode)
1028     {
1029         ERR("CreateTextNode failed: %08x\n", nsres);
1030         return E_FAIL;
1031     }
1032
1033     hr = HTMLElement_InsertAdjacentNode(This, where, nsnode);
1034     nsIDOMNode_Release(nsnode);
1035
1036     return hr;
1037 }
1038
1039 static HRESULT WINAPI HTMLElement_get_parentTextEdit(IHTMLElement *iface, IHTMLElement **p)
1040 {
1041     HTMLElement *This = HTMLELEM_THIS(iface);
1042     FIXME("(%p)->(%p)\n", This, p);
1043     return E_NOTIMPL;
1044 }
1045
1046 static HRESULT WINAPI HTMLElement_get_isTextEdit(IHTMLElement *iface, VARIANT_BOOL *p)
1047 {
1048     HTMLElement *This = HTMLELEM_THIS(iface);
1049     FIXME("(%p)->(%p)\n", This, p);
1050     return E_NOTIMPL;
1051 }
1052
1053 static HRESULT WINAPI HTMLElement_click(IHTMLElement *iface)
1054 {
1055     HTMLElement *This = HTMLELEM_THIS(iface);
1056     FIXME("(%p)\n", This);
1057     return E_NOTIMPL;
1058 }
1059
1060 static HRESULT WINAPI HTMLElement_get_filters(IHTMLElement *iface,
1061                                               IHTMLFiltersCollection **p)
1062 {
1063     HTMLElement *This = HTMLELEM_THIS(iface);
1064     FIXME("(%p)->(%p)\n", This, p);
1065     return E_NOTIMPL;
1066 }
1067
1068 static HRESULT WINAPI HTMLElement_put_ondragstart(IHTMLElement *iface, VARIANT v)
1069 {
1070     HTMLElement *This = HTMLELEM_THIS(iface);
1071     FIXME("(%p)->()\n", This);
1072     return E_NOTIMPL;
1073 }
1074
1075 static HRESULT WINAPI HTMLElement_get_ondragstart(IHTMLElement *iface, VARIANT *p)
1076 {
1077     HTMLElement *This = HTMLELEM_THIS(iface);
1078     FIXME("(%p)->(%p)\n", This, p);
1079     return E_NOTIMPL;
1080 }
1081
1082 static HRESULT WINAPI HTMLElement_toString(IHTMLElement *iface, BSTR *String)
1083 {
1084     HTMLElement *This = HTMLELEM_THIS(iface);
1085     FIXME("(%p)->(%p)\n", This, String);
1086     return E_NOTIMPL;
1087 }
1088
1089 static HRESULT WINAPI HTMLElement_put_onbeforeupdate(IHTMLElement *iface, VARIANT v)
1090 {
1091     HTMLElement *This = HTMLELEM_THIS(iface);
1092     FIXME("(%p)->()\n", This);
1093     return E_NOTIMPL;
1094 }
1095
1096 static HRESULT WINAPI HTMLElement_get_onbeforeupdate(IHTMLElement *iface, VARIANT *p)
1097 {
1098     HTMLElement *This = HTMLELEM_THIS(iface);
1099     FIXME("(%p)->(%p)\n", This, p);
1100     return E_NOTIMPL;
1101 }
1102
1103 static HRESULT WINAPI HTMLElement_put_onafterupdate(IHTMLElement *iface, VARIANT v)
1104 {
1105     HTMLElement *This = HTMLELEM_THIS(iface);
1106     FIXME("(%p)->()\n", This);
1107     return E_NOTIMPL;
1108 }
1109
1110 static HRESULT WINAPI HTMLElement_get_onafterupdate(IHTMLElement *iface, VARIANT *p)
1111 {
1112     HTMLElement *This = HTMLELEM_THIS(iface);
1113     FIXME("(%p)->(%p)\n", This, p);
1114     return E_NOTIMPL;
1115 }
1116
1117 static HRESULT WINAPI HTMLElement_put_onerrorupdate(IHTMLElement *iface, VARIANT v)
1118 {
1119     HTMLElement *This = HTMLELEM_THIS(iface);
1120     FIXME("(%p)->()\n", This);
1121     return E_NOTIMPL;
1122 }
1123
1124 static HRESULT WINAPI HTMLElement_get_onerrorupdate(IHTMLElement *iface, VARIANT *p)
1125 {
1126     HTMLElement *This = HTMLELEM_THIS(iface);
1127     FIXME("(%p)->(%p)\n", This, p);
1128     return E_NOTIMPL;
1129 }
1130
1131 static HRESULT WINAPI HTMLElement_put_onrowexit(IHTMLElement *iface, VARIANT v)
1132 {
1133     HTMLElement *This = HTMLELEM_THIS(iface);
1134     FIXME("(%p)->()\n", This);
1135     return E_NOTIMPL;
1136 }
1137
1138 static HRESULT WINAPI HTMLElement_get_onrowexit(IHTMLElement *iface, VARIANT *p)
1139 {
1140     HTMLElement *This = HTMLELEM_THIS(iface);
1141     FIXME("(%p)->(%p)\n", This, p);
1142     return E_NOTIMPL;
1143 }
1144
1145 static HRESULT WINAPI HTMLElement_put_onrowenter(IHTMLElement *iface, VARIANT v)
1146 {
1147     HTMLElement *This = HTMLELEM_THIS(iface);
1148     FIXME("(%p)->()\n", This);
1149     return E_NOTIMPL;
1150 }
1151
1152 static HRESULT WINAPI HTMLElement_get_onrowenter(IHTMLElement *iface, VARIANT *p)
1153 {
1154     HTMLElement *This = HTMLELEM_THIS(iface);
1155     FIXME("(%p)->(%p)\n", This, p);
1156     return E_NOTIMPL;
1157 }
1158
1159 static HRESULT WINAPI HTMLElement_put_ondatasetchanged(IHTMLElement *iface, VARIANT v)
1160 {
1161     HTMLElement *This = HTMLELEM_THIS(iface);
1162     FIXME("(%p)->()\n", This);
1163     return E_NOTIMPL;
1164 }
1165
1166 static HRESULT WINAPI HTMLElement_get_ondatasetchanged(IHTMLElement *iface, VARIANT *p)
1167 {
1168     HTMLElement *This = HTMLELEM_THIS(iface);
1169     FIXME("(%p)->(%p)\n", This, p);
1170     return E_NOTIMPL;
1171 }
1172
1173 static HRESULT WINAPI HTMLElement_put_ondataavailable(IHTMLElement *iface, VARIANT v)
1174 {
1175     HTMLElement *This = HTMLELEM_THIS(iface);
1176     FIXME("(%p)->()\n", This);
1177     return E_NOTIMPL;
1178 }
1179
1180 static HRESULT WINAPI HTMLElement_get_ondataavailable(IHTMLElement *iface, VARIANT *p)
1181 {
1182     HTMLElement *This = HTMLELEM_THIS(iface);
1183     FIXME("(%p)->(%p)\n", This, p);
1184     return E_NOTIMPL;
1185 }
1186
1187 static HRESULT WINAPI HTMLElement_put_ondatasetcomplete(IHTMLElement *iface, VARIANT v)
1188 {
1189     HTMLElement *This = HTMLELEM_THIS(iface);
1190     FIXME("(%p)->()\n", This);
1191     return E_NOTIMPL;
1192 }
1193
1194 static HRESULT WINAPI HTMLElement_get_ondatasetcomplete(IHTMLElement *iface, VARIANT *p)
1195 {
1196     HTMLElement *This = HTMLELEM_THIS(iface);
1197     FIXME("(%p)->(%p)\n", This, p);
1198     return E_NOTIMPL;
1199 }
1200
1201 static HRESULT WINAPI HTMLElement_put_onfilterchange(IHTMLElement *iface, VARIANT v)
1202 {
1203     HTMLElement *This = HTMLELEM_THIS(iface);
1204     FIXME("(%p)->()\n", This);
1205     return E_NOTIMPL;
1206 }
1207
1208 static HRESULT WINAPI HTMLElement_get_onfilterchange(IHTMLElement *iface, VARIANT *p)
1209 {
1210     HTMLElement *This = HTMLELEM_THIS(iface);
1211     FIXME("(%p)->(%p)\n", This, p);
1212     return E_NOTIMPL;
1213 }
1214
1215 static void create_child_list(HTMLDocument *doc, HTMLElement *elem, elem_vector *buf)
1216 {
1217     nsIDOMNodeList *nsnode_list;
1218     nsIDOMNode *iter;
1219     PRUint32 list_len = 0, i;
1220     nsresult nsres;
1221
1222     nsres = nsIDOMNode_GetChildNodes(elem->node.nsnode, &nsnode_list);
1223     if(NS_FAILED(nsres)) {
1224         ERR("GetChildNodes failed: %08x\n", nsres);
1225         return;
1226     }
1227
1228     nsIDOMNodeList_GetLength(nsnode_list, &list_len);
1229     if(!list_len)
1230         return;
1231
1232     buf->size = list_len;
1233     buf->buf = heap_alloc(buf->size*sizeof(HTMLElement**));
1234
1235     for(i=0; i<list_len; i++) {
1236         nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
1237         if(NS_FAILED(nsres)) {
1238             ERR("Item failed: %08x\n", nsres);
1239             continue;
1240         }
1241
1242         if(is_elem_node(iter))
1243             elem_vector_add(buf, HTMLELEM_NODE_THIS(get_node(doc, iter, TRUE)));
1244     }
1245 }
1246
1247 static HRESULT WINAPI HTMLElement_get_children(IHTMLElement *iface, IDispatch **p)
1248 {
1249     HTMLElement *This = HTMLELEM_THIS(iface);
1250     elem_vector buf = {NULL, 0, 0};
1251
1252     TRACE("(%p)->(%p)\n", This, p);
1253
1254     create_child_list(This->node.doc, This, &buf);
1255
1256     *p = (IDispatch*)HTMLElementCollection_Create((IUnknown*)HTMLELEM(This), buf.buf, buf.len);
1257     return S_OK;
1258 }
1259
1260 static void create_all_list(HTMLDocument *doc, HTMLDOMNode *elem, elem_vector *buf)
1261 {
1262     nsIDOMNodeList *nsnode_list;
1263     nsIDOMNode *iter;
1264     PRUint32 list_len = 0, i;
1265     nsresult nsres;
1266
1267     nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list);
1268     if(NS_FAILED(nsres)) {
1269         ERR("GetChildNodes failed: %08x\n", nsres);
1270         return;
1271     }
1272
1273     nsIDOMNodeList_GetLength(nsnode_list, &list_len);
1274     if(!list_len)
1275         return;
1276
1277     for(i=0; i<list_len; i++) {
1278         nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
1279         if(NS_FAILED(nsres)) {
1280             ERR("Item failed: %08x\n", nsres);
1281             continue;
1282         }
1283
1284         if(is_elem_node(iter)) {
1285             HTMLDOMNode *node = get_node(doc, iter, TRUE);
1286
1287             elem_vector_add(buf, HTMLELEM_NODE_THIS(node));
1288             create_all_list(doc, node, buf);
1289         }
1290     }
1291 }
1292
1293 static HRESULT WINAPI HTMLElement_get_all(IHTMLElement *iface, IDispatch **p)
1294 {
1295     HTMLElement *This = HTMLELEM_THIS(iface);
1296     elem_vector buf = {NULL, 0, 8};
1297
1298     TRACE("(%p)->(%p)\n", This, p);
1299
1300     buf.buf = heap_alloc(buf.size*sizeof(HTMLElement**));
1301
1302     create_all_list(This->node.doc, &This->node, &buf);
1303     elem_vector_normalize(&buf);
1304
1305     *p = (IDispatch*)HTMLElementCollection_Create((IUnknown*)HTMLELEM(This), buf.buf, buf.len);
1306     return S_OK;
1307 }
1308
1309 #undef HTMLELEM_THIS
1310
1311 static const IHTMLElementVtbl HTMLElementVtbl = {
1312     HTMLElement_QueryInterface,
1313     HTMLElement_AddRef,
1314     HTMLElement_Release,
1315     HTMLElement_GetTypeInfoCount,
1316     HTMLElement_GetTypeInfo,
1317     HTMLElement_GetIDsOfNames,
1318     HTMLElement_Invoke,
1319     HTMLElement_setAttribute,
1320     HTMLElement_getAttribute,
1321     HTMLElement_removeAttribute,
1322     HTMLElement_put_className,
1323     HTMLElement_get_className,
1324     HTMLElement_put_id,
1325     HTMLElement_get_id,
1326     HTMLElement_get_tagName,
1327     HTMLElement_get_parentElement,
1328     HTMLElement_get_style,
1329     HTMLElement_put_onhelp,
1330     HTMLElement_get_onhelp,
1331     HTMLElement_put_onclick,
1332     HTMLElement_get_onclick,
1333     HTMLElement_put_ondblclick,
1334     HTMLElement_get_ondblclick,
1335     HTMLElement_put_onkeydown,
1336     HTMLElement_get_onkeydown,
1337     HTMLElement_put_onkeyup,
1338     HTMLElement_get_onkeyup,
1339     HTMLElement_put_onkeypress,
1340     HTMLElement_get_onkeypress,
1341     HTMLElement_put_onmouseout,
1342     HTMLElement_get_onmouseout,
1343     HTMLElement_put_onmouseover,
1344     HTMLElement_get_onmouseover,
1345     HTMLElement_put_onmousemove,
1346     HTMLElement_get_onmousemove,
1347     HTMLElement_put_onmousedown,
1348     HTMLElement_get_onmousedown,
1349     HTMLElement_put_onmouseup,
1350     HTMLElement_get_onmouseup,
1351     HTMLElement_get_document,
1352     HTMLElement_put_title,
1353     HTMLElement_get_title,
1354     HTMLElement_put_language,
1355     HTMLElement_get_language,
1356     HTMLElement_put_onselectstart,
1357     HTMLElement_get_onselectstart,
1358     HTMLElement_scrollIntoView,
1359     HTMLElement_contains,
1360     HTMLElement_get_sourceIndex,
1361     HTMLElement_get_recordNumber,
1362     HTMLElement_put_lang,
1363     HTMLElement_get_lang,
1364     HTMLElement_get_offsetLeft,
1365     HTMLElement_get_offsetTop,
1366     HTMLElement_get_offsetWidth,
1367     HTMLElement_get_offsetHeight,
1368     HTMLElement_get_offsetParent,
1369     HTMLElement_put_innerHTML,
1370     HTMLElement_get_innerHTML,
1371     HTMLElement_put_innerText,
1372     HTMLElement_get_innerText,
1373     HTMLElement_put_outerHTML,
1374     HTMLElement_get_outerHTML,
1375     HTMLElement_put_outerText,
1376     HTMLElement_get_outerText,
1377     HTMLElement_insertAdjacentHTML,
1378     HTMLElement_insertAdjacentText,
1379     HTMLElement_get_parentTextEdit,
1380     HTMLElement_get_isTextEdit,
1381     HTMLElement_click,
1382     HTMLElement_get_filters,
1383     HTMLElement_put_ondragstart,
1384     HTMLElement_get_ondragstart,
1385     HTMLElement_toString,
1386     HTMLElement_put_onbeforeupdate,
1387     HTMLElement_get_onbeforeupdate,
1388     HTMLElement_put_onafterupdate,
1389     HTMLElement_get_onafterupdate,
1390     HTMLElement_put_onerrorupdate,
1391     HTMLElement_get_onerrorupdate,
1392     HTMLElement_put_onrowexit,
1393     HTMLElement_get_onrowexit,
1394     HTMLElement_put_onrowenter,
1395     HTMLElement_get_onrowenter,
1396     HTMLElement_put_ondatasetchanged,
1397     HTMLElement_get_ondatasetchanged,
1398     HTMLElement_put_ondataavailable,
1399     HTMLElement_get_ondataavailable,
1400     HTMLElement_put_ondatasetcomplete,
1401     HTMLElement_get_ondatasetcomplete,
1402     HTMLElement_put_onfilterchange,
1403     HTMLElement_get_onfilterchange,
1404     HTMLElement_get_children,
1405     HTMLElement_get_all
1406 };
1407
1408 HRESULT HTMLElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
1409 {
1410     HTMLElement *This = HTMLELEM_NODE_THIS(iface);
1411
1412     *ppv =  NULL;
1413
1414     if(IsEqualGUID(&IID_IUnknown, riid)) {
1415         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1416         *ppv = HTMLELEM(This);
1417     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1418         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1419         *ppv = HTMLELEM(This);
1420     }else if(IsEqualGUID(&IID_IHTMLElement, riid)) {
1421         TRACE("(%p)->(IID_IHTMLElement %p)\n", This, ppv);
1422         *ppv = HTMLELEM(This);
1423     }else if(IsEqualGUID(&IID_IHTMLElement2, riid)) {
1424         TRACE("(%p)->(IID_IHTMLElement2 %p)\n", This, ppv);
1425         *ppv = HTMLELEM2(This);
1426     }else if(IsEqualGUID(&IID_IConnectionPointContainer, riid)) {
1427         TRACE("(%p)->(IID_IConnectionPointContainer %p)\n", This, ppv);
1428         *ppv = CONPTCONT(&This->cp_container);
1429     }
1430
1431     if(*ppv) {
1432         IHTMLElement_AddRef(HTMLELEM(This));
1433         return S_OK;
1434     }
1435
1436     return HTMLDOMNode_QI(&This->node, riid, ppv);
1437 }
1438
1439 void HTMLElement_destructor(HTMLDOMNode *iface)
1440 {
1441     HTMLElement *This = HTMLELEM_NODE_THIS(iface);
1442
1443     ConnectionPointContainer_Destroy(&This->cp_container);
1444
1445     if(This->nselem)
1446         nsIDOMHTMLElement_Release(This->nselem);
1447
1448     HTMLDOMNode_destructor(&This->node);
1449 }
1450
1451 static const NodeImplVtbl HTMLElementImplVtbl = {
1452     HTMLElement_QI,
1453     HTMLElement_destructor
1454 };
1455
1456 static const tid_t HTMLElement_iface_tids[] = {
1457     IHTMLDOMNode_tid,
1458     IHTMLDOMNode2_tid,
1459     IHTMLElement_tid,
1460     IHTMLElement2_tid,
1461     0
1462 };
1463
1464 static dispex_static_data_t HTMLElement_dispex = {
1465     NULL,
1466     DispHTMLUnknownElement_tid,
1467     NULL,
1468     HTMLElement_iface_tids
1469 };
1470
1471 void HTMLElement_Init(HTMLElement *This)
1472 {
1473     This->lpHTMLElementVtbl = &HTMLElementVtbl;
1474
1475     ConnectionPointContainer_Init(&This->cp_container, (IUnknown*)HTMLELEM(This));
1476
1477     HTMLElement2_Init(This);
1478
1479     if(!This->node.dispex.data)
1480         init_dispex(&This->node.dispex, (IUnknown*)HTMLELEM(This), &HTMLElement_dispex);
1481 }
1482
1483 HTMLElement *HTMLElement_Create(HTMLDocument *doc, nsIDOMNode *nsnode, BOOL use_generic)
1484 {
1485     nsIDOMHTMLElement *nselem;
1486     HTMLElement *ret = NULL;
1487     nsAString class_name_str;
1488     const PRUnichar *class_name;
1489     nsresult nsres;
1490
1491     static const WCHAR wszA[]        = {'A',0};
1492     static const WCHAR wszBODY[]     = {'B','O','D','Y',0};
1493     static const WCHAR wszIMG[]      = {'I','M','G',0};
1494     static const WCHAR wszINPUT[]    = {'I','N','P','U','T',0};
1495     static const WCHAR wszOPTION[]   = {'O','P','T','I','O','N',0};
1496     static const WCHAR wszSCRIPT[]   = {'S','C','R','I','P','T',0};
1497     static const WCHAR wszSELECT[]   = {'S','E','L','E','C','T',0};
1498     static const WCHAR wszTABLE[]    = {'T','A','B','L','E',0};
1499     static const WCHAR wszTEXTAREA[] = {'T','E','X','T','A','R','E','A',0};
1500
1501     nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMHTMLElement, (void**)&nselem);
1502     if(NS_FAILED(nsres))
1503         return NULL;
1504
1505     nsAString_Init(&class_name_str, NULL);
1506     nsIDOMHTMLElement_GetTagName(nselem, &class_name_str);
1507
1508     nsAString_GetData(&class_name_str, &class_name);
1509
1510     if(!strcmpW(class_name, wszA))
1511         ret = HTMLAnchorElement_Create(nselem);
1512     else if(!strcmpW(class_name, wszBODY))
1513         ret = HTMLBodyElement_Create(nselem);
1514     else if(!strcmpW(class_name, wszIMG))
1515         ret = HTMLImgElement_Create(nselem);
1516     else if(!strcmpW(class_name, wszINPUT))
1517         ret = HTMLInputElement_Create(nselem);
1518     else if(!strcmpW(class_name, wszOPTION))
1519         ret = HTMLOptionElement_Create(nselem);
1520     else if(!strcmpW(class_name, wszSCRIPT))
1521         ret = HTMLScriptElement_Create(nselem);
1522     else if(!strcmpW(class_name, wszSELECT))
1523         ret = HTMLSelectElement_Create(nselem);
1524     else if(!strcmpW(class_name, wszTABLE))
1525         ret = HTMLTable_Create(nselem);
1526     else if(!strcmpW(class_name, wszTEXTAREA))
1527         ret = HTMLTextAreaElement_Create(nselem);
1528     else if(use_generic)
1529         ret = HTMLGenericElement_Create(nselem);
1530
1531     if(!ret) {
1532         ret = heap_alloc_zero(sizeof(HTMLElement));
1533         HTMLElement_Init(ret);
1534         ret->node.vtbl = &HTMLElementImplVtbl;
1535     }
1536
1537     TRACE("%s ret %p\n", debugstr_w(class_name), ret);
1538
1539     nsAString_Finish(&class_name_str);
1540
1541     ret->nselem = nselem;
1542     HTMLDOMNode_Init(doc, &ret->node, (nsIDOMNode*)nselem);
1543
1544     return ret;
1545 }
1546
1547 typedef struct {
1548     DispatchEx dispex;
1549     const IHTMLElementCollectionVtbl *lpHTMLElementCollectionVtbl;
1550
1551     IUnknown *ref_unk;
1552     HTMLElement **elems;
1553     DWORD len;
1554
1555     LONG ref;
1556 } HTMLElementCollection;
1557
1558 #define HTMLELEMCOL(x)  ((IHTMLElementCollection*) &(x)->lpHTMLElementCollectionVtbl)
1559
1560 #define ELEMCOL_THIS(iface) DEFINE_THIS(HTMLElementCollection, HTMLElementCollection, iface)
1561
1562 static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface,
1563                                                            REFIID riid, void **ppv)
1564 {
1565     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1566
1567     *ppv = NULL;
1568
1569     if(IsEqualGUID(&IID_IUnknown, riid)) {
1570         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1571         *ppv = HTMLELEMCOL(This);
1572     }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) {
1573         TRACE("(%p)->(IID_IHTMLElementCollection %p)\n", This, ppv);
1574         *ppv = HTMLELEMCOL(This);
1575     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
1576         return *ppv ? S_OK : E_NOINTERFACE;
1577     }
1578
1579     if(*ppv) {
1580         IHTMLElementCollection_AddRef(HTMLELEMCOL(This));
1581         return S_OK;
1582     }
1583
1584     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1585     return E_NOINTERFACE;
1586 }
1587
1588 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface)
1589 {
1590     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1591     LONG ref = InterlockedIncrement(&This->ref);
1592
1593     TRACE("(%p) ref=%d\n", This, ref);
1594
1595     return ref;
1596 }
1597
1598 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
1599 {
1600     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1601     LONG ref = InterlockedDecrement(&This->ref);
1602
1603     TRACE("(%p) ref=%d\n", This, ref);
1604
1605     if(!ref) {
1606         IUnknown_Release(This->ref_unk);
1607         heap_free(This->elems);
1608         heap_free(This);
1609     }
1610
1611     return ref;
1612 }
1613
1614 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface,
1615                                                              UINT *pctinfo)
1616 {
1617     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1618     FIXME("(%p)->(%p)\n", This, pctinfo);
1619     return E_NOTIMPL;
1620 }
1621
1622 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface,
1623         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1624 {
1625     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1626     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1627     return E_NOTIMPL;
1628 }
1629
1630 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface,
1631         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1632 {
1633     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1634     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1635                                         lcid, rgDispId);
1636     return E_NOTIMPL;
1637 }
1638
1639 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface,
1640         DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1641         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1642 {
1643     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1644     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1645             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1646     return E_NOTIMPL;
1647 }
1648
1649 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface,
1650                                                      BSTR *String)
1651 {
1652     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1653     FIXME("(%p)->(%p)\n", This, String);
1654     return E_NOTIMPL;
1655 }
1656
1657 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface,
1658                                                        long v)
1659 {
1660     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1661     FIXME("(%p)->(%ld)\n", This, v);
1662     return E_NOTIMPL;
1663 }
1664
1665 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface,
1666                                                        long *p)
1667 {
1668     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1669
1670     TRACE("(%p)->(%p)\n", This, p);
1671
1672     *p = This->len;
1673     return S_OK;
1674 }
1675
1676 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface,
1677                                                          IUnknown **p)
1678 {
1679     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1680     FIXME("(%p)->(%p)\n", This, p);
1681     return E_NOTIMPL;
1682 }
1683
1684 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
1685 {
1686     const PRUnichar *str;
1687     nsAString nsstr, nsname;
1688     BOOL ret = FALSE;
1689     nsresult nsres;
1690
1691     static const PRUnichar nameW[] = {'n','a','m','e',0};
1692
1693     if(!elem->nselem)
1694         return FALSE;
1695
1696     nsAString_Init(&nsstr, NULL);
1697     nsIDOMHTMLElement_GetId(elem->nselem, &nsstr);
1698     nsAString_GetData(&nsstr, &str);
1699     if(!strcmpiW(str, name)) {
1700         nsAString_Finish(&nsstr);
1701         return TRUE;
1702     }
1703
1704     nsAString_Init(&nsname, nameW);
1705     nsres =  nsIDOMHTMLElement_GetAttribute(elem->nselem, &nsname, &nsstr);
1706     nsAString_Finish(&nsname);
1707     if(NS_SUCCEEDED(nsres)) {
1708         nsAString_GetData(&nsstr, &str);
1709         ret = !strcmpiW(str, name);
1710     }
1711
1712     nsAString_Finish(&nsstr);
1713     return ret;
1714 }
1715
1716 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface,
1717         VARIANT name, VARIANT index, IDispatch **pdisp)
1718 {
1719     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1720
1721     TRACE("(%p)->(v(%d) v(%d) %p)\n", This, V_VT(&name), V_VT(&index), pdisp);
1722
1723     *pdisp = NULL;
1724
1725     if(V_VT(&name) == VT_I4) {
1726         TRACE("name is VT_I4: %d\n", V_I4(&name));
1727
1728         if(V_I4(&name) < 0)
1729             return E_INVALIDARG;
1730         if(V_I4(&name) >= This->len)
1731             return S_OK;
1732
1733         *pdisp = (IDispatch*)This->elems[V_I4(&name)];
1734         IDispatch_AddRef(*pdisp);
1735         TRACE("Returning pdisp=%p\n", pdisp);
1736         return S_OK;
1737     }
1738
1739     if(V_VT(&name) == VT_BSTR) {
1740         DWORD i;
1741
1742         TRACE("name is VT_BSTR: %s\n", debugstr_w(V_BSTR(&name)));
1743
1744         if(V_VT(&index) == VT_I4) {
1745             LONG idx = V_I4(&index);
1746
1747             TRACE("index = %d\n", idx);
1748
1749             if(idx < 0)
1750                 return E_INVALIDARG;
1751
1752             for(i=0; i<This->len; i++) {
1753                 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--)
1754                     break;
1755             }
1756
1757             if(i != This->len) {
1758                 *pdisp = (IDispatch*)HTMLELEM(This->elems[i]);
1759                 IDispatch_AddRef(*pdisp);
1760             }
1761
1762             return S_OK;
1763         }else {
1764             elem_vector buf = {NULL, 0, 8};
1765
1766             buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
1767
1768             for(i=0; i<This->len; i++) {
1769                 if(is_elem_name(This->elems[i], V_BSTR(&name)))
1770                     elem_vector_add(&buf, This->elems[i]);
1771             }
1772
1773             if(buf.len > 1) {
1774                 elem_vector_normalize(&buf);
1775                 *pdisp = (IDispatch*)HTMLElementCollection_Create(This->ref_unk, buf.buf, buf.len);
1776             }else {
1777                 if(buf.len == 1) {
1778                     *pdisp = (IDispatch*)HTMLELEM(buf.buf[0]);
1779                     IDispatch_AddRef(*pdisp);
1780                 }
1781
1782                 heap_free(buf.buf);
1783             }
1784
1785             return S_OK;
1786         }
1787     }
1788
1789     FIXME("unsupported arguments\n");
1790     return E_INVALIDARG;
1791 }
1792
1793 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface,
1794                                                  VARIANT tagName, IDispatch **pdisp)
1795 {
1796     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1797     DWORD i;
1798     nsAString tag_str;
1799     const PRUnichar *tag;
1800     elem_vector buf = {NULL, 0, 8};
1801
1802     if(V_VT(&tagName) != VT_BSTR) {
1803         WARN("Invalid arg\n");
1804         return DISP_E_MEMBERNOTFOUND;
1805     }
1806
1807     TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp);
1808
1809     buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
1810
1811     nsAString_Init(&tag_str, NULL);
1812
1813     for(i=0; i<This->len; i++) {
1814         if(!This->elems[i]->nselem)
1815             continue;
1816
1817         nsIDOMElement_GetTagName(This->elems[i]->nselem, &tag_str);
1818         nsAString_GetData(&tag_str, &tag);
1819
1820         if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1,
1821                           V_BSTR(&tagName), -1) == CSTR_EQUAL)
1822             elem_vector_add(&buf, This->elems[i]);
1823     }
1824
1825     nsAString_Finish(&tag_str);
1826     elem_vector_normalize(&buf);
1827
1828     TRACE("fount %d tags\n", buf.len);
1829
1830     *pdisp = (IDispatch*)HTMLElementCollection_Create(This->ref_unk, buf.buf, buf.len);
1831     return S_OK;
1832 }
1833
1834 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN
1835
1836 static HRESULT HTMLElementCollection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
1837 {
1838     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1839     WCHAR *ptr;
1840     DWORD idx=0;
1841
1842     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
1843         idx = idx*10 + (*ptr-'0');
1844
1845     if(*ptr || idx >= This->len)
1846         return DISP_E_UNKNOWNNAME;
1847
1848     *dispid = DISPID_ELEMCOL_0 + idx;
1849     TRACE("ret %x\n", *dispid);
1850     return S_OK;
1851 }
1852
1853 static HRESULT HTMLElementCollection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
1854         VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
1855 {
1856     HTMLElementCollection *This = ELEMCOL_THIS(iface);
1857     DWORD idx;
1858
1859     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
1860
1861     idx = id - DISPID_ELEMCOL_0;
1862     if(idx >= This->len)
1863         return DISP_E_UNKNOWNNAME;
1864
1865     switch(flags) {
1866     case INVOKE_PROPERTYGET:
1867         V_VT(res) = VT_DISPATCH;
1868         V_DISPATCH(res) = (IDispatch*)HTMLELEM(This->elems[idx]);
1869         IHTMLElement_AddRef(HTMLELEM(This->elems[idx]));
1870         break;
1871     default:
1872         FIXME("unimplemented flags %x\n", flags);
1873         return E_NOTIMPL;
1874     }
1875
1876     return S_OK;
1877 }
1878
1879 #undef ELEMCOL_THIS
1880
1881 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
1882     HTMLElementCollection_QueryInterface,
1883     HTMLElementCollection_AddRef,
1884     HTMLElementCollection_Release,
1885     HTMLElementCollection_GetTypeInfoCount,
1886     HTMLElementCollection_GetTypeInfo,
1887     HTMLElementCollection_GetIDsOfNames,
1888     HTMLElementCollection_Invoke,
1889     HTMLElementCollection_toString,
1890     HTMLElementCollection_put_length,
1891     HTMLElementCollection_get_length,
1892     HTMLElementCollection_get__newEnum,
1893     HTMLElementCollection_item,
1894     HTMLElementCollection_tags
1895 };
1896
1897 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
1898     HTMLElementCollection_get_dispid,
1899     HTMLElementCollection_invoke
1900 };
1901
1902 static const tid_t HTMLElementCollection_iface_tids[] = {
1903     IHTMLElementCollection_tid,
1904     0
1905 };
1906 static dispex_static_data_t HTMLElementCollection_dispex = {
1907     &HTMLElementColection_dispex_vtbl,
1908     DispHTMLElementCollection_tid,
1909     NULL,
1910     HTMLElementCollection_iface_tids
1911 };
1912
1913 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node)
1914 {
1915     elem_vector buf = {NULL, 0, 8};
1916
1917     buf.buf = heap_alloc(buf.size*sizeof(HTMLElement**));
1918
1919     elem_vector_add(&buf, HTMLELEM_NODE_THIS(node));
1920     create_all_list(node->doc, node, &buf);
1921     elem_vector_normalize(&buf);
1922
1923     return HTMLElementCollection_Create((IUnknown*)HTMLDOMNODE(node), buf.buf, buf.len);
1924 }
1925
1926 IHTMLElementCollection *create_collection_from_nodelist(HTMLDocument *doc, IUnknown *unk, nsIDOMNodeList *nslist)
1927 {
1928     PRUint32 length = 0, i;
1929     elem_vector buf;
1930
1931     nsIDOMNodeList_GetLength(nslist, &length);
1932
1933     buf.len = buf.size = length;
1934     if(buf.len) {
1935         nsIDOMNode *nsnode;
1936
1937         buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
1938
1939         for(i=0; i<length; i++) {
1940             nsIDOMNodeList_Item(nslist, i, &nsnode);
1941             buf.buf[i] = HTMLELEM_NODE_THIS(get_node(doc, nsnode, TRUE));
1942             nsIDOMNode_Release(nsnode);
1943         }
1944     }else {
1945         buf.buf = NULL;
1946     }
1947
1948     return HTMLElementCollection_Create(unk, buf.buf, buf.len);
1949 }
1950
1951 static IHTMLElementCollection *HTMLElementCollection_Create(IUnknown *ref_unk,
1952             HTMLElement **elems, DWORD len)
1953 {
1954     HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection));
1955
1956     ret->lpHTMLElementCollectionVtbl = &HTMLElementCollectionVtbl;
1957     ret->ref = 1;
1958     ret->elems = elems;
1959     ret->len = len;
1960
1961     init_dispex(&ret->dispex, (IUnknown*)HTMLELEMCOL(ret), &HTMLElementCollection_dispex);
1962
1963     IUnknown_AddRef(ref_unk);
1964     ret->ref_unk = ref_unk;
1965
1966     TRACE("ret=%p len=%d\n", ret, len);
1967
1968     return HTMLELEMCOL(ret);
1969 }