diff options
| author | Lev Ufimtsev | 2016-08-04 19:13:18 +0000 |
|---|---|---|
| committer | Leo Ufimtsev | 2016-09-19 14:51:39 +0000 |
| commit | 688c0e346bc63c155a78983d3bf38fb76a8c5b6c (patch) | |
| tree | a039ab5fed1e6f88c606073894af7cf2ee6a45e8 | |
| parent | 002373ea04e53bd20e0f1f34ceea2733b256c5be (diff) | |
| download | eclipse.platform.swt-688c0e346bc63c155a78983d3bf38fb76a8c5b6c.tar.gz eclipse.platform.swt-688c0e346bc63c155a78983d3bf38fb76a8c5b6c.tar.xz eclipse.platform.swt-688c0e346bc63c155a78983d3bf38fb76a8c5b6c.zip | |
Bug 430538: [GTK3][webkit] Support Custom JavaScript execution in
WebKit2 mode of SWT Browser
Re-Applying patch that was reverted because build servers were not
updated:
https://git.eclipse.org/r/#/c/80902/
--------------------------
Stage 1
Patch Set 1: 2016-08Aug-04Thu (pushed2Gerrit)
Implement return mechanism for webkit_*_run_javascript()
- Adding a webkitgtk_custom.c file for custom function
- modified linux_makefil for additional file
- cleanup of linux_makefile for webkit, (confusing target naming).
Patch Set 2: 2016-08Aug-08Mon (pushed2Gerrit)
- Implemented call to webkit
- Implemented spinlock and while loop to wait for callback
to finish. Spinlock is passed as pointer to callback.
Patch Set 3: (pushed2Gerrit)
- 2016-08Aug-08Mon - minor tweaks.
- 2016-08Aug-09Tue - renamed custom method/function name.
- 2016-08Aug-10Wed - fixed potential memory leak.
- 2016-08Aug-15Mon - Implemented conditional compilation for
build servers without webkit2gtk4
Patch Set 4:
2016-08Aug-30Tue
- Rewrite to call webkit functions dynamically instead of hard-linking
- removed pkg-config dependencies to webkitgtk
- Changed pkg-config webkit flags to use gio instead of glib.
Note, glib is a subset of gio, and gio is a subset of Gtk2/Gtk3,
thus this should not break anything.
Patchset 14:
- Adjusted comment in webkitgtk_custom.c
> Warning to future developers as it's not obvious. I did not know
until you pointed it out.
- Removed 'ifndef' from function swt_webkit_web_view_run_javascript
call. In hindsight, it doesn't look like it's necessary.
Things I've tested:
- Child Eclipse with webkit2 browser
- Browser tests: (fixes tests 3,4, 8).
- Various browser snippets.
To test yourself:
- To enable webkit2, set:
SWT_WEBKIT2=1
- Manual inspection via SWT-SNIPPET:
https://github.com/ericwill/SWT-snippets/blob/master/src/browser/Bug430538_JS_Set_Background.java
If you click the 'execute' button, now background is set.
(Note, other button 'evalute' not working yet).
- Browser8.java now passes and correctly executes JS
(enable verbose on line 30 to see before/after, now background
changes).
- Browser3.java now passes
Change-Id: I1202064798ef7839af1d29aff41391d411276005
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=430538
Signed-off-by: Lev Ufimtsev <lufimtse@redhat.com>
9 files changed, 210 insertions, 15 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak index 9d3aa874e7..40ee285d22 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak @@ -100,7 +100,9 @@ MOZILLAEXCLUDES = -DNO__1XPCOMGlueShutdown \ -DNO_nsDynamicFunctionLoad XULRUNNEREXCLUDES = -DNO__1NS_1InitXPCOM2 -WEBKITCFLAGS = `pkg-config --cflags glib-2.0` + +WEBKITLIBS = `pkg-config --libs-only-l gio-2.0` # Avoid adding 'webkit2gtk-4.0', as some systems might not have it. +WEBKITCFLAGS = `pkg-config --cflags gio-2.0` # webkit functions should be called dynamically. See Bug 430538 SWT_OBJECTS = swt.o c.o c_stats.o callback.o CDE_OBJECTS = swt.o cde.o cde_structs.o cde_stats.o @@ -112,7 +114,7 @@ GNOME_OBJECTS = swt.o gnome.o gnome_structs.o gnome_stats.o MOZILLA_OBJECTS = swt.o xpcom.o xpcom_custom.o xpcom_structs.o xpcom_stats.o XULRUNNER_OBJECTS = swt.o xpcomxul.o xpcomxul_custom.o xpcomxul_structs.o xpcomxul_stats.o XPCOMINIT_OBJECTS = swt.o xpcominit.o xpcominit_structs.o xpcominit_stats.o -WEBKIT_OBJECTS = swt.o webkit.o webkit_structs.o webkit_stats.o +WEBKIT_OBJECTS = swt.o webkitgtk.o webkitgtk_structs.o webkitgtk_stats.o webkitgtk_custom.o GLX_OBJECTS = swt.o glx.o glx_structs.o glx_stats.o CFLAGS = -O -Wall \ @@ -294,16 +296,19 @@ xpcominit_stats.o: xpcominit_stats.cpp make_webkit: $(WEBKIT_LIB) $(WEBKIT_LIB): $(WEBKIT_OBJECTS) - $(CC) $(LFLAGS) -o $(WEBKIT_LIB) $(WEBKIT_OBJECTS) + $(CC) $(LFLAGS) -o $(WEBKIT_LIB) $(WEBKIT_OBJECTS) $(WEBKITLIBS) -webkit.o: webkitgtk.c - $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk.c -o webkit.o +webkitgtk.o: webkitgtk.c webkitgtk_custom.h + $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk.c -webkit_structs.o: webkitgtk_structs.c - $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk_structs.c -o webkit_structs.o - -webkit_stats.o: webkitgtk_stats.c webkitgtk_stats.h - $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk_stats.c -o webkit_stats.o +webkitgtk_structs.o: webkitgtk_structs.c + $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk_structs.c + +webkitgtk_stats.o: webkitgtk_stats.c webkitgtk_stats.h + $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk_stats.c + +webkitgtk_custom.o: webkitgtk_custom.c + $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk_custom.c # # GLX lib 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 87ead7f286..3947b5bfe3 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 @@ -1041,6 +1041,22 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1soup_1uri_1to_1string) } #endif +#ifndef NO__1swt_1webkit_1web_1view_1run_1javascript +JNIEXPORT jlong JNICALL WebKitGTK_NATIVE(_1swt_1webkit_1web_1view_1run_1javascript) + (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1) +{ + jbyte *lparg1=NULL; + jlong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1swt_1webkit_1web_1view_1run_1javascript_FUNC); + if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail; + rc = (jlong)swt_webkit_web_view_run_javascript(arg0, lparg1); +fail: + if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1swt_1webkit_1web_1view_1run_1javascript_FUNC); + return rc; +} +#endif + #ifndef NO__1webkit_1authentication_1request_1authenticate JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1webkit_1authentication_1request_1authenticate) (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1) diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.h b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.h index 8621fef9c3..00219cf811 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.h +++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.h @@ -12,7 +12,9 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ - + +/* Manually written code */ + #ifndef INC_webkitgtk_H #define INC_webkitgtk_H @@ -21,6 +23,9 @@ #include <stdlib.h> #include <glib-object.h> +// For JNI bindings in webkitgtk.c to properly link to custom functions: +#include "webkitgtk_custom.h" + #define WebKitGTK_LOAD_FUNCTION(var, name) \ static int initialized = 0; \ static void *var = NULL; \ diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_custom.c b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_custom.c new file mode 100644 index 0000000000..3b2f887377 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_custom.c @@ -0,0 +1,133 @@ +/******************************************************************************* +* Copyright (c) 2016 Red Hat, Inc. 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 +* available at http://www.gnu.org/licenses/lgpl.html. If the version +* of the LGPL at http://www.gnu.org is different to the version of +* the LGPL accompanying this distribution and there is any conflict +* between the two license versions, the terms of the LGPL accompanying +* this distribution shall govern. +* +* Contributors: +* Red Hat, Inc +*******************************************************************************/ + +/* Manually written code */ + +#include "webkitgtk_custom.h" +#include "webkitgtk.h" // For WebKitGTK_LOAD_FUNCTION macro +#include "swt.h" // For types like jintLong etc.. + +#include <gio/gio.h> // For things like GAsyncResult + + +// Note about webkit includes: +// Do not include things like '<webkit2/webkit2.h>' '<JavaScriptCore/JavaScript.h>' directly. +// All webkit functions must be loaded dynamically. +// If you compile on a newer Linux that contains Webkit2, trying to run the compiled binary on older +// OS's without webkit2 will lead to a crash even when they are running in 'Webkit1' mode. +// See Bug 430538. + + +/* + Calling JS script and getting return value example copied and adapted from: + https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html#webkit-web-view-run-javascript-finish +*/ +static void +web_view_javascript_finished_callback (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + + //// TODO handling of return value to be implemented in Stage 2. + //// All webkit functions will need to be called dynamically. +// WebKitJavascriptResult *js_result; +// JSValueRef value; +// JSGlobalContextRef context; +// GError *error = NULL; +// +// +// js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error); +// if (!js_result) { +// // Recoverable runtime error: +// g_warning ("webkitgtk_custom.c: Error running javascript(1): %s", error->message); +// g_error_free (error); +// } else { +// context = webkit_javascript_result_get_global_context (js_result); +// value = webkit_javascript_result_get_value (js_result); +// +// +//// // TODO WEBKIT2 - handle various return value(s). Starter code below. +// // Idea: create struct with pointer to return value and lock; +// // then pass it along via user_data. NOTE *malloc it* +// +// // Supress compiler warnings till return types implemented. +// (void) value; +// (void) context; +// +//// if (JSValueIsString (context, value)) { +//// JSStringRef js_str_value; +//// gchar *str_value; +//// gsize str_length; +//// +//// js_str_value = JSValueToStringCopy (context, value, NULL); +//// str_length = JSStringGetMaximumUTF8CStringSize (js_str_value); +//// str_value = (gchar *)g_malloc (str_length); +//// JSStringGetUTF8CString (js_str_value, str_value, str_length); +//// JSStringRelease (js_str_value); +//// g_print ("Script result: %s\n", str_value); +//// g_free (str_value); +//// +//// // else if JSValueIsBoolean +//// // else if JSValueIsNumber +//// // else if JSValueIsObject +//// // else if JSValueIsNull +//// // else if JSValueIsArray +//// // else if JSValueIsUndefined (?) +//// // else if JSValueIsDate (?) +//// } else { +//// g_warning ("webkitgtk_custom.c: Error running javascript(2): unexpected return value"); +//// } +// +// webkit_javascript_result_unref (js_result); +// } +// +// // Note about exit points: this function must unlock the spinlock prior to returning. +// // As such there should not be a 'return' in this function above the unlocking code + gboolean *JsCallFinished = (gboolean* ) user_data; + *JsCallFinished = TRUE; +} + + + +/* + * Type notes: + * [Java] -> [native] + * byte [] -> signed char *str + * long /int/ -> long +*/ +/** + * Convert the async function webkit_web_view_run_javascript(..) into a synchronous one + * by spinning until the callback is completed. + */ +long swt_webkit_web_view_run_javascript (long webkit_handle, signed char *script) { + + // TODO - WEBKIT2 port this will eventually be a struct that will hold the return value. + gboolean * JsCallFinished = g_new(gboolean, 1); //allocate 1 unit of gboolean (not assigning '1' to it). + *JsCallFinished = FALSE; + + // Macro usage copied and adjusted from webkitgtk.c's 'NO__1webkit_1web_1view_1run_1javascript' wrapper. + WebKitGTK_LOAD_FUNCTION(fp, webkit_web_view_run_javascript) + if (fp) { + ((void (CALLING_CONVENTION*)(jintLong, jbyte *, jintLong, jintLong, jintLong))fp)((jintLong) webkit_handle, script, (jintLong) 0, (jintLong) web_view_javascript_finished_callback, (jintLong) JsCallFinished); + } + + // Spin till callback completes. Note this spin is needed for 'callback' event to be called, otherwise we have a hang. + while (*JsCallFinished == FALSE) { + g_main_context_iteration(0, FALSE); + } + g_free(JsCallFinished); + + return 1; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_custom.h b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_custom.h new file mode 100644 index 0000000000..c220705b07 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_custom.h @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2016 Red Hat, Inc. 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 +* available at http://www.gnu.org/licenses/lgpl.html. If the version +* of the LGPL at http://www.gnu.org is different to the version of +* the LGPL accompanying this distribution and there is any conflict +* between the two license versions, the terms of the LGPL accompanying +* this distribution shall govern. +* +* Contributors: +* Red Hat, Inc +*******************************************************************************/ + +#ifndef INC_webkitgtk_custom_H +#define INC_webkitgtk_custom_H + +/* Manually written code */ + +long swt_webkit_web_view_run_javascript (long webkit_handle, signed char *script); + +#endif /*INC_webkit_custom_H*/ + 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 6d0961a560..0a8a44ae42 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 @@ -73,6 +73,7 @@ char * WebKitGTK_nativeFunctionNames[] = { "_1soup_1uri_1free", "_1soup_1uri_1new", "_1soup_1uri_1to_1string", + "_1swt_1webkit_1web_1view_1run_1javascript", "_1webkit_1authentication_1request_1authenticate", "_1webkit_1authentication_1request_1cancel", "_1webkit_1authentication_1request_1is_1retry", 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 a882b17f55..20502b0ba8 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 @@ -83,6 +83,7 @@ typedef enum { _1soup_1uri_1free_FUNC, _1soup_1uri_1new_FUNC, _1soup_1uri_1to_1string_FUNC, + _1swt_1webkit_1web_1view_1run_1javascript_FUNC, _1webkit_1authentication_1request_1authenticate_FUNC, _1webkit_1authentication_1request_1cancel_FUNC, _1webkit_1authentication_1request_1is_1retry_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 a4abe6e53f..a850e8da21 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 @@ -905,12 +905,11 @@ boolean close (boolean showPrompters) { public boolean execute (String script) { byte[] scriptBytes = (script + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$ - long /*int*/ result = 0; if (WEBKIT2){ - WebKitGTK.webkit_web_view_run_javascript (webView, scriptBytes, 0, 0, 0); - // TODO - this call is asynchronous, so no return vaulue. As result this call executes but - // returns false. Handling of return value to be implemented... + // Currently always returns 1 upon completion. + // TODO WEBKIT2 - modify webkitgtk_custom to return 0 if there is an error. + result = (int) WebKitGTK.swt_webkit_web_view_run_javascript(webView, scriptBytes); } else { long /*int*/ jsScriptString = WebKitGTK.JSStringCreateWithUTF8CString (scriptBytes); 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 98fe4e30d0..4e52d2db86 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 @@ -1675,4 +1675,15 @@ public static final long /*int*/ SoupMessage_request_headers (long /*int*/ messa } } +/* This custom function must only be called on Webkit2, use if (WEBKIT2) boolean. */ +public static final native long _swt_webkit_web_view_run_javascript (long /*int*/ webkit_handle, byte[] script); +public static final long swt_webkit_web_view_run_javascript (long /*int*/ webkit_handle, byte[] script) { + lock.lock(); + try { + return _swt_webkit_web_view_run_javascript (webkit_handle, script); + } finally { + lock.unlock(); + } +} + } |
