AddEventListener fix
authorLukasz Marek <l.marek@samsung.com>
Tue, 26 Mar 2013 13:38:51 +0000 (14:38 +0100)
committerTaejeong Lee <taejeong.lee@samsung.com>
Sat, 30 Mar 2013 11:50:47 +0000 (20:50 +0900)
[Issue#] N/A
[Problem] AddEventListener operates only static context object
[Cause] N/A
[Solution] Context is stored on Listener info and used when needed
[SCMRequest] N/A
[Verification]
Requires commit http://slp-info.sec.samsung.net/gerrit/#/c/172220/
Install widget ./manual_tests/wrt_test_widgets/iframes/iframe3/iframe3.wgt
1. Run widget
2. Click "Open page"
3. Click "Close"
4. Click "Click" inside popup
5. No crash occurs, another page is loaded

Change-Id: I144dd1781f90bd81d0676d4d054e4bb43df87f28

src/js-overlay/js_overlay_addEventListener.cpp
src/js-overlay/js_overlay_addEventListener.h
src/js-overlay/js_overlay_support.cpp
src/plugin-loading/explorer.cpp

index 1caf179..8cb6801 100644 (file)
@@ -32,6 +32,7 @@
 
 namespace WrtPlugins {
 namespace W3C {
+
 const std::string storageEventName = "storage";
 const std::string appServiceEventName = "appservice";
 const std::string softKeyboardChangeEventName = "softkeyboardchange";
@@ -40,42 +41,21 @@ AddEventListenerSupport::IFramesListeners
 AddEventListenerSupport::m_listeners =
     AddEventListenerSupport::IFramesListeners();
 
-JSContextRef AddEventListenerSupport::m_context = NULL;
-
-void AddEventListenerSupport::initialize(JSContextRef context)
-{
-    if (!m_context) {
-        m_context = context;
-    }
-}
-
-void AddEventListenerSupport::deinitialize()
-{
-    if (!m_context) {
-        LogDebug("Not yet initialized");
-    }
-
-    m_listeners.clear();
-    m_context = NULL;
-}
-
-bool AddEventListenerSupport::isInitialized()
-{
-    return m_context != NULL;
-}
-
-JSValueRef AddEventListenerSupport::
-    AddEventListener(JSContextRef context,
-                     JSObjectRef object,
-                     JSObjectRef thisObject,
-                     size_t argumentCount,
-                     const JSValueRef arguments[],
-                     JSValueRef* /*exception*/)
+JSValueRef AddEventListenerSupport::AddEventListener(
+        JSContextRef context,
+        JSObjectRef object,
+        JSObjectRef thisObject,
+        size_t argumentCount,
+        const JSValueRef arguments[],
+        JSValueRef* /*exception*/)
 {
     LogDebug("Add event listener invoked");
     LogDebug("This(iframe?):" << thisObject);
     LogDebug("object:" << object);
 
+    JSContextRef global_context = JSContextGetGlobalContext(context);
+    LogDebug("context:" << context << "(global:" << global_context << ")");
+
     if (argumentCount < 2 || !JSValueIsString(context, arguments[0])) {
         LogError("Wrong arguments");
         return JSValueMakeUndefined(context);
@@ -93,20 +73,18 @@ JSValueRef AddEventListenerSupport::
         return JSValueMakeUndefined(context);
     }
 
-    JSValueProtect(m_context, arguments[1]);
-    JSObjectRef objectCb =
-        JSValueToObject(m_context,
-                        arguments[1],
-                        NULL);
-    if (!JSObjectIsFunction(m_context, objectCb)) {
+    JSObjectRef objectCb = JSValueToObject(context, arguments[1], NULL);
+    if (!JSObjectIsFunction(context, objectCb)) {
         LogError("JS object is not a function");
         return JSValueMakeUndefined(context);
     }
+    JSValueProtect(global_context, arguments[1]);
     //add object to Listeners
     //set event information according to each event type
     CallbackData data;
     data.object = objectCb;
     data.thisObject = thisObject;
+    data.context = global_context;
 
     if (eventName == storageEventName) {
         data.eventType = StorageCustomEvent;
@@ -121,13 +99,27 @@ JSValueRef AddEventListenerSupport::
     return JSValueMakeUndefined(context);
 }
 
-void AddEventListenerSupport::
-    CallStorageListenersFromDifferentIFrames(
-    JSObjectRef iframe,
-    const WrtDeviceApis::StorageEvent::Api::IStorageEventPtr& event)
+void AddEventListenerSupport::RemoveIFrame(JSObjectPtr iframe)
+{
+    auto it = m_listeners.find(iframe->getObject());
+    if (it == m_listeners.end()) {
+        LogWarning("Iframe not registered");
+        return;
+    }
+
+    FOREACH(listener, *it->second)
+    {
+        JSValueUnprotect(listener->context, listener->object);
+    }
+    m_listeners.erase(it);
+    LogDebug("Iframe removed from add event listener object");
+}
+
+void AddEventListenerSupport::CallStorageListenersFromDifferentIFrames(
+        JSObjectRef iframe,
+        const WrtDeviceApis::StorageEvent::Api::IStorageEventPtr& event)
 {
     LogDebug("Invoked callbacks");
-    LogInfo("Context: " << m_context);
 
     FOREACH(it, m_listeners)
     {
@@ -135,44 +127,42 @@ void AddEventListenerSupport::
             continue;
         }
 
-        auto eventPriv = new JSStorageEventPrivateObject(m_context,
-                                                         event);
-
-        JSObjectRef eventObject =
-            JSObjectMake(m_context, JSStorageEvent::getClassRef(), eventPriv);
-        const size_t argc = 1;
-        JSValueRef argv[argc] = { eventObject };
-
-        JSValueProtect(m_context, eventObject);
-
         FOREACH(listener, *it->second)
         {
             LogDebug("Call");
 
-            if (listener->eventType ==
-                StorageCustomEvent)
+            auto eventPriv =
+                new JSStorageEventPrivateObject(listener->context, event);
+
+            JSObjectRef eventObject =
+                JSObjectMake(listener->context, JSStorageEvent::getClassRef(), eventPriv);
+            const size_t argc = 1;
+            JSValueRef argv[argc] = { eventObject };
+
+            JSValueProtect(listener->context, eventObject);
+
+            if (listener->eventType == StorageCustomEvent)
             {
                 JSObjectCallAsFunction(
-                    m_context,
+                    listener->context,
                     listener->object,
                     NULL,
                     argc,
                     argv,
                     NULL);
             }
-        }
 
-        JSValueUnprotect(m_context, eventObject);
+            JSValueUnprotect(listener->context, eventObject);
+        }
     }
 
     LogDebug("Done");
 }
 
-void AddEventListenerSupport::
-    CallCustomEventListenersFromIFrame(
-    JSObjectRef iframe,
-    CustomEventType eventType,
-    JSObjectRef eventObject)
+void AddEventListenerSupport::CallCustomEventListenersFromIFrame(
+        JSObjectRef iframe,
+        CustomEventType eventType,
+        JSObjectRef eventObject)
 {
     LogDebug("Invoked callbacks");
 
@@ -185,13 +175,12 @@ void AddEventListenerSupport::
     const size_t argc = 1;
     JSValueRef argv[argc] = { eventObject };
 
-    JSValueProtect(m_context, eventObject);
     FOREACH(listener, *it->second)
     {
         if (listener->eventType == eventType) {
             LogDebug("Call");
             JSObjectCallAsFunction(
-                m_context,
+                listener->context,
                 listener->object,
                 iframe,
                 argc,
@@ -199,7 +188,6 @@ void AddEventListenerSupport::
                 NULL);
         }
     }
-    JSValueUnprotect(m_context, eventObject);
     LogDebug("Done");
 }
 
index bfbd0b0..0a9717e 100644 (file)
 #include <list>
 #include <memory>
 #include <JavaScriptCore/JavaScript.h>
+#include <JavaScriptCore/JSContextRef.h>
 #include <StorageEvent/IStorageEvent.h>
 #include <TizenServiceEvent/ITizenServiceEvent.h>
 #include <js_overlay_types.h>
+#include <JSObject.h>
+
+// import temporarily from JSContextRefPrivate.h
+extern "C" JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx);
 
 namespace WrtPlugins {
 namespace W3C {
 class AddEventListenerSupport
 {
   public:
-    static void initialize(JSContextRef context);
-    static void deinitialize();
-
-    static bool isInitialized();
-
     static JSValueRef AddEventListener(JSContextRef context,
                                        JSObjectRef object,
                                        JSObjectRef thisObject,
@@ -50,6 +50,8 @@ class AddEventListenerSupport
                                        const JSValueRef arguments[],
                                        JSValueRef* exception);
 
+    static void RemoveIFrame(JSObjectPtr iframe);
+
     static void CallStorageListenersFromDifferentIFrames(
         JSObjectRef iframe,
         const WrtDeviceApis::StorageEvent::Api::IStorageEventPtr& event);
@@ -65,6 +67,7 @@ class AddEventListenerSupport
         CustomEventType eventType;
         JSObjectRef object;
         JSObjectRef thisObject;
+        JSContextRef context;
     };
 
     typedef std::list<CallbackData> Listeners;
@@ -73,7 +76,6 @@ class AddEventListenerSupport
     //first-iframe, 2nd - listeners list
     typedef std::map<JSObjectRef, ListenersPtr> IFramesListeners;
 
-    static JSContextRef m_context;
     static IFramesListeners m_listeners;
 
   private:
index 9bd809e..cad75a5 100644 (file)
@@ -158,7 +158,7 @@ JSValueRef JSFunctionDispatcher::callAsFunction(
     if (priv->overlayFunction->getObject()) {
         LogDebug("Overlayed function will be invoked...");
         result = JSObjectCallAsFunction(
-                context,
+                priv->context,
                 static_cast<JSObjectRef>(
                     priv->overlayFunction->getObject()),
                 thisObject,
index fc69a28..3a76b3a 100644 (file)
@@ -63,21 +63,10 @@ Explorer::Explorer(JSGlobalContextRef context) :
     m_iframeSupport.registerIframe(m_globalObject);
 
     m_propertySupport.reset(new WindowPropertySupport(m_context));
-
-    // initialization for use of custom event
-    if (!AddEventListenerSupport::isInitialized()) {
-        LogInfo("initialization for use of custom event");
-        AddEventListenerSupport::initialize(context);
-    }
 }
 
 Explorer::~Explorer()
 {
-    // deinitialization for use of custom event
-    if (AddEventListenerSupport::isInitialized()) {
-        LogInfo("deinitialization for use of custom event");
-        AddEventListenerSupport::deinitialize();
-    }
 }
 
 JSObjectPtr Explorer::getJSObjectProperty(const std::string& propertyName,
@@ -353,6 +342,7 @@ void Explorer::unloadFrame(JSGlobalContextRef context)
     JSObjectPtr frameObject =
         JavaScriptInterfaceSingleton::Instance().getGlobalObject(context);
 
+    AddEventListenerSupport::RemoveIFrame(frameObject);
     m_iframeSupport.unregisterIframe(frameObject);
 }