]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/IE.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / browser / IE.java
1 /*******************************************************************************
2  * Copyright (c) 2003, 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 import java.io.*;
17 import java.net.*;
18 import java.util.*;
19
20 import org.eclipse.swt.*;
21 import org.eclipse.swt.graphics.*;
22 import org.eclipse.swt.internal.*;
23 import org.eclipse.swt.internal.ole.win32.*;
24 import org.eclipse.swt.internal.win32.*;
25 import org.eclipse.swt.ole.win32.*;
26 import org.eclipse.swt.widgets.*;
27
28 class IE extends WebBrowser {
29
30         OleFrame frame;
31         WebSite site;
32         OleAutomation auto;
33         OleListener domListener;
34         OleAutomation[] documents = new OleAutomation[0];
35
36         boolean back, forward, delaySetText, ignoreDispose, ignoreTraverse, performingInitialNavigate;
37         boolean installFunctionsOnDocumentComplete, untrustedText, isRefresh, isAboutBlank;
38         Point location;
39         Point size;
40         boolean addressBar = true, menuBar = true, statusBar = true, toolBar = true;
41         long globalDispatch;
42         String html, lastNavigateURL, uncRedirect;
43         Object[] pendingText, pendingUrl;
44         int style, lastKeyCode, lastCharCode;
45         int lastMouseMoveX, lastMouseMoveY;
46
47         static boolean Initialized;
48         static int IEVersion, PDFCount;
49         static String ProgId = "Shell.Explorer";        //$NON-NLS-1$
50
51         static final int BeforeNavigate2 = 0xfa;
52         static final int CommandStateChange = 0x69;
53         static final int DocumentComplete = 0x103;
54         static final int DownloadComplete = 0x68;
55         static final int NavigateComplete2 = 0xfc;
56         static final int NewWindow2 = 0xfb;
57         static final int OnMenuBar = 0x100;
58         static final int OnStatusBar = 0x101;
59         static final int OnToolBar = 0xff;
60         static final int OnVisible = 0xfe;
61         static final int ProgressChange = 0x6c;
62         static final int RegisterAsBrowser = 0x228;
63         static final int StatusTextChange = 0x66;
64         static final int TitleChange = 0x71;
65         static final int WindowClosing = 0x107;
66         static final int WindowSetHeight = 0x10b;
67         static final int WindowSetLeft = 0x108;
68         static final int WindowSetResizable = 0x106;
69         static final int WindowSetTop = 0x109;
70         static final int WindowSetWidth = 0x10a;
71         static final int NavigateError = 0x10f;
72
73         static final short CSC_NAVIGATEFORWARD = 1;
74         static final short CSC_NAVIGATEBACK = 2;
75         static final int INET_E_DEFAULT_ACTION = 0x800C0011;
76         static final int INET_E_RESOURCE_NOT_FOUND = 0x800C0005;
77         static final int READYSTATE_COMPLETE = 4;
78         static final int URLPOLICY_ALLOW = 0x00;
79         static final int URLPOLICY_DISALLOW = 0x03;
80         static final int URLPOLICY_JAVA_PROHIBIT = 0x0;
81         static final int URLPOLICY_JAVA_LOW = 0x00030000;
82         static final int URLZONE_LOCAL_MACHINE = 0;
83         static final int URLZONE_INTRANET = 1;
84         static final int URLACTION_ACTIVEX_MIN = 0x00001200;
85         static final int URLACTION_ACTIVEX_MAX = 0x000013ff;
86         static final int URLACTION_ACTIVEX_RUN = 0x00001200;
87         static final int URLACTION_FEATURE_ZONE_ELEVATION = 0x00002101;
88         static final int URLACTION_JAVA_MIN = 0x00001C00;
89         static final int URLACTION_JAVA_MAX = 0x00001Cff;
90         static final int URLACTION_SCRIPT_RUN = 0x00001400;
91
92         static final int DISPID_AMBIENT_DLCONTROL = -5512;
93         static final int DLCTL_DLIMAGES = 0x00000010;
94         static final int DLCTL_VIDEOS = 0x00000020;
95         static final int DLCTL_BGSOUNDS = 0x00000040;
96         static final int DLCTL_NO_SCRIPTS = 0x00000080;
97         static final int DLCTL_NO_JAVA = 0x00000100;
98         static final int DLCTL_NO_RUNACTIVEXCTLS = 0x00000200;
99         static final int DLCTL_NO_DLACTIVEXCTLS = 0x00000400;
100         static final int DLCTL_DOWNLOADONLY = 0x00000800;
101         static final int DLCTL_NO_FRAMEDOWNLOAD = 0x00001000;
102         static final int DLCTL_RESYNCHRONIZE = 0x00002000;
103         static final int DLCTL_PRAGMA_NO_CACHE = 0x00004000;
104         static final int DLCTL_FORCEOFFLINE = 0x10000000;
105         static final int DLCTL_NO_CLIENTPULL = 0x20000000;
106         static final int DLCTL_SILENT = 0x40000000;
107         static final int DOCHOSTUIFLAG_THEME = 0x00040000;
108         static final int DOCHOSTUIFLAG_NO3DBORDER  = 0x0000004;
109         static final int DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000;
110         static final int DOCHOSTUIFLAG_ENABLE_REDIRECT_NOTIFICATION = 0x04000000;
111         static final int DOCHOSTUIFLAG_DPI_AWARE = 0x40000000;
112
113         static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
114         static final String CLSID_SHELLEXPLORER1 = "{EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B}"; //$NON-NLS-1$
115         static final int DEFAULT_IE_VERSION = 9999;
116         static final String EXTENSION_PDF = ".pdf";     //$NON-NLS-1$
117         static final String HTML_DOCUMENT = "HTML Document";    //$NON-NLS-1$
118         static final int MAX_PDF = 20;
119         static final char SEPARATOR_OS = File.separatorChar;
120         static final String PROPERTY_IEVERSION = "org.eclipse.swt.browser.IEVersion"; //$NON-NLS-1$
121         static final String VALUE_DEFAULT = "default"; //$NON-NLS-1$
122
123         static final String EVENT_DOUBLECLICK = "dblclick"; //$NON-NLS-1$
124         static final String EVENT_DRAGEND = "dragend";  //$NON-NLS-1$
125         static final String EVENT_DRAGSTART = "dragstart";      //$NON-NLS-1$
126         static final String EVENT_KEYDOWN = "keydown";  //$NON-NLS-1$
127         static final String EVENT_KEYPRESS = "keypress";        //$NON-NLS-1$
128         static final String EVENT_KEYUP = "keyup";      //$NON-NLS-1$
129         static final String EVENT_MOUSEMOVE = "mousemove";      //$NON-NLS-1$
130         static final String EVENT_MOUSEWHEEL = "mousewheel";    //$NON-NLS-1$
131         static final String EVENT_MOUSEUP = "mouseup";  //$NON-NLS-1$
132         static final String EVENT_MOUSEDOWN = "mousedown";      //$NON-NLS-1$
133         static final String EVENT_MOUSEOUT = "mouseout";        //$NON-NLS-1$
134         static final String EVENT_MOUSEOVER = "mouseover";      //$NON-NLS-1$
135         static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
136         static final String PROPERTY_ALTKEY = "altKey"; //$NON-NLS-1$
137         static final String PROPERTY_BUTTON = "button"; //$NON-NLS-1$
138         static final String PROPERTY_CTRLKEY = "ctrlKey"; //$NON-NLS-1$
139         static final String PROPERTY_DOCUMENT = "Document"; //$NON-NLS-1$
140         static final String PROPERTY_FROMELEMENT = "fromElement"; //$NON-NLS-1$
141         static final String PROPERTY_KEYCODE = "keyCode"; //$NON-NLS-1$
142         static final String PROPERTY_REPEAT = "repeat"; //$NON-NLS-1$
143         static final String PROPERTY_RETURNVALUE = "returnValue"; //$NON-NLS-1$
144         static final String PROPERTY_SCREENX = "screenX"; //$NON-NLS-1$
145         static final String PROPERTY_SCREENY = "screenY"; //$NON-NLS-1$
146         static final String PROPERTY_SHIFTKEY = "shiftKey"; //$NON-NLS-1$
147         static final String PROPERTY_TOELEMENT = "toElement"; //$NON-NLS-1$
148         static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
149         static final String PROPERTY_WHEELDELTA = "wheelDelta"; //$NON-NLS-1$
150
151         static {
152                 NativeClearSessions = () -> {
153                         OS.InternetSetOption (0, OS.INTERNET_OPTION_END_BROWSER_SESSION, 0, 0);
154                 };
155
156                 NativeGetCookie = () -> {
157                         TCHAR url = new TCHAR (0, CookieUrl, true);
158                         TCHAR cookieData = new TCHAR (0, 8192);
159                         int[] size = new int[] {cookieData.length ()};
160                         if (!OS.InternetGetCookie (url, null, cookieData, size)) {
161                                 /* original cookieData size was not large enough */
162                                 size[0] /= TCHAR.sizeof;
163                                 cookieData = new TCHAR (0, size[0]);
164                                 if (!OS.InternetGetCookie (url, null, cookieData, size)) return;
165                         }
166                         String allCookies = cookieData.toString (0, size[0]);
167                         StringTokenizer tokenizer = new StringTokenizer (allCookies, ";"); //$NON-NLS-1$
168                         while (tokenizer.hasMoreTokens ()) {
169                                 String cookie = tokenizer.nextToken ();
170                                 int index = cookie.indexOf ('=');
171                                 if (index != -1) {
172                                         String name = cookie.substring (0, index).trim ();
173                                         if (name.equals (CookieName)) {
174                                                 CookieValue = cookie.substring (index + 1).trim ();
175                                                 return;
176                                         }
177                                 }
178                         }
179                 };
180
181                 NativeSetCookie = () -> {
182                         TCHAR url = new TCHAR (0, CookieUrl, true);
183                         TCHAR value = new TCHAR (0, CookieValue, true);
184                         CookieResult = OS.InternetSetCookie (url, null, value);
185                 };
186
187                 /*
188                 * The installed version of IE can be determined by looking at registry entry
189                 * HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\svcVersion, or
190                 * HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Version (for
191                 * IE releases prior to IE10).  Check this value in order to determine
192                 * version-specific features that can be enabled.
193                 */
194                 TCHAR key = new TCHAR (0, "Software\\Microsoft\\Internet Explorer", true);      //$NON-NLS-1$
195                 long [] phkResult = new long [1];
196                 if (OS.RegOpenKeyEx (OS.HKEY_LOCAL_MACHINE, key, 0, OS.KEY_READ, phkResult) == 0) {
197                         int [] lpcbData = new int [1];
198                         TCHAR buffer = new TCHAR (0, "svcVersion", true); //$NON-NLS-1$
199                         int result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, (TCHAR) null, lpcbData);
200                         if (result != 0) {
201                                 buffer = new TCHAR (0, "Version", true); //$NON-NLS-1$
202                                 result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, (TCHAR) null, lpcbData);
203                         }
204                         if (result == 0) {
205                                 TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
206                                 result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, lpData, lpcbData);
207                                 if (result == 0) {
208                                         String versionString = lpData.toString (0, lpData.strlen ());
209                                         int index = versionString.indexOf ("."); //$NON-NLS-1$
210                                         if (index != -1) {
211                                                 String majorString = versionString.substring (0, index);
212                                                 try {
213                                                         IEVersion = Integer.valueOf (majorString).intValue ();
214                                                 } catch (NumberFormatException e) {
215                                                         /* just continue, version-specific features will not be enabled */
216                                                 }
217                                         }
218                                 }
219                         }
220                         OS.RegCloseKey (phkResult [0]);
221                 }
222
223                 /*
224                 * Registry entry HKEY_CLASSES_ROOT\Shell.Explorer\CLSID indicates which version of
225                 * Shell.Explorer to use by default.  We usually want to use this value because it
226                 * typically points at the newest one that is available.  However it is possible for
227                 * this registry entry to be changed by another application to point at some other
228                 * Shell.Explorer version.
229                 *
230                 * The Browser depends on the Shell.Explorer version being at least Shell.Explorer.2.
231                 * If it is detected in the registry to be Shell.Explorer.1 then change the progId that
232                 * will be embedded to explicitly specify Shell.Explorer.2.
233                 */
234                 key = new TCHAR (0, "Shell.Explorer\\CLSID", true);     //$NON-NLS-1$
235                 phkResult = new long [1];
236                 if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult) == 0) {
237                         int [] lpcbData = new int [1];
238                         int result = OS.RegQueryValueEx (phkResult [0], null, 0, null, (TCHAR) null, lpcbData);
239                         if (result == 0) {
240                                 TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
241                                 result = OS.RegQueryValueEx (phkResult [0], null, 0, null, lpData, lpcbData);
242                                 if (result == 0) {
243                                         String clsid = lpData.toString (0, lpData.strlen ());
244                                         if (clsid.equals (CLSID_SHELLEXPLORER1)) {
245                                                 /* Shell.Explorer.1 is the default, ensure that Shell.Explorer.2 is available */
246                                                 key = new TCHAR (0, "Shell.Explorer.2", true);  //$NON-NLS-1$
247                                                 long [] phkResult2 = new long [1];
248                                                 if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult2) == 0) {
249                                                         /* specify that Shell.Explorer.2 is to be used */
250                                                         OS.RegCloseKey (phkResult2 [0]);
251                                                         ProgId = "Shell.Explorer.2";    //$NON-NLS-1$
252                                                 }
253                                         }
254                                 }
255                         }
256                         OS.RegCloseKey (phkResult [0]);
257                 }
258
259                 if (NativePendingCookies != null) {
260                         SetPendingCookies (NativePendingCookies);
261                 }
262                 NativePendingCookies = null;
263         }
264
265 @Override
266 public void create(Composite parent, int style) {
267         this.style = style;
268         frame = new OleFrame(browser, SWT.NONE);
269
270         try {
271                 site = new WebSite(frame, SWT.NONE, ProgId);
272         } catch (SWTException e) {
273                 browser.dispose();
274                 SWT.error(SWT.ERROR_NO_HANDLES);
275         }
276
277         if (!Initialized) {
278                 Initialized = true;
279                 int version = 0;
280                 String versionProperty = System.getProperty(PROPERTY_IEVERSION);
281                 if (versionProperty != null) {
282                         if (versionProperty.equalsIgnoreCase(VALUE_DEFAULT)) {
283                                 version = -1;
284                         } else {
285                                 try {
286                                         version = Integer.valueOf(versionProperty).intValue();
287                                 } catch (NumberFormatException e) {
288                                         /*
289                                          * An invalid value was specified for the IEVersion java property.  Ignore it
290                                          * and continue with the usual steps for determining the version to specify.
291                                          */
292                                 }
293                         }
294                 }
295                 if (version == 0) {
296                         if (IEVersion != 0) {
297                                 /*
298                                  * By default in Embedded IE the docuemntMode is Quirks(5)
299                                  * mode unless !DOCTYPE directives is defined in the HTML.
300                                  * As per MSDN IE8 and onwards, there is a way we could hint
301                                  * embedded IE to use current documentMode via appropriate
302                                  * version value in the registry. Refer bug 342145.
303                                  *
304                                  * Complete list of IE emulation modes is listed on MSDN:
305                                  * http://msdn.microsoft
306                                  * .com/en-us/library/ie/ee330730%28v=vs
307                                  * .85%29.aspx#browser_emulation
308                                  */
309                                 if (IEVersion >= 10) {
310                                         version = IEVersion * 1000 + 1;
311                                 }
312                                 else if (IEVersion >= 8) {
313                                         version = IEVersion * 1111;
314                                 }
315                                 else {
316                                         version = IEVersion * 1000;
317                                 }
318                         } else {
319                                 version = DEFAULT_IE_VERSION;
320                         }
321                 }
322
323                 if (version != -1) {
324                         long[] key = new long[1];
325                         final TCHAR subkey = new TCHAR(0, "Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", true);     //$NON-NLS-1$
326                         if (OS.RegCreateKeyEx(OS.HKEY_CURRENT_USER, subkey, 0, null, OS.REG_OPTION_VOLATILE, OS.KEY_WRITE | OS.KEY_QUERY_VALUE, 0, key, null) == 0) {
327                                 TCHAR lpszFile = new TCHAR(0, OS.MAX_PATH);
328                                 OS.GetModuleFileName(0, lpszFile, lpszFile.length());
329                                 String path = lpszFile.toString(0, lpszFile.strlen());
330                                 int index = path.lastIndexOf(SEPARATOR_OS);
331                                 String executable = index != -1 ? path.substring(index + 1) : path;
332                                 final TCHAR lpValueName = new TCHAR(0, executable, true);
333                                 /*
334                                  * Program name & IE version entry is added to the Windows
335                                  * registry and same gets deleted during the dispose cycle.
336                                  * There is a possibility if the SWT application crashes or
337                                  * is exited forcefully, which leaves the registry entry
338                                  * as-is and hence if entry exists, updating it next time
339                                  * the SWT application creates embedded IE, refer bug 440300
340                                  */
341                                 int result = OS.RegQueryValueEx(key[0], lpValueName, 0, null, (int[])null, null);
342                                 if (result == 0 || result == OS.ERROR_FILE_NOT_FOUND) {
343                                         if (OS.RegSetValueEx(key[0], lpValueName, 0, OS.REG_DWORD, new int[] {version}, 4) == 0) {
344                                                 parent.getDisplay().addListener(SWT.Dispose, event -> {
345                                                         long[] key1 = new long[1];
346                                                         if (OS.RegOpenKeyEx(OS.HKEY_CURRENT_USER, subkey, 0, OS.KEY_WRITE, key1) == 0) {
347                                                                 OS.RegDeleteValue(key1[0], lpValueName);
348                                                         }
349                                                 });
350                                         }
351                                 }
352                                 OS.RegCloseKey(key[0]);
353                         }
354                 }
355         }
356
357         site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
358         auto = new OleAutomation(site);
359
360         domListener = e -> handleDOMEvent(e);
361
362         Listener listener = e -> {
363                 switch (e.type) {
364                         case SWT.Dispose: {
365                                 /* make this handler run after other dispose listeners */
366                                 if (ignoreDispose) {
367                                         ignoreDispose = false;
368                                         break;
369                                 }
370                                 ignoreDispose = true;
371                                 browser.notifyListeners (e.type, e);
372                                 e.type = SWT.NONE;
373
374                                 /* invoke onbeforeunload handlers */
375                                 if (!browser.isClosing) {
376                                         LocationListener[] oldLocationListeners = locationListeners;
377                                         locationListeners = new LocationListener[0];
378                                         site.ignoreAllMessages = true;
379                                         execute ("window.location.href='about:blank'"); //$NON-NLS-1$
380                                         site.ignoreAllMessages = false;
381                                         locationListeners = oldLocationListeners;
382                                 }
383
384                                 /*
385                                 * It is possible for the Browser's OLE frame to have been disposed
386                                 * by a Dispose listener that was invoked by notifyListeners above,
387                                 * so check for this before unhooking its DOM listeners.
388                                 */
389                                 if (!frame.isDisposed ()) unhookDOMListeners(documents);
390
391                                 for (int i = 0; i < documents.length; i++) {
392                                         documents[i].dispose();
393                                 }
394                                 documents = null;
395
396                                 Iterator<BrowserFunction> elements = functions.values().iterator ();
397                                 while (elements.hasNext ()) {
398                                         elements.next ().dispose (false);
399                                 }
400                                 functions = null;
401
402                                 lastNavigateURL = uncRedirect = null;
403                                 domListener = null;
404                                 if (auto != null) auto.dispose();
405                                 auto = null;
406                                 break;
407                         }
408                         case SWT.Resize: {
409                                 frame.setBounds(browser.getClientArea());
410                                 break;
411                         }
412                         case SWT.MouseWheel: {
413                                 /* MouseWheel events come from the DOM */
414                                 e.doit = false;
415                                 break;
416                         }
417                         case SWT.FocusIn: {
418                                 site.setFocus();
419                                 break;
420                         }
421                         case SWT.Traverse: {
422                                 /*
423                                  * Tabbing out of the browser can fail as a result of the WebSite
424                                  * control embedded within the Browser.  The workaround is to
425                                  * listen for traversals and re-perform the traversal on the
426                                  * appropriate control.
427                                  */
428                                 if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS && e.widget instanceof WebSite) {
429                                         /* otherwise will traverse to the Browser control */
430                                         browser.traverse(SWT.TRAVERSE_TAB_PREVIOUS, e);
431                                         e.doit = false;
432                                 }
433                                 /*
434                                  * Return traversals can sometimes come through TranslateAccelerator,
435                                  * depending on where focus is within the Browser.  Traversal
436                                  * events should always be triggered by a key event from the DOM,
437                                  * so if a Traversal from TranslateAccelerator is detected
438                                  * (e.doit == true) then stop its propagation.
439                                  */
440                                 if (e.detail == SWT.TRAVERSE_RETURN && e.doit && e.widget instanceof Browser) {
441                                         e.type = SWT.None;
442                                         e.doit = false;
443                                 }
444                                 break;
445                         }
446                 }
447         };
448         browser.addListener(SWT.Dispose, listener);
449         browser.addListener(SWT.FocusIn, listener);
450         browser.addListener(SWT.Resize, listener);
451         browser.addListener(SWT.Traverse, listener);
452         site.addListener(SWT.MouseWheel, listener);
453         site.addListener(SWT.Traverse, listener);
454
455         OleListener oleListener = event -> {
456                 /* callbacks are asynchronous, auto could be disposed */
457                 if (auto != null) {
458                         switch (event.type) {
459                                 case BeforeNavigate2: {
460
461                                         /* don't send client events if the initial navigate to about:blank has not completed */
462                                         if (performingInitialNavigate) break;
463
464                                         Variant varResult1 = event.arguments[1];
465                                         String url1 = varResult1.getString();
466
467                                         if (uncRedirect != null) {
468                                                 /*
469                                                 * Silently allow the navigate to proceed if the url is the first segment of a
470                                                 * UNC path being navigated to (initiated by the NavigateError listener to show
471                                                 * a name/password prompter), or if the url is the full UNC path (initiated by
472                                                 * the NavigateComplete listener to redirect from the UNC's first segment to its
473                                                 * full path).
474                                                 */
475                                                 if (uncRedirect.equals(url1) || (uncRedirect.startsWith(url1) && uncRedirect.indexOf('\\', 2) == url1.length())) {
476                                                         Variant cancel1 = event.arguments[6];
477                                                         if (cancel1 != null) {
478                                                                 long pCancel1 = cancel1.getByRef();
479                                                                 OS.MoveMemory(pCancel1, new short[] {OS.VARIANT_FALSE}, 2);
480                                                         }
481                                                         setAboutBlank(false);
482                                                         break;
483                                                 } else {
484                                                         /*
485                                                         * This navigate does not correspond to the previously-initiated
486                                                         * UNC navigation so clear this state since it's no longer valid.
487                                                         */
488                                                         uncRedirect = null;
489                                                 }
490                                         }
491
492                                         /*
493                                         * Feature in IE.  For navigations on the local machine, BeforeNavigate2's url
494                                         * field contains a string representation of the file path in a non-URL format.
495                                         * In order to be consistent with the other Browser implementations, this
496                                         * case is detected and the string is changed to be a proper url string.
497                                         */
498                                         if (url1.indexOf(":/") == -1 && url1.indexOf(":\\") != -1) { //$NON-NLS-1$ //$NON-NLS-2$
499                                                 TCHAR filePath1 = new TCHAR(0, url1, true);
500                                                 TCHAR urlResult1 = new TCHAR(0, OS.INTERNET_MAX_URL_LENGTH);
501                                                 int[] size1 = new int[] {urlResult1.length()};
502                                                 if (OS.UrlCreateFromPath(filePath1, urlResult1, size1, 0) == COM.S_OK) {
503                                                         url1 = urlResult1.toString(0, size1[0]);
504                                                 } else {
505                                                         url1 = PROTOCOL_FILE + url1.replace('\\', '/');
506                                                 }
507                                         }
508
509                                         /* Disallow local file system accesses if the browser content is untrusted */
510                                         if (url1.startsWith(PROTOCOL_FILE) && _getUrl().startsWith(ABOUT_BLANK) && untrustedText) {
511                                                 Variant cancel2 = event.arguments[6];
512                                                 if (cancel2 != null) {
513                                                         long pCancel2 = cancel2.getByRef();
514                                                         OS.MoveMemory(pCancel2, new short[] {OS.VARIANT_TRUE}, 2);
515                                                 }
516                                                 break;
517                                         }
518
519                                         LocationEvent newEvent1 = new LocationEvent(browser);
520                                         newEvent1.display = browser.getDisplay();
521                                         newEvent1.widget = browser;
522                                         newEvent1.location = url1;
523                                         newEvent1.doit = true;
524                                         for (int i1 = 0; i1 < locationListeners.length; i1++) {
525                                                 locationListeners[i1].changing(newEvent1);
526                                         }
527                                         boolean doit1 = newEvent1.doit && !browser.isDisposed();
528                                         Variant cancel3 = event.arguments[6];
529                                         if (cancel3 != null) {
530                                                 long pCancel3 = cancel3.getByRef();
531                                                 OS.MoveMemory(pCancel3, new short[] {doit1 ? OS.VARIANT_FALSE : OS.VARIANT_TRUE}, 2);
532                                         }
533                                         if (doit1) {
534                                                 varResult1 = event.arguments[0];
535                                                 IDispatch dispatch1 = varResult1.getDispatch();
536                                                 Variant variant1 = new Variant(auto); /* does not need to be disposed */
537                                                 IDispatch top1 = variant1.getDispatch();
538                                                 if (top1.getAddress() == dispatch1.getAddress()) {
539                                                         setAboutBlank(url1.startsWith(ABOUT_BLANK));
540                                                 }
541                                         }
542                                         break;
543                                 }
544                                 case CommandStateChange: {
545                                         boolean enabled = false;
546                                         Variant varResult2 = event.arguments[0];
547                                         int command = varResult2.getInt();
548                                         varResult2 = event.arguments[1];
549                                         enabled = varResult2.getBoolean();
550                                         switch (command) {
551                                                 case CSC_NAVIGATEBACK : back = enabled; break;
552                                                 case CSC_NAVIGATEFORWARD : forward = enabled; break;
553                                         }
554                                         break;
555                                 }
556                                 case DocumentComplete: {
557                                         if (performingInitialNavigate) {
558                                                 /* this event marks the completion of the initial navigate to about:blank */
559                                                 performingInitialNavigate = false;
560
561                                                 /* if browser content has been provided by the client then set it now */
562                                                 if (pendingText != null) {
563                                                         setText((String)pendingText[0], ((Boolean)pendingText[1]).booleanValue());
564                                                 } else if (pendingUrl != null) {
565                                                         setUrl((String)pendingUrl[0], (String)pendingUrl[1], (String[])pendingUrl[2]);
566                                                 }
567                                                 pendingText = pendingUrl = null;
568                                                 break;
569                                         }
570
571                                         Variant varResult3 = event.arguments[0];
572                                         IDispatch dispatch2 = varResult3.getDispatch();
573
574                                         varResult3 = event.arguments[1];
575                                         String url2 = varResult3.getString();
576                                         /*
577                                         * Feature in IE.  For navigations on the local machine, DocumentComplete's url
578                                         * field contains a string representation of the file path in a non-URL format.
579                                         * In order to be consistent with the other Browser implementations, this
580                                         * case is detected and the string is changed to be a proper url string.
581                                         */
582                                         if (url2.indexOf(":/") == -1 && url2.indexOf(":\\") != -1) { //$NON-NLS-1$ //$NON-NLS-2$
583                                                 TCHAR filePath2 = new TCHAR(0, url2, true);
584                                                 TCHAR urlResult2 = new TCHAR(0, OS.INTERNET_MAX_URL_LENGTH);
585                                                 int[] size2 = new int[] {urlResult2.length()};
586                                                 if (OS.UrlCreateFromPath(filePath2, urlResult2, size2, 0) == COM.S_OK) {
587                                                         url2 = urlResult2.toString(0, size2[0]);
588                                                 } else {
589                                                         url2 = PROTOCOL_FILE + url2.replace('\\', '/');
590                                                 }
591                                         }
592                                         if (html != null && url2.equals(ABOUT_BLANK)) {
593                                                 if (delaySetText) {
594                                                         delaySetText = false;
595                                                         browser.getDisplay().asyncExec(() -> {
596                                                                 if (browser.isDisposed() || html == null) return;
597                                                                 setHTML(html);
598                                                                 html = null;
599                                                         });
600                                                 } else {
601                                                         setHTML(html);
602                                                         html = null;
603                                                 }
604                                         } else {
605                                                 Variant variant2 = new Variant(auto); /* does not need to be disposed */
606                                                 IDispatch top2 = variant2.getDispatch();
607                                                 LocationEvent locationEvent = new LocationEvent(browser);
608                                                 locationEvent.display = browser.getDisplay();
609                                                 locationEvent.widget = browser;
610                                                 locationEvent.location = url2;
611                                                 locationEvent.top = top2.getAddress() == dispatch2.getAddress();
612                                                 for (int i2 = 0; i2 < locationListeners.length; i2++) {
613                                                         locationListeners[i2].changed(locationEvent);
614                                                 }
615                                                 if (browser.isDisposed()) return;
616
617                                                 /*
618                                                 * With the IBM 64-bit JVM an unexpected document complete event occurs before
619                                                 * the native browser's DOM has been built. Filter this premature event based
620                                                 * on the browser's ready state.
621                                                 */
622                                                 int[] rgdispid1 = auto.getIDsOfNames(new String[] { "ReadyState" }); //$NON-NLS-1$
623                                                 Variant pVarResult1 = auto.getProperty(rgdispid1[0]);
624                                                 if (pVarResult1 != null) {
625                                                         int readyState = pVarResult1.getInt();
626                                                         pVarResult1.dispose ();
627                                                         if (readyState != READYSTATE_COMPLETE) {
628                                                                 break;
629                                                         }
630                                                 }
631
632                                                 /*
633                                                  * Note.  The completion of the page loading is detected as
634                                                  * described in the MSDN article "Determine when a page is
635                                                  * done loading in WebBrowser Control".
636                                                  */
637                                                 if (globalDispatch != 0 && dispatch2.getAddress() == globalDispatch) {
638                                                         /* final document complete */
639                                                         globalDispatch = 0;
640
641                                                         /* re-install registered functions iff needed */
642                                                         IE ie = (IE)browser.webBrowser;
643                                                         if (ie.installFunctionsOnDocumentComplete) {
644                                                                 ie.installFunctionsOnDocumentComplete = false;
645                                                                 Iterator<BrowserFunction> elements1 = functions.values().iterator ();
646                                                                 while (elements1.hasNext ()) {
647                                                                         BrowserFunction function1 = elements1.next ();
648                                                                         execute (function1.functionString);
649                                                                 }
650                                                         }
651
652                                                         ProgressEvent progressEvent1 = new ProgressEvent(browser);
653                                                         progressEvent1.display = browser.getDisplay();
654                                                         progressEvent1.widget = browser;
655                                                         for (int i3 = 0; i3 < progressListeners.length; i3++) {
656                                                                 progressListeners[i3].completed(progressEvent1);
657                                                         }
658                                                 }
659                                         }
660                                         break;
661                                 }
662                                 case DownloadComplete: {
663                                         /*
664                                         * IE feature.  Some events that swt relies on are not sent when
665                                         * a page is refreshed (as opposed to being navigated to).  The
666                                         * workaround is to use DownloadComplete as an opportunity to
667                                         * do this work.
668                                         */
669
670                                         Iterator<BrowserFunction> elements2 = functions.values().iterator ();
671                                         while (elements2.hasNext ()) {
672                                                 BrowserFunction function2 = elements2.next ();
673                                                 execute (function2.functionString);
674                                         }
675
676                                         if (!isRefresh) break;
677                                         isRefresh = false;
678
679                                         /*
680                                         * DocumentComplete is not received for refreshes, but clients may rely
681                                         * on this event for tasks like hooking javascript listeners, so send the
682                                         * event here.
683                                         */
684                                         ProgressEvent progressEvent2 = new ProgressEvent(browser);
685                                         progressEvent2.display = browser.getDisplay();
686                                         progressEvent2.widget = browser;
687                                         for (int i4 = 0; i4 < progressListeners.length; i4++) {
688                                                 progressListeners[i4].completed(progressEvent2);
689                                         }
690
691                                         break;
692                                 }
693                                 case NavigateComplete2: {
694                                         jsEnabled = jsEnabledOnNextPage;
695
696                                         Variant varResult4 = event.arguments[1];
697                                         String url3 = varResult4.getString();
698                                         if (!performingInitialNavigate) {
699                                                 varResult4 = event.arguments[0];
700                                                 IDispatch dispatch3 = varResult4.getDispatch();
701                                                 Variant variant3 = new Variant(auto); /* does not need to be disposed */
702                                                 IDispatch top3 = variant3.getDispatch();
703                                                 if (top3.getAddress() == dispatch3.getAddress()) {
704                                                         setAboutBlank(url3.startsWith(ABOUT_BLANK));
705                                                         lastNavigateURL = url3;
706                                                 }
707                                         }
708
709                                         /*
710                                         * Bug in Acrobat Reader.  Opening > MAX_PDF PDF files causes Acrobat to not
711                                         * clean up its shells properly when the container Browser is disposed.
712                                         * This results in Eclipse crashing at shutdown time because the leftover
713                                         * shells have invalid references to unloaded Acrobat libraries.  The
714                                         * workaround is to not unload the Acrobat libraries if > MAX_PDF PDF
715                                         * files have been opened.
716                                         */
717                                         boolean isPDF = false;
718                                         String path = null;
719                                         try {
720                                                 path = new URL(url3).getPath();
721                                         } catch (MalformedURLException e) {
722                                         }
723                                         if (path != null) {
724                                                 int extensionIndex = path.lastIndexOf('.');
725                                                 if (extensionIndex != -1) {
726                                                         String extension = path.substring(extensionIndex);
727                                                         if (extension.equalsIgnoreCase(EXTENSION_PDF)) {
728                                                                 isPDF = true;
729                                                                 PDFCount++;
730                                                                 if (PDFCount > MAX_PDF) {
731                                                                         COM.FreeUnusedLibraries = false;
732                                                                 }
733                                                         }
734                                                 }
735                                         }
736
737                                         if (uncRedirect != null) {
738                                                 if (uncRedirect.equals(url3)) {
739                                                         /* full UNC path has been successfully navigated */
740                                                         uncRedirect = null;
741                                                         break;
742                                                 }
743                                                 if (uncRedirect.startsWith(url3)) {
744                                                         /*
745                                                         * UNC first segment has been successfully navigated,
746                                                         * now redirect to the full UNC path.
747                                                         */
748                                                         navigate(uncRedirect, null, null, true);
749                                                         break;
750                                                 }
751                                                 uncRedirect = null;
752                                         }
753
754                                         varResult4 = event.arguments[0];
755                                         IDispatch dispatch4 = varResult4.getDispatch();
756                                         if (globalDispatch == 0) globalDispatch = dispatch4.getAddress();
757
758                                         OleAutomation webBrowser = varResult4.getAutomation();
759                                         Variant variant4 = new Variant(auto); /* does not need to be disposed */
760                                         IDispatch top4 = variant4.getDispatch();
761                                         boolean isTop = top4.getAddress() == dispatch4.getAddress();
762                                         if (isTop) {
763                                                 /* unhook DOM listeners and unref the last document(s) */
764                                                 unhookDOMListeners(documents);
765                                                 for (int i5 = 0; i5 < documents.length; i5++) {
766                                                         documents[i5].dispose();
767                                                 }
768                                                 documents = new OleAutomation[0];
769
770                                                 /* re-install registered functions */
771                                                 Iterator<BrowserFunction> elements3 = functions.values().iterator ();
772                                                 while (elements3.hasNext ()) {
773                                                         BrowserFunction function3 = elements3.next ();
774                                                         execute (function3.functionString);
775                                                 }
776                                         }
777                                         if (!isPDF) {
778                                                 hookDOMListeners(webBrowser, isTop);
779                                         }
780                                         webBrowser.dispose();
781                                         break;
782                                 }
783                                 case NavigateError: {
784                                         if (uncRedirect != null) {
785                                                 /*
786                                                 * This is the second error attempting to reach this UNC path, so
787                                                 * it does not exist.  Don't override the default error handling.
788                                                 */
789                                                 uncRedirect = null;
790                                                 break;
791                                         }
792                                         Variant varResult5 = event.arguments[1];
793                                         final String url4 = varResult5.getString();
794                                         if (url4.startsWith("\\\\")) { //$NON-NLS-1$
795                                                 varResult5 = event.arguments[3];
796                                                 int statusCode = varResult5.getInt();
797                                                 if (statusCode == INET_E_RESOURCE_NOT_FOUND) {
798                                                         int index = url4.indexOf('\\', 2);
799                                                         if (index != -1) {
800                                                                 final String host = url4.substring(0, index);
801                                                                 Variant cancel4 = event.arguments[4];
802                                                                 if (cancel4 != null) {
803                                                                         long pCancel4 = cancel4.getByRef();
804                                                                         OS.MoveMemory(pCancel4, new short[] {OS.VARIANT_TRUE}, 2);
805                                                                 }
806                                                                 browser.getDisplay().asyncExec(() -> {
807                                                                         if (browser.isDisposed()) return;
808                                                                         /*
809                                                                         * Feature of IE.  When a UNC path ends with a '\' character IE
810                                                                         * drops this character when providing the path as an argument
811                                                                         * to some IE listeners.  Remove this character here too in
812                                                                         * order to match these other listener argument values.
813                                                                         */
814                                                                         if (url4.endsWith("\\")) { //$NON-NLS-1$
815                                                                                 uncRedirect = url4.substring(0, url4.length() - 1);
816                                                                         } else {
817                                                                                 uncRedirect = url4;
818                                                                         }
819                                                                         navigate(host, null, null, true);
820                                                                 });
821                                                         }
822                                                 }
823                                         }
824                                         break;
825                                 }
826                                 case NewWindow2: {
827                                         Variant cancel5 = event.arguments[1];
828                                         long pCancel5 = cancel5.getByRef();
829                                         WindowEvent newEvent2 = new WindowEvent(browser);
830                                         newEvent2.display = browser.getDisplay();
831                                         newEvent2.widget = browser;
832                                         newEvent2.required = false;
833                                         for (int i6 = 0; i6 < openWindowListeners.length; i6++) {
834                                                 openWindowListeners[i6].open(newEvent2);
835                                         }
836                                         IE browser = null;
837                                         if (newEvent2.browser != null && newEvent2.browser.webBrowser instanceof IE) {
838                                                 browser = (IE)newEvent2.browser.webBrowser;
839                                         }
840                                         boolean doit2 = browser != null && !browser.browser.isDisposed();
841                                         if (doit2) {
842                                                 /*
843                                                 * When a Browser is opened in a new window, BrowserFunctions that are
844                                                 * installed in it in the NavigateComplete2 callback are not retained
845                                                 * through the loading of the page.  The workaround is to re-install
846                                                 * the functions when DocumentComplete is received.
847                                                 */
848                                                 browser.installFunctionsOnDocumentComplete = true;
849
850                                                 Variant variant5 = new Variant(browser.auto); /* does not need to be disposed */
851                                                 IDispatch iDispatch = variant5.getDispatch();
852                                                 Variant ppDisp = event.arguments[0];
853                                                 long byref = ppDisp.getByRef();
854                                                 if (byref != 0) OS.MoveMemory(byref, new long[] {iDispatch.getAddress()}, C.PTR_SIZEOF);
855                                         }
856                                         if (newEvent2.required) {
857                                                 OS.MoveMemory(pCancel5, new short[]{doit2 ? OS.VARIANT_FALSE : OS.VARIANT_TRUE}, 2);
858                                         }
859                                         break;
860                                 }
861                                 case OnMenuBar: {
862                                         Variant arg01 = event.arguments[0];
863                                         menuBar = arg01.getBoolean();
864                                         break;
865                                 }
866                                 case OnStatusBar: {
867                                         Variant arg02 = event.arguments[0];
868                                         statusBar = arg02.getBoolean();
869                                         break;
870                                 }
871                                 case OnToolBar: {
872                                         Variant arg03 = event.arguments[0];
873                                         toolBar = arg03.getBoolean();
874                                         /*
875                                         * Feature in Internet Explorer.  OnToolBar FALSE is emitted
876                                         * when both tool bar, address bar and menu bar must not be visible.
877                                         * OnToolBar TRUE is emitted when either of tool bar, address bar
878                                         * or menu bar is visible.
879                                         */
880                                         if (!toolBar) {
881                                                 addressBar = false;
882                                                 menuBar = false;
883                                         }
884                                         break;
885                                 }
886                                 case OnVisible: {
887                                         Variant arg11 = event.arguments[0];
888                                         boolean visible = arg11.getBoolean();
889                                         WindowEvent newEvent3 = new WindowEvent(browser);
890                                         newEvent3.display = browser.getDisplay();
891                                         newEvent3.widget = browser;
892                                         if (visible) {
893                                                 if (addressBar) {
894                                                         /*
895                                                         * Bug in Internet Explorer.  There is no distinct notification for
896                                                         * the address bar.  If neither address, menu or tool bars are visible,
897                                                         * OnToolBar FALSE is emitted. For some reason, querying the value of
898                                                         * AddressBar in this case returns true even though it should not be
899                                                         * set visible.  The workaround is to only query the value of AddressBar
900                                                         * when OnToolBar FALSE has not been emitted.
901                                                         */
902                                                         int[] rgdispid2 = auto.getIDsOfNames(new String[] { "AddressBar" }); //$NON-NLS-1$
903                                                         Variant pVarResult2 = auto.getProperty(rgdispid2[0]);
904                                                         if (pVarResult2 != null) {
905                                                                 if (pVarResult2.getType () == OLE.VT_BOOL) {
906                                                                         addressBar = pVarResult2.getBoolean ();
907                                                                 }
908                                                                 pVarResult2.dispose ();
909                                                         }
910                                                 }
911                                                 newEvent3.addressBar = addressBar;
912                                                 newEvent3.menuBar = menuBar;
913                                                 newEvent3.statusBar = statusBar;
914                                                 newEvent3.toolBar = toolBar;
915                                                 newEvent3.location = location;
916                                                 newEvent3.size = size;
917                                                 for (int i7 = 0; i7 < visibilityWindowListeners.length; i7++) {
918                                                         visibilityWindowListeners[i7].show(newEvent3);
919                                                 }
920                                                 location = null;
921                                                 size = null;
922                                         } else {
923                                                 for (int i8 = 0; i8 < visibilityWindowListeners.length; i8++) {
924                                                         visibilityWindowListeners[i8].hide(newEvent3);
925                                                 }
926                                         }
927                                         break;
928                                 }
929                                 case ProgressChange: {
930                                         /* don't send client events if the initial navigate to about:blank has not completed */
931                                         if (performingInitialNavigate) break;
932
933                                         Variant arg12 = event.arguments[0];
934                                         int nProgress = arg12.getType() != OLE.VT_I4 ? 0 : arg12.getInt(); // may be -1
935                                         Variant arg2 = event.arguments[1];
936                                         int nProgressMax = arg2.getType() != OLE.VT_I4 ? 0 : arg2.getInt();
937                                         ProgressEvent newEvent4 = new ProgressEvent(browser);
938                                         newEvent4.display = browser.getDisplay();
939                                         newEvent4.widget = browser;
940                                         newEvent4.current = nProgress;
941                                         newEvent4.total = nProgressMax;
942                                         if (nProgress != -1) {
943                                                 for (int i9 = 0; i9 < progressListeners.length; i9++) {
944                                                         progressListeners[i9].changed(newEvent4);
945                                                 }
946                                         }
947                                         break;
948                                 }
949                                 case StatusTextChange: {
950                                         /* don't send client events if the initial navigate to about:blank has not completed */
951                                         if (performingInitialNavigate) break;
952
953                                         Variant arg13 = event.arguments[0];
954                                         if (arg13.getType() == OLE.VT_BSTR) {
955                                                 String text = arg13.getString();
956                                                 StatusTextEvent newEvent5 = new StatusTextEvent(browser);
957                                                 newEvent5.display = browser.getDisplay();
958                                                 newEvent5.widget = browser;
959                                                 newEvent5.text = text;
960                                                 for (int i10 = 0; i10 < statusTextListeners.length; i10++) {
961                                                         statusTextListeners[i10].changed(newEvent5);
962                                                 }
963                                         }
964                                         break;
965                                 }
966                                 case TitleChange: {
967                                         /* don't send client events if the initial navigate to about:blank has not completed */
968                                         if (performingInitialNavigate) break;
969
970                                         Variant arg14 = event.arguments[0];
971                                         if (arg14.getType() == OLE.VT_BSTR) {
972                                                 String title = arg14.getString();
973                                                 TitleEvent newEvent6 = new TitleEvent(browser);
974                                                 newEvent6.display = browser.getDisplay();
975                                                 newEvent6.widget = browser;
976                                                 newEvent6.title = title;
977                                                 for (int i11 = 0; i11 < titleListeners.length; i11++) {
978                                                         titleListeners[i11].changed(newEvent6);
979                                                 }
980                                         }
981                                         break;
982                                 }
983                                 case WindowClosing: {
984                                         /*
985                                         * Disposing the Browser directly from this callback will crash if the
986                                         * Browser has a text field with an active caret.  As a workaround fire
987                                         * the Close event and dispose the Browser in an async block.
988                                         */
989                                         browser.getDisplay().asyncExec(() -> {
990                                                 if (browser.isDisposed()) return;
991                                                 WindowEvent newEvent = new WindowEvent(browser);
992                                                 newEvent.display = browser.getDisplay();
993                                                 newEvent.widget = browser;
994                                                 for (int i = 0; i < closeWindowListeners.length; i++) {
995                                                         closeWindowListeners[i].close(newEvent);
996                                                 }
997                                                 browser.dispose();
998                                         });
999                                         Variant cancel6 = event.arguments[1];
1000                                         long pCancel6 = cancel6.getByRef();
1001                                         Variant arg15 = event.arguments[0];
1002                                         boolean isChildWindow = arg15.getBoolean();
1003                                         OS.MoveMemory(pCancel6, new short[]{isChildWindow ? OS.VARIANT_FALSE : OS.VARIANT_TRUE}, 2);
1004                                         break;
1005                                 }
1006                                 case WindowSetHeight: {
1007                                         if (size == null) size = new Point(0, 0);
1008                                         Variant arg16 = event.arguments[0];
1009                                         size.y = arg16.getInt();
1010                                         break;
1011                                 }
1012                                 case WindowSetLeft: {
1013                                         if (location == null) location = new Point(0, 0);
1014                                         Variant arg17 = event.arguments[0];
1015                                         location.x = arg17.getInt();
1016                                         break;
1017                                 }
1018                                 case WindowSetTop: {
1019                                         if (location == null) location = new Point(0, 0);
1020                                         Variant arg18 = event.arguments[0];
1021                                         location.y = arg18.getInt();
1022                                         break;
1023                                 }
1024                                 case WindowSetWidth: {
1025                                         if (size == null) size = new Point(0, 0);
1026                                         Variant arg19 = event.arguments[0];
1027                                         size.x = arg19.getInt();
1028                                         break;
1029                                 }
1030                         }
1031                 }
1032         };
1033         site.addEventListener(BeforeNavigate2, oleListener);
1034         site.addEventListener(CommandStateChange, oleListener);
1035         site.addEventListener(DocumentComplete, oleListener);
1036         site.addEventListener(DownloadComplete, oleListener);
1037         site.addEventListener(NavigateComplete2, oleListener);
1038         site.addEventListener(NavigateError, oleListener);
1039         site.addEventListener(NewWindow2, oleListener);
1040         site.addEventListener(OnMenuBar, oleListener);
1041         site.addEventListener(OnStatusBar, oleListener);
1042         site.addEventListener(OnToolBar, oleListener);
1043         site.addEventListener(OnVisible, oleListener);
1044         site.addEventListener(ProgressChange, oleListener);
1045         site.addEventListener(StatusTextChange, oleListener);
1046         site.addEventListener(TitleChange, oleListener);
1047         site.addEventListener(WindowClosing, oleListener);
1048         site.addEventListener(WindowSetHeight, oleListener);
1049         site.addEventListener(WindowSetLeft, oleListener);
1050         site.addEventListener(WindowSetTop, oleListener);
1051         site.addEventListener(WindowSetWidth, oleListener);
1052
1053         Variant variant = new Variant(true);
1054         auto.setProperty(RegisterAsBrowser, variant);
1055         variant.dispose();
1056
1057         variant = new Variant(false);
1058         int[] rgdispid = auto.getIDsOfNames(new String[] {"RegisterAsDropTarget"}); //$NON-NLS-1$
1059         if (rgdispid != null) auto.setProperty(rgdispid[0], variant);
1060         variant.dispose();
1061 }
1062
1063 @Override
1064 public boolean back() {
1065         if (!back) return false;
1066         int[] rgdispid = auto.getIDsOfNames(new String[] { "GoBack" }); //$NON-NLS-1$
1067         Variant pVarResult = auto.invoke(rgdispid[0]);
1068         return pVarResult != null && pVarResult.getType() == OLE.VT_EMPTY;
1069 }
1070
1071 @Override
1072 public boolean close() {
1073         boolean result = true;
1074         int[] rgdispid = auto.getIDsOfNames(new String[] {PROPERTY_DOCUMENT});
1075         int dispIdMember = rgdispid[0];
1076         Variant pVarResult = auto.getProperty(dispIdMember);
1077         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1078                 if (pVarResult != null) pVarResult.dispose();
1079         } else {
1080                 OleAutomation document = pVarResult.getAutomation();
1081                 pVarResult.dispose();
1082                 rgdispid = document.getIDsOfNames(new String[]{"parentWindow"}); //$NON-NLS-1$
1083                 /* rgdispid != null implies HTML content */
1084                 if (rgdispid != null) {
1085                         dispIdMember = rgdispid[0];
1086                         pVarResult = document.getProperty(dispIdMember);
1087                         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1088                                 if (pVarResult != null) pVarResult.dispose();
1089                         } else {
1090                                 OleAutomation window = pVarResult.getAutomation();
1091                                 pVarResult.dispose();
1092                                 rgdispid = window.getIDsOfNames(new String[]{"location"}); //$NON-NLS-1$
1093                                 dispIdMember = rgdispid[0];
1094                                 pVarResult = window.getProperty(dispIdMember);
1095                                 if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1096                                         if (pVarResult != null) pVarResult.dispose();
1097                                 } else {
1098                                         OleAutomation location = pVarResult.getAutomation();
1099                                         pVarResult.dispose();
1100                                         LocationListener[] oldListeners = locationListeners;
1101                                         locationListeners = new LocationListener[0];
1102                                         rgdispid = location.getIDsOfNames(new String[]{"replace"}); //$NON-NLS-1$
1103                                         dispIdMember = rgdispid[0];
1104                                         Variant[] args = new Variant[] {new Variant("about:blank")}; //$NON-NLS-1$
1105                                         pVarResult = location.invoke(dispIdMember, args);
1106                                         if (pVarResult == null) {
1107                                                 /* cancelled by user */
1108                                                 result = false;
1109                                         } else {
1110                                                 pVarResult.dispose();
1111                                         }
1112                                         args[0].dispose();
1113                                         locationListeners = oldListeners;
1114                                         location.dispose();
1115                                 }
1116                                 window.dispose();
1117                         }
1118                 }
1119                 document.dispose();
1120         }
1121         return result;
1122 }
1123
1124 static Variant createSafeArray(String string) {
1125         /* Create a pointer and copy the data into it */
1126         byte[] bytes = string.getBytes();
1127         int length = bytes.length;
1128         long pvData = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, length);
1129         C.memmove(pvData, bytes, length);
1130         int cElements1 = length;
1131
1132         /* Create a SAFEARRAY in memory */
1133         long pSafeArray = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, SAFEARRAY.sizeof);
1134         SAFEARRAY safeArray = new SAFEARRAY();
1135         safeArray.cDims = 1;
1136         safeArray.fFeatures = OS.FADF_FIXEDSIZE;
1137         safeArray.cbElements = 1;
1138         safeArray.pvData = pvData;
1139         SAFEARRAYBOUND safeArrayBound = new SAFEARRAYBOUND();
1140         safeArray.rgsabound = safeArrayBound;
1141         safeArrayBound.cElements = cElements1;
1142         OS.MoveMemory (pSafeArray, safeArray, SAFEARRAY.sizeof);
1143
1144         /* Return a Variant that holds the SAFEARRAY */
1145         long pVariant = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, Variant.sizeof);
1146         short vt = (short)(OLE.VT_ARRAY | OLE.VT_UI1);
1147         OS.MoveMemory(pVariant, new short[] {vt}, 2);
1148         OS.MoveMemory(pVariant + 8, new long[] {pSafeArray}, C.PTR_SIZEOF);
1149         return new Variant(pVariant, (short)(OLE.VT_BYREF | OLE.VT_VARIANT));
1150 }
1151
1152 @Override
1153 public boolean execute(String script) {
1154         /*
1155          * Issue with IE: If the browser has not shown any content yet then
1156          * first navigate to about:blank to work around bug 465822, then execute
1157          * the requested script.
1158          */
1159         if (!performingInitialNavigate && _getUrl().length() == 0) {
1160                 performingInitialNavigate = true;
1161                 navigate (ABOUT_BLANK, null, null, true);
1162         }
1163
1164         /* get IHTMLDocument2 */
1165         int[] rgdispid = auto.getIDsOfNames(new String[] {PROPERTY_DOCUMENT});
1166         int dispIdMember = rgdispid[0];
1167         Variant pVarResult = auto.getProperty(dispIdMember);
1168         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1169                 if (pVarResult != null) pVarResult.dispose ();
1170                 return false;
1171         }
1172         OleAutomation document = pVarResult.getAutomation();
1173         pVarResult.dispose();
1174
1175         /* get IHTMLWindow2 */
1176         rgdispid = document.getIDsOfNames(new String[]{"parentWindow"}); //$NON-NLS-1$
1177         if (rgdispid == null) {
1178                 /* implies that browser's content is not a IHTMLDocument2 (eg.- acrobat reader) */
1179                 document.dispose();
1180                 return false;
1181         }
1182         dispIdMember = rgdispid[0];
1183         pVarResult = document.getProperty(dispIdMember);
1184         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1185                 if (pVarResult != null) pVarResult.dispose ();
1186                 document.dispose();
1187                 return false;
1188         }
1189         OleAutomation ihtmlWindow2 = pVarResult.getAutomation();
1190         pVarResult.dispose();
1191         document.dispose();
1192
1193         rgdispid = ihtmlWindow2.getIDsOfNames(new String[] { "execScript", "code" }); //$NON-NLS-1$  //$NON-NLS-2$
1194         if (rgdispid == null) {
1195                 ihtmlWindow2.dispose();
1196                 return false;
1197         }
1198         Variant[] rgvarg = new Variant[1];
1199         rgvarg[0] = new Variant(script);
1200         int[] rgdispidNamedArgs = new int[1];
1201         rgdispidNamedArgs[0] = rgdispid[1];
1202         pVarResult = ihtmlWindow2.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
1203         rgvarg[0].dispose();
1204         ihtmlWindow2.dispose();
1205         if (pVarResult == null) return false;
1206         pVarResult.dispose();
1207         return true;
1208 }
1209
1210 @Override
1211 public boolean forward() {
1212         if (!forward) return false;
1213         int[] rgdispid = auto.getIDsOfNames(new String[] { "GoForward" }); //$NON-NLS-1$
1214         Variant pVarResult = auto.invoke(rgdispid[0]);
1215         return pVarResult != null && pVarResult.getType() == OLE.VT_EMPTY;
1216 }
1217
1218 @Override
1219 public String getBrowserType () {
1220         return "ie"; //$NON-NLS-1$
1221 }
1222
1223 @Override
1224 String getDeleteFunctionString (String functionName) {
1225         return "window." + functionName + "=undefined"; //$NON-NLS-1$ //$NON-NLS-2$
1226 }
1227
1228 @Override
1229 public String getText() {
1230         /* get the document object */
1231         int[] rgdispid = auto.getIDsOfNames(new String[] {PROPERTY_DOCUMENT});
1232         Variant pVarResult = auto.getProperty(rgdispid[0]);
1233         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1234                 if (pVarResult != null) pVarResult.dispose ();
1235                 return ""; //$NON-NLS-1$
1236         }
1237         OleAutomation document = pVarResult.getAutomation();
1238         pVarResult.dispose();
1239
1240         /* get the html object */
1241         rgdispid = document.getIDsOfNames(new String[] {"documentElement"}); //$NON-NLS-1$
1242         if (rgdispid == null) {
1243                 /* implies that the browser is displaying non-HTML content */
1244                 document.dispose();
1245                 return ""; //$NON-NLS-1$
1246         }
1247         pVarResult = document.getProperty(rgdispid[0]);
1248         document.dispose();
1249         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY || pVarResult.getType() == COM.VT_NULL) {
1250                 if (pVarResult != null) pVarResult.dispose ();
1251                 return ""; //$NON-NLS-1$
1252         }
1253         OleAutomation element = pVarResult.getAutomation();
1254         pVarResult.dispose();
1255
1256         /* get its outerHTML property */
1257         rgdispid = element.getIDsOfNames(new String[] {"outerHTML"}); //$NON-NLS-1$
1258         pVarResult = element.getProperty(rgdispid[0]);
1259         element.dispose();
1260         if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
1261                 if (pVarResult != null) pVarResult.dispose ();
1262                 return ""; //$NON-NLS-1$
1263         }
1264         String result = pVarResult.getString();
1265         pVarResult.dispose();
1266
1267         return result;
1268 }
1269
1270 @Override
1271 public String getUrl() {
1272         /*
1273          * If the url is "" then return ABOUT_BLANK in order to be consistent
1274          * with the other Browser implementations which auto-navigate to ABOUT_BLANK
1275          * when opened.
1276          */
1277         String result = _getUrl();
1278         return result.length() != 0 ? result : ABOUT_BLANK;
1279 }
1280
1281 String _getUrl() {
1282         int[] rgdispid = auto.getIDsOfNames(new String[] { "LocationURL" }); //$NON-NLS-1$
1283         Variant pVarResult = auto.getProperty(rgdispid[0]);
1284         if (pVarResult == null || pVarResult.getType() != OLE.VT_BSTR) return ""; //$NON-NLS-1$
1285         String result = pVarResult.getString();
1286         pVarResult.dispose();
1287         return result;
1288 }
1289
1290 @Override
1291 public boolean isBackEnabled() {
1292         return back;
1293 }
1294
1295 @Override
1296 public boolean isForwardEnabled() {
1297         return forward;
1298 }
1299
1300 @Override
1301 public boolean isFocusControl () {
1302         return site.isFocusControl() || frame.isFocusControl();
1303 }
1304
1305 boolean navigate(String url, String postData, String headers[], boolean silent) {
1306         int count = 1;
1307         if (postData != null) count++;
1308         if (headers != null) count++;
1309         Variant[] rgvarg = new Variant[count];
1310         int[] rgdispidNamedArgs = new int[count];
1311         int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL", "PostData", "Headers" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
1312         int index = 0;
1313         rgvarg[index] = new Variant(url);
1314         rgdispidNamedArgs[index++] = rgdispid[1];
1315         if (postData != null) {
1316                 rgvarg[index] = createSafeArray(postData);
1317                 rgdispidNamedArgs[index++] = rgdispid[2];
1318         }
1319         if (headers != null) {
1320                 StringBuilder buffer = new StringBuilder();
1321                 for (int i = 0; i < headers.length; i++) {
1322                         String current = headers[i];
1323                         if (current != null) {
1324                                 int sep = current.indexOf(':');
1325                                 if (sep != -1) {
1326                                         String key = current.substring(0, sep).trim();
1327                                         String value = current.substring(sep + 1).trim();
1328                                         if (key.length() > 0 && value.length() > 0) {
1329                                                 buffer.append(key);
1330                                                 buffer.append(':');
1331                                                 buffer.append(value);
1332                                                 buffer.append("\r\n");
1333                                         }
1334                                 }
1335                         }
1336                 }
1337                 rgvarg[index] = new Variant(buffer.toString());
1338                 rgdispidNamedArgs[index++] = rgdispid[3];
1339         }
1340         boolean oldValue = false;
1341         if (silent && IEVersion >= 7) {
1342                 int hResult = OS.CoInternetIsFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.GET_FEATURE_FROM_PROCESS);
1343                 oldValue = hResult == COM.S_OK;
1344                 OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
1345         }
1346         Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
1347         if (silent && IEVersion >= 7) {
1348                 OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, oldValue);
1349         }
1350         for (int i = 0; i < count; i++) {
1351                 rgvarg[i].dispose();
1352         }
1353         if (pVarResult == null) return false;
1354         boolean result = pVarResult.getType() == OLE.VT_EMPTY;
1355         pVarResult.dispose();
1356         return result;
1357 }
1358
1359 @Override
1360 public void refresh() {
1361         uncRedirect = null;
1362
1363         /*
1364         * Bug in Acrobat Reader.  Opening > MAX_PDF PDF files causes Acrobat to not
1365         * clean up its shells properly when the container Browser is disposed.
1366         * This results in Eclipse crashing at shutdown time because the leftover
1367         * shells have invalid references to unloaded Acrobat libraries.  The
1368         * workaround is to not unload the Acrobat libraries if > MAX_PDF PDF
1369         * files have been opened.
1370         */
1371         String url = _getUrl();
1372         int extensionIndex = url.lastIndexOf('.');
1373         if (extensionIndex != -1) {
1374                 String extension = url.substring(extensionIndex);
1375                 if (extension.equalsIgnoreCase (EXTENSION_PDF)) {
1376                         PDFCount++;
1377                         if (PDFCount > MAX_PDF) {
1378                                 COM.FreeUnusedLibraries = false;
1379                         }
1380                 }
1381         }
1382
1383         isRefresh = true;
1384         int[] rgdispid = auto.getIDsOfNames(new String[] { "Refresh" }); //$NON-NLS-1$
1385         auto.invoke(rgdispid[0]);
1386 }
1387
1388 void setHTML (String string) {
1389         int charCount = string.length();
1390         char[] chars = new char[charCount];
1391         string.getChars(0, charCount, chars, 0);
1392         int byteCount = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, charCount, null, 0, null, null);
1393         /*
1394         * Internet Explorer appears to treat the data loaded with
1395         * nsIPersistStreamInit.Load as if it were encoded using the default
1396         * local charset.  There does not seem to be an API to set the
1397         * desired charset explicitly in this case.  The fix is to
1398         * prepend the UTF-8 Byte Order Mark signature to the data.
1399         */
1400         byte[] UTF8BOM = {(byte)0xEF, (byte)0xBB, (byte)0xBF};
1401         long hGlobal = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, UTF8BOM.length + byteCount);
1402         if (hGlobal != 0) {
1403                 OS.MoveMemory(hGlobal, UTF8BOM, UTF8BOM.length);
1404                 OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, charCount, hGlobal + UTF8BOM.length, byteCount, null, null);
1405                 long [] ppstm = new long [1];
1406                 /*
1407                 * CreateStreamOnHGlobal is called with the flag fDeleteOnRelease.
1408                 * If the call succeeds the buffer hGlobal is freed automatically
1409                 * when the IStream object is released. If the call fails, free the
1410                 * buffer hGlobal.
1411                 */
1412                 if (OS.CreateStreamOnHGlobal(hGlobal, true, ppstm) == OS.S_OK) {
1413                         int[] rgdispid = auto.getIDsOfNames(new String[] {PROPERTY_DOCUMENT});
1414                         Variant pVarResult = auto.getProperty(rgdispid[0]);
1415                         IDispatch dispatchDocument = pVarResult.getDispatch();
1416                         long [] ppvObject = new long [1];
1417                         int result = dispatchDocument.QueryInterface(COM.IIDIPersistStreamInit, ppvObject);
1418                         if (result == OS.S_OK) {
1419                                 IPersistStreamInit persistStreamInit = new IPersistStreamInit(ppvObject[0]);
1420                                 if (persistStreamInit.InitNew() == OS.S_OK) {
1421                                         persistStreamInit.Load(ppstm[0]);
1422                                 }
1423                                 persistStreamInit.Release();
1424                         }
1425                         pVarResult.dispose();
1426                         IUnknown stream = new IUnknown(ppstm[0]);
1427                         stream.Release();
1428                 } else {
1429                         OS.GlobalFree(hGlobal);
1430                 }
1431         }
1432 }
1433
1434 private void setAboutBlank(boolean value) {
1435         isAboutBlank = value;
1436         updateForceTrusted();
1437 }
1438
1439 private void setUntrustedText(boolean value) {
1440         untrustedText = value;
1441         updateForceTrusted();
1442 }
1443
1444 private void updateForceTrusted() {
1445         site.isForceTrusted = isAboutBlank && !untrustedText;
1446 }
1447
1448 @Override
1449 public boolean setText(final String html, boolean trusted) {
1450         /*
1451         * If the browser is navigating to about:blank in response to its first
1452         * setUrl() invocation then delay setting this text content until the
1453         * navigate has completed.  about:blank will be re-navigated to in order
1454         * to ensure that all expected client events are sent.
1455         */
1456         if (performingInitialNavigate) {
1457                 pendingText = new Object[] {html, trusted};
1458                 pendingUrl = null;
1459                 return true;
1460         }
1461
1462         /*
1463         * If the html field is non-null then the about:blank page is already being
1464         * loaded from a previous setText() invocation, so no Stop or Navigate is
1465         * required.  Just set the html that is to be shown.
1466         */
1467         boolean blankLoading = this.html != null;
1468         this.html = html;
1469         setUntrustedText(!trusted);
1470         if (blankLoading) return true;
1471
1472         /*
1473         * Navigate to the blank page and insert the given html when
1474         * receiving the next DocumentComplete notification.  See the
1475         * MSDN article "Loading HTML content from a Stream".
1476         *
1477         * Note.  Stop any pending request.  This is required to avoid displaying a
1478         * blank page as a result of consecutive calls to setUrl and/or setText.
1479         * The previous request would otherwise render the new html content and
1480         * reset the html field before the browser actually navigates to the blank
1481         * page as requested below.
1482         *
1483         * Feature in Internet Explorer.  Stopping pending requests when no request
1484         * is pending causes a default page 'Action cancelled' to be displayed.  The
1485         * workaround is to not invoke 'stop' when no request has been set since
1486         * that instance was created.
1487         */
1488
1489         /*
1490         * Stopping the loading of a page causes DocumentComplete events from previous
1491         * requests to be received before the DocumentComplete for this page.  In such
1492         * cases we must be sure to not set the html into the browser too soon, since
1493         * doing so could result in its page being cleared out by a subsequent
1494         * DocumentComplete.  The Browser's ReadyState can be used to determine whether
1495         * these extra events will be received or not.
1496         */
1497         if (_getUrl().length() != 0) {
1498                 int[] rgdispid = auto.getIDsOfNames(new String[] { "ReadyState" }); //$NON-NLS-1$
1499                 Variant pVarResult = auto.getProperty(rgdispid[0]);
1500                 if (pVarResult == null) return false;
1501                 delaySetText = pVarResult.getInt() != READYSTATE_COMPLETE;
1502                 pVarResult.dispose();
1503                 rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
1504                 auto.invoke(rgdispid[0]);
1505         }
1506
1507         int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
1508         Variant[] rgvarg = new Variant[1];
1509         rgvarg[0] = new Variant(ABOUT_BLANK);
1510         int[] rgdispidNamedArgs = new int[1];
1511         rgdispidNamedArgs[0] = rgdispid[1];
1512         boolean oldValue = false;
1513         if (IEVersion >= 7) {
1514                 int hResult = OS.CoInternetIsFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.GET_FEATURE_FROM_PROCESS);
1515                 oldValue = hResult == COM.S_OK;
1516                 OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
1517         }
1518         Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
1519         if (IEVersion >= 7) {
1520                 OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, oldValue);
1521         }
1522         rgvarg[0].dispose();
1523         if (pVarResult == null) return false;
1524         boolean result = pVarResult.getType() == OLE.VT_EMPTY;
1525         pVarResult.dispose();
1526         return result;
1527 }
1528
1529 @Override
1530 public boolean setUrl(String url, String postData, String headers[]) {
1531         html = uncRedirect = null;
1532
1533         /*
1534         * If the browser has not shown any content yet then first navigate to
1535         * about:blank to work around IE bug http://support.microsoft.com/kb/320153,
1536         * then navigate to the requested url once about:blank has loaded.
1537         */
1538         if (_getUrl().length() == 0 && !ABOUT_BLANK.equalsIgnoreCase(url)) {
1539                 pendingText = null;
1540                 pendingUrl = new Object[] {url, postData, headers};
1541                 performingInitialNavigate = true;
1542                 navigate (ABOUT_BLANK, null, null, true);
1543                 return true;
1544         }
1545
1546         /*
1547         * Bug in Internet Explorer.  For some reason, Navigating to an xml document before
1548         * a previous Navigate has completed will leave the Browser in a bad state if the
1549         * Navigate to the xml document does not complete.  This bad state causes a GP when
1550         * the parent window is eventually disposed.  The workaround is to issue a Stop before
1551         * navigating to any xml document.
1552         */
1553         if (url.endsWith(".xml")) {     //$NON-NLS-1$
1554                 int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
1555                 auto.invoke(rgdispid[0]);
1556         }
1557         return navigate(url, postData, headers, false);
1558 }
1559
1560 @Override
1561 public void stop() {
1562         /*
1563         * If the browser has not completed its initial navigate to about:blank
1564         * then do not issue Stop here, as this will display the IE error page.
1565         * Just clear the pending url and text fields so that any pending content
1566         * will not be set into the browser when the about:blank navigate completes.
1567         */
1568         if (performingInitialNavigate) {
1569                 pendingText = pendingUrl = null;
1570                 return;
1571         }
1572
1573         /*
1574         * Feature of IE.  Invoking Stop in IE before any content has been shown
1575         * displays a Navigation Cancelled error page.  The workaround is to not
1576         * invoke Stop if no content has been shown yet.
1577         */
1578         if (_getUrl().length() == 0) return;
1579
1580         /*
1581         * Ensure that isAboutBlank is set accurately since Stop can be issued at
1582         * any stage in the page load cycle.
1583         */
1584         setAboutBlank(getUrl().startsWith(ABOUT_BLANK));
1585
1586         uncRedirect = null;
1587         int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
1588         auto.invoke(rgdispid[0]);
1589 }
1590
1591 @Override
1592 boolean translateMnemonics () {
1593         return false;
1594 }
1595
1596 void handleDOMEvent (OleEvent e) {
1597         if (e.arguments == null || e.arguments.length == 0) return; /* for IE5 */
1598
1599         Variant arg = e.arguments[0];
1600         OleAutomation event = arg.getAutomation();
1601         int[] rgdispid = event.getIDsOfNames(new String[]{ PROPERTY_TYPE });
1602         int dispIdMember = rgdispid[0];
1603         Variant pVarResult = event.getProperty(dispIdMember);
1604         String eventType = pVarResult.getString();
1605         pVarResult.dispose();
1606
1607         if (eventType.equals(EVENT_KEYDOWN)) {
1608                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_KEYCODE });
1609                 dispIdMember = rgdispid[0];
1610                 pVarResult = event.getProperty(dispIdMember);
1611                 lastKeyCode = translateKey (pVarResult.getInt());
1612                 pVarResult.dispose();
1613
1614                 rgdispid = event.getIDsOfNames (new String[] {PROPERTY_RETURNVALUE});
1615                 pVarResult = event.getProperty (rgdispid[0]);
1616                 boolean consume = pVarResult != null && pVarResult.getType () == OLE.VT_BOOL && !pVarResult.getBoolean ();
1617                 pVarResult.dispose ();
1618
1619                 MSG msg = new MSG ();
1620                 int flags = OS.PM_NOYIELD | (consume ? OS.PM_REMOVE : OS.PM_NOREMOVE);
1621                 if (OS.PeekMessage (msg, frame.handle, OS.WM_CHAR, OS.WM_CHAR, flags)) {
1622                         /* a keypress will be received for this key so don't send KeyDown here */
1623                         event.dispose();
1624                         return;
1625                 }
1626
1627                 if (consume) {
1628                         /*
1629                          * an event should not be sent if another listener has vetoed the
1630                          * KeyDown (this is for non-character cases like arrow keys, etc.)
1631                          */
1632                         event.dispose();
1633                         return;
1634                 }
1635
1636                 /* if this is a repeating key then an event should not be fired for it */
1637                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_REPEAT });
1638                 dispIdMember = rgdispid[0];
1639                 pVarResult = event.getProperty(dispIdMember);
1640                 boolean repeating = pVarResult.getBoolean();
1641                 pVarResult.dispose();
1642                 if (repeating) {
1643                         event.dispose();
1644                         return;
1645                 }
1646
1647                 int mask = 0;
1648                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
1649                 dispIdMember = rgdispid[0];
1650                 pVarResult = event.getProperty(dispIdMember);
1651                 if (pVarResult.getBoolean()) mask |= SWT.ALT;
1652                 pVarResult.dispose();
1653
1654                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
1655                 dispIdMember = rgdispid[0];
1656                 pVarResult = event.getProperty(dispIdMember);
1657                 if (pVarResult.getBoolean()) mask |= SWT.CTRL;
1658                 pVarResult.dispose();
1659
1660                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
1661                 dispIdMember = rgdispid[0];
1662                 pVarResult = event.getProperty(dispIdMember);
1663                 if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
1664                 pVarResult.dispose();
1665
1666                 Event keyEvent = new Event ();
1667                 keyEvent.widget = browser;
1668                 keyEvent.type = SWT.KeyDown;
1669                 keyEvent.keyCode = lastKeyCode;
1670                 keyEvent.stateMask = mask;
1671                 keyEvent.stateMask &= ~lastKeyCode;             /* remove current keydown if it's a state key */
1672                 /*
1673                 * keypress events are not received for Backspace, Enter, Delete and
1674                 * Tab, so KeyDown events are sent for them here.  Set the KeyDown
1675                 * event's character field and IE's lastCharCode field for these keys
1676                 * so that the Browser's key events are consistent with other controls.
1677                 */
1678                 switch (lastKeyCode) {
1679                         case SWT.BS: lastCharCode = keyEvent.character = SWT.BS; break;
1680                         case SWT.CR: lastCharCode = keyEvent.character = SWT.CR; break;
1681                         case SWT.DEL: lastCharCode = keyEvent.character = SWT.DEL; break;
1682                         case SWT.TAB: lastCharCode = keyEvent.character = SWT.TAB; break;
1683                 }
1684
1685                 if (!sendKeyEvent(keyEvent)) {
1686                         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_RETURNVALUE });
1687                         dispIdMember = rgdispid[0];
1688                         Variant pVarFalse = new Variant(false);
1689                         event.setProperty(dispIdMember, pVarFalse);
1690                         pVarFalse.dispose();
1691                 }
1692
1693                 /*
1694                 * Pressing F5 refreshes the current page.  If this is about to happen
1695                 * then set isRefresh to true so that received IE events will be treated
1696                 * accordingly.
1697                 */
1698                 if (lastKeyCode == SWT.F5) isRefresh = true;
1699
1700                 event.dispose();
1701                 return;
1702         }
1703
1704         if (eventType.equals(EVENT_KEYPRESS)) {
1705                 int mask = 0;
1706                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
1707                 dispIdMember = rgdispid[0];
1708                 pVarResult = event.getProperty(dispIdMember);
1709                 if (pVarResult.getBoolean()) mask |= SWT.CTRL;
1710                 pVarResult.dispose();
1711
1712                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
1713                 dispIdMember = rgdispid[0];
1714                 pVarResult = event.getProperty(dispIdMember);
1715                 if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
1716                 pVarResult.dispose();
1717
1718                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
1719                 dispIdMember = rgdispid[0];
1720                 pVarResult = event.getProperty(dispIdMember);
1721                 if (pVarResult.getBoolean()) mask |= SWT.ALT;
1722                 pVarResult.dispose();
1723
1724                 /* in the keypress event the keyCode actually corresponds to the character code */
1725                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_KEYCODE });
1726                 dispIdMember = rgdispid[0];
1727                 pVarResult = event.getProperty(dispIdMember);
1728                 lastCharCode = pVarResult.getInt();
1729                 pVarResult.dispose();
1730
1731                 /*
1732                 * WebSite.TranslateAccelerator() explicitly does not translate OS.VK_RETURN
1733                 * keys, so the PeekMessage check in the keydown handler always allows a
1734                 * KeyDown to be sent for this key.  However, keydown and keypress events are
1735                 * both sometimes received for OS.VK_RETURN, depending on the page's focus
1736                 * control.  To handle this, do not send a KeyDown for CR or LF here since
1737                 * one is always sent for it from the keydown handler.
1738                 */
1739                 if (lastCharCode == SWT.CR || lastCharCode == SWT.LF) {
1740                         event.dispose();
1741                         return;
1742                 }
1743
1744                 Event keyEvent = new Event ();
1745                 keyEvent.widget = browser;
1746                 keyEvent.type = SWT.KeyDown;
1747                 keyEvent.keyCode = lastKeyCode;
1748                 keyEvent.character = (char)lastCharCode;
1749                 keyEvent.stateMask = mask;
1750                 if (!sendKeyEvent(keyEvent)) {
1751                         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_RETURNVALUE });
1752                         dispIdMember = rgdispid[0];
1753                         Variant pVarFalse = new Variant(false);
1754                         event.setProperty(dispIdMember, pVarFalse);
1755                         pVarFalse.dispose();
1756                 }
1757
1758                 event.dispose();
1759                 return;
1760         }
1761
1762         if (eventType.equals(EVENT_KEYUP)) {
1763                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_KEYCODE });
1764                 dispIdMember = rgdispid[0];
1765                 pVarResult = event.getProperty(dispIdMember);
1766                 int keyCode = translateKey (pVarResult.getInt());
1767                 pVarResult.dispose();
1768
1769                 /*
1770                 * if a key code could not be determined for this key then it's a
1771                 * key for which key events are not sent (eg.- the Windows key)
1772                 */
1773                 if (keyCode == 0) {
1774                         lastKeyCode = lastCharCode = 0;
1775                         event.dispose();
1776                         return;
1777                 }
1778
1779                 if (keyCode != lastKeyCode) {
1780                         /* keyup does not correspond to the last keydown */
1781                         lastKeyCode = keyCode;
1782                         lastCharCode = 0;
1783                 }
1784
1785                 int mask = 0;
1786                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
1787                 dispIdMember = rgdispid[0];
1788                 pVarResult = event.getProperty(dispIdMember);
1789                 if (pVarResult.getBoolean()) mask |= SWT.CTRL;
1790                 pVarResult.dispose();
1791
1792                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
1793                 dispIdMember = rgdispid[0];
1794                 pVarResult = event.getProperty(dispIdMember);
1795                 if (pVarResult.getBoolean()) mask |= SWT.ALT;
1796                 pVarResult.dispose();
1797
1798                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
1799                 dispIdMember = rgdispid[0];
1800                 pVarResult = event.getProperty(dispIdMember);
1801                 if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
1802                 pVarResult.dispose();
1803
1804                 Event keyEvent = new Event ();
1805                 keyEvent.widget = browser;
1806                 keyEvent.type = SWT.KeyUp;
1807                 keyEvent.keyCode = lastKeyCode;
1808                 keyEvent.character = (char)lastCharCode;
1809                 keyEvent.stateMask = mask;
1810                 switch (lastKeyCode) {
1811                         case SWT.SHIFT:
1812                         case SWT.CONTROL:
1813                         case SWT.ALT:
1814                         case SWT.COMMAND: {
1815                                 keyEvent.stateMask |= lastKeyCode;
1816                         }
1817                 }
1818                 browser.notifyListeners (keyEvent.type, keyEvent);
1819                 if (!keyEvent.doit) {
1820                         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_RETURNVALUE });
1821                         dispIdMember = rgdispid[0];
1822                         Variant pVarFalse = new Variant(false);
1823                         event.setProperty(dispIdMember, pVarFalse);
1824                         pVarFalse.dispose();
1825                 }
1826
1827                 lastKeyCode = lastCharCode = 0;
1828                 event.dispose();
1829                 return;
1830         }
1831
1832         /*
1833          * Feature in IE. MouseOver/MouseOut events are fired any time the mouse enters
1834          * or exits any element within the Browser.  To ensure that SWT events are only
1835          * fired for mouse movements into or out of the Browser, do not fire an event if
1836          * the element being exited (on MouseOver) or entered (on MouseExit) is within
1837          * the Browser.
1838          */
1839         if (eventType.equals(EVENT_MOUSEOVER)) {
1840                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_FROMELEMENT });
1841                 dispIdMember = rgdispid[0];
1842                 pVarResult = event.getProperty(dispIdMember);
1843                 boolean isInternal = pVarResult.getType() != COM.VT_EMPTY;
1844                 pVarResult.dispose();
1845                 if (isInternal) {
1846                         event.dispose();
1847                         return;
1848                 }
1849         }
1850         if (eventType.equals(EVENT_MOUSEOUT)) {
1851                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_TOELEMENT });
1852                 dispIdMember = rgdispid[0];
1853                 pVarResult = event.getProperty(dispIdMember);
1854                 boolean isInternal = pVarResult.getType() != COM.VT_EMPTY;
1855                 pVarResult.dispose();
1856                 if (isInternal) {
1857                         event.dispose();
1858                         return;
1859                 }
1860         }
1861
1862         int mask = 0;
1863         Event newEvent = new Event();
1864         newEvent.widget = browser;
1865
1866         /*
1867          * The position of mouse events is received in screen-relative coordinates
1868          * in order to handle pages with frames, since frames express their event
1869          * coordinates relative to themselves rather than relative to their top-
1870          * level page.  Convert screen-relative coordinates to be browser-relative.
1871          */
1872         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SCREENX });
1873         dispIdMember = rgdispid[0];
1874         pVarResult = event.getProperty(dispIdMember);
1875         int screenX = pVarResult.getInt();
1876         pVarResult.dispose();
1877
1878         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SCREENY });
1879         dispIdMember = rgdispid[0];
1880         pVarResult = event.getProperty(dispIdMember);
1881         int screenY = pVarResult.getInt();
1882         pVarResult.dispose();
1883
1884         Point position = DPIUtil.autoScaleDown(new Point(screenX, screenY)); // To Points
1885         position = browser.getDisplay().map(null, browser, position);
1886         newEvent.x = position.x; newEvent.y = position.y;
1887
1888         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
1889         dispIdMember = rgdispid[0];
1890         pVarResult = event.getProperty(dispIdMember);
1891         if (pVarResult.getBoolean()) mask |= SWT.CTRL;
1892         pVarResult.dispose();
1893
1894         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
1895         dispIdMember = rgdispid[0];
1896         pVarResult = event.getProperty(dispIdMember);
1897         if (pVarResult.getBoolean()) mask |= SWT.ALT;
1898         pVarResult.dispose();
1899
1900         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
1901         dispIdMember = rgdispid[0];
1902         pVarResult = event.getProperty(dispIdMember);
1903         if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
1904         pVarResult.dispose();
1905
1906         newEvent.stateMask = mask;
1907
1908         rgdispid = event.getIDsOfNames(new String[] { PROPERTY_BUTTON });
1909         dispIdMember = rgdispid[0];
1910         pVarResult = event.getProperty(dispIdMember);
1911         int button = pVarResult.getInt();
1912         pVarResult.dispose();
1913         switch (button) {
1914                 case 1: button = 1; break;
1915                 case 2: button = 3; break;
1916                 case 4: button = 2; break;
1917         }
1918
1919         if (eventType.equals(EVENT_MOUSEDOWN)) {
1920                 newEvent.type = SWT.MouseDown;
1921                 newEvent.button = button;
1922                 newEvent.count = 1;
1923         } else if (eventType.equals(EVENT_MOUSEUP) || eventType.equals(EVENT_DRAGEND)) {
1924                 newEvent.type = SWT.MouseUp;
1925                 newEvent.button = button != 0 ? button : 1;     /* button assumed to be 1 for dragends */
1926                 newEvent.count = 1;
1927                 switch (newEvent.button) {
1928                         case 1: newEvent.stateMask |= SWT.BUTTON1; break;
1929                         case 2: newEvent.stateMask |= SWT.BUTTON2; break;
1930                         case 3: newEvent.stateMask |= SWT.BUTTON3; break;
1931                         case 4: newEvent.stateMask |= SWT.BUTTON4; break;
1932                         case 5: newEvent.stateMask |= SWT.BUTTON5; break;
1933                 }
1934         } else if (eventType.equals(EVENT_MOUSEWHEEL)) {
1935                 newEvent.type = SWT.MouseWheel;
1936                 rgdispid = event.getIDsOfNames(new String[] { PROPERTY_WHEELDELTA });
1937                 dispIdMember = rgdispid[0];
1938                 pVarResult = event.getProperty(dispIdMember);
1939                 newEvent.count = pVarResult.getInt () / 120 * 3;
1940                 pVarResult.dispose();
1941         } else if (eventType.equals(EVENT_MOUSEMOVE)) {
1942                 /*
1943                 * Feature in IE.  Spurious and redundant mousemove events are often received.  The workaround
1944                 * is to not fire MouseMove events whose x and y values match the last MouseMove.
1945                 */
1946                 if (newEvent.x == lastMouseMoveX && newEvent.y == lastMouseMoveY) {
1947                         event.dispose();
1948                         return;
1949                 }
1950                 newEvent.type = SWT.MouseMove;
1951                 lastMouseMoveX = newEvent.x; lastMouseMoveY = newEvent.y;
1952         } else if (eventType.equals(EVENT_MOUSEOVER)) {
1953                 newEvent.type = SWT.MouseEnter;
1954         } else if (eventType.equals(EVENT_MOUSEOUT)) {
1955                 newEvent.type = SWT.MouseExit;
1956         } else if (eventType.equals(EVENT_DRAGSTART)) {
1957                 newEvent.type = SWT.DragDetect;
1958                 newEvent.button = 1;    /* button assumed to be 1 for dragstarts */
1959                 newEvent.stateMask |= SWT.BUTTON1;
1960         }
1961
1962         event.dispose();
1963         browser.notifyListeners(newEvent.type, newEvent);
1964
1965         if (eventType.equals(EVENT_DOUBLECLICK)) {
1966                 newEvent = new Event ();
1967                 newEvent.widget = browser;
1968                 newEvent.type = SWT.MouseDoubleClick;
1969                 newEvent.x = position.x; newEvent.y = position.y;
1970                 newEvent.stateMask = mask;
1971                 newEvent.type = SWT.MouseDoubleClick;
1972                 newEvent.button = 1; /* dblclick only comes for button 1 and does not set the button property */
1973                 newEvent.count = 2;
1974                 browser.notifyListeners (newEvent.type, newEvent);
1975         }
1976 }
1977
1978 void hookDOMListeners(OleAutomation webBrowser, final boolean isTop) {
1979         int[] rgdispid = webBrowser.getIDsOfNames(new String[] { PROPERTY_DOCUMENT });
1980         int dispIdMember = rgdispid[0];
1981         Variant pVarResult = webBrowser.getProperty(dispIdMember);
1982         if (pVarResult == null) return;
1983         if (pVarResult.getType() == COM.VT_EMPTY) {
1984                 pVarResult.dispose();
1985                 return;
1986         }
1987         final OleAutomation document = pVarResult.getAutomation();
1988         pVarResult.dispose();
1989
1990         /*
1991          * In some cases, such as setting the Browser's content from a string,
1992          * NavigateComplete2 is received multiple times for a top-level document.
1993          * For cases like this, any previously-hooked DOM listeners must be
1994          * removed from the document before hooking the new set of listeners,
1995          * otherwise multiple sets of events will be received.
1996          */
1997         unhookDOMListeners (new OleAutomation[] {document});
1998
1999         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN, domListener);
2000         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS, domListener);
2001         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYUP, domListener);
2002         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN, domListener);
2003         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP, domListener);
2004         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEWHEEL, domListener);
2005         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK, domListener);
2006         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE, domListener);
2007         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART, domListener);
2008         site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGEND, domListener);
2009         /* ensure that enter/exit are only fired once, by the top-level document */
2010         if (isTop) {
2011                 site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER, domListener);
2012                 site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT, domListener);
2013         }
2014
2015         OleAutomation[] newDocuments = new OleAutomation[documents.length + 1];
2016         System.arraycopy(documents, 0, newDocuments, 0, documents.length);
2017         newDocuments[documents.length] = document;
2018         documents = newDocuments;
2019 }
2020
2021 void unhookDOMListeners(OleAutomation[] documents) {
2022         char[] buffer = (COM.IIDIHTMLDocumentEvents2 + '\0').toCharArray();
2023         GUID guid = new GUID();
2024         if (COM.IIDFromString(buffer, guid) == COM.S_OK) {
2025                 for (int i = 0; i < documents.length; i++) {
2026                         OleAutomation document = documents[i];
2027                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN, domListener);
2028                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS, domListener);
2029                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYUP, domListener);
2030                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN, domListener);
2031                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP, domListener);
2032                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEWHEEL, domListener);
2033                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK, domListener);
2034                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE, domListener);
2035                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART, domListener);
2036                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGEND, domListener);
2037                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER, domListener);
2038                         site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT, domListener);
2039                 }
2040         }
2041 }
2042 }