Improve plugin loading code, make it more efficient and easier to understand. Allow Mac OS X plugins to modify their NPAPI function table. b=543405 r=jst

This commit is contained in:
Josh Aas 2010-04-07 18:14:54 -04:00
Родитель bcf48bea34
Коммит aaff52da2b
4 изменённых файлов: 93 добавлений и 308 удалений

Просмотреть файл

@ -47,7 +47,7 @@
interface nsIPluginInstance;
[uuid(15246FD3-29FB-4354-8811-AD8B53661B71)]
[uuid(843D6092-2BB0-4A21-8827-0510A52CA795)]
interface nsIPlugin : nsISupports
{
/**
@ -57,17 +57,6 @@ interface nsIPlugin : nsISupports
*/
void createPluginInstance(out nsIPluginInstance aResult);
/**
* Initializes the plugin and will be called before any new instances are
* created. It is passed browserInterfaces on which QueryInterface
* may be used to obtain an nsIPluginManager, and other interfaces.
*
* @param browserInterfaces - an object that allows access to other browser
* interfaces via QueryInterface
* @result - NS_OK if this operation was successful
*/
void initialize();
/**
* Called when the browser is done with the plugin factory, or when
* the plugin is disabled by the user.

Просмотреть файл

@ -201,8 +201,7 @@ void NS_NotifyPluginCall(PRIntervalTime startTime)
runTime);
}
void
nsNPAPIPlugin::CheckClassInitialized()
static void CheckClassInitialized()
{
static PRBool initialized = PR_FALSE;
@ -219,68 +218,16 @@ nsNPAPIPlugin::CheckClassInitialized()
NS_IMPL_ISUPPORTS1(nsNPAPIPlugin, nsIPlugin)
nsNPAPIPlugin::nsNPAPIPlugin(NPPluginFuncs* callbacks,
PluginLibrary* aLibrary)
nsNPAPIPlugin::nsNPAPIPlugin()
{
memset((void*) &mPluginFuncs, 0, sizeof(mPluginFuncs));
mPluginFuncs.size = sizeof(mPluginFuncs);
mLibrary = nsnull;
#if defined(XP_WIN) || defined(XP_OS2)
// On Windows and OS/2 we need to keep a direct reference to
// the plugin's function struct, we can't just copy it. See
// Mozilla bug 85334.
NPError gepError;
nsresult gepResult = aLibrary->NP_GetEntryPoints(&mPluginFuncs, &gepError);
if (gepResult != NS_OK || gepError != NPERR_NO_ERROR)
return;
NS_ASSERTION(HIBYTE(mPluginFuncs.version) >= NP_VERSION_MAJOR,
"callback version is less than NP version");
#elif defined(XP_MACOSX)
NPPluginFuncs np_callbacks;
memset((void*) &np_callbacks, 0, sizeof(np_callbacks));
np_callbacks.size = sizeof(np_callbacks);
if (!aLibrary->HasRequiredFunctions()) {
NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
return;
}
// we call NP_Initialize before getting function pointers to match
// WebKit's behavior. They implemented this first on Mac OS X.
NPError initError;
nsresult initResult = aLibrary->NP_Initialize(&(sBrowserFuncs), &initError);
if (initResult != NS_OK || initError != NPERR_NO_ERROR)
return;
NPError gepError;
nsresult gepResult = aLibrary->NP_GetEntryPoints(&np_callbacks, &gepError);
if (gepResult != NS_OK || gepError != NPERR_NO_ERROR)
return;
mPluginFuncs.version = np_callbacks.version;
mPluginFuncs.newp = (NPP_NewProcPtr)np_callbacks.newp;
mPluginFuncs.destroy = (NPP_DestroyProcPtr)np_callbacks.destroy;
mPluginFuncs.setwindow = (NPP_SetWindowProcPtr)np_callbacks.setwindow;
mPluginFuncs.newstream = (NPP_NewStreamProcPtr)np_callbacks.newstream;
mPluginFuncs.destroystream = (NPP_DestroyStreamProcPtr)np_callbacks.destroystream;
mPluginFuncs.asfile = (NPP_StreamAsFileProcPtr)np_callbacks.asfile;
mPluginFuncs.writeready = (NPP_WriteReadyProcPtr)np_callbacks.writeready;
mPluginFuncs.write = (NPP_WriteProcPtr)np_callbacks.write;
mPluginFuncs.print = (NPP_PrintProcPtr)np_callbacks.print;
mPluginFuncs.event = (NPP_HandleEventProcPtr)np_callbacks.event;
mPluginFuncs.urlnotify = (NPP_URLNotifyProcPtr)np_callbacks.urlnotify;
mPluginFuncs.getvalue = (NPP_GetValueProcPtr)np_callbacks.getvalue;
mPluginFuncs.setvalue = (NPP_SetValueProcPtr)np_callbacks.setvalue;
#else // for everyone else
memcpy((void*) &mPluginFuncs, (void*) callbacks, sizeof(mPluginFuncs));
#if defined(XP_MACOSX) && !defined(__LP64__)
mPluginRefNum = -1;
#endif
mLibrary = aLibrary;
mLibrary->SetPlugin(this);
memset((void*)&mPluginFuncs, 0, sizeof(mPluginFuncs));
mPluginFuncs.size = sizeof(mPluginFuncs);
mLibrary = nsnull;
}
nsNPAPIPlugin::~nsNPAPIPlugin()
@ -288,10 +235,9 @@ nsNPAPIPlugin::~nsNPAPIPlugin()
// reset the callbacks list
memset((void*) &mPluginFuncs, 0, sizeof(mPluginFuncs));
delete mLibrary;
mLibrary = NULL;
mLibrary = nsnull;
}
#if defined(XP_MACOSX)
void
nsNPAPIPlugin::SetPluginRefNum(short aRefNum)
@ -419,235 +365,78 @@ GetNewPluginLibrary(const char* aFilePath,
} /* anonymous namespace */
// Creates the nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).
// Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).
nsresult
nsNPAPIPlugin::CreatePlugin(const char* aFilePath, PRLibrary* aLibrary,
nsIPlugin** aResult)
{
*aResult = nsnull;
CheckClassInitialized();
#if defined(XP_UNIX) && !defined(XP_MACOSX)
nsNPAPIPlugin *plptr;
NPPluginFuncs callbacks;
memset((void*) &callbacks, 0, sizeof(callbacks));
callbacks.size = sizeof(callbacks);
PluginLibrary* pluginLib = GetNewPluginLibrary(aFilePath, aLibrary);
// create the new plugin handler
*aResult = plptr = new nsNPAPIPlugin(&callbacks, pluginLib);
if (*aResult == NULL)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
// Do not initialize if the file path is NULL.
if (!aFilePath)
return NS_OK;
// we must init here because the plugin may call NPN functions
// when we call into the NP_Initialize entry point - NPN functions
// require that mBrowserManager be set up
plptr->Initialize();
NPError initError;
nsresult initResult = pluginLib->NP_Initialize(&(sBrowserFuncs),&callbacks, &initError);
if (initResult != NS_OK || initError != NPERR_NO_ERROR) {
NS_RELEASE(*aResult);
return NS_ERROR_UNEXPECTED;
}
// now copy function table back to nsNPAPIPlugin instance
memcpy((void*) &(plptr->mPluginFuncs), (void*)&callbacks, sizeof(callbacks));
#endif
#ifdef XP_WIN
PluginLibrary* pluginLib = GetNewPluginLibrary(aFilePath, aLibrary);
// Note: on Windows, we must use the fCallback because plugins may
// change the function table. The Shockwave installer makes changes
// in the table while running
*aResult = new nsNPAPIPlugin(nsnull, pluginLib);
if (*aResult == NULL)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
// we must init here because the plugin may call NPN functions
// when we call into the NP_Initialize entry point - NPN functions
// require that mBrowserManager be set up
if (NS_FAILED((*aResult)->Initialize())) {
NS_RELEASE(*aResult);
return NS_ERROR_FAILURE;
}
NPError initError;
nsresult initResult = pluginLib->NP_Initialize(&(sBrowserFuncs), &initError);
if (initResult != NS_OK || initError != NPERR_NO_ERROR)
return NS_ERROR_FAILURE;
#endif
#ifdef XP_OS2
PluginLibrary* pluginLib = GetNewPluginLibrary(aFilePath, aLibrary);
// create the new plugin handler
*aResult = new nsNPAPIPlugin(nsnull, pluginLib);
if (*aResult == NULL)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
// we must init here because the plugin may call NPN functions
// when we call into the NP_Initialize entry point - NPN functions
// require that mBrowserManager be set up
if (NS_FAILED((*aResult)->Initialize())) {
NS_RELEASE(*aResult);
return NS_ERROR_FAILURE;
}
NP_PLUGININIT pfnInitialize =
(NP_PLUGININIT)PR_FindSymbol(aLibrary, "NP_Initialize");
if (!pfnInitialize)
return NS_ERROR_UNEXPECTED;
// Fixes problem where the OS/2 native multimedia plugins weren't
// working on mozilla though did work on 4.x. Problem is that they
// expect the current working directory to be the plugins dir.
// Since these plugins are no longer maintained and they represent
// the majority of the OS/2 plugin contingency, we'll have to make
// them work here.
#define MAP_DISKNUM_TO_LETTER(n) ('A' + (n - 1))
#define MAP_LETTER_TO_DISKNUM(c) (toupper(c)-'A'+1)
unsigned long origDiskNum, pluginDiskNum, logicalDisk;
char pluginPath[CCHMAXPATH], origPath[CCHMAXPATH];
strcpy(pluginPath, aFilePath);
char* slash = strrchr(pluginPath, '\\');
*slash = '\0';
DosQueryCurrentDisk( &origDiskNum, &logicalDisk );
pluginDiskNum = MAP_LETTER_TO_DISKNUM(pluginPath[0]);
origPath[0] = MAP_DISKNUM_TO_LETTER(origDiskNum);
origPath[1] = ':';
origPath[2] = '\\';
ULONG len = CCHMAXPATH-3;
APIRET rc = DosQueryCurrentDir(0, &origPath[3], &len);
NS_ASSERTION(NO_ERROR == rc,"DosQueryCurrentDir failed");
BOOL bChangedDir = FALSE;
BOOL bChangedDisk = FALSE;
if (pluginDiskNum != origDiskNum) {
rc = DosSetDefaultDisk(pluginDiskNum);
NS_ASSERTION(NO_ERROR == rc,"DosSetDefaultDisk failed");
bChangedDisk = TRUE;
}
if (stricmp(origPath, pluginPath) != 0) {
rc = DosSetCurrentDir(pluginPath);
NS_ASSERTION(NO_ERROR == rc,"DosSetCurrentDir failed");
bChangedDir = TRUE;
}
nsresult rv = pfnInitialize(&(sBrowserFuncs));
if (bChangedDisk) {
rc= DosSetDefaultDisk(origDiskNum);
NS_ASSERTION(NO_ERROR == rc,"DosSetDefaultDisk failed");
}
if (bChangedDir) {
rc = DosSetCurrentDir(origPath);
NS_ASSERTION(NO_ERROR == rc,"DosSetCurrentDir failed");
}
if (!NS_SUCCEEDED(rv)) {
return NS_ERROR_UNEXPECTED;
}
#endif
#if defined(XP_MACOSX)
#ifndef __LP64__
short appRefNum = ::CurResFile();
short pluginRefNum;
nsCOMPtr<nsILocalFile> pluginPath;
NS_NewNativeLocalFile(nsDependentCString(aFilePath), PR_TRUE,
getter_AddRefs(pluginPath));
nsPluginFile pluginFile(pluginPath);
pluginRefNum = pluginFile.OpenPluginResource();
#endif
PluginLibrary* pluginLib = GetNewPluginLibrary(aFilePath, aLibrary);
nsNPAPIPlugin* plugin = new nsNPAPIPlugin(nsnull, pluginLib);
#ifndef __LP64__
::UseResFile(appRefNum);
#endif
nsRefPtr<nsNPAPIPlugin> plugin = new nsNPAPIPlugin();
if (!plugin)
return NS_ERROR_OUT_OF_MEMORY;
*aResult = plugin;
NS_ADDREF(*aResult);
if (NS_FAILED((*aResult)->Initialize())) {
NS_RELEASE(*aResult);
PluginLibrary* pluginLib = GetNewPluginLibrary(aFilePath, aLibrary);
if (!pluginLib) {
return NS_ERROR_FAILURE;
}
#ifndef __LP64__
plugin->SetPluginRefNum(pluginRefNum);
#endif
#endif
#ifdef XP_BEOS
// I just copied UNIX version.
// Makoto Hamanaka <VYA04230@nifty.com>
// XXX this code won't compile with the new e10s changes
nsNPAPIPlugin *plptr;
NPPluginFuncs callbacks;
memset((void*) &callbacks, 0, sizeof(callbacks));
callbacks.size = sizeof(callbacks);
NP_PLUGINSHUTDOWN pfnShutdown =
(NP_PLUGINSHUTDOWN)PR_FindSymbol(aLibrary, "NP_Shutdown");
// create the new plugin handler
*aResult = plptr = new nsNPAPIPlugin(&callbacks, aLibrary, pfnShutdown);
if (*aResult == NULL)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
// we must init here because the plugin may call NPN functions
// when we call into the NP_Initialize entry point - NPN functions
// require that mBrowserManager be set up
plptr->Initialize();
NP_PLUGINUNIXINIT pfnInitialize =
(NP_PLUGINUNIXINIT)PR_FindSymbol(aLibrary, "NP_Initialize");
if (!pfnInitialize)
#ifdef XP_MACOSX
if (!pluginLib->HasRequiredFunctions()) {
NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
return NS_ERROR_FAILURE;
if (pfnInitialize(&(sBrowserFuncs),&callbacks) != NS_OK)
return NS_ERROR_FAILURE;
// now copy function table back to nsNPAPIPlugin instance
memcpy((void*) &(plptr->mPluginFuncs), (void*)&callbacks, sizeof(callbacks));
}
#endif
plugin->mLibrary = pluginLib;
pluginLib->SetPlugin(plugin);
#if defined(XP_UNIX) && !defined(XP_MACOSX)
// Do not initialize if the file path is NULL.
if (!aFilePath) {
*aResult = plugin.forget().get();
return NS_OK;
}
#endif
NPError pluginCallError;
nsresult rv;
// Exchange NPAPI entry points.
#if defined(XP_WIN) || defined(XP_OS2)
// NP_GetEntryPoints must be called before NP_Initialize on Windows.
rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError);
if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
return NS_ERROR_FAILURE;
}
// NP_Initialize must be called after NP_GetEntryPoints on Windows.
rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError);
if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
return NS_ERROR_FAILURE;
}
#elif defined(XP_MACOSX)
// NP_Initialize must be called before NP_GetEntryPoints on Mac OS X.
// We need to match WebKit's behavior.
rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError);
if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
return NS_ERROR_FAILURE;
}
rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError);
if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
return NS_ERROR_FAILURE;
}
#else
rv = pluginLib->NP_Initialize(&sBrowserFuncs, &plugin->mPluginFuncs, &pluginCallError);
if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
return NS_ERROR_FAILURE;
}
#endif
*aResult = plugin.forget().get();
return NS_OK;
}
@ -669,14 +458,6 @@ nsNPAPIPlugin::CreatePluginInstance(nsIPluginInstance **aResult)
return NS_OK;
}
nsresult
nsNPAPIPlugin::Initialize()
{
if (!mLibrary)
return NS_ERROR_FAILURE;
return NS_OK;
}
nsresult
nsNPAPIPlugin::Shutdown()
{

Просмотреть файл

@ -76,8 +76,7 @@ private:
typedef mozilla::PluginLibrary PluginLibrary;
public:
nsNPAPIPlugin(NPPluginFuncs* callbacks,
PluginLibrary* aLibrary /*assume ownership*/);
nsNPAPIPlugin();
virtual ~nsNPAPIPlugin();
NS_DECL_ISUPPORTS
@ -87,7 +86,8 @@ public:
// will prevent this from calling NP_Initialize.
static nsresult CreatePlugin(const char* aFilePath, PRLibrary* aLibrary,
nsIPlugin** aResult);
#ifdef XP_MACOSX
#if defined(XP_MACOSX) && !defined(__LP64__)
void SetPluginRefNum(short aRefNum);
#endif
@ -101,15 +101,11 @@ public:
#endif
protected:
// Ensures that the static browser functions are properly initialized
static void CheckClassInitialized();
#ifdef XP_MACOSX
#if defined(XP_MACOSX) && !defined(__LP64__)
short mPluginRefNum;
#endif
// The plugin-side callbacks that the browser calls. One set of
// plugin callbacks for each plugin.
NPPluginFuncs mPluginFuncs;
PluginLibrary* mLibrary;
};

Просмотреть файл

@ -3040,9 +3040,28 @@ static nsresult CreateNPAPIPlugin(const nsPluginTag *aPluginTag,
fullPath = aPluginTag->mFullPath;
}
return nsNPAPIPlugin::CreatePlugin(fullPath.get(),
#if defined(XP_MACOSX) && !defined(__LP64__)
short appRefNum = ::CurResFile();
nsCOMPtr<nsILocalFile> pluginPath;
NS_NewNativeLocalFile(nsDependentCString(fullPath.get()), PR_TRUE,
getter_AddRefs(pluginPath));
nsPluginFile pluginFile(pluginPath);
short pluginRefNum = pluginFile.OpenPluginResource();
#endif
rv = nsNPAPIPlugin::CreatePlugin(fullPath.get(),
aPluginTag->mLibrary,
aOutNPAPIPlugin);
#if defined(XP_MACOSX) && !defined(__LP64__)
if (NS_SUCCEEDED(rv))
static_cast<nsNPAPIPlugin*>(*aOutNPAPIPlugin)->SetPluginRefNum(pluginRefNum);
else if (pluginRefNum > 0)
::CloseResFile(pluginRefNum);
::UseResFile(appRefNum);
#endif
return rv;
}
NS_IMETHODIMP nsPluginHost::GetPlugin(const char *aMimeType, nsIPlugin** aPlugin)