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