]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/WebKit.java
e935db206b9b164f2bdeb5643cf915d0885ce49b
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / browser / WebKit.java
1 /*******************************************************************************
2  * Copyright (c) 2010, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.browser;
15
16
17 import java.io.*;
18 import java.net.*;
19 import java.nio.charset.*;
20 import java.util.*;
21
22 import org.eclipse.swt.*;
23 import org.eclipse.swt.graphics.*;
24 import org.eclipse.swt.internal.*;
25 import org.eclipse.swt.internal.ole.win32.*;
26 import org.eclipse.swt.internal.webkit.*;
27 import org.eclipse.swt.internal.win32.*;
28 import org.eclipse.swt.widgets.*;
29
30 class WebKit extends WebBrowser {
31         IWebView webView;
32         long webViewWindowHandle, webViewData;
33         int refCount = 0;
34         int lastKeyCode, lastCharCode;
35
36         WebDownloadDelegate webDownloadDelegate;
37         WebFrameLoadDelegate webFrameLoadDelegate;
38         WebPolicyDelegate webPolicyDelegate;
39         WebResourceLoadDelegate webResourceLoadDelegate;
40         WebUIDelegate webUIDelegate;
41
42         boolean ignoreDispose;
43         boolean loadingText = false;
44         boolean traverseNext = true;
45         boolean traverseOut = false;
46         boolean untrustedText;
47         String lastNavigateURL;
48         BrowserFunction eventFunction;
49
50         static int prefsIdentifier;
51         static long ExternalClass;
52         static boolean LibraryLoaded = false;
53         static String LibraryLoadError;
54         static Callback JSObjectHasPropertyProc;
55         static Callback JSObjectGetPropertyProc;
56         static Callback JSObjectCallAsFunctionProc;
57         static final int MAX_PROGRESS = 100;
58         static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
59         static final String CLASSNAME_EXTERNAL = "External"; //$NON-NLS-1$
60         static final String EMPTY_STRING = ""; //$NON-NLS-1$
61         static final String FUNCTIONNAME_CALLJAVA = "callJava"; //$NON-NLS-1$
62         static final String HEADER_SETCOOKIE = "Set-Cookie"; //$NON-NLS-1$
63         static final String POST = "POST"; //$NON-NLS-1$
64         static final String PROPERTY_LENGTH = "length"; //$NON-NLS-1$
65         static final String PROTOCOL_HTTPS = "https://"; //$NON-NLS-1$
66         static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
67         static final String PROTOCOL_HTTP = "http://"; //$NON-NLS-1$
68         static final String USER_AGENT = "user-agent"; //$NON-NLS-1$
69         static final String URI_FILEROOT = "file:///"; //$NON-NLS-1$
70
71         /* event strings */
72         static final String DOMEVENT_DRAGSTART = "dragstart"; //$NON-NLS-1$
73         static final String DOMEVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
74         static final String DOMEVENT_KEYPRESS = "keypress"; //$NON-NLS-1$
75         static final String DOMEVENT_KEYUP = "keyup"; //$NON-NLS-1$
76         static final String DOMEVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
77         static final String DOMEVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
78         static final String DOMEVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
79         static final String DOMEVENT_MOUSEOUT = "mouseout"; //$NON-NLS-1$
80         static final String DOMEVENT_MOUSEOVER = "mouseover"; //$NON-NLS-1$
81         static final String DOMEVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
82
83 static {
84         /*
85         * Attempt to load the swt-webkit library.  This will only succeed if the Apple
86         * Application Support package is on the user's Windows Path environment variable.
87         */
88         try {
89                 Library.loadLibrary ("swt-webkit"); // $NON-NLS-1$
90                 LibraryLoaded = true;
91         } catch (Throwable e) {
92         }
93
94         /*
95         * If needed, add the Apple Application Support package's directory to the library
96         * lookup path and try to load the swt-webkit library again.
97         */
98         if (!LibraryLoaded) {
99                 /*
100                  * Locate the Apple Application Support directory (if installed) and add its path to the library lookup path.
101                  *
102                  * As of Safari 5.1.4, the Apple Application Support directory is in the Safari installation directory,
103                  * which is pointed to by registry entry "HKEY_LOCAL_MACHINE\SOFTWARE\Apple Computer, Inc.\Safari".
104                  *
105                  * With earlier versions of Safari the Apple Application Support is installed in a stand-alone location, which
106                  * is pointed to by registry entry "HKEY_LOCAL_MACHINE\SOFTWARE\Apple Inc.\Apple Application Support\InstallDir".
107                  */
108
109                 String AASDirectory = readInstallDir ("SOFTWARE\\Apple Computer, Inc.\\Safari"); //$NON-NLS-1$
110                 if (AASDirectory != null) {
111                         AASDirectory += "\\Apple Application Support"; //$NON-NLS-1$
112                         if (!new File(AASDirectory).exists()) {
113                                 AASDirectory = null;
114                         }
115                 }
116
117                 if (AASDirectory == null) {
118                         AASDirectory = readInstallDir ("SOFTWARE\\Apple Inc.\\Apple Application Support"); //$NON-NLS-1$
119                 }
120
121                 if (AASDirectory != null) {
122                         TCHAR buffer = new TCHAR (0, AASDirectory, true);
123                         boolean success = OS.SetDllDirectory (buffer); /* should succeed on XP+SP1 and newer */
124                         if (success) {
125                                 try {
126                                         Library.loadLibrary ("swt-webkit"); //$NON-NLS-1$
127                                         LibraryLoaded = true;
128                                 } catch (Throwable e) {
129                                         LibraryLoadError = "Failed to load the swt-webkit library"; //$NON-NLS-1$
130                                         if (Device.DEBUG) System.out.println ("Failed to load swt-webkit library. Apple Application Support directory path: " + AASDirectory); //$NON-NLS-1$
131                                 }
132                         } else {
133                                 LibraryLoadError = "Failed to add the Apple Application Support package to the library lookup path.  "; //$NON-NLS-1$
134                                 LibraryLoadError += "To use a SWT.WEBKIT-style Browser prepend " + AASDirectory + " to your Windows 'Path' environment variable and restart."; //$NON-NLS-1$ //$NON-NLS-2$
135                         }
136                 } else {
137                         LibraryLoadError = "Safari must be installed to use a SWT.WEBKIT-style Browser"; //$NON-NLS-1$
138                 }
139         }
140
141         if (LibraryLoaded) {
142                 JSObjectHasPropertyProc = new Callback (WebKit.class, "JSObjectHasPropertyProc", 3); //$NON-NLS-1$
143                 if (JSObjectHasPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
144                 JSObjectGetPropertyProc = new Callback (WebKit.class, "JSObjectGetPropertyProc", 4); //$NON-NLS-1$
145                 if (JSObjectGetPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
146                 JSObjectCallAsFunctionProc = new Callback (WebKit.class, "JSObjectCallAsFunctionProc", 6); //$NON-NLS-1$
147                 if (JSObjectCallAsFunctionProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
148
149                 NativeClearSessions = () -> {
150                         long[] result = new long[1];
151                         int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebCookieManager, 0, WebKit_win32.IID_IWebCookieManager, result);
152                         if (hr != COM.S_OK || result[0] == 0) {
153                                 return;
154                         }
155                         IWebCookieManager cookieManager = new IWebCookieManager (result[0]);
156                         long[] storage = new long[1];
157                         hr = cookieManager.cookieStorage (storage);
158                         cookieManager.Release ();
159                         if (hr != COM.S_OK || storage[0] == 0) {
160                                 return;
161                         }
162                         long cookies = WebKit_win32.CFHTTPCookieStorageCopyCookies (storage[0]);
163                         if (cookies != 0) {
164                                 int count = WebKit_win32.CFArrayGetCount (cookies);
165                                 for (int i = 0; i < count; i++) {
166                                         long cookie = WebKit_win32.CFArrayGetValueAtIndex (cookies, i);
167                                         long flags = WebKit_win32.CFHTTPCookieGetFlags (cookie);
168                                         if ((flags & WebKit_win32.CFHTTPCookieSessionOnlyFlag) != 0) {
169                                                 WebKit_win32.CFHTTPCookieStorageDeleteCookie (storage[0], cookie);
170                                         }
171                                 }
172                                 WebKit_win32.CFRelease (cookies);
173                         }
174                         // WebKit_win32.CFRelease (storage[0]); //intentionally commented, causes crash
175                 };
176
177                 NativeGetCookie = () -> {
178                         long[] result = new long[1];
179                         int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebCookieManager, 0, WebKit_win32.IID_IWebCookieManager, result);
180                         if (hr != COM.S_OK || result[0] == 0) {
181                                 return;
182                         }
183                         IWebCookieManager cookieManager = new IWebCookieManager (result[0]);
184                         long[] storage = new long[1];
185                         hr = cookieManager.cookieStorage (storage);
186                         cookieManager.Release ();
187                         if (hr != COM.S_OK || storage[0] == 0) {
188                                 return;
189                         }
190                         char[] chars = CookieUrl.toCharArray ();
191                         long string = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
192                         if (string != 0) {
193                                 long cfUrl = WebKit_win32.CFURLCreateWithString (0, string, 0);
194                                 if (cfUrl != 0) {
195                                         boolean secure = CookieUrl.startsWith (PROTOCOL_HTTPS);
196                                         long cookiesArray = WebKit_win32.CFHTTPCookieStorageCopyCookiesForURL (storage[0], cfUrl, secure);
197                                         if (cookiesArray != 0) {
198                                                 int count = WebKit_win32.CFArrayGetCount (cookiesArray);
199                                                 for (int i = 0; i < count; i++) {
200                                                         long cookie = WebKit_win32.CFArrayGetValueAtIndex (cookiesArray, i);
201                                                         if (cookie != 0) {
202                                                                 long cookieName = WebKit_win32.CFHTTPCookieGetName (cookie);
203                                                                 if (cookieName != 0) {
204                                                                         String name = stringFromCFString (cookieName);
205                                                                         if (CookieName.equals (name)) {
206                                                                                 long value = WebKit_win32.CFHTTPCookieGetValue (cookie);
207                                                                                 if (value != 0) CookieValue = stringFromCFString (value);
208                                                                                 break;
209                                                                         }
210                                                                 }
211                                                         }
212                                                 }
213                                                 WebKit_win32.CFRelease (cookiesArray);
214                                         }
215                                         WebKit_win32.CFRelease (cfUrl);
216                                 }
217                                 WebKit_win32.CFRelease (string);
218                         }
219                         // WebKit_win32.CFRelease (storage[0]); //intentionally commented, causes crash
220                 };
221
222                 NativeSetCookie = () -> {
223                         long[] result = new long[1];
224                         int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebCookieManager, 0, WebKit_win32.IID_IWebCookieManager, result);
225                         if (hr != COM.S_OK || result[0] == 0) {
226                                 return;
227                         }
228                         IWebCookieManager cookieManager = new IWebCookieManager (result[0]);
229                         long[] storage = new long[1];
230                         hr = cookieManager.cookieStorage (storage);
231                         cookieManager.Release ();
232                         if (hr != COM.S_OK || storage[0] == 0) {
233                                 return;
234                         }
235
236                         char[] chars = CookieUrl.toCharArray ();
237                         long string = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
238                         if (string != 0) {
239                                 long cfUrl = WebKit_win32.CFURLCreateWithString (0, string, 0);
240                                 if (cfUrl != 0) {
241                                         chars = CookieValue.toCharArray ();
242                                         long value = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
243                                         if (value != 0) {
244                                                 chars = HEADER_SETCOOKIE.toCharArray ();
245                                                 long key = WebKit_win32.CFStringCreateWithCharacters (0, chars, chars.length);
246                                                 if (key != 0) {
247                                                         long headers = WebKit_win32.CFDictionaryCreate (0, new long[] {key}, new long[] {value}, 1, WebKit_win32.kCFCopyStringDictionaryKeyCallBacks (), WebKit_win32.kCFTypeDictionaryValueCallBacks ());
248                                                         if (headers != 0) {
249                                                                 long cookies = WebKit_win32.CFHTTPCookieCreateWithResponseHeaderFields (0, headers, cfUrl);
250                                                                 if (cookies != 0) {
251                                                                         long cookie = WebKit_win32.CFArrayGetValueAtIndex (cookies, 0);
252                                                                         if (cookie != 0) {
253                                                                                 WebKit_win32.CFHTTPCookieStorageSetCookie (storage[0], cookie);
254                                                                                 CookieResult = true;
255                                                                         }
256                                                                         WebKit_win32.CFRelease (cookies);
257                                                                 }
258                                                                 WebKit_win32.CFRelease (headers);
259                                                         }
260                                                         WebKit_win32.CFRelease (key);
261                                                 }
262                                                 WebKit_win32.CFRelease (value);
263                                         }
264                                         WebKit_win32.CFRelease (cfUrl);
265                                 }
266                                 WebKit_win32.CFRelease (string);
267                         }
268                         // WebKit_win32.CFRelease (storage[0]); //intentionally commented, causes crash
269                 };
270
271                 if (NativePendingCookies != null) {
272                         SetPendingCookies (NativePendingCookies);
273                 }
274                 NativePendingCookies = null;
275         }
276 }
277
278 static long createBSTR (String string) {
279         char[] data = (string + '\0').toCharArray ();
280         return COM.SysAllocString (data);
281 }
282
283 static String error (int code) {
284         throw new SWTError ("WebKit error " + code); //$NON-NLS-1$
285 }
286
287 static String extractBSTR (long bstrString) {
288         int size = COM.SysStringByteLen (bstrString);
289         if (size == 0) return EMPTY_STRING;
290         char[] buffer = new char[(size + 1) / 2]; // add one to avoid rounding errors
291         OS.MoveMemory (buffer, bstrString, size);
292         return new String (buffer);
293 }
294
295 static Browser findBrowser (long webView) {
296         if (webView == 0) return null;
297         IWebView iwebView = new IWebView (webView);
298         long[] result = new long[1];
299         int hr = iwebView.hostWindow (result);
300         if (hr == COM.S_OK && result[0] != 0) {
301                 Widget widget = Display.getCurrent ().findWidget (result[0]);
302                 if (widget != null && widget instanceof Browser) return (Browser)widget;
303         }
304         return null;
305 }
306
307 static long JSObjectCallAsFunctionProc (long ctx, long function, long thisObject, long argumentCount, long arguments, long exception) {
308         WebKit_win32.JSGlobalContextRetain (ctx);
309         if (WebKit_win32.JSValueIsObjectOfClass (ctx, thisObject, ExternalClass) == 0) {
310                 return WebKit_win32.JSValueMakeUndefined (ctx);
311         }
312         long ptr = WebKit_win32.JSObjectGetPrivate (thisObject);
313         long[] handle = new long[1];
314         C.memmove (handle, ptr, C.PTR_SIZEOF);
315         Browser browser = findBrowser (handle[0]);
316         if (browser == null) return WebKit_win32.JSValueMakeUndefined (ctx);
317         WebKit webkit = (WebKit)browser.webBrowser;
318         return webkit.callJava (ctx, function, thisObject, argumentCount, arguments, exception);
319 }
320
321 static long JSObjectGetPropertyProc (long ctx, long object, long propertyName, long exception) {
322         byte[] bytes = (FUNCTIONNAME_CALLJAVA + '\0').getBytes (StandardCharsets.UTF_8);
323         long name = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
324         long addr = WebKit_win32.JSObjectCallAsFunctionProc_CALLBACK (WebKit.JSObjectCallAsFunctionProc.getAddress ());
325         long function = WebKit_win32.JSObjectMakeFunctionWithCallback (ctx, name, addr);
326         WebKit_win32.JSStringRelease (name);
327         return function;
328 }
329
330 static long JSObjectHasPropertyProc (long ctx, long object, long propertyName) {
331         byte[] bytes = (FUNCTIONNAME_CALLJAVA + '\0').getBytes (StandardCharsets.UTF_8);
332         return WebKit_win32.JSStringIsEqualToUTF8CString (propertyName, bytes);
333 }
334
335 static String readInstallDir (String keyString) {
336         long[] phkResult = new long[1];
337         TCHAR key = new TCHAR (0, keyString, true);
338         if (OS.RegOpenKeyEx (OS.HKEY_LOCAL_MACHINE, key, 0, OS.KEY_READ, phkResult) == 0) {
339                 int[] lpcbData = new int[1];
340                 TCHAR buffer = new TCHAR (0, "InstallDir", true); //$NON-NLS-1$
341                 int result = OS.RegQueryValueEx (phkResult[0], buffer, 0, null, (TCHAR)null, lpcbData);
342                 if (result == 0) {
343                         TCHAR lpData = new TCHAR (0, lpcbData[0] / TCHAR.sizeof);
344                         result = OS.RegQueryValueEx (phkResult[0], buffer, 0, null, lpData, lpcbData);
345                         if (result == 0) {
346                                 OS.RegCloseKey (phkResult[0]);
347                                 return lpData.toString (0, lpData.strlen ());
348                         }
349                 }
350                 OS.RegCloseKey (phkResult[0]);
351         }
352         return null;
353 }
354
355 static String stringFromCFString (long cfString) {
356         if (cfString == 0) return null;
357         int length = WebKit_win32.CFStringGetLength (cfString);
358         long ptr = WebKit_win32.CFStringGetCharactersPtr (cfString);
359         char[] chars = new char[length];
360         if (ptr != 0) {
361                 OS.MoveMemory (chars, ptr, length);
362         } else {
363                 for (int j = 0; j < length; j++) {
364                         chars[j] = WebKit_win32.CFStringGetCharacterAtIndex (cfString, j);
365                 }
366         }
367         return new String (chars);
368 }
369
370 static String stringFromJSString (long jsString) {
371         if (jsString == 0) return null;
372         int length = WebKit_win32.JSStringGetLength (jsString);
373         byte[] bytes = new byte[length + 1];
374         WebKit_win32.JSStringGetUTF8CString (jsString, bytes, length + 1);
375         return new String (bytes);
376 }
377
378 @Override
379 public boolean back () {
380         int[] result = new int[1];
381         webView.goBack (result);
382         return result[0] != 0;
383 }
384
385 long callJava (long ctx, long func, long thisObject, long argumentCount, long arguments, long exception) {
386         Object returnValue = null;
387         if (argumentCount == 3) {
388                 long[] result = new long[1];
389                 C.memmove (result, arguments, C.PTR_SIZEOF);
390                 int type = WebKit_win32.JSValueGetType (ctx, result[0]);
391                 if (type == WebKit_win32.kJSTypeNumber) {
392                         int index = ((Double)convertToJava (ctx, result[0])).intValue ();
393                         result[0] = 0;
394                         if (index > 0) {
395                                 C.memmove (result, arguments + C.PTR_SIZEOF, C.PTR_SIZEOF);
396                                 type = WebKit_win32.JSValueGetType (ctx, result[0]);
397                                 if (type == WebKit_win32.kJSTypeString) {
398                                         String token = (String)convertToJava (ctx, result[0]);
399                                         BrowserFunction function = (BrowserFunction)functions.get (index);
400                                         if (function != null && token.equals (function.token)) {
401                                                 try {
402                                                         C.memmove (result, arguments + 2 * C.PTR_SIZEOF, C.PTR_SIZEOF);
403                                                         Object temp = convertToJava (ctx, result[0]);
404                                                         if (temp instanceof Object[]) {
405                                                                 Object[] args = (Object[])temp;
406                                                                 try {
407                                                                         returnValue = function.function (args);
408                                                                 } catch (Exception e) {
409                                                                         /* exception during function invocation */
410                                                                         returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
411                                                                 }
412                                                         }
413                                                 } catch (IllegalArgumentException e) {
414                                                         /* invalid argument value type */
415                                                         if (function.isEvaluate) {
416                                                                 /* notify the function so that a java exception can be thrown */
417                                                                 function.function (new String[] {WebBrowser.CreateErrorString (new SWTException (SWT.ERROR_INVALID_RETURN_VALUE).getLocalizedMessage ())});
418                                                         }
419                                                         returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
420                                                 }
421                                         }
422                                 }
423                         }
424                 }
425         }
426         return convertToJS (ctx, returnValue);
427 }
428
429 @Override
430 public boolean close () {
431         return shouldClose ();
432 }
433
434 Object convertToJava (long ctx, long value) {
435         int type = WebKit_win32.JSValueGetType (ctx, value);
436         switch (type) {
437                 case WebKit_win32.kJSTypeBoolean: {
438                         int result = (int)WebKit_win32.JSValueToNumber (ctx, value, null);
439                         return result != 0;
440                 }
441                 case WebKit_win32.kJSTypeNumber: {
442                         double result = WebKit_win32.JSValueToNumber (ctx, value, null);
443                         return result;
444                 }
445                 case WebKit_win32.kJSTypeString: {
446                         long string = WebKit_win32.JSValueToStringCopy (ctx, value, null);
447                         if (string == 0) return ""; //$NON-NLS-1$
448                         long length = WebKit_win32.JSStringGetMaximumUTF8CStringSize (string);
449                         byte[] bytes = new byte[(int)length];
450                         length = WebKit_win32.JSStringGetUTF8CString (string, bytes, length);
451                         WebKit_win32.JSStringRelease (string);
452                         /* length-1 is needed below to exclude the terminator character */
453                         return new String (bytes, 0, (int)length - 1, StandardCharsets.UTF_8);
454                 }
455                 case WebKit_win32.kJSTypeNull:
456                         // FALL THROUGH
457                 case WebKit_win32.kJSTypeUndefined: return null;
458                 case WebKit_win32.kJSTypeObject: {
459                         byte[] bytes = (PROPERTY_LENGTH + '\0').getBytes (StandardCharsets.UTF_8);
460                         long propertyName = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
461                         long valuePtr = WebKit_win32.JSObjectGetProperty (ctx, value, propertyName, null);
462                         WebKit_win32.JSStringRelease (propertyName);
463                         type = WebKit_win32.JSValueGetType (ctx, valuePtr);
464                         if (type == WebKit_win32.kJSTypeNumber) {
465                                 int length = (int)WebKit_win32.JSValueToNumber (ctx, valuePtr, null);
466                                 Object[] result = new Object[length];
467                                 for (int i = 0; i < length; i++) {
468                                         long current = WebKit_win32.JSObjectGetPropertyAtIndex (ctx, value, i, null);
469                                         if (current != 0) {
470                                                 result[i] = convertToJava (ctx, current);
471                                         }
472                                 }
473                                 return result;
474                         }
475                 }
476         }
477         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
478         return null;
479 }
480
481 long convertToJS (long ctx, Object value) {
482         if (value == null) {
483                 return WebKit_win32.JSValueMakeNull (ctx);
484         }
485         if (value instanceof String) {
486                 byte[] bytes = ((String)value + '\0').getBytes (StandardCharsets.UTF_8);
487                 long stringRef = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
488                 long result = WebKit_win32.JSValueMakeString (ctx, stringRef);
489                 WebKit_win32.JSStringRelease (stringRef);
490                 return result;
491         }
492         if (value instanceof Boolean) {
493                 return WebKit_win32.JSValueMakeBoolean (ctx, ((Boolean)value).booleanValue () ? 1 : 0);
494         }
495         if (value instanceof Number) {
496                 return WebKit_win32.JSValueMakeNumber (ctx, ((Number)value).doubleValue ());
497         }
498         if (value instanceof Object[]) {
499                 Object[] arrayValue = (Object[]) value;
500                 int length = arrayValue.length;
501                 long[] arguments = new long[length];
502                 for (int i = 0; i < length; i++) {
503                         Object javaObject = arrayValue[i];
504                         long jsObject = convertToJS (ctx, javaObject);
505                         arguments[i] = jsObject;
506                 }
507                 return WebKit_win32.JSObjectMakeArray (ctx, length, arguments, null);
508         }
509         SWT.error (SWT.ERROR_INVALID_RETURN_VALUE);
510         return 0;
511 }
512
513 @Override
514 public void create (Composite parent, int style) {
515         if (!LibraryLoaded) {
516                 browser.dispose ();
517                 SWT.error (SWT.ERROR_NO_HANDLES, null, LibraryLoadError == null ? null : " [" + LibraryLoadError + ']'); //$NON-NLS-1$
518         }
519
520         if (ExternalClass == 0) {
521                 JSClassDefinition jsClassDefinition = new JSClassDefinition ();
522                 byte[] bytes = (CLASSNAME_EXTERNAL + '\0').getBytes ();
523                 jsClassDefinition.className = C.malloc (bytes.length);
524                 C.memmove (jsClassDefinition.className, bytes, bytes.length);
525
526                 /* custom callbacks for hasProperty, getProperty and callAsFunction */
527                 long addr = WebKit_win32.JSObjectHasPropertyProc_CALLBACK (JSObjectHasPropertyProc.getAddress ());
528                 jsClassDefinition.hasProperty = addr;
529                 addr = WebKit_win32.JSObjectGetPropertyProc_CALLBACK (JSObjectGetPropertyProc.getAddress ());
530                 jsClassDefinition.getProperty = addr;
531
532                 long classDefinitionPtr = C.malloc (JSClassDefinition.sizeof);
533                 WebKit_win32.memmove (classDefinitionPtr, jsClassDefinition, JSClassDefinition.sizeof);
534                 ExternalClass = WebKit_win32.JSClassCreate (classDefinitionPtr);
535                 WebKit_win32.JSClassRetain (ExternalClass);
536         }
537
538         long[] result = new long[1];
539         int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebView, 0, WebKit_win32.IID_IWebView, result);
540         if (hr != COM.S_OK || result[0] == 0) {
541                 browser.dispose ();
542                 error (hr);
543         }
544         webView = new IWebView (result[0]);
545         webViewData = C.malloc (C.PTR_SIZEOF);
546         C.memmove (webViewData, new long[] {webView.getAddress ()}, C.PTR_SIZEOF);
547         hr = webView.setHostWindow (browser.handle);
548         if (hr != COM.S_OK) {
549                 browser.dispose ();
550                 error (hr);
551         }
552         hr = webView.initWithFrame (new RECT (), 0, 0);
553         if (hr != COM.S_OK) {
554                 browser.dispose ();
555                 error (hr);
556         }
557         result[0] = 0;
558         hr = webView.QueryInterface (WebKit_win32.IID_IWebViewPrivate, result);
559         if (hr != COM.S_OK || result[0] == 0) {
560                 browser.dispose ();
561                 error (hr);
562         }
563         IWebViewPrivate webViewPrivate = new IWebViewPrivate (result[0]);
564         result[0] = 0;
565         hr = webViewPrivate.viewWindow (result);
566         if (hr != COM.S_OK || result[0] == 0) {
567                 browser.dispose ();
568                 error (hr);
569         }
570         webViewPrivate.Release ();
571         webViewWindowHandle = result[0];
572
573         webFrameLoadDelegate = new WebFrameLoadDelegate (browser);
574         hr = webView.setFrameLoadDelegate (webFrameLoadDelegate.getAddress ());
575         if (hr != COM.S_OK) {
576                 browser.dispose ();
577                 error (hr);
578         }
579         webUIDelegate = new WebUIDelegate (browser);
580         hr = webView.setUIDelegate (webUIDelegate.getAddress ());
581         if (hr != COM.S_OK) {
582                 browser.dispose ();
583                 error (hr);
584         }
585
586         webResourceLoadDelegate = new WebResourceLoadDelegate (browser);
587         hr = webView.setResourceLoadDelegate (webResourceLoadDelegate.getAddress ());
588         if (hr != COM.S_OK) {
589                 browser.dispose ();
590                 error (hr);
591         }
592
593         webDownloadDelegate = new WebDownloadDelegate (browser);
594         hr = webView.setDownloadDelegate (webDownloadDelegate.getAddress ());
595         if (hr != COM.S_OK) {
596                 browser.dispose ();
597                 error (hr);
598         }
599
600         webPolicyDelegate = new WebPolicyDelegate (browser);
601         hr = webView.setPolicyDelegate (webPolicyDelegate.getAddress ());
602         if (hr != COM.S_OK) {
603                 browser.dispose ();
604                 error (hr);
605         }
606
607         initializeWebViewPreferences ();
608
609         Listener listener = e -> {
610                 switch (e.type) {
611                         case SWT.Dispose: {
612                                 /* make this handler run after other dispose listeners */
613                                 if (ignoreDispose) {
614                                         ignoreDispose = false;
615                                         break;
616                                 }
617                                 ignoreDispose = true;
618                                 browser.notifyListeners (e.type, e);
619                                 e.type = SWT.NONE;
620                                 onDispose ();
621                                 break;
622                         }
623                         case SWT.FocusIn: {
624                                 OS.SetFocus (webViewWindowHandle);
625                                 break;
626                         }
627                         case SWT.Resize: {
628                                 Rectangle bounds = DPIUtil.autoScaleUp(browser.getClientArea ()); // To Pixels
629                                 OS.SetWindowPos (webViewWindowHandle, 0, bounds.x, bounds.y, bounds.width, bounds.height, OS.SWP_DRAWFRAME);
630                                 break;
631                         }
632                         case SWT.Traverse: {
633                                 if (traverseOut) {
634                                         e.doit = true;
635                                         traverseOut = false;
636                                 } else {
637                                         e.doit = false;
638                                 }
639                                 break;
640                         }
641                 }
642         };
643         browser.addListener (SWT.Dispose, listener);
644         browser.addListener (SWT.KeyDown, listener); /* needed for tabbing into the Browser */
645         browser.addListener (SWT.FocusIn, listener);
646         browser.addListener (SWT.Resize, listener);
647         browser.addListener (SWT.Traverse, listener);
648
649         eventFunction = new BrowserFunction (browser, "HandleWebKitEvent") { //$NON-NLS-1$
650                 @Override
651                 public Object function (Object[] arguments) {
652                         return handleEvent (arguments) ? Boolean.TRUE : Boolean.FALSE;
653                 };
654         };
655 }
656
657 @Override
658 public boolean execute (String script) {
659         long[] result = new long[1];
660         int hr = webView.mainFrame (result);
661         if (hr != COM.S_OK || result[0] == 0) {
662                 return false;
663         }
664         IWebFrame frame = new IWebFrame (result[0]);
665         long context = frame.globalContext ();
666         frame.Release ();
667         if (context == 0) {
668                 return false;
669         }
670         byte[] bytes = (script + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$
671         long scriptString = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
672         if (scriptString == 0) return false;
673         bytes = (getUrl () + '\0').getBytes (StandardCharsets.UTF_8); //$NON-NLS-1$
674         long urlString = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
675         if (urlString == 0) {
676                 WebKit_win32.JSStringRelease (scriptString);
677                 return false;
678         }
679         long evalResult = WebKit_win32.JSEvaluateScript (context, scriptString, 0, urlString, 0, null);
680         WebKit_win32.JSStringRelease (urlString);
681         WebKit_win32.JSStringRelease (scriptString);
682         return evalResult != 0;
683 }
684
685 @Override
686 public boolean forward () {
687         int[] result = new int[1];
688         webView.goForward (result);
689         return result[0] != 0;
690 }
691
692 @Override
693 public String getBrowserType () {
694         return "webkit"; //$NON-NLS-1$
695 }
696
697 @Override
698 public String getText () {
699         long[] result = new long[1];
700         int hr = webView.mainFrame (result);
701         if (hr != COM.S_OK || result[0] == 0) {
702                 return EMPTY_STRING;
703         }
704         IWebFrame mainFrame = new IWebFrame (result[0]);
705         result[0] = 0;
706         hr = mainFrame.dataSource (result);
707         mainFrame.Release ();
708         if (hr != COM.S_OK || result[0] == 0) {
709                 return EMPTY_STRING;
710         }
711         IWebDataSource dataSource = new IWebDataSource (result[0]);
712         result[0] = 0;
713         hr = dataSource.representation (result);
714         dataSource.Release ();
715         if (hr != COM.S_OK || result[0] == 0) {
716                 return EMPTY_STRING;
717         }
718         IWebDocumentRepresentation representation = new IWebDocumentRepresentation (result[0]);
719         result[0] = 0;
720         hr = representation.documentSource (result);
721         representation.Release ();
722         if (hr != COM.S_OK || result[0] == 0) {
723                 return EMPTY_STRING;
724         }
725         String source = extractBSTR (result[0]);
726         COM.SysFreeString (result[0]);
727         return source;
728 }
729
730 @Override
731 public String getUrl () {
732         return webFrameLoadDelegate.getUrl ();
733 }
734
735 boolean handleEvent (Object[] arguments) {
736
737         /*
738         * DOM events are currently received by hooking DOM listeners
739         * in javascript that invoke this method via a BrowserFunction.
740         * Document.addListener is not implemented on WebKit on windows.
741         * The argument lists received here are:
742         *
743         * For key events:
744         *       argument 0: type (String)
745         *       argument 1: keyCode (Double)
746         *       argument 2: charCode (Double)
747         *       argument 3: altKey (Boolean)
748         *       argument 4: ctrlKey (Boolean)
749         *       argument 5: shiftKey (Boolean)
750         *       argument 6: metaKey (Boolean)
751         *       returns doit
752         *
753         * For mouse events
754         *       argument 0: type (String)
755         *       argument 1: screenX (Double)
756         *       argument 2: screenY (Double)
757         *       argument 3: detail (Double)
758         *       argument 4: button (Double)
759         *       argument 5: altKey (Boolean)
760         *       argument 6: ctrlKey (Boolean)
761         *       argument 7: shiftKey (Boolean)
762         *       argument 8: metaKey (Boolean)
763         *       argument 9: hasRelatedTarget (Boolean)
764         *       returns doit
765         */
766
767         String type = (String)arguments[0];
768         if (type.equals (DOMEVENT_KEYDOWN)) {
769                 int keyCode = translateKey (((Double)arguments[1]).intValue ());
770                 lastKeyCode = keyCode;
771                 switch (keyCode) {
772                         case SWT.SHIFT:
773                         case SWT.CONTROL:
774                         case SWT.ALT:
775                         case SWT.CAPS_LOCK:
776                         case SWT.NUM_LOCK:
777                         case SWT.SCROLL_LOCK:
778                         case SWT.COMMAND:
779 //                      case SWT.ESC:
780                         case SWT.TAB:
781                         case SWT.PAUSE:
782 //                      case SWT.BS:
783                         case SWT.INSERT:
784                         case SWT.DEL:
785                         case SWT.HOME:
786                         case SWT.END:
787                         case SWT.PAGE_UP:
788                         case SWT.PAGE_DOWN:
789                         case SWT.ARROW_DOWN:
790                         case SWT.ARROW_UP:
791                         case SWT.ARROW_LEFT:
792                         case SWT.ARROW_RIGHT:
793                         case SWT.F1:
794                         case SWT.F2:
795                         case SWT.F3:
796                         case SWT.F4:
797                         case SWT.F5:
798                         case SWT.F6:
799                         case SWT.F7:
800                         case SWT.F8:
801                         case SWT.F9:
802                         case SWT.F10:
803                         case SWT.F11:
804                         case SWT.F12: {
805                                 /* keypress events will not be received for these keys, so send KeyDowns for them now */
806
807                                 Event keyEvent = new Event ();
808                                 keyEvent.widget = browser;
809                                 keyEvent.type = type.equals (DOMEVENT_KEYDOWN) ? SWT.KeyDown : SWT.KeyUp;
810                                 keyEvent.keyCode = keyCode;
811                                 switch (keyCode) {
812                                         case SWT.BS: keyEvent.character = SWT.BS; break;
813                                         case SWT.DEL: keyEvent.character = SWT.DEL; break;
814                                         case SWT.ESC: keyEvent.character = SWT.ESC; break;
815                                         case SWT.TAB: keyEvent.character = SWT.TAB; break;
816                                 }
817                                 lastCharCode = keyEvent.character;
818                                 keyEvent.stateMask =
819                                         (((Boolean)arguments[3]).booleanValue () ? SWT.ALT : 0) |
820                                         (((Boolean)arguments[4]).booleanValue () ? SWT.CTRL : 0) |
821                                         (((Boolean)arguments[5]).booleanValue () ? SWT.SHIFT : 0) |
822                                         (((Boolean)arguments[6]).booleanValue () ? SWT.COMMAND : 0);
823                                 keyEvent.stateMask &= ~keyCode;         /* remove current keydown if it's a state key */
824                                 if (!sendKeyEvent (keyEvent) || browser.isDisposed ()) return false;
825                                 break;
826                         }
827                 }
828                 return true;
829         }
830
831         if (type.equals (DOMEVENT_KEYPRESS)) {
832                 /*
833                 * if keydown could not determine a keycode for this key then it's a
834                 * key for which key events are not sent (eg.- the Windows key)
835                 */
836                 if (lastKeyCode == 0) return true;
837
838                 lastCharCode = ((Double)arguments[2]).intValue ();
839                 if (((Boolean)arguments[4]).booleanValue () && (0 <= lastCharCode && lastCharCode <= 0x7F)) {
840                         if ('a' <= lastCharCode && lastCharCode <= 'z') lastCharCode -= 'a' - 'A';
841                         if (64 <= lastCharCode && lastCharCode <= 95) lastCharCode -= 64;
842                 }
843
844                 Event keyEvent = new Event ();
845                 keyEvent.widget = browser;
846                 keyEvent.type = SWT.KeyDown;
847                 keyEvent.keyCode = lastKeyCode;
848                 keyEvent.character = (char)lastCharCode;
849                 keyEvent.stateMask =
850                         (((Boolean)arguments[3]).booleanValue () ? SWT.ALT : 0) |
851                         (((Boolean)arguments[4]).booleanValue () ? SWT.CTRL : 0) |
852                         (((Boolean)arguments[5]).booleanValue () ? SWT.SHIFT : 0) |
853                         (((Boolean)arguments[6]).booleanValue () ? SWT.COMMAND : 0);
854                 return sendKeyEvent (keyEvent) && !browser.isDisposed ();
855         }
856
857         if (type.equals (DOMEVENT_KEYUP)) {
858                 int keyCode = translateKey (((Double)arguments[1]).intValue ());
859                 if (keyCode == 0) {
860                         /* indicates a key for which key events are not sent */
861                         return true;
862                 }
863                 if (keyCode != lastKeyCode) {
864                         /* keyup does not correspond to the last keydown */
865                         lastKeyCode = keyCode;
866                         lastCharCode = 0;
867                 }
868
869                 Event keyEvent = new Event ();
870                 keyEvent.widget = browser;
871                 keyEvent.type = SWT.KeyUp;
872                 keyEvent.keyCode = lastKeyCode;
873                 keyEvent.character = (char)lastCharCode;
874                 keyEvent.stateMask =
875                         (((Boolean)arguments[3]).booleanValue () ? SWT.ALT : 0) |
876                         (((Boolean)arguments[4]).booleanValue () ? SWT.CTRL : 0) |
877                         (((Boolean)arguments[5]).booleanValue () ? SWT.SHIFT : 0) |
878                         (((Boolean)arguments[6]).booleanValue () ? SWT.COMMAND : 0);
879                 switch (lastKeyCode) {
880                         case SWT.SHIFT:
881                         case SWT.CONTROL:
882                         case SWT.ALT:
883                         case SWT.COMMAND: {
884                                 keyEvent.stateMask |= lastKeyCode;
885                         }
886                 }
887                 browser.notifyListeners (keyEvent.type, keyEvent);
888                 lastKeyCode = lastCharCode = 0;
889                 return keyEvent.doit && !browser.isDisposed ();
890         }
891
892         /* mouse events */
893
894         /*
895          * MouseOver and MouseOut events are fired any time the mouse enters or exits
896          * any element within the Browser.  To ensure that SWT events are only
897          * fired for mouse movements into or out of the Browser, do not fire an
898          * event if there is a related target element.
899          */
900         if (type.equals (DOMEVENT_MOUSEOVER) || type.equals (DOMEVENT_MOUSEOUT)) {
901                 if (((Boolean)arguments[9]).booleanValue ()) return true;
902         }
903
904         /*
905          * The position of mouse events is received in screen-relative coordinates
906          * in order to handle pages with frames, since frames express their event
907          * coordinates relative to themselves rather than relative to their top-
908          * level page.  Convert screen-relative coordinates to be browser-relative.
909          */
910         Point position = new Point (((Double)arguments[1]).intValue (), ((Double)arguments[2]).intValue ());// Points or Pixles ?
911         position = browser.getDisplay ().map (null, browser, position);
912
913         Event mouseEvent = new Event ();
914         mouseEvent.widget = browser;
915         mouseEvent.x = position.x;
916         mouseEvent.y = position.y;
917         int mask =
918                 (((Boolean)arguments[5]).booleanValue () ? SWT.ALT : 0) |
919                 (((Boolean)arguments[6]).booleanValue () ? SWT.CTRL : 0) |
920                 (((Boolean)arguments[7]).booleanValue () ? SWT.SHIFT : 0);
921         mouseEvent.stateMask = mask;
922
923         if (type.equals (DOMEVENT_MOUSEDOWN)) {
924                 mouseEvent.type = SWT.MouseDown;
925                 mouseEvent.count = ((Double)arguments[3]).intValue ();
926                 mouseEvent.button = ((Double)arguments[4]).intValue ();
927                 browser.notifyListeners (mouseEvent.type, mouseEvent);
928                 if (browser.isDisposed ()) return true;
929                 if (((Double)arguments[3]).intValue () == 2) {
930                         mouseEvent = new Event ();
931                         mouseEvent.type = SWT.MouseDoubleClick;
932                         mouseEvent.widget = browser;
933                         mouseEvent.x = position.x;
934                         mouseEvent.y = position.y;
935                         mouseEvent.stateMask = mask;
936                         mouseEvent.count = ((Double)arguments[3]).intValue ();
937                         mouseEvent.button = ((Double)arguments[4]).intValue ();
938                         browser.notifyListeners (mouseEvent.type, mouseEvent);
939                 }
940                 return true;
941         }
942
943         if (type.equals (DOMEVENT_MOUSEUP)) {
944                 mouseEvent.type = SWT.MouseUp;
945                 mouseEvent.count = ((Double)arguments[3]).intValue ();
946                 mouseEvent.button = ((Double)arguments[4]).intValue ();
947                 switch (mouseEvent.button) {
948                         case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
949                         case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
950                         case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
951                         case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
952                         case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
953                 }
954         } else if (type.equals (DOMEVENT_MOUSEMOVE)) {
955                 mouseEvent.type = SWT.MouseMove;
956         } else if (type.equals (DOMEVENT_MOUSEWHEEL)) {
957                 mouseEvent.type = SWT.MouseWheel;
958                 mouseEvent.count = ((Double)arguments[3]).intValue ();
959         } else if (type.equals (DOMEVENT_MOUSEOVER)) {
960                 mouseEvent.type = SWT.MouseEnter;
961         } else if (type.equals (DOMEVENT_MOUSEOUT)) {
962                 mouseEvent.type = SWT.MouseExit;
963                 if (mouseEvent.x < 0) mouseEvent.x = -1;
964                 if (mouseEvent.y < 0) mouseEvent.y = -1;
965         } else if (type.equals (DOMEVENT_DRAGSTART)) {
966                 mouseEvent.type = SWT.DragDetect;
967                 mouseEvent.button = ((Double)arguments[4]).intValue () + 1;
968                 switch (mouseEvent.button) {
969                         case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
970                         case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
971                         case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
972                         case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
973                         case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
974                 }
975         }
976
977         browser.notifyListeners (mouseEvent.type, mouseEvent);
978         return true;
979 }
980
981 @Override
982 public boolean isBackEnabled () {
983         long[] address = new long[1];
984         int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, address);
985         if (hr != COM.S_OK || address[0] == 0) {
986                 return false;
987         }
988         IWebIBActions webIBActions = new IWebIBActions (address[0]);
989         int[] result = new int[1];
990         webIBActions.canGoBack (webView.getAddress (), result);
991         webIBActions.Release ();
992         return result[0] != 0;
993 }
994
995 @Override
996 public boolean isFocusControl () {
997         long hwndFocus = OS.GetFocus ();
998         return hwndFocus != 0 && hwndFocus == webViewWindowHandle;
999 }
1000
1001 @Override
1002 public boolean isForwardEnabled () {
1003         long[] address = new long[1];
1004         int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, address);
1005         if (hr != COM.S_OK || address[0] == 0) {
1006                 return false;
1007         }
1008         IWebIBActions webIBActions = new IWebIBActions (address[0]);
1009         int[] result = new int[1];
1010         webIBActions.canGoForward (webView.getAddress (), result);
1011         webIBActions.Release ();
1012         return result[0] != 0;
1013 }
1014
1015 void onDispose () {
1016         /* Browser could have been disposed by one of the Dispose listeners */
1017         if (!browser.isDisposed ()) {
1018                 /* invoke onbeforeunload handlers but don't prompt with message box */
1019                 if (!browser.isClosing) {
1020                         webUIDelegate.prompt = false;
1021                         shouldClose ();
1022                         webUIDelegate.prompt = true;
1023                 }
1024         }
1025
1026         Iterator<BrowserFunction> elements = functions.values().iterator ();
1027         while (elements.hasNext ()) {
1028                 elements.next ().dispose (false);
1029         }
1030         functions = null;
1031
1032         eventFunction.dispose();
1033         eventFunction = null;
1034         C.free (webViewData);
1035
1036         webView.setPreferences (0);
1037         webView.setHostWindow (0);
1038         webView.setFrameLoadDelegate (0);
1039         webView.setResourceLoadDelegate (0);
1040         webView.setUIDelegate (0);
1041         webView.setPolicyDelegate (0);
1042         webView.setDownloadDelegate (0);
1043         webView.Release();
1044         webView = null;
1045         webDownloadDelegate = null;
1046         webFrameLoadDelegate = null;
1047         webPolicyDelegate = null;
1048         webResourceLoadDelegate = null;
1049         webUIDelegate = null;
1050         lastNavigateURL = null;
1051 }
1052
1053 @Override
1054 public void refresh () {
1055         webFrameLoadDelegate.html = null;
1056         long[] result = new long[1];
1057         int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, result);
1058         if (hr != COM.S_OK || result[0] == 0) {
1059                 return;
1060         }
1061         IWebIBActions webIBActions = new IWebIBActions (result[0]);
1062         webIBActions.reload (webView.getAddress ());
1063         webIBActions.Release ();
1064 }
1065
1066 @Override
1067 boolean sendKeyEvent (Event event) {
1068         /*
1069          * browser.traverse() is called through dislay.translateTraversal() for all
1070          * traversal types except SWT.TRAVERSE_MNEMONIC. So, override
1071          * WebBrowser.sendKeyEvent() so that when it is called from handleEvent(),
1072          * browser.traverse() is not called again.
1073          */
1074         boolean doit = true;
1075         switch (event.keyCode) {
1076                 case SWT.ESC:
1077                 case SWT.CR:
1078                 case SWT.ARROW_DOWN:
1079                 case SWT.ARROW_RIGHT:
1080                 case SWT.ARROW_UP:
1081                 case SWT.ARROW_LEFT:
1082                 case SWT.TAB:
1083                 case SWT.PAGE_DOWN:
1084                 case SWT.PAGE_UP:
1085                         break;
1086                 default: {
1087                         if (translateMnemonics ()) {
1088                                 if (event.character != 0 && (event.stateMask & (SWT.ALT | SWT.CTRL)) == SWT.ALT) {
1089                                         int traversal = SWT.TRAVERSE_MNEMONIC;
1090                                         boolean oldEventDoit = event.doit;
1091                                         event.doit = true;
1092                                         doit = !browser.traverse (traversal, event);
1093                                         event.doit = oldEventDoit;
1094                                 }
1095                         }
1096                         break;
1097                 }
1098         }
1099         if (doit) {
1100                 browser.notifyListeners (event.type, event);
1101                 doit = event.doit;
1102         }
1103         return doit;
1104 }
1105
1106 @Override
1107 public boolean setText (String html, boolean trusted) {
1108         /*
1109         * If this.html is not null then the about:blank page is already being loaded,
1110         * so no navigate is required.  Just set the html that is to be shown.
1111         */
1112         boolean blankLoading = webFrameLoadDelegate.html != null;
1113         webFrameLoadDelegate.html = html;
1114         untrustedText = !trusted;
1115         if (blankLoading) return true;
1116
1117         long[] result = new long[1];
1118         int hr = webView.mainFrame (result);
1119         if (hr != COM.S_OK || result[0] == 0) {
1120                 return false;
1121         }
1122         IWebFrame frame = new IWebFrame (result[0]);
1123
1124         result[0] = 0;
1125         hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebMutableURLRequest, 0, WebKit_win32.IID_IWebMutableURLRequest, result);
1126         if (hr != COM.S_OK || result[0] == 0) {
1127                 frame.Release ();
1128                 return false;
1129         }
1130         IWebMutableURLRequest request = new IWebMutableURLRequest (result[0]);
1131
1132         long urlString = createBSTR (ABOUT_BLANK);
1133         hr = request.setURL (urlString);
1134         COM.SysFreeString (urlString);
1135
1136         if (hr == COM.S_OK) {
1137                 hr = frame.loadRequest (request.getAddress ());
1138         }
1139         frame.Release ();
1140         request.Release ();
1141         return hr == COM.S_OK;
1142 }
1143
1144 @Override
1145 public boolean setUrl (String url, String postData, String[] headers) {
1146         if (url.length () == 0) return false;
1147         /*
1148         * WebKit attempts to open the exact url string that is passed to it and
1149         * will not infer a protocol if it's not specified.  Detect the case of an
1150         * invalid URL string and try to fix it by prepending an appropriate protocol.
1151         */
1152         try {
1153                 new URL (url);
1154         } catch (MalformedURLException e) {
1155                 String testUrl = null;
1156                 if (new File (url).isAbsolute ()) {
1157                         /* appears to be a local file */
1158                         testUrl = PROTOCOL_FILE + url;
1159                 } else {
1160                         testUrl = PROTOCOL_HTTP + url;
1161                 }
1162                 try {
1163                         new URL (testUrl);
1164                         url = testUrl;          /* adding the protocol made the url valid */
1165                 } catch (MalformedURLException e2) {
1166                         /* adding the protocol did not make the url valid, so do nothing */
1167                 }
1168         }
1169         webFrameLoadDelegate.html = null;
1170         lastNavigateURL = url;
1171         long[] result = new long[1];
1172         int hr = webView.mainFrame (result);
1173         if (hr != COM.S_OK || result[0] == 0) {
1174                 return false;
1175         }
1176         IWebFrame frame = new IWebFrame (result[0]);
1177
1178         result[0] = 0;
1179         hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebMutableURLRequest, 0, WebKit_win32.IID_IWebMutableURLRequest, result);
1180         if (hr != COM.S_OK || result[0] == 0) {
1181                 frame.Release ();
1182                 return false;
1183         }
1184         IWebMutableURLRequest request = new IWebMutableURLRequest (result[0]);
1185
1186         if (postData != null) { //TODO: POST
1187 //      webResourceLoadDelegate.postData = postData;
1188 //      long postString = createBSTR (POST);
1189 //              hr = request.setHTTPMethod (postString);
1190 //              COM.SysFreeString (postString);
1191 //
1192 //              result[0] = 0;
1193 //              hr = request.QueryInterface (WebKit_win32.IID_IWebMutableURLRequestPrivate, result);
1194 //              if (hr == COM.S_OK && result[0] != 0) {
1195 //                      IWebMutableURLRequestPrivate requestPrivate = new IWebMutableURLRequestPrivate(result[0]);
1196 //                      int cfRequest = requestPrivate.cfRequest();
1197 //                      byte[] bytes = postData.getBytes();
1198 //                      long data = WebKit_win32.CFDataCreate(0, bytes, bytes.length);
1199 //                      if (data != 0)WebKit_win32.CFURLRequestSetHTTPRequestBody(cfRequest, data);
1200 //
1201 //                      long dataGet = WebKit_win32.CFURLRequestCopyHTTPRequestBody(cfRequest);
1202 //                      int length = WebKit_win32.CFDataGetLength(dataGet);
1203 //                      long bytePtr = WebKit_win32.CFDataGetBytePtr(dataGet);
1204 //              }
1205         }
1206         hr = COM.S_OK;  //TODO: once post code is completed, remove this line if not required
1207         if (headers != null) {
1208                 for (int i = 0; i < headers.length; i++) {
1209                         String current = headers[i];
1210                         if (current != null) {
1211                                 int index = current.indexOf (':');
1212                                 if (index != -1) {
1213                                         String key = current.substring (0, index).trim ();
1214                                         String value = current.substring (index + 1).trim ();
1215                                         if (key.length () > 0 && value.length () > 0) {
1216                                                 long valueString = createBSTR (value);
1217                                                 if (key.equalsIgnoreCase (USER_AGENT)) {
1218                                                         /*
1219                                                         * Feature of WebKit.  The user-agent header value cannot be overridden
1220                                                         * here.  The workaround is to temporarily set the value on the WebView
1221                                                         * and then remove it after the loading of the request has begun.
1222                                                         */
1223                                                         hr = webView.setCustomUserAgent (valueString);
1224                                                 } else {
1225                                                         long keyString = createBSTR (key);
1226                                                         hr = request.setValue (valueString, keyString);
1227                                                         COM.SysFreeString (keyString);
1228                                                 }
1229                                                 COM.SysFreeString (valueString);
1230                                         }
1231                                 }
1232                         }
1233                 }
1234         }
1235         if (hr == COM.S_OK) {
1236                 long urlString = createBSTR (url);
1237                 hr = request.setURL (urlString);
1238                 COM.SysFreeString (urlString);
1239                 if (hr == COM.S_OK) {
1240                         hr = frame.loadRequest (request.getAddress ());
1241                 }
1242                 webView.setCustomUserAgent (0);
1243         }
1244         frame.Release ();
1245         request.Release ();
1246         return hr == COM.S_OK;
1247 }
1248
1249 boolean shouldClose () {
1250         if (!jsEnabled) return true;
1251
1252         long[] address = new long[1];
1253         int hr = webView.QueryInterface (WebKit_win32.IID_IWebViewPrivate, address);
1254         if (hr != COM.S_OK || address[0] == 0) {
1255                 return false;
1256         }
1257         IWebViewPrivate webViewPrivate = new IWebViewPrivate (address[0]);
1258         int[] result = new int[1];
1259         /* This function will fire the before unload handler for a page */
1260         webViewPrivate.shouldClose (result);
1261         webViewPrivate.Release ();
1262         return result[0] != 0;
1263 }
1264
1265 @Override
1266 public void stop () {
1267         webFrameLoadDelegate.html = null;
1268         long[] result = new long[1];
1269         int hr = webView.QueryInterface (WebKit_win32.IID_IWebIBActions, result);
1270         if (hr != COM.S_OK || result[0] == 0) {
1271                 return;
1272         }
1273         IWebIBActions webIBActions = new IWebIBActions (result[0]);
1274         webIBActions.stopLoading (webView.getAddress ());
1275         webIBActions.Release ();
1276 }
1277
1278 void initializeWebViewPreferences () {
1279         /*
1280          * Try to create separate preferences for each webview using different identifier for each webview.
1281          * Otherwise all the webviews use the shared preferences.
1282          */
1283         long[] result = new long[1];
1284         int hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebPreferences, 0, WebKit_win32.IID_IWebPreferences, result);
1285         if (hr == COM.S_OK && result[0] != 0) {
1286                 IWebPreferences preferences = new IWebPreferences (result[0]);
1287                 result[0] = 0;
1288                 hr = preferences.initWithIdentifier (createBSTR (String.valueOf (prefsIdentifier++)), result);
1289                 preferences.Release ();
1290                 if (hr == COM.S_OK && result[0] != 0) {
1291                         preferences = new IWebPreferences (result[0]);
1292                         webView.setPreferences (preferences.getAddress());
1293                         preferences.Release ();
1294                 }
1295         }
1296
1297         result[0] = 0;
1298         hr = webView.preferences (result);
1299         if (hr == COM.S_OK && result[0] != 0) {
1300                 IWebPreferences preferences = new IWebPreferences (result[0]);
1301                 preferences.setJavaScriptEnabled (1);
1302                 preferences.setJavaScriptCanOpenWindowsAutomatically (1);
1303                 preferences.setJavaEnabled (0); /* disable applets */
1304                 preferences.setTabsToLinks (1);
1305                 preferences.setFontSmoothing (WebKit_win32.FontSmoothingTypeWindows);
1306                 preferences.Release ();
1307         }
1308 }
1309
1310 }