Commit 76d2a71c authored by eric@webkit.org's avatar eric@webkit.org

2009-10-01 Vitaly Repeshko <vitalyr@chromium.org>

        Reviewed by Dimitri Glazkov.

        [V8] Refactored V8 event listeners:
        (This change should fix http://crbug.com/21079 and
        https://bugs.webkit.org/show_bug.cgi?id=29093.)
         o All listeners use weak handles to JS objects to avoid creating
           cycles and leaking memory.
         o "Object" variants of listeners removed.
         o All event accessor callbacks are generated.
         o Custom event accessors removed.
         o All wrappers have hidden dependencies on their listeners to
           prevent listeners from being collected.
         o All variats of getEventListener function grouped in V8DOMWrapper.
         o Pointers to C++ EventListener wrappers are stored in JS objects
           instead of event listener lists.
        https://bugs.webkit.org/show_bug.cgi?id=29825

        * WebCore.gypi: Removed "Object" listeners.
        * bindings/scripts/CodeGeneratorV8.pm: Now handles event accessors.
        * bindings/v8/DOMObjectsInclude.h:

        V8AbstractEventListener manages weak JS handle:
        * bindings/v8/V8AbstractEventListener.cpp:
        (WebCore::weakEventListenerCallback):
        (WebCore::V8AbstractEventListener::V8AbstractEventListener):
        (WebCore::V8AbstractEventListener::~V8AbstractEventListener):
        (WebCore::V8AbstractEventListener::handleEvent):
        (WebCore::V8AbstractEventListener::disposeListenerObject):
        (WebCore::V8AbstractEventListener::setListenerObject):
        * bindings/v8/V8AbstractEventListener.h:
        (WebCore::V8AbstractEventListener::cast):
        (WebCore::V8AbstractEventListener::isLazy):
        (WebCore::V8AbstractEventListener::getListenerObject):
        (WebCore::V8AbstractEventListener::getExistingListenerObject):
        (WebCore::V8AbstractEventListener::hasExistingListenerObject):
        (WebCore::V8AbstractEventListener::disconnectFrame):
        (WebCore::V8AbstractEventListener::disconnected):
        (WebCore::V8AbstractEventListener::prepareListenerObject):
        (WebCore::V8AbstractEventListener::lineNumber):
        (WebCore::V8AbstractEventListener::virtualisAttribute):

        Grouped getEventListener functions:
        * bindings/v8/V8DOMWrapper.cpp:
        (WebCore::V8DOMWrapper::getTemplate):
        (WebCore::V8DOMWrapper::getEventListener):
        * bindings/v8/V8DOMWrapper.h:

        Removed most event listener objects bookkeeping:
        * bindings/v8/V8EventListenerList.cpp:
        * bindings/v8/V8EventListenerList.h:
        (WebCore::V8EventListenerList::findWrapper):
        (WebCore::V8EventListenerList::clearWrapper):
        (WebCore::V8EventListenerList::doFindWrapper):
        (WebCore::V8EventListenerList::getHiddenProperty):
        (WebCore::V8EventListenerList::findOrCreateWrapper):

        Added hidden properties for storing EventListener wrappers:
        * bindings/v8/V8HiddenPropertyName.cpp:
        (WebCore::V8HiddenPropertyName::listener):
        (WebCore::V8HiddenPropertyName::attributeListener):
        * bindings/v8/V8HiddenPropertyName.h:

        * bindings/v8/V8LazyEventListener.cpp:
        (WebCore::V8LazyEventListener::V8LazyEventListener):
        (WebCore::V8LazyEventListener::callListenerFunction):
        (WebCore::V8LazyEventListener::prepareListenerObject):
        * bindings/v8/V8LazyEventListener.h:
        (WebCore::V8LazyEventListener::isLazy):
        * bindings/v8/V8ObjectEventListener.cpp: Removed.
        * bindings/v8/V8ObjectEventListener.h: Removed.
        * bindings/v8/V8Proxy.cpp:
        (WebCore::V8Proxy::disconnectFrame):
        (WebCore::V8Proxy::disconnectEventListeners):
        * bindings/v8/V8Proxy.h:
        * bindings/v8/V8WorkerContextEventListener.cpp:
        (WebCore::V8WorkerContextEventListener::reportError):
        (WebCore::V8WorkerContextEventListener::getReceiverObject):
        * bindings/v8/V8WorkerContextEventListener.h:
        * bindings/v8/V8WorkerContextObjectEventListener.cpp: Removed.
        * bindings/v8/V8WorkerContextObjectEventListener.h: Removed.
        * bindings/v8/WorkerContextExecutionProxy.cpp:
        (WebCore::WorkerContextExecutionProxy::dispose):
        (WebCore::WorkerContextExecutionProxy::initContextIfNeeded):
        (WebCore::WorkerContextExecutionProxy::findOrCreateEventListener):
        * bindings/v8/WorkerContextExecutionProxy.h:
        * bindings/v8/custom/V8AbstractWorkerCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8CustomBinding.h:
        * bindings/v8/custom/V8CustomEventListener.cpp:
        (WebCore::V8EventListener::V8EventListener):
        (WebCore::V8EventListener::getListenerFunction):
        (WebCore::V8EventListener::callListenerFunction):
        * bindings/v8/custom/V8CustomEventListener.h:
        * bindings/v8/custom/V8DOMApplicationCacheCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8DOMWindowCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp:
        * bindings/v8/custom/V8MessagePortCustom.cpp:
        (WebCore::getEventListener):
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8NodeCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8NotificationCenterCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8SVGElementInstanceCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8WebSocketCustom.cpp:
        * bindings/v8/custom/V8WorkerContextCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8WorkerCustom.cpp:
        * bindings/v8/custom/V8XMLHttpRequestConstructor.cpp:
        * bindings/v8/custom/V8XMLHttpRequestCustom.cpp:
        (WebCore::CALLBACK_FUNC_DECL):
        * bindings/v8/custom/V8XMLHttpRequestUploadCustom.cpp:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48978 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5a0d4fe1
2009-10-01 Vitaly Repeshko <vitalyr@chromium.org>
Reviewed by Dimitri Glazkov.
[V8] Refactored V8 event listeners:
(This change should fix http://crbug.com/21079 and
https://bugs.webkit.org/show_bug.cgi?id=29093.)
o All listeners use weak handles to JS objects to avoid creating
cycles and leaking memory.
o "Object" variants of listeners removed.
o All event accessor callbacks are generated.
o Custom event accessors removed.
o All wrappers have hidden dependencies on their listeners to
prevent listeners from being collected.
o All variats of getEventListener function grouped in V8DOMWrapper.
o Pointers to C++ EventListener wrappers are stored in JS objects
instead of event listener lists.
https://bugs.webkit.org/show_bug.cgi?id=29825
* WebCore.gypi: Removed "Object" listeners.
* bindings/scripts/CodeGeneratorV8.pm: Now handles event accessors.
* bindings/v8/DOMObjectsInclude.h:
V8AbstractEventListener manages weak JS handle:
* bindings/v8/V8AbstractEventListener.cpp:
(WebCore::weakEventListenerCallback):
(WebCore::V8AbstractEventListener::V8AbstractEventListener):
(WebCore::V8AbstractEventListener::~V8AbstractEventListener):
(WebCore::V8AbstractEventListener::handleEvent):
(WebCore::V8AbstractEventListener::disposeListenerObject):
(WebCore::V8AbstractEventListener::setListenerObject):
* bindings/v8/V8AbstractEventListener.h:
(WebCore::V8AbstractEventListener::cast):
(WebCore::V8AbstractEventListener::isLazy):
(WebCore::V8AbstractEventListener::getListenerObject):
(WebCore::V8AbstractEventListener::getExistingListenerObject):
(WebCore::V8AbstractEventListener::hasExistingListenerObject):
(WebCore::V8AbstractEventListener::disconnectFrame):
(WebCore::V8AbstractEventListener::disconnected):
(WebCore::V8AbstractEventListener::prepareListenerObject):
(WebCore::V8AbstractEventListener::lineNumber):
(WebCore::V8AbstractEventListener::virtualisAttribute):
Grouped getEventListener functions:
* bindings/v8/V8DOMWrapper.cpp:
(WebCore::V8DOMWrapper::getTemplate):
(WebCore::V8DOMWrapper::getEventListener):
* bindings/v8/V8DOMWrapper.h:
Removed most event listener objects bookkeeping:
* bindings/v8/V8EventListenerList.cpp:
* bindings/v8/V8EventListenerList.h:
(WebCore::V8EventListenerList::findWrapper):
(WebCore::V8EventListenerList::clearWrapper):
(WebCore::V8EventListenerList::doFindWrapper):
(WebCore::V8EventListenerList::getHiddenProperty):
(WebCore::V8EventListenerList::findOrCreateWrapper):
Added hidden properties for storing EventListener wrappers:
* bindings/v8/V8HiddenPropertyName.cpp:
(WebCore::V8HiddenPropertyName::listener):
(WebCore::V8HiddenPropertyName::attributeListener):
* bindings/v8/V8HiddenPropertyName.h:
* bindings/v8/V8LazyEventListener.cpp:
(WebCore::V8LazyEventListener::V8LazyEventListener):
(WebCore::V8LazyEventListener::callListenerFunction):
(WebCore::V8LazyEventListener::prepareListenerObject):
* bindings/v8/V8LazyEventListener.h:
(WebCore::V8LazyEventListener::isLazy):
* bindings/v8/V8ObjectEventListener.cpp: Removed.
* bindings/v8/V8ObjectEventListener.h: Removed.
* bindings/v8/V8Proxy.cpp:
(WebCore::V8Proxy::disconnectFrame):
(WebCore::V8Proxy::disconnectEventListeners):
* bindings/v8/V8Proxy.h:
* bindings/v8/V8WorkerContextEventListener.cpp:
(WebCore::V8WorkerContextEventListener::reportError):
(WebCore::V8WorkerContextEventListener::getReceiverObject):
* bindings/v8/V8WorkerContextEventListener.h:
* bindings/v8/V8WorkerContextObjectEventListener.cpp: Removed.
* bindings/v8/V8WorkerContextObjectEventListener.h: Removed.
* bindings/v8/WorkerContextExecutionProxy.cpp:
(WebCore::WorkerContextExecutionProxy::dispose):
(WebCore::WorkerContextExecutionProxy::initContextIfNeeded):
(WebCore::WorkerContextExecutionProxy::findOrCreateEventListener):
* bindings/v8/WorkerContextExecutionProxy.h:
* bindings/v8/custom/V8AbstractWorkerCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8CustomBinding.h:
* bindings/v8/custom/V8CustomEventListener.cpp:
(WebCore::V8EventListener::V8EventListener):
(WebCore::V8EventListener::getListenerFunction):
(WebCore::V8EventListener::callListenerFunction):
* bindings/v8/custom/V8CustomEventListener.h:
* bindings/v8/custom/V8DOMApplicationCacheCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8DOMWindowCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp:
* bindings/v8/custom/V8MessagePortCustom.cpp:
(WebCore::getEventListener):
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8NodeCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8NotificationCenterCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8SVGElementInstanceCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8WebSocketCustom.cpp:
* bindings/v8/custom/V8WorkerContextCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8WorkerCustom.cpp:
* bindings/v8/custom/V8XMLHttpRequestConstructor.cpp:
* bindings/v8/custom/V8XMLHttpRequestCustom.cpp:
(WebCore::CALLBACK_FUNC_DECL):
* bindings/v8/custom/V8XMLHttpRequestUploadCustom.cpp:
2009-10-01 Alexis Menard <alexis.menard@nokia.com>
Reviewed by Tor Arne Vestbø.
......@@ -802,8 +802,6 @@
'bindings/v8/V8NPUtils.h',
'bindings/v8/V8NodeFilterCondition.cpp',
'bindings/v8/V8NodeFilterCondition.h',
'bindings/v8/V8ObjectEventListener.cpp',
'bindings/v8/V8ObjectEventListener.h',
'bindings/v8/V8Proxy.cpp',
'bindings/v8/V8Proxy.h',
'bindings/v8/V8SVGPODTypeWrapper.h',
......@@ -811,8 +809,6 @@
'bindings/v8/V8Utilities.h',
'bindings/v8/V8WorkerContextEventListener.cpp',
'bindings/v8/V8WorkerContextEventListener.h',
'bindings/v8/V8WorkerContextObjectEventListener.cpp',
'bindings/v8/V8WorkerContextObjectEventListener.h',
'bindings/v8/WorkerContextExecutionProxy.h',
'bindings/v8/WorkerContextExecutionProxy.cpp',
'bindings/v8/WorkerScriptController.h',
......
......@@ -326,10 +326,26 @@ sub IsNodeSubType
return 0;
}
sub RequiresCustomEventListenerAccessors
sub GetHiddenDependencyIndex
{
my $dataNode = shift;
return !IsNodeSubType($dataNode) && $dataNode->name ne "SVGElementInstance";
my $attribute = shift;
my $name = $dataNode->name;
return "V8Custom::kNodeEventListenerCacheIndex" if IsNodeSubType($dataNode);
return "V8Custom::kSVGElementInstanceEventListenerCacheIndex" if $name eq "SVGElementInstance";
return "V8Custom::kAbstractWorkerRequestCacheIndex" if $name eq "AbstractWorker";
return "V8Custom::kWorkerRequestCacheIndex" if $name eq "Worker";
return "V8Custom::kDedicatedWorkerContextRequestCacheIndex" if $name eq "DedicatedWorkerContext";
return "V8Custom::kWorkerContextRequestCacheIndex" if $name eq "WorkerContext";
return "V8Custom::kWorkerContextRequestCacheIndex" if $name eq "SharedWorkerContext";
return "V8Custom::kMessagePortRequestCacheIndex" if $name eq "MessagePort";
return "V8Custom::kWebSocketCacheIndex" if $name eq "WebSocket";
return "V8Custom::kXMLHttpRequestCacheIndex" if $name eq "XMLHttpRequest";
return "V8Custom::kXMLHttpRequestCacheIndex" if $name eq "XMLHttpRequestUpload";
return "V8Custom::kDOMApplicationCacheCacheIndex" if $name eq "DOMApplicationCache";
return "V8Custom::kNotificationRequestCacheIndex" if $name eq "Notification";
return "V8Custom::kDOMWindowEventListenerCacheIndex" if $name eq "DOMWindow";
die "Unexpected name " . $name . " when generating " . $attribute;
}
sub HolderToNative
......@@ -594,6 +610,10 @@ END
}
} else {
if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
push(@implContentDecls, " if (!imp->document())\n");
push(@implContentDecls, " return v8::Undefined();\n");
}
push(@implContentDecls, " $nativeType v = ");
push(@implContentDecls, "$getterString;\n");
......@@ -675,7 +695,7 @@ sub GenerateNormalAttrSetter
# perform lookup first
push(@implContentDecls, <<END);
v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
if (holder.IsEmpty()) return v8::Undefined();
if (holder.IsEmpty()) return;
END
HolderToNative($dataNode, $implClassName, $classIndex);
} else {
......@@ -687,7 +707,11 @@ END
my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
if ($attribute->signature->type eq "EventListener") {
push(@implContentDecls, " $nativeType v = V8DOMWrapper::getEventListener(imp, value, true, false);\n");
if ($dataNode->name eq "DOMWindow") {
push(@implContentDecls, " if (!imp->document())\n");
push(@implContentDecls, " return;\n");
}
push(@implContentDecls, " $nativeType v = V8DOMWrapper::getEventListener(imp, value, true, ListenerFindOrCreate);\n");
} else {
push(@implContentDecls, " $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n");
}
......@@ -725,14 +749,17 @@ END
} elsif ($attribute->signature->type eq "EventListener") {
$implIncludes{"V8AbstractEventListener.h"} = 1;
$implIncludes{"V8CustomBinding.h"} = 1;
$cacheIndex = GetHiddenDependencyIndex($dataNode, $attrName);
push(@implContentDecls, " $nativeType old = imp->$attrName();\n");
push(@implContentDecls, " if (old && static_cast<V8AbstractEventListener*>(old.get())->isObjectListener()) {\n");
push(@implContentDecls, " v8::Local<v8::Object> oldListener = static_cast<V8AbstractEventListener*>(old.get())->getListenerObject();\n");
push(@implContentDecls, " removeHiddenDependency(holder, oldListener, V8Custom::kNodeEventListenerCacheIndex);\n");
push(@implContentDecls, " V8AbstractEventListener* oldListener = old ? V8AbstractEventListener::cast(old.get()) : 0;\n");
push(@implContentDecls, " if (oldListener) {\n");
push(@implContentDecls, " v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();\n");
push(@implContentDecls, " if (!oldListenerObject.IsEmpty())\n");
push(@implContentDecls, " removeHiddenDependency(holder, oldListenerObject, $cacheIndex);\n");
push(@implContentDecls, " }\n");
push(@implContentDecls, " imp->set$implSetterFunctionName($result);\n");
push(@implContentDecls, " if ($result)\n");
push(@implContentDecls, " createHiddenDependency(holder, value, V8Custom::kNodeEventListenerCacheIndex");
push(@implContentDecls, " createHiddenDependency(holder, value, $cacheIndex");
} else {
push(@implContentDecls, " imp->set$implSetterFunctionName(" . $result);
}
......@@ -967,26 +994,6 @@ sub GenerateBatchedAttributeData
$setter = "0";
$propAttr = "v8::ReadOnly";
# EventListeners
} elsif ($attribute->signature->type eq "EventListener" && RequiresCustomEventListenerAccessors($dataNode)) {
if ($interfaceName eq "DOMWindow") {
$getter = "V8Custom::v8DOMWindowEventHandlerAccessorGetter";
$setter = "V8Custom::v8DOMWindowEventHandlerAccessorSetter";
} elsif ($interfaceName eq "DOMApplicationCache") {
$getter = "V8Custom::v8DOMApplicationCacheEventHandlerAccessorGetter";
$setter = "V8Custom::v8DOMApplicationCacheEventHandlerAccessorSetter";
} elsif ($interfaceName eq "Notification") {
$getter = "V8Custom::v8NotificationEventHandlerAccessorGetter";
$setter = "V8Custom::v8NotificationEventHandlerAccessorSetter";
} else {
$getter = "V8Custom::v8${customAccessor}AccessorGetter";
if ($interfaceName eq "WorkerContext" and $attrName eq "self") {
$setter = "0";
$propAttr = "v8::ReadOnly";
} else {
$setter = "V8Custom::v8${customAccessor}AccessorSetter";
}
}
} else {
# Default Getter and Setter
$getter = "${interfaceName}Internal::${attrName}AttrGetter";
......@@ -1100,16 +1107,8 @@ sub GenerateImplementation
next;
}
# Make EventListeners custom for some types.
# FIXME: make the perl code capable of generating the
# event setters/getters. For now, WebKit has started removing the
# [Custom] attribute, so just automatically insert it to avoid forking
# other files. This should be okay because we can't generate stubs
# for any event getter/setters anyway.
if ($attrType eq "EventListener" && RequiresCustomEventListenerAccessors($dataNode)) {
$attribute->signature->extendedAttributes->{"Custom"} = 1;
$implIncludes{"V8CustomBinding.h"} = 1;
next;
if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
$attribute->signature->extendedAttributes->{"v8OnProto"} = 1;
}
# Do not generate accessor if this is a custom attribute. The
......
......@@ -157,7 +157,6 @@
#include "V8HTMLElement.h"
#include "V8LazyEventListener.h"
#include "V8NodeFilterCondition.h"
#include "V8ObjectEventListener.h"
#include "ValidityState.h"
#include "WebKitAnimationEvent.h"
#include "WebKitCSSKeyframeRule.h"
......
......@@ -37,12 +37,20 @@
#include "Frame.h"
#include "Tokenizer.h"
#include "V8Binding.h"
#include "V8EventListenerList.h"
#include "V8Utilities.h"
namespace WebCore {
static void weakEventListenerCallback(v8::Persistent<v8::Value>, void* parameter)
{
V8AbstractEventListener* listener = static_cast<V8AbstractEventListener*>(parameter);
listener->disposeListenerObject();
}
V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isAttribute)
: EventListener(JSEventListenerType)
, m_isWeak(true)
, m_isAttribute(isAttribute)
, m_frame(frame)
, m_lineNumber(0)
......@@ -63,6 +71,70 @@ V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isAttribute)
}
}
V8AbstractEventListener::~V8AbstractEventListener()
{
if (!m_listener.IsEmpty())
V8EventListenerList::clearWrapper(m_listener, m_isAttribute);
disposeListenerObject();
}
void V8AbstractEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
// EventListener could be disconnected from the frame.
if (disconnected())
return;
// The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it.
// See issue 889829.
RefPtr<V8AbstractEventListener> protect(this);
v8::HandleScope handleScope;
if (!m_context)
return;
// Create a new local handle since the persistent handle stored in
// m_context may be disposed before we're done.
v8::Handle<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context->get());
if (v8Context.IsEmpty())
return;
// m_frame can removed by the callback function, protect it until the callback function returns.
RefPtr<Frame> protectFrame(m_frame);
// Enter the V8 context in which to perform the event handling.
v8::Context::Scope scope(v8Context);
// Get the V8 wrapper for the event object.
v8::Handle<v8::Value> jsEvent = V8DOMWrapper::convertEventToV8Object(event);
invokeEventHandler(v8Context, event, jsEvent);
Document::updateStyleForAllDocuments();
}
void V8AbstractEventListener::disposeListenerObject()
{
if (!m_listener.IsEmpty()) {
#ifndef NDEBUG
V8GCController::unregisterGlobalHandle(this, m_listener);
#endif
m_listener.Dispose();
m_listener.Clear();
}
}
void V8AbstractEventListener::setListenerObject(v8::Handle<v8::Object> listener)
{
disposeListenerObject();
m_listener = v8::Persistent<v8::Object>::New(listener);
#ifndef NDEBUG
V8GCController::registerGlobalHandle(EVENT_LISTENER, this, m_listener);
#endif
if (m_isWeak)
m_listener.MakeWeak(this, &weakEventListenerCallback);
}
void V8AbstractEventListener::invokeEventHandler(v8::Handle<v8::Context> v8Context, Event* event, v8::Handle<v8::Value> jsEvent)
{
// We push the event being processed into the global object, so that it can be exposed by DOMWindow's bindings.
......@@ -124,52 +196,6 @@ void V8AbstractEventListener::invokeEventHandler(v8::Handle<v8::Context> v8Conte
event->preventDefault();
}
void V8AbstractEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
// EventListener could be disconnected from the frame.
if (disconnected())
return;
// The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it.
// See issue 889829.
RefPtr<V8AbstractEventListener> protect(this);
v8::HandleScope handleScope;
if (!m_context)
return;
// Create a new local handle since the persistent handle stored in
// m_context may be disposed before we're done.
v8::Handle<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context->get());
if (v8Context.IsEmpty())
return;
// m_frame can removed by the callback function, protect it until the callback function returns.
RefPtr<Frame> protectFrame(m_frame);
// Enter the V8 context in which to perform the event handling.
v8::Context::Scope scope(v8Context);
// Get the V8 wrapper for the event object.
v8::Handle<v8::Value> jsEvent = V8DOMWrapper::convertEventToV8Object(event);
invokeEventHandler(v8Context, event, jsEvent);
Document::updateStyleForAllDocuments();
}
void V8AbstractEventListener::disposeListenerObject()
{
if (!m_listener.IsEmpty()) {
#ifndef NDEBUG
V8GCController::unregisterGlobalHandle(this, m_listener);
#endif
m_listener.Dispose();
m_listener.Clear();
}
}
v8::Local<v8::Object> V8AbstractEventListener::getReceiverObject(Event* event)
{
if (!m_listener.IsEmpty() && !m_listener->IsFunction())
......
......@@ -51,43 +51,84 @@ namespace WebCore {
// but ALLOWs duplicated non-HTML event handlers.
class V8AbstractEventListener : public EventListener {
public:
virtual ~V8AbstractEventListener() { }
virtual ~V8AbstractEventListener();
static const V8AbstractEventListener* cast(const EventListener* listener)
{
return listener->type() == JSEventListenerType
? static_cast<const V8AbstractEventListener*>(listener)
: 0;
}
static V8AbstractEventListener* cast(EventListener* listener)
{
return const_cast<V8AbstractEventListener*>(cast(const_cast<const EventListener*>(listener)));
}
// Implementation of EventListener interface.
virtual bool operator==(const EventListener& other) { return this == &other; }
virtual void handleEvent(ScriptExecutionContext*, Event*);
// Returns the owner frame of the listener.
Frame* frame() { return m_frame; }
virtual void handleEvent(ScriptExecutionContext*, Event*);
void invokeEventHandler(v8::Handle<v8::Context>, Event*, v8::Handle<v8::Value> jsEvent);
virtual bool isLazy() const { return false; }
// Returns the listener object, either a function or an object.
virtual v8::Local<v8::Object> getListenerObject()
v8::Local<v8::Object> getListenerObject()
{
prepareListenerObject();
return v8::Local<v8::Object>::New(m_listener);
}
v8::Local<v8::Object> getExistingListenerObject()
{
return v8::Local<v8::Object>::New(m_listener);
}
bool hasExistingListenerObject()
{
return !m_listener.IsEmpty();
}
// Dispose listener object and clear the handle.
void disposeListenerObject();
virtual bool disconnected() const { return !m_frame; }
// Detach the listener from its owner frame.
void disconnectFrame() { m_frame = 0; }
virtual bool isObjectListener() const { return false; }
virtual bool disconnected() const { return !m_frame; }
protected:
v8::Persistent<v8::Object> m_listener;
V8AbstractEventListener(Frame*, bool isAttribute);
// Indicates if this is an HTML type listener.
bool m_isAttribute;
virtual void prepareListenerObject() { }
private:
V8AbstractEventListener(Frame*, bool isInline);
void setListenerObject(v8::Handle<v8::Object> listener);
virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsevent, Event*) = 0;
void invokeEventHandler(v8::Handle<v8::Context>, Event*, v8::Handle<v8::Value> jsEvent);
// Get the receiver object to use for event listener call.
v8::Local<v8::Object> getReceiverObject(Event*);
int lineNumber() const { return m_lineNumber; }
private:
// Implementation of EventListener function.
virtual bool virtualisAttribute() const { return m_isAttribute; }
virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsevent, Event*) = 0;
v8::Persistent<v8::Object> m_listener;
// Indicates if the above handle is weak.
bool m_isWeak;
// Indicates if this is an HTML type listener.
bool m_isAttribute;
// Frame to which the event listener is attached to. An event listener must be destroyed before its owner frame is
// deleted. See fast/dom/replaceChild.html
// FIXME: this could hold m_frame live until the event listener is deleted.
......@@ -97,10 +138,6 @@ namespace WebCore {
// Position in the HTML source for HTML event listeners.
int m_lineNumber;
int m_columnNumber;
friend class V8EventListener;
friend class V8ObjectEventListener;
friend class V8LazyEventListener;
};
} // namespace WebCore
......
......@@ -36,18 +36,19 @@
#include "DOMObjectsInclude.h"
#include "DocumentLoader.h"
#include "FrameLoaderClient.h"
#include "Notification.h"
#include "SVGElementInstance.h"
#include "ScriptController.h"
#include "V8AbstractEventListener.h"
#include "V8Binding.h"
#include "V8Collection.h"
#include "V8CustomBinding.h"
#include "V8CustomEventListener.h"
#include "V8DOMMap.h"
#include "V8DOMWindow.h"
#include "V8EventListenerList.h"
#include "V8Index.h"
#include "V8IsolatedWorld.h"
#include "V8ObjectEventListener.h"
#include "V8Proxy.h"
#include "WorkerContextExecutionProxy.h"
......@@ -393,6 +394,15 @@ v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8W
}
#endif // NOTIFICATIONS
#if ENABLE(SVG)
case V8ClassIndex::SVGELEMENTINSTANCE: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kSVGElementInstanceInternalFieldCount);
break;
}
#endif
#if ENABLE(WORKERS)
case V8ClassIndex::ABSTRACTWORKER: {
// Reserve one more internal field for keeping event listeners.
......@@ -1375,7 +1385,7 @@ v8::Handle<v8::Value> V8DOMWrapper::convertEventListenerToV8Object(EventListener
return v8listener->getListenerObject();
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, bool findOnly)
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
ScriptExecutionContext* context = node->scriptExecutionContext();
if (!context)
......@@ -1387,19 +1397,85 @@ PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v
if (!proxy)
proxy = V8Proxy::retrieve(V8Proxy::retrieveFrameForEnteredContext());
if (proxy) {
V8EventListenerList* list = proxy->objectListeners();
return findOnly ? list->findWrapper(value, isAttribute) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, isAttribute);
if (proxy)
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), value, isAttribute);
return 0;
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
return getEventListener(element->correspondingElement(), value, isAttribute, lookup);
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
if (worker->scriptExecutionContext()->isWorkerContext()) {
WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
ASSERT(workerContextProxy);
return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
}
V8Proxy* proxy = V8Proxy::retrieve(worker->scriptExecutionContext());
if (proxy)
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), value, isAttribute);
return 0;
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, bool findOnly)
#if ENABLE(NOTIFICATIONS)
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{