2 * Copyright 2008-2009 Jacek Caban for CodeWeavers
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.
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.
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
30 #include "mshtml_private.h"
31 #include "htmlevent.h"
32 #include "htmlscript.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml
);
39 LISTENER_TYPE_CAPTURE
,
41 LISTENER_TYPE_ONEVENT
,
42 LISTENER_TYPE_ATTACHED
52 struct wine_rb_entry entry
;
53 struct list listeners
;
55 } listener_container_t
;
57 static const WCHAR abortW
[] = {'a','b','o','r','t',0};
58 static const WCHAR beforeactivateW
[] = {'b','e','f','o','r','e','a','c','t','i','v','a','t','e',0};
59 static const WCHAR beforeunloadW
[] = {'b','e','f','o','r','e','u','n','l','o','a','d',0};
60 static const WCHAR blurW
[] = {'b','l','u','r',0};
61 static const WCHAR changeW
[] = {'c','h','a','n','g','e',0};
62 static const WCHAR clickW
[] = {'c','l','i','c','k',0};
63 static const WCHAR contextmenuW
[] = {'c','o','n','t','e','x','t','m','e','n','u',0};
64 static const WCHAR dataavailableW
[] = {'d','a','t','a','a','v','a','i','l','a','b','l','e',0};
65 static const WCHAR dblclickW
[] = {'d','b','l','c','l','i','c','k',0};
66 static const WCHAR dragW
[] = {'d','r','a','g',0};
67 static const WCHAR dragstartW
[] = {'d','r','a','g','s','t','a','r','t',0};
68 static const WCHAR errorW
[] = {'e','r','r','o','r',0};
69 static const WCHAR focusW
[] = {'f','o','c','u','s',0};
70 static const WCHAR focusinW
[] = {'f','o','c','u','s','i','n',0};
71 static const WCHAR focusoutW
[] = {'f','o','c','u','s','o','u','t',0};
72 static const WCHAR helpW
[] = {'h','e','l','p',0};
73 static const WCHAR keydownW
[] = {'k','e','y','d','o','w','n',0};
74 static const WCHAR keypressW
[] = {'k','e','y','p','r','e','s','s',0};
75 static const WCHAR keyupW
[] = {'k','e','y','u','p',0};
76 static const WCHAR loadW
[] = {'l','o','a','d',0};
77 static const WCHAR messageW
[] = {'m','e','s','s','a','g','e',0};
78 static const WCHAR mousedownW
[] = {'m','o','u','s','e','d','o','w','n',0};
79 static const WCHAR mousemoveW
[] = {'m','o','u','s','e','m','o','v','e',0};
80 static const WCHAR mouseoutW
[] = {'m','o','u','s','e','o','u','t',0};
81 static const WCHAR mouseoverW
[] = {'m','o','u','s','e','o','v','e','r',0};
82 static const WCHAR mouseupW
[] = {'m','o','u','s','e','u','p',0};
83 static const WCHAR mousewheelW
[] = {'m','o','u','s','e','w','h','e','e','l',0};
84 static const WCHAR pasteW
[] = {'p','a','s','t','e',0};
85 static const WCHAR readystatechangeW
[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
86 static const WCHAR resizeW
[] = {'r','e','s','i','z','e',0};
87 static const WCHAR scrollW
[] = {'s','c','r','o','l','l',0};
88 static const WCHAR selectstartW
[] = {'s','e','l','e','c','t','s','t','a','r','t',0};
89 static const WCHAR selectionchangeW
[] = {'s','e','l','e','c','t','i','o','n','c','h','a','n','g','e',0};
90 static const WCHAR submitW
[] = {'s','u','b','m','i','t',0};
91 static const WCHAR unloadW
[] = {'u','n','l','o','a','d',0};
92 static const WCHAR DOMContentLoadedW
[] = {'D','O','M','C','o','n','t','e','n','t','L','o','a','d','e','d',0};
94 static const WCHAR EventW
[] = {'E','v','e','n','t',0};
95 static const WCHAR UIEventW
[] = {'U','I','E','v','e','n','t',0};
96 static const WCHAR KeyboardEventW
[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
97 static const WCHAR MouseEventW
[] = {'M','o','u','s','e','E','v','e','n','t',0};
110 static const WCHAR
*event_types
[] = {
128 #define EVENT_DEFAULTLISTENER 0x0001
129 #define EVENT_BUBBLES 0x0002
130 #define EVENT_BIND_TO_BODY 0x0008
131 #define EVENT_CANCELABLE 0x0010
132 #define EVENT_HASDEFAULTHANDLERS 0x0020
133 #define EVENT_FIXME 0x0040
135 static const event_info_t event_info
[] = {
136 {abortW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONABORT
,
138 {beforeactivateW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONBEFOREACTIVATE
,
139 EVENT_FIXME
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
140 {beforeunloadW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONBEFOREUNLOAD
,
141 EVENT_DEFAULTLISTENER
| EVENT_CANCELABLE
},
142 {blurW
, EVENT_TYPE_FOCUS
, DISPID_EVMETH_ONBLUR
,
143 EVENT_DEFAULTLISTENER
},
144 {changeW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONCHANGE
,
145 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
},
146 {clickW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONCLICK
,
147 EVENT_DEFAULTLISTENER
| EVENT_HASDEFAULTHANDLERS
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
148 {contextmenuW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONCONTEXTMENU
,
149 EVENT_BUBBLES
| EVENT_CANCELABLE
},
150 {dataavailableW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONDATAAVAILABLE
,
151 EVENT_FIXME
| EVENT_BUBBLES
},
152 {dblclickW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONDBLCLICK
,
153 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
154 {DOMContentLoadedW
, EVENT_TYPE_EVENT
, 0,
155 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
156 {dragW
, EVENT_TYPE_DRAG
, DISPID_EVMETH_ONDRAG
,
157 EVENT_FIXME
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
158 {dragstartW
, EVENT_TYPE_DRAG
, DISPID_EVMETH_ONDRAGSTART
,
159 EVENT_FIXME
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
160 {errorW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONERROR
,
162 {focusW
, EVENT_TYPE_FOCUS
, DISPID_EVMETH_ONFOCUS
,
163 EVENT_DEFAULTLISTENER
},
164 {focusinW
, EVENT_TYPE_FOCUS
, DISPID_EVMETH_ONFOCUSIN
,
166 {focusoutW
, EVENT_TYPE_FOCUS
, DISPID_EVMETH_ONFOCUSOUT
,
168 {helpW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONHELP
,
169 EVENT_BUBBLES
| EVENT_CANCELABLE
},
170 {keydownW
, EVENT_TYPE_KEYBOARD
, DISPID_EVMETH_ONKEYDOWN
,
171 EVENT_DEFAULTLISTENER
| EVENT_HASDEFAULTHANDLERS
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
172 {keypressW
, EVENT_TYPE_KEYBOARD
, DISPID_EVMETH_ONKEYPRESS
,
173 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
174 {keyupW
, EVENT_TYPE_KEYBOARD
, DISPID_EVMETH_ONKEYUP
,
175 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
176 {loadW
, EVENT_TYPE_UIEVENT
, DISPID_EVMETH_ONLOAD
,
178 {messageW
, EVENT_TYPE_MESSAGE
, DISPID_EVMETH_ONMESSAGE
,
180 {mousedownW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONMOUSEDOWN
,
181 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
182 {mousemoveW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONMOUSEMOVE
,
183 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
184 {mouseoutW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONMOUSEOUT
,
185 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
186 {mouseoverW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONMOUSEOVER
,
187 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
188 {mouseupW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONMOUSEUP
,
189 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
190 {mousewheelW
, EVENT_TYPE_MOUSE
, DISPID_EVMETH_ONMOUSEWHEEL
,
192 {pasteW
, EVENT_TYPE_CLIPBOARD
, DISPID_EVMETH_ONPASTE
,
193 EVENT_FIXME
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
194 {readystatechangeW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONREADYSTATECHANGE
,
196 {resizeW
, EVENT_TYPE_UIEVENT
, DISPID_EVMETH_ONRESIZE
,
197 EVENT_DEFAULTLISTENER
},
198 {scrollW
, EVENT_TYPE_UIEVENT
, DISPID_EVMETH_ONSCROLL
,
199 EVENT_DEFAULTLISTENER
| EVENT_BUBBLES
/* FIXME: not for elements */},
200 {selectionchangeW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONSELECTIONCHANGE
,
202 {selectstartW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONSELECTSTART
,
203 EVENT_FIXME
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
204 {submitW
, EVENT_TYPE_EVENT
, DISPID_EVMETH_ONSUBMIT
,
205 EVENT_DEFAULTLISTENER
| EVENT_HASDEFAULTHANDLERS
| EVENT_BUBBLES
| EVENT_CANCELABLE
},
206 {unloadW
, EVENT_TYPE_UIEVENT
, DISPID_EVMETH_ONUNLOAD
,
210 static BOOL
use_event_quirks(EventTarget
*);
212 static eventid_t
str_to_eid(const WCHAR
*str
)
216 for(i
=0; i
< sizeof(event_info
)/sizeof(event_info
[0]); i
++) {
217 if(!strcmpW(event_info
[i
].name
, str
))
221 ERR("unknown type %s\n", debugstr_w(str
));
225 static eventid_t
attr_to_eid(const WCHAR
*str
)
229 if((str
[0] != 'o' && str
[0] != 'O') || (str
[1] != 'n' && str
[1] != 'N'))
232 for(i
=0; i
< sizeof(event_info
)/sizeof(event_info
[0]); i
++) {
233 if(!strcmpW(event_info
[i
].name
, str
+2) && event_info
[i
].dispid
)
240 static listener_container_t
*get_listener_container(EventTarget
*event_target
, const WCHAR
*type
, BOOL alloc
)
242 const event_target_vtbl_t
*vtbl
;
243 listener_container_t
*container
;
244 struct wine_rb_entry
*entry
;
248 entry
= wine_rb_get(&event_target
->handler_map
, type
);
250 return WINE_RB_ENTRY_VALUE(entry
, listener_container_t
, entry
);
254 eid
= str_to_eid(type
);
255 if(eid
!= EVENTID_LAST
&& (event_info
[eid
].flags
& EVENT_FIXME
))
256 FIXME("unimplemented event %s\n", debugstr_w(event_info
[eid
].name
));
258 type_len
= strlenW(type
);
259 container
= heap_alloc(FIELD_OFFSET(listener_container_t
, type
[type_len
+1]));
262 memcpy(container
->type
, type
, (type_len
+ 1) * sizeof(WCHAR
));
263 list_init(&container
->listeners
);
264 vtbl
= dispex_get_vtbl(&event_target
->dispex
);
266 vtbl
->bind_event(&event_target
->dispex
, eid
);
268 FIXME("Unsupported event binding on target %p\n", event_target
);
270 wine_rb_put(&event_target
->handler_map
, container
->type
, &container
->entry
);
274 static void remove_event_listener(EventTarget
*event_target
, const WCHAR
*type_name
, listener_type_t type
, IDispatch
*function
)
276 listener_container_t
*container
;
277 event_listener_t
*listener
;
279 container
= get_listener_container(event_target
, type_name
, FALSE
);
283 LIST_FOR_EACH_ENTRY(listener
, &container
->listeners
, event_listener_t
, entry
) {
284 if(listener
->function
== function
&& listener
->type
== type
) {
285 IDispatch_Release(listener
->function
);
286 list_remove(&listener
->entry
);
295 IHTMLEventObj IHTMLEventObj_iface
;
300 VARIANT return_value
;
303 static inline HTMLEventObj
*impl_from_IHTMLEventObj(IHTMLEventObj
*iface
)
305 return CONTAINING_RECORD(iface
, HTMLEventObj
, IHTMLEventObj_iface
);
308 static HRESULT WINAPI
HTMLEventObj_QueryInterface(IHTMLEventObj
*iface
, REFIID riid
, void **ppv
)
310 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
312 TRACE("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
314 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
315 *ppv
= &This
->IHTMLEventObj_iface
;
316 }else if(IsEqualGUID(&IID_IHTMLEventObj
, riid
)) {
317 *ppv
= &This
->IHTMLEventObj_iface
;
318 }else if(dispex_query_interface(&This
->dispex
, riid
, ppv
)) {
319 return *ppv
? S_OK
: E_NOINTERFACE
;
322 WARN("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
323 return E_NOINTERFACE
;
326 IUnknown_AddRef((IUnknown
*)*ppv
);
330 static ULONG WINAPI
HTMLEventObj_AddRef(IHTMLEventObj
*iface
)
332 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
333 LONG ref
= InterlockedIncrement(&This
->ref
);
335 TRACE("(%p) ref=%d\n", This
, ref
);
340 static ULONG WINAPI
HTMLEventObj_Release(IHTMLEventObj
*iface
)
342 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
343 LONG ref
= InterlockedDecrement(&This
->ref
);
345 TRACE("(%p) ref=%d\n", This
, ref
);
349 IDOMEvent_Release(&This
->event
->IDOMEvent_iface
);
350 release_dispex(&This
->dispex
);
357 static HRESULT WINAPI
HTMLEventObj_GetTypeInfoCount(IHTMLEventObj
*iface
, UINT
*pctinfo
)
359 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
360 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
363 static HRESULT WINAPI
HTMLEventObj_GetTypeInfo(IHTMLEventObj
*iface
, UINT iTInfo
,
364 LCID lcid
, ITypeInfo
**ppTInfo
)
366 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
367 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
370 static HRESULT WINAPI
HTMLEventObj_GetIDsOfNames(IHTMLEventObj
*iface
, REFIID riid
,
371 LPOLESTR
*rgszNames
, UINT cNames
,
372 LCID lcid
, DISPID
*rgDispId
)
374 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
375 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
, rgszNames
, cNames
,
379 static HRESULT WINAPI
HTMLEventObj_Invoke(IHTMLEventObj
*iface
, DISPID dispIdMember
,
380 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
381 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
383 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
384 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
, riid
, lcid
,
385 wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
388 static HRESULT WINAPI
HTMLEventObj_get_srcElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
390 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
392 TRACE("(%p)->(%p)\n", This
, p
);
395 if(This
->event
&& This
->event
->target
)
396 IDispatchEx_QueryInterface(&This
->event
->target
->dispex
.IDispatchEx_iface
, &IID_IHTMLElement
, (void**)p
);
400 static HRESULT WINAPI
HTMLEventObj_get_altKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
402 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
403 cpp_bool ret
= FALSE
;
405 TRACE("(%p)->(%p)\n", This
, p
);
408 nsIDOMKeyEvent
*key_event
;
411 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
412 if(NS_SUCCEEDED(nsres
)) {
413 nsIDOMKeyEvent_GetAltKey(key_event
, &ret
);
414 nsIDOMKeyEvent_Release(key_event
);
416 nsIDOMMouseEvent
*mouse_event
;
418 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
419 if(NS_SUCCEEDED(nsres
)) {
420 nsIDOMMouseEvent_GetAltKey(mouse_event
, &ret
);
421 nsIDOMMouseEvent_Release(mouse_event
);
426 *p
= variant_bool(ret
);
430 static HRESULT WINAPI
HTMLEventObj_get_ctrlKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
432 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
433 cpp_bool ret
= FALSE
;
435 TRACE("(%p)->(%p)\n", This
, p
);
438 nsIDOMKeyEvent
*key_event
;
441 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
442 if(NS_SUCCEEDED(nsres
)) {
443 nsIDOMKeyEvent_GetCtrlKey(key_event
, &ret
);
444 nsIDOMKeyEvent_Release(key_event
);
446 nsIDOMMouseEvent
*mouse_event
;
448 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
449 if(NS_SUCCEEDED(nsres
)) {
450 nsIDOMMouseEvent_GetCtrlKey(mouse_event
, &ret
);
451 nsIDOMMouseEvent_Release(mouse_event
);
456 *p
= variant_bool(ret
);
460 static HRESULT WINAPI
HTMLEventObj_get_shiftKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
462 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
463 cpp_bool ret
= FALSE
;
465 TRACE("(%p)->(%p)\n", This
, p
);
468 nsIDOMKeyEvent
*key_event
;
471 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
472 if(NS_SUCCEEDED(nsres
)) {
473 nsIDOMKeyEvent_GetShiftKey(key_event
, &ret
);
474 nsIDOMKeyEvent_Release(key_event
);
476 nsIDOMMouseEvent
*mouse_event
;
478 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
479 if(NS_SUCCEEDED(nsres
)) {
480 nsIDOMMouseEvent_GetShiftKey(mouse_event
, &ret
);
481 nsIDOMMouseEvent_Release(mouse_event
);
486 *p
= variant_bool(ret
);
490 static HRESULT WINAPI
HTMLEventObj_put_returnValue(IHTMLEventObj
*iface
, VARIANT v
)
492 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
494 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&v
));
496 if(V_VT(&v
) != VT_BOOL
) {
497 FIXME("unsupported value %s\n", debugstr_variant(&v
));
498 return DISP_E_BADVARTYPE
;
501 This
->return_value
= v
;
502 if(!V_BOOL(&v
) && This
->event
)
503 IDOMEvent_preventDefault(&This
->event
->IDOMEvent_iface
);
507 static HRESULT WINAPI
HTMLEventObj_get_returnValue(IHTMLEventObj
*iface
, VARIANT
*p
)
509 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
511 TRACE("(%p)->(%p)\n", This
, p
);
514 return VariantCopy(p
, &This
->return_value
);
517 static HRESULT WINAPI
HTMLEventObj_put_cancelBubble(IHTMLEventObj
*iface
, VARIANT_BOOL v
)
519 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
521 TRACE("(%p)->(%x)\n", This
, v
);
524 IDOMEvent_stopPropagation(&This
->event
->IDOMEvent_iface
);
528 static HRESULT WINAPI
HTMLEventObj_get_cancelBubble(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
530 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
532 TRACE("(%p)->(%p)\n", This
, p
);
534 *p
= variant_bool(This
->event
&& This
->event
->stop_propagation
);
538 static HRESULT WINAPI
HTMLEventObj_get_fromElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
540 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
542 FIXME("(%p)->(%p)\n", This
, p
);
548 static HRESULT WINAPI
HTMLEventObj_get_toElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
550 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
552 FIXME("(%p)->(%p)\n", This
, p
);
558 static HRESULT WINAPI
HTMLEventObj_put_keyCode(IHTMLEventObj
*iface
, LONG v
)
560 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
561 FIXME("(%p)->(%d)\n", This
, v
);
565 static HRESULT WINAPI
HTMLEventObj_get_keyCode(IHTMLEventObj
*iface
, LONG
*p
)
567 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
570 TRACE("(%p)->(%p)\n", This
, p
);
573 nsIDOMKeyEvent
*key_event
;
576 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
577 if(NS_SUCCEEDED(nsres
)) {
578 nsIDOMKeyEvent_GetKeyCode(key_event
, &key_code
);
579 nsIDOMKeyEvent_Release(key_event
);
587 static HRESULT WINAPI
HTMLEventObj_get_button(IHTMLEventObj
*iface
, LONG
*p
)
589 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
592 TRACE("(%p)->(%p)\n", This
, p
);
595 nsIDOMMouseEvent
*mouse_event
;
598 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
599 if(NS_SUCCEEDED(nsres
)) {
600 nsIDOMMouseEvent_GetButton(mouse_event
, &button
);
601 nsIDOMMouseEvent_Release(mouse_event
);
609 static HRESULT WINAPI
HTMLEventObj_get_type(IHTMLEventObj
*iface
, BSTR
*p
)
611 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
613 TRACE("(%p)->(%p)\n", This
, p
);
620 return IDOMEvent_get_type(&This
->event
->IDOMEvent_iface
, p
);
623 static HRESULT WINAPI
HTMLEventObj_get_qualifier(IHTMLEventObj
*iface
, BSTR
*p
)
625 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
627 FIXME("(%p)->(%p)\n", This
, p
);
633 static HRESULT WINAPI
HTMLEventObj_get_reason(IHTMLEventObj
*iface
, LONG
*p
)
635 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
637 FIXME("(%p)->(%p)\n", This
, p
);
643 static HRESULT WINAPI
HTMLEventObj_get_x(IHTMLEventObj
*iface
, LONG
*p
)
645 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
648 TRACE("(%p)->(%p)\n", This
, p
);
651 nsIDOMUIEvent
*ui_event
;
654 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMUIEvent
, (void**)&ui_event
);
655 if(NS_SUCCEEDED(nsres
)) {
656 /* NOTE: pageX is not exactly right here. */
657 nsres
= nsIDOMUIEvent_GetPageX(ui_event
, &x
);
658 assert(nsres
== NS_OK
);
659 nsIDOMUIEvent_Release(ui_event
);
667 static HRESULT WINAPI
HTMLEventObj_get_y(IHTMLEventObj
*iface
, LONG
*p
)
669 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
672 TRACE("(%p)->(%p)\n", This
, p
);
675 nsIDOMUIEvent
*ui_event
;
678 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMUIEvent
, (void**)&ui_event
);
679 if(NS_SUCCEEDED(nsres
)) {
680 /* NOTE: pageY is not exactly right here. */
681 nsres
= nsIDOMUIEvent_GetPageY(ui_event
, &y
);
682 assert(nsres
== NS_OK
);
683 nsIDOMUIEvent_Release(ui_event
);
691 static HRESULT WINAPI
HTMLEventObj_get_clientX(IHTMLEventObj
*iface
, LONG
*p
)
693 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
696 TRACE("(%p)->(%p)\n", This
, p
);
699 nsIDOMMouseEvent
*mouse_event
;
702 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
703 if(NS_SUCCEEDED(nsres
)) {
704 nsIDOMMouseEvent_GetClientX(mouse_event
, &x
);
705 nsIDOMMouseEvent_Release(mouse_event
);
713 static HRESULT WINAPI
HTMLEventObj_get_clientY(IHTMLEventObj
*iface
, LONG
*p
)
715 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
718 TRACE("(%p)->(%p)\n", This
, p
);
721 nsIDOMMouseEvent
*mouse_event
;
724 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
725 if(NS_SUCCEEDED(nsres
)) {
726 nsIDOMMouseEvent_GetClientY(mouse_event
, &y
);
727 nsIDOMMouseEvent_Release(mouse_event
);
735 static HRESULT WINAPI
HTMLEventObj_get_offsetX(IHTMLEventObj
*iface
, LONG
*p
)
737 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
739 FIXME("(%p)->(%p)\n", This
, p
);
745 static HRESULT WINAPI
HTMLEventObj_get_offsetY(IHTMLEventObj
*iface
, LONG
*p
)
747 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
749 FIXME("(%p)->(%p)\n", This
, p
);
755 static HRESULT WINAPI
HTMLEventObj_get_screenX(IHTMLEventObj
*iface
, LONG
*p
)
757 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
760 TRACE("(%p)->(%p)\n", This
, p
);
763 nsIDOMMouseEvent
*mouse_event
;
766 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
767 if(NS_SUCCEEDED(nsres
)) {
768 nsIDOMMouseEvent_GetScreenX(mouse_event
, &x
);
769 nsIDOMMouseEvent_Release(mouse_event
);
777 static HRESULT WINAPI
HTMLEventObj_get_screenY(IHTMLEventObj
*iface
, LONG
*p
)
779 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
782 TRACE("(%p)->(%p)\n", This
, p
);
785 nsIDOMMouseEvent
*mouse_event
;
788 nsres
= nsIDOMEvent_QueryInterface(This
->event
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
789 if(NS_SUCCEEDED(nsres
)) {
790 nsIDOMMouseEvent_GetScreenY(mouse_event
, &y
);
791 nsIDOMMouseEvent_Release(mouse_event
);
799 static HRESULT WINAPI
HTMLEventObj_get_srcFilter(IHTMLEventObj
*iface
, IDispatch
**p
)
801 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
803 FIXME("(%p)->(%p)\n", This
, p
);
809 static const IHTMLEventObjVtbl HTMLEventObjVtbl
= {
810 HTMLEventObj_QueryInterface
,
812 HTMLEventObj_Release
,
813 HTMLEventObj_GetTypeInfoCount
,
814 HTMLEventObj_GetTypeInfo
,
815 HTMLEventObj_GetIDsOfNames
,
817 HTMLEventObj_get_srcElement
,
818 HTMLEventObj_get_altKey
,
819 HTMLEventObj_get_ctrlKey
,
820 HTMLEventObj_get_shiftKey
,
821 HTMLEventObj_put_returnValue
,
822 HTMLEventObj_get_returnValue
,
823 HTMLEventObj_put_cancelBubble
,
824 HTMLEventObj_get_cancelBubble
,
825 HTMLEventObj_get_fromElement
,
826 HTMLEventObj_get_toElement
,
827 HTMLEventObj_put_keyCode
,
828 HTMLEventObj_get_keyCode
,
829 HTMLEventObj_get_button
,
830 HTMLEventObj_get_type
,
831 HTMLEventObj_get_qualifier
,
832 HTMLEventObj_get_reason
,
835 HTMLEventObj_get_clientX
,
836 HTMLEventObj_get_clientY
,
837 HTMLEventObj_get_offsetX
,
838 HTMLEventObj_get_offsetY
,
839 HTMLEventObj_get_screenX
,
840 HTMLEventObj_get_screenY
,
841 HTMLEventObj_get_srcFilter
844 static inline HTMLEventObj
*unsafe_impl_from_IHTMLEventObj(IHTMLEventObj
*iface
)
846 return iface
->lpVtbl
== &HTMLEventObjVtbl
? impl_from_IHTMLEventObj(iface
) : NULL
;
849 static const tid_t HTMLEventObj_iface_tids
[] = {
854 static dispex_static_data_t HTMLEventObj_dispex
= {
857 HTMLEventObj_iface_tids
860 static HTMLEventObj
*alloc_event_obj(DOMEvent
*event
)
862 HTMLEventObj
*event_obj
;
864 event_obj
= heap_alloc_zero(sizeof(*event_obj
));
868 event_obj
->IHTMLEventObj_iface
.lpVtbl
= &HTMLEventObjVtbl
;
870 event_obj
->event
= event
;
872 IDOMEvent_AddRef(&event
->IDOMEvent_iface
);
874 init_dispex(&event_obj
->dispex
, (IUnknown
*)&event_obj
->IHTMLEventObj_iface
, &HTMLEventObj_dispex
);
878 HRESULT
create_event_obj(IHTMLEventObj
**ret
)
880 HTMLEventObj
*event_obj
;
882 event_obj
= alloc_event_obj(NULL
);
884 return E_OUTOFMEMORY
;
886 *ret
= &event_obj
->IHTMLEventObj_iface
;
890 static inline DOMEvent
*impl_from_IDOMEvent(IDOMEvent
*iface
)
892 return CONTAINING_RECORD(iface
, DOMEvent
, IDOMEvent_iface
);
895 static HRESULT WINAPI
DOMEvent_QueryInterface(IDOMEvent
*iface
, REFIID riid
, void **ppv
)
897 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
899 TRACE("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
901 if(IsEqualGUID(&IID_IUnknown
, riid
))
902 *ppv
= &This
->IDOMEvent_iface
;
903 else if(IsEqualGUID(&IID_IDOMEvent
, riid
))
904 *ppv
= &This
->IDOMEvent_iface
;
905 else if(dispex_query_interface(&This
->dispex
, riid
, ppv
))
906 return *ppv
? S_OK
: E_NOINTERFACE
;
909 WARN("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
910 return E_NOINTERFACE
;
913 IUnknown_AddRef((IUnknown
*)*ppv
);
917 static ULONG WINAPI
DOMEvent_AddRef(IDOMEvent
*iface
)
919 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
920 LONG ref
= InterlockedIncrement(&This
->ref
);
922 TRACE("(%p) ref=%u\n", This
, ref
);
927 static ULONG WINAPI
DOMEvent_Release(IDOMEvent
*iface
)
929 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
930 LONG ref
= InterlockedDecrement(&This
->ref
);
932 TRACE("(%p) ref=%u\n", This
, ref
);
936 IDispatchEx_Release(&This
->target
->dispex
.IDispatchEx_iface
);
937 nsIDOMEvent_Release(This
->nsevent
);
938 release_dispex(&This
->dispex
);
939 heap_free(This
->type
);
946 static HRESULT WINAPI
DOMEvent_GetTypeInfoCount(IDOMEvent
*iface
, UINT
*pctinfo
)
948 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
949 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
952 static HRESULT WINAPI
DOMEvent_GetTypeInfo(IDOMEvent
*iface
, UINT iTInfo
,
953 LCID lcid
, ITypeInfo
**ppTInfo
)
955 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
956 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
959 static HRESULT WINAPI
DOMEvent_GetIDsOfNames(IDOMEvent
*iface
, REFIID riid
,
960 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
962 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
963 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
, rgszNames
, cNames
,
967 static HRESULT WINAPI
DOMEvent_Invoke(IDOMEvent
*iface
, DISPID dispIdMember
,
968 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
969 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
971 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
972 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
, riid
, lcid
,
973 wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
976 static HRESULT WINAPI
DOMEvent_get_bubbles(IDOMEvent
*iface
, VARIANT_BOOL
*p
)
978 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
980 TRACE("(%p)->(%p)\n", This
, p
);
982 *p
= variant_bool(This
->bubbles
);
986 static HRESULT WINAPI
DOMEvent_get_cancelable(IDOMEvent
*iface
, VARIANT_BOOL
*p
)
988 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
990 TRACE("(%p)->(%p)\n", This
, p
);
992 *p
= variant_bool(This
->cancelable
);
996 static HRESULT WINAPI
DOMEvent_get_currentTarget(IDOMEvent
*iface
, IEventTarget
**p
)
998 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1000 TRACE("(%p)->(%p)\n", This
, p
);
1002 if(This
->current_target
)
1003 IEventTarget_AddRef(*p
= &This
->current_target
->IEventTarget_iface
);
1009 static HRESULT WINAPI
DOMEvent_get_defaultPrevented(IDOMEvent
*iface
, VARIANT_BOOL
*p
)
1011 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1013 TRACE("(%p)->(%p)\n", This
, p
);
1015 *p
= variant_bool(This
->prevent_default
);
1019 static HRESULT WINAPI
DOMEvent_get_eventPhase(IDOMEvent
*iface
, USHORT
*p
)
1021 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1023 TRACE("(%p)->(%p)\n", This
, p
);
1029 static HRESULT WINAPI
DOMEvent_get_target(IDOMEvent
*iface
, IEventTarget
**p
)
1031 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1033 TRACE("(%p)->(%p)\n", This
, p
);
1036 IEventTarget_AddRef(*p
= &This
->target
->IEventTarget_iface
);
1042 static HRESULT WINAPI
DOMEvent_get_timeStamp(IDOMEvent
*iface
, ULONGLONG
*p
)
1044 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1045 FIXME("(%p)->(%p)\n", This
, p
);
1049 static HRESULT WINAPI
DOMEvent_get_type(IDOMEvent
*iface
, BSTR
*p
)
1051 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1053 TRACE("(%p)->(%p)\n", This
, p
);
1056 *p
= SysAllocString(This
->type
);
1058 return E_OUTOFMEMORY
;
1065 static HRESULT WINAPI
DOMEvent_initEvent(IDOMEvent
*iface
, BSTR type
, VARIANT_BOOL can_bubble
, VARIANT_BOOL cancelable
)
1067 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1068 FIXME("(%p)->()\n", This
);
1072 static HRESULT WINAPI
DOMEvent_preventDefault(IDOMEvent
*iface
)
1074 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1076 TRACE("(%p)\n", This
);
1078 if(This
->current_target
&& This
->cancelable
) {
1079 This
->prevent_default
= TRUE
;
1080 nsIDOMEvent_PreventDefault(This
->nsevent
);
1085 static HRESULT WINAPI
DOMEvent_stopPropagation(IDOMEvent
*iface
)
1087 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1089 TRACE("(%p)\n", This
);
1091 This
->stop_propagation
= TRUE
;
1092 nsIDOMEvent_StopPropagation(This
->nsevent
);
1093 IDOMEvent_preventDefault(&This
->IDOMEvent_iface
);
1097 static HRESULT WINAPI
DOMEvent_stopImmediatePropagation(IDOMEvent
*iface
)
1099 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1100 FIXME("(%p)\n", This
);
1104 static HRESULT WINAPI
DOMEvent_get_isTrusted(IDOMEvent
*iface
, VARIANT_BOOL
*p
)
1106 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1107 FIXME("(%p)->(%p)\n", This
, p
);
1111 static HRESULT WINAPI
DOMEvent_put_cancelBubble(IDOMEvent
*iface
, VARIANT_BOOL v
)
1113 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1114 FIXME("(%p)->(%x)\n", This
, v
);
1118 static HRESULT WINAPI
DOMEvent_get_cancelBubble(IDOMEvent
*iface
, VARIANT_BOOL
*p
)
1120 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1121 FIXME("(%p)->(%p)\n", This
, p
);
1125 static HRESULT WINAPI
DOMEvent_get_srcElement(IDOMEvent
*iface
, IHTMLElement
**p
)
1127 DOMEvent
*This
= impl_from_IDOMEvent(iface
);
1128 FIXME("(%p)->(%p)\n", This
, p
);
1132 static const IDOMEventVtbl DOMEventVtbl
= {
1133 DOMEvent_QueryInterface
,
1136 DOMEvent_GetTypeInfoCount
,
1137 DOMEvent_GetTypeInfo
,
1138 DOMEvent_GetIDsOfNames
,
1140 DOMEvent_get_bubbles
,
1141 DOMEvent_get_cancelable
,
1142 DOMEvent_get_currentTarget
,
1143 DOMEvent_get_defaultPrevented
,
1144 DOMEvent_get_eventPhase
,
1145 DOMEvent_get_target
,
1146 DOMEvent_get_timeStamp
,
1149 DOMEvent_preventDefault
,
1150 DOMEvent_stopPropagation
,
1151 DOMEvent_stopImmediatePropagation
,
1152 DOMEvent_get_isTrusted
,
1153 DOMEvent_put_cancelBubble
,
1154 DOMEvent_get_cancelBubble
,
1155 DOMEvent_get_srcElement
1158 static const tid_t DOMEvent_iface_tids
[] = {
1163 static dispex_static_data_t DOMEvent_dispex
= {
1169 static DOMEvent
*alloc_event(nsIDOMEvent
*nsevent
, eventid_t event_id
)
1173 event
= heap_alloc_zero(sizeof(*event
));
1177 init_dispex(&event
->dispex
, (IUnknown
*)&event
->IDOMEvent_iface
, &DOMEvent_dispex
);
1178 event
->IDOMEvent_iface
.lpVtbl
= &DOMEventVtbl
;
1180 event
->event_id
= event_id
;
1181 if(event_id
!= EVENTID_LAST
) {
1182 event
->type
= heap_strdupW(event_info
[event_id
].name
);
1184 IDOMEvent_Release(&event
->IDOMEvent_iface
);
1187 event
->bubbles
= (event_info
[event_id
].flags
& EVENT_BUBBLES
) != 0;
1188 event
->cancelable
= (event_info
[event_id
].flags
& EVENT_CANCELABLE
) != 0;
1190 nsIDOMEvent_AddRef(event
->nsevent
= nsevent
);
1194 HRESULT
create_event_from_nsevent(nsIDOMEvent
*nsevent
, DOMEvent
**ret_event
)
1196 eventid_t event_id
= EVENTID_LAST
;
1201 nsAString_Init(&nsstr
, NULL
);
1202 nsres
= nsIDOMEvent_GetType(nsevent
, &nsstr
);
1203 if(NS_SUCCEEDED(nsres
)) {
1205 nsAString_GetData(&nsstr
, &type
);
1206 event_id
= str_to_eid(type
);
1207 if(event_id
== EVENTID_LAST
)
1208 FIXME("unknown event type %s\n", debugstr_w(type
));
1210 ERR("GetType failed: %08x\n", nsres
);
1212 nsAString_Finish(&nsstr
);
1214 event
= alloc_event(nsevent
, event_id
);
1216 return E_OUTOFMEMORY
;
1222 HRESULT
create_document_event_str(HTMLDocumentNode
*doc
, const WCHAR
*type
, IDOMEvent
**ret_event
)
1224 nsIDOMEvent
*nsevent
;
1229 nsAString_InitDepend(&nsstr
, type
);
1230 nsres
= nsIDOMHTMLDocument_CreateEvent(doc
->nsdoc
, &nsstr
, &nsevent
);
1231 nsAString_Finish(&nsstr
);
1232 if(NS_FAILED(nsres
)) {
1233 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(type
), nsres
);
1237 event
= alloc_event(nsevent
, EVENTID_LAST
);
1238 nsIDOMEvent_Release(nsevent
);
1240 return E_OUTOFMEMORY
;
1242 *ret_event
= &event
->IDOMEvent_iface
;
1246 HRESULT
create_document_event(HTMLDocumentNode
*doc
, eventid_t event_id
, DOMEvent
**ret_event
)
1248 nsIDOMEvent
*nsevent
;
1253 nsAString_InitDepend(&nsstr
, event_types
[event_info
[event_id
].type
]);
1254 nsres
= nsIDOMHTMLDocument_CreateEvent(doc
->nsdoc
, &nsstr
, &nsevent
);
1255 nsAString_Finish(&nsstr
);
1256 if(NS_FAILED(nsres
)) {
1257 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(event_types
[event_info
[event_id
].type
]), nsres
);
1261 event
= alloc_event(nsevent
, event_id
);
1263 return E_OUTOFMEMORY
;
1265 event
->event_id
= event_id
;
1270 static HRESULT
call_disp_func(IDispatch
*disp
, DISPPARAMS
*dp
, VARIANT
*retv
)
1272 IDispatchEx
*dispex
;
1276 memset(&ei
, 0, sizeof(ei
));
1278 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1279 if(SUCCEEDED(hres
)) {
1280 hres
= IDispatchEx_InvokeEx(dispex
, 0, GetUserDefaultLCID(), DISPATCH_METHOD
, dp
, retv
, &ei
, NULL
);
1281 IDispatchEx_Release(dispex
);
1283 TRACE("Could not get IDispatchEx interface: %08x\n", hres
);
1284 hres
= IDispatch_Invoke(disp
, 0, &IID_NULL
, GetUserDefaultLCID(), DISPATCH_METHOD
,
1285 dp
, retv
, &ei
, NULL
);
1291 static HRESULT
call_cp_func(IDispatch
*disp
, DISPID dispid
, IHTMLEventObj
*event_obj
, VARIANT
*retv
)
1293 DISPPARAMS dp
= {NULL
,NULL
,0,0};
1299 V_VT(&event_arg
) = VT_DISPATCH
;
1300 V_DISPATCH(&event_arg
) = (IDispatch
*)event_obj
;
1301 dp
.rgvarg
= &event_arg
;
1305 memset(&ei
, 0, sizeof(ei
));
1306 return IDispatch_Invoke(disp
, dispid
, &IID_NULL
, 0, DISPATCH_METHOD
, &dp
, retv
, &ei
, &argerr
);
1309 static BOOL
is_cp_event(cp_static_data_t
*data
, DISPID dispid
)
1318 hres
= get_dispids(data
->tid
, &data
->id_cnt
, &data
->ids
);
1324 max
= data
->id_cnt
-1;
1327 if(data
->ids
[i
] == dispid
)
1330 if(data
->ids
[i
] < dispid
)
1339 static void call_event_handlers(EventTarget
*event_target
, DOMEvent
*event
)
1341 const listener_container_t
*container
= get_listener_container(event_target
, event
->type
, FALSE
);
1342 const BOOL use_quirks
= use_event_quirks(event_target
);
1343 event_listener_t
*listener
, listeners_buf
[8], *listeners
= listeners_buf
;
1344 unsigned listeners_cnt
, listeners_size
;
1345 ConnectionPointContainer
*cp_container
= NULL
;
1346 const event_target_vtbl_t
*vtbl
= NULL
;
1350 assert(!event
->current_target
);
1351 event
->current_target
= event_target
;
1353 if(use_quirks
&& container
&& !list_empty(&container
->listeners
)
1354 && event
->phase
!= DEP_CAPTURING_PHASE
) {
1355 listener
= LIST_ENTRY(list_tail(&container
->listeners
), event_listener_t
, entry
);
1356 if(listener
&& listener
->function
&& listener
->type
== LISTENER_TYPE_ONEVENT
) {
1357 DISPID named_arg
= DISPID_THIS
;
1359 DISPPARAMS dp
= {&arg
, &named_arg
, 1, 1};
1361 V_VT(&arg
) = VT_DISPATCH
;
1362 V_DISPATCH(&arg
) = (IDispatch
*)&event_target
->dispex
.IDispatchEx_iface
;
1363 V_VT(&v
) = VT_EMPTY
;
1365 TRACE("%s >>>\n", debugstr_w(event
->type
));
1366 hres
= call_disp_func(listener
->function
, &dp
, &v
);
1368 TRACE("%s <<< %s\n", debugstr_w(event
->type
), debugstr_variant(&v
));
1370 if(event
->cancelable
) {
1371 if(V_VT(&v
) == VT_BOOL
) {
1373 IDOMEvent_preventDefault(&event
->IDOMEvent_iface
);
1374 }else if(V_VT(&v
) != VT_EMPTY
) {
1375 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1380 WARN("%s <<< %08x\n", debugstr_w(event
->type
), hres
);
1386 listeners_size
= sizeof(listeners_buf
)/sizeof(*listeners_buf
);
1389 LIST_FOR_EACH_ENTRY(listener
, &container
->listeners
, event_listener_t
, entry
) {
1390 if(!listener
->function
)
1392 switch(listener
->type
) {
1393 case LISTENER_TYPE_ONEVENT
:
1394 if(use_quirks
|| event
->phase
== DEP_CAPTURING_PHASE
)
1397 case LISTENER_TYPE_CAPTURE
:
1398 if(event
->phase
== DEP_BUBBLING_PHASE
|| event
->in_fire_event
)
1401 case LISTENER_TYPE_BUBBLE
:
1402 if(event
->in_fire_event
)
1405 case LISTENER_TYPE_ATTACHED
:
1406 if(event
->phase
== DEP_CAPTURING_PHASE
)
1411 if(listeners_cnt
== listeners_size
) {
1412 event_listener_t
*new_listeners
;
1413 if(listeners
== listeners_buf
) {
1414 new_listeners
= heap_alloc(listeners_size
* 2 * sizeof(*new_listeners
));
1417 memcpy(new_listeners
, listeners
, listeners_cnt
* sizeof(*listeners
));
1419 new_listeners
= heap_realloc(listeners
, listeners_size
* 2 * sizeof(*new_listeners
));
1421 listeners
= new_listeners
;
1422 listeners_size
*= 2;
1425 listeners
[listeners_cnt
].type
= listener
->type
;
1426 IDispatch_AddRef(listeners
[listeners_cnt
].function
= listener
->function
);
1431 for(listener
= listeners
; listener
< listeners
+ listeners_cnt
; listener
++) {
1432 if(listener
->type
!= LISTENER_TYPE_ATTACHED
) {
1433 DISPID named_arg
= DISPID_THIS
;
1435 DISPPARAMS dp
= {args
, &named_arg
, 2, 1};
1437 V_VT(args
) = VT_DISPATCH
;
1438 V_DISPATCH(args
) = (IDispatch
*)&event_target
->dispex
.IDispatchEx_iface
;
1439 V_VT(args
+1) = VT_DISPATCH
;
1440 V_DISPATCH(args
+1) = event
->in_fire_event
1441 ? (IDispatch
*)event
->event_obj
: (IDispatch
*)&event
->IDOMEvent_iface
;
1442 V_VT(&v
) = VT_EMPTY
;
1444 TRACE("%s >>>\n", debugstr_w(event
->type
));
1445 hres
= call_disp_func(listener
->function
, &dp
, &v
);
1447 TRACE("%s <<< %s\n", debugstr_w(event
->type
),
1448 debugstr_variant(&v
));
1450 if(event
->cancelable
) {
1451 if(V_VT(&v
) == VT_BOOL
) {
1453 IDOMEvent_preventDefault(&event
->IDOMEvent_iface
);
1454 }else if(V_VT(&v
) != VT_EMPTY
) {
1455 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1460 WARN("%s <<< %08x\n", debugstr_w(event
->type
), hres
);
1464 DISPPARAMS dp
= {&arg
, NULL
, 1, 0};
1466 V_VT(&arg
) = VT_DISPATCH
;
1467 V_DISPATCH(&arg
) = (IDispatch
*)event
->event_obj
;
1468 V_VT(&v
) = VT_EMPTY
;
1470 TRACE("%s attached >>>\n", debugstr_w(event
->type
));
1471 hres
= call_disp_func(listener
->function
, &dp
, &v
);
1473 TRACE("%s attached <<<\n", debugstr_w(event
->type
));
1475 if(event
->cancelable
) {
1476 if(V_VT(&v
) == VT_BOOL
) {
1478 IDOMEvent_preventDefault(&event
->IDOMEvent_iface
);
1479 }else if(V_VT(&v
) != VT_EMPTY
) {
1480 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1485 WARN("%s attached <<< %08x\n", debugstr_w(event
->type
), hres
);
1490 for(listener
= listeners
; listener
< listeners
+ listeners_cnt
; listener
++)
1491 IDispatch_Release(listener
->function
);
1492 if(listeners
!= listeners_buf
)
1493 heap_free(listeners
);
1495 if(event
->phase
!= DEP_CAPTURING_PHASE
&& event
->event_id
!= EVENTID_LAST
1496 && event_info
[event
->event_id
].dispid
&& (vtbl
= dispex_get_vtbl(&event_target
->dispex
))
1497 && vtbl
->get_cp_container
)
1498 cp_container
= vtbl
->get_cp_container(&event_target
->dispex
);
1500 if(cp_container
->cps
) {
1501 ConnectionPoint
*cp
;
1504 for(j
=0; cp_container
->cp_entries
[j
].riid
; j
++) {
1505 cp
= cp_container
->cps
+ j
;
1506 if(!cp
->sinks_size
|| !is_cp_event(cp
->data
, event_info
[event
->event_id
].dispid
))
1509 for(i
=0; i
< cp
->sinks_size
; i
++) {
1510 if(!cp
->sinks
[i
].disp
)
1513 V_VT(&v
) = VT_EMPTY
;
1515 TRACE("cp %s [%u] >>>\n", debugstr_w(event
->type
), i
);
1516 hres
= call_cp_func(cp
->sinks
[i
].disp
, event_info
[event
->event_id
].dispid
,
1517 cp
->data
->pass_event_arg
? event
->event_obj
: NULL
, &v
);
1519 TRACE("cp %s [%u] <<<\n", debugstr_w(event
->type
), i
);
1521 if(event
->cancelable
) {
1522 if(V_VT(&v
) == VT_BOOL
) {
1524 IDOMEvent_preventDefault(&event
->IDOMEvent_iface
);
1525 }else if(V_VT(&v
) != VT_EMPTY
) {
1526 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1531 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event
->type
), i
, hres
);
1536 IConnectionPointContainer_Release(&cp_container
->IConnectionPointContainer_iface
);
1539 event
->current_target
= NULL
;
1542 void dispatch_event(EventTarget
*event_target
, DOMEvent
*event
)
1544 EventTarget
*target_chain_buf
[8], **target_chain
= target_chain_buf
;
1545 unsigned chain_cnt
, chain_buf_size
, i
;
1546 const event_target_vtbl_t
*vtbl
, *target_vtbl
;
1547 HTMLEventObj
*event_obj_ref
= NULL
;
1548 IHTMLEventObj
*prev_event
= NULL
;
1552 TRACE("(%p) %s\n", event_target
, debugstr_w(event
->type
));
1554 if(event
->event_id
== EVENTID_LAST
) {
1555 FIXME("Unsupported on unknown events\n");
1559 if(event
->current_target
) {
1560 FIXME("event is being dispatched.\n");
1564 iter
= event_target
;
1565 IDispatchEx_AddRef(&event_target
->dispex
.IDispatchEx_iface
);
1568 chain_buf_size
= sizeof(target_chain_buf
)/sizeof(*target_chain_buf
);
1571 if(chain_cnt
== chain_buf_size
) {
1572 EventTarget
**new_chain
;
1573 if(target_chain
== target_chain_buf
) {
1574 new_chain
= heap_alloc(chain_buf_size
* 2 * sizeof(*new_chain
));
1577 memcpy(new_chain
, target_chain
, chain_buf_size
* sizeof(*new_chain
));
1579 new_chain
= heap_realloc(target_chain
, chain_buf_size
* 2 * sizeof(*new_chain
));
1583 chain_buf_size
*= 2;
1584 target_chain
= new_chain
;
1587 target_chain
[chain_cnt
++] = iter
;
1589 if(!(vtbl
= dispex_get_vtbl(&iter
->dispex
)) || !vtbl
->get_parent_event_target
)
1591 iter
= vtbl
->get_parent_event_target(&iter
->dispex
);
1594 if(!event
->event_obj
&& !event
->no_event_obj
) {
1595 event_obj_ref
= alloc_event_obj(event
);
1597 event
->event_obj
= &event_obj_ref
->IHTMLEventObj_iface
;
1600 target_vtbl
= dispex_get_vtbl(&event_target
->dispex
);
1601 if(target_vtbl
&& target_vtbl
->set_current_event
)
1602 prev_event
= target_vtbl
->set_current_event(&event_target
->dispex
, event
->event_obj
);
1605 IDispatchEx_Release(&event
->target
->dispex
.IDispatchEx_iface
);
1606 event
->target
= event_target
;
1607 IDispatchEx_AddRef(&event_target
->dispex
.IDispatchEx_iface
);
1609 event
->phase
= DEP_CAPTURING_PHASE
;
1611 while(!event
->stop_propagation
&& i
)
1612 call_event_handlers(target_chain
[i
--], event
);
1614 if(!event
->stop_propagation
) {
1615 event
->phase
= DEP_AT_TARGET
;
1616 call_event_handlers(target_chain
[0], event
);
1619 if(event
->bubbles
) {
1620 event
->phase
= DEP_BUBBLING_PHASE
;
1621 for(i
= 1; !event
->stop_propagation
&& i
< chain_cnt
; i
++)
1622 call_event_handlers(target_chain
[i
], event
);
1625 if(target_vtbl
&& target_vtbl
->set_current_event
) {
1626 prev_event
= target_vtbl
->set_current_event(&event_target
->dispex
, prev_event
);
1628 IHTMLEventObj_Release(prev_event
);
1631 if(event
->event_id
!= EVENTID_LAST
&& (event_info
[event
->event_id
].flags
& EVENT_HASDEFAULTHANDLERS
)) {
1632 for(i
= 0; !event
->prevent_default
&& i
< chain_cnt
; i
++) {
1633 BOOL prevent_default
= FALSE
;
1634 vtbl
= dispex_get_vtbl(&target_chain
[i
]->dispex
);
1635 if(!vtbl
|| !vtbl
->handle_event_default
)
1637 hres
= vtbl
->handle_event_default(&event_target
->dispex
, event
->event_id
,
1638 event
->nsevent
, &prevent_default
);
1639 if(FAILED(hres
) || event
->stop_propagation
)
1642 IDOMEvent_preventDefault(&event
->IDOMEvent_iface
);
1647 event
->event_obj
= NULL
;
1648 IHTMLEventObj_Release(&event_obj_ref
->IHTMLEventObj_iface
);
1651 for(i
= 0; i
< chain_cnt
; i
++)
1652 IDispatchEx_Release(&target_chain
[i
]->dispex
.IDispatchEx_iface
);
1653 if(target_chain
!= target_chain_buf
)
1654 heap_free(target_chain
);
1657 HRESULT
fire_event(HTMLDOMNode
*node
, const WCHAR
*event_name
, VARIANT
*event_var
, VARIANT_BOOL
*cancelled
)
1659 HTMLEventObj
*event_obj
= NULL
;
1661 HRESULT hres
= S_OK
;
1663 eid
= attr_to_eid(event_name
);
1664 if(eid
== EVENTID_LAST
) {
1665 WARN("unknown event %s\n", debugstr_w(event_name
));
1666 return E_INVALIDARG
;
1669 if(event_var
&& V_VT(event_var
) != VT_EMPTY
&& V_VT(event_var
) != VT_ERROR
) {
1670 if(V_VT(event_var
) != VT_DISPATCH
) {
1671 FIXME("event_var %s not supported\n", debugstr_variant(event_var
));
1675 if(V_DISPATCH(event_var
)) {
1676 IHTMLEventObj
*event_iface
;
1678 hres
= IDispatch_QueryInterface(V_DISPATCH(event_var
), &IID_IHTMLEventObj
, (void**)&event_iface
);
1680 FIXME("No IHTMLEventObj iface\n");
1684 event_obj
= unsafe_impl_from_IHTMLEventObj(event_iface
);
1686 ERR("Not our IHTMLEventObj?\n");
1687 IHTMLEventObj_Release(event_iface
);
1694 event_obj
= alloc_event_obj(NULL
);
1696 return E_OUTOFMEMORY
;
1699 if(!event_obj
->event
)
1700 hres
= create_document_event(node
->doc
, eid
, &event_obj
->event
);
1702 if(SUCCEEDED(hres
)) {
1703 event_obj
->event
->event_obj
= &event_obj
->IHTMLEventObj_iface
;
1704 event_obj
->event
->in_fire_event
++;
1705 dispatch_event(&node
->event_target
, event_obj
->event
);
1706 event_obj
->event
->in_fire_event
--;
1707 event_obj
->event
->event_obj
= NULL
;
1710 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1714 *cancelled
= VARIANT_TRUE
; /* FIXME */
1718 HRESULT
ensure_doc_nsevent_handler(HTMLDocumentNode
*doc
, eventid_t eid
)
1720 nsIDOMNode
*nsnode
= NULL
;
1722 TRACE("%s\n", debugstr_w(event_info
[eid
].name
));
1728 case EVENTID_FOCUSIN
:
1729 doc
->event_vector
[eid
] = TRUE
;
1730 eid
= EVENTID_FOCUS
;
1732 case EVENTID_FOCUSOUT
:
1733 doc
->event_vector
[eid
] = TRUE
;
1740 if(doc
->event_vector
[eid
] || !(event_info
[eid
].flags
& (EVENT_DEFAULTLISTENER
|EVENT_BIND_TO_BODY
)))
1743 if(event_info
[eid
].flags
& EVENT_BIND_TO_BODY
) {
1744 nsnode
= doc
->node
.nsnode
;
1745 nsIDOMNode_AddRef(nsnode
);
1748 doc
->event_vector
[eid
] = TRUE
;
1749 add_nsevent_listener(doc
, nsnode
, event_info
[eid
].name
);
1752 nsIDOMNode_Release(nsnode
);
1756 void detach_events(HTMLDocumentNode
*doc
)
1758 if(doc
->event_vector
) {
1761 for(i
=0; i
< EVENTID_LAST
; i
++) {
1762 if(doc
->event_vector
[i
]) {
1763 detach_nsevent(doc
, event_info
[i
].name
);
1764 doc
->event_vector
[i
] = FALSE
;
1769 release_nsevents(doc
);
1772 static HRESULT
get_event_dispex_ref(EventTarget
*event_target
, eventid_t eid
, BOOL alloc
, VARIANT
**ret
)
1777 strcpyW(buf
+2, event_info
[eid
].name
);
1778 return dispex_get_dprop_ref(&event_target
->dispex
, buf
, alloc
, ret
);
1781 static event_listener_t
*get_onevent_listener(EventTarget
*event_target
, eventid_t eid
, BOOL alloc
)
1783 listener_container_t
*container
;
1784 event_listener_t
*listener
;
1786 container
= get_listener_container(event_target
, event_info
[eid
].name
, alloc
);
1790 LIST_FOR_EACH_ENTRY_REV(listener
, &container
->listeners
, event_listener_t
, entry
) {
1791 if(listener
->type
== LISTENER_TYPE_ONEVENT
)
1798 listener
= heap_alloc(sizeof(*listener
));
1802 listener
->type
= LISTENER_TYPE_ONEVENT
;
1803 listener
->function
= NULL
;
1804 list_add_tail(&container
->listeners
, &listener
->entry
);
1808 static void remove_event_handler(EventTarget
*event_target
, eventid_t eid
)
1810 event_listener_t
*listener
;
1814 hres
= get_event_dispex_ref(event_target
, eid
, FALSE
, &store
);
1816 VariantClear(store
);
1818 listener
= get_onevent_listener(event_target
, eid
, FALSE
);
1819 if(listener
&& listener
->function
) {
1820 IDispatch_Release(listener
->function
);
1821 listener
->function
= NULL
;
1825 static HRESULT
set_event_handler_disp(EventTarget
*event_target
, eventid_t eid
, IDispatch
*disp
)
1827 event_listener_t
*listener
;
1829 if(event_info
[eid
].flags
& EVENT_FIXME
)
1830 FIXME("unimplemented event %s\n", debugstr_w(event_info
[eid
].name
));
1832 remove_event_handler(event_target
, eid
);
1836 listener
= get_onevent_listener(event_target
, eid
, TRUE
);
1838 return E_OUTOFMEMORY
;
1840 if(listener
->function
)
1841 IDispatch_Release(listener
->function
);
1843 IDispatch_AddRef(listener
->function
= disp
);
1847 HRESULT
set_event_handler(EventTarget
*event_target
, eventid_t eid
, VARIANT
*var
)
1851 if(use_event_quirks(event_target
)) {
1852 WARN("attempt to set to VT_EMPTY in quirks mode\n");
1857 remove_event_handler(event_target
, eid
);
1861 return set_event_handler_disp(event_target
, eid
, V_DISPATCH(var
));
1867 if(!use_event_quirks(event_target
))
1868 FIXME("Setting to string %s not supported\n", debugstr_w(V_BSTR(var
)));
1871 * Setting event handler to string is a rare case and we don't want to
1872 * complicate nor increase memory of listener_container_t for that. Instead,
1873 * we store the value in DispatchEx, which can already handle custom
1876 remove_event_handler(event_target
, eid
);
1878 hres
= get_event_dispex_ref(event_target
, eid
, TRUE
, &v
);
1882 V_BSTR(v
) = SysAllocString(V_BSTR(var
));
1884 return E_OUTOFMEMORY
;
1890 FIXME("not handler %s\n", debugstr_variant(var
));
1897 HRESULT
get_event_handler(EventTarget
*event_target
, eventid_t eid
, VARIANT
*var
)
1899 event_listener_t
*listener
;
1903 hres
= get_event_dispex_ref(event_target
, eid
, FALSE
, &v
);
1904 if(SUCCEEDED(hres
) && V_VT(v
) != VT_EMPTY
) {
1905 V_VT(var
) = VT_EMPTY
;
1906 return VariantCopy(var
, v
);
1909 listener
= get_onevent_listener(event_target
, eid
, FALSE
);
1910 if(listener
&& listener
->function
) {
1911 V_VT(var
) = VT_DISPATCH
;
1912 V_DISPATCH(var
) = listener
->function
;
1913 IDispatch_AddRef(V_DISPATCH(var
));
1915 V_VT(var
) = VT_NULL
;
1921 HRESULT
attach_event(EventTarget
*event_target
, BSTR name
, IDispatch
*disp
, VARIANT_BOOL
*res
)
1923 listener_container_t
*container
;
1924 event_listener_t
*listener
;
1927 eid
= attr_to_eid(name
);
1928 if(eid
== EVENTID_LAST
) {
1929 WARN("Unknown event\n");
1930 *res
= VARIANT_TRUE
;
1934 container
= get_listener_container(event_target
, event_info
[eid
].name
, TRUE
);
1936 return E_OUTOFMEMORY
;
1938 listener
= heap_alloc(sizeof(*listener
));
1940 return E_OUTOFMEMORY
;
1942 listener
->type
= LISTENER_TYPE_ATTACHED
;
1943 IDispatch_AddRef(listener
->function
= disp
);
1944 if(use_event_quirks(event_target
))
1945 list_add_head(&container
->listeners
, &listener
->entry
);
1947 list_add_tail(&container
->listeners
, &listener
->entry
);
1949 *res
= VARIANT_TRUE
;
1953 HRESULT
detach_event(EventTarget
*event_target
, BSTR name
, IDispatch
*disp
)
1957 eid
= attr_to_eid(name
);
1958 if(eid
== EVENTID_LAST
) {
1959 WARN("Unknown event\n");
1963 remove_event_listener(event_target
, event_info
[eid
].name
, LISTENER_TYPE_ATTACHED
, disp
);
1967 void bind_target_event(HTMLDocumentNode
*doc
, EventTarget
*event_target
, const WCHAR
*event
, IDispatch
*disp
)
1971 TRACE("(%p %p %s %p)\n", doc
, event_target
, debugstr_w(event
), disp
);
1973 eid
= attr_to_eid(event
);
1974 if(eid
== EVENTID_LAST
) {
1975 WARN("Unsupported event %s\n", debugstr_w(event
));
1979 set_event_handler_disp(event_target
, eid
, disp
);
1982 void update_doc_cp_events(HTMLDocumentNode
*doc
, cp_static_data_t
*cp
)
1986 for(i
=0; i
< EVENTID_LAST
; i
++) {
1987 if((event_info
[i
].flags
& EVENT_DEFAULTLISTENER
) && is_cp_event(cp
, event_info
[i
].dispid
))
1988 ensure_doc_nsevent_handler(doc
, i
);
1992 void check_event_attr(HTMLDocumentNode
*doc
, nsIDOMHTMLElement
*nselem
)
1994 nsIDOMMozNamedAttrMap
*attr_map
;
1995 const PRUnichar
*name
, *value
;
1996 nsAString name_str
, value_str
;
1997 HTMLDOMNode
*node
= NULL
;
2006 nsres
= nsIDOMHTMLElement_HasAttributes(nselem
, &has_attrs
);
2007 if(NS_FAILED(nsres
) || !has_attrs
)
2010 nsres
= nsIDOMHTMLElement_GetAttributes(nselem
, &attr_map
);
2011 if(NS_FAILED(nsres
))
2014 nsres
= nsIDOMMozNamedAttrMap_GetLength(attr_map
, &length
);
2015 assert(nsres
== NS_OK
);
2017 nsAString_Init(&name_str
, NULL
);
2018 nsAString_Init(&value_str
, NULL
);
2020 for(i
= 0; i
< length
; i
++) {
2021 nsres
= nsIDOMMozNamedAttrMap_Item(attr_map
, i
, &attr
);
2022 if(NS_FAILED(nsres
))
2025 nsres
= nsIDOMAttr_GetName(attr
, &name_str
);
2026 if(NS_FAILED(nsres
)) {
2027 nsIDOMAttr_Release(attr
);
2031 nsAString_GetData(&name_str
, &name
);
2032 eid
= attr_to_eid(name
);
2033 if(eid
== EVENTID_LAST
) {
2034 nsIDOMAttr_Release(attr
);
2038 nsres
= nsIDOMAttr_GetValue(attr
, &value_str
);
2039 nsIDOMAttr_Release(attr
);
2040 if(NS_FAILED(nsres
))
2043 nsAString_GetData(&value_str
, &value
);
2047 TRACE("%p.%s = %s\n", nselem
, debugstr_w(name
), debugstr_w(value
));
2049 disp
= script_parse_event(doc
->window
, value
);
2054 hres
= get_node(doc
, (nsIDOMNode
*)nselem
, TRUE
, &node
);
2056 IDispatch_Release(disp
);
2061 set_event_handler_disp(get_node_event_prop_target(node
, eid
), eid
, disp
);
2062 IDispatch_Release(disp
);
2067 nsAString_Finish(&name_str
);
2068 nsAString_Finish(&value_str
);
2069 nsIDOMMozNamedAttrMap_Release(attr_map
);
2072 HRESULT
doc_init_events(HTMLDocumentNode
*doc
)
2077 doc
->event_vector
= heap_alloc_zero(EVENTID_LAST
*sizeof(BOOL
));
2078 if(!doc
->event_vector
)
2079 return E_OUTOFMEMORY
;
2083 for(i
=0; i
< EVENTID_LAST
; i
++) {
2084 if(event_info
[i
].flags
& EVENT_HASDEFAULTHANDLERS
) {
2085 hres
= ensure_doc_nsevent_handler(doc
, i
);
2094 static inline EventTarget
*impl_from_IEventTarget(IEventTarget
*iface
)
2096 return CONTAINING_RECORD(iface
, EventTarget
, IEventTarget_iface
);
2099 static HRESULT WINAPI
EventTarget_QueryInterface(IEventTarget
*iface
, REFIID riid
, void **ppv
)
2101 EventTarget
*This
= impl_from_IEventTarget(iface
);
2102 return IDispatchEx_QueryInterface(&This
->dispex
.IDispatchEx_iface
, riid
, ppv
);
2105 static ULONG WINAPI
EventTarget_AddRef(IEventTarget
*iface
)
2107 EventTarget
*This
= impl_from_IEventTarget(iface
);
2108 return IDispatchEx_AddRef(&This
->dispex
.IDispatchEx_iface
);
2111 static ULONG WINAPI
EventTarget_Release(IEventTarget
*iface
)
2113 EventTarget
*This
= impl_from_IEventTarget(iface
);
2114 return IDispatchEx_Release(&This
->dispex
.IDispatchEx_iface
);
2117 static HRESULT WINAPI
EventTarget_GetTypeInfoCount(IEventTarget
*iface
, UINT
*pctinfo
)
2119 EventTarget
*This
= impl_from_IEventTarget(iface
);
2120 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
2123 static HRESULT WINAPI
EventTarget_GetTypeInfo(IEventTarget
*iface
, UINT iTInfo
,
2124 LCID lcid
, ITypeInfo
**ppTInfo
)
2126 EventTarget
*This
= impl_from_IEventTarget(iface
);
2127 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
2130 static HRESULT WINAPI
EventTarget_GetIDsOfNames(IEventTarget
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
2131 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
2133 EventTarget
*This
= impl_from_IEventTarget(iface
);
2134 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
,
2135 rgszNames
, cNames
, lcid
, rgDispId
);
2138 static HRESULT WINAPI
EventTarget_Invoke(IEventTarget
*iface
, DISPID dispIdMember
,
2139 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
2140 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
2142 EventTarget
*This
= impl_from_IEventTarget(iface
);
2143 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
,
2144 riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
2147 static HRESULT WINAPI
EventTarget_addEventListener(IEventTarget
*iface
, BSTR type
,
2148 IDispatch
*function
, VARIANT_BOOL capture
)
2150 EventTarget
*This
= impl_from_IEventTarget(iface
);
2151 listener_type_t listener_type
= capture
? LISTENER_TYPE_CAPTURE
: LISTENER_TYPE_BUBBLE
;
2152 listener_container_t
*container
;
2153 event_listener_t
*listener
;
2155 TRACE("(%p)->(%s %p %x)\n", This
, debugstr_w(type
), function
, capture
);
2157 container
= get_listener_container(This
, type
, TRUE
);
2159 return E_OUTOFMEMORY
;
2161 /* check for duplicates */
2162 LIST_FOR_EACH_ENTRY(listener
, &container
->listeners
, event_listener_t
, entry
) {
2163 if(listener
->type
== listener_type
&& listener
->function
== function
)
2167 listener
= heap_alloc(sizeof(*listener
));
2169 return E_OUTOFMEMORY
;
2171 listener
->type
= listener_type
;
2172 IDispatch_AddRef(listener
->function
= function
);
2173 list_add_tail(&container
->listeners
, &listener
->entry
);
2177 static HRESULT WINAPI
EventTarget_removeEventListener(IEventTarget
*iface
, BSTR type
,
2178 IDispatch
*listener
, VARIANT_BOOL capture
)
2180 EventTarget
*This
= impl_from_IEventTarget(iface
);
2182 TRACE("(%p)->(%s %p %x)\n", This
, debugstr_w(type
), listener
, capture
);
2184 remove_event_listener(This
, type
, capture
? LISTENER_TYPE_CAPTURE
: LISTENER_TYPE_BUBBLE
, listener
);
2188 static HRESULT WINAPI
EventTarget_dispatchEvent(IEventTarget
*iface
, IDOMEvent
*event
, VARIANT_BOOL
*result
)
2190 EventTarget
*This
= impl_from_IEventTarget(iface
);
2191 FIXME("(%p)->(%p %p)\n", This
, event
, result
);
2195 HRESULT
IEventTarget_addEventListener_hook(DispatchEx
*dispex
, LCID lcid
, WORD flags
,
2196 DISPPARAMS
*dp
, VARIANT
*res
, EXCEPINFO
*ei
, IServiceProvider
*caller
)
2198 /* If only two arguments were given, implicitly set capture to false */
2199 if((flags
& DISPATCH_METHOD
) && dp
->cArgs
== 2 && !dp
->cNamedArgs
) {
2201 DISPPARAMS new_dp
= {args
, NULL
, 3, 0};
2202 V_VT(args
) = VT_BOOL
;
2203 V_BOOL(args
) = VARIANT_FALSE
;
2204 args
[1] = dp
->rgvarg
[0];
2205 args
[2] = dp
->rgvarg
[1];
2207 TRACE("implicit capture\n");
2209 return IDispatchEx_InvokeEx(&dispex
->IDispatchEx_iface
, DISPID_IEVENTTARGET_ADDEVENTLISTENER
,
2210 lcid
, flags
, &new_dp
, res
, ei
, caller
);
2213 return S_FALSE
; /* fallback to default */
2216 HRESULT
IEventTarget_removeEventListener_hook(DispatchEx
*dispex
, LCID lcid
, WORD flags
,
2217 DISPPARAMS
*dp
, VARIANT
*res
, EXCEPINFO
*ei
, IServiceProvider
*caller
)
2219 /* If only two arguments were given, implicitly set capture to false */
2220 if((flags
& DISPATCH_METHOD
) && dp
->cArgs
== 2 && !dp
->cNamedArgs
) {
2222 DISPPARAMS new_dp
= {args
, NULL
, 3, 0};
2223 V_VT(args
) = VT_BOOL
;
2224 V_BOOL(args
) = VARIANT_FALSE
;
2225 args
[1] = dp
->rgvarg
[0];
2226 args
[2] = dp
->rgvarg
[1];
2228 TRACE("implicit capture\n");
2230 return IDispatchEx_InvokeEx(&dispex
->IDispatchEx_iface
, DISPID_IEVENTTARGET_REMOVEEVENTLISTENER
,
2231 lcid
, flags
, &new_dp
, res
, ei
, caller
);
2234 return S_FALSE
; /* fallback to default */
2237 static const IEventTargetVtbl EventTargetVtbl
= {
2238 EventTarget_QueryInterface
,
2240 EventTarget_Release
,
2241 EventTarget_GetTypeInfoCount
,
2242 EventTarget_GetTypeInfo
,
2243 EventTarget_GetIDsOfNames
,
2245 EventTarget_addEventListener
,
2246 EventTarget_removeEventListener
,
2247 EventTarget_dispatchEvent
2250 #define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
2252 static BOOL
use_event_quirks(EventTarget
*event_target
)
2254 if(event_target
->IEventTarget_iface
.lpVtbl
== DELAY_INIT_VTBL
) {
2255 event_target
->IEventTarget_iface
.lpVtbl
=
2256 dispex_compat_mode(&event_target
->dispex
) >= COMPAT_MODE_IE9
2257 ? &EventTargetVtbl
: NULL
;
2259 return !event_target
->IEventTarget_iface
.lpVtbl
;
2262 HRESULT
EventTarget_QI(EventTarget
*event_target
, REFIID riid
, void **ppv
)
2264 if(IsEqualGUID(riid
, &IID_IEventTarget
)) {
2265 if(use_event_quirks(event_target
)) {
2266 WARN("IEventTarget queried, but not supported by in document mode\n");
2268 return E_NOINTERFACE
;
2270 IEventTarget_AddRef(&event_target
->IEventTarget_iface
);
2271 *ppv
= &event_target
->IEventTarget_iface
;
2275 if(dispex_query_interface(&event_target
->dispex
, riid
, ppv
))
2276 return *ppv
? S_OK
: E_NOINTERFACE
;
2278 WARN("(%p)->(%s %p)\n", event_target
, debugstr_mshtml_guid(riid
), ppv
);
2280 return E_NOINTERFACE
;
2283 void EventTarget_init_dispex_info(dispex_data_t
*dispex_info
, compat_mode_t compat_mode
)
2285 static const dispex_hook_t IEventTarget_hooks
[] = {
2286 {DISPID_IEVENTTARGET_ADDEVENTLISTENER
, IEventTarget_addEventListener_hook
},
2287 {DISPID_IEVENTTARGET_REMOVEEVENTLISTENER
, IEventTarget_removeEventListener_hook
},
2291 if(compat_mode
>= COMPAT_MODE_IE9
)
2292 dispex_info_add_interface(dispex_info
, IEventTarget_tid
, IEventTarget_hooks
);
2295 static int event_id_cmp(const void *key
, const struct wine_rb_entry
*entry
)
2297 return strcmpW(key
, WINE_RB_ENTRY_VALUE(entry
, listener_container_t
, entry
)->type
);
2300 void EventTarget_Init(EventTarget
*event_target
, IUnknown
*outer
, dispex_static_data_t
*dispex_data
,
2301 compat_mode_t compat_mode
)
2303 init_dispex_with_compat_mode(&event_target
->dispex
, outer
, dispex_data
, compat_mode
);
2304 wine_rb_init(&event_target
->handler_map
, event_id_cmp
);
2307 * IEventTarget is supported by the object or not depending on compatibility mode.
2308 * We use NULL vtbl for objects in compatibility mode not supporting the interface.
2309 * For targets that don't know compatibility mode at creation time, we set vtbl
2310 * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
2313 if(compat_mode
== COMPAT_MODE_QUIRKS
&& dispex_data
->vtbl
&& dispex_data
->vtbl
->get_compat_mode
)
2314 event_target
->IEventTarget_iface
.lpVtbl
= DELAY_INIT_VTBL
;
2315 else if(compat_mode
< COMPAT_MODE_IE9
)
2316 event_target
->IEventTarget_iface
.lpVtbl
= NULL
;
2318 event_target
->IEventTarget_iface
.lpVtbl
= &EventTargetVtbl
;
2321 void release_event_target(EventTarget
*event_target
)
2323 listener_container_t
*iter
, *iter2
;
2325 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter
, iter2
, &event_target
->handler_map
, listener_container_t
, entry
) {
2326 while(!list_empty(&iter
->listeners
)) {
2327 event_listener_t
*listener
= LIST_ENTRY(list_head(&iter
->listeners
), event_listener_t
, entry
);
2328 if(listener
->function
)
2329 IDispatch_Release(listener
->function
);
2330 list_remove(&listener
->entry
);
2331 heap_free(listener
);