urlmon: Fix a failing test with IE7.
[wine] / dlls / mshtml / htmlnode.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 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29
30 #include "mshtml_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
33
34 static HTMLDOMNode *get_node_obj(HTMLDocument*,IUnknown*);
35
36 typedef struct {
37     DispatchEx dispex;
38     const IHTMLDOMChildrenCollectionVtbl  *lpIHTMLDOMChildrenCollectionVtbl;
39
40     LONG ref;
41
42     /* FIXME: implement weak reference */
43     HTMLDocument *doc;
44
45     nsIDOMNodeList *nslist;
46 } HTMLDOMChildrenCollection;
47
48 #define HTMLCHILDCOL(x)  ((IHTMLDOMChildrenCollection*)  &(x)->lpIHTMLDOMChildrenCollectionVtbl)
49
50 #define HTMLCHILDCOL_THIS(iface) DEFINE_THIS(HTMLDOMChildrenCollection, IHTMLDOMChildrenCollection, iface)
51
52 static HRESULT WINAPI HTMLDOMChildrenCollection_QueryInterface(IHTMLDOMChildrenCollection *iface, REFIID riid, void **ppv)
53 {
54     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
55
56     *ppv = NULL;
57
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = HTMLCHILDCOL(This);
61     }else if(IsEqualGUID(&IID_IHTMLDOMChildrenCollection, riid)) {
62         TRACE("(%p)->(IID_IHTMLDOMChildrenCollection %p)\n", This, ppv);
63         *ppv = HTMLCHILDCOL(This);
64     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
65         return *ppv ? S_OK : E_NOINTERFACE;
66     }
67
68     if(*ppv) {
69         IUnknown_AddRef((IUnknown*)*ppv);
70         return S_OK;
71     }
72
73     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
74     return E_NOINTERFACE;
75 }
76
77 static ULONG WINAPI HTMLDOMChildrenCollection_AddRef(IHTMLDOMChildrenCollection *iface)
78 {
79     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
80     LONG ref = InterlockedIncrement(&This->ref);
81
82     TRACE("(%p) ref=%d\n", This, ref);
83
84     return ref;
85 }
86
87 static ULONG WINAPI HTMLDOMChildrenCollection_Release(IHTMLDOMChildrenCollection *iface)
88 {
89     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
90     LONG ref = InterlockedDecrement(&This->ref);
91
92     TRACE("(%p) ref=%d\n", This, ref);
93
94     if(!ref) {
95         nsIDOMNodeList_Release(This->nslist);
96         heap_free(This);
97     }
98
99     return ref;
100 }
101
102 static HRESULT WINAPI HTMLDOMChildrenCollection_GetTypeInfoCount(IHTMLDOMChildrenCollection *iface, UINT *pctinfo)
103 {
104     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
105     FIXME("(%p)->(%p)\n", This, pctinfo);
106     return E_NOTIMPL;
107 }
108
109 static HRESULT WINAPI HTMLDOMChildrenCollection_GetTypeInfo(IHTMLDOMChildrenCollection *iface, UINT iTInfo,
110         LCID lcid, ITypeInfo **ppTInfo)
111 {
112     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
113     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
114     return E_NOTIMPL;
115 }
116
117 static HRESULT WINAPI HTMLDOMChildrenCollection_GetIDsOfNames(IHTMLDOMChildrenCollection *iface, REFIID riid,
118         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
119 {
120     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
121     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
122           lcid, rgDispId);
123     return E_NOTIMPL;
124 }
125
126 static HRESULT WINAPI HTMLDOMChildrenCollection_Invoke(IHTMLDOMChildrenCollection *iface, DISPID dispIdMember,
127         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
128         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
129 {
130     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
131     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
132           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
133     return E_NOTIMPL;
134 }
135
136 static HRESULT WINAPI HTMLDOMChildrenCollection_get_length(IHTMLDOMChildrenCollection *iface, long *p)
137 {
138     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
139     PRUint32 length=0;
140
141     TRACE("(%p)->(%p)\n", This, p);
142
143     nsIDOMNodeList_GetLength(This->nslist, &length);
144     *p = length;
145     return S_OK;
146 }
147
148 static HRESULT WINAPI HTMLDOMChildrenCollection__newEnum(IHTMLDOMChildrenCollection *iface, IUnknown **p)
149 {
150     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
151     FIXME("(%p)->(%p)\n", This, p);
152     return E_NOTIMPL;
153 }
154
155 static HRESULT WINAPI HTMLDOMChildrenCollection_item(IHTMLDOMChildrenCollection *iface, long index, IDispatch **ppItem)
156 {
157     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
158     nsIDOMNode *nsnode = NULL;
159     PRUint32 length=0;
160     nsresult nsres;
161
162     TRACE("(%p)->(%ld %p)\n", This, index, ppItem);
163
164     nsIDOMNodeList_GetLength(This->nslist, &length);
165     if(index < 0 || index >= length)
166         return E_INVALIDARG;
167
168     nsres = nsIDOMNodeList_Item(This->nslist, index, &nsnode);
169     if(NS_FAILED(nsres) || !nsnode) {
170         ERR("Item failed: %08x\n", nsres);
171         return E_FAIL;
172     }
173
174     *ppItem = (IDispatch*)get_node(This->doc, nsnode, TRUE);
175     IDispatch_AddRef(*ppItem);
176     return S_OK;
177 }
178
179 #define DISPID_CHILDCOL_0 MSHTML_DISPID_CUSTOM_MIN
180
181 static HRESULT HTMLDOMChildrenCollection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
182 {
183     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
184     WCHAR *ptr;
185     DWORD idx=0;
186     PRUint32 len = 0;
187
188     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
189         idx = idx*10 + (*ptr-'0');
190     if(*ptr)
191         return DISP_E_UNKNOWNNAME;
192
193     nsIDOMNodeList_GetLength(This->nslist, &len);
194     if(idx >= len)
195         return DISP_E_UNKNOWNNAME;
196
197     *dispid = DISPID_CHILDCOL_0 + idx;
198     TRACE("ret %x\n", *dispid);
199     return S_OK;
200 }
201
202 static HRESULT HTMLDOMChildrenCollection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
203         VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
204 {
205     HTMLDOMChildrenCollection *This = HTMLCHILDCOL_THIS(iface);
206
207     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
208
209     switch(flags) {
210     case INVOKE_PROPERTYGET: {
211         IDispatch *disp = NULL;
212         HRESULT hres;
213
214         hres = IHTMLDOMChildrenCollection_item(HTMLCHILDCOL(This), id - DISPID_CHILDCOL_0, &disp);
215         if(0&&FAILED(hres))
216             return hres;
217
218         V_VT(res) = VT_DISPATCH;
219         V_DISPATCH(res) = disp;
220         break;
221     }
222
223     default:
224         FIXME("unimplemented flags %x\n", flags);
225         return E_NOTIMPL;
226     }
227
228     return S_OK;
229 }
230
231 #undef HTMLCHILDCOL_THIS
232
233 static const IHTMLDOMChildrenCollectionVtbl HTMLDOMChildrenCollectionVtbl = {
234     HTMLDOMChildrenCollection_QueryInterface,
235     HTMLDOMChildrenCollection_AddRef,
236     HTMLDOMChildrenCollection_Release,
237     HTMLDOMChildrenCollection_GetTypeInfoCount,
238     HTMLDOMChildrenCollection_GetTypeInfo,
239     HTMLDOMChildrenCollection_GetIDsOfNames,
240     HTMLDOMChildrenCollection_Invoke,
241     HTMLDOMChildrenCollection_get_length,
242     HTMLDOMChildrenCollection__newEnum,
243     HTMLDOMChildrenCollection_item
244 };
245
246 static const tid_t HTMLDOMChildrenCollection_iface_tids[] = {
247     IHTMLDOMChildrenCollection_tid,
248     0
249 };
250
251 static const dispex_static_data_vtbl_t HTMLDOMChildrenCollection_dispex_vtbl = {
252     HTMLDOMChildrenCollection_get_dispid,
253     HTMLDOMChildrenCollection_invoke
254 };
255
256 static dispex_static_data_t HTMLDOMChildrenCollection_dispex = {
257     &HTMLDOMChildrenCollection_dispex_vtbl,
258     DispDOMChildrenCollection_tid,
259     NULL,
260     HTMLDOMChildrenCollection_iface_tids
261 };
262
263 static IHTMLDOMChildrenCollection *create_child_collection(HTMLDocument *doc, nsIDOMNodeList *nslist)
264 {
265     HTMLDOMChildrenCollection *ret;
266
267     ret = heap_alloc_zero(sizeof(*ret));
268     ret->lpIHTMLDOMChildrenCollectionVtbl = &HTMLDOMChildrenCollectionVtbl;
269     ret->ref = 1;
270
271     nsIDOMNodeList_AddRef(nslist);
272     ret->nslist = nslist;
273     ret->doc = doc;
274
275     init_dispex(&ret->dispex, (IUnknown*)HTMLCHILDCOL(ret), &HTMLDOMChildrenCollection_dispex);
276
277     return HTMLCHILDCOL(ret);
278 }
279
280 #define HTMLDOMNODE_THIS(iface) DEFINE_THIS(HTMLDOMNode, HTMLDOMNode, iface)
281
282 static HRESULT WINAPI HTMLDOMNode_QueryInterface(IHTMLDOMNode *iface,
283                                                  REFIID riid, void **ppv)
284 {
285     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
286
287     return This->vtbl->qi(This, riid, ppv);
288 }
289
290 static ULONG WINAPI HTMLDOMNode_AddRef(IHTMLDOMNode *iface)
291 {
292     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
293     LONG ref = InterlockedIncrement(&This->ref);
294
295     TRACE("(%p) ref=%d\n", This, ref);
296
297     return ref;
298 }
299
300 static ULONG WINAPI HTMLDOMNode_Release(IHTMLDOMNode *iface)
301 {
302     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
303     LONG ref = InterlockedDecrement(&This->ref);
304
305     TRACE("(%p) ref=%d\n", This, ref);
306
307     if(!ref) {
308         This->vtbl->destructor(This);
309         heap_free(This);
310     }
311
312     return ref;
313 }
314
315 static HRESULT WINAPI HTMLDOMNode_GetTypeInfoCount(IHTMLDOMNode *iface, UINT *pctinfo)
316 {
317     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
318     FIXME("(%p)->(%p)\n", This, pctinfo);
319     return E_NOTIMPL;
320 }
321
322 static HRESULT WINAPI HTMLDOMNode_GetTypeInfo(IHTMLDOMNode *iface, UINT iTInfo,
323                                               LCID lcid, ITypeInfo **ppTInfo)
324 {
325     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
326     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
327     return E_NOTIMPL;
328 }
329
330 static HRESULT WINAPI HTMLDOMNode_GetIDsOfNames(IHTMLDOMNode *iface, REFIID riid,
331                                                 LPOLESTR *rgszNames, UINT cNames,
332                                                 LCID lcid, DISPID *rgDispId)
333 {
334     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
335     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
336                                         lcid, rgDispId);
337     return E_NOTIMPL;
338 }
339
340 static HRESULT WINAPI HTMLDOMNode_Invoke(IHTMLDOMNode *iface, DISPID dispIdMember,
341                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
342                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
343 {
344     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
345     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
346             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT WINAPI HTMLDOMNode_get_nodeType(IHTMLDOMNode *iface, long *p)
351 {
352     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
353     PRUint16 type = -1;
354
355     TRACE("(%p)->(%p)\n", This, p);
356
357     nsIDOMNode_GetNodeType(This->nsnode, &type);
358
359     switch(type) {
360     case ELEMENT_NODE:
361         *p = 1;
362         break;
363     case TEXT_NODE:
364         *p = 3;
365         break;
366     case COMMENT_NODE:
367         *p = 8;
368         break;
369     case DOCUMENT_NODE:
370         *p = 9;
371         break;
372     default:
373         /*
374          * FIXME:
375          * According to MSDN only ELEMENT_NODE and TEXT_NODE are supported.
376          * It needs more tests.
377          */
378         FIXME("type %u\n", type);
379         *p = 0;
380     }
381
382     return S_OK;
383 }
384
385 static HRESULT WINAPI HTMLDOMNode_get_parentNode(IHTMLDOMNode *iface, IHTMLDOMNode **p)
386 {
387     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
388     HTMLDOMNode *node;
389     nsIDOMNode *nsnode;
390     nsresult nsres;
391
392     TRACE("(%p)->(%p)\n", This, p);
393
394     nsres = nsIDOMNode_GetParentNode(This->nsnode, &nsnode);
395     if(NS_FAILED(nsres)) {
396         ERR("GetParentNode failed: %08x\n", nsres);
397         return E_FAIL;
398     }
399
400     if(!nsnode) {
401         *p = NULL;
402         return S_OK;
403     }
404
405     node = get_node(This->doc, nsnode, TRUE);
406     *p = HTMLDOMNODE(node);
407     IHTMLDOMNode_AddRef(*p);
408     return S_OK;
409 }
410
411 static HRESULT WINAPI HTMLDOMNode_hasChildNodes(IHTMLDOMNode *iface, VARIANT_BOOL *fChildren)
412 {
413     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
414     PRBool has_child = FALSE;
415     nsresult nsres;
416
417     TRACE("(%p)->(%p)\n", This, fChildren);
418
419     nsres = nsIDOMNode_HasChildNodes(This->nsnode, &has_child);
420     if(NS_FAILED(nsres))
421         ERR("HasChildNodes failed: %08x\n", nsres);
422
423     *fChildren = has_child ? VARIANT_TRUE : VARIANT_FALSE;
424     return S_OK;
425 }
426
427 static HRESULT WINAPI HTMLDOMNode_get_childNodes(IHTMLDOMNode *iface, IDispatch **p)
428 {
429     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
430     nsIDOMNodeList *nslist;
431     nsresult nsres;
432
433     TRACE("(%p)->(%p)\n", This, p);
434
435     nsres = nsIDOMNode_GetChildNodes(This->nsnode, &nslist);
436     if(NS_FAILED(nsres)) {
437         ERR("GetChildNodes failed: %08x\n", nsres);
438         return E_FAIL;
439     }
440
441     *p = (IDispatch*)create_child_collection(This->doc, nslist);
442     nsIDOMNodeList_Release(nslist);
443
444     return S_OK;
445 }
446
447 static HRESULT WINAPI HTMLDOMNode_get_attributes(IHTMLDOMNode *iface, IDispatch **p)
448 {
449     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
450     FIXME("(%p)->(%p)\n", This, p);
451     return E_NOTIMPL;
452 }
453
454 static HRESULT WINAPI HTMLDOMNode_insertBefore(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
455                                                VARIANT refChild, IHTMLDOMNode **node)
456 {
457     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
458     FIXME("(%p)->(%p v %p)\n", This, newChild, node);
459     return E_NOTIMPL;
460 }
461
462 static HRESULT WINAPI HTMLDOMNode_removeChild(IHTMLDOMNode *iface, IHTMLDOMNode *oldChild,
463                                               IHTMLDOMNode **node)
464 {
465     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
466     HTMLDOMNode *node_obj;
467     nsIDOMNode *nsnode;
468     nsresult nsres;
469
470     TRACE("(%p)->(%p %p)\n", This, oldChild, node);
471
472     node_obj = get_node_obj(This->doc, (IUnknown*)oldChild);
473     if(!node_obj)
474         return E_FAIL;
475
476     nsres = nsIDOMNode_RemoveChild(This->nsnode, node_obj->nsnode, &nsnode);
477     if(NS_FAILED(nsres)) {
478         ERR("RemoveChild failed: %08x\n", nsres);
479         return E_FAIL;
480     }
481
482     /* FIXME: Make sure that node != newChild */
483     *node = HTMLDOMNODE(get_node(This->doc, nsnode, TRUE));
484     IHTMLDOMNode_AddRef(*node);
485     return S_OK;
486 }
487
488 static HRESULT WINAPI HTMLDOMNode_replaceChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
489                                                IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
490 {
491     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
492     FIXME("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
493     return E_NOTIMPL;
494 }
495
496 static HRESULT WINAPI HTMLDOMNode_cloneNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
497                                             IHTMLDOMNode **clonedNode)
498 {
499     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
500     FIXME("(%p)->(%x %p)\n", This, fDeep, clonedNode);
501     return E_NOTIMPL;
502 }
503
504 static HRESULT WINAPI HTMLDOMNode_removeNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
505                                              IHTMLDOMNode **removed)
506 {
507     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
508     FIXME("(%p)->(%x %p)\n", This, fDeep, removed);
509     return E_NOTIMPL;
510 }
511
512 static HRESULT WINAPI HTMLDOMNode_swapNode(IHTMLDOMNode *iface, IHTMLDOMNode *otherNode,
513                                            IHTMLDOMNode **swappedNode)
514 {
515     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
516     FIXME("(%p)->(%p %p)\n", This, otherNode, swappedNode);
517     return E_NOTIMPL;
518 }
519
520 static HRESULT WINAPI HTMLDOMNode_replaceNode(IHTMLDOMNode *iface, IHTMLDOMNode *replacement,
521                                               IHTMLDOMNode **replaced)
522 {
523     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
524     FIXME("(%p)->(%p %p)\n", This, replacement, replaced);
525     return E_NOTIMPL;
526 }
527
528 static HRESULT WINAPI HTMLDOMNode_appendChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
529                                               IHTMLDOMNode **node)
530 {
531     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
532     HTMLDOMNode *node_obj;
533     nsIDOMNode *nsnode;
534     nsresult nsres;
535
536     TRACE("(%p)->(%p %p)\n", This, newChild, node);
537
538     node_obj = get_node_obj(This->doc, (IUnknown*)newChild);
539     if(!node_obj)
540         return E_FAIL;
541
542     nsres = nsIDOMNode_AppendChild(This->nsnode, node_obj->nsnode, &nsnode);
543     if(NS_FAILED(nsres)) {
544         ERR("AppendChild failed: %08x\n", nsres);
545         return E_FAIL;
546     }
547
548     /* FIXME: Make sure that node != newChild */
549     *node = HTMLDOMNODE(get_node(This->doc, nsnode, TRUE));
550     IHTMLDOMNode_AddRef(*node);
551     return S_OK;
552 }
553
554 static HRESULT WINAPI HTMLDOMNode_get_nodeName(IHTMLDOMNode *iface, BSTR *p)
555 {
556     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
557
558     TRACE("(%p)->(%p)\n", This, p);
559
560     *p = NULL;
561
562     if(This->nsnode) {
563         nsAString name_str;
564         const PRUnichar *name;
565         nsresult nsres;
566
567         nsAString_Init(&name_str, NULL);
568         nsres = nsIDOMNode_GetNodeName(This->nsnode, &name_str);
569
570         if(NS_SUCCEEDED(nsres)) {
571             nsAString_GetData(&name_str, &name);
572             *p = SysAllocString(name);
573         }else {
574             ERR("GetNodeName failed: %08x\n", nsres);
575         }
576
577         nsAString_Finish(&name_str);
578     }
579
580     return S_OK;
581 }
582
583 static HRESULT WINAPI HTMLDOMNode_put_nodeValue(IHTMLDOMNode *iface, VARIANT v)
584 {
585     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
586
587     TRACE("(%p)->()\n", This);
588
589     switch(V_VT(&v)) {
590     case VT_BSTR: {
591         nsAString val_str;
592
593         TRACE("bstr %s\n", debugstr_w(V_BSTR(&v)));
594
595         nsAString_Init(&val_str, V_BSTR(&v));
596         nsIDOMNode_SetNodeValue(This->nsnode, &val_str);
597         nsAString_Finish(&val_str);
598
599         return S_OK;
600     }
601
602     default:
603         FIXME("unsupported vt %d\n", V_VT(&v));
604     }
605
606     return E_NOTIMPL;
607 }
608
609 static HRESULT WINAPI HTMLDOMNode_get_nodeValue(IHTMLDOMNode *iface, VARIANT *p)
610 {
611     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
612     const PRUnichar *val;
613     nsAString val_str;
614
615     TRACE("(%p)->(%p)\n", This, p);
616
617     nsAString_Init(&val_str, NULL);
618     nsIDOMNode_GetNodeValue(This->nsnode, &val_str);
619     nsAString_GetData(&val_str, &val);
620
621     if(*val) {
622         V_VT(p) = VT_BSTR;
623         V_BSTR(p) = SysAllocString(val);
624     }else {
625         V_VT(p) = VT_NULL;
626     }
627
628     nsAString_Finish(&val_str);
629
630     return S_OK;
631 }
632
633 static HRESULT WINAPI HTMLDOMNode_get_firstChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
634 {
635     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
636     nsIDOMNode *nschild = NULL;
637
638     TRACE("(%p)->(%p)\n", This, p);
639
640     nsIDOMNode_GetFirstChild(This->nsnode, &nschild);
641     if(nschild) {
642         *p = HTMLDOMNODE(get_node(This->doc, nschild, TRUE));
643         IHTMLDOMNode_AddRef(*p);
644     }else {
645         *p = NULL;
646     }
647
648     return S_OK;
649 }
650
651 static HRESULT WINAPI HTMLDOMNode_get_lastChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
652 {
653     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
654     nsIDOMNode *nschild = NULL;
655
656     TRACE("(%p)->(%p)\n", This, p);
657
658     nsIDOMNode_GetLastChild(This->nsnode, &nschild);
659     if(nschild) {
660         *p = HTMLDOMNODE(get_node(This->doc, nschild, TRUE));
661         IHTMLDOMNode_AddRef(*p);
662     }else {
663         *p = NULL;
664     }
665
666     return S_OK;
667 }
668
669 static HRESULT WINAPI HTMLDOMNode_get_previousSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
670 {
671     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
672     FIXME("(%p)->(%p)\n", This, p);
673     return E_NOTIMPL;
674 }
675
676 static HRESULT WINAPI HTMLDOMNode_get_nextSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
677 {
678     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
679     FIXME("(%p)->(%p)\n", This, p);
680     return E_NOTIMPL;
681 }
682
683 #undef HTMLDOMNODE_THIS
684
685 static const IHTMLDOMNodeVtbl HTMLDOMNodeVtbl = {
686     HTMLDOMNode_QueryInterface,
687     HTMLDOMNode_AddRef,
688     HTMLDOMNode_Release,
689     HTMLDOMNode_GetTypeInfoCount,
690     HTMLDOMNode_GetTypeInfo,
691     HTMLDOMNode_GetIDsOfNames,
692     HTMLDOMNode_Invoke,
693     HTMLDOMNode_get_nodeType,
694     HTMLDOMNode_get_parentNode,
695     HTMLDOMNode_hasChildNodes,
696     HTMLDOMNode_get_childNodes,
697     HTMLDOMNode_get_attributes,
698     HTMLDOMNode_insertBefore,
699     HTMLDOMNode_removeChild,
700     HTMLDOMNode_replaceChild,
701     HTMLDOMNode_cloneNode,
702     HTMLDOMNode_removeNode,
703     HTMLDOMNode_swapNode,
704     HTMLDOMNode_replaceNode,
705     HTMLDOMNode_appendChild,
706     HTMLDOMNode_get_nodeName,
707     HTMLDOMNode_put_nodeValue,
708     HTMLDOMNode_get_nodeValue,
709     HTMLDOMNode_get_firstChild,
710     HTMLDOMNode_get_lastChild,
711     HTMLDOMNode_get_previousSibling,
712     HTMLDOMNode_get_nextSibling
713 };
714
715 #define HTMLDOMNODE2_THIS(iface) DEFINE_THIS(HTMLDOMNode, HTMLDOMNode2, iface)
716
717 static HRESULT WINAPI HTMLDOMNode2_QueryInterface(IHTMLDOMNode2 *iface,
718         REFIID riid, void **ppv)
719 {
720     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
721
722     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(This), riid, ppv);
723 }
724
725 static ULONG WINAPI HTMLDOMNode2_AddRef(IHTMLDOMNode2 *iface)
726 {
727     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
728
729     return IHTMLDOMNode_AddRef(HTMLDOMNODE(This));
730 }
731
732 static ULONG WINAPI HTMLDOMNode2_Release(IHTMLDOMNode2 *iface)
733 {
734     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
735
736     return IHTMLDOMNode_Release(HTMLDOMNODE(This));
737 }
738
739 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfoCount(IHTMLDOMNode2 *iface, UINT *pctinfo)
740 {
741     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
742     FIXME("(%p)->(%p)\n", This, pctinfo);
743     return E_NOTIMPL;
744 }
745
746 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfo(IHTMLDOMNode2 *iface, UINT iTInfo,
747         LCID lcid, ITypeInfo **ppTInfo)
748 {
749     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
750     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
751     return E_NOTIMPL;
752 }
753
754 static HRESULT WINAPI HTMLDOMNode2_GetIDsOfNames(IHTMLDOMNode2 *iface, REFIID riid,
755                                                 LPOLESTR *rgszNames, UINT cNames,
756                                                 LCID lcid, DISPID *rgDispId)
757 {
758     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
759     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
760           lcid, rgDispId);
761     return E_NOTIMPL;
762 }
763
764 static HRESULT WINAPI HTMLDOMNode2_Invoke(IHTMLDOMNode2 *iface, DISPID dispIdMember,
765         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
766         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
767 {
768     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
769     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
770             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
771     return E_NOTIMPL;
772 }
773
774 static HRESULT WINAPI HTMLDOMNode2_get_ownerDocument(IHTMLDOMNode2 *iface, IDispatch **p)
775 {
776     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
777     FIXME("(%p)->(%p)\n", This, p);
778     return E_NOTIMPL;
779 }
780
781 #undef HTMLDOMNODE2_THIS
782
783 static const IHTMLDOMNode2Vtbl HTMLDOMNode2Vtbl = {
784     HTMLDOMNode2_QueryInterface,
785     HTMLDOMNode2_AddRef,
786     HTMLDOMNode2_Release,
787     HTMLDOMNode2_GetTypeInfoCount,
788     HTMLDOMNode2_GetTypeInfo,
789     HTMLDOMNode2_GetIDsOfNames,
790     HTMLDOMNode2_Invoke,
791     HTMLDOMNode2_get_ownerDocument
792 };
793
794 HRESULT HTMLDOMNode_QI(HTMLDOMNode *This, REFIID riid, void **ppv)
795 {
796     *ppv = NULL;
797
798     if(IsEqualGUID(&IID_IUnknown, riid)) {
799         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
800         *ppv = HTMLDOMNODE(This);
801     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
802         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
803         *ppv = HTMLDOMNODE(This);
804     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
805         if(This->dispex.data) {
806             TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
807             *ppv = DISPATCHEX(&This->dispex);
808         }else {
809             FIXME("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
810             return E_NOINTERFACE;
811         }
812     }else if(IsEqualGUID(&IID_IHTMLDOMNode, riid)) {
813         TRACE("(%p)->(IID_IHTMLDOMNode %p)\n", This, ppv);
814         *ppv = HTMLDOMNODE(This);
815     }else if(IsEqualGUID(&IID_IHTMLDOMNode2, riid)) {
816         TRACE("(%p)->(IID_IHTMLDOMNode2 %p)\n", This, ppv);
817         *ppv = HTMLDOMNODE2(This);
818     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
819         return *ppv ? S_OK : E_NOINTERFACE;
820     }
821
822     if(*ppv) {
823         IUnknown_AddRef((IUnknown*)*ppv);
824         return S_OK;
825     }
826
827     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
828     return E_NOINTERFACE;
829 }
830
831 void HTMLDOMNode_destructor(HTMLDOMNode *This)
832 {
833     if(This->nsnode)
834         nsIDOMNode_Release(This->nsnode);
835     if(This->event_target)
836         release_event_target(This->event_target);
837 }
838
839 static const NodeImplVtbl HTMLDOMNodeImplVtbl = {
840     HTMLDOMNode_QI,
841     HTMLDOMNode_destructor
842 };
843
844 void HTMLDOMNode_Init(HTMLDocument *doc, HTMLDOMNode *node, nsIDOMNode *nsnode)
845 {
846     node->lpHTMLDOMNodeVtbl = &HTMLDOMNodeVtbl;
847     node->lpHTMLDOMNode2Vtbl = &HTMLDOMNode2Vtbl;
848     node->ref = 1;
849     node->doc = doc;
850
851     nsIDOMNode_AddRef(nsnode);
852     node->nsnode = nsnode;
853
854     node->next = doc->nodes;
855     doc->nodes = node;
856 }
857
858 static HTMLDOMNode *create_node(HTMLDocument *doc, nsIDOMNode *nsnode)
859 {
860     HTMLDOMNode *ret;
861     PRUint16 node_type;
862
863     nsIDOMNode_GetNodeType(nsnode, &node_type);
864
865     switch(node_type) {
866     case ELEMENT_NODE:
867         ret = &HTMLElement_Create(doc, nsnode, FALSE)->node;
868         break;
869     case TEXT_NODE:
870         ret = HTMLDOMTextNode_Create(doc, nsnode);
871         break;
872     case COMMENT_NODE:
873         ret = &HTMLCommentElement_Create(doc, nsnode)->node;
874         break;
875     default:
876         ret = heap_alloc_zero(sizeof(HTMLDOMNode));
877         ret->vtbl = &HTMLDOMNodeImplVtbl;
878         HTMLDOMNode_Init(doc, ret, nsnode);
879     }
880
881     TRACE("type %d ret %p\n", node_type, ret);
882
883     return ret;
884 }
885
886 /*
887  * FIXME
888  * List looks really ugly here. We should use a better data structure or
889  * (better) find a way to store HTMLDOMelement pointer in nsIDOMNode.
890  */
891
892 HTMLDOMNode *get_node(HTMLDocument *This, nsIDOMNode *nsnode, BOOL create)
893 {
894     HTMLDOMNode *iter = This->nodes;
895
896     while(iter) {
897         if(iter->nsnode == nsnode)
898             break;
899         iter = iter->next;
900     }
901
902     if(iter || !create)
903         return iter;
904
905     return create_node(This, nsnode);
906 }
907
908 /*
909  * FIXME
910  * We should use better way for getting node object (like private interface)
911  * or avoid it at all.
912  */
913 static HTMLDOMNode *get_node_obj(HTMLDocument *This, IUnknown *iface)
914 {
915     HTMLDOMNode *iter = This->nodes;
916     IHTMLDOMNode *node;
917
918     IUnknown_QueryInterface(iface, &IID_IHTMLDOMNode, (void**)&node);
919     IHTMLDOMNode_Release(node);
920
921     while(iter) {
922         if(HTMLDOMNODE(iter) == node)
923             return iter;
924         iter = iter->next;
925     }
926
927     FIXME("Not found %p\n", iface);
928     return NULL;
929 }
930
931 void release_nodes(HTMLDocument *This)
932 {
933     HTMLDOMNode *iter, *next;
934
935     if(!This->nodes)
936         return;
937
938     for(iter = This->nodes; iter; iter = next) {
939         next = iter->next;
940         iter->doc = NULL;
941         IHTMLDOMNode_Release(HTMLDOMNODE(iter));
942     }
943 }