diff dwt/browser/Mozilla.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 649b8e223d5a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/browser/Mozilla.d	Sat Aug 09 17:00:02 2008 +0200
@@ -0,0 +1,3254 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.browser.Mozilla;
+
+import dwt.dwthelper.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Vector;
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.graphics.Device;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.internal.C;
+import dwt.internal.Compatibility;
+import dwt.internal.LONG;
+import dwt.internal.Library;
+import dwt.internal.mozilla.GREVersionRange;
+import dwt.internal.mozilla.XPCOM;
+import dwt.internal.mozilla.XPCOMInit;
+import dwt.internal.mozilla.XPCOMObject;
+import dwt.internal.mozilla.nsEmbedString;
+import dwt.internal.mozilla.nsIAppShell;
+import dwt.internal.mozilla.nsIBaseWindow;
+import dwt.internal.mozilla.nsICategoryManager;
+import dwt.internal.mozilla.nsIComponentManager;
+import dwt.internal.mozilla.nsIComponentRegistrar;
+import dwt.internal.mozilla.nsIContextMenuListener;
+import dwt.internal.mozilla.nsICookie;
+import dwt.internal.mozilla.nsICookieManager;
+import dwt.internal.mozilla.nsID;
+import dwt.internal.mozilla.nsIDOMEvent;
+import dwt.internal.mozilla.nsIDOMEventTarget;
+import dwt.internal.mozilla.nsIDOMKeyEvent;
+import dwt.internal.mozilla.nsIDOMMouseEvent;
+import dwt.internal.mozilla.nsIDOMSerializer;
+import dwt.internal.mozilla.nsIDOMSerializer_1_7;
+import dwt.internal.mozilla.nsIDOMWindow;
+import dwt.internal.mozilla.nsIDOMWindowCollection;
+import dwt.internal.mozilla.nsIDirectoryService;
+import dwt.internal.mozilla.nsIDocShell;
+import dwt.internal.mozilla.nsIDocShell_1_8;
+import dwt.internal.mozilla.nsIDocShell_1_9;
+import dwt.internal.mozilla.nsIEmbeddingSiteWindow;
+import dwt.internal.mozilla.nsIFile;
+import dwt.internal.mozilla.nsIIOService;
+import dwt.internal.mozilla.nsIInterfaceRequestor;
+import dwt.internal.mozilla.nsIJSContextStack;
+import dwt.internal.mozilla.nsILocalFile;
+import dwt.internal.mozilla.nsIObserverService;
+import dwt.internal.mozilla.nsIPrefBranch;
+import dwt.internal.mozilla.nsIPrefLocalizedString;
+import dwt.internal.mozilla.nsIPrefService;
+import dwt.internal.mozilla.nsIProperties;
+import dwt.internal.mozilla.nsIServiceManager;
+import dwt.internal.mozilla.nsISimpleEnumerator;
+import dwt.internal.mozilla.nsISupports;
+import dwt.internal.mozilla.nsISupportsWeakReference;
+import dwt.internal.mozilla.nsITooltipListener;
+import dwt.internal.mozilla.nsIURI;
+import dwt.internal.mozilla.nsIURIContentListener;
+import dwt.internal.mozilla.nsIWeakReference;
+import dwt.internal.mozilla.nsIWebBrowser;
+import dwt.internal.mozilla.nsIWebBrowserChrome;
+import dwt.internal.mozilla.nsIWebBrowserChromeFocus;
+import dwt.internal.mozilla.nsIWebBrowserFocus;
+import dwt.internal.mozilla.nsIWebNavigation;
+import dwt.internal.mozilla.nsIWebNavigationInfo;
+import dwt.internal.mozilla.nsIWebProgress;
+import dwt.internal.mozilla.nsIWebProgressListener;
+import dwt.internal.mozilla.nsIWindowWatcher;
+import dwt.layout.FillLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Label;
+import dwt.widgets.Listener;
+import dwt.widgets.Menu;
+import dwt.widgets.Shell;
+
+class Mozilla extends WebBrowser {
+    int /*long*/ embedHandle;
+    nsIWebBrowser webBrowser;
+    Object webBrowserObject;
+    MozillaDelegate delegate;
+
+    /* Interfaces for this Mozilla embedding notification */
+    XPCOMObject supports;
+    XPCOMObject weakReference;
+    XPCOMObject webProgressListener;
+    XPCOMObject webBrowserChrome;
+    XPCOMObject webBrowserChromeFocus;
+    XPCOMObject embeddingSiteWindow;
+    XPCOMObject interfaceRequestor;
+    XPCOMObject supportsWeakReference;
+    XPCOMObject contextMenuListener;    
+    XPCOMObject uriContentListener;
+    XPCOMObject tooltipListener;
+    XPCOMObject domEventListener;
+    int chromeFlags = nsIWebBrowserChrome.CHROME_DEFAULT;
+    int refCount, lastKeyCode, lastCharCode;
+    int /*long*/ request;
+    Point location, size;
+    bool visible, isChild, ignoreDispose, awaitingNavigate;
+    Shell tip = null;
+    Listener listener;
+    Vector unhookedDOMWindows = new Vector ();
+
+    static nsIAppShell AppShell;
+    static AppFileLocProvider LocationProvider;
+    static WindowCreator2 WindowCreator;
+    static int BrowserCount;
+    static bool Initialized, IsPre_1_8, PerformedVersionCheck, XPCOMWasGlued, XPCOMInitWasGlued;
+
+    /* XULRunner detect constants */
+    static final String GRERANGE_LOWER = "1.8.1.2"; //$NON-NLS-1$
+    static final String GRERANGE_LOWER_FALLBACK = "1.8"; //$NON-NLS-1$
+    static final bool LowerRangeInclusive = true;
+    static final String GRERANGE_UPPER = "1.9.*"; //$NON-NLS-1$
+    static final bool UpperRangeInclusive = true;
+
+    static final int MAX_PORT = 65535;
+    static final String SEPARATOR_OS = System.getProperty ("file.separator"); //$NON-NLS-1$
+    static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
+    static final String DISPOSE_LISTENER_HOOKED = "dwt.browser.Mozilla.disposeListenerHooked"; //$NON-NLS-1$
+    static final String PREFIX_JAVASCRIPT = "javascript:"; //$NON-NLS-1$
+    static final String PREFERENCE_CHARSET = "intl.charset.default"; //$NON-NLS-1$
+    static final String PREFERENCE_DISABLEOPENDURINGLOAD = "dom.disable_open_during_load"; //$NON-NLS-1$
+    static final String PREFERENCE_DISABLEWINDOWSTATUSCHANGE = "dom.disable_window_status_change"; //$NON-NLS-1$
+    static final String PREFERENCE_LANGUAGES = "intl.accept_languages"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYHOST_FTP = "network.proxy.ftp"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYPORT_FTP = "network.proxy.ftp_port"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYHOST_HTTP = "network.proxy.http"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYPORT_HTTP = "network.proxy.http_port"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYHOST_SSL = "network.proxy.ssl"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYPORT_SSL = "network.proxy.ssl_port"; //$NON-NLS-1$
+    static final String PREFERENCE_PROXYTYPE = "network.proxy.type"; //$NON-NLS-1$
+    static final String PROFILE_AFTER_CHANGE = "profile-after-change"; //$NON-NLS-1$
+    static final String PROFILE_BEFORE_CHANGE = "profile-before-change"; //$NON-NLS-1$
+    static final String PROFILE_DIR = SEPARATOR_OS + "eclipse" + SEPARATOR_OS; //$NON-NLS-1$
+    static final String PROFILE_DO_CHANGE = "profile-do-change"; //$NON-NLS-1$
+    static final String PROPERTY_PROXYPORT = "network.proxy_port"; //$NON-NLS-1$
+    static final String PROPERTY_PROXYHOST = "network.proxy_host"; //$NON-NLS-1$
+    static final String SEPARATOR_LOCALE = "-"; //$NON-NLS-1$
+    static final String SHUTDOWN_PERSIST = "shutdown-persist"; //$NON-NLS-1$
+    static final String STARTUP = "startup"; //$NON-NLS-1$
+    static final String TOKENIZER_LOCALE = ","; //$NON-NLS-1$
+    static final String URI_FROMMEMORY = "file:///"; //$NON-NLS-1$
+    static final String XULRUNNER_PATH = "dwt.browser.XULRunnerPath"; //$NON-NLS-1$
+
+    // TEMPORARY CODE
+    static final String GRE_INITIALIZED = "dwt.browser.XULRunnerInitialized"; //$NON-NLS-1$
+
+    static {
+        MozillaClearSessions = new Runnable () {
+            public void run () {
+                if (!Initialized) return;
+                int /*long*/[] result = new int /*long*/[1];
+                int rc = XPCOM.NS_GetServiceManager (result);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+                nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
+                result[0] = 0;
+                byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_COOKIEMANAGER_CONTRACTID, true);
+                rc = serviceManager.GetServiceByContractID (aContractID, nsICookieManager.NS_ICOOKIEMANAGER_IID, result);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+                serviceManager.Release ();
+
+                nsICookieManager manager = new nsICookieManager (result[0]);
+                result[0] = 0;
+                rc = manager.GetEnumerator (result);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                manager.Release ();
+
+                nsISimpleEnumerator enumerator = new nsISimpleEnumerator (result[0]);
+                int[] moreElements = new int[1]; /* PRBool */
+                rc = enumerator.HasMoreElements (moreElements);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                while (moreElements[0] !is 0) {
+                    result[0] = 0;
+                    rc = enumerator.GetNext (result);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                    nsICookie cookie = new nsICookie (result[0]);
+                    long[] expires = new long[1];
+                    rc = cookie.GetExpires (expires);
+                    if (expires[0] is 0) {
+                        /* indicates a session cookie */
+                        int /*long*/ domain = XPCOM.nsEmbedCString_new ();
+                        int /*long*/ name = XPCOM.nsEmbedCString_new ();
+                        int /*long*/ path = XPCOM.nsEmbedCString_new ();
+                        cookie.GetHost (domain);
+                        cookie.GetName (name);
+                        cookie.GetPath (path);
+                        rc = manager.Remove (domain, name, path, 0);
+                        XPCOM.nsEmbedCString_delete (domain);
+                        XPCOM.nsEmbedCString_delete (name);
+                        XPCOM.nsEmbedCString_delete (path);
+                        if (rc !is XPCOM.NS_OK) error (rc);
+                    }
+                    cookie.Release ();
+                    rc = enumerator.HasMoreElements (moreElements);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                }
+                enumerator.Release ();
+            }
+        };
+    }
+
+public void create (Composite parent, int style) {
+    delegate = new MozillaDelegate (browser);
+    Display display = parent.getDisplay ();
+
+    int /*long*/[] result = new int /*long*/[1];
+    if (!Initialized) {
+        bool initLoaded = false;
+        bool IsXULRunner = false;
+
+        String greInitialized = System.getProperty (GRE_INITIALIZED); 
+        if ("true".equals (greInitialized)) { //$NON-NLS-1$
+            /* 
+             * Another browser has already initialized xulrunner in this process,
+             * so just bind to it instead of trying to initialize a new one.
+             */
+            Initialized = true;
+        }
+
+        String mozillaPath = System.getProperty (XULRUNNER_PATH);
+        /*
+        * Browser clients that ship XULRunner in a plug-in must have an opportunity 
+        * to set the dwt.browser.XULRunnerPath system property to point
+        * at their XULRunner before the first Mozilla-based Browser is created.  To
+        * facilitate this, reflection is used to reference non-existent class
+        * dwt.browser.XULRunnerInitializer the first time a Mozilla-
+        * based Browser is created.   A client wishing to use this hook can do so
+        * by creating a fragment of dwt that implements this class and
+        * sets the system property in its static initializer.
+        */
+        if (mozillaPath is null) {
+            try {
+                Class.forName ("dwt.browser.XULRunnerInitializer"); //$NON-NLS-1$
+                mozillaPath = System.getProperty (XULRUNNER_PATH);
+            } catch (ClassNotFoundException e) {
+                /* no fragment is providing this class, which is the typical case */
+            }
+        }
+
+        if (mozillaPath is null) {
+            try {
+                String libName = delegate.getSWTInitLibraryName ();
+                Library.loadLibrary (libName);
+                initLoaded = true;
+            } catch (UnsatisfiedLinkError e) {
+                /* 
+                * If this library failed to load then do not attempt to detect a
+                * xulrunner to use.  The Browser may still be usable if MOZILLA_FIVE_HOME
+                * points at a GRE. 
+                */
+            }
+        } else {
+            mozillaPath += SEPARATOR_OS + delegate.getLibraryName ();
+            IsXULRunner = true;
+        }
+
+        if (initLoaded) {
+            /* attempt to discover a XULRunner to use as the GRE */
+            GREVersionRange range = new GREVersionRange ();
+            byte[] bytes = MozillaDelegate.wcsToMbcs (null, GRERANGE_LOWER, true);
+            int /*long*/ lower = C.malloc (bytes.length);
+            C.memmove (lower, bytes, bytes.length);
+            range.lower = lower;
+            range.lowerInclusive = LowerRangeInclusive;
+
+            bytes = MozillaDelegate.wcsToMbcs (null, GRERANGE_UPPER, true);
+            int /*long*/ upper = C.malloc (bytes.length);
+            C.memmove (upper, bytes, bytes.length);
+            range.upper = upper;
+            range.upperInclusive = UpperRangeInclusive;
+
+            int length = XPCOMInit.PATH_MAX;
+            int /*long*/ greBuffer = C.malloc (length);
+            int /*long*/ propertiesPtr = C.malloc (2 * C.PTR_SIZEOF);
+            int rc = XPCOMInit.GRE_GetGREPathWithProperties (range, 1, propertiesPtr, 0, greBuffer, length);
+
+            /*
+             * A XULRunner was not found that supports wrapping of XPCOM handles as JavaXPCOM objects.
+             * Drop the lower version bound and try to detect an earlier XULRunner installation.
+             */
+            if (rc !is XPCOM.NS_OK) {
+                C.free (lower);
+                bytes = MozillaDelegate.wcsToMbcs (null, GRERANGE_LOWER_FALLBACK, true);
+                lower = C.malloc (bytes.length);
+                C.memmove (lower, bytes, bytes.length);
+                range.lower = lower;
+                rc = XPCOMInit.GRE_GetGREPathWithProperties (range, 1, propertiesPtr, 0, greBuffer, length);
+            }
+
+            C.free (lower);
+            C.free (upper);
+            C.free (propertiesPtr);
+            if (rc is XPCOM.NS_OK) {
+                /* indicates that a XULRunner was found */
+                length = C.strlen (greBuffer);
+                bytes = new byte[length];
+                C.memmove (bytes, greBuffer, length);
+                mozillaPath = new String (MozillaDelegate.mbcsToWcs (null, bytes));
+                IsXULRunner = mozillaPath.length () > 0;
+
+                /*
+                 * Test whether the detected XULRunner can be used as the GRE before loading swt's
+                 * XULRunner library.  If it cannot be used then fall back to attempting to use
+                 * the GRE pointed to by MOZILLA_FIVE_HOME.
+                 * 
+                 * One case where this will fail is attempting to use a 64-bit xulrunner while swt
+                 * is running in 32-bit mode, or vice versa.
+                 */
+                if (IsXULRunner) {
+                    byte[] path = MozillaDelegate.wcsToMbcs (null, mozillaPath, true);
+                    rc = XPCOMInit.XPCOMGlueStartup (path);
+                    if (rc !is XPCOM.NS_OK) {
+                        IsXULRunner = false;    /* failed */
+                        mozillaPath = mozillaPath.substring (0, mozillaPath.lastIndexOf (SEPARATOR_OS));
+                        if (Device.DEBUG) System.out.println ("cannot use detected XULRunner: " + mozillaPath); //$NON-NLS-1$
+                    } else {
+                        XPCOMInitWasGlued = true;
+                    }
+                }
+            }
+            C.free (greBuffer);
+        }
+
+        if (IsXULRunner) {
+            if (Device.DEBUG) System.out.println ("XULRunner path: " + mozillaPath); //$NON-NLS-1$
+            try {
+                Library.loadLibrary ("swt-xulrunner"); //$NON-NLS-1$
+            } catch (UnsatisfiedLinkError e) {
+                DWT.error (DWT.ERROR_NO_HANDLES, e);
+            }
+            byte[] path = MozillaDelegate.wcsToMbcs (null, mozillaPath, true);
+            int rc = XPCOM.XPCOMGlueStartup (path);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            XPCOMWasGlued = true;
+
+            /*
+             * Remove the trailing xpcom lib name from mozillaPath because the
+             * Mozilla.initialize and NS_InitXPCOM2 invocations require a directory name only.
+             */ 
+            mozillaPath = mozillaPath.substring (0, mozillaPath.lastIndexOf (SEPARATOR_OS));
+        } else {
+            if ((style & DWT.MOZILLA) !is 0) {
+                browser.dispose ();
+                String errorString = (mozillaPath !is null && mozillaPath.length () > 0) ?
+                    " [Failed to use detected XULRunner: " + mozillaPath + "]" :
+                    " [Could not detect registered XULRunner to use]";  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                DWT.error (DWT.ERROR_NO_HANDLES, null, errorString);
+            }
+
+            /* attempt to use the GRE pointed at by MOZILLA_FIVE_HOME */
+            int /*long*/ ptr = C.getenv (MozillaDelegate.wcsToMbcs (null, XPCOM.MOZILLA_FIVE_HOME, true));
+            if (ptr !is 0) {
+                int length = C.strlen (ptr);
+                byte[] buffer = new byte[length];
+                C.memmove (buffer, ptr, length);
+                mozillaPath = new String (MozillaDelegate.mbcsToWcs (null, buffer));
+            } else {
+                browser.dispose ();
+                DWT.error (DWT.ERROR_NO_HANDLES, null, " [Unknown Mozilla path (MOZILLA_FIVE_HOME not set)]"); //$NON-NLS-1$
+            }
+            if (Device.DEBUG) System.out.println ("Mozilla path: " + mozillaPath); //$NON-NLS-1$
+
+            /*
+            * Note.  Embedding a Mozilla GTK1.2 causes a crash.  The workaround
+            * is to check the version of GTK used by Mozilla by looking for
+            * the libwidget_gtk.so library used by Mozilla GTK1.2. Mozilla GTK2
+            * uses the libwidget_gtk2.so library.   
+            */
+            if (Compatibility.fileExists (mozillaPath, "components/libwidget_gtk.so")) { //$NON-NLS-1$
+                browser.dispose ();
+                DWT.error (DWT.ERROR_NO_HANDLES, null, " [Mozilla GTK2 required (GTK1.2 detected)]"); //$NON-NLS-1$                         
+            }
+
+            try {
+                Library.loadLibrary ("swt-mozilla"); //$NON-NLS-1$
+            } catch (UnsatisfiedLinkError e) {
+                try {
+                    /* 
+                     * The initial loadLibrary attempt may have failed as a result of the user's
+                     * system not having libstdc++.so.6 installed, so try to load the alternate
+                     * swt mozilla library that depends on libswtc++.so.5 instead.
+                     */
+                    Library.loadLibrary ("swt-mozilla-gcc3"); //$NON-NLS-1$
+                } catch (UnsatisfiedLinkError ex) {
+                    browser.dispose ();
+                    /*
+                     * Print the error from the first failed attempt since at this point it's
+                     * known that the failure was not due to the libstdc++.so.6 dependency.
+                     */
+                    DWT.error (DWT.ERROR_NO_HANDLES, e, " [MOZILLA_FIVE_HOME='" + mozillaPath + "']"); //$NON-NLS-1$ //$NON-NLS-2$
+                }
+            }
+        }
+
+        if (!Initialized) {
+            int /*long*/[] retVal = new int /*long*/[1];
+            nsEmbedString pathString = new nsEmbedString (mozillaPath);
+            int rc = XPCOM.NS_NewLocalFile (pathString.getAddress (), 1, retVal);
+            pathString.dispose ();
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (retVal[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_ERROR_NULL_POINTER);
+            }
+
+            LocationProvider = new AppFileLocProvider (mozillaPath);
+            LocationProvider.AddRef ();
+
+            nsIFile localFile = new nsILocalFile (retVal[0]);
+            rc = XPCOM.NS_InitXPCOM2 (0, localFile.getAddress(), LocationProvider.getAddress ());
+            localFile.Release ();
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                DWT.error (DWT.ERROR_NO_HANDLES, null, " [MOZILLA_FIVE_HOME may not point at an embeddable GRE] [NS_InitEmbedding " + mozillaPath + " error " + rc + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+            }
+            System.setProperty (GRE_INITIALIZED, "true"); //$NON-NLS-1$
+            if (IsXULRunner) {
+                System.setProperty (XULRUNNER_PATH, mozillaPath);
+            }
+        }
+
+        /* If JavaXPCOM is detected then attempt to initialize it with the XULRunner being used */
+        if (IsXULRunner) {
+            try {
+                Class clazz = Class.forName ("org.mozilla.xpcom.Mozilla"); //$NON-NLS-1$
+                Method method = clazz.getMethod ("getInstance", new Class[0]); //$NON-NLS-1$
+                Object mozilla = method.invoke (null, new Object[0]);
+                method = clazz.getMethod ("getComponentManager", new Class[0]); //$NON-NLS-1$
+                try {
+                    method.invoke (mozilla, new Object[0]);
+                } catch (InvocationTargetException e) {
+                    /* indicates that JavaXPCOM has not been initialized yet */
+                    Class fileClass = Class.forName ("java.io.File"); //$NON-NLS-1$
+                    method = clazz.getMethod ("initialize", new Class[] {fileClass}); //$NON-NLS-1$
+                    Constructor constructor = fileClass.getDeclaredConstructor (new Class[] {String.class});
+                    Object argument = constructor.newInstance (new Object[] {mozillaPath});
+                    method.invoke (mozilla, new Object[] {argument});
+                }
+            } catch (ClassNotFoundException e) {
+                /* JavaXPCOM is not on the classpath */
+            } catch (NoSuchMethodException e) {
+                /* the JavaXPCOM on the classpath does not implement initialize() */
+            } catch (IllegalArgumentException e) {
+            } catch (IllegalAccessException e) {
+            } catch (InvocationTargetException e) {
+            } catch (InstantiationException e) {
+            }
+        }
+
+        int rc = XPCOM.NS_GetComponentManager (result);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_NOINTERFACE);
+        }
+        
+        nsIComponentManager componentManager = new nsIComponentManager (result[0]);
+        result[0] = 0;
+        if (delegate.needsSpinup ()) {
+            /* nsIAppShell is discontinued as of xulrunner 1.9, so do not fail if it is not found */
+            rc = componentManager.CreateInstance (XPCOM.NS_APPSHELL_CID, 0, nsIAppShell.NS_IAPPSHELL_IID, result);
+            if (rc !is XPCOM.NS_ERROR_NO_INTERFACE) {
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                if (result[0] is 0) {
+                    browser.dispose ();
+                    error (XPCOM.NS_NOINTERFACE);
+                }
+    
+                AppShell = new nsIAppShell (result[0]);
+                rc = AppShell.Create (0, null);
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                rc = AppShell.Spinup ();
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+            }
+            result[0] = 0;
+        }
+
+        WindowCreator = new WindowCreator2 ();
+        WindowCreator.AddRef ();
+        
+        rc = XPCOM.NS_GetServiceManager (result);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_NOINTERFACE);
+        }
+        
+        nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
+        result[0] = 0;      
+        byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_WINDOWWATCHER_CONTRACTID, true);
+        rc = serviceManager.GetServiceByContractID (aContractID, nsIWindowWatcher.NS_IWINDOWWATCHER_IID, result);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_NOINTERFACE);       
+        }
+
+        nsIWindowWatcher windowWatcher = new nsIWindowWatcher (result[0]);
+        result[0] = 0;
+        rc = windowWatcher.SetWindowCreator (WindowCreator.getAddress());
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        windowWatcher.Release ();
+
+        /* compute the profile directory and set it on the AppFileLocProvider */
+        if (LocationProvider !is null) {
+            byte[] buffer = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_DIRECTORYSERVICE_CONTRACTID, true);
+            rc = serviceManager.GetServiceByContractID (buffer, nsIDirectoryService.NS_IDIRECTORYSERVICE_IID, result);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+
+            nsIDirectoryService directoryService = new nsIDirectoryService (result[0]);
+            result[0] = 0;
+            rc = directoryService.QueryInterface (nsIProperties.NS_IPROPERTIES_IID, result);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+            directoryService.Release ();
+
+            nsIProperties properties = new nsIProperties (result[0]);
+            result[0] = 0;
+            buffer = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_APP_APPLICATION_REGISTRY_DIR, true);
+            rc = properties.Get (buffer, nsIFile.NS_IFILE_IID, result);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+            properties.Release ();
+
+            nsIFile profileDir = new nsIFile (result[0]);
+            result[0] = 0;
+            int /*long*/ path = XPCOM.nsEmbedCString_new ();
+            rc = profileDir.GetNativePath (path);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            int length = XPCOM.nsEmbedCString_Length (path);
+            int /*long*/ ptr = XPCOM.nsEmbedCString_get (path);
+            buffer = new byte [length];
+            XPCOM.memmove (buffer, ptr, length);
+            String profilePath = new String (MozillaDelegate.mbcsToWcs (null, buffer)) + PROFILE_DIR;
+            LocationProvider.setProfilePath (profilePath);
+            LocationProvider.isXULRunner = IsXULRunner;
+            XPCOM.nsEmbedCString_delete (path);
+            profileDir.Release ();
+
+            /* notify observers of a new profile directory being used */
+            buffer = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_OBSERVER_CONTRACTID, true);
+            rc = serviceManager.GetServiceByContractID (buffer, nsIObserverService.NS_IOBSERVERSERVICE_IID, result);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+
+            nsIObserverService observerService = new nsIObserverService (result[0]);
+            result[0] = 0;
+            buffer = MozillaDelegate.wcsToMbcs (null, PROFILE_DO_CHANGE, true);
+            length = STARTUP.length ();
+            char[] chars = new char [length + 1];
+            STARTUP.getChars (0, length, chars, 0);
+            rc = observerService.NotifyObservers (0, buffer, chars);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            buffer = MozillaDelegate.wcsToMbcs (null, PROFILE_AFTER_CHANGE, true);
+            rc = observerService.NotifyObservers (0, buffer, chars);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            observerService.Release ();
+        }
+
+        /*
+         * As a result of using a common profile the user cannot change their locale
+         * and charset.  The fix for this is to set mozilla's locale and charset
+         * preference values according to the user's current locale and charset.
+         */
+        aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_PREFSERVICE_CONTRACTID, true);
+        rc = serviceManager.GetServiceByContractID (aContractID, nsIPrefService.NS_IPREFSERVICE_IID, result);
+        serviceManager.Release ();
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_NOINTERFACE);
+        }
+
+        nsIPrefService prefService = new nsIPrefService (result[0]);
+        result[0] = 0;
+        byte[] buffer = new byte[1];
+        rc = prefService.GetBranch (buffer, result);    /* empty buffer denotes root preference level */
+        prefService.Release ();
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_NOINTERFACE);
+        }
+
+        nsIPrefBranch prefBranch = new nsIPrefBranch (result[0]);
+        result[0] = 0;
+
+        /* get Mozilla's current locale preference value */
+        String prefLocales = null;
+        nsIPrefLocalizedString localizedString = null;
+        buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_LANGUAGES, true);
+        rc = prefBranch.GetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, result);
+        /* 
+         * Feature of Debian.  For some reason attempting to query for the current locale
+         * preference fails on Debian.  The workaround for this is to assume a value of
+         * "en-us,en" since this is typically the default value when mozilla is used without
+         * a profile.
+         */
+        if (rc !is XPCOM.NS_OK) {
+            prefLocales = "en-us,en" + TOKENIZER_LOCALE;    //$NON-NLS-1$
+        } else {
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+            localizedString = new nsIPrefLocalizedString (result[0]);
+            result[0] = 0;
+            rc = localizedString.ToString (result);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+            int length = XPCOM.strlen_PRUnichar (result[0]);
+            char[] dest = new char[length];
+            XPCOM.memmove (dest, result[0], length * 2);
+            prefLocales = new String (dest) + TOKENIZER_LOCALE;
+        }
+        result[0] = 0;
+
+        /*
+         * construct the new locale preference value by prepending the
+         * user's current locale and language to the original value 
+         */
+        Locale locale = Locale.getDefault ();
+        String language = locale.getLanguage ();
+        String country = locale.getCountry ();
+        StringBuffer stringBuffer = new StringBuffer (language);
+        stringBuffer.append (SEPARATOR_LOCALE);
+        stringBuffer.append (country.toLowerCase ());
+        stringBuffer.append (TOKENIZER_LOCALE);
+        stringBuffer.append (language);
+        stringBuffer.append (TOKENIZER_LOCALE);
+        String newLocales = stringBuffer.toString ();
+
+        int start, end = -1;
+        do {
+            start = end + 1;
+            end = prefLocales.indexOf (TOKENIZER_LOCALE, start);
+            String token;
+            if (end is -1) {
+                token = prefLocales.substring (start);
+            } else {
+                token = prefLocales.substring (start, end);
+            }
+            if (token.length () > 0) {
+                token = (token + TOKENIZER_LOCALE).trim ();
+                /* ensure that duplicate locale values are not added */
+                if (newLocales.indexOf (token) is -1) {
+                    stringBuffer.append (token);
+                }
+            }
+        } while (end !is -1);
+        newLocales = stringBuffer.toString ();
+        if (!newLocales.equals (prefLocales)) {
+            /* write the new locale value */
+            newLocales = newLocales.substring (0, newLocales.length () - TOKENIZER_LOCALE.length ()); /* remove trailing tokenizer */
+            int length = newLocales.length ();
+            char[] charBuffer = new char[length + 1];
+            newLocales.getChars (0, length, charBuffer, 0);
+            if (localizedString is null) {
+                byte[] contractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_PREFLOCALIZEDSTRING_CONTRACTID, true);
+                rc = componentManager.CreateInstanceByContractID (contractID, 0, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, result);
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                if (result[0] is 0) {
+                    browser.dispose ();
+                    error (XPCOM.NS_NOINTERFACE);
+                }
+                localizedString = new nsIPrefLocalizedString (result[0]);
+                result[0] = 0;
+            }
+            localizedString.SetDataWithLength (length, charBuffer);
+            rc = prefBranch.SetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, localizedString.getAddress());
+        }
+        if (localizedString !is null) {
+            localizedString.Release ();
+            localizedString = null;
+        }
+
+        /* get Mozilla's current charset preference value */
+        String prefCharset = null;
+        buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_CHARSET, true);
+        rc = prefBranch.GetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, result);
+        /* 
+         * Feature of Debian.  For some reason attempting to query for the current charset
+         * preference fails on Debian.  The workaround for this is to assume a value of
+         * "ISO-8859-1" since this is typically the default value when mozilla is used
+         * without a profile.
+         */
+        if (rc !is XPCOM.NS_OK) {
+            prefCharset = "ISO-8859-1"; //$NON_NLS-1$
+        } else {
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+            localizedString = new nsIPrefLocalizedString (result[0]);
+            result[0] = 0;
+            rc = localizedString.ToString (result);
+            if (rc !is XPCOM.NS_OK) {
+                browser.dispose ();
+                error (rc);
+            }
+            if (result[0] is 0) {
+                browser.dispose ();
+                error (XPCOM.NS_NOINTERFACE);
+            }
+            int length = XPCOM.strlen_PRUnichar (result[0]);
+            char[] dest = new char[length];
+            XPCOM.memmove (dest, result[0], length * 2);
+            prefCharset = new String (dest);
+        }
+        result[0] = 0;
+
+        String newCharset = System.getProperty ("file.encoding");   // $NON-NLS-1$
+        if (!newCharset.equals (prefCharset)) {
+            /* write the new charset value */
+            int length = newCharset.length ();
+            char[] charBuffer = new char[length + 1];
+            newCharset.getChars (0, length, charBuffer, 0);
+            if (localizedString is null) {
+                byte[] contractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_PREFLOCALIZEDSTRING_CONTRACTID, true);
+                rc = componentManager.CreateInstanceByContractID (contractID, 0, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, result);
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                if (result[0] is 0) {
+                    browser.dispose ();
+                    error (XPCOM.NS_NOINTERFACE);
+                }
+                localizedString = new nsIPrefLocalizedString (result[0]);
+                result[0] = 0;
+            }
+            localizedString.SetDataWithLength (length, charBuffer);
+            rc = prefBranch.SetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, localizedString.getAddress ());
+        }
+        if (localizedString !is null) localizedString.Release ();
+
+        /*
+        * Check for proxy values set as documented java properties and update mozilla's
+        * preferences with these values if needed.
+        */
+        String proxyHost = System.getProperty (PROPERTY_PROXYHOST);
+        String proxyPortString = System.getProperty (PROPERTY_PROXYPORT);
+
+        int port = -1;
+        if (proxyPortString !is null) {
+            try {
+                int value = Integer.valueOf (proxyPortString).intValue ();
+                if (0 <= value && value <= MAX_PORT) port = value;
+            } catch (NumberFormatException e) {
+                /* do nothing, java property has non-integer value */
+            }
+        }
+
+        if (proxyHost !is null) {
+            byte[] contractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_PREFLOCALIZEDSTRING_CONTRACTID, true);
+            rc = componentManager.CreateInstanceByContractID (contractID, 0, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+            localizedString = new nsIPrefLocalizedString (result[0]);
+            result[0] = 0;
+            int length = proxyHost.length ();
+            char[] charBuffer = new char[length + 1];
+            proxyHost.getChars (0, length, charBuffer, 0);
+            rc = localizedString.SetDataWithLength (length, charBuffer);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYHOST_FTP, true);
+            rc = prefBranch.SetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, localizedString.getAddress ());
+            if (rc !is XPCOM.NS_OK) error (rc);
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYHOST_HTTP, true);
+            rc = prefBranch.SetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, localizedString.getAddress ());
+            if (rc !is XPCOM.NS_OK) error (rc);
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYHOST_SSL, true);
+            rc = prefBranch.SetComplexValue (buffer, nsIPrefLocalizedString.NS_IPREFLOCALIZEDSTRING_IID, localizedString.getAddress ());
+            if (rc !is XPCOM.NS_OK) error (rc);
+            localizedString.Release ();
+        }
+
+        if (port !is -1) {
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYPORT_FTP, true);
+            rc = prefBranch.SetIntPref (buffer, port);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYPORT_HTTP, true);
+            rc = prefBranch.SetIntPref (buffer, port);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYPORT_SSL, true);
+            rc = prefBranch.SetIntPref (buffer, port);
+            if (rc !is XPCOM.NS_OK) error (rc);
+        }
+
+        if (proxyHost !is null || port !is -1) {
+            buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_PROXYTYPE, true);
+            rc = prefBranch.SetIntPref (buffer, 1);
+            if (rc !is XPCOM.NS_OK) error (rc);
+        }
+
+        /*
+        * Ensure that windows that are shown during page loads are not blocked.  Firefox may
+        * try to block these by default since such windows are often unwelcome, but this
+        * assumption should not be made in the Browser's context.  Since the Browser client
+        * is responsible for creating the new Browser and Shell in an OpenWindowListener,
+        * they should decide whether the new window is unwelcome or not and act accordingly. 
+        */
+        buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_DISABLEOPENDURINGLOAD, true);
+        rc = prefBranch.SetBoolPref (buffer, 0);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+
+        /* Ensure that the status text can be set through means like javascript */ 
+        buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_DISABLEWINDOWSTATUSCHANGE, true);
+        rc = prefBranch.SetBoolPref (buffer, 0);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+
+        prefBranch.Release ();
+
+        PromptService2Factory factory = new PromptService2Factory ();
+        factory.AddRef ();
+
+        rc = componentManager.QueryInterface (nsIComponentRegistrar.NS_ICOMPONENTREGISTRAR_IID, result);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_NOINTERFACE);
+        }
+        
+        nsIComponentRegistrar componentRegistrar = new nsIComponentRegistrar (result[0]);
+        result[0] = 0;
+        aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_PROMPTSERVICE_CONTRACTID, true); 
+        byte[] aClassName = MozillaDelegate.wcsToMbcs (null, "Prompt Service", true); //$NON-NLS-1$
+        rc = componentRegistrar.RegisterFactory (XPCOM.NS_PROMPTSERVICE_CID, aClassName, aContractID, factory.getAddress ());
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        factory.Release ();
+        
+        HelperAppLauncherDialogFactory dialogFactory = new HelperAppLauncherDialogFactory ();
+        dialogFactory.AddRef ();
+        aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_HELPERAPPLAUNCHERDIALOG_CONTRACTID, true);
+        aClassName = MozillaDelegate.wcsToMbcs (null, "Helper App Launcher Dialog", true); //$NON-NLS-1$
+        rc = componentRegistrar.RegisterFactory (XPCOM.NS_HELPERAPPLAUNCHERDIALOG_CID, aClassName, aContractID, dialogFactory.getAddress ());
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        dialogFactory.Release ();
+
+        /*
+        * This Download factory will be used if the GRE version is < 1.8.
+        * If the GRE version is 1.8.x then the Download factory that is registered later for
+        *   contract "Transfer" will be used.
+        * If the GRE version is >= 1.9 then no Download factory is registered because this
+        *   functionality is provided by the GRE.
+        */
+        DownloadFactory downloadFactory = new DownloadFactory ();
+        downloadFactory.AddRef ();
+        aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_DOWNLOAD_CONTRACTID, true);
+        aClassName = MozillaDelegate.wcsToMbcs (null, "Download", true); //$NON-NLS-1$
+        rc = componentRegistrar.RegisterFactory (XPCOM.NS_DOWNLOAD_CID, aClassName, aContractID, downloadFactory.getAddress ());
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        downloadFactory.Release ();
+
+        FilePickerFactory pickerFactory = IsXULRunner ? new FilePickerFactory_1_8 () : new FilePickerFactory ();
+        pickerFactory.AddRef ();
+        aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_FILEPICKER_CONTRACTID, true);
+        aClassName = MozillaDelegate.wcsToMbcs (null, "FilePicker", true); //$NON-NLS-1$
+        rc = componentRegistrar.RegisterFactory (XPCOM.NS_FILEPICKER_CID, aClassName, aContractID, pickerFactory.getAddress ());
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (rc);
+        }
+        pickerFactory.Release ();
+
+        componentRegistrar.Release ();
+        componentManager.Release ();
+
+        Initialized = true;
+    }
+
+    if (display.getData (DISPOSE_LISTENER_HOOKED) is null) {
+        display.setData (DISPOSE_LISTENER_HOOKED, DISPOSE_LISTENER_HOOKED);
+        display.addListener (DWT.Dispose, new Listener () {
+            public void handleEvent (Event event) {
+                if (BrowserCount > 0) return; /* another display is still active */
+
+                int /*long*/[] result = new int /*long*/[1];
+                int rc = XPCOM.NS_GetServiceManager (result);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+                nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
+                result[0] = 0;      
+                byte[] buffer = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_OBSERVER_CONTRACTID, true);
+                rc = serviceManager.GetServiceByContractID (buffer, nsIObserverService.NS_IOBSERVERSERVICE_IID, result);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+                nsIObserverService observerService = new nsIObserverService (result[0]);
+                result[0] = 0;
+                buffer = MozillaDelegate.wcsToMbcs (null, PROFILE_BEFORE_CHANGE, true);
+                int length = SHUTDOWN_PERSIST.length ();
+                char[] chars = new char [length + 1];
+                SHUTDOWN_PERSIST.getChars (0, length, chars, 0);
+                rc = observerService.NotifyObservers (0, buffer, chars);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                observerService.Release ();
+
+                if (LocationProvider !is null) {
+                    String prefsLocation = LocationProvider.profilePath + AppFileLocProvider.PREFERENCES_FILE;
+                    nsEmbedString pathString = new nsEmbedString (prefsLocation);
+                    rc = XPCOM.NS_NewLocalFile (pathString.getAddress (), 1, result);
+                    if (rc !is XPCOM.NS_OK) Mozilla.error (rc);
+                    if (result[0] is 0) Mozilla.error (XPCOM.NS_ERROR_NULL_POINTER);
+                    pathString.dispose ();
+
+                    nsILocalFile localFile = new nsILocalFile (result [0]);
+                    result[0] = 0;
+                    rc = localFile.QueryInterface (nsIFile.NS_IFILE_IID, result); 
+                    if (rc !is XPCOM.NS_OK) Mozilla.error (rc);
+                    if (result[0] is 0) Mozilla.error (XPCOM.NS_ERROR_NO_INTERFACE);
+                    localFile.Release ();
+
+                    nsIFile prefFile = new nsIFile (result[0]);
+                    result[0] = 0;
+
+                    buffer = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_PREFSERVICE_CONTRACTID, true);
+                    rc = serviceManager.GetServiceByContractID (buffer, nsIPrefService.NS_IPREFSERVICE_IID, result);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+                    nsIPrefService prefService = new nsIPrefService (result[0]);
+                    result[0] = 0;
+                    rc = prefService.SavePrefFile(prefFile.getAddress ());
+                    prefService.Release ();
+                    prefFile.Release ();
+                }
+                serviceManager.Release ();
+
+                if (XPCOMWasGlued) {
+                    XPCOM.XPCOMGlueShutdown ();
+                    XPCOMWasGlued = false;
+                }
+                if (XPCOMInitWasGlued) {
+                    XPCOMInit.XPCOMGlueShutdown ();
+                    XPCOMInitWasGlued = false;
+                }
+                Initialized = false;
+            }
+        });
+    }
+
+    BrowserCount++;
+    int rc = XPCOM.NS_GetComponentManager (result);
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (rc);
+    }
+    if (result[0] is 0) {
+        browser.dispose ();
+        error (XPCOM.NS_NOINTERFACE);
+    }
+    
+    nsIComponentManager componentManager = new nsIComponentManager (result[0]);
+    result[0] = 0;
+    nsID NS_IWEBBROWSER_CID = new nsID ("F1EAC761-87E9-11d3-AF80-00A024FFC08C"); //$NON-NLS-1$
+    rc = componentManager.CreateInstance (NS_IWEBBROWSER_CID, 0, nsIWebBrowser.NS_IWEBBROWSER_IID, result);
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (rc);
+    }
+    if (result[0] is 0) {
+        browser.dispose ();
+        error (XPCOM.NS_NOINTERFACE);   
+    }
+    
+    webBrowser = new nsIWebBrowser (result[0]);
+    result[0] = 0;
+
+    createCOMInterfaces ();
+    AddRef ();
+
+    rc = webBrowser.SetContainerWindow (webBrowserChrome.getAddress());
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (rc);
+    }
+            
+    rc = webBrowser.QueryInterface (nsIBaseWindow.NS_IBASEWINDOW_IID, result);
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (rc);
+    }
+    if (result[0] is 0) {
+        browser.dispose ();
+        error (XPCOM.NS_ERROR_NO_INTERFACE);
+    }
+    
+    nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
+    result[0] = 0;
+    Rectangle rect = browser.getClientArea ();
+    if (rect.isEmpty ()) {
+        rect.width = 1;
+        rect.height = 1;
+    }
+
+    embedHandle = delegate.getHandle ();
+
+    rc = baseWindow.InitWindow (embedHandle, 0, 0, 0, rect.width, rect.height);
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (XPCOM.NS_ERROR_FAILURE);
+    }
+    rc = baseWindow.Create ();
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (XPCOM.NS_ERROR_FAILURE);
+    }
+    rc = baseWindow.SetVisibility (1);
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (XPCOM.NS_ERROR_FAILURE);
+    }
+    baseWindow.Release ();
+
+    if (!PerformedVersionCheck) {
+        PerformedVersionCheck = true;
+
+        /*
+        * Check for the availability of the pre-1.8 implementation of nsIDocShell
+        * to determine if the GRE's version is < 1.8.
+        */
+        rc = webBrowser.QueryInterface (nsIInterfaceRequestor.NS_IINTERFACEREQUESTOR_IID, result);
+        if (rc !is XPCOM.NS_OK) {
+            browser.dispose ();
+            error (XPCOM.NS_ERROR_FAILURE);
+        }
+        if (result[0] is 0) {
+            browser.dispose ();
+            error (XPCOM.NS_ERROR_NO_INTERFACE);
+        }
+        nsIInterfaceRequestor interfaceRequestor = new nsIInterfaceRequestor (result[0]);
+        result[0] = 0;
+
+        rc = interfaceRequestor.GetInterface (nsIDocShell.NS_IDOCSHELL_IID, result);
+        if (rc is XPCOM.NS_OK && result[0] !is 0) {
+            IsPre_1_8 = true;
+            new nsISupports (result[0]).Release ();
+        }
+        result[0] = 0;
+
+        /*
+        * A Download factory for contract "Transfer" must be registered iff the GRE's version is 1.8.x.
+        *   Check for the availability of the 1.8 implementation of nsIDocShell to determine if the
+        *   GRE's version is 1.8.x.
+        * If the GRE version is < 1.8 then the previously-registered Download factory for contract
+        *   "Download" will be used.
+        * If the GRE version is >= 1.9 then no Download factory is registered because this
+        *   functionality is provided by the GRE.
+        */
+        if (!IsPre_1_8) {
+            rc = interfaceRequestor.GetInterface (nsIDocShell_1_8.NS_IDOCSHELL_IID, result);
+            if (rc is XPCOM.NS_OK && result[0] !is 0) { /* 1.8 */
+                new nsISupports (result[0]).Release ();
+                result[0] = 0;
+                rc = componentManager.QueryInterface (nsIComponentRegistrar.NS_ICOMPONENTREGISTRAR_IID, result);
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                if (result[0] is 0) {
+                    browser.dispose ();
+                    error (XPCOM.NS_NOINTERFACE);
+                }
+
+                nsIComponentRegistrar componentRegistrar = new nsIComponentRegistrar (result[0]);
+                DownloadFactory_1_8 downloadFactory_1_8 = new DownloadFactory_1_8 ();
+                downloadFactory_1_8.AddRef ();
+                byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_TRANSFER_CONTRACTID, true);
+                byte[] aClassName = MozillaDelegate.wcsToMbcs (null, "Transfer", true); //$NON-NLS-1$
+                rc = componentRegistrar.RegisterFactory (XPCOM.NS_DOWNLOAD_CID, aClassName, aContractID, downloadFactory_1_8.getAddress ());
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                downloadFactory_1_8.Release ();
+                componentRegistrar.Release ();
+            } else { /* >= 1.9 */
+                /*
+                 * Bug in XULRunner 1.9.  Mozilla no longer clears its background before initial content has
+                 * been set.  As a result embedders appear broken if they do not immediately navigate to a url.
+                 * The workaround for this is to navigate to about:blank immediately so that the background is
+                 * cleared, but do not fire any corresponding events or allow Browser API calls to reveal this.
+                 * Once the client does a proper navigate with either setUrl() or setText() then resume as
+                 * normal.  The Mozilla bug for this is https://bugzilla.mozilla.org/show_bug.cgi?id=415789.
+                 */
+                awaitingNavigate = true;
+                rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+                if (rc !is XPCOM.NS_OK) {
+                    browser.dispose ();
+                    error (rc);
+                }
+                if (result[0] is 0) {
+                    browser.dispose ();
+                    error (XPCOM.NS_ERROR_NO_INTERFACE);
+                }
+                nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+                char[] uri = new char[ABOUT_BLANK.length () + 1];
+                ABOUT_BLANK.getChars (0, ABOUT_BLANK.length (), uri, 0);
+                rc = webNavigation.LoadURI (uri, nsIWebNavigation.LOAD_FLAGS_NONE, 0, 0, 0);
+                webNavigation.Release ();
+            }
+        }
+        result[0] = 0;
+        interfaceRequestor.Release ();
+    }
+    componentManager.Release ();
+
+    rc = webBrowser.AddWebBrowserListener (weakReference.getAddress (), nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID);
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (rc);
+    }
+
+    rc = webBrowser.SetParentURIContentListener (uriContentListener.getAddress ());
+    if (rc !is XPCOM.NS_OK) {
+        browser.dispose ();
+        error (rc);
+    }
+
+    delegate.init ();
+
+    listener = new Listener () {
+        public void handleEvent (Event event) {
+            switch (event.type) {
+                case DWT.Dispose: {
+                    /* make this handler run after other dispose listeners */
+                    if (ignoreDispose) {
+                        ignoreDispose = false;
+                        break;
+                    }
+                    ignoreDispose = true;
+                    browser.notifyListeners (event.type, event);
+                    event.type = DWT.NONE;
+                    onDispose (event.display);
+                    break;
+                }
+                case DWT.Resize: onResize (); break;
+                case DWT.FocusIn: Activate (); break;
+                case DWT.Activate: Activate (); break;
+                case DWT.Deactivate: {
+                    Display display = event.display;
+                    if (Mozilla.this.browser is display.getFocusControl ()) Deactivate ();
+                    break;
+                }
+                case DWT.Show: {
+                    /*
+                    * Feature in GTK Mozilla.  Mozilla does not show up when
+                    * its container (a GTK fixed handle) is made visible
+                    * after having been hidden.  The workaround is to reset
+                    * its size after the container has been made visible. 
+                    */
+                    Display display = event.display;
+                    display.asyncExec(new Runnable () {
+                        public void run() {
+                            if (browser.isDisposed ()) return;
+                            onResize ();
+                        }
+                    });
+                    break;
+                }
+            }
+        }
+    };  
+    int[] folderEvents = new int[] {
+        DWT.Dispose,
+        DWT.Resize,  
+        DWT.FocusIn,
+        DWT.Activate,
+        DWT.Deactivate,
+        DWT.Show,
+        DWT.KeyDown     // needed to make browser traversable
+    };
+    for (int i = 0; i < folderEvents.length; i++) {
+        browser.addListener (folderEvents[i], listener);
+    }
+}
+
+public bool back () {
+    if (awaitingNavigate) return false;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);          
+    rc = webNavigation.GoBack ();   
+    webNavigation.Release ();
+    return rc is XPCOM.NS_OK;
+}
+
+void createCOMInterfaces () {
+    // Create each of the interfaces that this object implements
+    supports = new XPCOMObject (new int[] {2, 0, 0}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+    };
+    
+    weakReference = new XPCOMObject (new int[] {2, 0, 0, 2}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return QueryReferent (args[0], args[1]);}
+    };
+
+    webProgressListener = new XPCOMObject (new int[] {2, 0, 0, 4, 6, 3, 4, 3}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return OnStateChange (args[0], args[1], (int)/*64*/args[2], (int)/*64*/args[3]);}
+        public int /*long*/ method4 (int /*long*/[] args) {return OnProgressChange (args[0], args[1], (int)/*64*/args[2], (int)/*64*/args[3], (int)/*64*/args[4], (int)/*64*/args[5]);}
+        public int /*long*/ method5 (int /*long*/[] args) {return OnLocationChange (args[0], args[1], args[2]);}
+        public int /*long*/ method6 (int /*long*/[] args) {return OnStatusChange (args[0], args[1], (int)/*64*/args[2], args[3]);}
+        public int /*long*/ method7 (int /*long*/[] args) {return OnSecurityChange (args[0], args[1], (int)/*64*/args[2]);}
+    };
+    
+    webBrowserChrome = new XPCOMObject (new int[] {2, 0, 0, 2, 1, 1, 1, 1, 0, 2, 0, 1, 1}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return SetStatus ((int)/*64*/args[0], args[1]);}
+        public int /*long*/ method4 (int /*long*/[] args) {return GetWebBrowser (args[0]);}
+        public int /*long*/ method5 (int /*long*/[] args) {return SetWebBrowser (args[0]);}
+        public int /*long*/ method6 (int /*long*/[] args) {return GetChromeFlags (args[0]);}
+        public int /*long*/ method7 (int /*long*/[] args) {return SetChromeFlags ((int)/*64*/args[0]);}
+        public int /*long*/ method8 (int /*long*/[] args) {return DestroyBrowserWindow ();}
+        public int /*long*/ method9 (int /*long*/[] args) {return SizeBrowserTo ((int)/*64*/args[0], (int)/*64*/args[1]);}
+        public int /*long*/ method10 (int /*long*/[] args) {return ShowAsModal ();}
+        public int /*long*/ method11 (int /*long*/[] args) {return IsWindowModal (args[0]);}
+        public int /*long*/ method12 (int /*long*/[] args) {return ExitModalEventLoop ((int)/*64*/args[0]);}
+    };
+    
+    webBrowserChromeFocus = new XPCOMObject (new int[] {2, 0, 0, 0, 0}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return FocusNextElement ();}
+        public int /*long*/ method4 (int /*long*/[] args) {return FocusPrevElement ();}
+    };
+        
+    embeddingSiteWindow = new XPCOMObject (new int[] {2, 0, 0, 5, 5, 0, 1, 1, 1, 1, 1}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return SetDimensions ((int)/*64*/args[0], (int)/*64*/args[1], (int)/*64*/args[2], (int)/*64*/args[3], (int)/*64*/args[4]);}
+        public int /*long*/ method4 (int /*long*/[] args) {return GetDimensions ((int)/*64*/args[0], args[1], args[2], args[3], args[4]);}
+        public int /*long*/ method5 (int /*long*/[] args) {return SetFocus ();}
+        public int /*long*/ method6 (int /*long*/[] args) {return GetVisibility (args[0]);}
+        public int /*long*/ method7 (int /*long*/[] args) {return SetVisibility ((int)/*64*/args[0]);}
+        public int /*long*/ method8 (int /*long*/[] args) {return GetTitle (args[0]);}
+        public int /*long*/ method9 (int /*long*/[] args) {return SetTitle (args[0]);}
+        public int /*long*/ method10 (int /*long*/[] args) {return GetSiteWindow (args[0]);}
+    };
+    
+    interfaceRequestor = new XPCOMObject (new int[] {2, 0, 0, 2} ){
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return GetInterface (args[0], args[1]);}
+    };
+        
+    supportsWeakReference = new XPCOMObject (new int[] {2, 0, 0, 1}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return GetWeakReference (args[0]);}
+    };
+    
+    contextMenuListener = new XPCOMObject (new int[] {2, 0, 0, 3}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return OnShowContextMenu ((int)/*64*/args[0], args[1], args[2]);}
+    };
+    
+    uriContentListener = new XPCOMObject (new int[] {2, 0, 0, 2, 5, 3, 4, 1, 1, 1, 1}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return OnStartURIOpen (args[0], args[1]);}
+        public int /*long*/ method4 (int /*long*/[] args) {return DoContent (args[0], (int)/*64*/args[1], args[2], args[3], args[4]);}
+        public int /*long*/ method5 (int /*long*/[] args) {return IsPreferred (args[0], args[1], args[2]);}
+        public int /*long*/ method6 (int /*long*/[] args) {return CanHandleContent (args[0], (int)/*64*/args[1], args[2], args[3]);}
+        public int /*long*/ method7 (int /*long*/[] args) {return GetLoadCookie (args[0]);}
+        public int /*long*/ method8 (int /*long*/[] args) {return SetLoadCookie (args[0]);}
+        public int /*long*/ method9 (int /*long*/[] args) {return GetParentContentListener (args[0]);}
+        public int /*long*/ method10 (int /*long*/[] args) {return SetParentContentListener (args[0]);}     
+    };
+    
+    tooltipListener = new XPCOMObject (new int[] {2, 0, 0, 3, 0}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return OnShowTooltip ((int)/*64*/args[0], (int)/*64*/args[1], args[2]);}
+        public int /*long*/ method4 (int /*long*/[] args) {return OnHideTooltip ();}        
+    };
+
+    domEventListener = new XPCOMObject (new int[] {2, 0, 0, 1}) {
+        public int /*long*/ method0 (int /*long*/[] args) {return QueryInterface (args[0], args[1]);}
+        public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+        public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+        public int /*long*/ method3 (int /*long*/[] args) {return HandleEvent (args[0]);}
+    };
+}
+
+void disposeCOMInterfaces () {
+    if (supports !is null) {
+        supports.dispose ();
+        supports = null;
+    }   
+    if (weakReference !is null) {
+        weakReference.dispose ();
+        weakReference = null;   
+    }
+    if (webProgressListener !is null) {
+        webProgressListener.dispose ();
+        webProgressListener = null;
+    }
+    if (webBrowserChrome !is null) {
+        webBrowserChrome.dispose ();
+        webBrowserChrome = null;
+    }
+    if (webBrowserChromeFocus !is null) {
+        webBrowserChromeFocus.dispose ();
+        webBrowserChromeFocus = null;
+    }
+    if (embeddingSiteWindow !is null) {
+        embeddingSiteWindow.dispose ();
+        embeddingSiteWindow = null;
+    }
+    if (interfaceRequestor !is null) {
+        interfaceRequestor.dispose ();
+        interfaceRequestor = null;
+    }       
+    if (supportsWeakReference !is null) {
+        supportsWeakReference.dispose ();
+        supportsWeakReference = null;
+    }   
+    if (contextMenuListener !is null) {
+        contextMenuListener.dispose ();
+        contextMenuListener = null;
+    }
+    if (uriContentListener !is null) {
+        uriContentListener.dispose ();
+        uriContentListener = null;
+    }
+    if (tooltipListener !is null) {
+        tooltipListener.dispose ();
+        tooltipListener = null;
+    }
+    if (domEventListener !is null) {
+        domEventListener.dispose ();
+        domEventListener = null;
+    }
+}
+
+public bool execute (String script) {
+    if (awaitingNavigate) return false;
+
+    String url = PREFIX_JAVASCRIPT + script + ";void(0);";  //$NON-NLS-1$
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+    char[] arg = url.toCharArray (); 
+    char[] c = new char[arg.length+1];
+    System.arraycopy (arg, 0, c, 0, arg.length);
+    rc = webNavigation.LoadURI (c, nsIWebNavigation.LOAD_FLAGS_NONE, 0, 0, 0);
+    webNavigation.Release ();
+    return rc is XPCOM.NS_OK;
+}
+
+static Browser findBrowser (int /*long*/ handle) {
+    return MozillaDelegate.findBrowser (handle);
+}
+
+public bool forward () {
+    if (awaitingNavigate) return false;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+    rc = webNavigation.GoForward ();
+    webNavigation.Release ();
+
+    return rc is XPCOM.NS_OK;
+}
+
+public String getText () {
+    if (awaitingNavigate) return ""; //$NON-NLS-1$
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.GetContentDOMWindow (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+    nsIDOMWindow window = new nsIDOMWindow (result[0]);
+    result[0] = 0;
+    rc = window.GetDocument (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+    window.Release ();
+
+    int /*long*/ document = result[0];
+    result[0] = 0;
+    rc = XPCOM.NS_GetComponentManager (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+    nsIComponentManager componentManager = new nsIComponentManager (result[0]);
+    result[0] = 0;
+    byte[] contractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_DOMSERIALIZER_CONTRACTID, true);
+    char[] chars = null;
+
+    rc = componentManager.CreateInstanceByContractID (contractID, 0, nsIDOMSerializer_1_7.NS_IDOMSERIALIZER_IID, result);
+    if (rc is XPCOM.NS_OK) {    /* mozilla >= 1.7 */
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+        nsIDOMSerializer_1_7 serializer = new nsIDOMSerializer_1_7 (result[0]);
+        result[0] = 0;
+        int /*long*/ string = XPCOM.nsEmbedString_new ();
+        rc = serializer.SerializeToString (document, string);
+        serializer.Release ();
+
+        int length = XPCOM.nsEmbedString_Length (string);
+        int /*long*/ buffer = XPCOM.nsEmbedString_get (string);
+        chars = new char[length];
+        XPCOM.memmove (chars, buffer, length * 2);
+        XPCOM.nsEmbedString_delete (string);
+    } else {    /* mozilla < 1.7 */
+        rc = componentManager.CreateInstanceByContractID (contractID, 0, nsIDOMSerializer.NS_IDOMSERIALIZER_IID, result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+        nsIDOMSerializer serializer = new nsIDOMSerializer (result[0]);
+        result[0] = 0;
+        rc = serializer.SerializeToString (document, result);
+        serializer.Release ();
+
+        int length = XPCOM.strlen_PRUnichar (result[0]);
+        chars = new char[length];
+        XPCOM.memmove (chars, result[0], length * 2);
+    }
+
+    componentManager.Release ();
+    new nsISupports (document).Release ();
+    return new String (chars);
+}
+
+public String getUrl () {
+    if (awaitingNavigate) return ""; //$NON-NLS-1$
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+    int /*long*/[] aCurrentURI = new int /*long*/[1];
+    rc = webNavigation.GetCurrentURI (aCurrentURI);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    webNavigation.Release ();
+
+    byte[] dest = null;
+    if (aCurrentURI[0] !is 0) {
+        nsIURI uri = new nsIURI (aCurrentURI[0]);
+        int /*long*/ aSpec = XPCOM.nsEmbedCString_new ();
+        rc = uri.GetSpec (aSpec);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        int length = XPCOM.nsEmbedCString_Length (aSpec);
+        int /*long*/ buffer = XPCOM.nsEmbedCString_get (aSpec);
+        dest = new byte[length];
+        XPCOM.memmove (dest, buffer, length);
+        XPCOM.nsEmbedCString_delete (aSpec);
+        uri.Release ();
+    }
+    if (dest is null) return ""; //$NON-NLS-1$
+
+    String location = new String (dest);
+    /*
+     * If the URI indicates that the page is being rendered from memory
+     * (via setText()) then set it to about:blank to be consistent with IE.
+     */
+    if (location.equals (URI_FROMMEMORY)) location = ABOUT_BLANK;
+    return location;
+}
+
+public Object getWebBrowser () {
+    if ((browser.getStyle () & DWT.MOZILLA) is 0) return null;
+    if (webBrowserObject !is null) return webBrowserObject;
+
+    try {
+        Class clazz = Class.forName ("org.mozilla.xpcom.Mozilla"); //$NON-NLS-1$
+        Method method = clazz.getMethod ("getInstance", new Class[0]); //$NON-NLS-1$
+        Object mozilla = method.invoke (null, new Object[0]);
+        method = clazz.getMethod ("wrapXPCOMObject", new Class[] {Long.TYPE, String.class}); //$NON-NLS-1$
+        webBrowserObject = method.invoke (mozilla, new Object[] {new Long (webBrowser.getAddress ()), nsIWebBrowser.NS_IWEBBROWSER_IID_STR});
+        /*
+         * The following AddRef() is needed to offset the automatic Release() that
+         * will be performed by JavaXPCOM when webBrowserObject is finalized.
+         */
+        webBrowser.AddRef ();
+        return webBrowserObject;
+    } catch (ClassNotFoundException e) {
+    } catch (NoSuchMethodException e) {
+    } catch (IllegalArgumentException e) {
+    } catch (IllegalAccessException e) {
+    } catch (InvocationTargetException e) {
+    }
+    return null;
+}
+
+public bool isBackEnabled () {
+    if (awaitingNavigate) return false;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+    int[] aCanGoBack = new int[1]; /* PRBool */
+    rc = webNavigation.GetCanGoBack (aCanGoBack);   
+    webNavigation.Release ();
+    return aCanGoBack[0] !is 0;
+}
+
+public bool isForwardEnabled () {
+    if (awaitingNavigate) return false;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+    int[] aCanGoForward = new int[1]; /* PRBool */
+    rc = webNavigation.GetCanGoForward (aCanGoForward);
+    webNavigation.Release ();
+    return aCanGoForward[0] !is 0;
+}
+
+static String error (int code) {
+    throw new DWTError ("XPCOM error " + code); //$NON-NLS-1$
+}
+
+void onDispose (Display display) {
+    int rc = webBrowser.RemoveWebBrowserListener (weakReference.getAddress (), nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID);
+    if (rc !is XPCOM.NS_OK) error (rc);
+
+    rc = webBrowser.SetParentURIContentListener (0);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    
+    unhookDOMListeners ();
+    if (listener !is null) {
+        int[] folderEvents = new int[] {
+            DWT.Dispose,
+            DWT.Resize,  
+            DWT.FocusIn,
+            DWT.Activate,
+            DWT.Deactivate,
+            DWT.Show,
+            DWT.KeyDown,
+        };
+        for (int i = 0; i < folderEvents.length; i++) {
+            browser.removeListener (folderEvents[i], listener);
+        }
+        listener = null;
+    }
+
+    int /*long*/[] result = new int /*long*/[1];
+    rc = webBrowser.QueryInterface (nsIBaseWindow.NS_IBASEWINDOW_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
+    rc = baseWindow.Destroy ();
+    if (rc !is XPCOM.NS_OK) error (rc);
+    baseWindow.Release ();
+
+    Release ();
+    webBrowser.Release ();
+    webBrowser = null;
+    webBrowserObject = null;
+
+    if (tip !is null && !tip.isDisposed ()) tip.dispose ();
+    tip = null;
+    location = size = null;
+
+    Enumeration elements = unhookedDOMWindows.elements ();
+    while (elements.hasMoreElements ()) {
+        LONG ptrObject = (LONG)elements.nextElement ();
+        new nsISupports (ptrObject.value).Release ();
+    }
+    unhookedDOMWindows = null;
+
+    delegate.onDispose (embedHandle);
+    delegate = null;
+
+    embedHandle = 0;
+    BrowserCount--;
+}
+
+void Activate () {
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebBrowserFocus.NS_IWEBBROWSERFOCUS_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebBrowserFocus webBrowserFocus = new nsIWebBrowserFocus (result[0]);
+    rc = webBrowserFocus.Activate ();
+    if (rc !is XPCOM.NS_OK) error (rc);
+    webBrowserFocus.Release ();
+}
+    
+void Deactivate () {
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebBrowserFocus.NS_IWEBBROWSERFOCUS_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebBrowserFocus webBrowserFocus = new nsIWebBrowserFocus (result[0]);
+    rc = webBrowserFocus.Deactivate ();
+    if (rc !is XPCOM.NS_OK) error (rc);
+    webBrowserFocus.Release ();
+}
+
+void onResize () {
+    Rectangle rect = browser.getClientArea ();
+    int width = Math.max (1, rect.width);
+    int height = Math.max (1, rect.height);
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIBaseWindow.NS_IBASEWINDOW_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    delegate.setSize (embedHandle, width, height);
+    nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
+    rc = baseWindow.SetPositionAndSize (0, 0, width, height, 1);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    baseWindow.Release ();
+}
+
+public void refresh () {
+    if (awaitingNavigate) return;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error(rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);          
+    rc = webNavigation.Reload (nsIWebNavigation.LOAD_FLAGS_NONE);
+    webNavigation.Release ();
+    if (rc is XPCOM.NS_OK) return;
+    /*
+    * Feature in Mozilla.  Reload returns an error code NS_ERROR_INVALID_POINTER
+    * when it is called immediately after a request to load a new document using
+    * LoadURI.  The workaround is to ignore this error code.
+    *
+    * Feature in Mozilla.  Attempting to reload a file that no longer exists
+    * returns an error code of NS_ERROR_FILE_NOT_FOUND.  This is equivalent to
+    * attempting to load a non-existent local url, which is not a Browser error,
+    * so this error code should be ignored. 
+    */
+    if (rc !is XPCOM.NS_ERROR_INVALID_POINTER && rc !is XPCOM.NS_ERROR_FILE_NOT_FOUND) error (rc);
+}
+
+public bool setText (String html) {
+    /*
+    *  Feature in Mozilla.  The focus memory of Mozilla must be 
+    *  properly managed through the nsIWebBrowserFocus interface.
+    *  In particular, nsIWebBrowserFocus.deactivate must be called
+    *  when the focus moves from the browser (or one of its children
+    *  managed by Mozilla to another widget.  We currently do not
+    *  get notified when a widget takes focus away from the Browser.
+    *  As a result, deactivate is not properly called. This causes
+    *  Mozilla to retake focus the next time a document is loaded.
+    *  This breaks the case where the HTML loaded in the Browser 
+    *  varies while the user enters characters in a text widget. The text
+    *  widget loses focus every time new content is loaded.
+    *  The current workaround is to call deactivate everytime if 
+    *  the browser currently does not have focus. A better workaround
+    *  would be to have a way to call deactivate when the Browser
+    *  or one of its children loses focus.
+    */
+    if (browser !is browser.getDisplay ().getFocusControl ()) Deactivate ();
+    
+    /* convert the String containing HTML to an array of bytes with UTF-8 data */
+    byte[] data = null;
+    try {
+        data = html.getBytes ("UTF-8"); //$NON-NLS-1$
+    } catch (UnsupportedEncodingException e) {
+        return false;
+    }
+
+    awaitingNavigate = false;
+
+    byte[] contentTypeBuffer = MozillaDelegate.wcsToMbcs (null, "text/html", true); // $NON-NLS-1$
+    int /*long*/ aContentType = XPCOM.nsEmbedCString_new (contentTypeBuffer, contentTypeBuffer.length);
+    byte[] contentCharsetBuffer = MozillaDelegate.wcsToMbcs (null, "UTF-8", true);  //$NON-NLS-1$
+    int /*long*/ aContentCharset = XPCOM.nsEmbedCString_new (contentCharsetBuffer, contentCharsetBuffer.length);
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = XPCOM.NS_GetServiceManager (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+    nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
+    result[0] = 0;
+    rc = serviceManager.GetService (XPCOM.NS_IOSERVICE_CID, nsIIOService.NS_IIOSERVICE_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+    serviceManager.Release ();
+
+    nsIIOService ioService = new nsIIOService (result[0]);
+    result[0] = 0;
+    /*
+    * Note.  Mozilla ignores LINK tags used to load CSS stylesheets
+    * when the URI protocol for the nsInputStreamChannel
+    * is about:blank.  The fix is to specify the file protocol.
+    */
+    byte[] aString = MozillaDelegate.wcsToMbcs (null, URI_FROMMEMORY, false);
+    int /*long*/ aSpec = XPCOM.nsEmbedCString_new (aString, aString.length);
+    rc = ioService.NewURI (aSpec, null, 0, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+    XPCOM.nsEmbedCString_delete (aSpec);
+    ioService.Release ();
+
+    nsIURI uri = new nsIURI (result[0]);
+    result[0] = 0;
+
+    rc = webBrowser.QueryInterface (nsIInterfaceRequestor.NS_IINTERFACEREQUESTOR_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    nsIInterfaceRequestor interfaceRequestor = new nsIInterfaceRequestor (result[0]);
+    result[0] = 0;
+
+    /*
+    * Feature in Mozilla. LoadStream invokes the nsIInputStream argument
+    * through a different thread.  The callback mechanism must attach 
+    * a non java thread to the JVM otherwise the nsIInputStream Read and
+    * Close methods never get called.
+    */
+    InputStream inputStream = new InputStream (data);
+    inputStream.AddRef ();
+
+    rc = interfaceRequestor.GetInterface (nsIDocShell_1_9.NS_IDOCSHELL_IID, result);
+    if (rc is XPCOM.NS_OK) {
+        if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+        nsIDocShell_1_9 docShell = new nsIDocShell_1_9 (result[0]);
+        rc = docShell.LoadStream (inputStream.getAddress (), uri.getAddress (), aContentType,  aContentCharset, 0);
+        docShell.Release ();
+    } else {
+        result[0] = 0;
+        rc = interfaceRequestor.GetInterface (nsIDocShell_1_8.NS_IDOCSHELL_IID, result);
+        if (rc is XPCOM.NS_OK) {    
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+            nsIDocShell_1_8 docShell = new nsIDocShell_1_8 (result[0]);
+            rc = docShell.LoadStream (inputStream.getAddress (), uri.getAddress (), aContentType,  aContentCharset, 0);
+            docShell.Release ();
+        } else {
+            result[0] = 0;
+            rc = interfaceRequestor.GetInterface (nsIDocShell.NS_IDOCSHELL_IID, result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+            nsIDocShell docShell = new nsIDocShell (result[0]);
+            rc = docShell.LoadStream (inputStream.getAddress (), uri.getAddress (), aContentType,  aContentCharset, 0);
+            docShell.Release ();
+        }
+    }
+    if (rc !is XPCOM.NS_OK) error (rc);
+    result[0] = 0;
+
+    inputStream.Release ();
+    interfaceRequestor.Release ();
+    uri.Release ();
+    XPCOM.nsEmbedCString_delete (aContentCharset);
+    XPCOM.nsEmbedCString_delete (aContentType);
+    return true;
+}
+
+public bool setUrl (String url) {
+    awaitingNavigate = false;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
+    char[] uri = new char[url.length () + 1];
+    url.getChars (0, url.length (), uri, 0);
+    rc = webNavigation.LoadURI (uri, nsIWebNavigation.LOAD_FLAGS_NONE, 0, 0, 0);
+    webNavigation.Release ();
+    return rc is XPCOM.NS_OK;
+}
+
+public void stop () {
+    if (awaitingNavigate) return;
+
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIWebNavigation.NS_IWEBNAVIGATION_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);      
+    rc = webNavigation.Stop (nsIWebNavigation.STOP_ALL);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    webNavigation.Release ();
+}
+
+void hookDOMListeners (nsIDOMEventTarget target, bool isTop) {
+    nsEmbedString string = new nsEmbedString (XPCOM.DOMEVENT_FOCUS);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_UNLOAD);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDOWN);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEUP);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEMOVE);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEWHEEL);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDRAG);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+
+    /*
+    * Only hook mouseover and mouseout if the target is a top-level frame, so that mouse moves
+    * between frames will not generate events.
+    */
+    if (isTop && delegate.hookEnterExit ()) {
+        string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOVER);
+        target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+        string.dispose ();
+        string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOUT);
+        target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+        string.dispose ();
+    }
+
+    string = new nsEmbedString (XPCOM.DOMEVENT_KEYDOWN);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_KEYPRESS);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_KEYUP);
+    target.AddEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+}
+
+void unhookDOMListeners () {
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.GetContentDOMWindow (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    nsIDOMWindow window = new nsIDOMWindow (result[0]);
+    result[0] = 0;
+    rc = window.QueryInterface (nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+    nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
+    result[0] = 0;
+    unhookDOMListeners (target);
+    target.Release ();
+
+    /* Listeners must be unhooked in pages contained in frames */
+    rc = window.GetFrames (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    nsIDOMWindowCollection frames = new nsIDOMWindowCollection (result[0]);
+    result[0] = 0;
+    int[] frameCount = new int[1];
+    rc = frames.GetLength (frameCount); /* PRUint32 */
+    if (rc !is XPCOM.NS_OK) error (rc);
+    int count = frameCount[0];
+
+    if (count > 0) {
+        for (int i = 0; i < count; i++) {
+            rc = frames.Item (i, result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+            nsIDOMWindow frame = new nsIDOMWindow (result[0]);
+            result[0] = 0;
+            rc = frame.QueryInterface (nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID, result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+            target = new nsIDOMEventTarget (result[0]);
+            result[0] = 0;
+            unhookDOMListeners (target);
+            target.Release ();
+            frame.Release ();
+        }
+    }
+    frames.Release ();
+    window.Release ();
+}
+
+void unhookDOMListeners (nsIDOMEventTarget target) {
+    nsEmbedString string = new nsEmbedString (XPCOM.DOMEVENT_FOCUS);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_UNLOAD);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDOWN);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEUP);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEMOVE);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEWHEEL);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDRAG);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOVER);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOUT);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_KEYDOWN);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_KEYPRESS);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+    string = new nsEmbedString (XPCOM.DOMEVENT_KEYUP);
+    target.RemoveEventListener (string.getAddress (), domEventListener.getAddress (), 0);
+    string.dispose ();
+}
+
+/* nsISupports */
+
+int QueryInterface (int /*long*/ riid, int /*long*/ ppvObject) {
+    if (riid is 0 || ppvObject is 0) return XPCOM.NS_ERROR_NO_INTERFACE;
+
+    nsID guid = new nsID ();
+    XPCOM.memmove (guid, riid, nsID.sizeof);
+
+    if (guid.Equals (nsISupports.NS_ISUPPORTS_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {supports.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIWeakReference.NS_IWEAKREFERENCE_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {weakReference.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {webProgressListener.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIWebBrowserChrome.NS_IWEBBROWSERCHROME_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {webBrowserChrome.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIWebBrowserChromeFocus.NS_IWEBBROWSERCHROMEFOCUS_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {webBrowserChromeFocus.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIEmbeddingSiteWindow.NS_IEMBEDDINGSITEWINDOW_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {embeddingSiteWindow.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIInterfaceRequestor.NS_IINTERFACEREQUESTOR_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {interfaceRequestor.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsISupportsWeakReference.NS_ISUPPORTSWEAKREFERENCE_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {supportsWeakReference.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIContextMenuListener.NS_ICONTEXTMENULISTENER_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {contextMenuListener.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsIURIContentListener.NS_IURICONTENTLISTENER_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {uriContentListener.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    if (guid.Equals (nsITooltipListener.NS_ITOOLTIPLISTENER_IID)) {
+        XPCOM.memmove (ppvObject, new int /*long*/[] {tooltipListener.getAddress ()}, C.PTR_SIZEOF);
+        AddRef ();
+        return XPCOM.NS_OK;
+    }
+    XPCOM.memmove (ppvObject, new int /*long*/[] {0}, C.PTR_SIZEOF);
+    return XPCOM.NS_ERROR_NO_INTERFACE;
+}
+
+int AddRef () {
+    refCount++;
+    return refCount;
+}
+
+int Release () {
+    refCount--;
+    if (refCount is 0) disposeCOMInterfaces ();
+    return refCount;
+}
+
+/* nsIWeakReference */  
+    
+int QueryReferent (int /*long*/ riid, int /*long*/ ppvObject) {
+    return QueryInterface (riid, ppvObject);
+}
+
+/* nsIInterfaceRequestor */
+
+int GetInterface (int /*long*/ riid, int /*long*/ ppvObject) {
+    if (riid is 0 || ppvObject is 0) return XPCOM.NS_ERROR_NO_INTERFACE;
+    nsID guid = new nsID ();
+    XPCOM.memmove (guid, riid, nsID.sizeof);
+    if (guid.Equals (nsIDOMWindow.NS_IDOMWINDOW_IID)) {
+        int /*long*/[] aContentDOMWindow = new int /*long*/[1];
+        int rc = webBrowser.GetContentDOMWindow (aContentDOMWindow);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (aContentDOMWindow[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+        XPCOM.memmove (ppvObject, aContentDOMWindow, C.PTR_SIZEOF);
+        return rc;
+    }
+    return QueryInterface (riid, ppvObject);
+}
+
+int GetWeakReference (int /*long*/ ppvObject) {
+    XPCOM.memmove (ppvObject, new int /*long*/[] {weakReference.getAddress ()}, C.PTR_SIZEOF);
+    AddRef ();
+    return XPCOM.NS_OK;
+}
+
+/* nsIWebProgressListener */
+
+int OnStateChange (int /*long*/ aWebProgress, int /*long*/ aRequest, int aStateFlags, int aStatus) {
+    if ((aStateFlags & nsIWebProgressListener.STATE_IS_DOCUMENT) is 0) return XPCOM.NS_OK;
+    if ((aStateFlags & nsIWebProgressListener.STATE_START) !is 0) {
+        if (request is 0) request = aRequest;
+
+        if (!awaitingNavigate) {
+            /*
+             * Add the page's nsIDOMWindow to the collection of windows that will
+             * have DOM listeners added to them later on in the page loading
+             * process.  These listeners cannot be added yet because the
+             * nsIDOMWindow is not ready to take them at this stage.
+             */
+            int /*long*/[] result = new int /*long*/[1];
+            nsIWebProgress progress = new nsIWebProgress (aWebProgress);
+            int rc = progress.GetDOMWindow (result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+            unhookedDOMWindows.addElement (new LONG (result[0]));
+        }
+    } else if ((aStateFlags & nsIWebProgressListener.STATE_REDIRECTING) !is 0) {
+        if (request is aRequest) request = 0;
+    } else if ((aStateFlags & nsIWebProgressListener.STATE_STOP) !is 0) {
+        /*
+        * If this page's nsIDOMWindow handle is still in unhookedDOMWindows then
+        * add its DOM listeners now.  It's possible for this to happen since
+        * there is no guarantee that a STATE_TRANSFERRING state change will be
+        * received for every window in a page, which is when these listeners
+        * are typically added.
+        */
+        int /*long*/[] result = new int /*long*/[1];
+        nsIWebProgress progress = new nsIWebProgress (aWebProgress);
+        int rc = progress.GetDOMWindow (result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+        nsIDOMWindow domWindow = new nsIDOMWindow (result[0]);
+
+        LONG ptrObject = new LONG (result[0]);
+        result[0] = 0;
+        int index = unhookedDOMWindows.indexOf (ptrObject);
+        if (index !is -1) {
+            rc = webBrowser.GetContentDOMWindow (result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+            bool isTop = result[0] is domWindow.getAddress ();
+            new nsISupports (result[0]).Release ();
+            result[0] = 0;
+
+            rc = domWindow.QueryInterface (nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID, result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+            nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
+            result[0] = 0;
+            hookDOMListeners (target, isTop);
+            target.Release ();
+
+            /*
+            * Remove and unreference the nsIDOMWindow from the collection of windows
+            * that are waiting to have DOM listeners hooked on them. 
+            */
+            unhookedDOMWindows.remove (ptrObject);
+            new nsISupports (ptrObject.value).Release ();
+        }
+        domWindow.Release ();
+
+        /*
+        * Feature in Mozilla.  When a request is redirected (STATE_REDIRECTING),
+        * it never reaches the state STATE_STOP and it is replaced with a new request.
+        * The new request is received when it is in the state STATE_STOP.
+        * To handle this case,  the variable request is set to 0 when the corresponding
+        * request is redirected. The following request received with the state STATE_STOP
+        * - the new request resulting from the redirection - is used to send
+        * the ProgressListener.completed event.
+        */
+        if (request is aRequest || request is 0) {
+            request = 0;
+            if (!awaitingNavigate) {
+                StatusTextEvent event = new StatusTextEvent (browser);
+                event.display = browser.getDisplay ();
+                event.widget = browser;
+                event.text = ""; //$NON-NLS-1$
+                for (int i = 0; i < statusTextListeners.length; i++) {
+                    statusTextListeners[i].changed (event);
+                }
+                ProgressEvent event2 = new ProgressEvent (browser);
+                event2.display = browser.getDisplay ();
+                event2.widget = browser;
+                for (int i = 0; i < progressListeners.length; i++) {
+                    progressListeners[i].completed (event2);
+                }
+            }
+        }
+    } else if ((aStateFlags & nsIWebProgressListener.STATE_TRANSFERRING) !is 0) {
+        /*
+        * Hook DOM listeners to the page's nsIDOMWindow here because this is
+        * the earliest opportunity to do so.    
+        */
+        int /*long*/[] result = new int /*long*/[1];
+        nsIWebProgress progress = new nsIWebProgress (aWebProgress);
+        int rc = progress.GetDOMWindow (result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+        nsIDOMWindow domWindow = new nsIDOMWindow (result[0]);
+
+        LONG ptrObject = new LONG (result[0]);
+        result[0] = 0;
+        int index = unhookedDOMWindows.indexOf (ptrObject);
+        if (index !is -1) {
+            rc = webBrowser.GetContentDOMWindow (result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+            bool isTop = result[0] is domWindow.getAddress ();
+            new nsISupports (result[0]).Release ();
+            result[0] = 0;
+
+            rc = domWindow.QueryInterface (nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID, result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+
+            nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
+            result[0] = 0;
+            hookDOMListeners (target, isTop);
+            target.Release ();
+
+            /*
+            * Remove and unreference the nsIDOMWindow from the collection of windows
+            * that are waiting to have DOM listeners hooked on them. 
+            */
+            unhookedDOMWindows.remove (ptrObject);
+            new nsISupports (ptrObject.value).Release ();
+        }
+        domWindow.Release ();
+    }
+    return XPCOM.NS_OK;
+}
+
+int OnProgressChange (int /*long*/ aWebProgress, int /*long*/ aRequest, int aCurSelfProgress, int aMaxSelfProgress, int aCurTotalProgress, int aMaxTotalProgress) {
+    if (awaitingNavigate || progressListeners.length is 0) return XPCOM.NS_OK;
+    ProgressEvent event = new ProgressEvent (browser);
+    event.display = browser.getDisplay ();
+    event.widget = browser;
+    event.current = aCurTotalProgress;
+    event.total = aMaxTotalProgress;
+    for (int i = 0; i < progressListeners.length; i++) {
+        progressListeners[i].changed (event);
+    }
+    return XPCOM.NS_OK;
+}
+
+int OnLocationChange (int /*long*/ aWebProgress, int /*long*/ aRequest, int /*long*/ aLocation) {
+    /*
+    * Feature in Mozilla.  When a page is loaded via setText before a previous
+    * setText page load has completed, the expected OnStateChange STATE_STOP for the
+    * original setText never arrives because it gets replaced by the OnStateChange
+    * STATE_STOP for the new request.  This results in the request field never being
+    * cleared because the original request's OnStateChange STATE_STOP is still expected
+    * (but never arrives).  To handle this case, the request field is updated to the new
+    * overriding request since its OnStateChange STATE_STOP will be received next.
+    */
+    if (request !is 0 && request !is aRequest) request = aRequest;
+
+    if (awaitingNavigate || locationListeners.length is 0) return XPCOM.NS_OK;
+
+    nsIWebProgress webProgress = new nsIWebProgress (aWebProgress);
+    int /*long*/[] aDOMWindow = new int /*long*/[1];
+    int rc = webProgress.GetDOMWindow (aDOMWindow);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (aDOMWindow[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIDOMWindow domWindow = new nsIDOMWindow (aDOMWindow[0]);
+    int /*long*/[] aTop = new int /*long*/[1];
+    rc = domWindow.GetTop (aTop);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (aTop[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    domWindow.Release ();
+    
+    nsIDOMWindow topWindow = new nsIDOMWindow (aTop[0]);
+    topWindow.Release ();
+    
+    nsIURI location = new nsIURI (aLocation);
+    int /*long*/ aSpec = XPCOM.nsEmbedCString_new ();
+    location.GetSpec (aSpec);
+    int length = XPCOM.nsEmbedCString_Length (aSpec);
+    int /*long*/ buffer = XPCOM.nsEmbedCString_get (aSpec);
+    byte[] dest = new byte[length];
+    XPCOM.memmove (dest, buffer, length);
+    XPCOM.nsEmbedCString_delete (aSpec);
+    String url = new String (dest);
+
+    /*
+     * As of Mozilla 1.8, the first time that a page is displayed, regardless of
+     * whether it's via Browser.setURL() or Browser.setText(), the GRE navigates
+     * to about:blank and fires the corresponding navigation events.  Do not send
+     * this event on to the user since it is not expected.
+     */
+    if (!IsPre_1_8 && aRequest is 0 && url.startsWith (ABOUT_BLANK)) return XPCOM.NS_OK;
+
+    LocationEvent event = new LocationEvent (browser);
+    event.display = browser.getDisplay ();
+    event.widget = browser;
+    event.location = url;
+    /*
+     * If the URI indicates that the page is being rendered from memory
+     * (via setText()) then set it to about:blank to be consistent with IE.
+     */
+    if (event.location.equals (URI_FROMMEMORY)) event.location = ABOUT_BLANK;
+    event.top = aTop[0] is aDOMWindow[0];
+    for (int i = 0; i < locationListeners.length; i++) {
+        locationListeners[i].changed (event);
+    }
+    return XPCOM.NS_OK;
+}
+
+int OnStatusChange (int /*long*/ aWebProgress, int /*long*/ aRequest, int aStatus, int /*long*/ aMessage) {
+    if (awaitingNavigate || statusTextListeners.length is 0) return XPCOM.NS_OK;
+    StatusTextEvent event = new StatusTextEvent (browser);
+    event.display = browser.getDisplay ();
+    event.widget = browser;
+    int length = XPCOM.strlen_PRUnichar (aMessage);
+    char[] dest = new char[length];
+    XPCOM.memmove (dest, aMessage, length * 2);
+    event.text = new String (dest);
+    for (int i = 0; i < statusTextListeners.length; i++) {
+        statusTextListeners[i].changed (event);
+    }
+    return XPCOM.NS_OK;
+}       
+
+int OnSecurityChange (int /*long*/ aWebProgress, int /*long*/ aRequest, int state) {
+    return XPCOM.NS_OK;
+}
+
+/* nsIWebBrowserChrome */
+
+int SetStatus (int statusType, int /*long*/ status) {
+    if (awaitingNavigate || statusTextListeners.length is 0) return XPCOM.NS_OK;
+    StatusTextEvent event = new StatusTextEvent (browser);
+    event.display = browser.getDisplay ();
+    event.widget = browser;
+    int length = XPCOM.strlen_PRUnichar (status);
+    char[] dest = new char[length];
+    XPCOM.memmove (dest, status, length * 2);
+    String string = new String (dest);
+    event.text = string;
+    for (int i = 0; i < statusTextListeners.length; i++) {
+        statusTextListeners[i].changed (event);
+    }
+    return XPCOM.NS_OK;
+}
+
+int GetWebBrowser (int /*long*/ aWebBrowser) {
+    int /*long*/[] ret = new int /*long*/[1];   
+    if (webBrowser !is null) {
+        webBrowser.AddRef ();
+        ret[0] = webBrowser.getAddress ();  
+    }
+    XPCOM.memmove (aWebBrowser, ret, C.PTR_SIZEOF);
+    return XPCOM.NS_OK;
+}
+
+int SetWebBrowser (int /*long*/ aWebBrowser) {
+    if (webBrowser !is null) webBrowser.Release ();
+    webBrowser = aWebBrowser !is 0 ? new nsIWebBrowser (aWebBrowser) : null;                 
+    return XPCOM.NS_OK;
+}
+   
+int GetChromeFlags (int /*long*/ aChromeFlags) {
+    int[] ret = new int[1];
+    ret[0] = chromeFlags;
+    XPCOM.memmove (aChromeFlags, ret, 4); /* PRUint32 */
+    return XPCOM.NS_OK;
+}
+
+int SetChromeFlags (int aChromeFlags) {
+    chromeFlags = aChromeFlags;
+    return XPCOM.NS_OK;
+}
+
+int DestroyBrowserWindow () {
+    WindowEvent newEvent = new WindowEvent (browser);
+    newEvent.display = browser.getDisplay ();
+    newEvent.widget = browser;
+    for (int i = 0; i < closeWindowListeners.length; i++) {
+        closeWindowListeners[i].close (newEvent);
+    }
+    /*
+    * Note on Mozilla.  The DestroyBrowserWindow notification cannot be cancelled.
+    * The browser widget cannot be used after this notification has been received.
+    * The application is advised to close the window hosting the browser widget.
+    * The browser widget must be disposed in all cases.
+    */
+    browser.dispose ();
+    return XPCOM.NS_OK;
+}
+    
+int SizeBrowserTo (int aCX, int aCY) {
+    size = new Point (aCX, aCY);
+    bool isChrome = (chromeFlags & nsIWebBrowserChrome.CHROME_OPENAS_CHROME) !is 0;
+    if (isChrome) {
+        Shell shell = browser.getShell ();
+        shell.setSize (shell.computeSize (size.x, size.y));
+    }
+    return XPCOM.NS_OK;
+}
+
+int ShowAsModal () {
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = XPCOM.NS_GetServiceManager (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+    nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
+    result[0] = 0;
+    byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_CONTEXTSTACK_CONTRACTID, true);
+    rc = serviceManager.GetServiceByContractID (aContractID, nsIJSContextStack.NS_IJSCONTEXTSTACK_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+    serviceManager.Release ();
+
+    nsIJSContextStack stack = new nsIJSContextStack (result[0]);
+    result[0] = 0;
+    rc = stack.Push (0);
+    if (rc !is XPCOM.NS_OK) error (rc);
+
+    Shell shell = browser.getShell ();
+    Display display = browser.getDisplay ();
+    while (!shell.isDisposed ()) {
+        if (!display.readAndDispatch ()) display.sleep ();
+    }
+
+    rc = stack.Pop (result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    stack.Release ();
+    return XPCOM.NS_OK;
+}
+
+int IsWindowModal (int /*long*/ retval) {
+    int result = (chromeFlags & nsIWebBrowserChrome.CHROME_MODAL) !is 0 ? 1 : 0;
+    XPCOM.memmove (retval, new int[] {result}, 4); /* PRBool */
+    return XPCOM.NS_OK;
+}
+   
+int ExitModalEventLoop (int aStatus) {
+    return XPCOM.NS_OK;
+}
+
+/* nsIEmbeddingSiteWindow */ 
+
+int SetDimensions (int flags, int x, int y, int cx, int cy) {
+    if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_POSITION) !is 0) {
+        location = new Point (x, y);
+        browser.getShell ().setLocation (x, y);
+    }
+    if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_INNER) !is 0) {
+        browser.setSize (cx, cy);
+    }
+    if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_OUTER) !is 0) {
+        browser.getShell ().setSize (cx, cy);
+    }
+    return XPCOM.NS_OK;
+}
+
+int GetDimensions (int flags, int /*long*/ x, int /*long*/ y, int /*long*/ cx, int /*long*/ cy) {
+    if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_POSITION) !is 0) {
+        Point location = browser.getShell ().getLocation ();
+        if (x !is 0) C.memmove (x, new int[] {location.x}, 4); /* PRInt32 */
+        if (y !is 0) C.memmove (y, new int[] {location.y}, 4); /* PRInt32 */
+    }
+    if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_INNER) !is 0) {
+        Point size = browser.getSize ();
+        if (cx !is 0) C.memmove (cx, new int[] {size.x}, 4); /* PRInt32 */
+        if (cy !is 0) C.memmove (cy, new int[] {size.y}, 4); /* PRInt32 */
+    }
+    if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_OUTER) !is 0) {
+        Point size = browser.getShell().getSize ();
+        if (cx !is 0) C.memmove (cx, new int[] {size.x}, 4); /* PRInt32 */
+        if (cy !is 0) C.memmove (cy, new int[] {size.y}, 4); /* PRInt32 */
+    }
+    return XPCOM.NS_OK;
+}
+
+int SetFocus () {
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = webBrowser.QueryInterface (nsIBaseWindow.NS_IBASEWINDOW_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_ERROR_NO_INTERFACE);
+    
+    nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
+    rc = baseWindow.SetFocus ();
+    if (rc !is XPCOM.NS_OK) error (rc);
+    baseWindow.Release ();
+
+    /*
+    * Note. Mozilla notifies here that one of the children took
+    * focus. This could or should be used to fire an DWT.FOCUS_IN
+    * event on Browser focus listeners.
+    */
+    return XPCOM.NS_OK;         
+}   
+
+int GetVisibility (int /*long*/ aVisibility) {
+    bool visible = browser.isVisible () && !browser.getShell ().getMinimized ();
+    XPCOM.memmove (aVisibility, new int[] {visible ? 1 : 0}, 4); /* PRBool */
+    return XPCOM.NS_OK;
+}
+
+int SetVisibility (int aVisibility) {
+    if (isChild) {
+        WindowEvent event = new WindowEvent (browser);
+        event.display = browser.getDisplay ();
+        event.widget = browser;
+        if (aVisibility !is 0) {
+            /*
+            * Bug in Mozilla.  When the JavaScript window.open is executed, Mozilla
+            * fires multiple SetVisibility 1 notifications.  The workaround is
+            * to ignore subsequent notifications. 
+            */
+            if (!visible) {
+                visible = true;
+                event.location = location;
+                event.size = size;
+                event.addressBar = (chromeFlags & nsIWebBrowserChrome.CHROME_LOCATIONBAR) !is 0;
+                event.menuBar = (chromeFlags & nsIWebBrowserChrome.CHROME_MENUBAR) !is 0;
+                event.statusBar = (chromeFlags & nsIWebBrowserChrome.CHROME_STATUSBAR) !is 0;
+                event.toolBar = (chromeFlags & nsIWebBrowserChrome.CHROME_TOOLBAR) !is 0;
+                for (int i = 0; i < visibilityWindowListeners.length; i++) {
+                    visibilityWindowListeners[i].show (event);
+                }
+                location = null;
+                size = null;
+            }
+        } else {
+            visible = false;
+            for (int i = 0; i < visibilityWindowListeners.length; i++) {
+                visibilityWindowListeners[i].hide (event);
+            }
+        }
+    } else {
+        visible = aVisibility !is 0;
+    }
+    return XPCOM.NS_OK;         
+}
+
+int GetTitle (int /*long*/ aTitle) {
+    return XPCOM.NS_OK;         
+}
+ 
+int SetTitle (int /*long*/ aTitle) {
+    if (awaitingNavigate || titleListeners.length is 0) return XPCOM.NS_OK;
+    TitleEvent event = new TitleEvent (browser);
+    event.display = browser.getDisplay ();
+    event.widget = browser;
+    /*
+    * To be consistent with other platforms the title event should
+    * contain the page's url if the page does not contain a <title>
+    * tag. 
+    */
+    int length = XPCOM.strlen_PRUnichar (aTitle);
+    if (length > 0) {
+        char[] dest = new char[length];
+        XPCOM.memmove (dest, aTitle, length * 2);
+        event.title = new String (dest);
+    } else {
+        event.title = getUrl ();
+    }
+    for (int i = 0; i < titleListeners.length; i++) {
+        titleListeners[i].changed (event);
+    }
+    return XPCOM.NS_OK;         
+}
+
+int GetSiteWindow (int /*long*/ aSiteWindow) {
+    /*
+    * Note.  The handle is expected to be an HWND on Windows and
+    * a GtkWidget* on GTK.  This callback is invoked on Windows
+    * when the javascript window.print is invoked and the print
+    * dialog comes up. If no handle is returned, the print dialog
+    * does not come up on this platform.  
+    */
+    XPCOM.memmove (aSiteWindow, new int /*long*/[] {embedHandle}, C.PTR_SIZEOF);
+    return XPCOM.NS_OK;         
+}  
+ 
+/* nsIWebBrowserChromeFocus */
+
+int FocusNextElement () {
+    /*
+    * Bug in Mozilla embedding API.  Mozilla takes back the focus after sending
+    * this event.  This prevents tabbing out of Mozilla. This behaviour can be reproduced
+    * with the Mozilla application TestGtkEmbed.  The workaround is to
+    * send the traversal notification after this callback returns.
+    */
+    browser.getDisplay ().asyncExec (new Runnable () {
+        public void run () {
+            if (browser.isDisposed ()) return;
+            browser.traverse (DWT.TRAVERSE_TAB_NEXT);
+        }
+    });
+    return XPCOM.NS_OK;  
+}
+
+int FocusPrevElement () {
+    /*
+    * Bug in Mozilla embedding API.  Mozilla takes back the focus after sending
+    * this event.  This prevents tabbing out of Mozilla. This behaviour can be reproduced
+    * with the Mozilla application TestGtkEmbed.  The workaround is to
+    * send the traversal notification after this callback returns.
+    */
+    browser.getDisplay ().asyncExec (new Runnable () {
+        public void run () {
+            if (browser.isDisposed ()) return;
+            browser.traverse (DWT.TRAVERSE_TAB_PREVIOUS);
+        }
+    });
+    return XPCOM.NS_OK;         
+}
+
+/* nsIContextMenuListener */
+
+int OnShowContextMenu (int aContextFlags, int /*long*/ aEvent, int /*long*/ aNode) {
+    if (awaitingNavigate) return XPCOM.NS_OK;
+
+    nsIDOMEvent domEvent = new nsIDOMEvent (aEvent);
+    int /*long*/[] result = new int /*long*/[1];
+    int rc = domEvent.QueryInterface (nsIDOMMouseEvent.NS_IDOMMOUSEEVENT_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+    nsIDOMMouseEvent domMouseEvent = new nsIDOMMouseEvent (result[0]);
+    int[] aScreenX = new int[1], aScreenY = new int[1];
+    rc = domMouseEvent.GetScreenX (aScreenX);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    rc = domMouseEvent.GetScreenY (aScreenY);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    domMouseEvent.Release ();
+    
+    Event event = new Event ();
+    event.x = aScreenX[0];
+    event.y = aScreenY[0];
+    browser.notifyListeners (DWT.MenuDetect, event);
+    if (!event.doit || browser.isDisposed ()) return XPCOM.NS_OK;
+    Menu menu = browser.getMenu ();
+    if (menu !is null && !menu.isDisposed ()) {
+        if (aScreenX[0] !is event.x || aScreenY[0] !is event.y) {
+            menu.setLocation (event.x, event.y);
+        }
+        menu.setVisible (true);
+    }
+    return XPCOM.NS_OK;         
+}
+
+/* nsIURIContentListener */
+
+int OnStartURIOpen (int /*long*/ aURI, int /*long*/ retval) {
+    if (awaitingNavigate || locationListeners.length is 0) {
+        XPCOM.memmove (retval, new int[] {0}, 4); /* PRBool */
+        return XPCOM.NS_OK;
+    }
+    nsIURI location = new nsIURI (aURI);
+    int /*long*/ aSpec = XPCOM.nsEmbedCString_new ();
+    location.GetSpec (aSpec);
+    int length = XPCOM.nsEmbedCString_Length (aSpec);
+    int /*long*/ buffer = XPCOM.nsEmbedCString_get (aSpec);
+    buffer = XPCOM.nsEmbedCString_get (aSpec);
+    byte[] dest = new byte[length];
+    XPCOM.memmove (dest, buffer, length);
+    XPCOM.nsEmbedCString_delete (aSpec);
+    String value = new String (dest);
+    bool doit = true;
+    if (request is 0) {
+        /* 
+         * listeners should not be notified of internal transitions like "javascipt:..."
+         * because this is an implementation side-effect, not a true navigate
+         */
+        if (!value.startsWith (PREFIX_JAVASCRIPT)) {
+            LocationEvent event = new LocationEvent (browser);
+            event.display = browser.getDisplay();
+            event.widget = browser;
+            event.location = value;
+            /*
+             * If the URI indicates that the page is being rendered from memory
+             * (via setText()) then set it to about:blank to be consistent with IE.
+             */
+            if (event.location.equals (URI_FROMMEMORY)) event.location = ABOUT_BLANK;
+            event.doit = doit;
+            for (int i = 0; i < locationListeners.length; i++) {
+                locationListeners[i].changing (event);
+            }
+            doit = event.doit && !browser.isDisposed();
+        }
+    }
+    XPCOM.memmove (retval, new int[] {doit ? 0 : 1}, 4); /* PRBool */
+    return XPCOM.NS_OK;
+}
+
+int DoContent (int /*long*/ aContentType, int aIsContentPreferred, int /*long*/ aRequest, int /*long*/ aContentHandler, int /*long*/ retval) {
+    return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
+}
+
+int IsPreferred (int /*long*/ aContentType, int /*long*/ aDesiredContentType, int /*long*/ retval) {
+    bool preferred = false;
+    int size = XPCOM.strlen (aContentType);
+    if (size > 0) {
+        byte[] typeBytes = new byte[size + 1];
+        XPCOM.memmove (typeBytes, aContentType, size);
+        String contentType = new String (typeBytes, 0, size);
+
+        /* do not attempt to handle known problematic content types */
+        if (!contentType.equals (XPCOM.CONTENT_MAYBETEXT) && !contentType.equals (XPCOM.CONTENT_MULTIPART)) {
+            /* determine whether browser can handle the content type */
+            int /*long*/[] result = new int /*long*/[1];
+            int rc = XPCOM.NS_GetServiceManager (result);
+            if (rc !is XPCOM.NS_OK) error (rc);
+            if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+            nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
+            result[0] = 0;
+
+            /* First try to use the nsIWebNavigationInfo if it's available (>= mozilla 1.8) */
+            byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_WEBNAVIGATIONINFO_CONTRACTID, true);
+            rc = serviceManager.GetServiceByContractID (aContractID, nsIWebNavigationInfo.NS_IWEBNAVIGATIONINFO_IID, result);
+            if (rc is 0) {
+                byte[] bytes = MozillaDelegate.wcsToMbcs (null, contentType, true);
+                int /*long*/ typePtr = XPCOM.nsEmbedCString_new (bytes, bytes.length);
+                nsIWebNavigationInfo info = new nsIWebNavigationInfo (result[0]);
+                result[0] = 0;
+                int[] isSupportedResult = new int[1]; /* PRUint32 */
+                rc = info.IsTypeSupported (typePtr, 0, isSupportedResult);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                info.Release ();
+                XPCOM.nsEmbedCString_delete (typePtr);
+                preferred = isSupportedResult[0] !is 0;
+            } else {
+                /* nsIWebNavigationInfo is not available, so do the type lookup */
+                result[0] = 0;
+                rc = serviceManager.GetService (XPCOM.NS_CATEGORYMANAGER_CID, nsICategoryManager.NS_ICATEGORYMANAGER_IID, result);
+                if (rc !is XPCOM.NS_OK) error (rc);
+                if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+                nsICategoryManager categoryManager = new nsICategoryManager (result[0]);
+                result[0] = 0;
+                byte[] categoryBytes = MozillaDelegate.wcsToMbcs (null, "Gecko-Content-Viewers", true); //$NON-NLS-1$
+                rc = categoryManager.GetCategoryEntry (categoryBytes, typeBytes, result);
+                categoryManager.Release ();
+                /* if no viewer for the content type is registered then rc is XPCOM.NS_ERROR_NOT_AVAILABLE */
+                preferred = rc is XPCOM.NS_OK;
+            }
+            serviceManager.Release ();
+        }
+    }
+
+    XPCOM.memmove(retval, new int[] {preferred ? 1 : 0}, 4); /* PRBool */
+    if (preferred) {
+        XPCOM.memmove (aDesiredContentType, new int /*long*/[] {0}, C.PTR_SIZEOF);
+    }
+    return XPCOM.NS_OK;
+}
+
+int CanHandleContent (int /*long*/ aContentType, int aIsContentPreferred, int /*long*/ aDesiredContentType, int /*long*/ retval) {
+    return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
+}
+
+int GetLoadCookie (int /*long*/ aLoadCookie) {
+    return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
+}
+
+int SetLoadCookie (int /*long*/ aLoadCookie) {
+    return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
+}
+
+int GetParentContentListener (int /*long*/ aParentContentListener) {
+    return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
+}
+    
+int SetParentContentListener (int /*long*/ aParentContentListener) {
+    return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* nsITooltipListener */
+
+int OnShowTooltip (int aXCoords, int aYCoords, int /*long*/ aTipText) {
+    if (awaitingNavigate) return XPCOM.NS_OK;
+
+    int length = XPCOM.strlen_PRUnichar (aTipText);
+    char[] dest = new char[length];
+    XPCOM.memmove (dest, aTipText, length * 2);
+    String text = new String (dest);
+    if (tip !is null && !tip.isDisposed ()) tip.dispose ();
+    Display display = browser.getDisplay ();
+    Shell parent = browser.getShell ();
+    tip = new Shell (parent, DWT.ON_TOP);
+    tip.setLayout (new FillLayout());
+    Label label = new Label (tip, DWT.CENTER);
+    label.setForeground (display.getSystemColor (DWT.COLOR_INFO_FOREGROUND));
+    label.setBackground (display.getSystemColor (DWT.COLOR_INFO_BACKGROUND));
+    label.setText (text);
+    /*
+    * Bug in Mozilla embedded API.  Tooltip coordinates are wrong for 
+    * elements inside an inline frame (IFrame tag).  The workaround is 
+    * to position the tooltip based on the mouse cursor location.
+    */
+    Point point = display.getCursorLocation ();
+    /* Assuming cursor is 21x21 because this is the size of
+     * the arrow cursor on Windows
+     */ 
+    point.y += 21;
+    tip.setLocation (point);
+    tip.pack ();
+    tip.setVisible (true);
+    return XPCOM.NS_OK;
+}
+
+int OnHideTooltip () {
+    if (tip !is null && !tip.isDisposed ()) tip.dispose ();
+    tip = null;
+    return XPCOM.NS_OK;
+}
+
+/* nsIDOMEventListener */
+
+int HandleEvent (int /*long*/ event) {
+    nsIDOMEvent domEvent = new nsIDOMEvent (event);
+
+    int /*long*/ type = XPCOM.nsEmbedString_new ();
+    int rc = domEvent.GetType (type);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    int length = XPCOM.nsEmbedString_Length (type);
+    int /*long*/ buffer = XPCOM.nsEmbedString_get (type);
+    char[] chars = new char[length];
+    XPCOM.memmove (chars, buffer, length * 2);
+    String typeString = new String (chars);
+    XPCOM.nsEmbedString_delete (type);
+
+    if (XPCOM.DOMEVENT_UNLOAD.equals (typeString)) {
+        int /*long*/[] result = new int /*long*/[1];
+        rc = domEvent.GetCurrentTarget (result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+
+        nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
+        unhookDOMListeners (target);
+        target.Release ();
+        return XPCOM.NS_OK;
+    }
+
+    if (XPCOM.DOMEVENT_FOCUS.equals (typeString)) {
+        delegate.handleFocus ();
+        return XPCOM.NS_OK;
+    }
+
+    if (XPCOM.DOMEVENT_KEYDOWN.equals (typeString)) {
+        int /*long*/[] result = new int /*long*/[1];
+        rc = domEvent.QueryInterface (nsIDOMKeyEvent.NS_IDOMKEYEVENT_IID, result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+        nsIDOMKeyEvent domKeyEvent = new nsIDOMKeyEvent (result[0]);
+        result[0] = 0;
+
+        int[] aKeyCode = new int[1]; /* PRUint32 */
+        rc = domKeyEvent.GetKeyCode (aKeyCode);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        int keyCode = translateKey (aKeyCode[0]);
+
+        /*
+        * if keyCode is lastKeyCode then either a repeating key like Shift
+        * is being held or a key for which key events are not sent has been
+        * pressed.  In both of these cases a KeyDown should not be sent.
+        */
+        if (keyCode !is lastKeyCode) {
+            lastKeyCode = keyCode;
+            switch (keyCode) {
+                case DWT.SHIFT:
+                case DWT.CONTROL:
+                case DWT.ALT:
+                case DWT.CAPS_LOCK:
+                case DWT.NUM_LOCK:
+                case DWT.SCROLL_LOCK:
+                case DWT.COMMAND: {
+                    /* keypress events will not be received for these keys, so send KeyDowns for them now */
+                    int[] aAltKey = new int[1], aCtrlKey = new int[1], aShiftKey = new int[1], aMetaKey = new int[1]; /* PRBool */
+                    rc = domKeyEvent.GetAltKey (aAltKey);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                    rc = domKeyEvent.GetCtrlKey (aCtrlKey);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                    rc = domKeyEvent.GetShiftKey (aShiftKey);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                    rc = domKeyEvent.GetMetaKey (aMetaKey);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+
+                    Event keyEvent = new Event ();
+                    keyEvent.widget = browser;
+                    keyEvent.type = DWT.KeyDown;
+                    keyEvent.keyCode = keyCode;
+                    keyEvent.stateMask = (aAltKey[0] !is 0 ? DWT.ALT : 0) | (aCtrlKey[0] !is 0 ? DWT.CTRL : 0) | (aShiftKey[0] !is 0 ? DWT.SHIFT : 0) | (aMetaKey[0] !is 0 ? DWT.COMMAND : 0);
+                    keyEvent.stateMask &= ~keyCode;     /* remove current keydown if it's a state key */
+                    browser.notifyListeners (keyEvent.type, keyEvent);
+                    if (!keyEvent.doit || browser.isDisposed ()) {
+                        domEvent.PreventDefault ();
+                    }
+                    break;
+                }
+                default: {
+                    /* 
+                    * If the keydown has Meta (but not Meta+Ctrl) as a modifier then send a KeyDown event for it here
+                    * because a corresponding keypress event will not be received for it from the DOM.  If the keydown
+                    * does not have Meta as a modifier, or has Meta+Ctrl as a modifier, then then do nothing here
+                    * because its KeyDown event will be sent from the keypress listener.
+                    */
+                    int[] aMetaKey = new int[1]; /* PRBool */
+                    rc = domKeyEvent.GetMetaKey (aMetaKey);
+                    if (rc !is XPCOM.NS_OK) error (rc);
+                    if (aMetaKey[0] !is 0) {
+                        int[] aCtrlKey = new int[1]; /* PRBool */
+                        rc = domKeyEvent.GetCtrlKey (aCtrlKey);
+                        if (rc !is XPCOM.NS_OK) error (rc);
+                        if (aCtrlKey[0] is 0) {
+                            int[] aAltKey = new int[1], aShiftKey = new int[1]; /* PRBool */
+                            rc = domKeyEvent.GetAltKey (aAltKey);
+                            if (rc !is XPCOM.NS_OK) error (rc);
+                            rc = domKeyEvent.GetShiftKey (aShiftKey);
+                            if (rc !is XPCOM.NS_OK) error (rc);
+
+                            Event keyEvent = new Event ();
+                            keyEvent.widget = browser;
+                            keyEvent.type = DWT.KeyDown;
+                            keyEvent.keyCode = lastKeyCode;
+                            keyEvent.stateMask = (aAltKey[0] !is 0 ? DWT.ALT : 0) | (aCtrlKey[0] !is 0? DWT.CTRL : 0) | (aShiftKey[0] !is 0? DWT.SHIFT : 0) | (aMetaKey[0] !is 0? DWT.COMMAND : 0);
+                            browser.notifyListeners (keyEvent.type, keyEvent);
+                            if (!keyEvent.doit || browser.isDisposed ()) {
+                                domEvent.PreventDefault ();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        domKeyEvent.Release ();
+        return XPCOM.NS_OK;
+    }
+
+    if (XPCOM.DOMEVENT_KEYPRESS.equals (typeString)) {
+        /*
+        * if keydown could not determine a keycode for this key then it's a
+        * key for which key events are not sent (eg.- the Windows key)
+        */
+        if (lastKeyCode is 0) return XPCOM.NS_OK;
+
+        /*
+        * On linux only, unexpected keypress events are received for some
+        * modifier keys.  The workaround is to ignore these events since
+        * KeyDown events are sent for these keys in the keydown listener.  
+        */
+        switch (lastKeyCode) {
+            case DWT.CAPS_LOCK:
+            case DWT.NUM_LOCK:
+            case DWT.SCROLL_LOCK: return XPCOM.NS_OK;
+        }
+
+        int /*long*/[] result = new int /*long*/[1];
+        rc = domEvent.QueryInterface (nsIDOMKeyEvent.NS_IDOMKEYEVENT_IID, result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+        nsIDOMKeyEvent domKeyEvent = new nsIDOMKeyEvent (result[0]);
+        result[0] = 0;
+
+        int[] aAltKey = new int[1], aCtrlKey = new int[1], aShiftKey = new int[1], aMetaKey = new int[1]; /* PRBool */
+        rc = domKeyEvent.GetAltKey (aAltKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        rc = domKeyEvent.GetCtrlKey (aCtrlKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        rc = domKeyEvent.GetShiftKey (aShiftKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        rc = domKeyEvent.GetMetaKey (aMetaKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        domKeyEvent.Release ();
+
+        int[] aCharCode = new int[1]; /* PRUint32 */
+        rc = domKeyEvent.GetCharCode (aCharCode);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        lastCharCode = aCharCode[0];
+        if (lastCharCode is 0) {
+            switch (lastKeyCode) {
+                case DWT.TAB: lastCharCode = DWT.TAB; break;
+                case DWT.CR: lastCharCode = DWT.CR; break;
+                case DWT.BS: lastCharCode = DWT.BS; break;
+                case DWT.ESC: lastCharCode = DWT.ESC; break;
+                case DWT.DEL: lastCharCode = DWT.DEL; break;
+            }
+        }
+        if (aCtrlKey[0] !is 0 && (0 <= lastCharCode && lastCharCode <= 0x7F)) {
+            if ('a'  <= lastCharCode && lastCharCode <= 'z') lastCharCode -= 'a' - 'A';
+            if (64 <= lastCharCode && lastCharCode <= 95) lastCharCode -= 64;
+        }
+
+        Event keyEvent = new Event ();
+        keyEvent.widget = browser;
+        keyEvent.type = DWT.KeyDown;
+        keyEvent.keyCode = lastKeyCode;
+        keyEvent.character = (char)lastCharCode;
+        keyEvent.stateMask = (aAltKey[0] !is 0 ? DWT.ALT : 0) | (aCtrlKey[0] !is 0 ? DWT.CTRL : 0) | (aShiftKey[0] !is 0 ? DWT.SHIFT : 0) | (aMetaKey[0] !is 0 ? DWT.COMMAND : 0);
+        browser.notifyListeners (keyEvent.type, keyEvent);
+        if (!keyEvent.doit || browser.isDisposed ()) {
+            domEvent.PreventDefault ();
+        }
+        return XPCOM.NS_OK;
+    }
+
+    if (XPCOM.DOMEVENT_KEYUP.equals (typeString)) {
+        int /*long*/[] result = new int /*long*/[1];
+        rc = domEvent.QueryInterface (nsIDOMKeyEvent.NS_IDOMKEYEVENT_IID, result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+        nsIDOMKeyEvent domKeyEvent = new nsIDOMKeyEvent (result[0]);
+        result[0] = 0;
+
+        int[] aKeyCode = new int[1]; /* PRUint32 */
+        rc = domKeyEvent.GetKeyCode (aKeyCode);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        int keyCode = translateKey (aKeyCode[0]);
+        if (keyCode is 0) {
+            /* indicates a key for which key events are not sent */
+            domKeyEvent.Release ();
+            return XPCOM.NS_OK;
+        }
+        if (keyCode !is lastKeyCode) {
+            /* keyup does not correspond to the last keydown */
+            lastKeyCode = keyCode;
+            lastCharCode = 0;
+        }
+
+        int[] aAltKey = new int[1], aCtrlKey = new int[1], aShiftKey = new int[1], aMetaKey = new int[1]; /* PRBool */
+        rc = domKeyEvent.GetAltKey (aAltKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        rc = domKeyEvent.GetCtrlKey (aCtrlKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        rc = domKeyEvent.GetShiftKey (aShiftKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        rc = domKeyEvent.GetMetaKey (aMetaKey);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        domKeyEvent.Release ();
+
+        Event keyEvent = new Event ();
+        keyEvent.widget = browser;
+        keyEvent.type = DWT.KeyUp;
+        keyEvent.keyCode = lastKeyCode;
+        keyEvent.character = (char)lastCharCode;
+        keyEvent.stateMask = (aAltKey[0] !is 0 ? DWT.ALT : 0) | (aCtrlKey[0] !is 0 ? DWT.CTRL : 0) | (aShiftKey[0] !is 0 ? DWT.SHIFT : 0) | (aMetaKey[0] !is 0 ? DWT.COMMAND : 0);
+        switch (lastKeyCode) {
+            case DWT.SHIFT:
+            case DWT.CONTROL:
+            case DWT.ALT:
+            case DWT.COMMAND: {
+                keyEvent.stateMask |= lastKeyCode;
+            }
+        }
+        browser.notifyListeners (keyEvent.type, keyEvent);
+        if (!keyEvent.doit || browser.isDisposed ()) {
+            domEvent.PreventDefault ();
+        }
+        lastKeyCode = lastCharCode = 0;
+        return XPCOM.NS_OK;
+    }
+
+    /* mouse event */
+
+    int /*long*/[] result = new int /*long*/[1];
+    rc = domEvent.QueryInterface (nsIDOMMouseEvent.NS_IDOMMOUSEEVENT_IID, result);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    if (result[0] is 0) error (XPCOM.NS_NOINTERFACE);
+    nsIDOMMouseEvent domMouseEvent = new nsIDOMMouseEvent (result[0]);
+    result[0] = 0;
+
+    /*
+     * MouseOver and MouseOut events are fired any time the mouse enters or exits
+     * any element within the Browser.  To ensure that DWT events are only
+     * fired for mouse movements into or out of the Browser, do not fire an
+     * event if the element being exited (on MouseOver) or entered (on MouseExit)
+     * is within the Browser.
+     */
+    if (XPCOM.DOMEVENT_MOUSEOVER.equals (typeString) || XPCOM.DOMEVENT_MOUSEOUT.equals (typeString)) {
+        rc = domMouseEvent.GetRelatedTarget (result);
+        if (rc !is XPCOM.NS_OK) error (rc);
+        if (result[0] !is 0) {
+            domMouseEvent.Release ();
+            return XPCOM.NS_OK;
+        }
+    }
+
+    int[] aClientX = new int[1], aClientY = new int[1], aDetail = new int[1]; /* PRInt32 */
+    rc = domMouseEvent.GetClientX (aClientX);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    rc = domMouseEvent.GetClientY (aClientY);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    rc = domMouseEvent.GetDetail (aDetail);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    short[] aButton = new short[1]; /* PRUint16 */
+    rc = domMouseEvent.GetButton (aButton);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    int[] aAltKey = new int[1], aCtrlKey = new int[1], aShiftKey = new int[1], aMetaKey = new int[1]; /* PRBool */
+    rc = domMouseEvent.GetAltKey (aAltKey);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    rc = domMouseEvent.GetCtrlKey (aCtrlKey);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    rc = domMouseEvent.GetShiftKey (aShiftKey);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    rc = domMouseEvent.GetMetaKey (aMetaKey);
+    if (rc !is XPCOM.NS_OK) error (rc);
+    domMouseEvent.Release ();
+
+    Event mouseEvent = new Event ();
+    mouseEvent.widget = browser;
+    mouseEvent.x = aClientX[0]; mouseEvent.y = aClientY[0];
+    mouseEvent.stateMask = (aAltKey[0] !is 0 ? DWT.ALT : 0) | (aCtrlKey[0] !is 0 ? DWT.CTRL : 0) | (aShiftKey[0] !is 0 ? DWT.SHIFT : 0) | (aMetaKey[0] !is 0 ? DWT.COMMAND : 0);
+
+    if (XPCOM.DOMEVENT_MOUSEDOWN.equals (typeString)) {
+        delegate.handleMouseDown ();
+        mouseEvent.type = DWT.MouseDown;
+        mouseEvent.button = aButton[0] + 1;
+        mouseEvent.count = aDetail[0];
+    } else if (XPCOM.DOMEVENT_MOUSEUP.equals (typeString)) {
+        /*
+         * Bug on OSX.  For some reason multiple mouseup events come from the DOM
+         * when button 3 is released on OSX.  The first of these events has a count
+         * detail and the others do not.  The workaround is to not fire received
+         * button 3 mouseup events that do not have a count since mouse events
+         * without a click count are not valid.
+         */
+        int button = aButton[0] + 1;
+        int count = aDetail[0];
+        if (count is 0 && button is 3) return XPCOM.NS_OK;
+        mouseEvent.type = DWT.MouseUp;
+        mouseEvent.button = button;
+        mouseEvent.count = count;
+    } else if (XPCOM.DOMEVENT_MOUSEMOVE.equals (typeString)) {
+        mouseEvent.type = DWT.MouseMove;
+    } else if (XPCOM.DOMEVENT_MOUSEWHEEL.equals (typeString)) {
+        mouseEvent.type = DWT.MouseWheel;
+        mouseEvent.count = -aDetail[0];
+    } else if (XPCOM.DOMEVENT_MOUSEOVER.equals (typeString)) {
+        mouseEvent.type = DWT.MouseEnter;
+    } else if (XPCOM.DOMEVENT_MOUSEOUT.equals (typeString)) {
+        mouseEvent.type = DWT.MouseExit;
+    } else if (XPCOM.DOMEVENT_MOUSEDRAG.equals (typeString)) {
+        mouseEvent.type = DWT.DragDetect;
+        mouseEvent.button = aButton[0] + 1;
+        switch (mouseEvent.button) {
+            case 1: mouseEvent.stateMask |= DWT.BUTTON1; break;
+            case 2: mouseEvent.stateMask |= DWT.BUTTON2; break;
+            case 3: mouseEvent.stateMask |= DWT.BUTTON3; break;
+            case 4: mouseEvent.stateMask |= DWT.BUTTON4; break;
+            case 5: mouseEvent.stateMask |= DWT.BUTTON5; break;
+        }
+    }
+
+    browser.notifyListeners (mouseEvent.type, mouseEvent);
+    if (browser.isDisposed ()) return XPCOM.NS_OK;
+    if (aDetail[0] is 2 && XPCOM.DOMEVENT_MOUSEDOWN.equals (typeString)) {
+        mouseEvent = new Event ();
+        mouseEvent.widget = browser;
+        mouseEvent.x = aClientX[0]; mouseEvent.y = aClientY[0];
+        mouseEvent.stateMask = (aAltKey[0] !is 0 ? DWT.ALT : 0) | (aCtrlKey[0] !is 0 ? DWT.CTRL : 0) | (aShiftKey[0] !is 0 ? DWT.SHIFT : 0) | (aMetaKey[0] !is 0 ? DWT.COMMAND : 0);
+        mouseEvent.type = DWT.MouseDoubleClick;
+        mouseEvent.button = aButton[0] + 1;
+        mouseEvent.count = aDetail[0];
+        browser.notifyListeners (mouseEvent.type, mouseEvent);  
+    }
+    return XPCOM.NS_OK;
+}
+}