mshtml: Keep reference to document node in fire_event_obj.
[wine] / dlls / mshtml / htmloption.c
1 /*
2  * Copyright 2007 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 #include <assert.h>
21
22 #define COBJMACROS
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "ole2.h"
28
29 #include "wine/debug.h"
30
31 #include "mshtml_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34
35 struct HTMLOptionElement {
36     HTMLElement element;
37
38     IHTMLOptionElement IHTMLOptionElement_iface;
39
40     nsIDOMHTMLOptionElement *nsoption;
41 };
42
43 static inline HTMLOptionElement *impl_from_IHTMLOptionElement(IHTMLOptionElement *iface)
44 {
45     return CONTAINING_RECORD(iface, HTMLOptionElement, IHTMLOptionElement_iface);
46 }
47
48 static HRESULT WINAPI HTMLOptionElement_QueryInterface(IHTMLOptionElement *iface,
49         REFIID riid, void **ppv)
50 {
51     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
52
53     return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv);
54 }
55
56 static ULONG WINAPI HTMLOptionElement_AddRef(IHTMLOptionElement *iface)
57 {
58     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
59
60     return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface);
61 }
62
63 static ULONG WINAPI HTMLOptionElement_Release(IHTMLOptionElement *iface)
64 {
65     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
66
67     return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface);
68 }
69
70 static HRESULT WINAPI HTMLOptionElement_GetTypeInfoCount(IHTMLOptionElement *iface, UINT *pctinfo)
71 {
72     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
73     return IDispatchEx_GetTypeInfoCount(&This->element.node.dispex.IDispatchEx_iface, pctinfo);
74 }
75
76 static HRESULT WINAPI HTMLOptionElement_GetTypeInfo(IHTMLOptionElement *iface, UINT iTInfo,
77                                               LCID lcid, ITypeInfo **ppTInfo)
78 {
79     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
80     return IDispatchEx_GetTypeInfo(&This->element.node.dispex.IDispatchEx_iface, iTInfo, lcid,
81             ppTInfo);
82 }
83
84 static HRESULT WINAPI HTMLOptionElement_GetIDsOfNames(IHTMLOptionElement *iface, REFIID riid,
85                                                 LPOLESTR *rgszNames, UINT cNames,
86                                                 LCID lcid, DISPID *rgDispId)
87 {
88     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
89     return IDispatchEx_GetIDsOfNames(&This->element.node.dispex.IDispatchEx_iface, riid, rgszNames,
90             cNames, lcid, rgDispId);
91 }
92
93 static HRESULT WINAPI HTMLOptionElement_Invoke(IHTMLOptionElement *iface, DISPID dispIdMember,
94                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
95                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
96 {
97     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
98     return IDispatchEx_Invoke(&This->element.node.dispex.IDispatchEx_iface, dispIdMember, riid,
99             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
100 }
101
102 static HRESULT WINAPI HTMLOptionElement_put_selected(IHTMLOptionElement *iface, VARIANT_BOOL v)
103 {
104     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
105     nsresult nsres;
106
107     TRACE("(%p)->(%x)\n", This, v);
108
109     nsres = nsIDOMHTMLOptionElement_SetSelected(This->nsoption, v != VARIANT_FALSE);
110     if(NS_FAILED(nsres)) {
111         ERR("SetSelected failed: %08x\n", nsres);
112         return E_FAIL;
113     }
114
115     return S_OK;
116 }
117
118 static HRESULT WINAPI HTMLOptionElement_get_selected(IHTMLOptionElement *iface, VARIANT_BOOL *p)
119 {
120     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
121     cpp_bool selected;
122     nsresult nsres;
123
124     TRACE("(%p)->(%p)\n", This, p);
125
126     nsres = nsIDOMHTMLOptionElement_GetSelected(This->nsoption, &selected);
127     if(NS_FAILED(nsres)) {
128         ERR("GetSelected failed: %08x\n", nsres);
129         return E_FAIL;
130     }
131
132     *p = selected ? VARIANT_TRUE : VARIANT_FALSE;
133     return S_OK;
134 }
135
136 static HRESULT WINAPI HTMLOptionElement_put_value(IHTMLOptionElement *iface, BSTR v)
137 {
138     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
139     nsAString value_str;
140     nsresult nsres;
141
142     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
143
144     nsAString_InitDepend(&value_str, v);
145     nsres = nsIDOMHTMLOptionElement_SetValue(This->nsoption, &value_str);
146     nsAString_Finish(&value_str);
147     if(NS_FAILED(nsres))
148         ERR("SetValue failed: %08x\n", nsres);
149
150     return S_OK;
151 }
152
153 static HRESULT WINAPI HTMLOptionElement_get_value(IHTMLOptionElement *iface, BSTR *p)
154 {
155     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
156     nsAString value_str;
157     nsresult nsres;
158
159     TRACE("(%p)->(%p)\n", This, p);
160
161     nsAString_Init(&value_str, NULL);
162     nsres = nsIDOMHTMLOptionElement_GetValue(This->nsoption, &value_str);
163     return return_nsstr(nsres, &value_str, p);
164 }
165
166 static HRESULT WINAPI HTMLOptionElement_put_defaultSelected(IHTMLOptionElement *iface, VARIANT_BOOL v)
167 {
168     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
169     FIXME("(%p)->(%x)\n", This, v);
170     return E_NOTIMPL;
171 }
172
173 static HRESULT WINAPI HTMLOptionElement_get_defaultSelected(IHTMLOptionElement *iface, VARIANT_BOOL *p)
174 {
175     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
176     FIXME("(%p)->(%p)\n", This, p);
177     return E_NOTIMPL;
178 }
179
180 static HRESULT WINAPI HTMLOptionElement_put_index(IHTMLOptionElement *iface, LONG v)
181 {
182     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
183     FIXME("(%p)->(%d)\n", This, v);
184     return E_NOTIMPL;
185 }
186
187 static HRESULT WINAPI HTMLOptionElement_get_index(IHTMLOptionElement *iface, LONG *p)
188 {
189     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
190     FIXME("(%p)->(%p)\n", This, p);
191     return E_NOTIMPL;
192 }
193
194 static HRESULT WINAPI HTMLOptionElement_put_text(IHTMLOptionElement *iface, BSTR v)
195 {
196     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
197     nsIDOMText *text_node;
198     nsAString text_str;
199     nsIDOMNode *tmp;
200     nsresult nsres;
201
202     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
203
204     if(!This->element.node.doc->nsdoc) {
205         WARN("NULL nsdoc\n");
206         return E_UNEXPECTED;
207     }
208
209     while(1) {
210         nsIDOMNode *child;
211
212         nsres = nsIDOMHTMLOptionElement_GetFirstChild(This->nsoption, &child);
213         if(NS_FAILED(nsres) || !child)
214             break;
215
216         nsres = nsIDOMHTMLOptionElement_RemoveChild(This->nsoption, child, &tmp);
217         nsIDOMNode_Release(child);
218         if(NS_SUCCEEDED(nsres)) {
219             nsIDOMNode_Release(tmp);
220         }else {
221             ERR("RemoveChild failed: %08x\n", nsres);
222             break;
223         }
224     }
225
226     nsAString_InitDepend(&text_str, v);
227     nsres = nsIDOMHTMLDocument_CreateTextNode(This->element.node.doc->nsdoc, &text_str, &text_node);
228     nsAString_Finish(&text_str);
229     if(NS_FAILED(nsres)) {
230         ERR("CreateTextNode failed: %08x\n", nsres);
231         return E_FAIL;
232     }
233
234     nsres = nsIDOMHTMLOptionElement_AppendChild(This->nsoption, (nsIDOMNode*)text_node, &tmp);
235     if(NS_SUCCEEDED(nsres))
236         nsIDOMNode_Release(tmp);
237     else
238         ERR("AppendChild failed: %08x\n", nsres);
239
240     return S_OK;
241 }
242
243 static HRESULT WINAPI HTMLOptionElement_get_text(IHTMLOptionElement *iface, BSTR *p)
244 {
245     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
246     nsAString text_str;
247     nsresult nsres;
248
249     TRACE("(%p)->(%p)\n", This, p);
250
251     nsAString_Init(&text_str, NULL);
252     nsres = nsIDOMHTMLOptionElement_GetText(This->nsoption, &text_str);
253     return return_nsstr(nsres, &text_str, p);
254 }
255
256 static HRESULT WINAPI HTMLOptionElement_get_form(IHTMLOptionElement *iface, IHTMLFormElement **p)
257 {
258     HTMLOptionElement *This = impl_from_IHTMLOptionElement(iface);
259     FIXME("(%p)->(%p)\n", This, p);
260     return E_NOTIMPL;
261 }
262
263 static const IHTMLOptionElementVtbl HTMLOptionElementVtbl = {
264     HTMLOptionElement_QueryInterface,
265     HTMLOptionElement_AddRef,
266     HTMLOptionElement_Release,
267     HTMLOptionElement_GetTypeInfoCount,
268     HTMLOptionElement_GetTypeInfo,
269     HTMLOptionElement_GetIDsOfNames,
270     HTMLOptionElement_Invoke,
271     HTMLOptionElement_put_selected,
272     HTMLOptionElement_get_selected,
273     HTMLOptionElement_put_value,
274     HTMLOptionElement_get_value,
275     HTMLOptionElement_put_defaultSelected,
276     HTMLOptionElement_get_defaultSelected,
277     HTMLOptionElement_put_index,
278     HTMLOptionElement_get_index,
279     HTMLOptionElement_put_text,
280     HTMLOptionElement_get_text,
281     HTMLOptionElement_get_form
282 };
283
284 static inline HTMLOptionElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
285 {
286     return CONTAINING_RECORD(iface, HTMLOptionElement, element.node);
287 }
288
289 static HRESULT HTMLOptionElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
290 {
291     HTMLOptionElement *This = impl_from_HTMLDOMNode(iface);
292
293     *ppv = NULL;
294
295     if(IsEqualGUID(&IID_IUnknown, riid)) {
296         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
297         *ppv = &This->IHTMLOptionElement_iface;
298     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
299         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
300         *ppv = &This->IHTMLOptionElement_iface;
301     }else if(IsEqualGUID(&IID_IHTMLOptionElement, riid)) {
302         TRACE("(%p)->(IID_IHTMLOptionElement %p)\n", This, ppv);
303         *ppv = &This->IHTMLOptionElement_iface;
304     }
305
306     if(*ppv) {
307         IUnknown_AddRef((IUnknown*)*ppv);
308         return S_OK;
309     }
310
311     return HTMLElement_QI(&This->element.node, riid, ppv);
312 }
313
314 static const NodeImplVtbl HTMLOptionElementImplVtbl = {
315     HTMLOptionElement_QI,
316     HTMLElement_destructor,
317     HTMLElement_clone,
318     HTMLElement_handle_event,
319     HTMLElement_get_attr_col
320 };
321
322 static const tid_t HTMLOptionElement_iface_tids[] = {
323     HTMLELEMENT_TIDS,
324     IHTMLOptionElement_tid,
325     0
326 };
327 static dispex_static_data_t HTMLOptionElement_dispex = {
328     NULL,
329     DispHTMLOptionElement_tid,
330     NULL,
331     HTMLOptionElement_iface_tids
332 };
333
334 HRESULT HTMLOptionElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, HTMLElement **elem)
335 {
336     HTMLOptionElement *ret;
337     nsresult nsres;
338
339     ret = heap_alloc_zero(sizeof(HTMLOptionElement));
340     if(!ret)
341         return E_OUTOFMEMORY;
342
343     ret->IHTMLOptionElement_iface.lpVtbl = &HTMLOptionElementVtbl;
344     ret->element.node.vtbl = &HTMLOptionElementImplVtbl;
345
346     HTMLElement_Init(&ret->element, doc, nselem, &HTMLOptionElement_dispex);
347
348     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLOptionElement, (void**)&ret->nsoption);
349
350     /* Share nsoption reference with nsnode */
351     assert(nsres == NS_OK && (nsIDOMNode*)ret->nsoption == ret->element.node.nsnode);
352     nsIDOMNode_Release(ret->element.node.nsnode);
353
354     *elem = &ret->element;
355     return S_OK;
356 }
357
358 static inline HTMLOptionElementFactory *impl_from_IHTMLOptionElementFactory(IHTMLOptionElementFactory *iface)
359 {
360     return CONTAINING_RECORD(iface, HTMLOptionElementFactory, IHTMLOptionElementFactory_iface);
361 }
362
363 static HRESULT WINAPI HTMLOptionElementFactory_QueryInterface(IHTMLOptionElementFactory *iface,
364                                                               REFIID riid, void **ppv)
365 {
366     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
367
368     *ppv = NULL;
369
370     if(IsEqualGUID(&IID_IUnknown, riid)) {
371         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
372         *ppv = &This->IHTMLOptionElementFactory_iface;
373     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
374         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
375         *ppv = &This->IHTMLOptionElementFactory_iface;
376     }else if(IsEqualGUID(&IID_IHTMLOptionElementFactory, riid)) {
377         TRACE("(%p)->(IID_IHTMLOptionElementFactory %p)\n", This, ppv);
378         *ppv = &This->IHTMLOptionElementFactory_iface;
379     }
380
381     if(*ppv) {
382         IUnknown_AddRef((IUnknown*)*ppv);
383         return S_OK;
384     }
385
386     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
387     return E_NOINTERFACE;
388 }
389
390 static ULONG WINAPI HTMLOptionElementFactory_AddRef(IHTMLOptionElementFactory *iface)
391 {
392     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
393     LONG ref = InterlockedIncrement(&This->ref);
394
395     TRACE("(%p) ref=%d\n", This, ref);
396
397     return ref;
398 }
399
400 static ULONG WINAPI HTMLOptionElementFactory_Release(IHTMLOptionElementFactory *iface)
401 {
402     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
403     LONG ref = InterlockedDecrement(&This->ref);
404
405     TRACE("(%p) ref=%d\n", This, ref);
406
407     if(!ref)
408         heap_free(This);
409
410     return ref;
411 }
412
413 static HRESULT WINAPI HTMLOptionElementFactory_GetTypeInfoCount(IHTMLOptionElementFactory *iface, UINT *pctinfo)
414 {
415     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
416     FIXME("(%p)->(%p)\n", This, pctinfo);
417     return E_NOTIMPL;
418 }
419
420 static HRESULT WINAPI HTMLOptionElementFactory_GetTypeInfo(IHTMLOptionElementFactory *iface, UINT iTInfo,
421                                               LCID lcid, ITypeInfo **ppTInfo)
422 {
423     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
424     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
425     return E_NOTIMPL;
426 }
427
428 static HRESULT WINAPI HTMLOptionElementFactory_GetIDsOfNames(IHTMLOptionElementFactory *iface, REFIID riid,
429                                                 LPOLESTR *rgszNames, UINT cNames,
430                                                 LCID lcid, DISPID *rgDispId)
431 {
432     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
433     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
434                                         lcid, rgDispId);
435     return E_NOTIMPL;
436 }
437
438 static HRESULT WINAPI HTMLOptionElementFactory_Invoke(IHTMLOptionElementFactory *iface, DISPID dispIdMember,
439                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
440                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
441 {
442     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
443     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
444             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
445     return E_NOTIMPL;
446 }
447
448 static HRESULT WINAPI HTMLOptionElementFactory_create(IHTMLOptionElementFactory *iface,
449         VARIANT text, VARIANT value, VARIANT defaultselected, VARIANT selected,
450         IHTMLOptionElement **optelem)
451 {
452     HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface);
453     nsIDOMHTMLElement *nselem;
454     HTMLDOMNode *node;
455     HRESULT hres;
456
457     static const PRUnichar optionW[] = {'O','P','T','I','O','N',0};
458
459     TRACE("(%p)->(%s %s %s %s %p)\n", This, debugstr_variant(&text), debugstr_variant(&value),
460           debugstr_variant(&defaultselected), debugstr_variant(&selected), optelem);
461
462     if(!This->window || !This->window->doc) {
463         WARN("NULL doc\n");
464         return E_UNEXPECTED;
465     }
466
467     *optelem = NULL;
468
469     hres = create_nselem(This->window->doc, optionW, &nselem);
470     if(FAILED(hres))
471         return hres;
472
473     hres = get_node(This->window->doc, (nsIDOMNode*)nselem, TRUE, &node);
474     nsIDOMHTMLElement_Release(nselem);
475     if(FAILED(hres))
476         return hres;
477
478     hres = IHTMLDOMNode_QueryInterface(&node->IHTMLDOMNode_iface,
479             &IID_IHTMLOptionElement, (void**)optelem);
480     node_release(node);
481
482     if(V_VT(&text) == VT_BSTR)
483         IHTMLOptionElement_put_text(*optelem, V_BSTR(&text));
484     else if(V_VT(&text) != VT_EMPTY)
485         FIXME("Unsupported text %s\n", debugstr_variant(&text));
486
487     if(V_VT(&value) == VT_BSTR)
488         IHTMLOptionElement_put_value(*optelem, V_BSTR(&value));
489     else if(V_VT(&value) != VT_EMPTY)
490         FIXME("Unsupported value %s\n", debugstr_variant(&value));
491
492     if(V_VT(&defaultselected) != VT_EMPTY)
493         FIXME("Unsupported defaultselected %s\n", debugstr_variant(&defaultselected));
494     if(V_VT(&selected) != VT_EMPTY)
495         FIXME("Unsupported selected %s\n", debugstr_variant(&selected));
496
497     return S_OK;
498 }
499
500 static const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl = {
501     HTMLOptionElementFactory_QueryInterface,
502     HTMLOptionElementFactory_AddRef,
503     HTMLOptionElementFactory_Release,
504     HTMLOptionElementFactory_GetTypeInfoCount,
505     HTMLOptionElementFactory_GetTypeInfo,
506     HTMLOptionElementFactory_GetIDsOfNames,
507     HTMLOptionElementFactory_Invoke,
508     HTMLOptionElementFactory_create
509 };
510
511 HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionElementFactory **ret_ptr)
512 {
513     HTMLOptionElementFactory *ret;
514
515     ret = heap_alloc(sizeof(*ret));
516     if(!ret)
517         return E_OUTOFMEMORY;
518
519     ret->IHTMLOptionElementFactory_iface.lpVtbl = &HTMLOptionElementFactoryVtbl;
520     ret->ref = 1;
521     ret->window = window;
522
523     *ret_ptr = ret;
524     return S_OK;
525 }