1 /*
2 * Copyright 2008-2009 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 "mshtml_private.h"
20
21 typedef struct {
22 IDispatch *handler_prop;
23 DWORD handler_cnt;
24 IDispatch *handlers[0];
25 } handler_vector_t;
26
27 struct event_target_t {
28 handler_vector_t *event_table[EVENTID_LAST];
29 };
30
31 static const WCHAR abortW[] = {'a','b','o','r','t',0};
32 static const WCHAR onabortW[] = {'o','n','a','b','o','r','t',0};
33
34 static const WCHAR beforeunloadW[] = {'b','e','f','o','r','e','u','n','l','o','a','d',0};
35 static const WCHAR onbeforeunloadW[] = {'o','n','b','e','f','o','r','e','u','n','l','o','a','d',0};
36
37 static const WCHAR blurW[] = {'b','l','u','r',0};
38 static const WCHAR onblurW[] = {'o','n','b','l','u','r',0};
39
40 static const WCHAR changeW[] = {'c','h','a','n','g','e',0};
41 static const WCHAR onchangeW[] = {'o','n','c','h','a','n','g','e',0};
42
43 static const WCHAR clickW[] = {'c','l','i','c','k',0};
44 static const WCHAR onclickW[] = {'o','n','c','l','i','c','k',0};
45
46 static const WCHAR contextmenuW[] = {'c','o','n','t','e','x','t','m','e','n','u',0};
47 static const WCHAR oncontextmenuW[] = {'o','n','c','o','n','t','e','x','t','m','e','n','u',0};
48
49 static const WCHAR dataavailableW[] = {'d','a','t','a','a','v','a','i','l','a','b','l','e',0};
50 static const WCHAR ondataavailableW[] = {'o','n','d','a','t','a','a','v','a','i','l','a','b','l','e',0};
51
52 static const WCHAR dblclickW[] = {'d','b','l','c','l','i','c','k',0};
53 static const WCHAR ondblclickW[] = {'o','n','d','b','l','c','l','i','c','k',0};
54
55 static const WCHAR dragW[] = {'d','r','a','g',0};
56 static const WCHAR ondragW[] = {'o','n','d','r','a','g',0};
57
58 static const WCHAR dragstartW[] = {'d','r','a','g','s','t','a','r','t',0};
59 static const WCHAR ondragstartW[] = {'o','n','d','r','a','g','s','t','a','r','t',0};
60
61 static const WCHAR errorW[] = {'e','r','r','o','r',0};
62 static const WCHAR onerrorW[] = {'o','n','e','r','r','o','r',0};
63
64 static const WCHAR focusW[] = {'f','o','c','u','s',0};
65 static const WCHAR onfocusW[] = {'o','n','f','o','c','u','s',0};
66
67 static const WCHAR focusinW[] = {'f','o','c','u','s','i','n',0};
68 static const WCHAR onfocusinW[] = {'o','n','f','o','c','u','s','i','n',0};
69
70 static const WCHAR helpW[] = {'h','e','l','p',0};
71 static const WCHAR onhelpW[] = {'o','n','h','e','l','p',0};
72
73 static const WCHAR keydownW[] = {'k','e','y','d','o','w','n',0};
74 static const WCHAR onkeydownW[] = {'o','n','k','e','y','d','o','w','n',0};
75
76 static const WCHAR keypressW[] = {'k','e','y','p','r','e','s','s',0};
77 static const WCHAR onkeypressW[] = {'o','n','k','e','y','p','r','e','s','s',0};
78
79 static const WCHAR keyupW[] = {'k','e','y','u','p',0};
80 static const WCHAR onkeyupW[] = {'o','n','k','e','y','u','p',0};
81
82 static const WCHAR loadW[] = {'l','o','a','d',0};
83 static const WCHAR onloadW[] = {'o','n','l','o','a','d',0};
84
85 static const WCHAR mousedownW[] = {'m','o','u','s','e','d','o','w','n',0};
86 static const WCHAR onmousedownW[] = {'o','n','m','o','u','s','e','d','o','w','n',0};
87
88 static const WCHAR mousemoveW[] = {'m','o','u','s','e','m','o','v','e',0};
89 static const WCHAR onmousemoveW[] = {'o','n','m','o','u','s','e','m','o','v','e',0};
90
91 static const WCHAR mouseoutW[] = {'m','o','u','s','e','o','u','t',0};
92 static const WCHAR onmouseoutW[] = {'o','n','m','o','u','s','e','o','u','t',0};
93
94 static const WCHAR mouseoverW[] = {'m','o','u','s','e','o','v','e','r',0};
95 static const WCHAR onmouseoverW[] = {'o','n','m','o','u','s','e','o','v','e','r',0};
96
97 static const WCHAR mouseupW[] = {'m','o','u','s','e','u','p',0};
98 static const WCHAR onmouseupW[] = {'o','n','m','o','u','s','e','u','p',0};
99
100 static const WCHAR mousewheelW[] = {'m','o','u','s','e','w','h','e','e','l',0};
101 static const WCHAR onmousewheelW[] = {'o','n','m','o','u','s','e','w','h','e','e','l',0};
102
103 static const WCHAR pasteW[] = {'p','a','s','t','e',0};
104 static const WCHAR onpasteW[] = {'o','n','p','a','s','t','e',0};
105
106 static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
107 static const WCHAR onreadystatechangeW[] = {'o','n','r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
108
109 static const WCHAR resizeW[] = {'r','e','s','i','z','e',0};
110 static const WCHAR onresizeW[] = {'o','n','r','e','s','i','z','e',0};
111
112 static const WCHAR scrollW[] = {'s','c','r','o','l','l',0};
113 static const WCHAR onscrollW[] = {'o','n','s','c','r','o','l','l',0};
114
115 static const WCHAR selectstartW[] = {'s','e','l','e','c','t','s','t','a','r','t',0};
116 static const WCHAR onselectstartW[] = {'o','n','s','e','l','e','c','t','s','t','a','r','t',0};
117
118 static const WCHAR submitW[] = {'s','u','b','m','i','t',0};
119 static const WCHAR onsubmitW[] = {'o','n','s','u','b','m','i','t',0};
120
121 static const WCHAR HTMLEventsW[] = {'H','T','M','L','E','v','e','n','t','s',0};
122 static const WCHAR KeyboardEventW[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
123 static const WCHAR MouseEventW[] = {'M','o','u','s','e','E','v','e','n','t',0};
124
125 enum {
126 EVENTT_NONE,
127 EVENTT_HTML,
128 EVENTT_KEY,
129 EVENTT_MOUSE
130 };
131
132 static const WCHAR *event_types[] = {
133 NULL,
134 HTMLEventsW,
135 KeyboardEventW,
136 MouseEventW
137 };
138
139 typedef struct {
140 LPCWSTR name;
141 LPCWSTR attr_name;
142 DWORD type;
143 DISPID dispid;
144 DWORD flags;
145 } event_info_t;
146
147 #define EVENT_DEFAULTLISTENER 0x0001
148 #define EVENT_BUBBLE 0x0002
149 #define EVENT_FORWARDBODY 0x0004
150 #define EVENT_BIND_TO_BODY 0x0008
151 #define EVENT_CANCELABLE 0x0010
152 #define EVENT_HASDEFAULTHANDLERS 0x0020
153
154 static const event_info_t event_info[] = {
155 {abortW, onabortW, EVENTT_NONE, DISPID_EVMETH_ONABORT,
156 EVENT_BIND_TO_BODY},
157 {beforeunloadW, onbeforeunloadW, EVENTT_NONE, DISPID_EVMETH_ONBEFOREUNLOAD,
158 EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
159 {blurW, onblurW, EVENTT_HTML, DISPID_EVMETH_ONBLUR,
160 EVENT_DEFAULTLISTENER},
161 {changeW, onchangeW, EVENTT_HTML, DISPID_EVMETH_ONCHANGE,
162 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
163 {clickW, onclickW, EVENTT_MOUSE, DISPID_EVMETH_ONCLICK,
164 EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE|EVENT_HASDEFAULTHANDLERS},
165 {contextmenuW, oncontextmenuW, EVENTT_MOUSE, DISPID_EVMETH_ONCONTEXTMENU,
166 EVENT_BUBBLE|EVENT_CANCELABLE},
167 {dataavailableW, ondataavailableW, EVENTT_NONE, DISPID_EVMETH_ONDATAAVAILABLE,
168 EVENT_BUBBLE},
169 {dblclickW, ondblclickW, EVENTT_MOUSE, DISPID_EVMETH_ONDBLCLICK,
170 EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE},
171 {dragW, ondragW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAG,
172 EVENT_CANCELABLE},
173 {dragstartW, ondragstartW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAGSTART,
174 EVENT_CANCELABLE},
175 {errorW, onerrorW, EVENTT_NONE, DISPID_EVMETH_ONERROR,
176 EVENT_BIND_TO_BODY},
177 {focusW, onfocusW, EVENTT_HTML, DISPID_EVMETH_ONFOCUS,
178 EVENT_DEFAULTLISTENER},
179 {focusinW, onfocusinW, EVENTT_HTML, DISPID_EVMETH_ONFOCUSIN,
180 EVENT_BUBBLE},
181 {helpW, onhelpW, EVENTT_KEY, DISPID_EVMETH_ONHELP,
182 EVENT_BUBBLE|EVENT_CANCELABLE},
183 {keydownW, onkeydownW, EVENTT_KEY, DISPID_EVMETH_ONKEYDOWN,
184 EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_HASDEFAULTHANDLERS},
185 {keypressW, onkeypressW, EVENTT_KEY, DISPID_EVMETH_ONKEYPRESS,
186 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
187 {keyupW, onkeyupW, EVENTT_KEY, DISPID_EVMETH_ONKEYUP,
188 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
189 {loadW, onloadW, EVENTT_HTML, DISPID_EVMETH_ONLOAD,
190 EVENT_BIND_TO_BODY},
191 {mousedownW, onmousedownW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
192 EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE},
193 {mousemoveW, onmousemoveW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEMOVE,
194 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
195 {mouseoutW, onmouseoutW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOUT,
196 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
197 {mouseoverW, onmouseoverW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOVER,
198 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
199 {mouseupW, onmouseupW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEUP,
200 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
201 {mousewheelW, onmousewheelW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEWHEEL,
202 0},
203 {pasteW, onpasteW, EVENTT_NONE, DISPID_EVMETH_ONPASTE,
204 EVENT_CANCELABLE},
205 {readystatechangeW, onreadystatechangeW, EVENTT_NONE, DISPID_EVMETH_ONREADYSTATECHANGE,
206 0},
207 {resizeW, onresizeW, EVENTT_NONE, DISPID_EVMETH_ONRESIZE,
208 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
209 {scrollW, onscrollW, EVENTT_HTML, DISPID_EVMETH_ONSCROLL,
210 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
211 {selectstartW, onselectstartW, EVENTT_MOUSE, DISPID_EVMETH_ONSELECTSTART,
212 EVENT_CANCELABLE},
213 {submitW, onsubmitW, EVENTT_HTML, DISPID_EVMETH_ONSUBMIT,
214 EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE|EVENT_HASDEFAULTHANDLERS}
215 };
216
str_to_eid(LPCWSTR str)217 eventid_t str_to_eid(LPCWSTR str)
218 {
219 int i;
220
221 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
222 if(!strcmpW(event_info[i].name, str))
223 return i;
224 }
225
226 ERR("unknown type %s\n", debugstr_w(str));
227 return EVENTID_LAST;
228 }
229
attr_to_eid(LPCWSTR str)230 static eventid_t attr_to_eid(LPCWSTR str)
231 {
232 int i;
233
234 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
235 if(!strcmpW(event_info[i].attr_name, str))
236 return i;
237 }
238
239 return EVENTID_LAST;
240 }
241
242 struct HTMLEventObj {
243 DispatchEx dispex;
244 IHTMLEventObj IHTMLEventObj_iface;
245
246 LONG ref;
247
248 HTMLDOMNode *target;
249 const event_info_t *type;
250 nsIDOMEvent *nsevent;
251 VARIANT return_value;
252 BOOL prevent_default;
253 BOOL cancel_bubble;
254 };
255
impl_from_IHTMLEventObj(IHTMLEventObj * iface)256 static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface)
257 {
258 return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj_iface);
259 }
260
HTMLEventObj_QueryInterface(IHTMLEventObj * iface,REFIID riid,void ** ppv)261 static HRESULT WINAPI HTMLEventObj_QueryInterface(IHTMLEventObj *iface, REFIID riid, void **ppv)
262 {
263 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
264
265 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
266
267 if(IsEqualGUID(&IID_IUnknown, riid)) {
268 *ppv = &This->IHTMLEventObj_iface;
269 }else if(IsEqualGUID(&IID_IHTMLEventObj, riid)) {
270 *ppv = &This->IHTMLEventObj_iface;
271 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
272 return *ppv ? S_OK : E_NOINTERFACE;
273 }else {
274 *ppv = NULL;
275 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
276 return E_NOINTERFACE;
277 }
278
279 IUnknown_AddRef((IUnknown*)*ppv);
280 return S_OK;
281 }
282
HTMLEventObj_AddRef(IHTMLEventObj * iface)283 static ULONG WINAPI HTMLEventObj_AddRef(IHTMLEventObj *iface)
284 {
285 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
286 LONG ref = InterlockedIncrement(&This->ref);
287
288 TRACE("(%p) ref=%d\n", This, ref);
289
290 return ref;
291 }
292
HTMLEventObj_Release(IHTMLEventObj * iface)293 static ULONG WINAPI HTMLEventObj_Release(IHTMLEventObj *iface)
294 {
295 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
296 LONG ref = InterlockedDecrement(&This->ref);
297
298 TRACE("(%p) ref=%d\n", This, ref);
299
300 if(!ref) {
301 if(This->target)
302 IHTMLDOMNode_Release(&This->target->IHTMLDOMNode_iface);
303 if(This->nsevent)
304 nsIDOMEvent_Release(This->nsevent);
305 release_dispex(&This->dispex);
306 heap_free(This);
307 }
308
309 return ref;
310 }
311
HTMLEventObj_GetTypeInfoCount(IHTMLEventObj * iface,UINT * pctinfo)312 static HRESULT WINAPI HTMLEventObj_GetTypeInfoCount(IHTMLEventObj *iface, UINT *pctinfo)
313 {
314 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
315 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
316 }
317
HTMLEventObj_GetTypeInfo(IHTMLEventObj * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)318 static HRESULT WINAPI HTMLEventObj_GetTypeInfo(IHTMLEventObj *iface, UINT iTInfo,
319 LCID lcid, ITypeInfo **ppTInfo)
320 {
321 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
322 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
323 }
324
HTMLEventObj_GetIDsOfNames(IHTMLEventObj * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)325 static HRESULT WINAPI HTMLEventObj_GetIDsOfNames(IHTMLEventObj *iface, REFIID riid,
326 LPOLESTR *rgszNames, UINT cNames,
327 LCID lcid, DISPID *rgDispId)
328 {
329 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
330 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
331 lcid, rgDispId);
332 }
333
HTMLEventObj_Invoke(IHTMLEventObj * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)334 static HRESULT WINAPI HTMLEventObj_Invoke(IHTMLEventObj *iface, DISPID dispIdMember,
335 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
336 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
337 {
338 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
339 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
340 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
341 }
342
HTMLEventObj_get_srcElement(IHTMLEventObj * iface,IHTMLElement ** p)343 static HRESULT WINAPI HTMLEventObj_get_srcElement(IHTMLEventObj *iface, IHTMLElement **p)
344 {
345 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
346
347 TRACE("(%p)->(%p)\n", This, p);
348
349 *p = NULL;
350 if(This->target)
351 IHTMLDOMNode_QueryInterface(&This->target->IHTMLDOMNode_iface, &IID_IHTMLElement, (void**)p);
352 return S_OK;
353 }
354
HTMLEventObj_get_altKey(IHTMLEventObj * iface,VARIANT_BOOL * p)355 static HRESULT WINAPI HTMLEventObj_get_altKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
356 {
357 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
358 cpp_bool ret = FALSE;
359
360 TRACE("(%p)->(%p)\n", This, p);
361
362 if(This->nsevent) {
363 nsIDOMKeyEvent *key_event;
364 nsresult nsres;
365
366 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
367 if(NS_SUCCEEDED(nsres)) {
368 nsIDOMKeyEvent_GetAltKey(key_event, &ret);
369 nsIDOMKeyEvent_Release(key_event);
370 }else {
371 nsIDOMMouseEvent *mouse_event;
372
373 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
374 if(NS_SUCCEEDED(nsres)) {
375 nsIDOMMouseEvent_GetAltKey(mouse_event, &ret);
376 nsIDOMMouseEvent_Release(mouse_event);
377 }
378 }
379 }
380
381 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
382 return S_OK;
383 }
384
HTMLEventObj_get_ctrlKey(IHTMLEventObj * iface,VARIANT_BOOL * p)385 static HRESULT WINAPI HTMLEventObj_get_ctrlKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
386 {
387 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
388 cpp_bool ret = FALSE;
389
390 TRACE("(%p)->(%p)\n", This, p);
391
392 if(This->nsevent) {
393 nsIDOMKeyEvent *key_event;
394 nsresult nsres;
395
396 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
397 if(NS_SUCCEEDED(nsres)) {
398 nsIDOMKeyEvent_GetCtrlKey(key_event, &ret);
399 nsIDOMKeyEvent_Release(key_event);
400 }else {
401 nsIDOMMouseEvent *mouse_event;
402
403 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
404 if(NS_SUCCEEDED(nsres)) {
405 nsIDOMMouseEvent_GetCtrlKey(mouse_event, &ret);
406 nsIDOMMouseEvent_Release(mouse_event);
407 }
408 }
409 }
410
411 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
412 return S_OK;
413 }
414
HTMLEventObj_get_shiftKey(IHTMLEventObj * iface,VARIANT_BOOL * p)415 static HRESULT WINAPI HTMLEventObj_get_shiftKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
416 {
417 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
418 cpp_bool ret = FALSE;
419
420 TRACE("(%p)->(%p)\n", This, p);
421
422 if(This->nsevent) {
423 nsIDOMKeyEvent *key_event;
424 nsresult nsres;
425
426 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
427 if(NS_SUCCEEDED(nsres)) {
428 nsIDOMKeyEvent_GetShiftKey(key_event, &ret);
429 nsIDOMKeyEvent_Release(key_event);
430 }else {
431 nsIDOMMouseEvent *mouse_event;
432
433 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
434 if(NS_SUCCEEDED(nsres)) {
435 nsIDOMMouseEvent_GetShiftKey(mouse_event, &ret);
436 nsIDOMMouseEvent_Release(mouse_event);
437 }
438 }
439 }
440
441 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
442 return S_OK;
443 }
444
HTMLEventObj_put_returnValue(IHTMLEventObj * iface,VARIANT v)445 static HRESULT WINAPI HTMLEventObj_put_returnValue(IHTMLEventObj *iface, VARIANT v)
446 {
447 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
448
449 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
450
451 if(V_VT(&v) != VT_BOOL) {
452 FIXME("unsupported value %s\n", debugstr_variant(&v));
453 return DISP_E_BADVARTYPE;
454 }
455
456 This->return_value = v;
457 if(!V_BOOL(&v))
458 This->prevent_default = TRUE;
459 return S_OK;
460 }
461
HTMLEventObj_get_returnValue(IHTMLEventObj * iface,VARIANT * p)462 static HRESULT WINAPI HTMLEventObj_get_returnValue(IHTMLEventObj *iface, VARIANT *p)
463 {
464 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
465
466 TRACE("(%p)->(%p)\n", This, p);
467
468 V_VT(p) = VT_EMPTY;
469 return VariantCopy(p, &This->return_value);
470 }
471
HTMLEventObj_put_cancelBubble(IHTMLEventObj * iface,VARIANT_BOOL v)472 static HRESULT WINAPI HTMLEventObj_put_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL v)
473 {
474 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
475
476 TRACE("(%p)->(%x)\n", This, v);
477
478 This->cancel_bubble = !!v;
479 return S_OK;
480 }
481
HTMLEventObj_get_cancelBubble(IHTMLEventObj * iface,VARIANT_BOOL * p)482 static HRESULT WINAPI HTMLEventObj_get_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL *p)
483 {
484 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
485
486 TRACE("(%p)->(%p)\n", This, p);
487
488 *p = This->cancel_bubble ? VARIANT_TRUE : VARIANT_FALSE;
489 return S_OK;
490 }
491
HTMLEventObj_get_fromElement(IHTMLEventObj * iface,IHTMLElement ** p)492 static HRESULT WINAPI HTMLEventObj_get_fromElement(IHTMLEventObj *iface, IHTMLElement **p)
493 {
494 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
495
496 FIXME("(%p)->(%p)\n", This, p);
497
498 *p = NULL;
499 return S_OK;
500 }
501
HTMLEventObj_get_toElement(IHTMLEventObj * iface,IHTMLElement ** p)502 static HRESULT WINAPI HTMLEventObj_get_toElement(IHTMLEventObj *iface, IHTMLElement **p)
503 {
504 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
505
506 FIXME("(%p)->(%p)\n", This, p);
507
508 *p = NULL;
509 return S_OK;
510 }
511
HTMLEventObj_put_keyCode(IHTMLEventObj * iface,LONG v)512 static HRESULT WINAPI HTMLEventObj_put_keyCode(IHTMLEventObj *iface, LONG v)
513 {
514 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
515 FIXME("(%p)->(%d)\n", This, v);
516 return E_NOTIMPL;
517 }
518
HTMLEventObj_get_keyCode(IHTMLEventObj * iface,LONG * p)519 static HRESULT WINAPI HTMLEventObj_get_keyCode(IHTMLEventObj *iface, LONG *p)
520 {
521 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
522 UINT32 key_code = 0;
523
524 TRACE("(%p)->(%p)\n", This, p);
525
526 if(This->nsevent) {
527 nsIDOMKeyEvent *key_event;
528 nsresult nsres;
529
530 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
531 if(NS_SUCCEEDED(nsres)) {
532 nsIDOMKeyEvent_GetKeyCode(key_event, &key_code);
533 nsIDOMKeyEvent_Release(key_event);
534 }
535 }
536
537 *p = key_code;
538 return S_OK;
539 }
540
HTMLEventObj_get_button(IHTMLEventObj * iface,LONG * p)541 static HRESULT WINAPI HTMLEventObj_get_button(IHTMLEventObj *iface, LONG *p)
542 {
543 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
544 INT16 button = 0;
545
546 TRACE("(%p)->(%p)\n", This, p);
547
548 if(This->nsevent) {
549 nsIDOMMouseEvent *mouse_event;
550 nsresult nsres;
551
552 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
553 if(NS_SUCCEEDED(nsres)) {
554 nsIDOMMouseEvent_GetButton(mouse_event, &button);
555 nsIDOMMouseEvent_Release(mouse_event);
556 }
557 }
558
559 *p = button;
560 return S_OK;
561 }
562
HTMLEventObj_get_type(IHTMLEventObj * iface,BSTR * p)563 static HRESULT WINAPI HTMLEventObj_get_type(IHTMLEventObj *iface, BSTR *p)
564 {
565 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
566
567 TRACE("(%p)->(%p)\n", This, p);
568
569 if(!This->type) {
570 *p = NULL;
571 return S_OK;
572 }
573
574 *p = SysAllocString(This->type->name);
575 return *p ? S_OK : E_OUTOFMEMORY;
576 }
577
HTMLEventObj_get_qualifier(IHTMLEventObj * iface,BSTR * p)578 static HRESULT WINAPI HTMLEventObj_get_qualifier(IHTMLEventObj *iface, BSTR *p)
579 {
580 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
581
582 FIXME("(%p)->(%p)\n", This, p);
583
584 *p = NULL;
585 return S_OK;
586 }
587
HTMLEventObj_get_reason(IHTMLEventObj * iface,LONG * p)588 static HRESULT WINAPI HTMLEventObj_get_reason(IHTMLEventObj *iface, LONG *p)
589 {
590 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
591
592 FIXME("(%p)->(%p)\n", This, p);
593
594 *p = 0;
595 return S_OK;
596 }
597
HTMLEventObj_get_x(IHTMLEventObj * iface,LONG * p)598 static HRESULT WINAPI HTMLEventObj_get_x(IHTMLEventObj *iface, LONG *p)
599 {
600 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
601 LONG x = 0;
602
603 TRACE("(%p)->(%p)\n", This, p);
604
605 if(This->nsevent) {
606 nsIDOMUIEvent *ui_event;
607 nsresult nsres;
608
609 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMUIEvent, (void**)&ui_event);
610 if(NS_SUCCEEDED(nsres)) {
611 /* NOTE: pageX is not exactly right here. */
612 nsres = nsIDOMUIEvent_GetPageX(ui_event, &x);
613 assert(nsres == NS_OK);
614 nsIDOMUIEvent_Release(ui_event);
615 }
616 }
617
618 *p = x;
619 return S_OK;
620 }
621
HTMLEventObj_get_y(IHTMLEventObj * iface,LONG * p)622 static HRESULT WINAPI HTMLEventObj_get_y(IHTMLEventObj *iface, LONG *p)
623 {
624 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
625 LONG y = 0;
626
627 TRACE("(%p)->(%p)\n", This, p);
628
629 if(This->nsevent) {
630 nsIDOMUIEvent *ui_event;
631 nsresult nsres;
632
633 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMUIEvent, (void**)&ui_event);
634 if(NS_SUCCEEDED(nsres)) {
635 /* NOTE: pageY is not exactly right here. */
636 nsres = nsIDOMUIEvent_GetPageY(ui_event, &y);
637 assert(nsres == NS_OK);
638 nsIDOMUIEvent_Release(ui_event);
639 }
640 }
641
642 *p = y;
643 return S_OK;
644 }
645
HTMLEventObj_get_clientX(IHTMLEventObj * iface,LONG * p)646 static HRESULT WINAPI HTMLEventObj_get_clientX(IHTMLEventObj *iface, LONG *p)
647 {
648 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
649 LONG x = 0;
650
651 TRACE("(%p)->(%p)\n", This, p);
652
653 if(This->nsevent) {
654 nsIDOMMouseEvent *mouse_event;
655 nsresult nsres;
656
657 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
658 if(NS_SUCCEEDED(nsres)) {
659 nsIDOMMouseEvent_GetClientX(mouse_event, &x);
660 nsIDOMMouseEvent_Release(mouse_event);
661 }
662 }
663
664 *p = x;
665 return S_OK;
666 }
667
HTMLEventObj_get_clientY(IHTMLEventObj * iface,LONG * p)668 static HRESULT WINAPI HTMLEventObj_get_clientY(IHTMLEventObj *iface, LONG *p)
669 {
670 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
671 LONG y = 0;
672
673 TRACE("(%p)->(%p)\n", This, p);
674
675 if(This->nsevent) {
676 nsIDOMMouseEvent *mouse_event;
677 nsresult nsres;
678
679 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
680 if(NS_SUCCEEDED(nsres)) {
681 nsIDOMMouseEvent_GetClientY(mouse_event, &y);
682 nsIDOMMouseEvent_Release(mouse_event);
683 }
684 }
685
686 *p = y;
687 return S_OK;
688 }
689
HTMLEventObj_get_offsetX(IHTMLEventObj * iface,LONG * p)690 static HRESULT WINAPI HTMLEventObj_get_offsetX(IHTMLEventObj *iface, LONG *p)
691 {
692 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
693
694 FIXME("(%p)->(%p)\n", This, p);
695
696 *p = 0;
697 return S_OK;
698 }
699
HTMLEventObj_get_offsetY(IHTMLEventObj * iface,LONG * p)700 static HRESULT WINAPI HTMLEventObj_get_offsetY(IHTMLEventObj *iface, LONG *p)
701 {
702 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
703
704 FIXME("(%p)->(%p)\n", This, p);
705
706 *p = 0;
707 return S_OK;
708 }
709
HTMLEventObj_get_screenX(IHTMLEventObj * iface,LONG * p)710 static HRESULT WINAPI HTMLEventObj_get_screenX(IHTMLEventObj *iface, LONG *p)
711 {
712 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
713 LONG x = 0;
714
715 TRACE("(%p)->(%p)\n", This, p);
716
717 if(This->nsevent) {
718 nsIDOMMouseEvent *mouse_event;
719 nsresult nsres;
720
721 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
722 if(NS_SUCCEEDED(nsres)) {
723 nsIDOMMouseEvent_GetScreenX(mouse_event, &x);
724 nsIDOMMouseEvent_Release(mouse_event);
725 }
726 }
727
728 *p = x;
729 return S_OK;
730 }
731
HTMLEventObj_get_screenY(IHTMLEventObj * iface,LONG * p)732 static HRESULT WINAPI HTMLEventObj_get_screenY(IHTMLEventObj *iface, LONG *p)
733 {
734 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
735 LONG y = 0;
736
737 TRACE("(%p)->(%p)\n", This, p);
738
739 if(This->nsevent) {
740 nsIDOMMouseEvent *mouse_event;
741 nsresult nsres;
742
743 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
744 if(NS_SUCCEEDED(nsres)) {
745 nsIDOMMouseEvent_GetScreenY(mouse_event, &y);
746 nsIDOMMouseEvent_Release(mouse_event);
747 }
748 }
749
750 *p = y;
751 return S_OK;
752 }
753
HTMLEventObj_get_srcFilter(IHTMLEventObj * iface,IDispatch ** p)754 static HRESULT WINAPI HTMLEventObj_get_srcFilter(IHTMLEventObj *iface, IDispatch **p)
755 {
756 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
757
758 FIXME("(%p)->(%p)\n", This, p);
759
760 *p = NULL;
761 return S_OK;
762 }
763
764 static const IHTMLEventObjVtbl HTMLEventObjVtbl = {
765 HTMLEventObj_QueryInterface,
766 HTMLEventObj_AddRef,
767 HTMLEventObj_Release,
768 HTMLEventObj_GetTypeInfoCount,
769 HTMLEventObj_GetTypeInfo,
770 HTMLEventObj_GetIDsOfNames,
771 HTMLEventObj_Invoke,
772 HTMLEventObj_get_srcElement,
773 HTMLEventObj_get_altKey,
774 HTMLEventObj_get_ctrlKey,
775 HTMLEventObj_get_shiftKey,
776 HTMLEventObj_put_returnValue,
777 HTMLEventObj_get_returnValue,
778 HTMLEventObj_put_cancelBubble,
779 HTMLEventObj_get_cancelBubble,
780 HTMLEventObj_get_fromElement,
781 HTMLEventObj_get_toElement,
782 HTMLEventObj_put_keyCode,
783 HTMLEventObj_get_keyCode,
784 HTMLEventObj_get_button,
785 HTMLEventObj_get_type,
786 HTMLEventObj_get_qualifier,
787 HTMLEventObj_get_reason,
788 HTMLEventObj_get_x,
789 HTMLEventObj_get_y,
790 HTMLEventObj_get_clientX,
791 HTMLEventObj_get_clientY,
792 HTMLEventObj_get_offsetX,
793 HTMLEventObj_get_offsetY,
794 HTMLEventObj_get_screenX,
795 HTMLEventObj_get_screenY,
796 HTMLEventObj_get_srcFilter
797 };
798
unsafe_impl_from_IHTMLEventObj(IHTMLEventObj * iface)799 static inline HTMLEventObj *unsafe_impl_from_IHTMLEventObj(IHTMLEventObj *iface)
800 {
801 return iface->lpVtbl == &HTMLEventObjVtbl ? impl_from_IHTMLEventObj(iface) : NULL;
802 }
803
804 static const tid_t HTMLEventObj_iface_tids[] = {
805 IHTMLEventObj_tid,
806 0
807 };
808
809 static dispex_static_data_t HTMLEventObj_dispex = {
810 NULL,
811 DispCEventObj_tid,
812 NULL,
813 HTMLEventObj_iface_tids
814 };
815
create_event(void)816 static HTMLEventObj *create_event(void)
817 {
818 HTMLEventObj *ret;
819
820 ret = heap_alloc_zero(sizeof(*ret));
821 if(!ret)
822 return NULL;
823
824 ret->IHTMLEventObj_iface.lpVtbl = &HTMLEventObjVtbl;
825 ret->ref = 1;
826
827 init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLEventObj_iface, &HTMLEventObj_dispex);
828
829 return ret;
830 }
831
set_event_info(HTMLEventObj * event,HTMLDOMNode * target,eventid_t eid,nsIDOMEvent * nsevent)832 static HRESULT set_event_info(HTMLEventObj *event, HTMLDOMNode *target, eventid_t eid, nsIDOMEvent *nsevent)
833 {
834 event->type = event_info+eid;
835 event->nsevent = nsevent;
836
837 if(nsevent) {
838 nsIDOMEvent_AddRef(nsevent);
839 }else if(event_types[event_info[eid].type]) {
840 nsAString type_str;
841 nsresult nsres;
842
843 nsAString_InitDepend(&type_str, event_types[event_info[eid].type]);
844 nsres = nsIDOMHTMLDocument_CreateEvent(target->doc->nsdoc, &type_str, &event->nsevent);
845 nsAString_Finish(&type_str);
846 if(NS_FAILED(nsres)) {
847 ERR("Could not create event: %08x\n", nsres);
848 return E_FAIL;
849 }
850 }
851
852 event->target = target;
853 if(target)
854 IHTMLDOMNode_AddRef(&target->IHTMLDOMNode_iface);
855 return S_OK;
856 }
857
create_event_obj(IHTMLEventObj ** ret)858 HRESULT create_event_obj(IHTMLEventObj **ret)
859 {
860 HTMLEventObj *event;
861
862 event = create_event();
863 if(!event)
864 return E_OUTOFMEMORY;
865
866 *ret = &event->IHTMLEventObj_iface;
867 return S_OK;
868 }
869
get_event_target_data(EventTarget * event_target,BOOL alloc)870 static inline event_target_t *get_event_target_data(EventTarget *event_target, BOOL alloc)
871 {
872 event_target_t **ptr;
873
874 ptr = event_target->dispex.data->vtbl && event_target->dispex.data->vtbl->get_event_target_ptr
875 ? event_target->dispex.data->vtbl->get_event_target_ptr(&event_target->dispex)
876 : &event_target->ptr;
877 if(*ptr || !alloc)
878 return *ptr;
879
880 return *ptr = heap_alloc_zero(sizeof(event_target_t));
881 }
882
call_disp_func(IDispatch * disp,DISPPARAMS * dp,VARIANT * retv)883 static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
884 {
885 IDispatchEx *dispex;
886 EXCEPINFO ei;
887 HRESULT hres;
888
889 memset(&ei, 0, sizeof(ei));
890
891 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
892 if(SUCCEEDED(hres)) {
893 hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, dp, retv, &ei, NULL);
894 IDispatchEx_Release(dispex);
895 }else {
896 TRACE("Could not get IDispatchEx interface: %08x\n", hres);
897 hres = IDispatch_Invoke(disp, 0, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD,
898 dp, retv, &ei, NULL);
899 }
900
901 return hres;
902 }
903
call_cp_func(IDispatch * disp,DISPID dispid,HTMLEventObj * event_obj,VARIANT * retv)904 static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, HTMLEventObj *event_obj, VARIANT *retv)
905 {
906 DISPPARAMS dp = {NULL,NULL,0,0};
907 VARIANT event_arg;
908 ULONG argerr;
909 EXCEPINFO ei;
910
911 if(event_obj) {
912 V_VT(&event_arg) = VT_DISPATCH;
913 V_DISPATCH(&event_arg) = (IDispatch*)&event_obj->IHTMLEventObj_iface;
914 dp.rgvarg = &event_arg;
915 dp.cArgs = 1;
916 }
917
918 memset(&ei, 0, sizeof(ei));
919 return IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, retv, &ei, &argerr);
920 }
921
is_cp_event(cp_static_data_t * data,DISPID dispid)922 static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
923 {
924 int min, max, i;
925 HRESULT hres;
926
927 if(!data)
928 return FALSE;
929
930 if(!data->ids) {
931 hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
932 if(FAILED(hres))
933 return FALSE;
934 }
935
936 min = 0;
937 max = data->id_cnt-1;
938 while(min <= max) {
939 i = (min+max)/2;
940 if(data->ids[i] == dispid)
941 return TRUE;
942
943 if(data->ids[i] < dispid)
944 min = i+1;
945 else
946 max = i-1;
947 }
948
949 return FALSE;
950 }
951
call_event_handlers(HTMLDocumentNode * doc,HTMLEventObj * event_obj,EventTarget * event_target,ConnectionPointContainer * cp_container,eventid_t eid,IDispatch * this_obj)952 void call_event_handlers(HTMLDocumentNode *doc, HTMLEventObj *event_obj, EventTarget *event_target,
953 ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj)
954 {
955 event_target_t *data = get_event_target_data(event_target, FALSE);
956 const BOOL cancelable = event_info[eid].flags & EVENT_CANCELABLE;
957 VARIANT v;
958 HRESULT hres;
959
960 if(data && data->event_table[eid] && data->event_table[eid]->handler_prop) {
961 DISPID named_arg = DISPID_THIS;
962 VARIANTARG arg;
963 DISPPARAMS dp = {&arg, &named_arg, 1, 1};
964
965 V_VT(&arg) = VT_DISPATCH;
966 V_DISPATCH(&arg) = this_obj;
967 V_VT(&v) = VT_EMPTY;
968
969 TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
970 hres = call_disp_func(data->event_table[eid]->handler_prop, &dp, &v);
971 if(hres == S_OK) {
972 TRACE("%s <<< %s\n", debugstr_w(event_info[eid].name), debugstr_variant(&v));
973
974 if(cancelable) {
975 if(V_VT(&v) == VT_BOOL) {
976 if(!V_BOOL(&v))
977 event_obj->prevent_default = TRUE;
978 }else if(V_VT(&v) != VT_EMPTY) {
979 FIXME("unhandled result %s\n", debugstr_variant(&v));
980 }
981 }
982 VariantClear(&v);
983 }else {
984 WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
985 }
986 }
987
988 if(data && data->event_table[eid] && data->event_table[eid]->handler_cnt) {
989 VARIANTARG arg;
990 DISPPARAMS dp = {&arg, NULL, 1, 0};
991 int i;
992
993 V_VT(&arg) = VT_DISPATCH;
994 V_DISPATCH(&arg) = (IDispatch*)event_obj;
995
996 i = data->event_table[eid]->handler_cnt;
997 while(i--) {
998 if(data->event_table[eid]->handlers[i]) {
999 V_VT(&v) = VT_EMPTY;
1000
1001 TRACE("%s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
1002 hres = call_disp_func(data->event_table[eid]->handlers[i], &dp, &v);
1003 if(hres == S_OK) {
1004 TRACE("%s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
1005
1006 if(cancelable) {
1007 if(V_VT(&v) == VT_BOOL) {
1008 if(!V_BOOL(&v))
1009 event_obj->prevent_default = TRUE;
1010 }else if(V_VT(&v) != VT_EMPTY) {
1011 FIXME("unhandled result %s\n", debugstr_variant(&v));
1012 }
1013 }
1014 VariantClear(&v);
1015 }else {
1016 WARN("%s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
1017 }
1018 }
1019 }
1020 }
1021
1022 /*
1023 * NOTE: CP events may require doc_obj reference, which we don't own. We make sure that
1024 * it's safe to call event handler by checking nsevent_listener, which is NULL for
1025 * detached documents.
1026 */
1027 if(cp_container && cp_container->forward_container)
1028 cp_container = cp_container->forward_container;
1029 if(cp_container && cp_container->cps && doc->nsevent_listener) {
1030 ConnectionPoint *cp;
1031 unsigned i, j;
1032
1033 for(j=0; cp_container->cp_entries[j].riid; j++) {
1034 cp = cp_container->cps + j;
1035 if(!cp->sinks_size || !is_cp_event(cp->data, event_info[eid].dispid))
1036 continue;
1037
1038 for(i=0; doc->nsevent_listener && i < cp->sinks_size; i++) {
1039 if(!cp->sinks[i].disp)
1040 continue;
1041
1042 V_VT(&v) = VT_EMPTY;
1043
1044 TRACE("cp %s [%u] >>>\n", debugstr_w(event_info[eid].name), i);
1045 hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid,
1046 cp->data->pass_event_arg ? event_obj : NULL, &v);
1047 if(hres == S_OK) {
1048 TRACE("cp %s [%u] <<<\n", debugstr_w(event_info[eid].name), i);
1049
1050 if(cancelable) {
1051 if(V_VT(&v) == VT_BOOL) {
1052 if(!V_BOOL(&v))
1053 event_obj->prevent_default = TRUE;
1054 }else if(V_VT(&v) != VT_EMPTY) {
1055 FIXME("unhandled result %s\n", debugstr_variant(&v));
1056 }
1057 }
1058 VariantClear(&v);
1059 }else {
1060 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
1061 }
1062 }
1063
1064 if(!doc->nsevent_listener)
1065 break;
1066 }
1067 }
1068 }
1069
fire_event_obj(HTMLDocumentNode * doc,eventid_t eid,HTMLEventObj * event_obj,nsIDOMNode * target,IDispatch * script_this)1070 static void fire_event_obj(HTMLDocumentNode *doc, eventid_t eid, HTMLEventObj *event_obj,
1071 nsIDOMNode *target, IDispatch *script_this)
1072 {
1073 IHTMLEventObj *prev_event;
1074 nsIDOMNode *parent, *nsnode;
1075 BOOL prevent_default = FALSE;
1076 HTMLInnerWindow *window;
1077 HTMLDOMNode *node;
1078 UINT16 node_type;
1079 nsresult nsres;
1080 HRESULT hres;
1081
1082 TRACE("(%p) %s\n", doc, debugstr_w(event_info[eid].name));
1083
1084 window = doc->window;
1085 if(!window) {
1086 WARN("NULL window\n");
1087 return;
1088 }
1089
1090 htmldoc_addref(&doc->basedoc);
1091
1092 prev_event = window->event;
1093 window->event = event_obj ? &event_obj->IHTMLEventObj_iface : NULL;
1094
1095 nsIDOMNode_GetNodeType(target, &node_type);
1096 nsnode = target;
1097 nsIDOMNode_AddRef(nsnode);
1098
1099 switch(node_type) {
1100 case ELEMENT_NODE:
1101 do {
1102 hres = get_node(doc, nsnode, FALSE, &node);
1103 if(SUCCEEDED(hres) && node) {
1104 call_event_handlers(doc, event_obj, &node->event_target, node->cp_container, eid,
1105 script_this ? script_this : (IDispatch*)&node->IHTMLDOMNode_iface);
1106 node_release(node);
1107 }
1108
1109 if(!(event_info[eid].flags & EVENT_BUBBLE) || (event_obj && event_obj->cancel_bubble))
1110 break;
1111
1112 nsIDOMNode_GetParentNode(nsnode, &parent);
1113 nsIDOMNode_Release(nsnode);
1114 nsnode = parent;
1115 if(!nsnode)
1116 break;
1117
1118 nsIDOMNode_GetNodeType(nsnode, &node_type);
1119 }while(node_type == ELEMENT_NODE);
1120
1121 if(!(event_info[eid].flags & EVENT_BUBBLE) || (event_obj && event_obj->cancel_bubble))
1122 break;
1123
1124 case DOCUMENT_NODE:
1125 if(event_info[eid].flags & EVENT_FORWARDBODY) {
1126 nsIDOMHTMLElement *nsbody;
1127 nsresult nsres;
1128
1129 nsres = nsIDOMHTMLDocument_GetBody(doc->nsdoc, &nsbody);
1130 if(NS_SUCCEEDED(nsres) && nsbody) {
1131 hres = get_node(doc, (nsIDOMNode*)nsbody, FALSE, &node);
1132 if(SUCCEEDED(hres) && node) {
1133 call_event_handlers(doc, event_obj, &node->event_target, node->cp_container, eid,
1134 script_this ? script_this : (IDispatch*)&node->IHTMLDOMNode_iface);
1135 node_release(node);
1136 }
1137 nsIDOMHTMLElement_Release(nsbody);
1138 }else {
1139 ERR("Could not get body: %08x\n", nsres);
1140 }
1141 }
1142
1143 call_event_handlers(doc, event_obj, &doc->node.event_target, &doc->basedoc.cp_container, eid,
1144 script_this ? script_this : (IDispatch*)&doc->basedoc.IHTMLDocument2_iface);
1145 break;
1146
1147 default:
1148 FIXME("unimplemented node type %d\n", node_type);
1149 }
1150
1151 if(nsnode)
1152 nsIDOMNode_Release(nsnode);
1153
1154 if(event_obj && event_obj->prevent_default)
1155 prevent_default = TRUE;
1156 window->event = prev_event;
1157
1158 if(!prevent_default && (event_info[eid].flags & EVENT_HASDEFAULTHANDLERS)) {
1159 nsIDOMNode_AddRef(target);
1160 nsnode = target;
1161
1162 do {
1163 hres = get_node(doc, nsnode, TRUE, &node);
1164 if(FAILED(hres))
1165 break;
1166
1167 if(node) {
1168 if(node->vtbl->handle_event)
1169 hres = node->vtbl->handle_event(node, eid, event_obj ? event_obj->nsevent : NULL, &prevent_default);
1170 node_release(node);
1171 if(FAILED(hres) || prevent_default || (event_obj && event_obj->cancel_bubble))
1172 break;
1173 }
1174
1175 nsres = nsIDOMNode_GetParentNode(nsnode, &parent);
1176 if(NS_FAILED(nsres))
1177 break;
1178
1179 nsIDOMNode_Release(nsnode);
1180 nsnode = parent;
1181 } while(nsnode);
1182
1183 if(nsnode)
1184 nsIDOMNode_Release(nsnode);
1185 }
1186
1187 if(prevent_default && event_obj && event_obj->nsevent) {
1188 TRACE("calling PreventDefault\n");
1189 nsIDOMEvent_PreventDefault(event_obj->nsevent);
1190 }
1191
1192 htmldoc_release(&doc->basedoc);
1193 }
1194
fire_event(HTMLDocumentNode * doc,eventid_t eid,BOOL set_event,nsIDOMNode * target,nsIDOMEvent * nsevent,IDispatch * script_this)1195 void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode *target, nsIDOMEvent *nsevent,
1196 IDispatch *script_this)
1197 {
1198 HTMLEventObj *event_obj = NULL;
1199 HTMLDOMNode *node;
1200 HRESULT hres;
1201
1202 if(set_event) {
1203 hres = get_node(doc, target, TRUE, &node);
1204 if(FAILED(hres))
1205 return;
1206
1207 event_obj = create_event();
1208 node_release(node);
1209 if(!event_obj)
1210 return;
1211
1212 hres = set_event_info(event_obj, node, eid, nsevent);
1213 if(FAILED(hres)) {
1214 IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
1215 return;
1216 }
1217 }
1218
1219 fire_event_obj(doc, eid, event_obj, target, script_this);
1220
1221 if(event_obj)
1222 IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
1223 }
1224
dispatch_event(HTMLDOMNode * node,const WCHAR * event_name,VARIANT * event_var,VARIANT_BOOL * cancelled)1225 HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_var, VARIANT_BOOL *cancelled)
1226 {
1227 HTMLEventObj *event_obj = NULL;
1228 eventid_t eid;
1229 HRESULT hres;
1230
1231 eid = attr_to_eid(event_name);
1232 if(eid == EVENTID_LAST) {
1233 WARN("unknown event %s\n", debugstr_w(event_name));
1234 return E_INVALIDARG;
1235 }
1236
1237 if(event_var && V_VT(event_var) != VT_EMPTY && V_VT(event_var) != VT_ERROR) {
1238 if(V_VT(event_var) != VT_DISPATCH) {
1239 FIXME("event_var %s not supported\n", debugstr_variant(event_var));
1240 return E_NOTIMPL;
1241 }
1242
1243 if(V_DISPATCH(event_var)) {
1244 IHTMLEventObj *event_iface;
1245
1246 hres = IDispatch_QueryInterface(V_DISPATCH(event_var), &IID_IHTMLEventObj, (void**)&event_iface);
1247 if(FAILED(hres)) {
1248 FIXME("No IHTMLEventObj iface\n");
1249 return hres;
1250 }
1251
1252 event_obj = unsafe_impl_from_IHTMLEventObj(event_iface);
1253 if(!event_obj) {
1254 ERR("Not our IHTMLEventObj?\n");
1255 IHTMLEventObj_Release(event_iface);
1256 return E_FAIL;
1257 }
1258 }
1259 }
1260
1261 if(event_obj) {
1262 hres = set_event_info(event_obj, node, eid, NULL);
1263 if(SUCCEEDED(hres))
1264 fire_event_obj(node->doc, eid, event_obj, node->nsnode, NULL);
1265
1266 IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
1267 if(FAILED(hres))
1268 return hres;
1269 }else {
1270 if(!(event_info[eid].flags & EVENT_DEFAULTLISTENER)) {
1271 FIXME("not EVENT_DEFAULTEVENTHANDLER\n");
1272 return E_NOTIMPL;
1273 }
1274
1275 fire_event(node->doc, eid, TRUE, node->nsnode, NULL, NULL);
1276 }
1277
1278 *cancelled = VARIANT_TRUE; /* FIXME */
1279 return S_OK;
1280 }
1281
call_fire_event(HTMLDOMNode * node,eventid_t eid)1282 HRESULT call_fire_event(HTMLDOMNode *node, eventid_t eid)
1283 {
1284 HRESULT hres;
1285
1286 if(node->vtbl->fire_event) {
1287 BOOL handled = FALSE;
1288
1289 hres = node->vtbl->fire_event(node, eid, &handled);
1290 if(handled)
1291 return hres;
1292 }
1293
1294 fire_event(node->doc, eid, TRUE, node->nsnode, NULL, NULL);
1295 return S_OK;
1296 }
1297
alloc_handler_vector(event_target_t * event_target,eventid_t eid,int cnt)1298 static BOOL alloc_handler_vector(event_target_t *event_target, eventid_t eid, int cnt)
1299 {
1300 handler_vector_t *new_vector, *handler_vector = event_target->event_table[eid];
1301
1302 if(handler_vector) {
1303 if(cnt <= handler_vector->handler_cnt)
1304 return TRUE;
1305
1306 new_vector = heap_realloc_zero(handler_vector, sizeof(handler_vector_t) + sizeof(IDispatch*)*cnt);
1307 }else {
1308 new_vector = heap_alloc_zero(sizeof(handler_vector_t) + sizeof(IDispatch*)*cnt);
1309 }
1310
1311 if(!new_vector)
1312 return FALSE;
1313
1314 new_vector->handler_cnt = cnt;
1315 event_target->event_table[eid] = new_vector;
1316 return TRUE;
1317 }
1318
ensure_doc_nsevent_handler(HTMLDocumentNode * doc,eventid_t eid)1319 HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, eventid_t eid)
1320 {
1321 nsIDOMNode *nsnode = NULL;
1322
1323 TRACE("%s\n", debugstr_w(event_info[eid].name));
1324
1325 if(!doc->nsdoc || doc->event_vector[eid] || !(event_info[eid].flags & (EVENT_DEFAULTLISTENER|EVENT_BIND_TO_BODY)))
1326 return S_OK;
1327
1328 if(event_info[eid].flags & EVENT_BIND_TO_BODY) {
1329 nsnode = doc->node.nsnode;
1330 nsIDOMNode_AddRef(nsnode);
1331 }
1332
1333 doc->event_vector[eid] = TRUE;
1334 add_nsevent_listener(doc, nsnode, event_info[eid].name);
1335
1336 if(nsnode)
1337 nsIDOMNode_Release(nsnode);
1338 return S_OK;
1339 }
1340
detach_events(HTMLDocumentNode * doc)1341 void detach_events(HTMLDocumentNode *doc)
1342 {
1343 if(doc->event_vector) {
1344 int i;
1345
1346 for(i=0; i < EVENTID_LAST; i++) {
1347 if(doc->event_vector[i]) {
1348 detach_nsevent(doc, event_info[i].name);
1349 doc->event_vector[i] = FALSE;
1350 }
1351 }
1352 }
1353
1354 release_nsevents(doc);
1355 }
1356
bind_event(EventTarget * event_target,eventid_t eid)1357 static void bind_event(EventTarget *event_target, eventid_t eid)
1358 {
1359 if(event_target->dispex.data->vtbl->bind_event)
1360 event_target->dispex.data->vtbl->bind_event(&event_target->dispex, eid);
1361 else
1362 FIXME("Unsupported event binding on target %p\n", event_target);
1363 }
1364
remove_event_handler(EventTarget * event_target,eventid_t eid)1365 static void remove_event_handler(EventTarget *event_target, eventid_t eid)
1366 {
1367 event_target_t *data;
1368 VARIANT *store;
1369 HRESULT hres;
1370
1371 hres = dispex_get_dprop_ref(&event_target->dispex, event_info[eid].attr_name, FALSE, &store);
1372 if(SUCCEEDED(hres))
1373 VariantClear(store);
1374
1375 data = get_event_target_data(event_target, FALSE);
1376 if(data && data->event_table[eid] && data->event_table[eid]->handler_prop) {
1377 IDispatch_Release(data->event_table[eid]->handler_prop);
1378 data->event_table[eid]->handler_prop = NULL;
1379 }
1380 }
1381
set_event_handler_disp(EventTarget * event_target,eventid_t eid,IDispatch * disp)1382 static HRESULT set_event_handler_disp(EventTarget *event_target, eventid_t eid, IDispatch *disp)
1383 {
1384 event_target_t *data;
1385
1386 remove_event_handler(event_target, eid);
1387 if(!disp)
1388 return S_OK;
1389
1390 data = get_event_target_data(event_target, TRUE);
1391 if(!data)
1392 return E_OUTOFMEMORY;
1393
1394 if(!alloc_handler_vector(data, eid, 0))
1395 return E_OUTOFMEMORY;
1396
1397 data->event_table[eid]->handler_prop = disp;
1398 IDispatch_AddRef(disp);
1399
1400 bind_event(event_target, eid);
1401 return S_OK;
1402 }
1403
set_event_handler(EventTarget * event_target,eventid_t eid,VARIANT * var)1404 HRESULT set_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
1405 {
1406 switch(V_VT(var)) {
1407 case VT_NULL:
1408 remove_event_handler(event_target, eid);
1409 return S_OK;
1410
1411 case VT_DISPATCH:
1412 return set_event_handler_disp(event_target, eid, V_DISPATCH(var));
1413
1414 case VT_BSTR: {
1415 VARIANT *v;
1416 HRESULT hres;
1417
1418 /*
1419 * Setting event handler to string is a rare case and we don't want to
1420 * complicate nor increase memory of event_target_t for that. Instead,
1421 * we store the value in DispatchEx, which can already handle custom
1422 * properties.
1423 */
1424 remove_event_handler(event_target, eid);
1425
1426 hres = dispex_get_dprop_ref(&event_target->dispex, event_info[eid].attr_name, TRUE, &v);
1427 if(FAILED(hres))
1428 return hres;
1429
1430 V_BSTR(v) = SysAllocString(V_BSTR(var));
1431 if(!V_BSTR(v))
1432 return E_OUTOFMEMORY;
1433 V_VT(v) = VT_BSTR;
1434 return S_OK;
1435 }
1436
1437 default:
1438 FIXME("not handler %s\n", debugstr_variant(var));
1439 /* fall through */
1440 case VT_EMPTY:
1441 return E_NOTIMPL;
1442 }
1443
1444 return S_OK;
1445 }
1446
get_event_handler(EventTarget * event_target,eventid_t eid,VARIANT * var)1447 HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
1448 {
1449 event_target_t *data;
1450 VARIANT *v;
1451 HRESULT hres;
1452
1453 hres = dispex_get_dprop_ref(&event_target->dispex, event_info[eid].attr_name, FALSE, &v);
1454 if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY)
1455 return VariantCopy(var, v);
1456
1457 data = get_event_target_data(event_target, FALSE);
1458 if(data && data->event_table[eid] && data->event_table[eid]->handler_prop) {
1459 V_VT(var) = VT_DISPATCH;
1460 V_DISPATCH(var) = data->event_table[eid]->handler_prop;
1461 IDispatch_AddRef(V_DISPATCH(var));
1462 }else {
1463 V_VT(var) = VT_NULL;
1464 }
1465
1466 return S_OK;
1467 }
1468
attach_event(EventTarget * event_target,BSTR name,IDispatch * disp,VARIANT_BOOL * res)1469 HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARIANT_BOOL *res)
1470 {
1471 event_target_t *data;
1472 eventid_t eid;
1473 DWORD i = 0;
1474
1475 eid = attr_to_eid(name);
1476 if(eid == EVENTID_LAST) {
1477 WARN("Unknown event\n");
1478 *res = VARIANT_TRUE;
1479 return S_OK;
1480 }
1481
1482 data = get_event_target_data(event_target, TRUE);
1483 if(!data)
1484 return E_OUTOFMEMORY;
1485
1486 if(data->event_table[eid]) {
1487 while(i < data->event_table[eid]->handler_cnt && data->event_table[eid]->handlers[i])
1488 i++;
1489 if(i == data->event_table[eid]->handler_cnt && !alloc_handler_vector(data, eid, i+1))
1490 return E_OUTOFMEMORY;
1491 }else if(!alloc_handler_vector(data, eid, i+1)) {
1492 return E_OUTOFMEMORY;
1493 }
1494
1495 IDispatch_AddRef(disp);
1496 data->event_table[eid]->handlers[i] = disp;
1497
1498 bind_event(event_target, eid);
1499
1500 *res = VARIANT_TRUE;
1501 return S_OK;
1502 }
1503
detach_event(EventTarget * event_target,BSTR name,IDispatch * disp)1504 HRESULT detach_event(EventTarget *event_target, BSTR name, IDispatch *disp)
1505 {
1506 event_target_t *data;
1507 eventid_t eid;
1508 DWORD i = 0;
1509
1510 eid = attr_to_eid(name);
1511 if(eid == EVENTID_LAST) {
1512 WARN("Unknown event\n");
1513 return S_OK;
1514 }
1515
1516 data = get_event_target_data(event_target, FALSE);
1517 if(!data)
1518 return S_OK;
1519
1520 if(!data->event_table[eid])
1521 return S_OK;
1522
1523 while(i < data->event_table[eid]->handler_cnt) {
1524 if(data->event_table[eid]->handlers[i] == disp) {
1525 IDispatch_Release(data->event_table[eid]->handlers[i]);
1526 data->event_table[eid]->handlers[i] = NULL;
1527 }
1528 i++;
1529 }
1530
1531 return S_OK;
1532 }
1533
bind_target_event(HTMLDocumentNode * doc,EventTarget * event_target,const WCHAR * event,IDispatch * disp)1534 void bind_target_event(HTMLDocumentNode *doc, EventTarget *event_target, const WCHAR *event, IDispatch *disp)
1535 {
1536 eventid_t eid;
1537
1538 TRACE("(%p %p %s %p)\n", doc, event_target, debugstr_w(event), disp);
1539
1540 eid = attr_to_eid(event);
1541 if(eid == EVENTID_LAST) {
1542 WARN("Unsupported event %s\n", debugstr_w(event));
1543 return;
1544 }
1545
1546 set_event_handler_disp(event_target, eid, disp);
1547 }
1548
update_doc_cp_events(HTMLDocumentNode * doc,cp_static_data_t * cp)1549 void update_doc_cp_events(HTMLDocumentNode *doc, cp_static_data_t *cp)
1550 {
1551 int i;
1552
1553 for(i=0; i < EVENTID_LAST; i++) {
1554 if((event_info[i].flags & EVENT_DEFAULTLISTENER) && is_cp_event(cp, event_info[i].dispid))
1555 ensure_doc_nsevent_handler(doc, i);
1556 }
1557 }
1558
check_event_attr(HTMLDocumentNode * doc,nsIDOMHTMLElement * nselem)1559 void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
1560 {
1561 const PRUnichar *attr_value;
1562 nsAString attr_value_str;
1563 IDispatch *disp;
1564 HTMLDOMNode *node;
1565 int i;
1566 nsresult nsres;
1567 HRESULT hres;
1568
1569 for(i=0; i < EVENTID_LAST; i++) {
1570 nsres = get_elem_attr_value(nselem, event_info[i].attr_name, &attr_value_str, &attr_value);
1571 if(NS_SUCCEEDED(nsres)) {
1572 if(!*attr_value)
1573 continue;
1574
1575 TRACE("%p.%s = %s\n", nselem, debugstr_w(event_info[i].attr_name), debugstr_w(attr_value));
1576
1577 disp = script_parse_event(doc->window, attr_value);
1578 if(disp) {
1579 hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
1580 if(SUCCEEDED(hres)) {
1581 set_event_handler_disp(&node->event_target, i, disp);
1582 node_release(node);
1583 }
1584 IDispatch_Release(disp);
1585 }
1586 nsAString_Finish(&attr_value_str);
1587 }
1588 }
1589 }
1590
doc_init_events(HTMLDocumentNode * doc)1591 HRESULT doc_init_events(HTMLDocumentNode *doc)
1592 {
1593 unsigned i;
1594 HRESULT hres;
1595
1596 doc->event_vector = heap_alloc_zero(EVENTID_LAST*sizeof(BOOL));
1597 if(!doc->event_vector)
1598 return E_OUTOFMEMORY;
1599
1600 init_nsevents(doc);
1601
1602 for(i=0; i < EVENTID_LAST; i++) {
1603 if(event_info[i].flags & EVENT_HASDEFAULTHANDLERS) {
1604 hres = ensure_doc_nsevent_handler(doc, i);
1605 if(FAILED(hres))
1606 return hres;
1607 }
1608 }
1609
1610 return S_OK;
1611 }
1612
release_event_target(event_target_t * event_target)1613 void release_event_target(event_target_t *event_target)
1614 {
1615 int i;
1616 unsigned int j;
1617
1618 for(i=0; i < EVENTID_LAST; i++) {
1619 if(event_target->event_table[i]) {
1620 if(event_target->event_table[i]->handler_prop)
1621 IDispatch_Release(event_target->event_table[i]->handler_prop);
1622 for(j=0; j < event_target->event_table[i]->handler_cnt; j++)
1623 if(event_target->event_table[i]->handlers[j])
1624 IDispatch_Release(event_target->event_table[i]->handlers[j]);
1625 }
1626 }
1627
1628 heap_free(event_target);
1629 }
1630