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