Mercurial > projects > dwt-mac
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; +} +}