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