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 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 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 256 static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface) 257 { 258 return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj_iface); 259 } 260 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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