1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use dom::beforeunloadevent::BeforeUnloadEvent; 6 use dom::bindings::callback::{CallbackContainer, ExceptionHandling, CallbackFunction}; 7 use dom::bindings::cell::DomRefCell; 8 use dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEventMethods; 9 use dom::bindings::codegen::Bindings::ErrorEventBinding::ErrorEventMethods; 10 use dom::bindings::codegen::Bindings::EventBinding::EventMethods; 11 use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; 12 use dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull; 13 use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull; 14 use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener; 15 use dom::bindings::codegen::Bindings::EventTargetBinding::AddEventListenerOptions; 16 use dom::bindings::codegen::Bindings::EventTargetBinding::EventListenerOptions; 17 use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; 18 use dom::bindings::codegen::Bindings::EventTargetBinding::Wrap; 19 use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; 20 use dom::bindings::codegen::UnionTypes::AddEventListenerOptionsOrBoolean; 21 use dom::bindings::codegen::UnionTypes::EventListenerOptionsOrBoolean; 22 use dom::bindings::codegen::UnionTypes::EventOrString; 23 use dom::bindings::error::{Error, Fallible, report_pending_exception}; 24 use dom::bindings::inheritance::Castable; 25 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; 26 use dom::bindings::root::DomRoot; 27 use dom::bindings::str::DOMString; 28 use dom::element::Element; 29 use dom::errorevent::ErrorEvent; 30 use dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; 31 use dom::globalscope::GlobalScope; 32 use dom::node::document_from_node; 33 use dom::virtualmethods::VirtualMethods; 34 use dom::window::Window; 35 use dom_struct::dom_struct; 36 use fnv::FnvHasher; 37 use js::jsapi::{CompileFunction, JS_GetFunctionObject, JSAutoCompartment, JSFunction}; 38 use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper}; 39 use libc::{c_char, size_t}; 40 use servo_atoms::Atom; 41 use servo_url::ServoUrl; 42 use std::collections::HashMap; 43 use std::collections::hash_map::Entry::{Occupied, Vacant}; 44 use std::default::Default; 45 use std::ffi::CString; 46 use std::hash::BuildHasherDefault; 47 use std::mem; 48 use std::ops::{Deref, DerefMut}; 49 use std::ptr; 50 use std::rc::Rc; 51 52 #[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)] 53 pub enum CommonEventHandler { 54 EventHandler( 55 #[ignore_malloc_size_of = "Rc"] 56 Rc<EventHandlerNonNull>), 57 58 ErrorEventHandler( 59 #[ignore_malloc_size_of = "Rc"] 60 Rc<OnErrorEventHandlerNonNull>), 61 62 BeforeUnloadEventHandler( 63 #[ignore_malloc_size_of = "Rc"] 64 Rc<OnBeforeUnloadEventHandlerNonNull>), 65 } 66 67 impl CommonEventHandler { parent(&self) -> &CallbackFunction68 fn parent(&self) -> &CallbackFunction { 69 match *self { 70 CommonEventHandler::EventHandler(ref handler) => &handler.parent, 71 CommonEventHandler::ErrorEventHandler(ref handler) => &handler.parent, 72 CommonEventHandler::BeforeUnloadEventHandler(ref handler) => &handler.parent, 73 } 74 } 75 } 76 77 #[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)] 78 pub enum ListenerPhase { 79 Capturing, 80 Bubbling, 81 } 82 83 /// <https://html.spec.whatwg.org/multipage/#internal-raw-uncompiled-handler> 84 #[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)] 85 struct InternalRawUncompiledHandler { 86 source: DOMString, 87 url: ServoUrl, 88 line: usize, 89 } 90 91 /// A representation of an event handler, either compiled or uncompiled raw source, or null. 92 #[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)] 93 enum InlineEventListener { 94 Uncompiled(InternalRawUncompiledHandler), 95 Compiled(CommonEventHandler), 96 Null, 97 } 98 99 impl InlineEventListener { 100 /// Get a compiled representation of this event handler, compiling it from its 101 /// raw source if necessary. 102 /// <https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler> get_compiled_handler(&mut self, owner: &EventTarget, ty: &Atom) -> Option<CommonEventHandler>103 fn get_compiled_handler(&mut self, owner: &EventTarget, ty: &Atom) 104 -> Option<CommonEventHandler> { 105 match mem::replace(self, InlineEventListener::Null) { 106 InlineEventListener::Null => None, 107 InlineEventListener::Uncompiled(handler) => { 108 let result = owner.get_compiled_event_handler(handler, ty); 109 if let Some(ref compiled) = result { 110 *self = InlineEventListener::Compiled(compiled.clone()); 111 } 112 result 113 } 114 InlineEventListener::Compiled(handler) => { 115 *self = InlineEventListener::Compiled(handler.clone()); 116 Some(handler) 117 } 118 } 119 } 120 } 121 122 #[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)] 123 enum EventListenerType { 124 Additive(#[ignore_malloc_size_of = "Rc"] Rc<EventListener>), 125 Inline(InlineEventListener), 126 } 127 128 impl EventListenerType { get_compiled_listener(&mut self, owner: &EventTarget, ty: &Atom) -> Option<CompiledEventListener>129 fn get_compiled_listener(&mut self, owner: &EventTarget, ty: &Atom) 130 -> Option<CompiledEventListener> { 131 match self { 132 &mut EventListenerType::Inline(ref mut inline) => 133 inline.get_compiled_handler(owner, ty) 134 .map(CompiledEventListener::Handler), 135 &mut EventListenerType::Additive(ref listener) => 136 Some(CompiledEventListener::Listener(listener.clone())), 137 } 138 } 139 } 140 141 /// A representation of an EventListener/EventHandler object that has previously 142 /// been compiled successfully, if applicable. 143 pub enum CompiledEventListener { 144 Listener(Rc<EventListener>), 145 Handler(CommonEventHandler), 146 } 147 148 impl CompiledEventListener { 149 #[allow(unsafe_code)] 150 // https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm call_or_handle_event<T: DomObject>(&self, object: &T, event: &Event, exception_handle: ExceptionHandling)151 pub fn call_or_handle_event<T: DomObject>(&self, 152 object: &T, 153 event: &Event, 154 exception_handle: ExceptionHandling) { 155 // Step 3 156 match *self { 157 CompiledEventListener::Listener(ref listener) => { 158 let _ = listener.HandleEvent_(object, event, exception_handle); 159 }, 160 CompiledEventListener::Handler(ref handler) => { 161 match *handler { 162 CommonEventHandler::ErrorEventHandler(ref handler) => { 163 if let Some(event) = event.downcast::<ErrorEvent>() { 164 let cx = object.global().get_cx(); 165 rooted!(in(cx) let error = unsafe { event.Error(cx) }); 166 let return_value = handler.Call_(object, 167 EventOrString::String(event.Message()), 168 Some(event.Filename()), 169 Some(event.Lineno()), 170 Some(event.Colno()), 171 Some(error.handle()), 172 exception_handle); 173 // Step 4 174 if let Ok(return_value) = return_value { 175 rooted!(in(cx) let return_value = return_value); 176 if return_value.handle().is_boolean() && return_value.handle().to_boolean() == true { 177 event.upcast::<Event>().PreventDefault(); 178 } 179 } 180 return; 181 } 182 183 let _ = handler.Call_(object, EventOrString::Event(DomRoot::from_ref(event)), 184 None, None, None, None, exception_handle); 185 } 186 187 CommonEventHandler::BeforeUnloadEventHandler(ref handler) => { 188 if let Some(event) = event.downcast::<BeforeUnloadEvent>() { 189 let rv = event.ReturnValue(); 190 191 if let Ok(value) = handler.Call_(object, 192 event.upcast::<Event>(), 193 exception_handle) { 194 match value { 195 Some(value) => { 196 if rv.is_empty() { 197 event.SetReturnValue(value); 198 } 199 } 200 None => { 201 event.upcast::<Event>().PreventDefault(); 202 } 203 } 204 } 205 } 206 } 207 208 CommonEventHandler::EventHandler(ref handler) => { 209 if let Ok(value) = handler.Call_(object, event, exception_handle) { 210 let cx = object.global().get_cx(); 211 rooted!(in(cx) let value = value); 212 let value = value.handle(); 213 214 //Step 4 215 let should_cancel = match event.type_() { 216 atom!("mouseover") => value.is_boolean() && value.to_boolean() == true, 217 _ => value.is_boolean() && value.to_boolean() == false 218 }; 219 if should_cancel { 220 event.PreventDefault(); 221 } 222 } 223 } 224 } 225 } 226 } 227 } 228 } 229 230 #[derive(Clone, DenyPublicFields, JSTraceable, MallocSizeOf, PartialEq)] 231 /// A listener in a collection of event listeners. 232 struct EventListenerEntry { 233 phase: ListenerPhase, 234 listener: EventListenerType 235 } 236 237 #[derive(JSTraceable, MallocSizeOf)] 238 /// A mix of potentially uncompiled and compiled event listeners of the same type. 239 struct EventListeners(Vec<EventListenerEntry>); 240 241 impl Deref for EventListeners { 242 type Target = Vec<EventListenerEntry>; deref(&self) -> &Vec<EventListenerEntry>243 fn deref(&self) -> &Vec<EventListenerEntry> { 244 &self.0 245 } 246 } 247 248 impl DerefMut for EventListeners { deref_mut(&mut self) -> &mut Vec<EventListenerEntry>249 fn deref_mut(&mut self) -> &mut Vec<EventListenerEntry> { 250 &mut self.0 251 } 252 } 253 254 impl EventListeners { 255 // https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler get_inline_listener(&mut self, owner: &EventTarget, ty: &Atom) -> Option<CommonEventHandler>256 fn get_inline_listener(&mut self, owner: &EventTarget, ty: &Atom) -> Option<CommonEventHandler> { 257 for entry in &mut self.0 { 258 if let EventListenerType::Inline(ref mut inline) = entry.listener { 259 // Step 1.1-1.8 and Step 2 260 return inline.get_compiled_handler(owner, ty); 261 } 262 } 263 264 // Step 2 265 None 266 } 267 268 // https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler get_listeners(&mut self, phase: Option<ListenerPhase>, owner: &EventTarget, ty: &Atom) -> Vec<CompiledEventListener>269 fn get_listeners(&mut self, phase: Option<ListenerPhase>, owner: &EventTarget, ty: &Atom) 270 -> Vec<CompiledEventListener> { 271 self.0.iter_mut().filter_map(|entry| { 272 if phase.is_none() || Some(entry.phase) == phase { 273 // Step 1.1-1.8, 2 274 entry.listener.get_compiled_listener(owner, ty) 275 } else { 276 None 277 } 278 }).collect() 279 } 280 } 281 282 #[dom_struct] 283 pub struct EventTarget { 284 reflector_: Reflector, 285 handlers: DomRefCell<HashMap<Atom, EventListeners, BuildHasherDefault<FnvHasher>>>, 286 } 287 288 impl EventTarget { new_inherited() -> EventTarget289 pub fn new_inherited() -> EventTarget { 290 EventTarget { 291 reflector_: Reflector::new(), 292 handlers: DomRefCell::new(Default::default()), 293 } 294 } 295 new(global: &GlobalScope) -> DomRoot<EventTarget>296 fn new(global: &GlobalScope) -> DomRoot<EventTarget> { 297 reflect_dom_object(Box::new(EventTarget::new_inherited()), 298 global, 299 Wrap) 300 } 301 Constructor(global: &GlobalScope) -> Fallible<DomRoot<EventTarget>>302 pub fn Constructor(global: &GlobalScope) -> Fallible<DomRoot<EventTarget>> { 303 Ok(EventTarget::new(global)) 304 } 305 get_listeners_for(&self, type_: &Atom, specific_phase: Option<ListenerPhase>) -> Vec<CompiledEventListener>306 pub fn get_listeners_for(&self, 307 type_: &Atom, 308 specific_phase: Option<ListenerPhase>) 309 -> Vec<CompiledEventListener> { 310 self.handlers.borrow_mut().get_mut(type_).map_or(vec![], |listeners| { 311 listeners.get_listeners(specific_phase, self, type_) 312 }) 313 } 314 dispatch_event_with_target(&self, target: &EventTarget, event: &Event) -> EventStatus315 pub fn dispatch_event_with_target(&self, 316 target: &EventTarget, 317 event: &Event) -> EventStatus { 318 if let Some(window) = target.global().downcast::<Window>() { 319 if window.has_document() { 320 assert!(window.Document().can_invoke_script()); 321 } 322 }; 323 324 event.dispatch(self, Some(target)) 325 } 326 dispatch_event(&self, event: &Event) -> EventStatus327 pub fn dispatch_event(&self, event: &Event) -> EventStatus { 328 if let Some(window) = self.global().downcast::<Window>() { 329 if window.has_document() { 330 assert!(window.Document().can_invoke_script()); 331 } 332 }; 333 event.dispatch(self, None) 334 } 335 remove_all_listeners(&self)336 pub fn remove_all_listeners(&self) { 337 *self.handlers.borrow_mut() = Default::default(); 338 } 339 340 /// <https://html.spec.whatwg.org/multipage/#event-handler-attributes:event-handlers-11> set_inline_event_listener(&self, ty: Atom, listener: Option<InlineEventListener>)341 fn set_inline_event_listener(&self, 342 ty: Atom, 343 listener: Option<InlineEventListener>) { 344 let mut handlers = self.handlers.borrow_mut(); 345 let entries = match handlers.entry(ty) { 346 Occupied(entry) => entry.into_mut(), 347 Vacant(entry) => entry.insert(EventListeners(vec!())), 348 }; 349 350 let idx = entries.iter().position(|ref entry| { 351 match entry.listener { 352 EventListenerType::Inline(_) => true, 353 _ => false, 354 } 355 }); 356 357 match idx { 358 Some(idx) => { 359 entries[idx].listener = 360 EventListenerType::Inline(listener.unwrap_or(InlineEventListener::Null)); 361 } 362 None => { 363 if let Some(listener) = listener { 364 entries.push(EventListenerEntry { 365 phase: ListenerPhase::Bubbling, 366 listener: EventListenerType::Inline(listener), 367 }); 368 } 369 } 370 } 371 } 372 get_inline_event_listener(&self, ty: &Atom) -> Option<CommonEventHandler>373 fn get_inline_event_listener(&self, ty: &Atom) -> Option<CommonEventHandler> { 374 let mut handlers = self.handlers.borrow_mut(); 375 handlers.get_mut(ty).and_then(|entry| entry.get_inline_listener(self, ty)) 376 } 377 378 /// Store the raw uncompiled event handler for on-demand compilation later. 379 /// <https://html.spec.whatwg.org/multipage/#event-handler-attributes:event-handler-content-attributes-3> set_event_handler_uncompiled(&self, url: ServoUrl, line: usize, ty: &str, source: DOMString)380 pub fn set_event_handler_uncompiled(&self, 381 url: ServoUrl, 382 line: usize, 383 ty: &str, 384 source: DOMString) { 385 let handler = InternalRawUncompiledHandler { 386 source: source, 387 line: line, 388 url: url, 389 }; 390 self.set_inline_event_listener(Atom::from(ty), 391 Some(InlineEventListener::Uncompiled(handler))); 392 } 393 394 // https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler 395 #[allow(unsafe_code)] get_compiled_event_handler(&self, handler: InternalRawUncompiledHandler, ty: &Atom) -> Option<CommonEventHandler>396 fn get_compiled_event_handler(&self, 397 handler: InternalRawUncompiledHandler, 398 ty: &Atom) 399 -> Option<CommonEventHandler> { 400 // Step 1.1 401 let element = self.downcast::<Element>(); 402 let document = match element { 403 Some(element) => document_from_node(element), 404 None => self.downcast::<Window>().unwrap().Document(), 405 }; 406 407 // Step 1.2 408 if !document.is_scripting_enabled() { 409 return None; 410 } 411 412 // Step 1.3 413 let body: Vec<u16> = handler.source.encode_utf16().collect(); 414 415 // TODO step 1.5 (form owner) 416 417 // Step 1.6 418 let window = document.window(); 419 420 let url_serialized = CString::new(handler.url.to_string()).unwrap(); 421 let name = CString::new(&**ty).unwrap(); 422 423 static mut ARG_NAMES: [*const c_char; 1] = [b"event\0" as *const u8 as *const c_char]; 424 static mut ERROR_ARG_NAMES: [*const c_char; 5] = [b"event\0" as *const u8 as *const c_char, 425 b"source\0" as *const u8 as *const c_char, 426 b"lineno\0" as *const u8 as *const c_char, 427 b"colno\0" as *const u8 as *const c_char, 428 b"error\0" as *const u8 as *const c_char]; 429 // step 10 430 let is_error = ty == &atom!("error") && self.is::<Window>(); 431 let args = unsafe { 432 if is_error { 433 &ERROR_ARG_NAMES[..] 434 } else { 435 &ARG_NAMES[..] 436 } 437 }; 438 439 let cx = window.get_cx(); 440 let options = CompileOptionsWrapper::new(cx, url_serialized.as_ptr(), handler.line as u32); 441 // TODO step 1.10.1-3 (document, form owner, element in scope chain) 442 443 let scopechain = AutoObjectVectorWrapper::new(cx); 444 445 let _ac = JSAutoCompartment::new(cx, window.reflector().get_jsobject().get()); 446 rooted!(in(cx) let mut handler = ptr::null_mut::<JSFunction>()); 447 let rv = unsafe { 448 CompileFunction(cx, 449 scopechain.ptr, 450 options.ptr, 451 name.as_ptr(), 452 args.len() as u32, 453 args.as_ptr(), 454 body.as_ptr(), 455 body.len() as size_t, 456 handler.handle_mut()) 457 }; 458 if !rv || handler.get().is_null() { 459 // Step 1.8.2 460 unsafe { 461 let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get()); 462 // FIXME(#13152): dispatch error event. 463 report_pending_exception(cx, false); 464 } 465 // Step 1.8.1 / 1.8.3 466 return None; 467 } 468 469 // TODO step 1.11-13 470 let funobj = unsafe { JS_GetFunctionObject(handler.get()) }; 471 assert!(!funobj.is_null()); 472 // Step 1.14 473 if is_error { 474 Some(CommonEventHandler::ErrorEventHandler( 475 unsafe { OnErrorEventHandlerNonNull::new(cx, funobj) }, 476 )) 477 } else { 478 if ty == &atom!("beforeunload") { 479 Some(CommonEventHandler::BeforeUnloadEventHandler( 480 unsafe { OnBeforeUnloadEventHandlerNonNull::new(cx, funobj) }, 481 )) 482 } else { 483 Some(CommonEventHandler::EventHandler( 484 unsafe { EventHandlerNonNull::new(cx, funobj) }, 485 )) 486 } 487 } 488 } 489 490 #[allow(unsafe_code)] set_event_handler_common<T: CallbackContainer>( &self, ty: &str, listener: Option<Rc<T>>, ) where T: CallbackContainer,491 pub fn set_event_handler_common<T: CallbackContainer>( 492 &self, 493 ty: &str, 494 listener: Option<Rc<T>>, 495 ) 496 where 497 T: CallbackContainer, 498 { 499 let cx = self.global().get_cx(); 500 501 let event_listener = listener.map(|listener| { 502 InlineEventListener::Compiled(CommonEventHandler::EventHandler( 503 unsafe { EventHandlerNonNull::new(cx, listener.callback()) }, 504 )) 505 }); 506 self.set_inline_event_listener(Atom::from(ty), event_listener); 507 } 508 509 #[allow(unsafe_code)] set_error_event_handler<T: CallbackContainer>( &self, ty: &str, listener: Option<Rc<T>>, ) where T: CallbackContainer,510 pub fn set_error_event_handler<T: CallbackContainer>( 511 &self, 512 ty: &str, 513 listener: Option<Rc<T>>, 514 ) 515 where 516 T: CallbackContainer, 517 { 518 let cx = self.global().get_cx(); 519 520 let event_listener = listener.map(|listener| { 521 InlineEventListener::Compiled(CommonEventHandler::ErrorEventHandler( 522 unsafe { OnErrorEventHandlerNonNull::new(cx, listener.callback()) } 523 )) 524 }); 525 self.set_inline_event_listener(Atom::from(ty), event_listener); 526 } 527 528 #[allow(unsafe_code)] set_beforeunload_event_handler<T: CallbackContainer>( &self, ty: &str, listener: Option<Rc<T>>, ) where T: CallbackContainer,529 pub fn set_beforeunload_event_handler<T: CallbackContainer>( 530 &self, 531 ty: &str, 532 listener: Option<Rc<T>>, 533 ) 534 where 535 T: CallbackContainer, 536 { 537 let cx = self.global().get_cx(); 538 539 let event_listener = listener.map(|listener| { 540 InlineEventListener::Compiled(CommonEventHandler::BeforeUnloadEventHandler( 541 unsafe { OnBeforeUnloadEventHandlerNonNull::new(cx, listener.callback()) } 542 )) 543 }); 544 self.set_inline_event_listener(Atom::from(ty), event_listener); 545 } 546 547 #[allow(unsafe_code)] get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<Rc<T>>548 pub fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<Rc<T>> { 549 let cx = self.global().get_cx(); 550 let listener = self.get_inline_event_listener(&Atom::from(ty)); 551 unsafe { 552 listener.map(|listener| 553 CallbackContainer::new(cx, listener.parent().callback_holder().get())) 554 } 555 } 556 has_handlers(&self) -> bool557 pub fn has_handlers(&self) -> bool { 558 !self.handlers.borrow().is_empty() 559 } 560 561 // https://dom.spec.whatwg.org/#concept-event-fire fire_event(&self, name: Atom) -> DomRoot<Event>562 pub fn fire_event(&self, name: Atom) -> DomRoot<Event> { 563 self.fire_event_with_params(name, 564 EventBubbles::DoesNotBubble, 565 EventCancelable::NotCancelable) 566 } 567 568 // https://dom.spec.whatwg.org/#concept-event-fire fire_bubbling_event(&self, name: Atom) -> DomRoot<Event>569 pub fn fire_bubbling_event(&self, name: Atom) -> DomRoot<Event> { 570 self.fire_event_with_params(name, 571 EventBubbles::Bubbles, 572 EventCancelable::NotCancelable) 573 } 574 575 // https://dom.spec.whatwg.org/#concept-event-fire fire_cancelable_event(&self, name: Atom) -> DomRoot<Event>576 pub fn fire_cancelable_event(&self, name: Atom) -> DomRoot<Event> { 577 self.fire_event_with_params(name, 578 EventBubbles::DoesNotBubble, 579 EventCancelable::Cancelable) 580 } 581 582 // https://dom.spec.whatwg.org/#concept-event-fire fire_bubbling_cancelable_event(&self, name: Atom) -> DomRoot<Event>583 pub fn fire_bubbling_cancelable_event(&self, name: Atom) -> DomRoot<Event> { 584 self.fire_event_with_params(name, 585 EventBubbles::Bubbles, 586 EventCancelable::Cancelable) 587 } 588 589 // https://dom.spec.whatwg.org/#concept-event-fire fire_event_with_params(&self, name: Atom, bubbles: EventBubbles, cancelable: EventCancelable) -> DomRoot<Event>590 pub fn fire_event_with_params(&self, 591 name: Atom, 592 bubbles: EventBubbles, 593 cancelable: EventCancelable) 594 -> DomRoot<Event> { 595 let event = Event::new(&self.global(), name, bubbles, cancelable); 596 event.fire(self); 597 event 598 } 599 // https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener add_event_listener( &self, ty: DOMString, listener: Option<Rc<EventListener>>, options: AddEventListenerOptions, )600 pub fn add_event_listener( 601 &self, 602 ty: DOMString, 603 listener: Option<Rc<EventListener>>, 604 options: AddEventListenerOptions, 605 ) { 606 let listener = match listener { 607 Some(l) => l, 608 None => return, 609 }; 610 let mut handlers = self.handlers.borrow_mut(); 611 let entry = match handlers.entry(Atom::from(ty)) { 612 Occupied(entry) => entry.into_mut(), 613 Vacant(entry) => entry.insert(EventListeners(vec!())), 614 }; 615 616 let phase = if options.parent.capture { 617 ListenerPhase::Capturing 618 } else { 619 ListenerPhase::Bubbling 620 }; 621 let new_entry = EventListenerEntry { 622 phase: phase, 623 listener: EventListenerType::Additive(listener) 624 }; 625 if !entry.contains(&new_entry) { 626 entry.push(new_entry); 627 } 628 } 629 630 // https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener remove_event_listener( &self, ty: DOMString, listener: Option<Rc<EventListener>>, options: EventListenerOptions, )631 pub fn remove_event_listener( 632 &self, 633 ty: DOMString, 634 listener: Option<Rc<EventListener>>, 635 options: EventListenerOptions, 636 ) { 637 let ref listener = match listener { 638 Some(l) => l, 639 None => return, 640 }; 641 let mut handlers = self.handlers.borrow_mut(); 642 let entry = handlers.get_mut(&Atom::from(ty)); 643 for entry in entry { 644 let phase = if options.capture { 645 ListenerPhase::Capturing 646 } else { 647 ListenerPhase::Bubbling 648 }; 649 let old_entry = EventListenerEntry { 650 phase: phase, 651 listener: EventListenerType::Additive(listener.clone()) 652 }; 653 if let Some(position) = entry.iter().position(|e| *e == old_entry) { 654 entry.remove(position); 655 } 656 } 657 } 658 } 659 660 impl EventTargetMethods for EventTarget { 661 // https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener AddEventListener( &self, ty: DOMString, listener: Option<Rc<EventListener>>, options: AddEventListenerOptionsOrBoolean, )662 fn AddEventListener( 663 &self, 664 ty: DOMString, 665 listener: Option<Rc<EventListener>>, 666 options: AddEventListenerOptionsOrBoolean, 667 ) { 668 self.add_event_listener(ty, listener, options.into()) 669 } 670 671 // https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener RemoveEventListener( &self, ty: DOMString, listener: Option<Rc<EventListener>>, options: EventListenerOptionsOrBoolean, )672 fn RemoveEventListener( 673 &self, 674 ty: DOMString, 675 listener: Option<Rc<EventListener>>, 676 options: EventListenerOptionsOrBoolean, 677 ) { 678 self.remove_event_listener(ty, listener, options.into()) 679 } 680 681 // https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent DispatchEvent(&self, event: &Event) -> Fallible<bool>682 fn DispatchEvent(&self, event: &Event) -> Fallible<bool> { 683 if event.dispatching() || !event.initialized() { 684 return Err(Error::InvalidState); 685 } 686 event.set_trusted(false); 687 Ok(match self.dispatch_event(event) { 688 EventStatus::Canceled => false, 689 EventStatus::NotCanceled => true 690 }) 691 } 692 } 693 694 impl VirtualMethods for EventTarget { super_type(&self) -> Option<&VirtualMethods>695 fn super_type(&self) -> Option<&VirtualMethods> { 696 None 697 } 698 } 699 700 impl From<AddEventListenerOptionsOrBoolean> for AddEventListenerOptions { from(options: AddEventListenerOptionsOrBoolean) -> Self701 fn from(options: AddEventListenerOptionsOrBoolean) -> Self { 702 match options { 703 AddEventListenerOptionsOrBoolean::AddEventListenerOptions(options) => { 704 options 705 }, 706 AddEventListenerOptionsOrBoolean::Boolean(capture) => { 707 Self { parent: EventListenerOptions { capture } } 708 }, 709 } 710 } 711 } 712 713 impl From<EventListenerOptionsOrBoolean> for EventListenerOptions { from(options: EventListenerOptionsOrBoolean) -> Self714 fn from(options: EventListenerOptionsOrBoolean) -> Self { 715 match options { 716 EventListenerOptionsOrBoolean::EventListenerOptions(options) => { 717 options 718 }, 719 EventListenerOptionsOrBoolean::Boolean(capture) => { 720 Self { capture } 721 }, 722 } 723 } 724 } 725