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