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