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