Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event listeners and dispatch #1171

Merged
merged 4 commits into from Nov 5, 2013
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Add Event and EventTarget hierarchy via gross AbstractFoo mechanism.

  • Loading branch information
jdm committed Nov 5, 2013
commit bb97fd13f38090c460d79dad3322ab4b7e325a82
@@ -182,13 +182,20 @@ DOMInterfaces = {
},

'Event': {
'nativeType': 'AbstractEvent',
'concreteType': 'Event',
'pointerType': '',
},

'EventListener': {
'nativeType': 'EventListenerBinding::EventListener',
},

'EventTarget': {
'nativeType': 'AbstractEventTarget',
'concreteType': 'EventTarget',
'pointerType': '',
'needsAbstract': ['dispatchEvent']
},

'FileList': [
@@ -277,6 +284,9 @@ DOMInterfaces = {
}],

'MouseEvent': {
'nativeType': 'AbstractEvent',
'concreteType': 'MouseEvent',
'pointerType': '',
},

'Navigator': {
@@ -374,6 +384,9 @@ DOMInterfaces = {
}],

'UIEvent': {
'nativeType': 'AbstractEvent',
'concreteType': 'UIEvent',
'pointerType': '',
},

'ValidityState': {
@@ -2410,12 +2410,13 @@ class Argument():
"""
A class for outputting the type and name of an argument
"""
def __init__(self, argType, name, default=None):
def __init__(self, argType, name, default=None, mutable=False):
self.argType = argType
self.name = name
self.default = default
self.mutable = mutable
def declare(self):
string = self.name + ((': ' + self.argType) if self.argType else '')
string = ('mut ' if self.mutable else '') + self.name + ((': ' + self.argType) if self.argType else '')
#XXXjdm Support default arguments somehow :/
#if self.default is not None:
# string += " = " + self.default
@@ -5225,6 +5226,8 @@ def makeEnumTypedef(e):
'dom::bindings::proxyhandler::*',
'dom::document::AbstractDocument',
'dom::node::{AbstractNode, ScriptView}',
'dom::eventtarget::AbstractEventTarget',
'dom::event::AbstractEvent',
'servo_util::vec::zip_copies',
'std::cast',
'std::libc',
@@ -5652,6 +5655,11 @@ def getMethodImpls(self, method):
# CallSetup should re-throw exceptions on aRv.
args.append(Argument("ExceptionHandling", "aExceptionHandling",
"eReportExceptions"))

# Ensure the first argument is mutable
args[0] = Argument(args[0].argType, args[0].name, args[0].default, mutable=True)
method.args[2] = args[0]

# And now insert our template argument.
argsWithoutThis = list(args)
args.insert(0, Argument("@mut T", "thisObj"))
@@ -5661,7 +5669,7 @@ def getMethodImpls(self, method):
args.insert(0, Argument(None, "&self"))
argsWithoutThis.insert(0, Argument(None, "&self"))

setupCall = ("let s = CallSetup::new(cx_for_dom_object(${cxProvider}), aExceptionHandling);\n"
setupCall = ("let s = CallSetup::new(cx_for_dom_object(&mut ${cxProvider}), aExceptionHandling);\n"
"if s.GetContext().is_null() {\n"
" return${errorReturn};\n"
"}\n")
@@ -5676,7 +5684,7 @@ def getMethodImpls(self, method):
"errorReturn" : method.getDefaultRetval(),
"callArgs" : ", ".join(argnamesWithThis),
"methodName": 'self.' + method.name,
"cxProvider": 'thisObj'
"cxProvider": '*thisObj'
})
bodyWithoutThis = string.Template(
setupCall +
@@ -768,6 +768,7 @@ pub enum Error {
NotFound,
HierarchyRequest,
InvalidCharacter,
NotSupported
}

pub type Fallible<T> = Result<T, Error>;
@@ -841,7 +842,7 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
}

#[fixed_stack_segment]
fn cx_for_dom_wrapper(obj: *JSObject) -> *JSContext {
fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
unsafe {
let global = GetGlobalForObjectCrossCompartment(obj);
let clasp = JS_GetClass(global);
@@ -860,8 +861,8 @@ fn cx_for_dom_wrapper(obj: *JSObject) -> *JSContext {
}
}

pub fn cx_for_dom_object<T: Reflectable>(obj: @mut T) -> *JSContext {
cx_for_dom_wrapper(obj.reflector().get_jsobject())
pub fn cx_for_dom_object<T: Reflectable>(obj: &mut T) -> *JSContext {
cx_for_dom_reflector(obj.reflector().get_jsobject())
}

/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
@@ -5,16 +5,20 @@
use dom::comment::Comment;
use dom::bindings::codegen::DocumentBinding;
use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
use dom::bindings::utils::{Reflectable, Reflector, DerivedWrapper};
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, null_str_as_empty, null_str_as_word_null};
use dom::bindings::utils::{Reflectable, Reflector, DerivedWrapper, NotSupported};
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable};
use dom::bindings::utils::{null_str_as_empty_ref, null_str_as_empty, null_str_as_word_null};
use dom::documentfragment::DocumentFragment;
use dom::element::{Element};
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
use dom::event::Event;
use dom::event::{AbstractEvent, Event, HTMLEventTypeId, UIEventTypeId};
use dom::htmlcollection::HTMLCollection;
use dom::htmldocument::HTMLDocument;
use dom::htmlelement::HTMLElement;
use dom::mouseevent::MouseEvent;
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
use dom::text::Text;
use dom::uievent::UIEvent;
use dom::window::Window;
use dom::htmltitleelement::HTMLTitleElement;
use html::hubbub_html_parser::build_element_from_tag;
@@ -256,9 +260,13 @@ impl Document {
Comment::new(null_str_as_word_null(data), abstract_self)
}

pub fn CreateEvent(&self, interface: &DOMString) -> Fallible<@mut Event> {
//FIXME: We need to do a proper Event inheritance simulation
Ok(Event::new(self.window, interface))
pub fn CreateEvent(&self, interface: &DOMString) -> Fallible<AbstractEvent> {
match null_str_as_empty_ref(interface) {
"UIEvents" => Ok(UIEvent::new(self.window, UIEventTypeId)),
"MouseEvents" => Ok(MouseEvent::new(self.window)),
"HTMLEvents" => Ok(Event::new(self.window, HTMLEventTypeId)),
_ => Err(NotSupported)
}
}

pub fn Title(&self, _: AbstractDocument) -> DOMString {
@@ -2,17 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::eventtarget::EventTarget;
use dom::eventtarget::AbstractEventTarget;
use dom::window::Window;
use dom::bindings::codegen::EventBinding;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object, DerivedWrapper};
use dom::bindings::utils::{DOMString, ErrorResult, Fallible, null_str_as_word_null};
use dom::mouseevent::MouseEvent;
use dom::uievent::UIEvent;

use geom::point::Point2D;
use js::jsapi::{JSObject, JSContext};
use js::jsapi::{JSObject, JSContext, JSVal};
use js::glue::RUST_OBJECT_TO_JSVAL;

use script_task::page_from_context;

use std::cast;
use std::unstable::raw::Box;

pub enum Event_ {
ResizeEvent(uint, uint),
ReflowEvent,
@@ -21,7 +27,116 @@ pub enum Event_ {
MouseUpEvent(uint, Point2D<f32>),
}

pub struct AbstractEvent {
event: *mut Box<Event>
}

impl AbstractEvent {
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent {
AbstractEvent {
event: box
}
}

//
// Downcasting borrows
//

fn transmute<'a, T>(&'a self) -> &'a T {
unsafe {
let box: *Box<T> = self.event as *Box<T>;
&(*box).data
}
}

fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
unsafe {
let box: *mut Box<T> = self.event as *mut Box<T>;
&mut (*box).data
}
}

pub fn type_id(&self) -> EventTypeId {
self.event().type_id
}

pub fn event<'a>(&'a self) -> &'a Event {
self.transmute()
}

pub fn mut_event<'a>(&'a self) -> &'a mut Event {
self.transmute_mut()
}

pub fn is_uievent(&self) -> bool {
self.type_id() == UIEventTypeId
}

pub fn uievent<'a>(&'a self) -> &'a UIEvent {
assert!(self.is_uievent());
self.transmute()
}

pub fn mut_uievent<'a>(&'a self) -> &'a mut UIEvent {
assert!(self.is_uievent());
self.transmute_mut()
}

pub fn is_mouseevent(&self) -> bool {
self.type_id() == MouseEventTypeId
}

pub fn mouseevent<'a>(&'a self) -> &'a MouseEvent {
assert!(self.is_mouseevent());
self.transmute()
}

pub fn mut_mouseevent<'a>(&'a self) -> &'a mut MouseEvent {
assert!(self.is_mouseevent());
self.transmute_mut()
}
}

impl DerivedWrapper for AbstractEvent {
#[fixed_stack_segment]
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
let wrapper = self.reflector().get_jsobject();
if wrapper.is_not_null() {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
return 1;
}
unreachable!()
}
}

impl Reflectable for AbstractEvent {
fn reflector<'a>(&'a self) -> &'a Reflector {
self.event().reflector()
}

fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
self.mut_event().mut_reflector()
}

fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"doesn't make any sense");
}

fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
self.event().GetParentObject(cx)
}
}

#[deriving(Eq)]
pub enum EventTypeId {
HTMLEventTypeId,
UIEventTypeId,
MouseEventTypeId,
KeyEventTypeId
}

pub struct Event {
type_id: EventTypeId,
reflector_: Reflector,
type_: ~str,
default_prevented: bool,
@@ -31,19 +146,30 @@ pub struct Event {
}

impl Event {
pub fn new_inherited(type_: &DOMString) -> Event {
pub fn new_inherited(type_id: EventTypeId) -> Event {
Event {
type_id: type_id,
reflector_: Reflector::new(),
type_: null_str_as_word_null(type_),
type_: ~"",
default_prevented: false,
cancelable: true,
bubbles: true,
trusted: false
}
}

pub fn new(window: @mut Window, type_: &DOMString) -> @mut Event {
reflect_dom_object(@mut Event::new_inherited(type_), window, EventBinding::Wrap)
//FIXME: E should be bounded by some trait that is only implemented for Event types
pub fn as_abstract<E>(event: @mut E) -> AbstractEvent {
// This surrenders memory management of the event!
AbstractEvent {
event: unsafe { cast::transmute(event) },
}
}

pub fn new(window: @mut Window, type_id: EventTypeId) -> AbstractEvent {
let ev = reflect_dom_object(@mut Event::new_inherited(type_id), window,
EventBinding::Wrap);
Event::as_abstract(ev)
}

pub fn EventPhase(&self) -> u16 {
@@ -54,11 +180,11 @@ impl Event {
Some(self.type_.clone())
}

pub fn GetTarget(&self) -> Option<@mut EventTarget> {
pub fn GetTarget(&self) -> Option<AbstractEventTarget> {
None
}

pub fn GetCurrentTarget(&self) -> Option<@mut EventTarget> {
pub fn GetCurrentTarget(&self) -> Option<AbstractEventTarget> {
None
}

@@ -92,7 +218,7 @@ impl Event {
type_: &DOMString,
bubbles: bool,
cancelable: bool) -> ErrorResult {
self.type_ = type_.to_str();
self.type_ = null_str_as_word_null(type_);
self.cancelable = cancelable;
self.bubbles = bubbles;
Ok(())
@@ -103,9 +229,11 @@ impl Event {
}

pub fn Constructor(global: @mut Window,
type_: &DOMString,
_init: &EventBinding::EventInit) -> Fallible<@mut Event> {
Ok(Event::new(global, type_))
type_: &DOMString,
init: &EventBinding::EventInit) -> Fallible<AbstractEvent> {
let ev = Event::new(global, HTMLEventTypeId);
ev.mut_event().InitEvent(type_, init.bubbles, init.cancelable);
Ok(ev)
}
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.