mshtml: Added put_backgroundImage implementation.
[wine] / dlls / mshtml / htmlnode.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29
30 #include "mshtml_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
33
34 #define HTMLDOMNODE_THIS(iface) DEFINE_THIS(HTMLDOMNode, HTMLDOMNode, iface)
35
36 static HRESULT WINAPI HTMLDOMNode_QueryInterface(IHTMLDOMNode *iface,
37                                                  REFIID riid, void **ppv)
38 {
39     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
40
41     return This->vtbl->qi(This, riid, ppv);
42 }
43
44 static ULONG WINAPI HTMLDOMNode_AddRef(IHTMLDOMNode *iface)
45 {
46     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
47     LONG ref = InterlockedIncrement(&This->ref);
48
49     TRACE("(%p) ref=%d\n", This, ref);
50
51     return ref;
52 }
53
54 static ULONG WINAPI HTMLDOMNode_Release(IHTMLDOMNode *iface)
55 {
56     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
57     LONG ref = InterlockedDecrement(&This->ref);
58
59     TRACE("(%p) ref=%d\n", This, ref);
60
61     if(!ref) {
62         This->vtbl->destructor(This);
63         heap_free(This);
64     }
65
66     return ref;
67 }
68
69 static HRESULT WINAPI HTMLDOMNode_GetTypeInfoCount(IHTMLDOMNode *iface, UINT *pctinfo)
70 {
71     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
72     FIXME("(%p)->(%p)\n", This, pctinfo);
73     return E_NOTIMPL;
74 }
75
76 static HRESULT WINAPI HTMLDOMNode_GetTypeInfo(IHTMLDOMNode *iface, UINT iTInfo,
77                                               LCID lcid, ITypeInfo **ppTInfo)
78 {
79     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
80     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
81     return E_NOTIMPL;
82 }
83
84 static HRESULT WINAPI HTMLDOMNode_GetIDsOfNames(IHTMLDOMNode *iface, REFIID riid,
85                                                 LPOLESTR *rgszNames, UINT cNames,
86                                                 LCID lcid, DISPID *rgDispId)
87 {
88     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
89     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
90                                         lcid, rgDispId);
91     return E_NOTIMPL;
92 }
93
94 static HRESULT WINAPI HTMLDOMNode_Invoke(IHTMLDOMNode *iface, DISPID dispIdMember,
95                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
96                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
97 {
98     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
99     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
100             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
101     return E_NOTIMPL;
102 }
103
104 static HRESULT WINAPI HTMLDOMNode_get_nodeType(IHTMLDOMNode *iface, long *p)
105 {
106     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
107     PRUint16 type = -1;
108
109     TRACE("(%p)->(%p)\n", This, p);
110
111     nsIDOMNode_GetNodeType(This->nsnode, &type);
112
113     switch(type) {
114     case ELEMENT_NODE:
115         *p = 1;
116         break;
117     case TEXT_NODE:
118         *p = 3;
119         break;
120     default:
121         /*
122          * FIXME:
123          * According to MSDN only ELEMENT_NODE and TEXT_NODE are supported.
124          * It needs more tests.
125          */
126         FIXME("type %u\n", type);
127         *p = 0;
128     }
129
130     return S_OK;
131 }
132
133 static HRESULT WINAPI HTMLDOMNode_get_parentNode(IHTMLDOMNode *iface, IHTMLDOMNode **p)
134 {
135     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
136     FIXME("(%p)->(%p)\n", This, p);
137     return E_NOTIMPL;
138 }
139
140 static HRESULT WINAPI HTMLDOMNode_hasChildNodes(IHTMLDOMNode *iface, VARIANT_BOOL *fChildren)
141 {
142     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
143     FIXME("(%p)->(%p)\n", This, fChildren);
144     return E_NOTIMPL;
145 }
146
147 static HRESULT WINAPI HTMLDOMNode_get_childNodes(IHTMLDOMNode *iface, IDispatch **p)
148 {
149     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
150     FIXME("(%p)->(%p)\n", This, p);
151     return E_NOTIMPL;
152 }
153
154 static HRESULT WINAPI HTMLDOMNode_get_attributes(IHTMLDOMNode *iface, IDispatch **p)
155 {
156     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
157     FIXME("(%p)->(%p)\n", This, p);
158     return E_NOTIMPL;
159 }
160
161 static HRESULT WINAPI HTMLDOMNode_insertBefore(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
162                                                VARIANT refChild, IHTMLDOMNode **node)
163 {
164     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
165     FIXME("(%p)->(%p v %p)\n", This, newChild, node);
166     return E_NOTIMPL;
167 }
168
169 static HRESULT WINAPI HTMLDOMNode_removeChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
170                                               IHTMLDOMNode **node)
171 {
172     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
173     FIXME("(%p)->(%p %p)\n", This, newChild, node);
174     return E_NOTIMPL;
175 }
176
177 static HRESULT WINAPI HTMLDOMNode_replaceChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
178                                                IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
179 {
180     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
181     FIXME("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
182     return E_NOTIMPL;
183 }
184
185 static HRESULT WINAPI HTMLDOMNode_cloneNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
186                                             IHTMLDOMNode **clonedNode)
187 {
188     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
189     FIXME("(%p)->(%x %p)\n", This, fDeep, clonedNode);
190     return E_NOTIMPL;
191 }
192
193 static HRESULT WINAPI HTMLDOMNode_removeNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
194                                              IHTMLDOMNode **removed)
195 {
196     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
197     FIXME("(%p)->(%x %p)\n", This, fDeep, removed);
198     return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI HTMLDOMNode_swapNode(IHTMLDOMNode *iface, IHTMLDOMNode *otherNode,
202                                            IHTMLDOMNode **swappedNode)
203 {
204     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
205     FIXME("(%p)->(%p %p)\n", This, otherNode, swappedNode);
206     return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI HTMLDOMNode_replaceNode(IHTMLDOMNode *iface, IHTMLDOMNode *replacement,
210                                               IHTMLDOMNode **replaced)
211 {
212     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
213     FIXME("(%p)->(%p %p)\n", This, replacement, replaced);
214     return E_NOTIMPL;
215 }
216
217 static HRESULT WINAPI HTMLDOMNode_appendChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
218                                               IHTMLDOMNode **node)
219 {
220     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
221     FIXME("(%p)->(%p %p)\n", This, newChild, node);
222     return E_NOTIMPL;
223 }
224
225 static HRESULT WINAPI HTMLDOMNode_get_nodeName(IHTMLDOMNode *iface, BSTR *p)
226 {
227     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
228
229     TRACE("(%p)->(%p)\n", This, p);
230
231     *p = NULL;
232
233     if(This->nsnode) {
234         nsAString name_str;
235         const PRUnichar *name;
236         nsresult nsres;
237
238         nsAString_Init(&name_str, NULL);
239         nsres = nsIDOMNode_GetNodeName(This->nsnode, &name_str);
240
241         if(NS_SUCCEEDED(nsres)) {
242             nsAString_GetData(&name_str, &name);
243             *p = SysAllocString(name);
244         }else {
245             ERR("GetNodeName failed: %08x\n", nsres);
246         }
247
248         nsAString_Finish(&name_str);
249     }
250
251     return S_OK;
252 }
253
254 static HRESULT WINAPI HTMLDOMNode_put_nodeValue(IHTMLDOMNode *iface, VARIANT v)
255 {
256     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
257     FIXME("(%p)->()\n", This);
258     return E_NOTIMPL;
259 }
260
261 static HRESULT WINAPI HTMLDOMNode_get_nodeValue(IHTMLDOMNode *iface, VARIANT *p)
262 {
263     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
264     FIXME("(%p)->(%p)\n", This, p);
265     return E_NOTIMPL;
266 }
267
268 static HRESULT WINAPI HTMLDOMNode_get_firstChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
269 {
270     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
271     nsIDOMNode *nschild = NULL;
272
273     TRACE("(%p)->(%p)\n", This, p);
274
275     nsIDOMNode_GetFirstChild(This->nsnode, &nschild);
276     if(nschild) {
277         *p = HTMLDOMNODE(get_node(This->doc, nschild, TRUE));
278         IHTMLDOMNode_AddRef(*p);
279     }else {
280         *p = NULL;
281     }
282
283     return S_OK;
284 }
285
286 static HRESULT WINAPI HTMLDOMNode_get_lastChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
287 {
288     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
289     FIXME("(%p)->(%p)\n", This, p);
290     return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI HTMLDOMNode_get_previousSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
294 {
295     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
296     FIXME("(%p)->(%p)\n", This, p);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI HTMLDOMNode_get_nextSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
301 {
302     HTMLDOMNode *This = HTMLDOMNODE_THIS(iface);
303     FIXME("(%p)->(%p)\n", This, p);
304     return E_NOTIMPL;
305 }
306
307 #undef HTMLDOMNODE_THIS
308
309 static const IHTMLDOMNodeVtbl HTMLDOMNodeVtbl = {
310     HTMLDOMNode_QueryInterface,
311     HTMLDOMNode_AddRef,
312     HTMLDOMNode_Release,
313     HTMLDOMNode_GetTypeInfoCount,
314     HTMLDOMNode_GetTypeInfo,
315     HTMLDOMNode_GetIDsOfNames,
316     HTMLDOMNode_Invoke,
317     HTMLDOMNode_get_nodeType,
318     HTMLDOMNode_get_parentNode,
319     HTMLDOMNode_hasChildNodes,
320     HTMLDOMNode_get_childNodes,
321     HTMLDOMNode_get_attributes,
322     HTMLDOMNode_insertBefore,
323     HTMLDOMNode_removeChild,
324     HTMLDOMNode_replaceChild,
325     HTMLDOMNode_cloneNode,
326     HTMLDOMNode_removeNode,
327     HTMLDOMNode_swapNode,
328     HTMLDOMNode_replaceNode,
329     HTMLDOMNode_appendChild,
330     HTMLDOMNode_get_nodeName,
331     HTMLDOMNode_put_nodeValue,
332     HTMLDOMNode_get_nodeValue,
333     HTMLDOMNode_get_firstChild,
334     HTMLDOMNode_get_lastChild,
335     HTMLDOMNode_get_previousSibling,
336     HTMLDOMNode_get_nextSibling
337 };
338
339 #define HTMLDOMNODE2_THIS(iface) DEFINE_THIS(HTMLDOMNode, HTMLDOMNode2, iface)
340
341 static HRESULT WINAPI HTMLDOMNode2_QueryInterface(IHTMLDOMNode2 *iface,
342         REFIID riid, void **ppv)
343 {
344     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
345
346     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(This), riid, ppv);
347 }
348
349 static ULONG WINAPI HTMLDOMNode2_AddRef(IHTMLDOMNode2 *iface)
350 {
351     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
352
353     return IHTMLDOMNode_AddRef(HTMLDOMNODE(This));
354 }
355
356 static ULONG WINAPI HTMLDOMNode2_Release(IHTMLDOMNode2 *iface)
357 {
358     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
359
360     return IHTMLDOMNode_Release(HTMLDOMNODE(This));
361 }
362
363 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfoCount(IHTMLDOMNode2 *iface, UINT *pctinfo)
364 {
365     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
366     FIXME("(%p)->(%p)\n", This, pctinfo);
367     return E_NOTIMPL;
368 }
369
370 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfo(IHTMLDOMNode2 *iface, UINT iTInfo,
371         LCID lcid, ITypeInfo **ppTInfo)
372 {
373     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
374     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
375     return E_NOTIMPL;
376 }
377
378 static HRESULT WINAPI HTMLDOMNode2_GetIDsOfNames(IHTMLDOMNode2 *iface, REFIID riid,
379                                                 LPOLESTR *rgszNames, UINT cNames,
380                                                 LCID lcid, DISPID *rgDispId)
381 {
382     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
383     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
384           lcid, rgDispId);
385     return E_NOTIMPL;
386 }
387
388 static HRESULT WINAPI HTMLDOMNode2_Invoke(IHTMLDOMNode2 *iface, DISPID dispIdMember,
389         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
390         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
391 {
392     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
393     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
394             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
395     return E_NOTIMPL;
396 }
397
398 static HRESULT WINAPI HTMLDOMNode2_get_ownerDocument(IHTMLDOMNode2 *iface, IDispatch **p)
399 {
400     HTMLDOMNode *This = HTMLDOMNODE2_THIS(iface);
401     FIXME("(%p)->(%p)\n", This, p);
402     return E_NOTIMPL;
403 }
404
405 #undef HTMLDOMNODE2_THIS
406
407 static const IHTMLDOMNode2Vtbl HTMLDOMNode2Vtbl = {
408     HTMLDOMNode2_QueryInterface,
409     HTMLDOMNode2_AddRef,
410     HTMLDOMNode2_Release,
411     HTMLDOMNode2_GetTypeInfoCount,
412     HTMLDOMNode2_GetTypeInfo,
413     HTMLDOMNode2_GetIDsOfNames,
414     HTMLDOMNode2_Invoke,
415     HTMLDOMNode2_get_ownerDocument
416 };
417
418 HRESULT HTMLDOMNode_QI(HTMLDOMNode *This, REFIID riid, void **ppv)
419 {
420     *ppv = NULL;
421
422     if(IsEqualGUID(&IID_IUnknown, riid)) {
423         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
424         *ppv = HTMLDOMNODE(This);
425     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
426         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
427         *ppv = HTMLDOMNODE(This);
428     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
429         if(This->dispex.data) {
430             TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
431             *ppv = DISPATCHEX(&This->dispex);
432         }else {
433             FIXME("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
434             return E_NOINTERFACE;
435         }
436     }else if(IsEqualGUID(&IID_IHTMLDOMNode, riid)) {
437         TRACE("(%p)->(IID_IHTMLDOMNode %p)\n", This, ppv);
438         *ppv = HTMLDOMNODE(This);
439     }else if(IsEqualGUID(&IID_IHTMLDOMNode2, riid)) {
440         TRACE("(%p)->(IID_IHTMLDOMNode2 %p)\n", This, ppv);
441         *ppv = HTMLDOMNODE2(This);
442     }
443
444     if(*ppv) {
445         IUnknown_AddRef((IUnknown*)*ppv);
446         return S_OK;
447     }
448
449     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
450     return E_NOINTERFACE;
451 }
452
453 void HTMLDOMNode_destructor(HTMLDOMNode *This)
454 {
455     if(This->nsnode)
456         nsIDOMNode_Release(This->nsnode);
457     if(This->event_target)
458         release_event_target(This->event_target);
459 }
460
461 static const NodeImplVtbl HTMLDOMNodeImplVtbl = {
462     HTMLDOMNode_QI,
463     HTMLDOMNode_destructor
464 };
465
466 static HTMLDOMNode *create_node(HTMLDocument *doc, nsIDOMNode *nsnode)
467 {
468     HTMLDOMNode *ret;
469     PRUint16 node_type;
470
471     nsIDOMNode_GetNodeType(nsnode, &node_type);
472
473     switch(node_type) {
474     case ELEMENT_NODE:
475         ret = &HTMLElement_Create(nsnode)->node;
476         break;
477     case TEXT_NODE:
478         ret = HTMLDOMTextNode_Create(nsnode);
479         break;
480     default:
481         ret = heap_alloc_zero(sizeof(HTMLDOMNode));
482         ret->vtbl = &HTMLDOMNodeImplVtbl;
483     }
484
485     ret->lpHTMLDOMNodeVtbl = &HTMLDOMNodeVtbl;
486     ret->lpHTMLDOMNode2Vtbl = &HTMLDOMNode2Vtbl;
487     ret->ref = 1;
488     ret->doc = doc;
489
490     nsIDOMNode_AddRef(nsnode);
491     ret->nsnode = nsnode;
492
493     TRACE("type %d ret %p\n", node_type, ret);
494
495     return ret;
496 }
497
498 /*
499  * FIXME
500  * List looks really ugly here. We should use a better data structure or
501  * (better) find a way to store HTMLDOMelement pointer in nsIDOMNode.
502  */
503
504 HTMLDOMNode *get_node(HTMLDocument *This, nsIDOMNode *nsnode, BOOL create)
505 {
506     HTMLDOMNode *iter = This->nodes, *ret;
507
508     while(iter) {
509         if(iter->nsnode == nsnode)
510             break;
511         iter = iter->next;
512     }
513
514     if(iter || !create)
515         return iter;
516
517     ret = create_node(This, nsnode);
518
519     ret->next = This->nodes;
520     This->nodes = ret;
521
522     return ret;
523 }
524
525 void release_nodes(HTMLDocument *This)
526 {
527     HTMLDOMNode *iter, *next;
528
529     if(!This->nodes)
530         return;
531
532     for(iter = This->nodes; iter; iter = next) {
533         next = iter->next;
534         iter->doc = NULL;
535         IHTMLDOMNode_Release(HTMLDOMNODE(iter));
536     }
537 }