Reviewed by Geoff Garen.
Removed code that casts EventListener down to derived classes
without type checking. A crash could happen if you added event
listeners with Objective-C and then manipulated the class with
JavaScript.
* bindings/js/JSDOMApplicationCacheCustom.cpp:
(WebCore::JSDOMApplicationCache::mark): Removed all the casts
and used the markIfNotNull function and mark functions on
EventListener instead.
* bindings/js/JSMessagePortCustom.cpp:
(WebCore::JSMessagePort::mark): Ditto.
* bindings/js/JSWorkerContextCustom.cpp:
(WebCore::JSWorkerContext::mark): Ditto.
* bindings/js/JSWorkerCustom.cpp:
(WebCore::JSWorker::mark): Ditto.
* bindings/js/JSXMLHttpRequestCustom.cpp:
(WebCore::JSXMLHttpRequest::mark): Ditto.
* bindings/js/JSXMLHttpRequestUploadCustom.cpp:
(WebCore::JSXMLHttpRequestUpload::mark): Ditto.
* bindings/js/JSEventListener.cpp:
(WebCore::JSAbstractEventListener::handleEvent): Used function,
the new name for what used to be called listenerObj.
(WebCore::JSAbstractEventListener::virtualIsInline): Renamed since
this doesn't need to be virtual for callers who have a pointer to
this class, not the base class.
(WebCore::JSEventListener::function): Renamed from listenerObj.
(WebCore::JSProtectedEventListener::function): Ditto.
* bindings/js/JSEventListener.h: Removed unneeded forward class
declarations. Made all virtual functions private since there's no
need to call any of them on a particular derived class, only on
EventListener. Explicitly declare JSEventListener::mark as virtual
since it's now overriding a function in the EventListener base class.
Made JSProtectedEventListener::m_globalObject protected so the
JSLazyEventListener derived class can use it directly instead of using
a virtual function to get the pointer.
* bindings/js/JSLazyEventListener.cpp:
(WebCore::JSLazyEventListener::parseCode): Use m_globalObject instead
of globalObject since the latter is a virtual function and there's no
need to pay virtual function overhead.
(WebCore::JSLazyEventListener::function): Renamed from listenerObj.
* bindings/js/JSLazyEventListener.h: Moved forward declaration of the
Node class here from JSEventListener.h.
* bindings/scripts/CodeGeneratorJS.pm: Removed now-unneeded cast to
JSEventListener when getting the script object from a listener.
* dom/EventListener.h: Added virtual function and mark functions
so we can extract the JavaScript function object or mark a JavaScript
event listener in a type safe manner.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@42021
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2009-03-26 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Removed code that casts EventListener down to derived classes
+ without type checking. A crash could happen if you added event
+ listeners with Objective-C and then manipulated the class with
+ JavaScript.
+
+ * bindings/js/JSDOMApplicationCacheCustom.cpp:
+ (WebCore::JSDOMApplicationCache::mark): Removed all the casts
+ and used the markIfNotNull function and mark functions on
+ EventListener instead.
+ * bindings/js/JSMessagePortCustom.cpp:
+ (WebCore::JSMessagePort::mark): Ditto.
+ * bindings/js/JSWorkerContextCustom.cpp:
+ (WebCore::JSWorkerContext::mark): Ditto.
+ * bindings/js/JSWorkerCustom.cpp:
+ (WebCore::JSWorker::mark): Ditto.
+ * bindings/js/JSXMLHttpRequestCustom.cpp:
+ (WebCore::JSXMLHttpRequest::mark): Ditto.
+ * bindings/js/JSXMLHttpRequestUploadCustom.cpp:
+ (WebCore::JSXMLHttpRequestUpload::mark): Ditto.
+
+ * bindings/js/JSEventListener.cpp:
+ (WebCore::JSAbstractEventListener::handleEvent): Used function,
+ the new name for what used to be called listenerObj.
+ (WebCore::JSAbstractEventListener::virtualIsInline): Renamed since
+ this doesn't need to be virtual for callers who have a pointer to
+ this class, not the base class.
+ (WebCore::JSEventListener::function): Renamed from listenerObj.
+ (WebCore::JSProtectedEventListener::function): Ditto.
+
+ * bindings/js/JSEventListener.h: Removed unneeded forward class
+ declarations. Made all virtual functions private since there's no
+ need to call any of them on a particular derived class, only on
+ EventListener. Explicitly declare JSEventListener::mark as virtual
+ since it's now overriding a function in the EventListener base class.
+ Made JSProtectedEventListener::m_globalObject protected so the
+ JSLazyEventListener derived class can use it directly instead of using
+ a virtual function to get the pointer.
+
+ * bindings/js/JSLazyEventListener.cpp:
+ (WebCore::JSLazyEventListener::parseCode): Use m_globalObject instead
+ of globalObject since the latter is a virtual function and there's no
+ need to pay virtual function overhead.
+ (WebCore::JSLazyEventListener::function): Renamed from listenerObj.
+
+ * bindings/js/JSLazyEventListener.h: Moved forward declaration of the
+ Node class here from JSEventListener.h.
+
+ * bindings/scripts/CodeGeneratorJS.pm: Removed now-unneeded cast to
+ JSEventListener when getting the script object from a listener.
+
+ * dom/EventListener.h: Added virtual function and mark functions
+ so we can extract the JavaScript function object or mark a JavaScript
+ event listener in a type safe manner.
+
2009-03-26 Peter Kasting <pkasting@google.com>
Reviewed by Adele Peterson.
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
{
DOMObject::mark();
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onchecking()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onerror()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onnoupdate()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->ondownloading()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onprogress()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onupdateready()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->oncached()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onobsolete()))
- listener->mark();
+ markIfNotNull(m_impl->onchecking());
+ markIfNotNull(m_impl->onerror());
+ markIfNotNull(m_impl->onnoupdate());
+ markIfNotNull(m_impl->ondownloading());
+ markIfNotNull(m_impl->onprogress());
+ markIfNotNull(m_impl->onupdateready());
+ markIfNotNull(m_impl->oncached());
+ markIfNotNull(m_impl->onobsolete());
typedef DOMApplicationCache::EventListenersMap EventListenersMap;
typedef DOMApplicationCache::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
- for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
- JSEventListener* listener = static_cast<JSEventListener*>(vecIter->get());
- listener->mark();
- }
+ for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
+ (*vecIter)->mark();
}
}
/*
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
{
JSLock lock(false);
- JSObject* listener = listenerObj();
+ JSObject* listener = function();
if (!listener)
return;
}
}
-bool JSAbstractEventListener::isInline() const
+bool JSAbstractEventListener::virtualIsInline() const
{
return m_isInline;
}
}
}
-JSObject* JSEventListener::listenerObj() const
+JSObject* JSEventListener::function() const
{
return m_listener;
}
#endif
}
-JSObject* JSProtectedEventListener::listenerObj() const
+JSObject* JSProtectedEventListener::function() const
{
return m_listener;
}
/*
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
namespace WebCore {
- class Event;
class JSDOMGlobalObject;
- class Node;
class JSAbstractEventListener : public EventListener {
public:
- virtual void handleEvent(Event*, bool isWindowEvent);
- virtual bool isInline() const;
- virtual JSC::JSObject* listenerObj() const = 0;
- virtual JSDOMGlobalObject* globalObject() const = 0;
+ bool isInline() const { return m_isInline; }
protected:
JSAbstractEventListener(bool isInline)
}
private:
+ virtual void handleEvent(Event*, bool isWindowEvent);
+ virtual JSDOMGlobalObject* globalObject() const = 0;
+ virtual bool virtualIsInline() const;
+
bool m_isInline;
};
}
virtual ~JSEventListener();
- virtual JSC::JSObject* listenerObj() const;
- virtual JSDOMGlobalObject* globalObject() const;
void clearGlobalObject();
- void mark();
private:
JSEventListener(JSC::JSObject* listener, JSDOMGlobalObject*, bool isInline);
+ virtual JSC::JSObject* function() const;
+ virtual void mark();
+ virtual JSDOMGlobalObject* globalObject() const;
+
JSC::JSObject* m_listener;
JSDOMGlobalObject* m_globalObject;
};
}
virtual ~JSProtectedEventListener();
- virtual JSC::JSObject* listenerObj() const;
- virtual JSDOMGlobalObject* globalObject() const;
void clearGlobalObject();
protected:
JSProtectedEventListener(JSC::JSObject* listener, JSDOMGlobalObject*, bool isInline);
mutable JSC::ProtectedPtr<JSC::JSObject> m_listener;
+ JSC::ProtectedPtr<JSDOMGlobalObject> m_globalObject;
private:
- JSC::ProtectedPtr<JSDOMGlobalObject> m_globalObject;
+ virtual JSC::JSObject* function() const;
+ virtual JSDOMGlobalObject* globalObject() const;
};
} // namespace WebCore
/*
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
m_lineNumber = 1;
}
-JSObject* JSLazyEventListener::listenerObj() const
+JSObject* JSLazyEventListener::function() const
{
parseCode();
return m_listener;
if (m_parsed)
return;
- if (globalObject()->scriptExecutionContext()->isDocument()) {
- JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject());
+ if (m_globalObject->scriptExecutionContext()->isDocument()) {
+ JSDOMWindow* window = static_cast<JSDOMWindow*>(m_globalObject.get());
Frame* frame = window->impl()->frame();
if (!frame)
return;
m_parsed = true;
- ExecState* exec = globalObject()->globalExec();
+ ExecState* exec = m_globalObject->globalExec();
ArgList args;
- UString sourceURL(globalObject()->scriptExecutionContext()->url().string());
+ UString sourceURL(m_globalObject->scriptExecutionContext()->url().string());
args.append(eventParameterName(m_type, exec));
args.append(jsString(exec, m_code));
if (m_listener) {
ASSERT(isInline());
- JSDOMWindow::ProtectedListenersMap& listeners = globalObject()->jsProtectedInlineEventListeners();
+ JSDOMWindow::ProtectedListenersMap& listeners = m_globalObject->jsProtectedInlineEventListeners();
listeners.set(m_listener, const_cast<JSLazyEventListener*>(this));
}
}
/*
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
namespace WebCore {
+ class Node;
+
class JSLazyEventListener : public JSProtectedEventListener {
public:
enum LazyEventListenerType {
#endif
};
- virtual bool wasCreatedFromMarkup() const { return true; }
-
static PassRefPtr<JSLazyEventListener> create(LazyEventListenerType type, const String& functionName, const String& code, JSDOMGlobalObject* globalObject, Node* node, int lineNumber)
{
return adoptRef(new JSLazyEventListener(type, functionName, code, globalObject, node, lineNumber));
}
- virtual JSC::JSObject* listenerObj() const;
- protected:
+ private:
JSLazyEventListener(LazyEventListenerType, const String& functionName, const String& code, JSDOMGlobalObject*, Node*, int lineNumber);
- private:
+ virtual JSC::JSObject* function() const;
+ virtual bool wasCreatedFromMarkup() const { return true; }
+
void parseCode() const;
mutable String m_functionName;
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
{
DOMObject::mark();
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onmessage()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onclose()))
- listener->mark();
+ markIfNotNull(m_impl->onmessage());
+ markIfNotNull(m_impl->onclose());
if (MessagePort* entangledPort = m_impl->entangledPort()) {
DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), entangledPort);
typedef MessagePort::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
- for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
- JSEventListener* listener = static_cast<JSEventListener*>(vecIter->get());
- listener->mark();
- }
+ for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
+ (*vecIter)->mark();
}
}
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
markActiveObjectsForContext(*globalData(), scriptExecutionContext());
- if (JSEventListener* listener = static_cast<JSEventListener*>(impl()->onmessage()))
- listener->mark();
+ markIfNotNull(impl()->onmessage());
typedef WorkerContext::EventListenersMap EventListenersMap;
typedef WorkerContext::ListenerVector ListenerVector;
EventListenersMap& eventListeners = impl()->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
- for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
- JSEventListener* listener = static_cast<JSEventListener*>(vecIter->get());
- listener->mark();
- }
+ for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
+ (*vecIter)->mark();
}
}
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
{
DOMObject::mark();
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onmessage()))
- listener->mark();
-
- if (JSEventListener* listener = static_cast<JSEventListener*>(m_impl->onerror()))
- listener->mark();
+ markIfNotNull(m_impl->onmessage());
+ markIfNotNull(m_impl->onerror());
typedef Worker::EventListenersMap EventListenersMap;
typedef Worker::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
- for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
- JSEventListener* listener = static_cast<JSEventListener*>(vecIter->get());
- listener->mark();
- }
+ for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
+ (*vecIter)->mark();
}
}
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
wrapper->mark();
}
- if (JSEventListener* onReadyStateChangeListener = static_cast<JSEventListener*>(m_impl->onreadystatechange()))
- onReadyStateChangeListener->mark();
-
- if (JSEventListener* onAbortListener = static_cast<JSEventListener*>(m_impl->onabort()))
- onAbortListener->mark();
-
- if (JSEventListener* onErrorListener = static_cast<JSEventListener*>(m_impl->onerror()))
- onErrorListener->mark();
-
- if (JSEventListener* onLoadListener = static_cast<JSEventListener*>(m_impl->onload()))
- onLoadListener->mark();
-
- if (JSEventListener* onLoadStartListener = static_cast<JSEventListener*>(m_impl->onloadstart()))
- onLoadStartListener->mark();
-
- if (JSEventListener* onProgressListener = static_cast<JSEventListener*>(m_impl->onprogress()))
- onProgressListener->mark();
+ markIfNotNull(m_impl->onreadystatechange());
+ markIfNotNull(m_impl->onabort());
+ markIfNotNull(m_impl->onerror());
+ markIfNotNull(m_impl->onload());
+ markIfNotNull(m_impl->onloadstart());
+ markIfNotNull(m_impl->onprogress());
typedef XMLHttpRequest::EventListenersMap EventListenersMap;
typedef XMLHttpRequest::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
- for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
- JSEventListener* listener = static_cast<JSEventListener*>(vecIter->get());
- listener->mark();
- }
+ for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
+ (*vecIter)->mark();
}
}
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
wrapper->mark();
}
- if (JSEventListener* onAbortListener = static_cast<JSEventListener*>(m_impl->onabort()))
- onAbortListener->mark();
-
- if (JSEventListener* onErrorListener = static_cast<JSEventListener*>(m_impl->onerror()))
- onErrorListener->mark();
-
- if (JSEventListener* onLoadListener = static_cast<JSEventListener*>(m_impl->onload()))
- onLoadListener->mark();
-
- if (JSEventListener* onLoadStartListener = static_cast<JSEventListener*>(m_impl->onloadstart()))
- onLoadStartListener->mark();
-
- if (JSEventListener* onProgressListener = static_cast<JSEventListener*>(m_impl->onprogress()))
- onProgressListener->mark();
+ markIfNotNull(m_impl->onabort());
+ markIfNotNull(m_impl->onerror());
+ markIfNotNull(m_impl->onload());
+ markIfNotNull(m_impl->onloadstart());
+ markIfNotNull(m_impl->onprogress());
typedef XMLHttpRequestUpload::EventListenersMap EventListenersMap;
typedef XMLHttpRequestUpload::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
- for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
- JSEventListener* listener = static_cast<JSEventListener*>(vecIter->get());
- listener->mark();
- }
+ for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
+ (*vecIter)->mark();
}
}
push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(asObject(slot.slotBase()))->impl());\n");
push(@implContent, " return checkNodeSecurity(exec, imp->contentDocument()) ? " . NativeToJSValue($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$implGetterFunctionName()", "static_cast<$className*>(asObject(slot.slotBase()))") . " : jsUndefined();\n");
} elsif ($type eq "EventListener") {
- $implIncludes{"JSEventListener.h"} = 1;
$implIncludes{"EventListener.h"} = 1;
- my $listenerType;
- if ($attribute->signature->extendedAttributes->{"ProtectedListener"}) {
- $listenerType = "JSProtectedEventListener";
- } else {
- $listenerType = "JSEventListener";
- }
push(@implContent, " UNUSED_PARAM(exec);\n");
push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(asObject(slot.slotBase()))->impl());\n");
- push(@implContent, " if (${listenerType}* listener = static_cast<${listenerType}*>(imp->$implGetterFunctionName())) {\n");
- push(@implContent, " if (JSObject* listenerObj = listener->listenerObj())\n");
- push(@implContent, " return listenerObj;\n");
+ push(@implContent, " if (EventListener* listener = imp->$implGetterFunctionName()) {\n");
+ push(@implContent, " if (JSObject* function = listener->function())\n");
+ push(@implContent, " return function;\n");
push(@implContent, " }\n");
push(@implContent, " return jsNull();\n");
} elsif ($attribute->signature->type =~ /Constructor$/) {
/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include <wtf/RefCounted.h>
+namespace JSC {
+ class JSObject;
+}
+
namespace WebCore {
class Event;
public:
virtual ~EventListener() { }
virtual void handleEvent(Event*, bool isWindowEvent = false) = 0;
- virtual bool isInline() const { return false; }
virtual bool wasCreatedFromMarkup() const { return false; }
+
+#if USE(JSC)
+ virtual JSC::JSObject* function() const { return 0; }
+ virtual void mark() { }
+#endif
+
+ bool isInline() const { return virtualIsInline(); }
+
+ private:
+ virtual bool virtualIsInline() const { return false; }
};
+ inline void markIfNotNull(EventListener* listener) { if (listener) listener->mark(); }
+
}
#endif