Back to index

lightning-sunbird  0.9+nobinonly
MRJPlugin.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the MRJ Carbon OJI Plugin.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2001
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Patrick C. Beard <beard@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039     MRJPlugin.cpp
00040     
00041     XP COM Plugin Implementation.
00042     
00043     by Patrick C. Beard.
00044  */
00045 
00046 #include "MRJPlugin.h"
00047 #include "MRJSession.h"
00048 #include "MRJContext.h"
00049 #include "MRJConsole.h"
00050 #include "EmbeddedFramePluginInstance.h"
00051 
00052 #if !TARGET_CARBON
00053 #include "MRJFrame.h"
00054 #endif
00055 
00056 #include "nsIServiceManager.h"
00057 #include "nsIServiceManagerObsolete.h"
00058 #include "nsObsoleteModuleLoading.h"
00059 
00060 #include "nsIMemory.h"
00061 #include "nsIJVMManager.h"
00062 #include "nsIJVMPluginTagInfo.h"
00063 #include "nsIPluginManager2.h"
00064 #include "nsIPluginInstancePeer.h"
00065 #include "nsIWindowlessPlugInstPeer.h"
00066 #include "LiveConnectNativeMethods.h"
00067 #include "CSecureEnv.h"
00068 
00069 #include <Resources.h>
00070 #include <LaunchServices.h>
00071 #include <string>
00072 #include <CFBundle.h>
00073 
00074 nsIPluginManager* thePluginManager = NULL;
00075 nsIPluginManager2* thePluginManager2 = NULL;
00076 nsIMemory* theMemoryAllocator = NULL;
00077 
00078 FSSpec thePluginSpec;
00079 short thePluginRefnum = -1;
00080 
00081 // Common interface IDs.
00082 
00083 static NS_DEFINE_IID(kPluginCID, NS_PLUGIN_CID);
00084 static NS_DEFINE_IID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
00085 static NS_DEFINE_IID(kJVMManagerCID, NS_JVMMANAGER_CID);
00086 
00087 static NS_DEFINE_IID(kIWindowlessPluginInstancePeerIID, NS_IWINDOWLESSPLUGININSTANCEPEER_IID);
00088 
00093 static nsIServiceManager* theServiceManager = NULL;
00094 static nsIServiceManagerObsolete* theServiceManagerObsolete = NULL;
00095 
00096 nsresult MRJPlugin::GetService(const nsCID& aCID, const nsIID& aIID, void* *aService)
00097 {
00098     if (theServiceManager)
00099         return theServiceManager->GetService(aCID, aIID, aService);
00100     if (theServiceManagerObsolete)
00101         return theServiceManagerObsolete->GetService(aCID, aIID, (nsISupports **)aService);
00102     return NS_ERROR_FAILURE;
00103 }
00104 
00105 nsresult MRJPlugin::GetService(const char* aContractID, const nsIID& aIID, void* *aService)
00106 {
00107     if (theServiceManager)
00108         return theServiceManager->GetServiceByContractID(aContractID, aIID, aService);
00109     if (theServiceManagerObsolete)
00110         return theServiceManagerObsolete->GetService(aContractID, aIID, (nsISupports **)aService);
00111     return NS_ERROR_FAILURE;
00112 }
00113 
00114 #pragma export on
00115 
00116 static long getSystemVersion()
00117 {
00118     long version = 0;
00119     Gestalt(gestaltSystemVersion, &version);
00120     return version;
00121 }
00122 
00123 extern "C"
00124 nsresult NSGetFactory(nsISupports* serviceManager, const nsCID &aClass, const char *aClassName, const char *aContractID, nsIFactory **aFactory)
00125 {
00126     nsresult result = NS_OK;
00127 
00128     // First off, fail if not running on AT LEAST Mac OS X, v10.1.
00129     if (getSystemVersion() < 0x00001010)
00130         return NS_ERROR_FAILURE;
00131 
00132     if (theServiceManager == NULL && theServiceManagerObsolete == NULL) {
00133         if (NS_FAILED(serviceManager->QueryInterface(NS_GET_IID(nsIServiceManager), (void**)&theServiceManager)))
00134             if (NS_FAILED(serviceManager->QueryInterface(NS_GET_IID(nsIServiceManagerObsolete), (void**)&theServiceManagerObsolete)))
00135                 return NS_ERROR_FAILURE;
00136 
00137         // Our global operator new wants to use nsIMalloc to do all of its allocation.
00138         // This should be available from the Service Manager.
00139         if (NS_FAILED(MRJPlugin::GetService("@mozilla.org/xpcom/memory-service;1", NS_GET_IID(nsIMemory), (void **)&theMemoryAllocator)))
00140             return NS_ERROR_FAILURE;
00141     }
00142 
00143     if (aClass.Equals(kPluginCID)) {
00144         MRJPlugin* pluginFactory = new MRJPlugin();
00145         pluginFactory->AddRef();
00146         *aFactory = pluginFactory;
00147         return NS_OK;
00148     }
00149     return NS_NOINTERFACE;
00150 }
00151 
00152 #pragma export off
00153 
00154 #if TARGET_RT_MAC_CFM
00155 
00156 extern "C" {
00157 
00158 pascal OSErr __initialize(const CFragInitBlock *initBlock);
00159 pascal void __terminate(void);
00160 
00161 #if defined(MRJPLUGIN_GC)
00162 pascal OSErr __NSInitialize(const CFragInitBlock* initBlock);
00163 pascal void __NSTerminate(void);
00164 #define __initialize __NSInitialize
00165 #define __terminate __NSTerminate
00166 #endif
00167 
00168 pascal OSErr MRJPlugin__initialize(const CFragInitBlock *initBlock);
00169 pascal void MRJPlugin__terminate(void);
00170 
00171 }
00172 
00173 pascal OSErr MRJPlugin__initialize(const CFragInitBlock *initBlock)
00174 {
00175     OSErr err = __initialize(initBlock);
00176     if (err != noErr) return err;
00177 
00178     if (initBlock->fragLocator.where == kDataForkCFragLocator) {
00179         thePluginSpec = *initBlock->fragLocator.u.onDisk.fileSpec;
00180     
00181         // Open plugin's resource fork for read-only access.
00182         thePluginRefnum = ::FSpOpenResFile(&thePluginSpec, fsRdPerm);
00183     }
00184     
00185     return noErr;
00186 }
00187 
00188 pascal void MRJPlugin__terminate()
00189 {
00190 #if !TARGET_CARBON
00191     // last ditch release of the memory allocator.
00192     if (theMemoryAllocator != NULL) {
00193         theMemoryAllocator->Release();
00194         theMemoryAllocator = NULL;
00195     }
00196 #endif
00197 
00198     // Close plugin's resource fork.
00199     // If we don't, Mac OS X 10.1 crashes.
00200     if (thePluginRefnum != -1) {
00201         ::CloseResFile(thePluginRefnum);
00202         thePluginRefnum = -1;
00203     }
00204 
00205     __terminate();
00206 }
00207 
00208 #endif /* TARGET_RT_MAC_CFM */
00209 
00210 #if TARGET_RT_MAC_MACHO
00211 
00212 extern "C" {
00213 CF_EXPORT Boolean CFURLGetFSRef(CFURLRef url, FSRef *fsRef);
00214 }
00215 
00216 static CFBundleRef getPluginBundle()
00217 {
00218 #ifdef DEBUG
00219     printf("### MRJPlugin:  getPluginBundle() here. ###\n");
00220 #endif
00221     CFBundleRef bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.netscape.MRJPlugin"));
00222     if (bundle) {
00223 #ifdef DEBUG
00224         printf("### MRJPlugin:  CFBundleGetBundleWithIdentifier() succeeded. ###\n");
00225 #endif
00226         // initialize thePluginSpec for later use. open our resource fork as well?
00227         CFURLRef url = CFBundleCopyExecutableURL(bundle);
00228         if (url) {
00229             FSRef ref;
00230             if (CFURLGetFSRef(url, &ref)) {
00231 #ifdef DEBUG
00232                 printf("### MRJPlugin:  CFURLGetFSRef() succeeded. ###\n");
00233 #endif
00234                 FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, &thePluginSpec, NULL);
00235 
00236                 // Open plugin's resource fork for read-only access. is this really necessary?
00237                 thePluginRefnum = ::CFBundleOpenBundleResourceMap(bundle);
00238             }
00239             CFRelease(url);
00240         }
00241     }
00242     return bundle;
00243 }
00244 
00245 CFBundleRef thePluginBundle = getPluginBundle();
00246 
00247 #endif /* TARGET_RT_MAC_MACHO */
00248 
00249 //
00250 // The MEAT of the plugin.
00251 //
00252 
00253 #pragma mark *** MRJPlugin ***
00254 
00255 const InterfaceInfo MRJPlugin::sInterfaces[] = {
00256     { NS_IPLUGIN_IID, INTERFACE_OFFSET(MRJPlugin, nsIPlugin) },
00257     { NS_IJVMPLUGIN_IID, INTERFACE_OFFSET(MRJPlugin, nsIJVMPlugin) },
00258 #if USE_SYSTEM_CONSOLE
00259     { NS_IJVMCONSOLE_IID, INTERFACE_OFFSET(MRJPlugin, nsIJVMConsole) },
00260 #endif
00261     { NS_IRUNNABLE_IID, INTERFACE_OFFSET(MRJPlugin, nsIRunnable) },
00262 };
00263 const UInt32 MRJPlugin::kInterfaceCount = sizeof(sInterfaces) / sizeof(InterfaceInfo);
00264 
00265 MRJPlugin::MRJPlugin()
00266     :   SupportsMixin(this, sInterfaces, kInterfaceCount),
00267         mManager(NULL), mThreadManager(NULL), mSession(NULL), mConsole(NULL), mPluginThreadID(NULL), mIsEnabled(false)
00268 {
00269 }
00270 
00271 MRJPlugin::~MRJPlugin()
00272 {
00273     // Release the console.
00274     NS_IF_RELEASE(mConsole);
00275 
00276     // tear down the MRJ session, if it exists.
00277     if (mSession != NULL) {
00278         delete mSession;
00279         mSession = NULL;
00280     }
00281 
00282     // Release the managers.
00283     NS_IF_RELEASE(mManager);
00284     NS_IF_RELEASE(mThreadManager);
00285 }
00286 
00287 #if !USE_SYSTEM_CONSOLE
00288 
00295 NS_METHOD MRJPlugin::QueryInterface(const nsIID& aIID, void** instancePtr)
00296 {
00297     nsresult result = queryInterface(aIID, instancePtr);
00298     if (result == NS_NOINTERFACE) {
00299         result = mConsole->queryInterface(aIID, instancePtr);
00300     }
00301     return result;
00302 }
00303 #endif
00304 
00305 NS_METHOD MRJPlugin::CreateInstance(nsISupports *aOuter, const nsIID& aIID, void **aResult)
00306 {
00307     nsresult result = StartupJVM();
00308     if (result == NS_OK) {
00309         MRJPluginInstance* instance = new MRJPluginInstance(this);
00310         if (instance == nsnull)
00311             return NS_ERROR_OUT_OF_MEMORY;
00312         result = instance->QueryInterface(aIID, aResult);
00313         if (result != NS_OK)
00314             delete instance;
00315     }
00316     return result;
00317 }
00318 
00319 #define NS_APPLET_MIME_TYPE "application/x-java-applet"
00320 
00321 NS_METHOD MRJPlugin::CreatePluginInstance(nsISupports *aOuter, REFNSIID aIID, const char* aPluginMIMEType, void **aResult)
00322 {
00323     nsresult result = NS_NOINTERFACE;
00324 
00325     if (::strcmp(aPluginMIMEType, "application/x-java-frame") == 0) {
00326 #if !TARGET_CARBON
00327         // create a special plugin instance that manages an embedded frame.
00328         EmbeddedFramePluginInstance* instance = new EmbeddedFramePluginInstance();
00329         nsresult result = instance->QueryInterface(aIID, aResult);
00330         if (result != NS_OK)
00331             delete instance;
00332 #endif
00333     } else {
00334         // assume it's some kind of an applet.
00335         result = CreateInstance(aOuter, aIID, aResult);
00336     }
00337     return result;
00338 }
00339 
00340 NS_METHOD MRJPlugin::Initialize()
00341 {
00342     nsresult result = NS_OK;
00343 
00344     // try to get a plugin manager.
00345     if (thePluginManager == NULL) {
00346         result = MRJPlugin::GetService(kPluginManagerCID, NS_GET_IID(nsIPluginManager), (void**)&thePluginManager);
00347         if (result != NS_OK || thePluginManager == NULL)
00348             return NS_ERROR_FAILURE;
00349     }
00350 
00351     // see if the enhanced plugin manager exists.
00352     if (thePluginManager2 == NULL) {
00353         if (thePluginManager->QueryInterface(NS_GET_IID(nsIPluginManager2), (void**)&thePluginManager2) != NS_OK)
00354             thePluginManager2 = NULL;
00355     }
00356 
00357     // try to get a JVM manager. we have to be able to run without one.
00358     if (MRJPlugin::GetService(kJVMManagerCID, NS_GET_IID(nsIJVMManager), (void**)&mManager) != NS_OK)
00359         mManager = NULL;
00360     
00361     // try to get a Thread manager.
00362     if (mManager != NULL) {
00363         if (mManager->QueryInterface(NS_GET_IID(nsIThreadManager), (void**)&mThreadManager) != NS_OK)
00364             mThreadManager = NULL;
00365 
00366         if (mThreadManager != NULL)
00367             mThreadManager->GetCurrentThread(&mPluginThreadID);
00368     }
00369 
00370 #if !USE_SYSTEM_CONSOLE
00371     // create a console, only if there's user interface for it.
00372     if (thePluginManager2 != NULL) {
00373         mConsole = new MRJConsole(this);
00374         mConsole->AddRef();
00375     }
00376 #endif
00377 
00378     return result;
00379 }
00380 
00381 NS_METHOD MRJPlugin::Shutdown()
00382 {
00383     // shutdown LiveConnect.
00384     ShutdownLiveConnectSupport();
00385 
00386     // release our reference to the plugin manager(s).
00387     NS_IF_RELEASE(thePluginManager2);
00388     NS_IF_RELEASE(thePluginManager);
00389 
00390     // release our reference(s) to the service manager.
00391     NS_IF_RELEASE(theServiceManager);
00392     NS_IF_RELEASE(theServiceManagerObsolete);
00393     
00394     return NS_OK;
00395 }
00396 
00397 NS_METHOD MRJPlugin::GetMIMEDescription(const char* *result)
00398 {
00399     *result = NS_JVM_MIME_TYPE;
00400     return NS_OK;
00401 }
00402 
00403 NS_METHOD MRJPlugin::GetValue(nsPluginVariable variable, void *value)
00404 {
00405     return NS_ERROR_NOT_IMPLEMENTED;
00406 }
00407 
00408 MRJSession* MRJPlugin::getSession()
00409 {
00410     StartupJVM();
00411     return mSession;
00412 }
00413 
00414 nsIJVMManager* MRJPlugin::getManager()
00415 {
00416     return mManager;
00417 }
00418 
00419 nsIThreadManager* MRJPlugin::getThreadManager()
00420 {
00421     return mThreadManager;
00422 }
00423 
00424 static char* getJavaConsolePath(char* path, UInt32 maxPathSize)
00425 {
00426     path[0] = '\0';
00427     FSRef ref;
00428     OSErr err = FSFindFolder(kUserDomain, kDomainLibraryFolderType, true, &ref);
00429     if (err == noErr) {
00430         err = FSRefMakePath(&ref, (UInt8*) path, maxPathSize);
00431         const char kJavaConsoleLog[] = { "/Logs/Java Console.log" };
00432         int len = strlen(path);
00433         if (err == noErr && (len + sizeof(kJavaConsoleLog)) <= maxPathSize) {
00434             strcat(path + len, kJavaConsoleLog);
00435         }
00436     }
00437     return path;
00438 }
00439 
00440 nsresult MRJPlugin::StartupJVM()
00441 {
00442     if (mSession == NULL) {
00443         // start a session with MRJ.
00444         mSession = new MRJSession();
00445 
00446         // Add "MRJPlugin.jar" to the class path.
00447         FSSpec jarFileSpec = { thePluginSpec.vRefNum, thePluginSpec.parID, "\pMRJPlugin.jar" };
00448         mSession->addToClassPath(jarFileSpec);
00449         
00450         // Compute location of ~/Library/Logs/JavaConsole.log
00451         char consolePath[512];
00452         mSession->open(getJavaConsolePath(consolePath, sizeof(consolePath)));
00453 
00454         if (mSession->getStatus() != noErr) {
00455             // how can we signal an error?
00456             delete mSession;
00457             mSession = NULL;
00458             return NS_ERROR_FAILURE;
00459         }
00460 
00461         InitLiveConnectSupport(this);
00462 
00463 #if 0
00464         // start our idle thread.
00465         if (mThreadManager != NULL) {
00466             PRUint32 threadID;
00467             mThreadManager->CreateThread(&threadID, this);
00468         }
00469 #endif
00470 
00471         mIsEnabled = true;
00472     }
00473     return NS_OK;
00474 }
00475 
00476 NS_METHOD MRJPlugin::AddToClassPath(const char* dirPath)
00477 {
00478     if (mSession != NULL) {
00479         mSession->addToClassPath(dirPath);
00480         return NS_OK;
00481     }
00482     return NS_ERROR_FAILURE;
00483 }
00484 
00485 NS_METHOD MRJPlugin::GetClassPath(const char* *result)
00486 {
00487     char* classPath = mSession->getProperty("java.class.path");
00488     *result = classPath;
00489     return (classPath != NULL ? NS_OK : NS_ERROR_FAILURE);
00490 }
00491 
00492 NS_METHOD MRJPlugin::GetJavaWrapper(JNIEnv* env, jint jsobj, jobject *jobj)
00493 {
00494     // use jsobj as key into a table.
00495     // if not in the table, then create a new netscape.javascript.JSObject that references this.
00496     *jobj = Wrap_JSObject(env, jsobj);
00497     return NS_OK;
00498 }
00499 
00500 NS_METHOD MRJPlugin::UnwrapJavaWrapper(JNIEnv* env, jobject jobj, jint* jsobj)
00501 {
00502     *jsobj = Unwrap_JSObject(env, jobj);
00503     return NS_OK;
00504 }
00505 
00506 NS_METHOD MRJPlugin::CreateSecureEnv(JNIEnv* proxyEnv, nsISecureEnv* *outSecureEnv)
00507 {
00508     *outSecureEnv = NULL;
00509     nsresult rv = StartupJVM();
00510     if (rv == NS_OK) {
00511         // Need to spawn a new JVM communication thread here.
00512         // rv = CSecureEnv::Create(this, proxyEnv, NS_GET_IID(nsISecureEnv), (void**)outSecureEnv);
00513         static NS_DEFINE_IID(kISecureEnvIID, NS_ISECUREENV_IID);
00514         rv = CSecureEnv::Create(this, proxyEnv, kISecureEnvIID, (void**)outSecureEnv);
00515     }
00516     return rv;
00517 }
00518 
00519 NS_METHOD MRJPlugin::SpendTime(PRUint32 timeMillis)
00520 {
00521     nsresult result = NS_OK;
00522     // Only do this if there aren't any plugin instances.
00523     if (MRJPluginInstance::getInstances() == NULL) {
00524         if (mSession == NULL)
00525             result = StartupJVM();
00526         if (mSession != NULL)
00527             mSession->idle(timeMillis);
00528     }
00529     return result;
00530 }
00531 
00543 NS_METHOD MRJPlugin::Show()
00544 {
00545     // Launch the system console application.
00546     char consolePath[512];
00547     getJavaConsolePath(consolePath, sizeof(consolePath));
00548     CFURLRef consoleURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)consolePath, strlen(consolePath), false);
00549     if (consoleURL) {
00550         LSOpenCFURLRef(consoleURL, NULL);
00551         CFRelease(consoleURL);
00552     }
00553     return NS_OK;
00554 }
00555 
00556 NS_METHOD MRJPlugin::Hide()
00557 {
00558     // Hide system console?
00559     return NS_OK;
00560 }
00561 
00562 NS_METHOD MRJPlugin::IsVisible(PRBool *result)
00563 {
00564     // *result = IsConsoleRunning();
00565     *result = PR_FALSE;
00566     return NS_OK;
00567 }
00568     
00569 NS_METHOD MRJPlugin::Print(const char* msg, const char* /* encodingName */)
00570 {
00571     // printf onto the console.
00572     return NS_OK;
00573 }
00574 
00575 NS_METHOD MRJPlugin::Run()
00576 {
00577     while (mSession != NULL) {
00578         mSession->idle();
00579         mThreadManager->Sleep();
00580     }
00581     return NS_OK;
00582 }
00583 
00584 MRJPluginInstance* MRJPlugin::getPluginInstance(jobject applet)
00585 {
00586     JNIEnv* env = mSession->getCurrentEnv();
00587     MRJPluginInstance* instance = MRJPluginInstance::getInstances();
00588     while (instance != NULL) {
00589         jobject object = NULL;
00590         if (instance->GetJavaObject(&object) == NS_OK && env->IsSameObject(applet, object)) {
00591             instance->AddRef();
00592             return instance;
00593         }
00594         instance = instance->getNextInstance();
00595     }
00596     return NULL;
00597 }
00598 
00599 MRJPluginInstance* MRJPlugin::getPluginInstance(JNIEnv* jenv)
00600 {
00601 #if !TARGET_CARBON
00602     // Apple will provide an API that maps a JNIEnv to an JMAWTContextRef. We can map this to the MRJContext/Applet/Instance.
00603     MRJPluginInstance* instance = MRJPluginInstance::getInstances();
00604     if (&::JMJNIToAWTContext != NULL) {
00605         JMAWTContextRef contextRef = ::JMJNIToAWTContext(mSession->getSessionRef(), jenv);
00606         if (contextRef != NULL) {
00607             while (instance != NULL) {
00608                 if (instance->getContext()->getContextRef() == contextRef) {
00609                     instance->AddRef();
00610                     return instance;
00611                 }
00612                 instance = instance->getNextInstance();
00613             }
00614         }
00615     } else {
00616         if (instance != NULL) {
00617             instance->AddRef();
00618             return instance;
00619         }
00620     }
00621 #endif
00622     return NULL;
00623 }
00624 
00625 Boolean MRJPlugin::inPluginThread()
00626 {
00627     Boolean result = false;
00628     nsPluginThread *currentThreadID = NULL;
00629     
00630     if (mThreadManager != NULL)
00631         mThreadManager->GetCurrentThread(&currentThreadID);
00632     if ((NULL != currentThreadID) && (NULL != mPluginThreadID)) {
00633         if (currentThreadID == mPluginThreadID) {
00634             result = true;
00635         }
00636     }
00637     
00638     return result;
00639 }
00640 
00641 #pragma mark *** MRJPluginInstance ***
00642 
00643 const InterfaceInfo MRJPluginInstance::sInterfaces[] = {
00644     { NS_IPLUGININSTANCE_IID, INTERFACE_OFFSET(MRJPluginInstance, nsIPluginInstance) },
00645     { NS_IJVMPLUGININSTANCE_IID, INTERFACE_OFFSET(MRJPluginInstance, nsIJVMPluginInstance) },
00646     { NS_IEVENTHANDLER_IID, INTERFACE_OFFSET(MRJPluginInstance, nsIEventHandler) },
00647 };
00648 const UInt32 MRJPluginInstance::kInterfaceCount = sizeof(sInterfaces) / sizeof(InterfaceInfo);
00649 
00650 MRJPluginInstance::MRJPluginInstance(MRJPlugin* plugin)
00651     :   SupportsMixin(this, sInterfaces, kInterfaceCount),
00652         mPeer(NULL), mWindowlessPeer(NULL),
00653         mPlugin(plugin), mSession(plugin->getSession()),
00654         mContext(NULL), mApplet(NULL), mPluginWindow(NULL),
00655         mNext(NULL)
00656 {
00657     // add this instance to the instance list.
00658     pushInstance();
00659 
00660     // Tell the plugin we are retaining a reference.
00661     mPlugin->AddRef();
00662 }
00663 
00664 MRJPluginInstance::~MRJPluginInstance()
00665 {
00666     // Remove this instance from the global list.
00667     popInstance();
00668 
00669 #if 0
00670     if (mContext != NULL) {
00671         delete mContext;
00672         mContext = NULL;
00673     }
00674 
00675     if (mPlugin != NULL) {
00676         mPlugin->Release();
00677         mPlugin = NULL;
00678     }
00679 
00680     if (mWindowlessPeer != NULL) {
00681         mWindowlessPeer->Release();
00682         mWindowlessPeer = NULL;
00683     }
00684 
00685     if (mPeer != NULL) {
00686         mPeer->Release();
00687         mPeer = NULL;
00688     }
00689 
00690     if (mApplet != NULL) {
00691         JNIEnv* env = mSession->getCurrentEnv();
00692         env->DeleteGlobalRef(mApplet);
00693         mApplet = NULL;
00694     }
00695 #endif
00696 }
00697 
00698 static const char* kGetCodeBaseScriptURL = "javascript:var href = window.location.href; href.substring(0, href.lastIndexOf('/') + 1)";
00699 static const char* kGetDocumentBaseScriptURL = "javascript:window.location";
00700 
00701 static bool hasTagInfo(nsISupports* supports)
00702 {
00703     nsIJVMPluginTagInfo* tagInfo;
00704     if (supports->QueryInterface(NS_GET_IID(nsIJVMPluginTagInfo), (void**)&tagInfo) == NS_OK) {
00705         NS_RELEASE(tagInfo);
00706         return true;
00707     }
00708     return false;
00709 }
00710 
00711 NS_METHOD MRJPluginInstance::Initialize(nsIPluginInstancePeer* peer)
00712 {
00713     // Tell the peer we are retaining a reference.
00714     mPeer = peer;
00715     mPeer->AddRef();
00716 
00717     // See if we have a windowless peer.
00718     nsresult result = mPeer->QueryInterface(kIWindowlessPluginInstancePeerIID, (void**)&mWindowlessPeer);
00719     if (result != NS_OK) mWindowlessPeer = NULL;
00720 
00721     // create a context for the applet we will run.
00722     mContext = new MRJContext(mSession, this);
00723 
00724     if (hasTagInfo(mPeer)) {
00725         mContext->processAppletTag();
00726         mContext->createContext();
00727     } else {
00728         // we'll be using JavaScript to create windows.
00729         // fire up a JavaScript URL to get the current document's location.
00730         nsIPluginInstance* pluginInstance = this;
00731         nsIPluginStreamListener* listener = this;
00732         result = thePluginManager->GetURL(pluginInstance, kGetDocumentBaseScriptURL, NULL, listener);
00733     }
00734 
00735     return NS_OK;
00736 }
00737 
00738 NS_METHOD MRJPluginInstance::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 length)
00739 {
00740     // hopefully all our data is available.
00741     char* documentBase = new char[length + 1];
00742     if (documentBase != NULL) {
00743         if (input->Read(documentBase, length, &length) == NS_OK) {
00744             // We've delayed processing the applet tag, because we
00745             // don't know the location of the current document yet.
00746             documentBase[length] = '\0';
00747             
00748             // set up the default document location, which can be used to compute relative CODEBASE, etc.
00749             mContext->setDocumentBase(documentBase);
00750             delete[] documentBase;
00751             
00752             mContext->processAppletTag();
00753             mContext->createContext();
00754             
00755             // SetWindow may be called at an inopportune time.
00756             if (mPluginWindow != NULL)
00757                 mContext->setWindow(mPluginWindow);
00758         }
00759     }
00760     return NS_OK;
00761 }
00762 
00763 NS_METHOD MRJPluginInstance::GetPeer(nsIPluginInstancePeer* *result)
00764 {
00765     NS_IF_ADDREF(mPeer);
00766     *result = mPeer;
00767     return NS_OK;
00768 }
00769 
00770 NS_METHOD MRJPluginInstance::Start()
00771 {
00772     // Take this moment to show the applet's frames (if any).
00773     mContext->showFrames();
00774     
00775     mContext->resumeApplet();
00776     
00777     return NS_OK;
00778 }
00779 
00780 NS_METHOD MRJPluginInstance::Stop()
00781 {
00782     // Take this moment to hide the applet's frames.
00783     mContext->hideFrames();
00784 
00785     mContext->suspendApplet();
00786 
00787     return NS_OK;
00788 }
00789 
00790 NS_METHOD MRJPluginInstance::Destroy()
00791 {
00792     // Use this opportunity to break any cycles that might exist, and reduce
00793     // reference counts to their minimum values.
00794     if (mContext != NULL) {
00795         delete mContext;
00796         mContext = NULL;
00797     }
00798 
00799     if (mPlugin != NULL) {
00800         mPlugin->Release();
00801         mPlugin = NULL;
00802     }
00803 
00804     if (mWindowlessPeer != NULL) {
00805         mWindowlessPeer->Release();
00806         mWindowlessPeer = NULL;
00807     }
00808 
00809     if (mPeer != NULL) {
00810         mPeer->Release();
00811         mPeer = NULL;
00812     }
00813 
00814     if (mApplet != NULL) {
00815         JNIEnv* env = mSession->getCurrentEnv();
00816         env->DeleteGlobalRef(mApplet);
00817         mApplet = NULL;
00818     }
00819 
00820     return NS_OK;
00821 }
00822 
00825 NS_METHOD MRJPluginInstance::SetWindow(nsPluginWindow* pluginWindow)
00826 {
00827     mPluginWindow = pluginWindow;
00828 
00829     mContext->setWindow(pluginWindow);
00830 
00831     return NS_OK;
00832 }
00833 
00834 NS_METHOD MRJPluginInstance::HandleEvent(nsPluginEvent* pluginEvent, PRBool* eventHandled)
00835 {
00836     *eventHandled = PR_TRUE;
00837     Boolean isUpdate;
00838 
00839     if (pluginEvent != NULL) {
00840         EventRecord* event = pluginEvent->event;
00841 
00842         // Check for coordinate/clipping changes.
00843         // Too bad nsPluginEventType_ClippingChangedEvent events aren't implemented.
00844         isUpdate = (event->what == updateEvt);
00845         inspectInstance(isUpdate);
00846     
00847         if (event->what == nullEvent) {
00848             // Give Java another quantum of time. We don't need this on Mac OS X.
00849             mSession->idle(0x00000400); // now SpendTime does this.
00850         } else {
00851 #if TARGET_CARBON
00852             *eventHandled = mContext->handleEvent(event);
00853 #else
00854             MRJFrame* frame = mContext->findFrame(pluginEvent->window);
00855             if (frame != NULL) {
00856                 switch (event->what) {
00857                 case nsPluginEventType_GetFocusEvent:
00858                     frame->focusEvent(true);
00859                     break;
00860                 
00861                 case nsPluginEventType_LoseFocusEvent:
00862                     frame->focusEvent(false);
00863                     break;
00864 
00865                 case nsPluginEventType_AdjustCursorEvent:
00866                     frame->idle(event->modifiers);
00867                     break;
00868                 
00869                 case nsPluginEventType_MenuCommandEvent:
00870                     frame->menuSelected(event->message, event->modifiers);
00871                     break;
00872                     
00873                 default:
00874                     *eventHandled = frame->handleEvent(event);
00875                     break;
00876                 }
00877             } else {
00878                 if (event->what == updateEvt) {
00879                     mContext->drawApplet();
00880                 }
00881             }
00882 #endif
00883         }
00884     }
00885     
00886     return NS_OK;
00887 }
00888 
00889 NS_METHOD MRJPluginInstance::Print(nsPluginPrint* platformPrint)
00890 {
00891     if (platformPrint->mode == nsPluginMode_Embedded) {
00892         mContext->printApplet(&platformPrint->print.embedPrint.window);
00893         return NS_OK;
00894     }
00895     return NS_ERROR_NOT_IMPLEMENTED;
00896 }
00897 
00898 NS_METHOD MRJPluginInstance::GetValue(nsPluginInstanceVariable variable, void *value)
00899 {
00900     switch (variable) {
00901     case nsPluginInstanceVariable_WindowlessBool:
00902         *(PRBool*)value = PR_FALSE;
00903         break;
00904     case nsPluginInstanceVariable_TransparentBool:
00905         *(PRBool*)value = PR_FALSE;
00906         break;
00907     case nsPluginInstanceVariable_DoCacheBool:
00908         *(PRBool*)value = PR_FALSE;
00909         break;
00910     default:
00911         break;
00912     }
00913     return NS_OK;
00914 }
00915 
00916 NS_METHOD MRJPluginInstance::GetJavaObject(jobject *result)
00917 {
00918     if (mApplet == NULL) {
00919         jobject applet = mContext->getApplet();
00920         JNIEnv* env = mSession->getCurrentEnv();
00921         mApplet = env->NewGlobalRef(applet);
00922     }
00923     *result = mApplet;
00924     return NS_OK;
00925 }
00926 
00927 // Accessing the list of instances.
00928 
00929 static MRJPluginInstance* theInstances = NULL;
00930 
00931 void MRJPluginInstance::pushInstance()
00932 {
00933     mNext = theInstances;
00934     theInstances = this;
00935 }
00936 
00937 void MRJPluginInstance::popInstance()
00938 {
00939     MRJPluginInstance** link = &theInstances;
00940     MRJPluginInstance* instance  = *link;
00941     while (instance != NULL) {
00942         if (instance == this) {
00943             *link = mNext;
00944             mNext = NULL;
00945             break;
00946         }
00947         link = &instance->mNext;
00948         instance = *link;
00949     }
00950 }
00951 
00952 MRJPluginInstance* MRJPluginInstance::getInstances()
00953 {
00954     return theInstances;
00955 }
00956 
00957 MRJPluginInstance* MRJPluginInstance::getNextInstance()
00958 {
00959     return mNext;
00960 }
00961 
00962 MRJContext* MRJPluginInstance::getContext()
00963 {
00964     return mContext;
00965 }
00966 
00967 MRJSession* MRJPluginInstance::getSession()
00968 {
00969     return mSession;
00970 }
00971 
00972 void MRJPluginInstance::inspectInstance(Boolean isUpdateEvt)
00973 {
00974     if (mContext != NULL && mContext->inspectWindow() && !isUpdateEvt && mWindowlessPeer != NULL)
00975         mWindowlessPeer->ForceRedraw();
00976 }