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