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