]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/WebBrowser.java
27dd9f504519ed7de83cdb5594ac60171ced2332
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / browser / WebBrowser.java
1 /*******************************************************************************
2  * Copyright (c) 2003, 2018 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 import java.util.*;
17 import java.util.List;
18
19 import org.eclipse.swt.*;
20 import org.eclipse.swt.widgets.*;
21
22 abstract class WebBrowser {
23         Browser browser;
24         Map<Integer, BrowserFunction> functions = new HashMap<> ();
25         AuthenticationListener[] authenticationListeners = new AuthenticationListener[0];
26         CloseWindowListener[] closeWindowListeners = new CloseWindowListener[0];
27         LocationListener[] locationListeners = new LocationListener[0];
28         OpenWindowListener[] openWindowListeners = new OpenWindowListener[0];
29         ProgressListener[] progressListeners = new ProgressListener[0];
30         StatusTextListener[] statusTextListeners = new StatusTextListener[0];
31         TitleListener[] titleListeners = new TitleListener[0];
32         VisibilityWindowListener[] visibilityWindowListeners = new VisibilityWindowListener[0];
33         boolean jsEnabledOnNextPage = true, jsEnabled = true;
34         int nextFunctionIndex = 1;
35         Object evaluateResult;
36
37         static final String ERROR_ID = "org.eclipse.swt.browser.error"; // $NON-NLS-1$
38         static final String EXECUTE_ID = "SWTExecuteTemporaryFunction"; // $NON-NLS-1$
39
40         static List<String[]> NativePendingCookies = new ArrayList<> ();
41         static String CookieName, CookieValue, CookieUrl;
42         static boolean CookieResult;
43         static Runnable NativeClearSessions;
44         static Runnable NativeGetCookie;
45         static Runnable NativeSetCookie;
46
47         /* Key Mappings */
48         static final int [][] KeyTable = {
49                 /* Keyboard and Mouse Masks */
50                 {18,    SWT.ALT},
51                 {16,    SWT.SHIFT},
52                 {17,    SWT.CONTROL},
53                 {224,   SWT.COMMAND},
54
55                 /* Literal Keys */
56                 {65,    'a'},
57                 {66,    'b'},
58                 {67,    'c'},
59                 {68,    'd'},
60                 {69,    'e'},
61                 {70,    'f'},
62                 {71,    'g'},
63                 {72,    'h'},
64                 {73,    'i'},
65                 {74,    'j'},
66                 {75,    'k'},
67                 {76,    'l'},
68                 {77,    'm'},
69                 {78,    'n'},
70                 {79,    'o'},
71                 {80,    'p'},
72                 {81,    'q'},
73                 {82,    'r'},
74                 {83,    's'},
75                 {84,    't'},
76                 {85,    'u'},
77                 {86,    'v'},
78                 {87,    'w'},
79                 {88,    'x'},
80                 {89,    'y'},
81                 {90,    'z'},
82                 {48,    '0'},
83                 {49,    '1'},
84                 {50,    '2'},
85                 {51,    '3'},
86                 {52,    '4'},
87                 {53,    '5'},
88                 {54,    '6'},
89                 {55,    '7'},
90                 {56,    '8'},
91                 {57,    '9'},
92                 {32,    ' '},
93                 {59,    ';'},
94                 {61,    '='},
95                 {188,   ','},
96                 {190,   '.'},
97                 {191,   '/'},
98                 {219,   '['},
99                 {221,   ']'},
100                 {222,   '\''},
101                 {192,   '`'},
102                 {220,   '\\'},
103                 {108,   '|'},
104                 {226,   '<'},
105
106                 /* Non-Numeric Keypad Keys */
107                 {37,    SWT.ARROW_LEFT},
108                 {39,    SWT.ARROW_RIGHT},
109                 {38,    SWT.ARROW_UP},
110                 {40,    SWT.ARROW_DOWN},
111                 {45,    SWT.INSERT},
112                 {36,    SWT.HOME},
113                 {35,    SWT.END},
114                 {46,    SWT.DEL},
115                 {33,    SWT.PAGE_UP},
116                 {34,    SWT.PAGE_DOWN},
117
118                 /* Virtual and Ascii Keys */
119                 {8,             SWT.BS},
120                 {13,    SWT.CR},
121                 {9,             SWT.TAB},
122                 {27,    SWT.ESC},
123                 {12,    SWT.DEL},
124
125                 /* Functions Keys */
126                 {112,   SWT.F1},
127                 {113,   SWT.F2},
128                 {114,   SWT.F3},
129                 {115,   SWT.F4},
130                 {116,   SWT.F5},
131                 {117,   SWT.F6},
132                 {118,   SWT.F7},
133                 {119,   SWT.F8},
134                 {120,   SWT.F9},
135                 {121,   SWT.F10},
136                 {122,   SWT.F11},
137                 {123,   SWT.F12},
138                 {124,   SWT.F13},
139                 {125,   SWT.F14},
140                 {126,   SWT.F15},
141                 {127,   0},
142                 {128,   0},
143                 {129,   0},
144                 {130,   0},
145                 {131,   0},
146                 {132,   0},
147                 {133,   0},
148                 {134,   0},
149                 {135,   0},
150
151                 /* Numeric Keypad Keys */
152                 {96,    SWT.KEYPAD_0},
153                 {97,    SWT.KEYPAD_1},
154                 {98,    SWT.KEYPAD_2},
155                 {99,    SWT.KEYPAD_3},
156                 {100,   SWT.KEYPAD_4},
157                 {101,   SWT.KEYPAD_5},
158                 {102,   SWT.KEYPAD_6},
159                 {103,   SWT.KEYPAD_7},
160                 {104,   SWT.KEYPAD_8},
161                 {105,   SWT.KEYPAD_9},
162                 {14,    SWT.KEYPAD_CR},
163                 {107,   SWT.KEYPAD_ADD},
164                 {109,   SWT.KEYPAD_SUBTRACT},
165                 {106,   SWT.KEYPAD_MULTIPLY},
166                 {111,   SWT.KEYPAD_DIVIDE},
167                 {110,   SWT.KEYPAD_DECIMAL},
168
169                 /* Other keys */
170                 {20,    SWT.CAPS_LOCK},
171                 {144,   SWT.NUM_LOCK},
172                 {145,   SWT.SCROLL_LOCK},
173                 {44,    SWT.PRINT_SCREEN},
174                 {6,             SWT.HELP},
175                 {19,    SWT.PAUSE},
176                 {3,             SWT.BREAK},
177
178                 /* WebKit-specific */
179                 {186,   ';'},
180                 {187,   '='},
181                 {189,   '-'},
182         };
183
184 public class EvaluateFunction extends BrowserFunction {
185         public EvaluateFunction (Browser browser, String name) {
186                 super (browser, name, true, new String[0], false);
187         }
188         @Override
189         public Object function (Object[] arguments) {
190                 if (arguments[0] instanceof String) {
191                         String string = (String)arguments[0];
192                         if (string.startsWith (ERROR_ID)) {
193                                 String errorString = ExtractError (string);
194                                 if (errorString.length () > 0) {
195                                         evaluateResult = new SWTException (SWT.ERROR_FAILED_EVALUATE, errorString);
196                                 } else {
197                                         evaluateResult = new SWTException (SWT.ERROR_FAILED_EVALUATE);
198                                 }
199                                 return null;
200                         }
201                 }
202                 evaluateResult = arguments[0];
203                 return null;
204         }
205 }
206
207 public void addAuthenticationListener (AuthenticationListener listener) {
208         AuthenticationListener[] newAuthenticationListeners = new AuthenticationListener[authenticationListeners.length + 1];
209         System.arraycopy(authenticationListeners, 0, newAuthenticationListeners, 0, authenticationListeners.length);
210         authenticationListeners = newAuthenticationListeners;
211         authenticationListeners[authenticationListeners.length - 1] = listener;
212 }
213
214 public void addCloseWindowListener (CloseWindowListener listener) {
215         CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length + 1];
216         System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, closeWindowListeners.length);
217         closeWindowListeners = newCloseWindowListeners;
218         closeWindowListeners[closeWindowListeners.length - 1] = listener;
219 }
220
221 public void addLocationListener (LocationListener listener) {
222         LocationListener[] newLocationListeners = new LocationListener[locationListeners.length + 1];
223         System.arraycopy(locationListeners, 0, newLocationListeners, 0, locationListeners.length);
224         locationListeners = newLocationListeners;
225         locationListeners[locationListeners.length - 1] = listener;
226 }
227
228 public void addOpenWindowListener (OpenWindowListener listener) {
229         OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length + 1];
230         System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, openWindowListeners.length);
231         openWindowListeners = newOpenWindowListeners;
232         openWindowListeners[openWindowListeners.length - 1] = listener;
233 }
234
235 public void addProgressListener (ProgressListener listener) {
236         ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length + 1];
237         System.arraycopy(progressListeners, 0, newProgressListeners, 0, progressListeners.length);
238         progressListeners = newProgressListeners;
239         progressListeners[progressListeners.length - 1] = listener;
240 }
241
242 public void addStatusTextListener (StatusTextListener listener) {
243         StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length + 1];
244         System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, statusTextListeners.length);
245         statusTextListeners = newStatusTextListeners;
246         statusTextListeners[statusTextListeners.length - 1] = listener;
247 }
248
249 public void addTitleListener (TitleListener listener) {
250         TitleListener[] newTitleListeners = new TitleListener[titleListeners.length + 1];
251         System.arraycopy(titleListeners, 0, newTitleListeners, 0, titleListeners.length);
252         titleListeners = newTitleListeners;
253         titleListeners[titleListeners.length - 1] = listener;
254 }
255
256 public void addVisibilityWindowListener (VisibilityWindowListener listener) {
257         VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length + 1];
258         System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, visibilityWindowListeners.length);
259         visibilityWindowListeners = newVisibilityWindowListeners;
260         visibilityWindowListeners[visibilityWindowListeners.length - 1] = listener;
261 }
262
263 public abstract boolean back ();
264
265 public static void clearSessions () {
266         if (NativeClearSessions != null) NativeClearSessions.run ();
267 }
268
269 public static String GetCookie (String name, String url) {
270         CookieName = name; CookieUrl = url; CookieValue = null;
271         if (NativeGetCookie != null) NativeGetCookie.run ();
272         String result = CookieValue;
273         CookieName = CookieValue = CookieUrl = null;
274         return result;
275 }
276
277 public static boolean SetCookie (String value, String url, boolean addToPending) {
278         CookieValue = value; CookieUrl = url;
279         CookieResult = false;
280         if (NativeSetCookie != null) {
281                 NativeSetCookie.run ();
282         } else {
283                 if (addToPending && NativePendingCookies != null) {
284                         NativePendingCookies.add (new String[] {value, url});
285                 }
286         }
287         CookieValue = CookieUrl = null;
288         return CookieResult;
289 }
290
291 static void SetPendingCookies (List<String[]> pendingCookies) {
292         for (String[] current : pendingCookies) {
293                 SetCookie (current[0], current[1], false);
294         }
295 }
296
297 public abstract void create (Composite parent, int style);
298
299 static String CreateErrorString (String error) {
300         return ERROR_ID + error;
301 }
302
303 static String ExtractError (String error) {
304         return error.substring (ERROR_ID.length ());
305 }
306
307 public boolean close () {
308         return true;
309 }
310
311 public void createFunction (BrowserFunction function) {
312         /*
313          * If an existing function with the same name is found then
314          * remove it so that it is not recreated on subsequent pages
315          * (the new function overwrites the old one).
316          */
317         for (BrowserFunction current : functions.values()) {
318                 if (current.name.equals (function.name)) {
319                         deregisterFunction (current);
320                         break;
321                 }
322         }
323
324         function.index = getNextFunctionIndex ();
325         registerFunction (function);
326
327         StringBuilder functionBuffer = new StringBuilder (function.name);
328         functionBuffer.append (" = function "); //$NON-NLS-1$
329         functionBuffer.append (function.name);
330         functionBuffer.append ("() {var result = callJava("); //$NON-NLS-1$
331         functionBuffer.append (function.index);
332         functionBuffer.append (",'"); //$NON-NLS-1$
333         functionBuffer.append (function.token);
334         functionBuffer.append ("',Array.prototype.slice.call(arguments)); if (typeof result == 'string' && result.indexOf('"); //$NON-NLS-1$
335         functionBuffer.append (ERROR_ID);
336         functionBuffer.append ("') == 0) {var error = new Error(result.substring("); //$NON-NLS-1$
337         functionBuffer.append (ERROR_ID.length ());
338         functionBuffer.append (")); throw error;} return result;};"); //$NON-NLS-1$
339
340         String javaCallDeclaration = getJavaCallDeclaration();
341
342         StringBuilder buffer = new StringBuilder (); //$NON-NLS-1$
343         buffer.append (javaCallDeclaration); //$NON-NLS-1$
344         if (function.top) {
345                 buffer.append (functionBuffer.toString ());
346         }
347
348         buffer.append ("var frameIds = null;"); //$NON-NLS-1$
349         if (function.frameNames != null) {
350                 buffer.append ("frameIds = {"); //$NON-NLS-1$
351                 for (int i = 0; i < function.frameNames.length; i++) {
352                         buffer.append ('\'');
353                         buffer.append (function.frameNames[i]);
354                         buffer.append ("':1,"); //$NON-NLS-1$
355                 }
356                 if (function.frameNames.length > 0) {
357                         buffer.deleteCharAt(buffer.length () - 1);
358                 }
359                 buffer.append ("};"); //$NON-NLS-1$
360         }
361
362         buffer.append ("for (var i = 0; i < frames.length; i++) {try {if (!frameIds || (frames[i].name && frameIds[frames[i].name])) {"); //$NON-NLS-1$
363         buffer.append ("if (!frames[i].callJava) {frames[i].callJava = window.callJava;} frames[i]."); //$NON-NLS-1$
364         buffer.append (functionBuffer.toString ());
365         buffer.append ("}} catch(e) {}};"); //$NON-NLS-1$
366
367         function.functionString = buffer.toString ();
368         nonBlockingExecute (function.functionString);
369 }
370
371 /**
372  * Designed to be overriden.
373  * @return javaScrit code that defines the 'callJava' syntax for javascript.
374  */
375 String getJavaCallDeclaration() {
376         return    "if (!window.callJava) {\n"
377                         + "             window.callJava = function callJava(index, token, args) {\n"
378                         + "                     return external.callJava(index,token,args);\n"
379                         + "             }\n"
380                         + "};\n";
381 }
382
383 void deregisterFunction (BrowserFunction function) {
384         functions.remove (function.index);
385 }
386
387 public void destroyFunction (BrowserFunction function) {
388         String deleteString = getDeleteFunctionString (function.name);
389         StringBuilder buffer = new StringBuilder ("for (var i = 0; i < frames.length; i++) {try {frames[i].eval(\""); //$NON-NLS-1$
390         buffer.append (deleteString);
391         buffer.append ("\");} catch (e) {}}"); //$NON-NLS-1$
392         nonBlockingExecute (buffer.toString ());
393         nonBlockingExecute (deleteString);
394         deregisterFunction (function);
395 }
396
397 // Designed to be overriden by platform implementations, used for optimization and avoiding deadlocks.
398 // Webkit2 is async, we often don't need to bother waiting for a return type if we never use it.
399 void nonBlockingExecute(String script) {
400         execute(script);
401 }
402
403 public abstract boolean execute (String script);
404
405 public Object evaluate (String script, boolean trusted) throws SWTException {
406         return evaluate(script);
407 }
408
409 public Object evaluate (String script) throws SWTException {
410         // Gtk Developer note:
411         // Webkit1 uses this mechanism.
412         // Webkit2 uses a different mechanism. See WebKit:evaluate();
413         BrowserFunction function = new EvaluateFunction (browser, ""); // $NON-NLS-1$
414         int index = getNextFunctionIndex ();
415         function.index = index;
416         function.isEvaluate = true;  // Note, Webkit2 doesn't use 'isEvaluate' machinery because it doesn't use a function for evaluation.
417         registerFunction (function);
418         String functionName = EXECUTE_ID + index;
419
420         StringBuilder buffer = new StringBuilder ("window."); // $NON-NLS-1$
421         buffer.append (functionName);
422         buffer.append (" = function "); // $NON-NLS-1$
423         buffer.append (functionName);
424         buffer.append ("() {\n"); // $NON-NLS-1$
425         buffer.append (script);
426         buffer.append ("\n};"); // $NON-NLS-1$
427         nonBlockingExecute (buffer.toString ());
428
429         buffer = new StringBuilder ("if (window."); // $NON-NLS-1$
430         buffer.append (functionName);
431         buffer.append (" == undefined) {window.external.callJava("); // $NON-NLS-1$
432         buffer.append (index);
433         buffer.append (",'"); //$NON-NLS-1$
434         buffer.append (function.token);
435         buffer.append ("', ['"); // $NON-NLS-1$
436         buffer.append (ERROR_ID);
437         buffer.append ("']);} else {try {var result = "); // $NON-NLS-1$
438         buffer.append (functionName);
439         buffer.append ("(); window.external.callJava("); // $NON-NLS-1$
440         buffer.append (index);
441         buffer.append (",'"); //$NON-NLS-1$
442         buffer.append (function.token);
443         buffer.append ("', [result]);} catch (e) {window.external.callJava("); // $NON-NLS-1$
444         buffer.append (index);
445         buffer.append (",'"); //$NON-NLS-1$
446         buffer.append (function.token);
447         buffer.append ("', ['"); // $NON-NLS-1$
448         buffer.append (ERROR_ID);
449         buffer.append ("' + e.message]);}}"); // $NON-NLS-1$
450         nonBlockingExecute (buffer.toString ());
451         nonBlockingExecute (getDeleteFunctionString (functionName));
452         deregisterFunction (function);
453
454         Object result = evaluateResult;
455         evaluateResult = null;
456         if (result instanceof SWTException) throw (SWTException)result;
457         return result;
458 }
459
460 public abstract boolean forward ();
461
462 public abstract String getBrowserType ();
463
464 String getDeleteFunctionString (String functionName) {
465         return "delete window." + functionName; //$NON-NLS-1$
466 }
467
468 int getNextFunctionIndex () {
469         return nextFunctionIndex++;
470 }
471
472 public abstract String getText ();
473
474 public abstract String getUrl ();
475
476 public Object getWebBrowser () {
477         return null;
478 }
479
480 public abstract boolean isBackEnabled ();
481
482 public boolean isFocusControl () {
483         return false;
484 }
485
486 public abstract boolean isForwardEnabled ();
487
488 public abstract void refresh ();
489
490 void registerFunction (BrowserFunction function) {
491         functions.put (function.index, function);
492 }
493
494 public void removeAuthenticationListener (AuthenticationListener listener) {
495         if (authenticationListeners.length == 0) return;
496         int index = -1;
497         for (int i = 0; i < authenticationListeners.length; i++) {
498                 if (listener == authenticationListeners[i]) {
499                         index = i;
500                         break;
501                 }
502         }
503         if (index == -1) return;
504         if (authenticationListeners.length == 1) {
505                 authenticationListeners = new AuthenticationListener[0];
506                 return;
507         }
508         AuthenticationListener[] newAuthenticationListeners = new AuthenticationListener[authenticationListeners.length - 1];
509         System.arraycopy (authenticationListeners, 0, newAuthenticationListeners, 0, index);
510         System.arraycopy (authenticationListeners, index + 1, newAuthenticationListeners, index, authenticationListeners.length - index - 1);
511         authenticationListeners = newAuthenticationListeners;
512 }
513
514 public void removeCloseWindowListener (CloseWindowListener listener) {
515         if (closeWindowListeners.length == 0) return;
516         int index = -1;
517         for (int i = 0; i < closeWindowListeners.length; i++) {
518                 if (listener == closeWindowListeners[i]){
519                         index = i;
520                         break;
521                 }
522         }
523         if (index == -1) return;
524         if (closeWindowListeners.length == 1) {
525                 closeWindowListeners = new CloseWindowListener[0];
526                 return;
527         }
528         CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length - 1];
529         System.arraycopy (closeWindowListeners, 0, newCloseWindowListeners, 0, index);
530         System.arraycopy (closeWindowListeners, index + 1, newCloseWindowListeners, index, closeWindowListeners.length - index - 1);
531         closeWindowListeners = newCloseWindowListeners;
532 }
533
534 public void removeLocationListener (LocationListener listener) {
535         if (locationListeners.length == 0) return;
536         int index = -1;
537         for (int i = 0; i < locationListeners.length; i++) {
538                 if (listener == locationListeners[i]){
539                         index = i;
540                         break;
541                 }
542         }
543         if (index == -1) return;
544         if (locationListeners.length == 1) {
545                 locationListeners = new LocationListener[0];
546                 return;
547         }
548         LocationListener[] newLocationListeners = new LocationListener[locationListeners.length - 1];
549         System.arraycopy (locationListeners, 0, newLocationListeners, 0, index);
550         System.arraycopy (locationListeners, index + 1, newLocationListeners, index, locationListeners.length - index - 1);
551         locationListeners = newLocationListeners;
552 }
553
554 public void removeOpenWindowListener (OpenWindowListener listener) {
555         if (openWindowListeners.length == 0) return;
556         int index = -1;
557         for (int i = 0; i < openWindowListeners.length; i++) {
558                 if (listener == openWindowListeners[i]){
559                         index = i;
560                         break;
561                 }
562         }
563         if (index == -1) return;
564         if (openWindowListeners.length == 1) {
565                 openWindowListeners = new OpenWindowListener[0];
566                 return;
567         }
568         OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length - 1];
569         System.arraycopy (openWindowListeners, 0, newOpenWindowListeners, 0, index);
570         System.arraycopy (openWindowListeners, index + 1, newOpenWindowListeners, index, openWindowListeners.length - index - 1);
571         openWindowListeners = newOpenWindowListeners;
572 }
573
574 public void removeProgressListener (ProgressListener listener) {
575         if (progressListeners.length == 0) return;
576         int index = -1;
577         for (int i = 0; i < progressListeners.length; i++) {
578                 if (listener == progressListeners[i]){
579                         index = i;
580                         break;
581                 }
582         }
583         if (index == -1) return;
584         if (progressListeners.length == 1) {
585                 progressListeners = new ProgressListener[0];
586                 return;
587         }
588         ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length - 1];
589         System.arraycopy (progressListeners, 0, newProgressListeners, 0, index);
590         System.arraycopy (progressListeners, index + 1, newProgressListeners, index, progressListeners.length - index - 1);
591         progressListeners = newProgressListeners;
592 }
593
594 public void removeStatusTextListener (StatusTextListener listener) {
595         if (statusTextListeners.length == 0) return;
596         int index = -1;
597         for (int i = 0; i < statusTextListeners.length; i++) {
598                 if (listener == statusTextListeners[i]){
599                         index = i;
600                         break;
601                 }
602         }
603         if (index == -1) return;
604         if (statusTextListeners.length == 1) {
605                 statusTextListeners = new StatusTextListener[0];
606                 return;
607         }
608         StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length - 1];
609         System.arraycopy (statusTextListeners, 0, newStatusTextListeners, 0, index);
610         System.arraycopy (statusTextListeners, index + 1, newStatusTextListeners, index, statusTextListeners.length - index - 1);
611         statusTextListeners = newStatusTextListeners;
612 }
613
614 public void removeTitleListener (TitleListener listener) {
615         if (titleListeners.length == 0) return;
616         int index = -1;
617         for (int i = 0; i < titleListeners.length; i++) {
618                 if (listener == titleListeners[i]){
619                         index = i;
620                         break;
621                 }
622         }
623         if (index == -1) return;
624         if (titleListeners.length == 1) {
625                 titleListeners = new TitleListener[0];
626                 return;
627         }
628         TitleListener[] newTitleListeners = new TitleListener[titleListeners.length - 1];
629         System.arraycopy (titleListeners, 0, newTitleListeners, 0, index);
630         System.arraycopy (titleListeners, index + 1, newTitleListeners, index, titleListeners.length - index - 1);
631         titleListeners = newTitleListeners;
632 }
633
634 public void removeVisibilityWindowListener (VisibilityWindowListener listener) {
635         if (visibilityWindowListeners.length == 0) return;
636         int index = -1;
637         for (int i = 0; i < visibilityWindowListeners.length; i++) {
638                 if (listener == visibilityWindowListeners[i]){
639                         index = i;
640                         break;
641                 }
642         }
643         if (index == -1) return;
644         if (visibilityWindowListeners.length == 1) {
645                 visibilityWindowListeners = new VisibilityWindowListener[0];
646                 return;
647         }
648         VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length - 1];
649         System.arraycopy (visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, index);
650         System.arraycopy (visibilityWindowListeners, index + 1, newVisibilityWindowListeners, index, visibilityWindowListeners.length - index - 1);
651         visibilityWindowListeners = newVisibilityWindowListeners;
652 }
653
654 boolean sendKeyEvent (Event event) {
655         int traversal = SWT.TRAVERSE_NONE;
656         boolean traverseDoit = true;
657         switch (event.keyCode) {
658                 case SWT.ESC: {
659                         traversal = SWT.TRAVERSE_ESCAPE;
660                         traverseDoit = true;
661                         break;
662                 }
663                 case SWT.CR: {
664                         traversal = SWT.TRAVERSE_RETURN;
665                         traverseDoit = false;
666                         break;
667                 }
668                 case SWT.ARROW_DOWN:
669                 case SWT.ARROW_RIGHT: {
670                         traversal = SWT.TRAVERSE_ARROW_NEXT;
671                         traverseDoit = false;
672                         break;
673                 }
674                 case SWT.ARROW_UP:
675                 case SWT.ARROW_LEFT: {
676                         traversal = SWT.TRAVERSE_ARROW_PREVIOUS;
677                         traverseDoit = false;
678                         break;
679                 }
680                 case SWT.TAB: {
681                         traversal = (event.stateMask & SWT.SHIFT) != 0 ? SWT.TRAVERSE_TAB_PREVIOUS : SWT.TRAVERSE_TAB_NEXT;
682                         traverseDoit = (event.stateMask & SWT.CTRL) != 0;
683                         break;
684                 }
685                 case SWT.PAGE_DOWN: {
686                         if ((event.stateMask & SWT.CTRL) != 0) {
687                                 traversal = SWT.TRAVERSE_PAGE_NEXT;
688                                 traverseDoit = true;
689                         }
690                         break;
691                 }
692                 case SWT.PAGE_UP: {
693                         if ((event.stateMask & SWT.CTRL) != 0) {
694                                 traversal = SWT.TRAVERSE_PAGE_PREVIOUS;
695                                 traverseDoit = true;
696                         }
697                         break;
698                 }
699                 default: {
700                         if (translateMnemonics ()) {
701                                 if (event.character != 0 && (event.stateMask & (SWT.ALT | SWT.CTRL)) == SWT.ALT) {
702                                         traversal = SWT.TRAVERSE_MNEMONIC;
703                                         traverseDoit = true;
704                                 }
705                         }
706                         break;
707                 }
708         }
709
710         boolean doit = true;
711         if (traversal != SWT.TRAVERSE_NONE) {
712                 boolean oldEventDoit = event.doit;
713                 event.doit = traverseDoit;
714                 doit = !browser.traverse (traversal, event);
715                 event.doit = oldEventDoit;
716         }
717         if (doit) {
718                 browser.notifyListeners (event.type, event);
719                 doit = event.doit;
720         }
721         return doit;
722 }
723
724 public void setBrowser (Browser browser) {
725         this.browser = browser;
726 }
727
728 public abstract boolean setText (String html, boolean trusted);
729
730 public abstract boolean setUrl (String url, String postData, String[] headers);
731
732 public abstract void stop ();
733
734 int translateKey (int key) {
735         for (int i = 0; i < KeyTable.length; i++) {
736                 if (KeyTable[i][0] == key) return KeyTable[i][1];
737         }
738         return 0;
739 }
740
741 boolean translateMnemonics () {
742         return true;
743 }
744
745 }