PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/components/script/dom/eventtarget.rs

https://gitlab.com/0072016/0072016-SDK-js-sdk-framework-
Rust | 349 lines | 306 code | 36 blank | 7 comment | 24 complexity | b242811e7b8b0ca55a24e18a6175d027 MD5 | raw file
  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. use dom::bindings::callback::{CallbackContainer, ExceptionHandling};
  5. use dom::bindings::cell::DOMRefCell;
  6. use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
  7. use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
  8. use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
  9. use dom::bindings::error::Error::InvalidState;
  10. use dom::bindings::error::{Fallible, report_pending_exception};
  11. use dom::bindings::utils::{Reflectable, Reflector};
  12. use dom::event::Event;
  13. use dom::eventdispatcher::dispatch_event;
  14. use dom::node::NodeTypeId;
  15. use dom::virtualmethods::VirtualMethods;
  16. use dom::workerglobalscope::WorkerGlobalScopeTypeId;
  17. use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTargetTypeId;
  18. use js::jsapi::{CompileFunction, JS_GetFunctionObject};
  19. use js::jsapi::{JSAutoCompartment, JSAutoRequest};
  20. use js::jsapi::{JSContext, RootedFunction, HandleObject};
  21. use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper};
  22. use util::mem::HeapSizeOf;
  23. use util::str::DOMString;
  24. use fnv::FnvHasher;
  25. use libc::{c_char, size_t};
  26. use std::borrow::ToOwned;
  27. use std::collections::hash_map::Entry::{Occupied, Vacant};
  28. use std::collections::hash_state::DefaultState;
  29. use std::default::Default;
  30. use std::ffi::CString;
  31. use std::intrinsics;
  32. use std::ptr;
  33. use std::rc::Rc;
  34. use url::Url;
  35. use std::collections::HashMap;
  36. pub type EventHandler = EventHandlerNonNull;
  37. #[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
  38. pub enum ListenerPhase {
  39. Capturing,
  40. Bubbling,
  41. }
  42. #[derive(JSTraceable, Copy, Clone)]
  43. #[derive(HeapSizeOf)]
  44. pub enum EventTargetTypeId {
  45. Node(NodeTypeId),
  46. WebSocket,
  47. Window,
  48. Worker,
  49. FileReader,
  50. WorkerGlobalScope(WorkerGlobalScopeTypeId),
  51. XMLHttpRequestEventTarget(XMLHttpRequestEventTargetTypeId)
  52. }
  53. impl PartialEq for EventTargetTypeId {
  54. #[inline]
  55. fn eq(&self, other: &EventTargetTypeId) -> bool {
  56. match (*self, *other) {
  57. (EventTargetTypeId::Node(this_type), EventTargetTypeId::Node(other_type)) => {
  58. this_type == other_type
  59. }
  60. _ => self.eq_slow(other)
  61. }
  62. }
  63. }
  64. impl EventTargetTypeId {
  65. #[allow(unsafe_code)]
  66. fn eq_slow(&self, other: &EventTargetTypeId) -> bool {
  67. match (*self, *other) {
  68. (EventTargetTypeId::Node(this_type), EventTargetTypeId::Node(other_type)) => {
  69. this_type == other_type
  70. }
  71. (EventTargetTypeId::WorkerGlobalScope(this_type),
  72. EventTargetTypeId::WorkerGlobalScope(other_type)) => {
  73. this_type == other_type
  74. }
  75. (EventTargetTypeId::XMLHttpRequestEventTarget(this_type),
  76. EventTargetTypeId::XMLHttpRequestEventTarget(other_type)) => {
  77. this_type == other_type
  78. }
  79. (_, _) => {
  80. unsafe {
  81. intrinsics::discriminant_value(self) == intrinsics::discriminant_value(other)
  82. }
  83. }
  84. }
  85. }
  86. }
  87. #[derive(JSTraceable, Clone, PartialEq)]
  88. pub enum EventListenerType {
  89. Additive(Rc<EventListener>),
  90. Inline(Rc<EventHandler>),
  91. }
  92. impl HeapSizeOf for EventListenerType {
  93. fn heap_size_of_children(&self) -> usize {
  94. // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
  95. 0
  96. }
  97. }
  98. impl EventListenerType {
  99. pub fn call_or_handle_event<T: Reflectable>(&self,
  100. object: &T,
  101. event: &Event,
  102. exception_handle: ExceptionHandling) {
  103. match *self {
  104. EventListenerType::Additive(ref listener) => {
  105. let _ = listener.HandleEvent_(object, event, exception_handle);
  106. },
  107. EventListenerType::Inline(ref handler) => {
  108. let _ = handler.Call_(object, event, exception_handle);
  109. },
  110. }
  111. }
  112. }
  113. #[derive(JSTraceable, Clone, PartialEq, HeapSizeOf)]
  114. #[privatize]
  115. pub struct EventListenerEntry {
  116. phase: ListenerPhase,
  117. listener: EventListenerType
  118. }
  119. #[dom_struct]
  120. pub struct EventTarget {
  121. reflector_: Reflector,
  122. type_id: EventTargetTypeId,
  123. handlers: DOMRefCell<HashMap<DOMString, Vec<EventListenerEntry>, DefaultState<FnvHasher>>>,
  124. }
  125. impl EventTarget {
  126. pub fn new_inherited(type_id: EventTargetTypeId) -> EventTarget {
  127. EventTarget {
  128. reflector_: Reflector::new(),
  129. type_id: type_id,
  130. handlers: DOMRefCell::new(Default::default()),
  131. }
  132. }
  133. pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListenerType>> {
  134. self.handlers.borrow().get(type_).map(|listeners| {
  135. listeners.iter().map(|entry| entry.listener.clone()).collect()
  136. })
  137. }
  138. pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase)
  139. -> Option<Vec<EventListenerType>> {
  140. self.handlers.borrow().get(type_).map(|listeners| {
  141. let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
  142. filtered.map(|entry| entry.listener.clone()).collect()
  143. })
  144. }
  145. #[inline]
  146. pub fn type_id(&self) -> &EventTargetTypeId {
  147. &self.type_id
  148. }
  149. pub fn dispatch_event_with_target(&self,
  150. target: &EventTarget,
  151. event: &Event) -> bool {
  152. dispatch_event(self, Some(target), event)
  153. }
  154. pub fn dispatch_event(&self, event: &Event) -> bool {
  155. dispatch_event(self, None, event)
  156. }
  157. pub fn set_inline_event_listener(&self,
  158. ty: DOMString,
  159. listener: Option<Rc<EventHandler>>) {
  160. let mut handlers = self.handlers.borrow_mut();
  161. let entries = match handlers.entry(ty) {
  162. Occupied(entry) => entry.into_mut(),
  163. Vacant(entry) => entry.insert(vec!()),
  164. };
  165. let idx = entries.iter().position(|ref entry| {
  166. match entry.listener {
  167. EventListenerType::Inline(_) => true,
  168. _ => false,
  169. }
  170. });
  171. match idx {
  172. Some(idx) => {
  173. match listener {
  174. Some(listener) => entries[idx].listener = EventListenerType::Inline(listener),
  175. None => {
  176. entries.remove(idx);
  177. }
  178. }
  179. }
  180. None => {
  181. if listener.is_some() {
  182. entries.push(EventListenerEntry {
  183. phase: ListenerPhase::Bubbling,
  184. listener: EventListenerType::Inline(listener.unwrap()),
  185. });
  186. }
  187. }
  188. }
  189. }
  190. pub fn get_inline_event_listener(&self, ty: DOMString) -> Option<Rc<EventHandler>> {
  191. let handlers = self.handlers.borrow();
  192. let entries = handlers.get(&ty);
  193. entries.and_then(|entries| entries.iter().filter_map(|entry| {
  194. match entry.listener {
  195. EventListenerType::Inline(ref handler) => Some(handler.clone()),
  196. _ => None,
  197. }
  198. }).next())
  199. }
  200. #[allow(unsafe_code)]
  201. pub fn set_event_handler_uncompiled(&self,
  202. cx: *mut JSContext,
  203. url: Url,
  204. scope: HandleObject,
  205. ty: &str,
  206. source: DOMString) {
  207. let url = CString::new(url.serialize()).unwrap();
  208. let name = CString::new(ty).unwrap();
  209. let lineno = 0; //XXXjdm need to get a real number here
  210. let nargs = 1; //XXXjdm not true for onerror
  211. static mut ARG_NAMES: [*const c_char; 1] = [b"event\0" as *const u8 as *const c_char];
  212. let source: Vec<u16> = source.utf16_units().collect();
  213. let options = CompileOptionsWrapper::new(cx, url.as_ptr(), lineno);
  214. let scopechain = AutoObjectVectorWrapper::new(cx);
  215. let _ar = JSAutoRequest::new(cx);
  216. let _ac = JSAutoCompartment::new(cx, scope.get());
  217. let mut handler = RootedFunction::new(cx, ptr::null_mut());
  218. let rv = unsafe {
  219. CompileFunction(cx,
  220. scopechain.ptr,
  221. options.ptr,
  222. name.as_ptr(),
  223. nargs,
  224. ARG_NAMES.as_mut_ptr(),
  225. source.as_ptr() as *const i16,
  226. source.len() as size_t,
  227. handler.handle_mut())
  228. };
  229. if rv == 0 || handler.ptr.is_null() {
  230. report_pending_exception(cx, self.reflector().get_jsobject().get());
  231. return;
  232. }
  233. let funobj = unsafe { JS_GetFunctionObject(handler.ptr) };
  234. assert!(!funobj.is_null());
  235. self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)));
  236. }
  237. pub fn set_event_handler_common<T: CallbackContainer>(
  238. &self, ty: &str, listener: Option<Rc<T>>)
  239. {
  240. let event_listener = listener.map(|listener|
  241. EventHandlerNonNull::new(listener.callback()));
  242. self.set_inline_event_listener(ty.to_owned(), event_listener);
  243. }
  244. pub fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<Rc<T>> {
  245. let listener = self.get_inline_event_listener(ty.to_owned());
  246. listener.map(|listener| CallbackContainer::new(listener.parent.callback()))
  247. }
  248. pub fn has_handlers(&self) -> bool {
  249. !self.handlers.borrow().is_empty()
  250. }
  251. }
  252. impl EventTargetMethods for EventTarget {
  253. // https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
  254. fn AddEventListener(&self,
  255. ty: DOMString,
  256. listener: Option<Rc<EventListener>>,
  257. capture: bool) {
  258. match listener {
  259. Some(listener) => {
  260. let mut handlers = self.handlers.borrow_mut();
  261. let entry = match handlers.entry(ty) {
  262. Occupied(entry) => entry.into_mut(),
  263. Vacant(entry) => entry.insert(vec!()),
  264. };
  265. let phase = if capture { ListenerPhase::Capturing } else { ListenerPhase::Bubbling };
  266. let new_entry = EventListenerEntry {
  267. phase: phase,
  268. listener: EventListenerType::Additive(listener)
  269. };
  270. if !entry.contains(&new_entry) {
  271. entry.push(new_entry);
  272. }
  273. },
  274. _ => (),
  275. }
  276. }
  277. // https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener
  278. fn RemoveEventListener(&self,
  279. ty: DOMString,
  280. listener: Option<Rc<EventListener>>,
  281. capture: bool) {
  282. match listener {
  283. Some(ref listener) => {
  284. let mut handlers = self.handlers.borrow_mut();
  285. let entry = handlers.get_mut(&ty);
  286. for entry in entry {
  287. let phase = if capture { ListenerPhase::Capturing } else { ListenerPhase::Bubbling };
  288. let old_entry = EventListenerEntry {
  289. phase: phase,
  290. listener: EventListenerType::Additive(listener.clone())
  291. };
  292. if let Some(position) = entry.iter().position(|e| *e == old_entry) {
  293. entry.remove(position);
  294. }
  295. }
  296. },
  297. _ => (),
  298. }
  299. }
  300. // https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
  301. fn DispatchEvent(&self, event: &Event) -> Fallible<bool> {
  302. if event.dispatching() || !event.initialized() {
  303. return Err(InvalidState);
  304. }
  305. event.set_trusted(false);
  306. Ok(self.dispatch_event(event))
  307. }
  308. }
  309. impl VirtualMethods for EventTarget {
  310. fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
  311. None
  312. }
  313. }