Bug 514719: [Browser][Webkit2] port Browser.getText() to webkit2

Webkit2 implementation of getText().

Implementation is similar to evaluate(), in that
it converts async call to sync by waiting for async callback.
It piggybacks on evaluate's async-callback framework. 

As both use the same framework, I abstracted the framework from
being specific to 'evaluate' to a generic 'asyncToSync'.

Test:
- Checkout this patch
- Cherry pick jUnit patch: (if not merged yet).
  https://git.eclipse.org/r/#/c/96984/
- Run Test_org_eclipse_swt_browser_Browser
- All newly added getText() jUnits pass on Webkit2.

Gtk3.22, Webkit2.16.1

Change-Id: I0a1d4e94b3a78abba4be9acb5a3f43311d023059
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=514719
Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
index 3b02d20..0252457 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
@@ -3295,6 +3295,30 @@
 }
 #endif
 
+#ifndef NO__1g_1string_1free
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1string_1free)
+	(JNIEnv *env, jclass that, jintLong arg0, jint arg1)
+{
+	jintLong rc = 0;
+	OS_NATIVE_ENTER(env, that, _1g_1string_1free_FUNC);
+	rc = (jintLong)g_string_free((GString *)arg0, arg1);
+	OS_NATIVE_EXIT(env, that, _1g_1string_1free_FUNC);
+	return rc;
+}
+#endif
+
+#ifndef NO__1g_1string_1new_1len
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1string_1new_1len)
+	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1)
+{
+	jintLong rc = 0;
+	OS_NATIVE_ENTER(env, that, _1g_1string_1new_1len_FUNC);
+	rc = (jintLong)g_string_new_len((const gchar *)arg0, arg1);
+	OS_NATIVE_EXIT(env, that, _1g_1string_1new_1len_FUNC);
+	return rc;
+}
+#endif
+
 #ifndef NO__1g_1strtod
 JNIEXPORT jdouble JNICALL OS_NATIVE(_1g_1strtod)
 	(JNIEnv *env, jclass that, jintLong arg0, jintLongArray arg1)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
index ba00715..58825ea 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
@@ -340,6 +340,8 @@
 	"_1g_1slist_1next",
 	"_1g_1source_1remove",
 	"_1g_1strfreev",
+	"_1g_1string_1free",
+	"_1g_1string_1new_1len",
 	"_1g_1strtod",
 	"_1g_1thread_1init",
 	"_1g_1thread_1supported",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
index bac729c..fbe46b3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
@@ -350,6 +350,8 @@
 	_1g_1slist_1next_FUNC,
 	_1g_1source_1remove_FUNC,
 	_1g_1strfreev_FUNC,
+	_1g_1string_1free_FUNC,
+	_1g_1string_1new_1len_FUNC,
 	_1g_1strtod_FUNC,
 	_1g_1thread_1init_FUNC,
 	_1g_1thread_1supported_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
index 2d1ab89..02bfaab 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
@@ -3052,6 +3052,35 @@
 		lock.unlock();
 	}
 }
+
+/**
+ * @param init cast=(const gchar *)
+ */
+public static final native long /*int*/ _g_string_new_len(long /*int*/ init, long /*int*/ gssize);
+/** 				   GString * g_string_new_len (const gchar *init, gssize len); */
+public static final long /*int*/ g_string_new_len(long /*int*/ init, long /*int*/ gssize) {
+	lock.lock();
+	try {
+		return _g_string_new_len(init, gssize);
+	} finally {
+		lock.unlock();
+	}
+}
+
+/**
+ * @param GString cast=(GString *)
+ */
+public static final native long /*int*/ _g_string_free(long /*int*/ GString, int gboolen_free_segment);
+/** 					 gchar * g_string_free (GString *string, gboolean free_segment);*/
+public static final long /*int*/ g_string_free(long /*int*/ GString, int gboolen_free_segment) {
+	lock.lock();
+	try {
+		return _g_string_free(GString, gboolen_free_segment);
+	} finally {
+		lock.unlock();
+	}
+}
+
 /**
  * @param str cast=(const gchar *)
  * @param endptr cast=(gchar **)
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 4155731..403f0f2 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
@@ -2456,6 +2456,51 @@
 }
 #endif
 
+#ifndef NO__1webkit_1web_1resource_1get_1data
+JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1webkit_1web_1resource_1get_1data)
+	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1, jintLong arg2, jintLong arg3)
+{
+	WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1resource_1get_1data_FUNC);
+/*
+	webkit_web_resource_get_data(arg0, arg1, arg2, arg3);
+*/
+	{
+		WebKitGTK_LOAD_FUNCTION(fp, webkit_web_resource_get_data)
+		if (fp) {
+			((void (CALLING_CONVENTION*)(jintLong, jintLong, jintLong, jintLong))fp)(arg0, arg1, arg2, arg3);
+		}
+	}
+	WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1resource_1get_1data_FUNC);
+}
+#endif
+
+#ifndef NO__1webkit_1web_1resource_1get_1data_1finish
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1resource_1get_1data_1finish)
+	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1, jintLongArray arg2, jintLongArray arg3)
+{
+	jintLong *lparg2=NULL;
+	jintLong *lparg3=NULL;
+	jintLong rc = 0;
+	WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1resource_1get_1data_1finish_FUNC);
+	if (arg2) if ((lparg2 = (*env)->GetIntLongArrayElements(env, arg2, NULL)) == NULL) goto fail;
+	if (arg3) if ((lparg3 = (*env)->GetIntLongArrayElements(env, arg3, NULL)) == NULL) goto fail;
+/*
+	rc = (jintLong)webkit_web_resource_get_data_finish(arg0, arg1, lparg2, lparg3);
+*/
+	{
+		WebKitGTK_LOAD_FUNCTION(fp, webkit_web_resource_get_data_finish)
+		if (fp) {
+			rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong, jintLong, jintLong *, jintLong *))fp)(arg0, arg1, lparg2, lparg3);
+		}
+	}
+fail:
+	if (arg3 && lparg3) (*env)->ReleaseIntLongArrayElements(env, arg3, lparg3, 0);
+	if (arg2 && lparg2) (*env)->ReleaseIntLongArrayElements(env, arg2, lparg2, 0);
+	WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1resource_1get_1data_1finish_FUNC);
+	return rc;
+}
+#endif
+
 #ifndef NO__1webkit_1web_1view_1can_1go_1back
 JNIEXPORT jint JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1can_1go_1back)
 	(JNIEnv *env, jclass that, jintLong arg0)
@@ -2618,6 +2663,26 @@
 }
 #endif
 
+#ifndef NO__1webkit_1web_1view_1get_1main_1resource
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1get_1main_1resource)
+	(JNIEnv *env, jclass that, jintLong arg0)
+{
+	jintLong rc = 0;
+	WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1view_1get_1main_1resource_FUNC);
+/*
+	rc = (jintLong)webkit_web_view_get_main_resource(arg0);
+*/
+	{
+		WebKitGTK_LOAD_FUNCTION(fp, webkit_web_view_get_main_resource)
+		if (fp) {
+			rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong))fp)(arg0);
+		}
+	}
+	WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1view_1get_1main_1resource_FUNC);
+	return rc;
+}
+#endif
+
 #ifndef NO__1webkit_1web_1view_1get_1progress
 JNIEXPORT jdouble JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1get_1progress)
 	(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 4de8d3f..95a2179 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
@@ -144,6 +144,8 @@
 	"_1webkit_1web_1frame_1get_1web_1view",
 	"_1webkit_1web_1policy_1decision_1download",
 	"_1webkit_1web_1policy_1decision_1ignore",
+	"_1webkit_1web_1resource_1get_1data",
+	"_1webkit_1web_1resource_1get_1data_1finish",
 	"_1webkit_1web_1view_1can_1go_1back",
 	"_1webkit_1web_1view_1can_1go_1forward",
 	"_1webkit_1web_1view_1can_1show_1mime_1type",
@@ -152,6 +154,7 @@
 	"_1webkit_1web_1view_1get_1estimated_1load_1progress",
 	"_1webkit_1web_1view_1get_1load_1status",
 	"_1webkit_1web_1view_1get_1main_1frame",
+	"_1webkit_1web_1view_1get_1main_1resource",
 	"_1webkit_1web_1view_1get_1progress",
 	"_1webkit_1web_1view_1get_1settings",
 	"_1webkit_1web_1view_1get_1title",
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 e5ca96d..5488aaf 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
@@ -154,6 +154,8 @@
 	_1webkit_1web_1frame_1get_1web_1view_FUNC,
 	_1webkit_1web_1policy_1decision_1download_FUNC,
 	_1webkit_1web_1policy_1decision_1ignore_FUNC,
+	_1webkit_1web_1resource_1get_1data_FUNC,
+	_1webkit_1web_1resource_1get_1data_1finish_FUNC,
 	_1webkit_1web_1view_1can_1go_1back_FUNC,
 	_1webkit_1web_1view_1can_1go_1forward_FUNC,
 	_1webkit_1web_1view_1can_1show_1mime_1type_FUNC,
@@ -162,6 +164,7 @@
 	_1webkit_1web_1view_1get_1estimated_1load_1progress_FUNC,
 	_1webkit_1web_1view_1get_1load_1status_FUNC,
 	_1webkit_1web_1view_1get_1main_1frame_FUNC,
+	_1webkit_1web_1view_1get_1main_1resource_FUNC,
 	_1webkit_1web_1view_1get_1progress_FUNC,
 	_1webkit_1web_1view_1get_1settings_FUNC,
 	_1webkit_1web_1view_1get_1title_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 07a7fc7..0891235 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
@@ -17,6 +17,7 @@
 import java.net.*;
 import java.nio.charset.*;
 import java.util.*;
+import java.util.function.*;
 
 import org.eclipse.swt.*;
 import org.eclipse.swt.graphics.*;
@@ -172,7 +173,7 @@
 			if (Proc6.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
 
 			if (WEBKIT2) {
-				new Webkit2JavascriptEvaluator();
+				new Webkit2AsyncToSync();
 			}
 
 			if (WEBKIT2) {
@@ -1161,21 +1162,24 @@
 }
 
 /**
- * Deals with evaluating Javascript in a webkit2 instance.
+ * Webkit2 introduces async api. However SWT has sync execution model. This class it to convert async api to sync.
  *
- * Javascript execution is asynchronous in webkit2, so we map each call
- * to it's callback and wait for callback to finish.
+ * The mechanism generates an ID for each callback and waits for that callback to complete.
  */
-private static class Webkit2JavascriptEvaluator {
+private static class Webkit2AsyncToSync {
 
-	private static Callback callback;
+	private static Callback evaluate_callback;
+	private static Callback getText_callback;
 	static {
-		callback = new Callback(Webkit2JavascriptEvaluator.class, "javascriptExecutionFinishedProc", void.class, new Type[] {long.class, long.class, long.class});
-		if (callback.getAddress() == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+		evaluate_callback = new Callback(Webkit2AsyncToSync.class, "evaluate_callback", void.class, new Type[] {long.class, long.class, long.class});
+		if (evaluate_callback.getAddress() == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+		getText_callback = new Callback(Webkit2AsyncToSync.class, "getText_callback", void.class, new Type[] {long.class, long.class, long.class});
+		if (getText_callback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
 	}
 
-	/** Object used to pass data from callback back to caller of evaluate() */
-	private static class Webkit2EvalReturnObj {
+	/** Object used to return data from callback to original call */
+	private static class Webkit2AsyncReturnObj {
 		boolean callbackFinished = false;
 		Object returnValue;
 
@@ -1198,14 +1202,14 @@
 	 * org.eclipse.swt.tests.junit.Test_org_eclipse_swt_browser_Browser.test_execute_and_closeListener()
 	 */
 	private static class CallBackMap {
-		private static HashMap<Integer, Webkit2EvalReturnObj> callbackMap = new HashMap<>();
+		private static HashMap<Integer, Webkit2AsyncReturnObj> callbackMap = new HashMap<>();
 
-		static int putObject(Webkit2EvalReturnObj obj) {
+		static int putObject(Webkit2AsyncReturnObj obj) {
 			int id = getNextId();
 			callbackMap.put(id, obj);
 			return id;
 		}
-		static Webkit2EvalReturnObj getObj(int id) {
+		static Webkit2AsyncReturnObj getObj(int id) {
 			return callbackMap.get(id);
 		}
 		static void removeObject(int id) {
@@ -1254,20 +1258,10 @@
 			return null;
 		} else {
 			// Callback logic: Initiate an async callback and wait for it to finish.
-			// The callback comes back in javascriptExecutionFinishedProc(..) below.
-			Webkit2EvalReturnObj retObj = new Webkit2EvalReturnObj();
-			int callbackId = CallBackMap.putObject(retObj);
-			WebKitGTK.webkit_web_view_run_javascript(webView, Converter.wcsToMbcs(fixedScript, true), 0, callback.getAddress(), callbackId);
-			Shell shell = browser.getShell();
-			Display display = browser.getDisplay();
-			while (!shell.isDisposed()) {
-				boolean eventsDispatched = OS.g_main_context_iteration (0, false);
-				if (retObj.callbackFinished)
-					break;
-				else if (!eventsDispatched)
-					display.sleep();
-			}
-			CallBackMap.removeObject(callbackId);
+			// The callback comes back in evaluate_callback(..) below.
+
+			Consumer <Integer> asyncFunc = (callbackId) -> WebKitGTK.webkit_web_view_run_javascript(webView, Converter.wcsToMbcs(fixedScript, true), 0, evaluate_callback.getAddress(), callbackId);
+			Webkit2AsyncReturnObj retObj = execAsyncAndWaitForReturn(browser, asyncFunc);
 
 			if (retObj.errorNum != 0) {
 				throw new SWTException(retObj.errorNum, retObj.errorMsg);
@@ -1277,11 +1271,10 @@
 		}
 	}
 
-	/** Callback that is called directly from Javascirpt. **/
-	@SuppressWarnings("unused")
-	private static void javascriptExecutionFinishedProc (long /*int*/ GObject_source, long /*int*/ GAsyncResult, long /*int*/ user_data) {
+	@SuppressWarnings("unused") // Only called directly from C (from javascript).
+	private static void evaluate_callback (long /*int*/ GObject_source, long /*int*/ GAsyncResult, long /*int*/ user_data) {
 		int callbackId = (int) user_data;
-		Webkit2EvalReturnObj retObj = CallBackMap.getObj(callbackId);
+		Webkit2AsyncReturnObj retObj = CallBackMap.getObj(callbackId);
 
 		long /*int*/[] gerror = new long /*int*/ [1]; // GError **
 		long /*int*/ js_result = WebKitGTK.webkit_web_view_run_javascript_finish(GObject_source, GAsyncResult, gerror);
@@ -1308,6 +1301,58 @@
 		retObj.callbackFinished = true;
 		Display.getCurrent().wake();
 	}
+
+	static String getText(Browser browser, long /*int*/ webView) {
+		long /*int*/ WebKitWebResource = WebKitGTK.webkit_web_view_get_main_resource(webView);
+		if (WebKitWebResource == 0) { // No page yet loaded.
+			return "";
+		}
+
+		Consumer<Integer> asyncFunc = (callbackId) -> WebKitGTK.webkit_web_resource_get_data(WebKitWebResource, 0, getText_callback.getAddress(), callbackId);
+		Webkit2AsyncReturnObj retObj = execAsyncAndWaitForReturn(browser, asyncFunc);
+
+		return (String) retObj.returnValue;
+	}
+
+	@SuppressWarnings("unused") // Callback only called only by C directly
+	private static void getText_callback(long /*int*/ WebResource, long /*int*/ GAsyncResult, long /*int*/ user_data) {
+		int callbackId = (int) user_data;
+		Webkit2AsyncReturnObj retObj = CallBackMap.getObj(callbackId);
+
+		long /*int*/[] gsize_len = new long /*int*/ [1];
+		long /*int*/[] gerrorRes = new long /*int*/ [1]; // GError **
+		long /*int*/ guchar_data = WebKitGTK.webkit_web_resource_get_data_finish(WebResource, GAsyncResult, gsize_len, gerrorRes);
+		if (gerrorRes[0] != 0 || guchar_data == 0) {
+			OS.g_error_free(gerrorRes[0]);
+			retObj.returnValue = (String) "";
+		} else {
+			long /*int*/ GString;
+			GString = OS.g_string_new_len(guchar_data, gsize_len[0]); //(Str + len) -> (null terminated str)
+			String text = Converter.cCharPtrToJavaString(OS.GString_str(GString), false);
+			OS.g_string_free(GString, 1);
+			retObj.returnValue = (String) text;
+		}
+
+		retObj.callbackFinished = true;
+		Display.getCurrent().wake();
+	}
+
+	private static Webkit2AsyncReturnObj execAsyncAndWaitForReturn(Browser browser, Consumer<Integer> asyncFunc) {
+		Webkit2AsyncReturnObj retObj = new Webkit2AsyncReturnObj();
+		int callbackId = CallBackMap.putObject(retObj);
+		asyncFunc.accept(callbackId);
+		Shell shell = browser.getShell();
+		Display display = browser.getDisplay();
+		while (!shell.isDisposed()) {
+			boolean eventsDispatched = OS.g_main_context_iteration (0, false);
+			if (retObj.callbackFinished)
+				break;
+			else if (!eventsDispatched)
+				display.sleep();
+		}
+		CallBackMap.removeObject(callbackId);
+		return retObj;
+	}
 }
 
 @Override
@@ -1321,7 +1366,7 @@
         	return null;
         }
 		boolean doNotBlock = nonBlockingEvaluate > 0 ? true : false;
-		return Webkit2JavascriptEvaluator.evaluate(script, this.browser, webView, doNotBlock);
+		return Webkit2AsyncToSync.evaluate(script, this.browser, webView, doNotBlock);
 	} else {
 		return super.evaluate(script);
 	}
@@ -1341,28 +1386,33 @@
 
 @Override
 public String getText () {
-	long /*int*/ frame = WebKitGTK.webkit_web_view_get_main_frame (webView);
-	long /*int*/ source = WebKitGTK.webkit_web_frame_get_data_source (frame);
-	if (source == 0) return "";	//$NON-NLS-1$
-	long /*int*/ data = WebKitGTK.webkit_web_data_source_get_data (source);
-	if (data == 0) return "";	//$NON-NLS-1$
+	if (WEBKIT2) {
+		return Webkit2AsyncToSync.getText(browser, webView);
+	} else  {
+		// Webkit1 only.
+		long /*int*/ frame = WebKitGTK.webkit_web_view_get_main_frame (webView);
+		long /*int*/ source = WebKitGTK.webkit_web_frame_get_data_source (frame);
+		if (source == 0) return "";	//$NON-NLS-1$
+		long /*int*/ data = WebKitGTK.webkit_web_data_source_get_data (source);
+		if (data == 0) return "";	//$NON-NLS-1$
 
-	long /*int*/ encoding = WebKitGTK.webkit_web_data_source_get_encoding (source);
-	int length = OS.strlen (encoding);
-	byte[] bytes = new byte [length];
-	OS.memmove (bytes, encoding, length);
-	String encodingString = new String (Converter.mbcsToWcs (bytes));
+		long /*int*/ encoding = WebKitGTK.webkit_web_data_source_get_encoding (source);
+		int length = OS.strlen (encoding);
+		byte[] bytes = new byte [length];
+		OS.memmove (bytes, encoding, length);
+		String encodingString = new String (Converter.mbcsToWcs (bytes));
 
-	length = OS.GString_len (data);
-	bytes = new byte[length];
-	long /*int*/ string = OS.GString_str (data);
-	C.memmove (bytes, string, length);
+		length = OS.GString_len (data);
+		bytes = new byte[length];
+		long /*int*/ string = OS.GString_str (data);
+		C.memmove (bytes, string, length);
 
-	try {
-		return new String (bytes, encodingString);
-	} catch (UnsupportedEncodingException e) {
+		try {
+			return new String (bytes, encodingString);
+		} catch (UnsupportedEncodingException e) {
+		}
+		return new String (Converter.mbcsToWcs (bytes));
 	}
-	return new String (Converter.mbcsToWcs (bytes));
 }
 
 @Override
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 29496e4..0518142 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
@@ -78,10 +78,10 @@
 	/** Webkit1 only. On webkit2 & newer browsers 'window.status=txt' has no effect anymore.
 	 *  Status bar only updated when you hover mouse over hyperlink.*/
 	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$	// Webkit1
 	public static final byte[] ready_to_show = ascii ("ready-to-show"); // $NON-NLS-1$		// Webkit2
-	
+
 	/** 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$
 
@@ -1335,6 +1335,17 @@
 }
 
 /** @method flags=dynamic */
+public static final native long /*int*/ _webkit_web_view_get_main_resource (long /*int*/ web_view);
+public static final long /*int*/ webkit_web_view_get_main_resource (long /*int*/ web_view) {
+	lock.lock();
+	try {
+		return _webkit_web_view_get_main_resource (web_view);
+	} finally {
+		lock.unlock();
+	}
+}
+
+/** @method flags=dynamic */
 public static final native int _webkit_web_view_can_go_forward (long /*int*/ web_view);
 public static final int webkit_web_view_can_go_forward (long /*int*/ web_view) {
 	lock.lock();
@@ -1672,6 +1683,29 @@
 	}
 }
 
+/** @method flags=dynamic */
+public static final native void _webkit_web_resource_get_data (long /*int*/ webKitWebResource, long /*int*/ gCancellable, long /*int*/ GAsyncReadyCallback, long /*int*/ user_data);
+public static final void webkit_web_resource_get_data (long /*int*/ webKitWebResource, long /*int*/ gCancellable, long /*int*/ GAsyncReadyCallback, long /*int*/ user_data) {
+	lock.lock();
+	try {
+		_webkit_web_resource_get_data (webKitWebResource, gCancellable, GAsyncReadyCallback, user_data);
+	} finally {
+		lock.unlock();
+	}
+}
+
+/** @method flags=dynamic */
+public static final native long /*int*/ _webkit_web_resource_get_data_finish(long /*int*/ WebKitWebResource, long /*int*/ GAsyncResult, long /*int*/[] gsize, long /*int*/ GError[]);
+public static final long /*int*/ webkit_web_resource_get_data_finish(long /*int*/ WebKitWebResource, long /*int*/ GAsyncResult, long /*int*/[] gsize, long /*int*/ GError[]) {
+	lock.lock();
+	try {
+		return _webkit_web_resource_get_data_finish(WebKitWebResource, GAsyncResult, gsize, GError);
+	} finally {
+		lock.unlock();
+	}
+}
+
+
 /**
  * @method flags=dynamic
  * @param gerror cast=(GError **)