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