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