]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/WebKit.java
Merge branch 'bug-623' into release/1.43.0
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / browser / WebKit.java
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/WebKit.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/WebKit.java
new file mode 100644 (file)
index 0000000..e935db2
--- /dev/null
@@ -0,0 +1,1310 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+
+import java.io.*;
+import java.net.*;
+import java.nio.charset.*;
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.webkit.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+class WebKit extends WebBrowser {
+       IWebView webView;
+       long webViewWindowHandle, webViewData;
+       int refCount = 0;
+       int lastKeyCode, lastCharCode;
+
+       WebDownloadDelegate webDownloadDelegate;
+       WebFrameLoadDelegate webFrameLoadDelegate;
+       WebPolicyDelegate webPolicyDelegate;
+       WebResourceLoadDelegate webResourceLoadDelegate;
+       WebUIDelegate webUIDelegate;
+
+       boolean ignoreDispose;
+       boolean loadingText = false;
+       boolean traverseNext = true;
+       boolean traverseOut = false;
+       boolean untrustedText;
+       String lastNavigateURL;
+       BrowserFunction eventFunction;
+
+       static int prefsIdentifier;
+       static long ExternalClass;
+       static boolean LibraryLoaded = false;
+       static String LibraryLoadError;
+       static Callback JSObjectHasPropertyProc;
+       static Callback JSObjectGetPropertyProc;
+       static Callback JSObjectCallAsFunctionProc;
+       static final int MAX_PROGRESS = 100;
+       static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
+       static final String CLASSNAME_EXTERNAL = "External"; //$NON-NLS-1$
+       static final String EMPTY_STRING = ""; //$NON-NLS-1$
+       static final String FUNCTIONNAME_CALLJAVA = "callJava"; //$NON-NLS-1$
+       static final String HEADER_SETCOOKIE = "Set-Cookie"; //$NON-NLS-1$
+       static final String POST = "POST"; //$NON-NLS-1$
+       static final String PROPERTY_LENGTH = "length"; //$NON-NLS-1$
+       static final String PROTOCOL_HTTPS = "https://"; //$NON-NLS-1$
+       static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
+       static final String PROTOCOL_HTTP = "http://"; //$NON-NLS-1$
+       static final String USER_AGENT = "user-agent"; //$NON-NLS-1$
+       static final String URI_FILEROOT = "file:///"; //$NON-NLS-1$
+
+       /* event strings */
+       static final String DOMEVENT_DRAGSTART = "dragstart"; //$NON-NLS-1$
+       static final String DOMEVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
+       static final String DOMEVENT_KEYPRESS = "keypress"; //$NON-NLS-1$
+       static final String DOMEVENT_KEYUP = "keyup"; //$NON-NLS-1$
+       static final String DOMEVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
+       static final String DOMEVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
+       static final String DOMEVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
+       static final String DOMEVENT_MOUSEOUT = "mouseout"; //$NON-NLS-1$
+       static final String DOMEVENT_MOUSEOVER = "mouseover"; //$NON-NLS-1$
+       static final String DOMEVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
+
+static {
+       /*
+       * Attempt to load the swt-webkit library.  This will only succeed if the Apple
+       * Application Support package is on the user's Windows Path environment variable.
+       */
+       try {
+               Library.loadLibrary ("swt-webkit"); // $NON-NLS-1$
+               LibraryLoaded = true;
+       } catch (Throwable e) {
+       }
+
+       /*
+       * If needed, add the Apple Application Support package's directory to the library
+       * lookup path and try to load the swt-webkit library again.
+       */
+       if (!LibraryLoaded) {
+               /*
+                * Locate the Apple Application Support directory (if installed) and add its path to the library lookup path.
+                *
+                * As of Safari 5.1.4, the Apple Application Support directory is in the Safari installation directory,
+                * which is pointed to by registry entry "HKEY_LOCAL_MACHINE\SOFTWARE\Apple Computer, Inc.\Safari".
+                *
+                * With earlier versions of Safari the Apple Application Support is installed in a stand-alone location, which
+                * is pointed to by registry entry "HKEY_LOCAL_MACHINE\SOFTWARE\Apple Inc.\Apple Application Support\InstallDir".
+                */
+
+               String AASDirectory = readInstallDir ("SOFTWARE\\Apple Computer, Inc.\\Safari"); //$NON-NLS-1$
+               if (AASDirectory != null) {
+                       AASDirectory += "\\Apple Application Support"; //$NON-NLS-1$
+                       if (!new File(AASDirectory).exists()) {
+                               AASDirectory = null;
+                       }
+               }
+
+               if (AASDirectory == null) {
+                       AASDirectory = readInstallDir ("SOFTWARE\\Apple Inc.\\Apple Application Support"); //$NON-NLS-1$
+               }
+
+               if (AASDirectory != null) {
+                       TCHAR buffer = new TCHAR (0, AASDirectory, true);
+                       boolean success = OS.SetDllDirectory (buffer); /* should succeed on XP+SP1 and newer */
+                       if (success) {
+                               try {
+                                       Library.loadLibrary ("swt-webkit"); //$NON-NLS-1$
+                                       LibraryLoaded = true;
+                               } catch (Throwable e) {
+                                       LibraryLoadError = "Failed to load the swt-webkit library"; //$NON-NLS-1$
+                                       if (Device.DEBUG) System.out.println ("Failed to load swt-webkit library. Apple Application Support directory path: " + AASDirectory); //$NON-NLS-1$
+                               }
+                       } else {
+                               LibraryLoadError = "Failed to add the Apple Application Support package to the library lookup path.  "; //$NON-NLS-1$
+                               LibraryLoadError += "To use a SWT.WEBKIT-style Browser prepend " + AASDirectory + " to your Windows 'Path' environment variable and restart."; //$NON-NLS-1$ //$NON-NLS-2$
+                       }
+               } else {
+                       LibraryLoadError = "Safari must be installed to use a SWT.WEBKIT-style Browser"; //$NON-NLS-1$
+               }
+       }
+
+       if (LibraryLoaded) {
+               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);
+
+               NativeClearSessions = () -> {
+                       long[] result = new long[1];
+                       int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebCookieManager, 0, WebKit_win32.IID_IWebCookieManager, result);
+                       if (hr != COM.S_OK || result[0] == 0) {
+                               return;
+                       }
+                       IWebCookieManager cookieManager = new IWebCookieManager (result[0]);
+                       long[] storage = new long[1];
+                       hr = cookieManager.cookieStorage (storage);
+                       cookieManager.Release ();
+                       if (hr != COM.S_OK || storage[0] == 0) {
+                               return;
+                       }
+                       long cookies = WebKit_win32.CFHTTPCookieStorageCopyCookies (storage[0]);
+                       if (cookies != 0) {
+                               int count = WebKit_win32.CFArrayGetCount (cookies);
+                               for (int i = 0; i < count; i++) {
+                                       long cookie = WebKit_win32.CFArrayGetValueAtIndex (cookies, i);
+                                       long flags = WebKit_win32.CFHTTPCookieGetFlags (cookie);
+                                       if ((flags & WebKit_win32.CFHTTPCookieSessionOnlyFlag) != 0) {
+                                               WebKit_win32.CFHTTPCookieStorageDeleteCookie (storage[0], cookie);
+                                       }
+                               }
+                               WebKit_win32.CFRelease (cookies);
+                       }
+                       // WebKit_win32.CFRelease (storage[0]); //intentionally commented, causes crash
+               };
+
+               NativeGetCookie = () -> {
+                       long[] result = new long[1];
+                       int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebCookieManager, 0, WebKit_win32.IID_IWebCookieManager, result);
+                       if (hr != COM.S_OK || result[0] == 0) {
+                               return;
+                       }
+                       IWebCookieManager cookieManager = new IWebCookieManager (result[0]);
+                       long[] storage = new long[1];
+                       hr = cookieManager.cookieStorage (storage);
+                       cookieManager.Release ();
+                       if (hr != COM.S_OK || storage[0] == 0) {
+                               return;
+                       }
+                       char[] chars = CookieUrl.toCharArray ();
+                       long string = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
+                       if (string != 0) {
+                               long cfUrl = WebKit_win32.CFURLCreateWithString (0, string, 0);
+                               if (cfUrl != 0) {
+                                       boolean secure = CookieUrl.startsWith (PROTOCOL_HTTPS);
+                                       long cookiesArray = WebKit_win32.CFHTTPCookieStorageCopyCookiesForURL (storage[0], cfUrl, secure);
+                                       if (cookiesArray != 0) {
+                                               int count = WebKit_win32.CFArrayGetCount (cookiesArray);
+                                               for (int i = 0; i < count; i++) {
+                                                       long cookie = WebKit_win32.CFArrayGetValueAtIndex (cookiesArray, i);
+                                                       if (cookie != 0) {
+                                                               long cookieName = WebKit_win32.CFHTTPCookieGetName (cookie);
+                                                               if (cookieName != 0) {
+                                                                       String name = stringFromCFString (cookieName);
+                                                                       if (CookieName.equals (name)) {
+                                                                               long value = WebKit_win32.CFHTTPCookieGetValue (cookie);
+                                                                               if (value != 0) CookieValue = stringFromCFString (value);
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               WebKit_win32.CFRelease (cookiesArray);
+                                       }
+                                       WebKit_win32.CFRelease (cfUrl);
+                               }
+                               WebKit_win32.CFRelease (string);
+                       }
+                       // WebKit_win32.CFRelease (storage[0]); //intentionally commented, causes crash
+               };
+
+               NativeSetCookie = () -> {
+                       long[] result = new long[1];
+                       int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebCookieManager, 0, WebKit_win32.IID_IWebCookieManager, result);
+                       if (hr != COM.S_OK || result[0] == 0) {
+                               return;
+                       }
+                       IWebCookieManager cookieManager = new IWebCookieManager (result[0]);
+                       long[] storage = new long[1];
+                       hr = cookieManager.cookieStorage (storage);
+                       cookieManager.Release ();
+                       if (hr != COM.S_OK || storage[0] == 0) {
+                               return;
+                       }
+
+                       char[] chars = CookieUrl.toCharArray ();
+                       long string = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
+                       if (string != 0) {
+                               long cfUrl = WebKit_win32.CFURLCreateWithString (0, string, 0);
+                               if (cfUrl != 0) {
+                                       chars = CookieValue.toCharArray ();
+                                       long value = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
+                                       if (value != 0) {
+                                               chars = HEADER_SETCOOKIE.toCharArray ();
+                                               long key = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
+                                               if (key != 0) {
+                                                       long headers = WebKit_win32.CFDictionaryCreate (0, new long[] {key}, new long[] {value}, 1, WebKit_win32.kCFCopyStringDictionaryKeyCallBacks (), WebKit_win32.kCFTypeDictionaryValueCallBacks ());
+                                                       if (headers != 0) {
+                                                               long cookies = WebKit_win32.CFHTTPCookieCreateWithResponseHeaderFields (0, headers, cfUrl);
+                                                               if (cookies != 0) {
+                                                                       long cookie = WebKit_win32.CFArrayGetValueAtIndex (cookies, 0);
+                                                                       if (cookie != 0) {
+                                                                               WebKit_win32.CFHTTPCookieStorageSetCookie (storage[0], cookie);
+                                                                               CookieResult = true;
+                                                                       }
+                                                                       WebKit_win32.CFRelease (cookies);
+                                                               }
+                                                               WebKit_win32.CFRelease (headers);
+                                                       }
+                                                       WebKit_win32.CFRelease (key);
+                                               }
+                                               WebKit_win32.CFRelease (value);
+                                       }
+                                       WebKit_win32.CFRelease (cfUrl);
+                               }
+                               WebKit_win32.CFRelease (string);
+                       }
+                       // WebKit_win32.CFRelease (storage[0]); //intentionally commented, causes crash
+               };
+
+               if (NativePendingCookies != null) {
+                       SetPendingCookies (NativePendingCookies);
+               }
+               NativePendingCookies = null;
+       }
+}
+
+static long createBSTR (String string) {
+       char[] data = (string + '\0').toCharArray ();
+       return COM.SysAllocString (data);
+}
+
+static String error (int code) {
+       throw new SWTError ("WebKit error " + code); //$NON-NLS-1$
+}
+
+static String extractBSTR (long bstrString) {
+       int size = COM.SysStringByteLen (bstrString);
+       if (size == 0) return EMPTY_STRING;
+       char[] buffer = new char[(size + 1) / 2]; // add one to avoid rounding errors
+       OS.MoveMemory (buffer, bstrString, size);
+       return new String (buffer);
+}
+
+static Browser findBrowser (long webView) {
+       if (webView == 0) return null;
+       IWebView iwebView = new IWebView (webView);
+       long[] result = new long[1];
+       int hr = iwebView.hostWindow (result);
+       if (hr == COM.S_OK && result[0] != 0) {
+               Widget widget = Display.getCurrent ().findWidget (result[0]);
+               if (widget != null && widget instanceof Browser) return (Browser)widget;
+       }
+       return null;
+}
+
+static long JSObjectCallAsFunctionProc (long ctx, long function, long thisObject, long argumentCount, long arguments, long exception) {
+       WebKit_win32.JSGlobalContextRetain (ctx);
+       if (WebKit_win32.JSValueIsObjectOfClass (ctx, thisObject, ExternalClass) == 0) {
+               return WebKit_win32.JSValueMakeUndefined (ctx);
+       }
+       long ptr = WebKit_win32.JSObjectGetPrivate (thisObject);
+       long[] handle = new long[1];
+       C.memmove (handle, ptr, C.PTR_SIZEOF);
+       Browser browser = findBrowser (handle[0]);
+       if (browser == null) return WebKit_win32.JSValueMakeUndefined (ctx);
+       WebKit webkit = (WebKit)browser.webBrowser;
+       return webkit.callJava (ctx, function, thisObject, argumentCount, arguments, exception);
+}
+
+static long JSObjectGetPropertyProc (long ctx, long object, long propertyName, long exception) {
+       byte[] bytes = (FUNCTIONNAME_CALLJAVA + '\0').getBytes (StandardCharsets.UTF_8);
+       long name = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
+       long addr = WebKit_win32.JSObjectCallAsFunctionProc_CALLBACK (WebKit.JSObjectCallAsFunctionProc.getAddress ());
+       long function = WebKit_win32.JSObjectMakeFunctionWithCallback (ctx, name, addr);
+       WebKit_win32.JSStringRelease (name);
+       return function;
+}
+
+static long JSObjectHasPropertyProc (long ctx, long object, long propertyName) {
+       byte[] bytes = (FUNCTIONNAME_CALLJAVA + '\0').getBytes (StandardCharsets.UTF_8);
+       return WebKit_win32.JSStringIsEqualToUTF8CString (propertyName, bytes);
+}
+
+static String readInstallDir (String keyString) {
+       long[] phkResult = new long[1];
+       TCHAR key = new TCHAR (0, keyString, true);
+       if (OS.RegOpenKeyEx (OS.HKEY_LOCAL_MACHINE, key, 0, OS.KEY_READ, phkResult) == 0) {
+               int[] lpcbData = new int[1];
+               TCHAR buffer = new TCHAR (0, "InstallDir", true); //$NON-NLS-1$
+               int result = OS.RegQueryValueEx (phkResult[0], buffer, 0, null, (TCHAR)null, lpcbData);
+               if (result == 0) {
+                       TCHAR lpData = new TCHAR (0, lpcbData[0] / TCHAR.sizeof);
+                       result = OS.RegQueryValueEx (phkResult[0], buffer, 0, null, lpData, lpcbData);
+                       if (result == 0) {
+                               OS.RegCloseKey (phkResult[0]);
+                               return lpData.toString (0, lpData.strlen ());
+                       }
+               }
+               OS.RegCloseKey (phkResult[0]);
+       }
+       return null;
+}
+
+static String stringFromCFString (long cfString) {
+       if (cfString == 0) return null;
+       int length = WebKit_win32.CFStringGetLength (cfString);
+       long ptr = WebKit_win32.CFStringGetCharactersPtr (cfString);
+       char[] chars = new char[length];
+       if (ptr != 0) {
+               OS.MoveMemory (chars, ptr, length);
+       } else {
+               for (int j = 0; j < length; j++) {
+                       chars[j] = WebKit_win32.CFStringGetCharacterAtIndex (cfString, j);
+               }
+       }
+       return new String (chars);
+}
+
+static String stringFromJSString (long jsString) {
+       if (jsString == 0) return null;
+       int length = WebKit_win32.JSStringGetLength (jsString);
+       byte[] bytes = new byte[length + 1];
+       WebKit_win32.JSStringGetUTF8CString (jsString, bytes, length + 1);
+       return new String (bytes);
+}
+
+@Override
+public boolean back () {
+       int[] result = new int[1];
+       webView.goBack (result);
+       return result[0] != 0;
+}
+
+long callJava (long ctx, long func, long thisObject, long argumentCount, long arguments, long exception) {
+       Object returnValue = null;
+       if (argumentCount == 3) {
+               long[] result = new long[1];
+               C.memmove (result, arguments, C.PTR_SIZEOF);
+               int type = WebKit_win32.JSValueGetType (ctx, result[0]);
+               if (type == WebKit_win32.kJSTypeNumber) {
+                       int index = ((Double)convertToJava (ctx, result[0])).intValue ();
+                       result[0] = 0;
+                       if (index > 0) {
+                               C.memmove (result, arguments + C.PTR_SIZEOF, C.PTR_SIZEOF);
+                               type = WebKit_win32.JSValueGetType (ctx, result[0]);
+                               if (type == WebKit_win32.kJSTypeString) {
+                                       String token = (String)convertToJava (ctx, result[0]);
+                                       BrowserFunction function = (BrowserFunction)functions.get (index);
+                                       if (function != null && token.equals (function.token)) {
+                                               try {
+                                                       C.memmove (result, arguments + 2 * C.PTR_SIZEOF, C.PTR_SIZEOF);
+                                                       Object temp = convertToJava (ctx, result[0]);
+                                                       if (temp instanceof Object[]) {
+                                                               Object[] args = (Object[])temp;
+                                                               try {
+                                                                       returnValue = function.function (args);
+                                                               } catch (Exception e) {
+                                                                       /* exception during function invocation */
+                                                                       returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+                                                               }
+                                                       }
+                                               } catch (IllegalArgumentException e) {
+                                                       /* invalid argument value type */
+                                                       if (function.isEvaluate) {
+                                                               /* notify the function so that a java exception can be thrown */
+                                                               function.function (new String[] {WebBrowser.CreateErrorString (new SWTException (SWT.ERROR_INVALID_RETURN_VALUE).getLocalizedMessage ())});
+                                                       }
+                                                       returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       return convertToJS (ctx, returnValue);
+}
+
+@Override
+public boolean close () {
+       return shouldClose ();
+}
+
+Object convertToJava (long ctx, long value) {
+       int type = WebKit_win32.JSValueGetType (ctx, value);
+       switch (type) {
+               case WebKit_win32.kJSTypeBoolean: {
+                       int result = (int)WebKit_win32.JSValueToNumber (ctx, value, null);
+                       return result != 0;
+               }
+               case WebKit_win32.kJSTypeNumber: {
+                       double result = WebKit_win32.JSValueToNumber (ctx, value, null);
+                       return result;
+               }
+               case WebKit_win32.kJSTypeString: {
+                       long string = WebKit_win32.JSValueToStringCopy (ctx, value, null);
+                       if (string == 0) return ""; //$NON-NLS-1$
+                       long length = WebKit_win32.JSStringGetMaximumUTF8CStringSize (string);
+                       byte[] bytes = new byte[(int)length];
+                       length = WebKit_win32.JSStringGetUTF8CString (string, bytes, length);
+                       WebKit_win32.JSStringRelease (string);
+                       /* length-1 is needed below to exclude the terminator character */
+                       return new String (bytes, 0, (int)length - 1, StandardCharsets.UTF_8);
+               }
+               case WebKit_win32.kJSTypeNull:
+                       // FALL THROUGH
+               case WebKit_win32.kJSTypeUndefined: return null;
+               case WebKit_win32.kJSTypeObject: {
+                       byte[] bytes = (PROPERTY_LENGTH + '\0').getBytes (StandardCharsets.UTF_8);
+                       long propertyName = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
+                       long valuePtr = WebKit_win32.JSObjectGetProperty (ctx, value, propertyName, null);
+                       WebKit_win32.JSStringRelease (propertyName);
+                       type = WebKit_win32.JSValueGetType (ctx, valuePtr);
+                       if (type == WebKit_win32.kJSTypeNumber) {
+                               int length = (int)WebKit_win32.JSValueToNumber (ctx, valuePtr, null);
+                               Object[] result = new Object[length];
+                               for (int i = 0; i < length; i++) {
+                                       long current = WebKit_win32.JSObjectGetPropertyAtIndex (ctx, value, i, null);
+                                       if (current != 0) {
+                                               result[i] = convertToJava (ctx, current);
+                                       }
+                               }
+                               return result;
+                       }
+               }
+       }
+       SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+       return null;
+}
+
+long convertToJS (long ctx, Object value) {
+       if (value == null) {
+               return WebKit_win32.JSValueMakeNull (ctx);
+       }
+       if (value instanceof String) {
+               byte[] bytes = ((String)value + '\0').getBytes (StandardCharsets.UTF_8);
+               long stringRef = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
+               long result = WebKit_win32.JSValueMakeString (ctx, stringRef);
+               WebKit_win32.JSStringRelease (stringRef);
+               return result;
+       }
+       if (value instanceof Boolean) {
+               return WebKit_win32.JSValueMakeBoolean (ctx, ((Boolean)value).booleanValue () ? 1 : 0);
+       }
+       if (value instanceof Number) {
+               return WebKit_win32.JSValueMakeNumber (ctx, ((Number)value).doubleValue ());
+       }
+       if (value instanceof Object[]) {
+               Object[] arrayValue = (Object[]) value;
+               int length = arrayValue.length;
+               long[] arguments = new long[length];
+               for (int i = 0; i < length; i++) {
+                       Object javaObject = arrayValue[i];
+                       long jsObject = convertToJS (ctx, javaObject);
+                       arguments[i] = jsObject;
+               }
+               return WebKit_win32.JSObjectMakeArray (ctx, length, arguments, null);
+       }
+       SWT.error (SWT.ERROR_INVALID_RETURN_VALUE);
+       return 0;
+}
+
+@Override
+public void create (Composite parent, int style) {
+       if (!LibraryLoaded) {
+               browser.dispose ();
+               SWT.error (SWT.ERROR_NO_HANDLES, null, LibraryLoadError == null ? null : " [" + LibraryLoadError + ']'); //$NON-NLS-1$
+       }
+
+       if (ExternalClass == 0) {
+               JSClassDefinition jsClassDefinition = new JSClassDefinition ();
+               byte[] bytes = (CLASSNAME_EXTERNAL + '\0').getBytes ();
+               jsClassDefinition.className = C.malloc (bytes.length);
+               C.memmove (jsClassDefinition.className, bytes, bytes.length);
+
+               /* custom callbacks for hasProperty, getProperty and callAsFunction */
+               long addr = WebKit_win32.JSObjectHasPropertyProc_CALLBACK (JSObjectHasPropertyProc.getAddress ());
+               jsClassDefinition.hasProperty = addr;
+               addr = WebKit_win32.JSObjectGetPropertyProc_CALLBACK (JSObjectGetPropertyProc.getAddress ());
+               jsClassDefinition.getProperty = addr;
+
+               long classDefinitionPtr = C.malloc (JSClassDefinition.sizeof);
+               WebKit_win32.memmove (classDefinitionPtr, jsClassDefinition, JSClassDefinition.sizeof);
+               ExternalClass = WebKit_win32.JSClassCreate (classDefinitionPtr);
+               WebKit_win32.JSClassRetain (ExternalClass);
+       }
+
+       long[] result = new long[1];
+       int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebView, 0, WebKit_win32.IID_IWebView, result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               browser.dispose ();
+               error (hr);
+       }
+       webView = new IWebView (result[0]);
+       webViewData = C.malloc (C.PTR_SIZEOF);
+       C.memmove (webViewData, new long[] {webView.getAddress ()}, C.PTR_SIZEOF);
+       hr = webView.setHostWindow (browser.handle);
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+       hr = webView.initWithFrame (new RECT (), 0, 0);
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+       result[0] = 0;
+       hr = webView.QueryInterface (WebKit_win32.IID_IWebViewPrivate, result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               browser.dispose ();
+               error (hr);
+       }
+       IWebViewPrivate webViewPrivate = new IWebViewPrivate (result[0]);
+       result[0] = 0;
+       hr = webViewPrivate.viewWindow (result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               browser.dispose ();
+               error (hr);
+       }
+       webViewPrivate.Release ();
+       webViewWindowHandle = result[0];
+
+       webFrameLoadDelegate = new WebFrameLoadDelegate (browser);
+       hr = webView.setFrameLoadDelegate (webFrameLoadDelegate.getAddress ());
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+       webUIDelegate = new WebUIDelegate (browser);
+       hr = webView.setUIDelegate (webUIDelegate.getAddress ());
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+
+       webResourceLoadDelegate = new WebResourceLoadDelegate (browser);
+       hr = webView.setResourceLoadDelegate (webResourceLoadDelegate.getAddress ());
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+
+       webDownloadDelegate = new WebDownloadDelegate (browser);
+       hr = webView.setDownloadDelegate (webDownloadDelegate.getAddress ());
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+
+       webPolicyDelegate = new WebPolicyDelegate (browser);
+       hr = webView.setPolicyDelegate (webPolicyDelegate.getAddress ());
+       if (hr != COM.S_OK) {
+               browser.dispose ();
+               error (hr);
+       }
+
+       initializeWebViewPreferences ();
+
+       Listener listener = e -> {
+               switch (e.type) {
+                       case SWT.Dispose: {
+                               /* make this handler run after other dispose listeners */
+                               if (ignoreDispose) {
+                                       ignoreDispose = false;
+                                       break;
+                               }
+                               ignoreDispose = true;
+                               browser.notifyListeners (e.type, e);
+                               e.type = SWT.NONE;
+                               onDispose ();
+                               break;
+                       }
+                       case SWT.FocusIn: {
+                               OS.SetFocus (webViewWindowHandle);
+                               break;
+                       }
+                       case SWT.Resize: {
+                               Rectangle bounds = DPIUtil.autoScaleUp(browser.getClientArea ()); // To Pixels
+                               OS.SetWindowPos (webViewWindowHandle, 0, bounds.x, bounds.y, bounds.width, bounds.height, OS.SWP_DRAWFRAME);
+                               break;
+                       }
+                       case SWT.Traverse: {
+                               if (traverseOut) {
+                                       e.doit = true;
+                                       traverseOut = false;
+                               } else {
+                                       e.doit = false;
+                               }
+                               break;
+                       }
+               }
+       };
+       browser.addListener (SWT.Dispose, listener);
+       browser.addListener (SWT.KeyDown, listener); /* needed for tabbing into the Browser */
+       browser.addListener (SWT.FocusIn, listener);
+       browser.addListener (SWT.Resize, listener);
+       browser.addListener (SWT.Traverse, listener);
+
+       eventFunction = new BrowserFunction (browser, "HandleWebKitEvent") { //$NON-NLS-1$
+               @Override
+               public Object function (Object[] arguments) {
+                       return handleEvent (arguments) ? Boolean.TRUE : Boolean.FALSE;
+               };
+       };
+}
+
+@Override
+public boolean execute (String script) {
+       long[] result = new long[1];
+       int hr = webView.mainFrame (result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               return false;
+       }
+       IWebFrame frame = new IWebFrame (result[0]);
+       long context = frame.globalContext ();
+       frame.Release ();
+       if (context == 0) {
+               return false;
+       }
+       byte[] bytes = (script + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$
+       long scriptString = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
+       if (scriptString == 0) return false;
+       bytes = (getUrl () + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$
+       long urlString = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
+       if (urlString == 0) {
+               WebKit_win32.JSStringRelease (scriptString);
+               return false;
+       }
+       long evalResult = WebKit_win32.JSEvaluateScript (context, scriptString, 0, urlString, 0, null);
+       WebKit_win32.JSStringRelease (urlString);
+       WebKit_win32.JSStringRelease (scriptString);
+       return evalResult != 0;
+}
+
+@Override
+public boolean forward () {
+       int[] result = new int[1];
+       webView.goForward (result);
+       return result[0] != 0;
+}
+
+@Override
+public String getBrowserType () {
+       return "webkit"; //$NON-NLS-1$
+}
+
+@Override
+public String getText () {
+       long[] result = new long[1];
+       int hr = webView.mainFrame (result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               return EMPTY_STRING;
+       }
+       IWebFrame mainFrame = new IWebFrame (result[0]);
+       result[0] = 0;
+       hr = mainFrame.dataSource (result);
+       mainFrame.Release ();
+       if (hr != COM.S_OK || result[0] == 0) {
+               return EMPTY_STRING;
+       }
+       IWebDataSource dataSource = new IWebDataSource (result[0]);
+       result[0] = 0;
+       hr = dataSource.representation (result);
+       dataSource.Release ();
+       if (hr != COM.S_OK || result[0] == 0) {
+               return EMPTY_STRING;
+       }
+       IWebDocumentRepresentation representation = new IWebDocumentRepresentation (result[0]);
+       result[0] = 0;
+       hr = representation.documentSource (result);
+       representation.Release ();
+       if (hr != COM.S_OK || result[0] == 0) {
+               return EMPTY_STRING;
+       }
+       String source = extractBSTR (result[0]);
+       COM.SysFreeString (result[0]);
+       return source;
+}
+
+@Override
+public String getUrl () {
+       return webFrameLoadDelegate.getUrl ();
+}
+
+boolean handleEvent (Object[] arguments) {
+
+       /*
+       * DOM events are currently received by hooking DOM listeners
+       * in javascript that invoke this method via a BrowserFunction.
+       * Document.addListener is not implemented on WebKit on windows.
+       * The argument lists received here are:
+       *
+       * For key events:
+       *       argument 0: type (String)
+       *       argument 1: keyCode (Double)
+       *       argument 2: charCode (Double)
+       *       argument 3: altKey (Boolean)
+       *       argument 4: ctrlKey (Boolean)
+       *       argument 5: shiftKey (Boolean)
+       *       argument 6: metaKey (Boolean)
+       *       returns doit
+       *
+       * For mouse events
+       *       argument 0: type (String)
+       *       argument 1: screenX (Double)
+       *       argument 2: screenY (Double)
+       *       argument 3: detail (Double)
+       *       argument 4: button (Double)
+       *       argument 5: altKey (Boolean)
+       *       argument 6: ctrlKey (Boolean)
+       *       argument 7: shiftKey (Boolean)
+       *       argument 8: metaKey (Boolean)
+       *       argument 9: hasRelatedTarget (Boolean)
+       *       returns doit
+       */
+
+       String type = (String)arguments[0];
+       if (type.equals (DOMEVENT_KEYDOWN)) {
+               int keyCode = translateKey (((Double)arguments[1]).intValue ());
+               lastKeyCode = keyCode;
+               switch (keyCode) {
+                       case SWT.SHIFT:
+                       case SWT.CONTROL:
+                       case SWT.ALT:
+                       case SWT.CAPS_LOCK:
+                       case SWT.NUM_LOCK:
+                       case SWT.SCROLL_LOCK:
+                       case SWT.COMMAND:
+//                     case SWT.ESC:
+                       case SWT.TAB:
+                       case SWT.PAUSE:
+//                     case SWT.BS:
+                       case SWT.INSERT:
+                       case SWT.DEL:
+                       case SWT.HOME:
+                       case SWT.END:
+                       case SWT.PAGE_UP:
+                       case SWT.PAGE_DOWN:
+                       case SWT.ARROW_DOWN:
+                       case SWT.ARROW_UP:
+                       case SWT.ARROW_LEFT:
+                       case SWT.ARROW_RIGHT:
+                       case SWT.F1:
+                       case SWT.F2:
+                       case SWT.F3:
+                       case SWT.F4:
+                       case SWT.F5:
+                       case SWT.F6:
+                       case SWT.F7:
+                       case SWT.F8:
+                       case SWT.F9:
+                       case SWT.F10:
+                       case SWT.F11:
+                       case SWT.F12: {
+                               /* keypress events will not be received for these keys, so send KeyDowns for them now */
+
+                               Event keyEvent = new Event ();
+                               keyEvent.widget = browser;
+                               keyEvent.type = type.equals (DOMEVENT_KEYDOWN) ? SWT.KeyDown : SWT.KeyUp;
+                               keyEvent.keyCode = keyCode;
+                               switch (keyCode) {
+                                       case SWT.BS: keyEvent.character = SWT.BS; break;
+                                       case SWT.DEL: keyEvent.character = SWT.DEL; break;
+                                       case SWT.ESC: keyEvent.character = SWT.ESC; break;
+                                       case SWT.TAB: keyEvent.character = SWT.TAB; break;
+                               }
+                               lastCharCode = keyEvent.character;
+                               keyEvent.stateMask =
+                                       (((Boolean)arguments[3]).booleanValue () ? SWT.ALT : 0) |
+                                       (((Boolean)arguments[4]).booleanValue () ? SWT.CTRL : 0) |
+                                       (((Boolean)arguments[5]).booleanValue () ? SWT.SHIFT : 0) |
+                                       (((Boolean)arguments[6]).booleanValue () ? SWT.COMMAND : 0);
+                               keyEvent.stateMask &= ~keyCode;         /* remove current keydown if it's a state key */
+                               if (!sendKeyEvent (keyEvent) || browser.isDisposed ()) return false;
+                               break;
+                       }
+               }
+               return true;
+       }
+
+       if (type.equals (DOMEVENT_KEYPRESS)) {
+               /*
+               * if keydown could not determine a keycode for this key then it's a
+               * key for which key events are not sent (eg.- the Windows key)
+               */
+               if (lastKeyCode == 0) return true;
+
+               lastCharCode = ((Double)arguments[2]).intValue ();
+               if (((Boolean)arguments[4]).booleanValue () && (0 <= lastCharCode && lastCharCode <= 0x7F)) {
+                       if ('a' <= lastCharCode && lastCharCode <= 'z') lastCharCode -= 'a' - 'A';
+                       if (64 <= lastCharCode && lastCharCode <= 95) lastCharCode -= 64;
+               }
+
+               Event keyEvent = new Event ();
+               keyEvent.widget = browser;
+               keyEvent.type = SWT.KeyDown;
+               keyEvent.keyCode = lastKeyCode;
+               keyEvent.character = (char)lastCharCode;
+               keyEvent.stateMask =
+                       (((Boolean)arguments[3]).booleanValue () ? SWT.ALT : 0) |
+                       (((Boolean)arguments[4]).booleanValue () ? SWT.CTRL : 0) |
+                       (((Boolean)arguments[5]).booleanValue () ? SWT.SHIFT : 0) |
+                       (((Boolean)arguments[6]).booleanValue () ? SWT.COMMAND : 0);
+               return sendKeyEvent (keyEvent) && !browser.isDisposed ();
+       }
+
+       if (type.equals (DOMEVENT_KEYUP)) {
+               int keyCode = translateKey (((Double)arguments[1]).intValue ());
+               if (keyCode == 0) {
+                       /* indicates a key for which key events are not sent */
+                       return true;
+               }
+               if (keyCode != lastKeyCode) {
+                       /* keyup does not correspond to the last keydown */
+                       lastKeyCode = keyCode;
+                       lastCharCode = 0;
+               }
+
+               Event keyEvent = new Event ();
+               keyEvent.widget = browser;
+               keyEvent.type = SWT.KeyUp;
+               keyEvent.keyCode = lastKeyCode;
+               keyEvent.character = (char)lastCharCode;
+               keyEvent.stateMask =
+                       (((Boolean)arguments[3]).booleanValue () ? SWT.ALT : 0) |
+                       (((Boolean)arguments[4]).booleanValue () ? SWT.CTRL : 0) |
+                       (((Boolean)arguments[5]).booleanValue () ? SWT.SHIFT : 0) |
+                       (((Boolean)arguments[6]).booleanValue () ? SWT.COMMAND : 0);
+               switch (lastKeyCode) {
+                       case SWT.SHIFT:
+                       case SWT.CONTROL:
+                       case SWT.ALT:
+                       case SWT.COMMAND: {
+                               keyEvent.stateMask |= lastKeyCode;
+                       }
+               }
+               browser.notifyListeners (keyEvent.type, keyEvent);
+               lastKeyCode = lastCharCode = 0;
+               return keyEvent.doit && !browser.isDisposed ();
+       }
+
+       /* mouse events */
+
+       /*
+        * MouseOver and MouseOut events are fired any time the mouse enters or exits
+        * any element within the Browser.  To ensure that SWT events are only
+        * fired for mouse movements into or out of the Browser, do not fire an
+        * event if there is a related target element.
+        */
+       if (type.equals (DOMEVENT_MOUSEOVER) || type.equals (DOMEVENT_MOUSEOUT)) {
+               if (((Boolean)arguments[9]).booleanValue ()) return true;
+       }
+
+       /*
+        * The position of mouse events is received in screen-relative coordinates
+        * in order to handle pages with frames, since frames express their event
+        * coordinates relative to themselves rather than relative to their top-
+        * level page.  Convert screen-relative coordinates to be browser-relative.
+        */
+       Point position = new Point (((Double)arguments[1]).intValue (), ((Double)arguments[2]).intValue ());// Points or Pixles ?
+       position = browser.getDisplay ().map (null, browser, position);
+
+       Event mouseEvent = new Event ();
+       mouseEvent.widget = browser;
+       mouseEvent.x = position.x;
+       mouseEvent.y = position.y;
+       int mask =
+               (((Boolean)arguments[5]).booleanValue () ? SWT.ALT : 0) |
+               (((Boolean)arguments[6]).booleanValue () ? SWT.CTRL : 0) |
+               (((Boolean)arguments[7]).booleanValue () ? SWT.SHIFT : 0);
+       mouseEvent.stateMask = mask;
+
+       if (type.equals (DOMEVENT_MOUSEDOWN)) {
+               mouseEvent.type = SWT.MouseDown;
+               mouseEvent.count = ((Double)arguments[3]).intValue ();
+               mouseEvent.button = ((Double)arguments[4]).intValue ();
+               browser.notifyListeners (mouseEvent.type, mouseEvent);
+               if (browser.isDisposed ()) return true;
+               if (((Double)arguments[3]).intValue () == 2) {
+                       mouseEvent = new Event ();
+                       mouseEvent.type = SWT.MouseDoubleClick;
+                       mouseEvent.widget = browser;
+                       mouseEvent.x = position.x;
+                       mouseEvent.y = position.y;
+                       mouseEvent.stateMask = mask;
+                       mouseEvent.count = ((Double)arguments[3]).intValue ();
+                       mouseEvent.button = ((Double)arguments[4]).intValue ();
+                       browser.notifyListeners (mouseEvent.type, mouseEvent);
+               }
+               return true;
+       }
+
+       if (type.equals (DOMEVENT_MOUSEUP)) {
+               mouseEvent.type = SWT.MouseUp;
+               mouseEvent.count = ((Double)arguments[3]).intValue ();
+               mouseEvent.button = ((Double)arguments[4]).intValue ();
+               switch (mouseEvent.button) {
+                       case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
+                       case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
+                       case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
+                       case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
+                       case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
+               }
+       } else if (type.equals (DOMEVENT_MOUSEMOVE)) {
+               mouseEvent.type = SWT.MouseMove;
+       } else if (type.equals (DOMEVENT_MOUSEWHEEL)) {
+               mouseEvent.type = SWT.MouseWheel;
+               mouseEvent.count = ((Double)arguments[3]).intValue ();
+       } else if (type.equals (DOMEVENT_MOUSEOVER)) {
+               mouseEvent.type = SWT.MouseEnter;
+       } else if (type.equals (DOMEVENT_MOUSEOUT)) {
+               mouseEvent.type = SWT.MouseExit;
+               if (mouseEvent.x < 0) mouseEvent.x = -1;
+               if (mouseEvent.y < 0) mouseEvent.y = -1;
+       } else if (type.equals (DOMEVENT_DRAGSTART)) {
+               mouseEvent.type = SWT.DragDetect;
+               mouseEvent.button = ((Double)arguments[4]).intValue () + 1;
+               switch (mouseEvent.button) {
+                       case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
+                       case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
+                       case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
+                       case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
+                       case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
+               }
+       }
+
+       browser.notifyListeners (mouseEvent.type, mouseEvent);
+       return true;
+}
+
+@Override
+public boolean isBackEnabled () {
+       long[] address = new long[1];
+       int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, address);
+       if (hr != COM.S_OK || address[0] == 0) {
+               return false;
+       }
+       IWebIBActions webIBActions = new IWebIBActions (address[0]);
+       int[] result = new int[1];
+       webIBActions.canGoBack (webView.getAddress (), result);
+       webIBActions.Release ();
+       return result[0] != 0;
+}
+
+@Override
+public boolean isFocusControl () {
+       long hwndFocus = OS.GetFocus ();
+       return hwndFocus != 0 && hwndFocus == webViewWindowHandle;
+}
+
+@Override
+public boolean isForwardEnabled () {
+       long[] address = new long[1];
+       int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, address);
+       if (hr != COM.S_OK || address[0] == 0) {
+               return false;
+       }
+       IWebIBActions webIBActions = new IWebIBActions (address[0]);
+       int[] result = new int[1];
+       webIBActions.canGoForward (webView.getAddress (), result);
+       webIBActions.Release ();
+       return result[0] != 0;
+}
+
+void onDispose () {
+       /* Browser could have been disposed by one of the Dispose listeners */
+       if (!browser.isDisposed ()) {
+               /* invoke onbeforeunload handlers but don't prompt with message box */
+               if (!browser.isClosing) {
+                       webUIDelegate.prompt = false;
+                       shouldClose ();
+                       webUIDelegate.prompt = true;
+               }
+       }
+
+       Iterator<BrowserFunction> elements = functions.values().iterator ();
+       while (elements.hasNext ()) {
+               elements.next ().dispose (false);
+       }
+       functions = null;
+
+       eventFunction.dispose();
+       eventFunction = null;
+       C.free (webViewData);
+
+       webView.setPreferences (0);
+       webView.setHostWindow (0);
+       webView.setFrameLoadDelegate (0);
+       webView.setResourceLoadDelegate (0);
+       webView.setUIDelegate (0);
+       webView.setPolicyDelegate (0);
+       webView.setDownloadDelegate (0);
+       webView.Release();
+       webView = null;
+       webDownloadDelegate = null;
+       webFrameLoadDelegate = null;
+       webPolicyDelegate = null;
+       webResourceLoadDelegate = null;
+       webUIDelegate = null;
+       lastNavigateURL = null;
+}
+
+@Override
+public void refresh () {
+       webFrameLoadDelegate.html = null;
+       long[] result = new long[1];
+       int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               return;
+       }
+       IWebIBActions webIBActions = new IWebIBActions (result[0]);
+       webIBActions.reload (webView.getAddress ());
+       webIBActions.Release ();
+}
+
+@Override
+boolean sendKeyEvent (Event event) {
+       /*
+        * browser.traverse() is called through dislay.translateTraversal() for all
+        * traversal types except SWT.TRAVERSE_MNEMONIC. So, override
+        * WebBrowser.sendKeyEvent() so that when it is called from handleEvent(),
+        * browser.traverse() is not called again.
+        */
+       boolean doit = true;
+       switch (event.keyCode) {
+               case SWT.ESC:
+               case SWT.CR:
+               case SWT.ARROW_DOWN:
+               case SWT.ARROW_RIGHT:
+               case SWT.ARROW_UP:
+               case SWT.ARROW_LEFT:
+               case SWT.TAB:
+               case SWT.PAGE_DOWN:
+               case SWT.PAGE_UP:
+                       break;
+               default: {
+                       if (translateMnemonics ()) {
+                               if (event.character != 0 && (event.stateMask & (SWT.ALT | SWT.CTRL)) == SWT.ALT) {
+                                       int traversal = SWT.TRAVERSE_MNEMONIC;
+                                       boolean oldEventDoit = event.doit;
+                                       event.doit = true;
+                                       doit = !browser.traverse (traversal, event);
+                                       event.doit = oldEventDoit;
+                               }
+                       }
+                       break;
+               }
+       }
+       if (doit) {
+               browser.notifyListeners (event.type, event);
+               doit = event.doit;
+       }
+       return doit;
+}
+
+@Override
+public boolean setText (String html, boolean trusted) {
+       /*
+       * If this.html is not null then the about:blank page is already being loaded,
+       * so no navigate is required.  Just set the html that is to be shown.
+       */
+       boolean blankLoading = webFrameLoadDelegate.html != null;
+       webFrameLoadDelegate.html = html;
+       untrustedText = !trusted;
+       if (blankLoading) return true;
+
+       long[] result = new long[1];
+       int hr = webView.mainFrame (result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               return false;
+       }
+       IWebFrame frame = new IWebFrame (result[0]);
+
+       result[0] = 0;
+       hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebMutableURLRequest, 0, WebKit_win32.IID_IWebMutableURLRequest, result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               frame.Release ();
+               return false;
+       }
+       IWebMutableURLRequest request = new IWebMutableURLRequest (result[0]);
+
+       long urlString = createBSTR (ABOUT_BLANK);
+       hr = request.setURL (urlString);
+       COM.SysFreeString (urlString);
+
+       if (hr == COM.S_OK) {
+               hr = frame.loadRequest (request.getAddress ());
+       }
+       frame.Release ();
+       request.Release ();
+       return hr == COM.S_OK;
+}
+
+@Override
+public boolean setUrl (String url, String postData, String[] headers) {
+       if (url.length () == 0) return false;
+       /*
+       * WebKit attempts to open the exact url string that is passed to it and
+       * will not infer a protocol if it's not specified.  Detect the case of an
+       * invalid URL string and try to fix it by prepending an appropriate protocol.
+       */
+       try {
+               new URL (url);
+       } catch (MalformedURLException e) {
+               String testUrl = null;
+               if (new File (url).isAbsolute ()) {
+                       /* appears to be a local file */
+                       testUrl = PROTOCOL_FILE + url;
+               } else {
+                       testUrl = PROTOCOL_HTTP + url;
+               }
+               try {
+                       new URL (testUrl);
+                       url = testUrl;          /* adding the protocol made the url valid */
+               } catch (MalformedURLException e2) {
+                       /* adding the protocol did not make the url valid, so do nothing */
+               }
+       }
+       webFrameLoadDelegate.html = null;
+       lastNavigateURL = url;
+       long[] result = new long[1];
+       int hr = webView.mainFrame (result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               return false;
+       }
+       IWebFrame frame = new IWebFrame (result[0]);
+
+       result[0] = 0;
+       hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebMutableURLRequest, 0, WebKit_win32.IID_IWebMutableURLRequest, result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               frame.Release ();
+               return false;
+       }
+       IWebMutableURLRequest request = new IWebMutableURLRequest (result[0]);
+
+       if (postData != null) { //TODO: POST
+//     webResourceLoadDelegate.postData = postData;
+//     long postString = createBSTR (POST);
+//             hr = request.setHTTPMethod (postString);
+//             COM.SysFreeString (postString);
+//
+//             result[0] = 0;
+//             hr = request.QueryInterface (WebKit_win32.IID_IWebMutableURLRequestPrivate, result);
+//             if (hr == COM.S_OK && result[0] != 0) {
+//                     IWebMutableURLRequestPrivate requestPrivate = new IWebMutableURLRequestPrivate(result[0]);
+//                     int cfRequest = requestPrivate.cfRequest();
+//                     byte[] bytes = postData.getBytes();
+//                     long data = WebKit_win32.CFDataCreate(0, bytes, bytes.length);
+//                     if (data != 0)WebKit_win32.CFURLRequestSetHTTPRequestBody(cfRequest, data);
+//
+//                     long dataGet = WebKit_win32.CFURLRequestCopyHTTPRequestBody(cfRequest);
+//                     int length = WebKit_win32.CFDataGetLength(dataGet);
+//                     long bytePtr = WebKit_win32.CFDataGetBytePtr(dataGet);
+//             }
+       }
+       hr = COM.S_OK;  //TODO: once post code is completed, remove this line if not required
+       if (headers != null) {
+               for (int i = 0; i < headers.length; i++) {
+                       String current = headers[i];
+                       if (current != null) {
+                               int index = current.indexOf (':');
+                               if (index != -1) {
+                                       String key = current.substring (0, index).trim ();
+                                       String value = current.substring (index + 1).trim ();
+                                       if (key.length () > 0 && value.length () > 0) {
+                                               long valueString = createBSTR (value);
+                                               if (key.equalsIgnoreCase (USER_AGENT)) {
+                                                       /*
+                                                       * Feature of WebKit.  The user-agent header value cannot be overridden
+                                                       * here.  The workaround is to temporarily set the value on the WebView
+                                                       * and then remove it after the loading of the request has begun.
+                                                       */
+                                                       hr = webView.setCustomUserAgent (valueString);
+                                               } else {
+                                                       long keyString = createBSTR (key);
+                                                       hr = request.setValue (valueString, keyString);
+                                                       COM.SysFreeString (keyString);
+                                               }
+                                               COM.SysFreeString (valueString);
+                                       }
+                               }
+                       }
+               }
+       }
+       if (hr == COM.S_OK) {
+               long urlString = createBSTR (url);
+               hr = request.setURL (urlString);
+               COM.SysFreeString (urlString);
+               if (hr == COM.S_OK) {
+                       hr = frame.loadRequest (request.getAddress ());
+               }
+               webView.setCustomUserAgent (0);
+       }
+       frame.Release ();
+       request.Release ();
+       return hr == COM.S_OK;
+}
+
+boolean shouldClose () {
+       if (!jsEnabled) return true;
+
+       long[] address = new long[1];
+       int hr = webView.QueryInterface (WebKit_win32.IID_IWebViewPrivate, address);
+       if (hr != COM.S_OK || address[0] == 0) {
+               return false;
+       }
+       IWebViewPrivate webViewPrivate = new IWebViewPrivate (address[0]);
+       int[] result = new int[1];
+       /* This function will fire the before unload handler for a page */
+       webViewPrivate.shouldClose (result);
+       webViewPrivate.Release ();
+       return result[0] != 0;
+}
+
+@Override
+public void stop () {
+       webFrameLoadDelegate.html = null;
+       long[] result = new long[1];
+       int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, result);
+       if (hr != COM.S_OK || result[0] == 0) {
+               return;
+       }
+       IWebIBActions webIBActions = new IWebIBActions (result[0]);
+       webIBActions.stopLoading (webView.getAddress ());
+       webIBActions.Release ();
+}
+
+void initializeWebViewPreferences () {
+       /*
+        * Try to create separate preferences for each webview using different identifier for each webview.
+        * Otherwise all the webviews use the shared preferences.
+        */
+       long[] result = new long[1];
+       int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebPreferences, 0, WebKit_win32.IID_IWebPreferences, result);
+       if (hr == COM.S_OK && result[0] != 0) {
+               IWebPreferences preferences = new IWebPreferences (result[0]);
+               result[0] = 0;
+               hr = preferences.initWithIdentifier (createBSTR (String.valueOf (prefsIdentifier++)), result);
+               preferences.Release ();
+               if (hr == COM.S_OK && result[0] != 0) {
+                       preferences = new IWebPreferences (result[0]);
+                       webView.setPreferences (preferences.getAddress());
+                       preferences.Release ();
+               }
+       }
+
+       result[0] = 0;
+       hr = webView.preferences (result);
+       if (hr == COM.S_OK && result[0] != 0) {
+               IWebPreferences preferences = new IWebPreferences (result[0]);
+               preferences.setJavaScriptEnabled (1);
+               preferences.setJavaScriptCanOpenWindowsAutomatically (1);
+               preferences.setJavaEnabled (0); /* disable applets */
+               preferences.setTabsToLinks (1);
+               preferences.setFontSmoothing (WebKit_win32.FontSmoothingTypeWindows);
+               preferences.Release ();
+       }
+}
+
+}