Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Ufimtsev2017-01-24 17:23:26 +0000
committerAlexander Kurtakov2017-02-07 07:18:01 +0000
commit9b9501b0fef312da72586299e22d329f00ac5e20 (patch)
tree2a399c24a5820a37dc1aa420dfe1db0f1ba62146
parenta647bf412269ed1dee039baacd08a7c5472595bb (diff)
downloadeclipse.platform.swt-9b9501b0fef312da72586299e22d329f00ac5e20.tar.gz
eclipse.platform.swt-9b9501b0fef312da72586299e22d329f00ac5e20.tar.xz
eclipse.platform.swt-9b9501b0fef312da72586299e22d329f00ac5e20.zip
Bug 508217 Implement webkit2 support for browser function
(Part 1: JavaScript to call Java) This implements Browser.function() on webkit2. Current implementation allows javascript to reach java, but java doesn't provide a return vaulue in the callback. For detailed architecture changes, see: Webkit2JavaCallback() inside WebKit.java. In short, in webkit1 an 'external' object was registered and callJava was a property of this object. In webkit2, 'external' object is no longer used and instead a callback/signal is registered/connected. With this patch, the following jUnits pass: test_BrowserFunction_callback test_BrowserFunction_callback_with_integer test_BrowserFunction_callback_with_boolean test_BrowserFunction_callback_with_String test_BrowserFunction_callback_with_multipleValues testBrowser4. The following does not: test_BrowserFunction_callback_with_javaReturningInt Patch set 4: - I noticed that after a page re-load, webkit2 custom functions did not work. This is because the page-reload mechanism has changed (Bg:510972) but in the ported webkit2 mechanism functions were not re-registered). - Added code to re-register custom functions after page reload. Patch set 7: - Removed 'protected' modifier. - Moved comments around. Change-Id: I94549ed306e0095c735d18389b55a36923c5ec08 Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java21
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c106
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c7
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h7
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java342
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java67
-rw-r--r--tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java78
7 files changed, 540 insertions, 88 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java
index 5f79e68379..df7f31745e 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java
@@ -346,8 +346,10 @@ public void createFunction (BrowserFunction function) {
functionBuffer.append (ERROR_ID.length ());
functionBuffer.append (")); throw error;} return result;};"); //$NON-NLS-1$
- StringBuffer buffer = new StringBuffer ("if (!window.callJava) {window.callJava = function callJava(index, token, args) {"); //$NON-NLS-1$
- buffer.append ("return external.callJava(index,token,args);}};"); //$NON-NLS-1$
+ String javaCallDeclaration = getJavaCallDeclaration();
+
+ StringBuffer buffer = new StringBuffer (); //$NON-NLS-1$
+ buffer.append (javaCallDeclaration); //$NON-NLS-1$
if (function.top) {
buffer.append (functionBuffer.toString ());
}
@@ -375,6 +377,18 @@ public void createFunction (BrowserFunction function) {
execute (function.functionString);
}
+/**
+ * Designed to be overriden.
+ * @return javaScrit code that defines the 'callJava' syntax for javascript.
+ */
+String getJavaCallDeclaration() {
+ return "if (!window.callJava) {\n"
+ + " window.callJava = function callJava(index, token, args) {\n"
+ + " return external.callJava(index,token,args);\n"
+ + " }\n"
+ + "};\n";
+}
+
void deregisterFunction (BrowserFunction function) {
functions.remove (function.index);
}
@@ -396,6 +410,9 @@ public Object evaluate (String script, boolean trusted) throws SWTException {
}
public Object evaluate (String script) throws SWTException {
+ // Developer note:
+ // Webkit1 & Mozilla use this mechanism.
+ // Webkit2 uses a different mechanism. See WebKit:evaluate();
BrowserFunction function = new EvaluateFunction (browser, ""); // $NON-NLS-1$
int index = getNextFunctionIndex ();
function.index = index;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c
index 0d724f982a..694ed05d08 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2016 IBM Corporation and others. All rights reserved.
+ * Copyright (c) 2009, 2017 IBM Corporation and others. All rights reserved.
* The contents of this file are made available under the terms
* of the GNU Lesser General Public License (LGPL) Version 2.1 that
* accompanies this distribution (lgpl-v21.txt). The LGPL is also
@@ -1754,6 +1754,46 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1hit_1test_1result_1get_1li
}
#endif
+#ifndef NO__1webkit_1javascript_1result_1get_1global_1context
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1javascript_1result_1get_1global_1context)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jintLong rc = 0;
+ WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1javascript_1result_1get_1global_1context_FUNC);
+/*
+ rc = (jintLong)webkit_javascript_result_get_global_context((gpointer)arg0);
+*/
+ {
+ WebKitGTK_LOAD_FUNCTION(fp, webkit_javascript_result_get_global_context)
+ if (fp) {
+ rc = (jintLong)((jintLong (CALLING_CONVENTION*)(gpointer))fp)((gpointer)arg0);
+ }
+ }
+ WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1javascript_1result_1get_1global_1context_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1webkit_1javascript_1result_1get_1value
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1javascript_1result_1get_1value)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jintLong rc = 0;
+ WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1javascript_1result_1get_1value_FUNC);
+/*
+ rc = (jintLong)webkit_javascript_result_get_value((gpointer)arg0);
+*/
+ {
+ WebKitGTK_LOAD_FUNCTION(fp, webkit_javascript_result_get_value)
+ if (fp) {
+ rc = (jintLong)((jintLong (CALLING_CONVENTION*)(gpointer))fp)((gpointer)arg0);
+ }
+ }
+ WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1javascript_1result_1get_1value_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1webkit_1javascript_1result_1unref
JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1webkit_1javascript_1result_1unref)
(JNIEnv *env, jclass that, jintLong arg0)
@@ -2096,6 +2136,50 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1uri_1response_1get_1mime_1
}
#endif
+#ifndef NO__1webkit_1user_1content_1manager_1new
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1user_1content_1manager_1new)
+ (JNIEnv *env, jclass that)
+{
+ jintLong rc = 0;
+ WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1user_1content_1manager_1new_FUNC);
+/*
+ rc = (jintLong)webkit_user_content_manager_new();
+*/
+ {
+ WebKitGTK_LOAD_FUNCTION(fp, webkit_user_content_manager_new)
+ if (fp) {
+ rc = (jintLong)((jintLong (CALLING_CONVENTION*)())fp)();
+ }
+ }
+ WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1user_1content_1manager_1new_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1webkit_1user_1content_1manager_1register_1script_1message_1handler
+JNIEXPORT jboolean JNICALL WebKitGTK_NATIVE(_1webkit_1user_1content_1manager_1register_1script_1message_1handler)
+ (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1)
+{
+ jbyte *lparg1=NULL;
+ jboolean rc = 0;
+ WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1user_1content_1manager_1register_1script_1message_1handler_FUNC);
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+/*
+ rc = (jboolean)webkit_user_content_manager_register_script_message_handler(arg0, lparg1);
+*/
+ {
+ WebKitGTK_LOAD_FUNCTION(fp, webkit_user_content_manager_register_script_message_handler)
+ if (fp) {
+ rc = (jboolean)((jboolean (CALLING_CONVENTION*)(jintLong, jbyte *))fp)(arg0, lparg1);
+ }
+ }
+fail:
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
+ WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1user_1content_1manager_1register_1script_1message_1handler_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1webkit_1web_1context_1get_1default
JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1context_1get_1default)
(JNIEnv *env, jclass that)
@@ -2806,6 +2890,26 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1new)
}
#endif
+#ifndef NO__1webkit_1web_1view_1new_1with_1user_1content_1manager
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1new_1with_1user_1content_1manager)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jintLong rc = 0;
+ WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1view_1new_1with_1user_1content_1manager_FUNC);
+/*
+ rc = (jintLong)webkit_web_view_new_with_user_content_manager(arg0);
+*/
+ {
+ WebKitGTK_LOAD_FUNCTION(fp, webkit_web_view_new_with_user_content_manager)
+ if (fp) {
+ rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong))fp)(arg0);
+ }
+ }
+ WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1view_1new_1with_1user_1content_1manager_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1webkit_1web_1view_1reload
JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1reload)
(JNIEnv *env, jclass that, jintLong arg0)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c
index 0ec4066958..9b819cc129 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2016 IBM Corporation and others. All rights reserved.
+ * Copyright (c) 2009, 2017 IBM Corporation and others. All rights reserved.
* The contents of this file are made available under the terms
* of the GNU Lesser General Public License (LGPL) Version 2.1 that
* accompanies this distribution (lgpl-v21.txt). The LGPL is also
@@ -110,6 +110,8 @@ char * WebKitGTK_nativeFunctionNames[] = {
"_1webkit_1hit_1test_1result_1context_1is_1link",
"_1webkit_1hit_1test_1result_1get_1link_1title",
"_1webkit_1hit_1test_1result_1get_1link_1uri",
+ "_1webkit_1javascript_1result_1get_1global_1context",
+ "_1webkit_1javascript_1result_1get_1value",
"_1webkit_1javascript_1result_1unref",
"_1webkit_1major_1version",
"_1webkit_1micro_1version",
@@ -127,6 +129,8 @@ char * WebKitGTK_nativeFunctionNames[] = {
"_1webkit_1uri_1request_1get_1uri",
"_1webkit_1uri_1request_1new",
"_1webkit_1uri_1response_1get_1mime_1type",
+ "_1webkit_1user_1content_1manager_1new",
+ "_1webkit_1user_1content_1manager_1register_1script_1message_1handler",
"_1webkit_1web_1context_1get_1default",
"_1webkit_1web_1context_1set_1favicon_1database_1directory",
"_1webkit_1web_1data_1source_1get_1data",
@@ -162,6 +166,7 @@ char * WebKitGTK_nativeFunctionNames[] = {
"_1webkit_1web_1view_1load_1string",
"_1webkit_1web_1view_1load_1uri",
"_1webkit_1web_1view_1new",
+ "_1webkit_1web_1view_1new_1with_1user_1content_1manager",
"_1webkit_1web_1view_1reload",
"_1webkit_1web_1view_1run_1javascript",
"_1webkit_1web_1view_1stop_1loading",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h
index 6b1491dd0f..36d3bf6b18 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2016 IBM Corporation and others. All rights reserved.
+ * Copyright (c) 2009, 2017 IBM Corporation and others. All rights reserved.
* The contents of this file are made available under the terms
* of the GNU Lesser General Public License (LGPL) Version 2.1 that
* accompanies this distribution (lgpl-v21.txt). The LGPL is also
@@ -120,6 +120,8 @@ typedef enum {
_1webkit_1hit_1test_1result_1context_1is_1link_FUNC,
_1webkit_1hit_1test_1result_1get_1link_1title_FUNC,
_1webkit_1hit_1test_1result_1get_1link_1uri_FUNC,
+ _1webkit_1javascript_1result_1get_1global_1context_FUNC,
+ _1webkit_1javascript_1result_1get_1value_FUNC,
_1webkit_1javascript_1result_1unref_FUNC,
_1webkit_1major_1version_FUNC,
_1webkit_1micro_1version_FUNC,
@@ -137,6 +139,8 @@ typedef enum {
_1webkit_1uri_1request_1get_1uri_FUNC,
_1webkit_1uri_1request_1new_FUNC,
_1webkit_1uri_1response_1get_1mime_1type_FUNC,
+ _1webkit_1user_1content_1manager_1new_FUNC,
+ _1webkit_1user_1content_1manager_1register_1script_1message_1handler_FUNC,
_1webkit_1web_1context_1get_1default_FUNC,
_1webkit_1web_1context_1set_1favicon_1database_1directory_FUNC,
_1webkit_1web_1data_1source_1get_1data_FUNC,
@@ -172,6 +176,7 @@ typedef enum {
_1webkit_1web_1view_1load_1string_FUNC,
_1webkit_1web_1view_1load_1uri_FUNC,
_1webkit_1web_1view_1new_FUNC,
+ _1webkit_1web_1view_1new_1with_1user_1content_1manager_FUNC,
_1webkit_1web_1view_1reload_FUNC,
_1webkit_1web_1view_1run_1javascript_FUNC,
_1webkit_1web_1view_1stop_1loading_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java
index 79d740fbf3..25625a0384 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java
@@ -13,6 +13,7 @@ package org.eclipse.swt.browser;
import java.io.*;
+import java.lang.reflect.*;
import java.net.*;
import java.nio.charset.*;
import java.util.*;
@@ -32,10 +33,14 @@ class WebKit extends WebBrowser {
String[] headers;
boolean ignoreDispose, loadingText, untrustedText;
byte[] htmlBytes;
- BrowserFunction eventFunction;
+ BrowserFunction eventFunction; //Webkit1 only.
static int DisabledJSCount;
- static long /*int*/ ExternalClass, PostString, WebViewType;
+
+ /** Webkit1 only. Used for callJava. See JSObjectHasPropertyProc */
+ static long /*int*/ ExternalClass;
+
+ static long /*int*/ PostString, WebViewType;
static boolean IsWebKit14orNewer, LibraryLoaded;
static Map<LONG, LONG> WindowMappings = new HashMap<> ();
@@ -98,7 +103,23 @@ class WebKit extends WebBrowser {
/* the following Callbacks are never freed */
static Callback Proc2, Proc3, Proc4, Proc5, Proc6;
- static Callback JSObjectHasPropertyProc, JSObjectGetPropertyProc, JSObjectCallAsFunctionProc;
+
+
+ /**
+ * Webkit1 only: For javascript to call java via it's 'callJava'.
+ * For webkit2, see Webkit2JavaCallback.
+ *
+ * Webkit1: - callJava is implemented via an external object
+ * - Creates an object 'external' on javascipt side.
+ * -- see create(..) where it's initialized
+ * -- see webkit_window_object_cleared where it re-creates it on page-reloads
+ * - Javascript will call 'external.callJava' (where callJava is a property of 'external').
+ * this triggers JSObjectGetPropertyProc(..) callback, which initializes callJava function.
+ * Then the external.callJava reaches JSObjectCallAsFunctionProc(..) and subsequently WebKit.java:callJava(..) is called.
+ */
+ static Callback JSObjectHasPropertyProc, JSObjectGetPropertyProc, JSObjectCallAsFunctionProc; // webkit1 only.
+
+ /** Webkit1 & Webkit2, Process key/mouse events from javascript. */
static Callback JSDOMEventProc;
static boolean WEBKIT2;
@@ -130,12 +151,19 @@ class WebKit extends WebBrowser {
if (Proc5.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
Proc6 = new Callback (WebKit.class, "Proc", 6); //$NON-NLS-1$
if (Proc6.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
- JSObjectHasPropertyProc = new Callback (WebKit.class, "JSObjectHasPropertyProc", 3); //$NON-NLS-1$
- if (JSObjectHasPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
- JSObjectGetPropertyProc = new Callback (WebKit.class, "JSObjectGetPropertyProc", 4); //$NON-NLS-1$
- if (JSObjectGetPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
- JSObjectCallAsFunctionProc = new Callback (WebKit.class, "JSObjectCallAsFunctionProc", 6); //$NON-NLS-1$
- if (JSObjectCallAsFunctionProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+
+ if (WEBKIT2) {
+ new Webkit2JavaCallback();
+ } else {
+ JSObjectHasPropertyProc = new Callback (WebKit.class, "JSObjectHasPropertyProc", 3); //$NON-NLS-1$
+ if (JSObjectHasPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ JSObjectGetPropertyProc = new Callback (WebKit.class, "JSObjectGetPropertyProc", 4); //$NON-NLS-1$
+ if (JSObjectGetPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ JSObjectCallAsFunctionProc = new Callback (WebKit.class, "JSObjectCallAsFunctionProc", 6); //$NON-NLS-1$
+ if (JSObjectCallAsFunctionProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ }
+
JSDOMEventProc = new Callback (WebKit.class, "JSDOMEventProc", 3); //$NON-NLS-1$
if (JSDOMEventProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
@@ -225,6 +253,104 @@ class WebKit extends WebBrowser {
}
/**
+ * For javascript to call java.
+ * This callback is special in that we link Javascript to a C function and a C function to
+ * the SWT java function.
+ *
+ * Note there is an architecture difference how callJava is implemented in Webkit1 vs Webkit2:
+ *
+ * Webkit1: See JSObjectHasPropertyProc.
+ *
+ * Webkit2: - callJava is implemented by connecting and calling a webkit signal:
+ * - webkit2JavaCallProc is linked from C to java.
+ * - Each webkit instance connects a signal (Webkit2JavaCallback.signal) to Webkit2JavaCallback.webkit2JavaCallProc
+ * via Webkit2JavaCallback.connectSignal(..)
+ * - (Note, webView is created with user_content_manager on webkit2.)
+ * - callJava is a wrapper that calls window.webkit.messageHandlers.webkit2JavaCallProc.postMessage([index,token, args]),
+ * which triggers the script-message-received::webkit2JavaCallProc signal and is forwarded to webkit2JavaCallProc.
+ **/
+ static class Webkit2JavaCallback {
+ private static final String JavaScriptFunctionName = "webkit2JavaCallProc"; // $NON-NLS-1$
+ private static final String Signal = "script-message-received::" + JavaScriptFunctionName; // $NON-NLS-1$
+
+ static final String JavaScriptFunctionDeclaration =
+ "if (!window.callJava) {\n"
+ + " window.callJava = function callJava(index, token, args) {\n"
+ + " window.webkit.messageHandlers." + JavaScriptFunctionName + ".postMessage([index,token, args]);\n"
+ + " }\n"
+ + "};\n";
+
+ private static Callback callback;
+ static {
+ callback = new Callback (Webkit2JavaCallback.class, JavaScriptFunctionName, void.class, new Type[] {long.class, long.class, long.class});
+ if (callback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ }
+
+ /**
+ * This method is called directly from javascript via something like: <br>
+ * window.webkit.messageHandlers.webkit2JavaCallProc.postMessage('helloWorld') <br>
+ * - Note, this method is async when called from javascript. <br>
+ * - This method name MUST match: this.JavaScriptFunctionName <br>
+ * - This method somewhat mirrors 'long callJava(ctx,func...)'. Except that it doesn't return a value.
+ * Docu: <br>
+ * https://webkitgtk.org/reference/webkit2gtk/stable/WebKitUserContentManager.html#WebKitUserContentManager-script-message-received
+ * */
+ @SuppressWarnings("unused") // Method is called only directly from javascript.
+ private static void webkit2JavaCallProc (long /*int*/ WebKitUserContentManagerPtr, long /*int*/ WebKitJavascriptResultPtr, long /*int*/ webViewPtr) {
+ try {
+ long /*int*/ context = WebKitGTK.webkit_javascript_result_get_global_context (WebKitJavascriptResultPtr);
+ long /*int*/ value = WebKitGTK.webkit_javascript_result_get_value (WebKitJavascriptResultPtr);
+ Object[] arguments = (Object[]) convertToJava(context, value);
+ if (arguments.length != 3) throw new IllegalArgumentException("Expected 3 args. Received: " + arguments.length);
+
+ Double index = (Double) arguments[0];
+ String token = (String) arguments[1];
+
+ Browser browser = FindBrowser(webViewPtr);
+ if (browser == null) throw new NullPointerException("Could not find assosiated browser instance for handle: " + webViewPtr);
+
+ BrowserFunction function = browser.webBrowser.functions.get(index.intValue());
+
+ if (function == null) throw new NullPointerException("Could not find function with index: " + index);
+ if (!token.equals(function.token)) throw new IllegalStateException("Function token missmatch. Expected:" + function.token + " actual:" + token);
+ if (! (arguments[2] instanceof Object[])) {
+ throw new IllegalArgumentException("Javascript did not provide any arguments. An empty callback [like call()] should still provide an empty array");
+ }
+
+ try {
+ // TODO someday : Support return values. See Bug 510905
+ function.function ((Object[]) arguments[2]);
+ } catch (Exception e) {
+ // Exception in user function.
+ // Normally we would return an error to javascript. See callJava(..).
+ // But support for returning item back to java not implemented yet.
+ }
+
+ } catch (RuntimeException e) {
+ System.err.println("\nSWT Webkit2 internal error: Javascript callback from Webkit to Java encountered an error while processing the callback:");
+ System.err.println("Please report this via: https://bugs.eclipse.org/bugs/enter_bug.cgi?alias=&assigned_to=platform-swt-inbox%40eclipse.org&attach_text=&blocked=&bug_file_loc=http%3A%2F%2F&bug_severity=normal&bug_status=NEW&comment=&component=SWT&contenttypeentry=&contenttypemethod=autodetect&contenttypeselection=text%2Fplain&data=&defined_groups=1&dependson=&description=&flag_type-1=X&flag_type-11=X&flag_type-12=X&flag_type-13=X&flag_type-14=X&flag_type-15=X&flag_type-16=X&flag_type-2=X&flag_type-4=X&flag_type-6=X&flag_type-7=X&flag_type-8=X&form_name=enter_bug&keywords=&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Linux&product=Platform&qa_contact=&rep_platform=PC&requestee_type-1=&requestee_type-2=&short_desc=&version=4.7");
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ /** Connect an instance of a webkit to the callback. */
+ static void connectSignal(long /*int*/ WebKitUserContentManager, long /*int*/ webView) {
+ OS.g_signal_connect (WebKitUserContentManager, Converter.wcsToMbcs (Signal, true), callback.getAddress (), webView);
+ WebKitGTK.webkit_user_content_manager_register_script_message_handler(WebKitUserContentManager, Converter.wcsToMbcs(JavaScriptFunctionName, true));
+ }
+ }
+
+ @Override
+ String getJavaCallDeclaration() {
+ if (WEBKIT2) {
+ return Webkit2JavaCallback.JavaScriptFunctionDeclaration;
+ } else {
+ return super.getJavaCallDeclaration();
+ }
+ }
+
+ /**
* Gets the webkit version, within an <code>int[3]</code> array with
* <code>{major, minor, micro}</code> version
*/
@@ -273,7 +399,16 @@ static boolean IsInstalled () {
(major == MIN_VERSION[0] && minor == MIN_VERSION[1] && micro >= MIN_VERSION[2]);
}
+/**
+ * Webkit1 callback. Used when external.callJava is called in javascript.
+ * Not used by Webkit2.
+ */
static long /*int*/ JSObjectCallAsFunctionProc (long /*int*/ ctx, long /*int*/ function, long /*int*/ thisObject, long /*int*/ argumentCount, long /*int*/ arguments, long /*int*/ exception) {
+ if (WEBKIT2) {
+ System.err.println("Internal error: SWT JSObjectCallAsFunctionProc. This should never have been called on webkit2.");
+ return 0;
+ }
+
if (WebKitGTK.JSValueIsObjectOfClass (ctx, thisObject, ExternalClass) == 0) {
return WebKitGTK.JSValueMakeUndefined (ctx);
}
@@ -286,7 +421,16 @@ static long /*int*/ JSObjectCallAsFunctionProc (long /*int*/ ctx, long /*int*/ f
return webkit.callJava (ctx, function, thisObject, argumentCount, arguments, exception);
}
+/**
+ * This callback is only being ran by webkit1. Only for 'callJava'.
+ * It's used to initialize the 'callJava' function pointer in the 'external' object,
+ * such that external.callJava reaches Java land.
+ */
static long /*int*/ JSObjectGetPropertyProc (long /*int*/ ctx, long /*int*/ object, long /*int*/ propertyName, long /*int*/ exception) {
+ if (WEBKIT2) {
+ System.err.println("Internal error: SWT WebKit.java:JSObjectGetPropertyProc. This should never have been called on webkit2.");
+ return 0;
+ }
byte[] bytes = (FUNCTIONNAME_CALLJAVA + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$
long /*int*/ name = WebKitGTK.JSStringCreateWithUTF8CString (bytes);
long /*int*/ function = WebKitGTK.JSObjectMakeFunctionWithCallback (ctx, name, JSObjectCallAsFunctionProc.getAddress ());
@@ -294,7 +438,14 @@ static long /*int*/ JSObjectGetPropertyProc (long /*int*/ ctx, long /*int*/ obje
return function;
}
+/**
+ * Webkit1: Check if the 'external' object regiseterd earlied has the 'callJava' property.
+ */
static long /*int*/ JSObjectHasPropertyProc (long /*int*/ ctx, long /*int*/ object, long /*int*/ propertyName) {
+ if (WEBKIT2) {
+ System.err.println("Internal error: SWT JSObjectHasPropertyProc. This should never have been called on webkit2.");
+ return 0;
+ }
byte[] bytes = (FUNCTIONNAME_CALLJAVA + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$
return WebKitGTK.JSStringIsEqualToUTF8CString (propertyName, bytes);
}
@@ -558,17 +709,22 @@ public void create (Composite parent, int style) {
if (Device.DEBUG) {
System.out.println(String.format("WebKit version %s.%s.%s", vers[0], vers[1], vers[2])); //$NON-NLS-1$
}
- JSClassDefinition jsClassDefinition = new JSClassDefinition ();
- byte[] bytes = Converter.wcsToMbcs (CLASSNAME_EXTERNAL, true);
- jsClassDefinition.className = C.malloc (bytes.length);
- OS.memmove (jsClassDefinition.className, bytes, bytes.length);
- jsClassDefinition.hasProperty = JSObjectHasPropertyProc.getAddress ();
- jsClassDefinition.getProperty = JSObjectGetPropertyProc.getAddress ();
- long /*int*/ classDefinitionPtr = C.malloc (JSClassDefinition.sizeof);
- WebKitGTK.memmove (classDefinitionPtr, jsClassDefinition, JSClassDefinition.sizeof);
- ExternalClass = WebKitGTK.JSClassCreate (classDefinitionPtr);
-
- bytes = Converter.wcsToMbcs ("POST", true); //$NON-NLS-1$
+
+ if (!WEBKIT2) { // 'external' object only used on webkit1 for javaCall. Webkit2 has a different mechanism.
+ JSClassDefinition jsClassDefinition = new JSClassDefinition ();
+ byte[] bytes = Converter.wcsToMbcs (CLASSNAME_EXTERNAL, true);
+ jsClassDefinition.className = C.malloc (bytes.length);
+ OS.memmove (jsClassDefinition.className, bytes, bytes.length);
+
+ jsClassDefinition.hasProperty = JSObjectHasPropertyProc.getAddress ();
+ jsClassDefinition.getProperty = JSObjectGetPropertyProc.getAddress ();
+ long /*int*/ classDefinitionPtr = C.malloc (JSClassDefinition.sizeof);
+ WebKitGTK.memmove (classDefinitionPtr, jsClassDefinition, JSClassDefinition.sizeof);
+
+ ExternalClass = WebKitGTK.JSClassCreate (classDefinitionPtr);
+ }
+
+ byte [] bytes = Converter.wcsToMbcs ("POST", true); //$NON-NLS-1$
PostString = C.malloc (bytes.length);
C.memmove (PostString, bytes, bytes.length);
@@ -593,7 +749,15 @@ public void create (Composite parent, int style) {
OS.gtk_scrolled_window_set_policy (scrolledWindow, OS.GTK_POLICY_AUTOMATIC, OS.GTK_POLICY_AUTOMATIC);
}
- webView = WebKitGTK.webkit_web_view_new ();
+ if (WEBKIT2) {
+ // On Webkit2, webView has to be created with UserContentManager so that Javascript callbacks work. See #508217
+ long /*int*/ WebKitUserContentManager = WebKitGTK.webkit_user_content_manager_new();
+ webView = WebKitGTK.webkit_web_view_new_with_user_content_manager (WebKitUserContentManager);
+ Webkit2JavaCallback.connectSignal(WebKitUserContentManager, webView);
+ } else { // Webkit1
+ webView = WebKitGTK.webkit_web_view_new ();
+ }
+
webViewData = C.malloc (C.PTR_SIZEOF);
C.memmove (webViewData, new long /*int*/[] {webView}, C.PTR_SIZEOF);
@@ -746,12 +910,14 @@ public void create (Composite parent, int style) {
}
}
- eventFunction = new BrowserFunction (browser, "HandleWebKitEvent") { //$NON-NLS-1$
- @Override
- public Object function(Object[] arguments) {
- return handleEventFromFunction (arguments) ? Boolean.TRUE : Boolean.FALSE;
- }
- };
+ if (!WEBKIT2) { // HandleWebKitEvent registration. Pre Webkit 1.4 way of handling mouse/keyboard events. Webkit2 uses dom.
+ eventFunction = new BrowserFunction (browser, "HandleWebKitEvent") { //$NON-NLS-1$
+ @Override
+ public Object function(Object[] arguments) {
+ return handleEventFromFunction (arguments) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ };
+ }
/*
* Bug in WebKitGTK. MouseOver/MouseLeave events are not consistently sent from
@@ -812,51 +978,54 @@ void addEventHandlers (long /*int*/ web_view, boolean top) {
return;
}
- /* install the JS call-out to the registered BrowserFunction */
- StringBuffer buffer = new StringBuffer ("window.SWTkeyhandler = function SWTkeyhandler(e) {"); //$NON-NLS-1$
- buffer.append ("try {e.returnValue = HandleWebKitEvent(e.type, e.keyCode, e.charCode, e.altKey, e.ctrlKey, e.shiftKey, e.metaKey);} catch (e) {}};"); //$NON-NLS-1$
- execute (buffer.toString ());
- buffer = new StringBuffer ("window.SWTmousehandler = function SWTmousehandler(e) {"); //$NON-NLS-1$
- buffer.append ("try {e.returnValue = HandleWebKitEvent(e.type, e.screenX, e.screenY, e.detail, e.button, e.altKey, e.ctrlKey, e.shiftKey, e.metaKey, e.relatedTarget != null);} catch (e) {}};"); //$NON-NLS-1$
- execute (buffer.toString ());
- if (top) {
- /* DOM API is not available, so add listener to top-level document */
- buffer = new StringBuffer ("document.addEventListener('keydown', SWTkeyhandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('keypress', SWTkeyhandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('keyup', SWTkeyhandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('mousedown', SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('mouseup', SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('mousemove', SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('mousewheel', SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("document.addEventListener('dragstart', SWTmousehandler, true);"); //$NON-NLS-1$
+ if (!WEBKIT2) { // add HandleWebKitEvent key/mouse handlers
+ /* install the JS call-out to the registered BrowserFunction */
+ StringBuffer buffer = new StringBuffer ("window.SWTkeyhandler = function SWTkeyhandler(e) {"); //$NON-NLS-1$
+ buffer.append ("try {e.returnValue = HandleWebKitEvent(e.type, e.keyCode, e.charCode, e.altKey, e.ctrlKey, e.shiftKey, e.metaKey);} catch (e) {}};"); //$NON-NLS-1$
+ execute (buffer.toString ());
+ buffer = new StringBuffer ("window.SWTmousehandler = function SWTmousehandler(e) {"); //$NON-NLS-1$
+ buffer.append ("try {e.returnValue = HandleWebKitEvent(e.type, e.screenX, e.screenY, e.detail, e.button, e.altKey, e.ctrlKey, e.shiftKey, e.metaKey, e.relatedTarget != null);} catch (e) {}};"); //$NON-NLS-1$
+ execute (buffer.toString ());
- /*
- * The following two lines are intentionally commented because they cannot be used to
- * consistently send MouseEnter/MouseExit events until https://bugs.webkit.org/show_bug.cgi?id=35246
- * is fixed.
- */
- //buffer.append ("document.addEventListener('mouseover', SWTmousehandler, true);"); //$NON-NLS-1$
- //buffer.append ("document.addEventListener('mouseout', SWTmousehandler, true);"); //$NON-NLS-1$
+ if (top) {
+ /* DOM API is not available, so add listener to top-level document */
+ buffer = new StringBuffer ("document.addEventListener('keydown', SWTkeyhandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('keypress', SWTkeyhandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('keyup', SWTkeyhandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('mousedown', SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('mouseup', SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('mousemove', SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('mousewheel', SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("document.addEventListener('dragstart', SWTmousehandler, true);"); //$NON-NLS-1$
+ /*
+ * The following two lines are intentionally commented because they cannot be used to
+ * consistently send MouseEnter/MouseExit events until https://bugs.webkit.org/show_bug.cgi?id=35246
+ * is fixed.
+ */
+ //buffer.append ("document.addEventListener('mouseover', SWTmousehandler, true);"); //$NON-NLS-1$
+ //buffer.append ("document.addEventListener('mouseout', SWTmousehandler, true);"); //$NON-NLS-1$
+
+ execute (buffer.toString ());
+ return;
+ }
+
+ /* add JS event listener in frames */
+ buffer = new StringBuffer ("for (var i = 0; i < frames.length; i++) {"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('keydown', window.SWTkeyhandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('keypress', window.SWTkeyhandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('keyup', window.SWTkeyhandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('mousedown', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('mouseup', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('mousemove', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('mouseover', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('mouseout', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('mousewheel', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ("frames[i].document.addEventListener('dragstart', window.SWTmousehandler, true);"); //$NON-NLS-1$
+ buffer.append ('}');
execute (buffer.toString ());
- return;
}
-
- /* add JS event listener in frames */
- buffer = new StringBuffer ("for (var i = 0; i < frames.length; i++) {"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('keydown', window.SWTkeyhandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('keypress', window.SWTkeyhandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('keyup', window.SWTkeyhandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('mousedown', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('mouseup', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('mousemove', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('mouseover', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('mouseout', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('mousewheel', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ("frames[i].document.addEventListener('dragstart', window.SWTmousehandler, true);"); //$NON-NLS-1$
- buffer.append ('}');
- execute (buffer.toString ());
}
@Override
@@ -940,15 +1109,6 @@ public boolean execute (String script) {
@Override
public Object evaluate (String script) throws SWTException {
if (WEBKIT2){
-
- if (script.contains(FUNCTIONNAME_CALLJAVA)) {
- // Bug 508217 - Support for browser.funcction/close not yet implemented.
- // trying to execute 'callJava' code currently can lead to infinite
- // recursion/loops causing freeze ups. See Bug 510183.
- // Disabling till function and close() implemented.
- return null;
- }
-
/* Webkit2: We remove the 'return' prefix that normally comes with the script.
* The reason is that in Webkit1, script was wrapped into a function and if an exception occured
* it was caught on Javascript side and a callback to java was made.
@@ -2066,6 +2226,10 @@ long /*int*/ webkit_notify_load_status (long /*int*/ web_view, long /*int*/ pspe
return 0;
}
+/**
+ * This method is only called by Webkit2.
+ * The webkit1 equivalent is webkit_window_object_cleared;
+ */
long /*int*/ webkit_load_changed (long /*int*/ web_view, int status, long user_data) {
switch (status) {
case WebKitGTK.WEBKIT2_LOAD_COMMITTED: {
@@ -2073,6 +2237,10 @@ long /*int*/ webkit_load_changed (long /*int*/ web_view, int status, long user_d
return handleLoadCommitted (uri, true);
}
case WebKitGTK.WEBKIT2_LOAD_FINISHED: {
+
+ registerBrowserFunctions(); // Bug 508217
+ addEventHandlers (web_view, true);
+
long /*int*/ title = WebKitGTK.webkit_web_view_get_title (webView);
if (title == 0) {
long /*int*/ uri = WebKitGTK.webkit_web_view_get_uri (webView);
@@ -2318,6 +2486,10 @@ long /*int*/ webkit_web_view_ready (long /*int*/ web_view) {
return 0;
}
+/**
+ * This method is only called by Webkit1.
+ * The webkit2 equivalent is webkit_load_changed(..):caseWEBKIT2__LOAD_FINISHED
+ */
long /*int*/ webkit_window_object_cleared (long /*int*/ web_view, long /*int*/ frame, long /*int*/ context, long /*int*/ window_object) {
long /*int*/ globalObject = WebKitGTK.JSContextGetGlobalObject (context);
long /*int*/ externalObject = WebKitGTK.JSObjectMake (context, ExternalClass, webViewData);
@@ -2325,17 +2497,25 @@ long /*int*/ webkit_window_object_cleared (long /*int*/ web_view, long /*int*/ f
long /*int*/ name = WebKitGTK.JSStringCreateWithUTF8CString (bytes);
WebKitGTK.JSObjectSetProperty (context, globalObject, name, externalObject, 0, null);
WebKitGTK.JSStringRelease (name);
+
+ registerBrowserFunctions(); // Bug 508217
+ long /*int*/ mainFrame = WebKitGTK.webkit_web_view_get_main_frame (webView);
+ boolean top = mainFrame == frame;
+ addEventHandlers (web_view, top);
+ return 0;
+}
+
+private void registerBrowserFunctions() {
Iterator<BrowserFunction> elements = functions.values().iterator ();
while (elements.hasNext ()) {
BrowserFunction current = elements.next ();
execute (current.functionString);
}
- long /*int*/ mainFrame = WebKitGTK.webkit_web_view_get_main_frame (webView);
- boolean top = mainFrame == frame;
- addEventHandlers (web_view, top);
- return 0;
}
+/**
+ * Webkit1 callback for javascript to call java.
+ */
long /*int*/ callJava (long /*int*/ ctx, long /*int*/ func, long /*int*/ thisObject, long /*int*/ argumentCount, long /*int*/ arguments, long /*int*/ exception) {
Object returnValue = null;
if (argumentCount == 3) {
@@ -2415,7 +2595,7 @@ long /*int*/ convertToJS (long /*int*/ ctx, Object value) {
return 0;
}
-Object convertToJava (long /*int*/ ctx, long /*int*/ value) {
+static Object convertToJava (long /*int*/ ctx, long /*int*/ value) {
int type = WebKitGTK.JSValueGetType (ctx, value);
switch (type) {
case WebKitGTK.kJSTypeBoolean: {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java
index 6a429efdb1..16fe5a7a93 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java
@@ -46,6 +46,7 @@ public class WebKitGTK extends C {
public static final int WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION = 1;
public static final int WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT = 2;
+
/** Signals */
public static final byte[] authenticate = ascii ("authenticate"); // $NON-NLS-1$
public static final byte[] close_web_view = ascii ("close-web-view"); // $NON-NLS-1$
@@ -58,6 +59,7 @@ public class WebKitGTK extends C {
public static final byte[] download_requested = ascii ("download-requested"); // $NON-NLS-1$
public static final byte[] download_started = ascii ("download-started"); // $NON-NLS-1$
public static final byte[] hovering_over_link = ascii ("hovering-over-link"); // $NON-NLS-1$
+ /** Webkit2 only, to implement equivalent of webkit1 window_object_cleared*/
public static final byte[] load_changed = ascii ("load-changed"); // $NON-NLS-1$
public static final byte[] mime_type_policy_decision_requested = ascii ("mime-type-policy-decision-requested"); // $NON-NLS-1$
public static final byte[] mouse_target_changed = ascii ("mouse-target-changed"); // $NON-NLS-1$
@@ -74,8 +76,10 @@ public class WebKitGTK extends C {
public static final byte[] status_bar_text_changed = ascii ("status-bar-text-changed"); // $NON-NLS-1$
public static final byte[] web_view_ready = ascii ("web-view-ready"); // $NON-NLS-1$
public static final byte[] ready_to_show = ascii ("ready-to-show"); // $NON-NLS-1$
+ /** Webkit1 only. On Webkit2 this is found in a webextension. Instead 'load_changed' is used on webkit2 **/
public static final byte[] window_object_cleared = ascii ("window-object-cleared"); // $NON-NLS-1$
+
/** Properties */
public static final byte[] default_encoding = ascii ("default-encoding"); // $NON-NLS-1$
public static final byte[] default_charset = ascii ("default-charset"); // $NON-NLS-1$
@@ -1523,6 +1527,69 @@ public static final long /*int*/ webkit_web_view_new () {
}
/** @method flags=dynamic */
+public static final native long /*int*/ _webkit_user_content_manager_new();
+public static final long /*int*/ webkit_user_content_manager_new() {
+ lock.lock();
+ try {
+ return _webkit_user_content_manager_new ();
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @method flags=dynamic
+ * @param js_result cast=(gpointer)
+ */
+public static final native long /*int*/ _webkit_javascript_result_get_global_context(long /*int*/ js_result);
+/** JSGlobalContextRef webkit_javascript_result_get_global_context (WebKitJavascriptResult *js_result); */
+public static final long /*int*/ webkit_javascript_result_get_global_context(long /*int*/ js_result) {
+ lock.lock();
+ try {
+ return _webkit_javascript_result_get_global_context (js_result);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @method flags=dynamic
+ * @param js_result cast=(gpointer)
+ */
+public static final native long /*int*/ _webkit_javascript_result_get_value(long /*int*/ js_result);
+/** JSValueRef webkit_javascript_result_get_value (WebKitJavascriptResult *js_result); */
+public static final long /*int*/ webkit_javascript_result_get_value(long /*int*/ js_result) {
+ lock.lock();
+ try {
+ return _webkit_javascript_result_get_value (js_result);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/** @method flags=dynamic */
+public static final native boolean _webkit_user_content_manager_register_script_message_handler(long /*int*/ WebKitUserContentManager, byte[] name);
+public static final boolean webkit_user_content_manager_register_script_message_handler(long /*int*/ WebKitUserContentManager, byte[] name) {
+ lock.lock();
+ try {
+ return _webkit_user_content_manager_register_script_message_handler (WebKitUserContentManager, name);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/** @method flags=dynamic */
+public static final native long /*int*/ _webkit_web_view_new_with_user_content_manager (long /*int*/ WebKitUserContentManager);
+public static final long /*int*/ webkit_web_view_new_with_user_content_manager (long /*int*/ WebKitUserContentManager) {
+ lock.lock();
+ try {
+ return _webkit_web_view_new_with_user_content_manager (WebKitUserContentManager);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/** @method flags=dynamic */
public static final native void _webkit_web_view_reload (long /*int*/ web_view);
public static final void webkit_web_view_reload (long /*int*/ web_view) {
lock.lock();
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java
index 87eaea190a..0d4c31549f 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java
@@ -63,6 +63,7 @@ public class Test_org_eclipse_swt_browser_Browser extends Test_org_eclipse_swt_w
boolean browser_debug = false;
boolean isWebkit1 = false;
+ boolean isWebkit2 = false;
/**
* Normally, sleep in 1 ms intervals 1000 times. During browser_debug, sleep 1000 ms for 1 interval.
@@ -106,6 +107,8 @@ public void setUp() {
// webkitgtk 2.5 and onwards uses webkit2.
if (webkitGtkVersionInts[0] == 1 || (webkitGtkVersionInts[0] == 2 && webkitGtkVersionInts[1] <= 4)) {
isWebkit1 = true;
+ } else if (webkitGtkVersionInts[0] == 2 && webkitGtkVersionInts[1] > 4) {
+ isWebkit2 = true;
}
}
shell.setText(shellTitle);
@@ -785,7 +788,9 @@ public void test_execute_and_closeListener () {
*/
@Test
public void test_evaluate_string() {
- assumeFalse(webkit1SkipMsg(), isWebkit1); // Bug 509411
+ // Run locally, skip on hudson. see Bug 509411
+ // This test sometimes crashes on webkit1, but it's useful to test at least one 'evaluate' situation.
+ assumeFalse(webkit1SkipMsg(), (SwtTestUtil.isRunningOnEclipseOrgHudsonGTK && isWebkit1));
final AtomicReference<String> returnValue = new AtomicReference<>();
browser.addProgressListener(new ProgressListener() {
@@ -1227,7 +1232,8 @@ public void test_BrowserFunction_callback_with_integer () {
// On webkit1, this test works if ran on it's own. But sometimes in test-suite with other tests it causes jvm crash.
// culprit seems to be the main_context_iteration() call in shell.setVisible().
// See Bug 509587. Solution: Webkit2.
- assumeFalse(webkit1SkipMsg(), isWebkit1);
+ // It's useful to run at least one function test on webkit1 locally.
+ assumeFalse(webkit1SkipMsg(), (SwtTestUtil.isRunningOnEclipseOrgHudsonGTK && isWebkit1)); // run locally. Skip on hudson that runs webkit1.
AtomicInteger returnInt = new AtomicInteger(0);
@@ -1459,6 +1465,9 @@ public void test_BrowserFunction_callback_with_javaReturningInt () {
// See Bug 509587. Solution: Webkit2.
assumeFalse(webkit1SkipMsg(), isWebkit1);
+ // Skip till Bug 510905 is implemented.
+ assumeFalse("Skipping test_BrowserFunction_callback_with_javaReturningInt. Java's callback to Javascript doesn't support return yet", isWebkit2);
+
AtomicInteger returnInt = new AtomicInteger(0);
class JavascriptCallback extends BrowserFunction { // Note: Local class defined inside method.
@@ -1515,6 +1524,71 @@ public void test_BrowserFunction_callback_with_javaReturningInt () {
}
+/**
+ * Test that a callback works even after a new page is loaded.
+ * I.e, BrowserFunctions should have to be re-initialized after a page load.
+ *
+ * Logic:
+ * - load a page.
+ * - Register java callback.
+ * - call java callback from javascript. (exec)
+ *
+ * - java callback instantiates new page load.
+ * - new page load triggers 'completed' listener
+ * - completed listener calls the registered function again.
+ *
+ * - once regiseterd function is called a 2nd time, it sets the test to pass.
+ */
+@Test
+public void test_BrowserFunction_callback_afterPageReload() {
+ // On webkit1, this test works if ran on it's own. But sometimes in test-suite with other tests it causes jvm crash.
+ // culprit seems to be the main_context_iteration() call in shell.setVisible().
+ // See Bug 509587. Solution: Webkit2.
+ assumeFalse(webkit1SkipMsg(), isWebkit1);
+
+ AtomicBoolean javaCallbackExecuted = new AtomicBoolean(false);
+ AtomicInteger callCount = new AtomicInteger(0);
+
+ class JavascriptCallback extends BrowserFunction { // Note: Local class defined inside method.
+ JavascriptCallback(Browser browser, String name) {
+ super(browser, name);
+ }
+
+ @Override
+ public Object function(Object[] arguments) {
+ if (callCount.get() == 0) {
+ callCount.set(1);
+ browser.setText("2nd page load");
+ } else {
+ javaCallbackExecuted.set(true);
+ }
+ return null;
+ }
+ }
+ browser.setText("1st (initial) page load");
+ new JavascriptCallback(browser, "jsCallbackToJava");
+ browser.execute("jsCallbackToJava()");
+
+ browser.addProgressListener(new ProgressListener() {
+ @Override
+ public void completed(ProgressEvent event) {
+ // see if function still works after a page change:
+ browser.execute("jsCallbackToJava()");
+ }
+ @Override
+ public void changed(ProgressEvent event) {}
+ });
+
+ shell.open();
+ for (int i = 0; i < (loopMultipier * secondsToWaitTillFail); i++) { // Wait up to seconds before declaring test as failed.
+ runLoopTimer(waitMS);
+ if (javaCallbackExecuted.get()) {
+ return; // pass.
+ }
+ }
+ fail();
+}
+
/* custom */
void runLoopTimer(final int milliseconds) {

Back to the top