[EFL][WK2] Add API to execute js script
authorryuan.choi@samsung.com <ryuan.choi@samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Jan 2014 01:07:05 +0000 (01:07 +0000)
committerryuan.choi@samsung.com <ryuan.choi@samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Jan 2014 01:07:05 +0000 (01:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=101904

Reviewed by Gyuyoung Kim.

Add ewk_view_script_execute() which provides a way to execute user
script.

* UIProcess/API/efl/ewk_context.cpp:
Added JS Global Contexta which is required to deserialize to the script
value from the callback.
(EwkContext::EwkContext):
(EwkContext::~EwkContext):
(EwkContext::jsGlobalContext):
* UIProcess/API/efl/ewk_context_private.h:
* UIProcess/API/efl/ewk_view.cpp:
(Ewk_View_Script_Execute_Callback_Context::Ewk_View_Script_Execute_Callback_Context):
(runJavaScriptCallback):
(ewk_view_script_execute):
* UIProcess/API/efl/ewk_view.h:
* UIProcess/API/efl/tests/test_ewk2_view.cpp:
Added unit test for ewk_view_script_execute.
(scriptExecuteCallback):
(TEST_F):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@161527 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/efl/ewk_context.cpp
Source/WebKit2/UIProcess/API/efl/ewk_context_private.h
Source/WebKit2/UIProcess/API/efl/ewk_view.cpp
Source/WebKit2/UIProcess/API/efl/ewk_view.h
Source/WebKit2/UIProcess/API/efl/tests/test_ewk2_view.cpp

index c5c92fe..f4ebb5a 100644 (file)
@@ -1,3 +1,30 @@
+2014-01-08  Ryuan Choi  <ryuan.choi@samsung.com>
+
+        [EFL][WK2] Add API to execute js script
+        https://bugs.webkit.org/show_bug.cgi?id=101904
+
+        Reviewed by Gyuyoung Kim.
+
+        Add ewk_view_script_execute() which provides a way to execute user
+        script.
+
+        * UIProcess/API/efl/ewk_context.cpp:
+        Added JS Global Contexta which is required to deserialize to the script
+        value from the callback.
+        (EwkContext::EwkContext):
+        (EwkContext::~EwkContext):
+        (EwkContext::jsGlobalContext):
+        * UIProcess/API/efl/ewk_context_private.h:
+        * UIProcess/API/efl/ewk_view.cpp:
+        (Ewk_View_Script_Execute_Callback_Context::Ewk_View_Script_Execute_Callback_Context):
+        (runJavaScriptCallback):
+        (ewk_view_script_execute):
+        * UIProcess/API/efl/ewk_view.h:
+        * UIProcess/API/efl/tests/test_ewk2_view.cpp:
+        Added unit test for ewk_view_script_execute.
+        (scriptExecuteCallback):
+        (TEST_F):
+
 2014-01-08  Gyuyoung Kim  <gyuyoung.kim@samsung.com>
 
         [EFL] Move efl API test binaries to TestWebKitAPI/EWebKit|EWebKit2
index f4da1ea..d8e48d9 100644 (file)
@@ -39,6 +39,7 @@
 #include "ewk_private.h"
 #include "ewk_storage_manager_private.h"
 #include "ewk_url_scheme_request_private.h"
+#include <JavaScriptCore/JSContextRef.h>
 #include <WebCore/FileSystem.h>
 #include <WebCore/IconDatabase.h>
 #include <wtf/HashMap.h>
@@ -72,6 +73,7 @@ EwkContext::EwkContext(WKContextRef context)
     , m_downloadManager(std::make_unique<DownloadManagerEfl>(context))
     , m_requestManagerClient(std::make_unique<RequestManagerClientEfl>(context))
     , m_historyClient(std::make_unique<ContextHistoryClientEfl>(context))
+    , m_jsGlobalContext(nullptr)
 {
     ContextMap::AddResult result = contextMap().add(context, this);
     ASSERT_UNUSED(result, result.isNewEntry);
@@ -96,6 +98,10 @@ EwkContext::EwkContext(WKContextRef context)
 EwkContext::~EwkContext()
 {
     ASSERT(contextMap().get(m_context.get()) == this);
+
+    if (m_jsGlobalContext)
+        JSGlobalContextRelease(m_jsGlobalContext);
+
     contextMap().remove(m_context.get());
 }
 
@@ -214,6 +220,15 @@ void EwkContext::clearResourceCache()
     WKResourceCacheManagerClearCacheForAllOrigins(WKContextGetResourceCacheManager(m_context.get()), WKResourceCachesToClearAll);
 }
 
+
+JSGlobalContextRef EwkContext::jsGlobalContext()
+{
+    if (!m_jsGlobalContext)
+        m_jsGlobalContext = JSGlobalContextCreate(0);
+
+    return m_jsGlobalContext;
+}
+
 Ewk_Cookie_Manager* ewk_context_cookie_manager_get(const Ewk_Context* ewkContext)
 {
     EWK_OBJ_GET_IMPL_OR_RETURN(const EwkContext, ewkContext, impl, 0);
index 525d859..e2023d1 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "ewk_context.h"
 #include "ewk_object_private.h"
+#include <JavaScriptCore/JSContextRef.h>
 #include <WebKit2/WKBase.h>
 #include <WebKit2/WKRetainPtr.h>
 #include <wtf/RefPtr.h>
@@ -85,6 +86,8 @@ public:
 
     void clearResourceCache();
 
+    JSGlobalContextRef jsGlobalContext();
+
 private:
     explicit EwkContext(WKContextRef);
 
@@ -106,6 +109,8 @@ private:
     std::unique_ptr<WebKit::RequestManagerClientEfl> m_requestManagerClient;
 
     std::unique_ptr<WebKit::ContextHistoryClientEfl> m_historyClient;
+
+    JSGlobalContextRef m_jsGlobalContext;
 };
 
 #endif // ewk_context_private_h
index 1b09a1a..63bafca 100644 (file)
@@ -40,6 +40,7 @@
 #include "ewk_private.h"
 #include "ewk_settings_private.h"
 #include <Ecore_Evas.h>
+#include <JavaScriptCore/JSRetainPtr.h>
 #include <WebKit2/WKAPICast.h>
 #include <WebKit2/WKData.h>
 #include <WebKit2/WKEinaSharedString.h>
@@ -47,6 +48,7 @@
 #include <WebKit2/WKInspector.h>
 #include <WebKit2/WKPageGroup.h>
 #include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WKSerializedScriptValue.h>
 #include <WebKit2/WKString.h>
 #include <WebKit2/WKURL.h>
 #include <WebKit2/WKView.h>
@@ -625,3 +627,51 @@ Eina_Bool ewk_view_source_mode_get(const Evas_Object* ewkView)
 
     return WKViewGetShowsAsSource(impl->wkView());
 }
+
+struct Ewk_View_Script_Execute_Callback_Context {
+    Ewk_View_Script_Execute_Callback_Context(Ewk_View_Script_Execute_Cb callback, Evas_Object* ewkView, void* userData)
+        : m_callback(callback)
+        , m_view(ewkView)
+        , m_userData(userData)
+    {
+    }
+
+    Ewk_View_Script_Execute_Cb m_callback;
+    Evas_Object* m_view;
+    void* m_userData;
+};
+
+static void runJavaScriptCallback(WKSerializedScriptValueRef scriptValue, WKErrorRef, void* context)
+{
+    ASSERT(context);
+
+    auto callbackContext = std::unique_ptr<Ewk_View_Script_Execute_Callback_Context>(static_cast<Ewk_View_Script_Execute_Callback_Context*>(context));
+    ASSERT(callbackContext->m_view);
+
+    if (!callbackContext->m_callback)
+        return;
+
+    if (scriptValue) {
+        EWK_VIEW_IMPL_GET_OR_RETURN(callbackContext->m_view, impl);
+        JSGlobalContextRef jsGlobalContext = impl->ewkContext()->jsGlobalContext();
+
+        JSValueRef value = WKSerializedScriptValueDeserialize(scriptValue, jsGlobalContext, 0);
+        JSRetainPtr<JSStringRef> jsStringValue(Adopt, JSValueToStringCopy(jsGlobalContext, value, 0));
+        size_t length = JSStringGetMaximumUTF8CStringSize(jsStringValue.get());
+        auto buffer = std::make_unique<char[]>(length);
+        JSStringGetUTF8CString(jsStringValue.get(), buffer.get(), length);
+        callbackContext->m_callback(callbackContext->m_view, buffer.get(), callbackContext->m_userData);
+    } else
+        callbackContext->m_callback(callbackContext->m_view, 0, callbackContext->m_userData);
+}
+
+Eina_Bool ewk_view_script_execute(Evas_Object* ewkView, const char* script, Ewk_View_Script_Execute_Cb callback, void* userData)
+{
+    EWK_VIEW_IMPL_GET_OR_RETURN(ewkView, impl, false);
+    EINA_SAFETY_ON_NULL_RETURN_VAL(script, false);
+
+    Ewk_View_Script_Execute_Callback_Context* context = new Ewk_View_Script_Execute_Callback_Context(callback, ewkView, userData);
+    WKRetainPtr<WKStringRef> scriptString(AdoptWK, WKStringCreateWithUTF8CString(script));
+    WKPageRunJavaScriptInMainFrame(impl->wkPage(), scriptString.get(), context, runJavaScriptCallback);
+    return true;
+}
index 244e437..bb9665f 100644 (file)
@@ -279,6 +279,12 @@ typedef enum {
 } Ewk_Pagination_Mode;
 
 /**
+ * @typedef Ewk_View_Script_Execute_Cb Ewk_View_Script_Execute_Cb
+ * @brief Callback type for use with ewk_view_script_execute()
+ */
+typedef void (*Ewk_View_Script_Execute_Cb)(Evas_Object *o, const char *return_value, void *user_data);
+
+/**
  * Creates a type name for the callback function used to get the page contents.
  *
  * @param type type of the contents
@@ -884,6 +890,20 @@ EAPI Eina_Bool ewk_view_source_mode_set(Evas_Object *o, Eina_Bool enabled);
  */
 EAPI Eina_Bool ewk_view_source_mode_get(const Evas_Object *o);
 
+/**
+ * Requests execution of the given script.
+ *
+ * The result value for the execution can be retrieved from the asynchronous callback.
+ *
+ * @param o The view to execute script
+ * @param script JavaScript to execute
+ * @param callback The function to call when the execution is completed, may be @c NULL
+ * @param user_data User data, may be @c NULL
+ *
+ * @return @c EINA_TRUE on success or @c EINA_FALSE on failure
+ */
+EAPI Eina_Bool ewk_view_script_execute(Evas_Object *o, const char *script, Ewk_View_Script_Execute_Cb callback, void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
index fef31f0..9fc14cb 100644 (file)
@@ -30,6 +30,7 @@ extern EWK2UnitTestEnvironment* environment;
 
 static bool fullScreenCallbackCalled;
 static bool obtainedPageContents = false;
+static bool scriptExecuteCallbackCalled;
 
 static struct {
     const char* expectedMessage;
@@ -1033,3 +1034,52 @@ TEST_F(EWK2ViewTest, ewk_view_user_agent)
     ASSERT_STREQ(defaultUserAgent, ewk_view_user_agent_get(webView()));
     eina_stringshare_del(defaultUserAgent);
 }
+
+static void scriptExecuteCallback(Evas_Object*, const char* returnValue, void* userData)
+{
+    Eina_Strbuf* buffer = static_cast<Eina_Strbuf*>(userData);
+    eina_strbuf_reset(buffer);
+
+    if (returnValue)
+        eina_strbuf_append(buffer, returnValue);
+
+    scriptExecuteCallbackCalled = true;
+}
+
+TEST_F(EWK2UnitTestBase, ewk_view_script_execute)
+{
+    const char scriptExecuteHTML[] =
+        "<!DOCTYPE html>"
+        "<body>"
+        "<p id=\"TestContent\">test content</p>"
+        "</body>";
+
+    ewk_view_html_string_load(webView(), scriptExecuteHTML, 0, 0);
+    ASSERT_TRUE(waitUntilLoadFinished());
+
+    Eina_Strbuf* result = eina_strbuf_new();
+
+    // 1. Get the innerHTML for "TestContent"
+    const char getDataScript[] = "document.getElementById('TestContent').innerHTML";
+
+    scriptExecuteCallbackCalled = false;
+    ASSERT_TRUE(ewk_view_script_execute(webView(), getDataScript, scriptExecuteCallback, static_cast<void*>(result)));
+    waitUntilTrue(scriptExecuteCallbackCalled);
+    ASSERT_STREQ("test content", eina_strbuf_string_get(result));
+
+    // 2. Change the innerHTML for "TestContent"
+    const char changeDataScript[] =
+    "document.getElementById('TestContent').innerHTML = \"test\";";
+    ASSERT_TRUE(ewk_view_script_execute(webView(), changeDataScript, 0, 0));
+
+    // 3. Check the change of the innerHTML.
+    eina_strbuf_reset(result);
+    scriptExecuteCallbackCalled = false;
+    ASSERT_TRUE(ewk_view_script_execute(webView(), getDataScript, scriptExecuteCallback, static_cast<void*>(result)));
+    waitUntilTrue(scriptExecuteCallbackCalled);
+    ASSERT_STREQ("test", eina_strbuf_string_get(result));
+
+    eina_strbuf_free(result);
+
+    ASSERT_FALSE(ewk_view_script_execute(webView(), 0, 0, 0));
+}