Separate plugin tag code from the plugin host. b=533371 r=jst

This commit is contained in:
Josh Aas 2009-12-16 08:16:42 -05:00
parent 0ce7b2a2ba
commit a2cdef8b23
5 changed files with 1019 additions and 902 deletions

View File

@ -57,6 +57,7 @@ CPPSRCS = \
nsPluginHost.cpp \
nsPluginModule.cpp \
nsJSNPRuntime.cpp \
nsPluginTags.cpp \
$(NULL)
ifeq ($(OS_ARCH), BeOS)

View File

@ -92,7 +92,6 @@
#include "nsEnumeratorUtils.h"
#include "nsXPCOM.h"
#include "nsXPCOMCID.h"
#include "nsICategoryManager.h"
#include "nsISupportsPrimitives.h"
// for the dialog
@ -226,8 +225,6 @@ PRLogModuleInfo* nsPluginLogging::gPluginLog = nsnull;
#define MAGIC_REQUEST_CONTEXT 0x01020304
nsresult PostPluginUnloadEvent(PRLibrary * aLibrary);
static nsPluginInstanceTagList *gActivePluginList;
#ifdef CALL_SAFETY_ON
@ -309,619 +306,6 @@ NS_IMETHODIMP nsPluginDocReframeEvent::Run() {
return mDocs->Clear();
}
nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance,
const char * url,
PRBool aDefaultPlugin)
{
mNext = nsnull;
mPluginTag = aPluginTag;
mURL = PL_strdup(url);
mInstance = aInstance;
if (aInstance)
NS_ADDREF(aInstance);
mXPConnected = PR_FALSE;
mDefaultPlugin = aDefaultPlugin;
mStopped = PR_FALSE;
mllStopTime = LL_ZERO;
}
nsPluginInstanceTag::~nsPluginInstanceTag()
{
mPluginTag = nsnull;
if (mInstance) {
nsCOMPtr<nsIPluginInstanceOwner> owner;
mInstance->GetOwner(getter_AddRefs(owner));
if (owner)
owner->SetInstance(nsnull);
mInstance->InvalidateOwner();
NS_RELEASE(mInstance);
}
PL_strfree(mURL);
}
void nsPluginInstanceTag::setStopped(PRBool stopped)
{
mStopped = stopped;
if (mStopped) // plugin instance is told to stop
mllStopTime = PR_Now();
else
mllStopTime = LL_ZERO;
}
nsPluginInstanceTagList::nsPluginInstanceTagList()
{
mFirst = nsnull;
mLast = nsnull;
mCount = 0;
}
nsPluginInstanceTagList::~nsPluginInstanceTagList()
{
if (!mFirst)
return;
shutdown();
}
void nsPluginInstanceTagList::shutdown()
{
if (!mFirst)
return;
for (nsPluginInstanceTag * plugin = mFirst; plugin != nsnull;) {
nsPluginInstanceTag * next = plugin->mNext;
remove(plugin);
plugin = next;
}
mFirst = nsnull;
mLast = nsnull;
}
PRInt32 nsPluginInstanceTagList::add(nsPluginInstanceTag * plugin)
{
if (!mFirst) {
mFirst = plugin;
mLast = plugin;
mFirst->mNext = nsnull;
}
else {
mLast->mNext = plugin;
mLast = plugin;
}
mLast->mNext = nsnull;
mCount++;
return mCount;
}
PRBool nsPluginInstanceTagList::IsLastInstance(nsPluginInstanceTag * plugin)
{
if (!plugin)
return PR_FALSE;
if (!plugin->mPluginTag)
return PR_FALSE;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if ((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
return PR_FALSE;
}
return PR_TRUE;
}
PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin)
{
if (!mFirst)
return PR_FALSE;
nsPluginInstanceTag * prev = nsnull;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (p == plugin) {
PRBool lastInstance = IsLastInstance(p);
if (p == mFirst)
mFirst = p->mNext;
else
prev->mNext = p->mNext;
if (prev && !prev->mNext)
mLast = prev;
if (lastInstance) {
nsRefPtr<nsPluginTag> pluginTag = p->mPluginTag;
delete p;
if (pluginTag) {
nsresult rv;
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
PRBool unloadPluginsASAP = PR_FALSE;
rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
pluginTag->TryUnloadPlugin();
} else {
NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
}
} else {
delete p;
}
mCount--;
return PR_TRUE;
}
prev = p;
}
return PR_FALSE;
}
// This method terminates all running instances of plugins and collects their
// documents to be returned through an array. This method is used
// when we are shutting down or when a plugins.refresh(1) happens.
// If aPluginTag is given, then only that plugin is terminated
void nsPluginInstanceTagList::stopRunning(nsISupportsArray* aReloadDocs,
nsPluginTag* aPluginTag)
{
if (!mFirst)
return;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (!p->mStopped && p->mInstance &&
(!aPluginTag || aPluginTag == p->mPluginTag)) {
p->mInstance->SetWindow(nsnull);
p->mInstance->Stop();
p->setStopped(PR_TRUE);
// If we've been passed an array to return, lets collect all our documents,
// removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
// to kickstart our instances.
if (aReloadDocs && p->mInstance) {
nsCOMPtr<nsIPluginInstanceOwner> owner;
p->mInstance->GetOwner(getter_AddRefs(owner));
if (owner) {
nsCOMPtr<nsIDocument> doc;
owner->GetDocument(getter_AddRefs(doc));
if (doc && aReloadDocs->IndexOf(doc) == -1) // don't allow for duplicates
aReloadDocs->AppendElement(doc);
}
}
}
}
}
void nsPluginInstanceTagList::removeAllStopped()
{
if (!mFirst)
return;
nsPluginInstanceTag * next = nsnull;
for (nsPluginInstanceTag * p = mFirst; p != nsnull;) {
next = p->mNext;
if (p->mStopped)
remove(p);
p = next;
}
return;
}
nsPluginInstanceTag * nsPluginInstanceTagList::find(nsIPluginInstance* instance)
{
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (p->mInstance == instance)
return p;
}
return nsnull;
}
nsPluginInstanceTag * nsPluginInstanceTagList::find(const char * mimetype)
{
PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
// give it some special treatment for the default plugin first
// because we cannot tell the default plugin by asking instance for a mime type
if (defaultplugin && p->mDefaultPlugin)
return p;
if (!p->mInstance)
continue;
const char* mt;
nsresult rv = p->mInstance->GetMIMEType(&mt);
if (NS_FAILED(rv))
continue;
if (PL_strcasecmp(mt, mimetype) == 0)
return p;
}
return nsnull;
}
nsPluginInstanceTag * nsPluginInstanceTagList::findStopped(const char * url)
{
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (!PL_strcmp(url, p->mURL) && p->mStopped)
return p;
}
return nsnull;
}
PRUint32 nsPluginInstanceTagList::getStoppedCount()
{
PRUint32 stoppedCount = 0;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (p->mStopped)
stoppedCount++;
}
return stoppedCount;
}
nsPluginInstanceTag * nsPluginInstanceTagList::findOldestStopped()
{
nsPluginInstanceTag * res = nsnull;
PRInt64 llTime = LL_MAXINT;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (!p->mStopped)
continue;
if (LL_CMP(p->mllStopTime, <, llTime)) {
llTime = p->mllStopTime;
res = p;
}
}
return res;
}
inline char* new_str(const char* str)
{
if (str == nsnull)
return nsnull;
char* result = new char[strlen(str) + 1];
if (result != nsnull)
return strcpy(result, str);
return result;
}
nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
: mPluginHost(nsnull),
mName(aPluginTag->mName),
mDescription(aPluginTag->mDescription),
mVariants(aPluginTag->mVariants),
mMimeTypeArray(nsnull),
mMimeDescriptionArray(aPluginTag->mMimeDescriptionArray),
mExtensionsArray(nsnull),
mLibrary(nsnull),
mCanUnloadLibrary(PR_TRUE),
mXPConnected(PR_FALSE),
mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin),
mFileName(aPluginTag->mFileName),
mFullPath(aPluginTag->mFullPath),
mVersion(aPluginTag->mVersion),
mLastModifiedTime(0),
mFlags(NS_PLUGIN_FLAG_ENABLED)
{
if (aPluginTag->mMimeTypeArray != nsnull) {
mMimeTypeArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
}
if (aPluginTag->mExtensionsArray != nsnull) {
mExtensionsArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
}
}
nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
: mPluginHost(nsnull),
mName(aPluginInfo->fName),
mDescription(aPluginInfo->fDescription),
mVariants(aPluginInfo->fVariantCount),
mMimeTypeArray(nsnull),
mExtensionsArray(nsnull),
mLibrary(nsnull),
#ifdef XP_MACOSX
mCanUnloadLibrary(!aPluginInfo->fBundle),
#else
mCanUnloadLibrary(PR_TRUE),
#endif
mXPConnected(PR_FALSE),
mIsJavaPlugin(PR_FALSE),
mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
mFileName(aPluginInfo->fFileName),
mFullPath(aPluginInfo->fFullPath),
mVersion(aPluginInfo->fVersion),
mLastModifiedTime(0),
mFlags(NS_PLUGIN_FLAG_ENABLED)
{
if (aPluginInfo->fMimeTypeArray != nsnull) {
mMimeTypeArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++) {
if (mIsJavaPlugin && aPluginInfo->fMimeTypeArray[i] &&
strcmp(aPluginInfo->fMimeTypeArray[i],
"application/x-java-vm-npruntime") == 0) {
mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
// Stop processing here, any mimetypes after the magic "I'm a
// NPRuntime enabled Java plugin" mimetype will be ignored.
mVariants = i;
break;
}
mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
mIsJavaPlugin = PR_TRUE;
}
}
if (aPluginInfo->fMimeDescriptionArray != nsnull) {
for (int i = 0; i < mVariants; i++) {
// we should cut off the list of suffixes which the mime
// description string may have, see bug 53895
// it is usually in form "some description (*.sf1, *.sf2)"
// so we can search for the opening round bracket
char cur = '\0';
char pre = '\0';
char * p = PL_strrchr(aPluginInfo->fMimeDescriptionArray[i], '(');
if (p && (p != aPluginInfo->fMimeDescriptionArray[i])) {
if ((p - 1) && *(p - 1) == ' ') {
pre = *(p - 1);
*(p - 1) = '\0';
} else {
cur = *p;
*p = '\0';
}
}
mMimeDescriptionArray.AppendElement(
aPluginInfo->fMimeDescriptionArray[i]);
// restore the original string
if (cur != '\0')
*p = cur;
if (pre != '\0')
*(p - 1) = pre;
}
} else {
mMimeDescriptionArray.SetLength(mVariants);
}
if (aPluginInfo->fExtensionArray != nsnull) {
mExtensionsArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
}
EnsureMembersAreUTF8();
}
nsPluginTag::nsPluginTag(const char* aName,
const char* aDescription,
const char* aFileName,
const char* aFullPath,
const char* aVersion,
const char* const* aMimeTypes,
const char* const* aMimeDescriptions,
const char* const* aExtensions,
PRInt32 aVariants,
PRInt64 aLastModifiedTime,
PRBool aCanUnload,
PRBool aArgsAreUTF8)
: mPluginHost(nsnull),
mName(aName),
mDescription(aDescription),
mVariants(aVariants),
mMimeTypeArray(nsnull),
mExtensionsArray(nsnull),
mLibrary(nsnull),
mCanUnloadLibrary(aCanUnload),
mXPConnected(PR_FALSE),
mIsJavaPlugin(PR_FALSE),
mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
mFileName(aFileName),
mFullPath(aFullPath),
mVersion(aVersion),
mLastModifiedTime(aLastModifiedTime),
mFlags(0) // Caller will read in our flags from cache
{
if (aVariants) {
mMimeTypeArray = new char*[mVariants];
mExtensionsArray = new char*[mVariants];
for (PRInt32 i = 0; i < aVariants; ++i) {
if (mIsJavaPlugin && aMimeTypes[i] &&
strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) {
mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
// Stop processing here, any mimetypes after the magic "I'm a
// NPRuntime enabled Java plugin" mimetype will be ignored.
mVariants = i;
break;
}
mMimeTypeArray[i] = new_str(aMimeTypes[i]);
mMimeDescriptionArray.AppendElement(aMimeDescriptions[i]);
mExtensionsArray[i] = new_str(aExtensions[i]);
if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
mIsJavaPlugin = PR_TRUE;
}
}
if (!aArgsAreUTF8)
EnsureMembersAreUTF8();
}
nsPluginTag::~nsPluginTag()
{
NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
if (mMimeTypeArray) {
for (int i = 0; i < mVariants; i++)
delete[] mMimeTypeArray[i];
delete[] (mMimeTypeArray);
mMimeTypeArray = nsnull;
}
if (mExtensionsArray) {
for (int i = 0; i < mVariants; i++)
delete[] mExtensionsArray[i];
delete[] (mExtensionsArray);
mExtensionsArray = nsnull;
}
}
NS_IMPL_ISUPPORTS1(nsPluginTag, nsIPluginTag)
static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
nsAFlatCString& aString)
{
PRInt32 numberOfBytes = aString.Length();
PRInt32 outUnicodeLen;
nsAutoString buffer;
nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
&outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
if (!EnsureStringLength(buffer, outUnicodeLen))
return NS_ERROR_OUT_OF_MEMORY;
rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
buffer.BeginWriting(), &outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
buffer.SetLength(outUnicodeLen);
CopyUTF16toUTF8(buffer, aString);
return NS_OK;
}
nsresult nsPluginTag::EnsureMembersAreUTF8()
{
nsresult rv;
nsCOMPtr<nsIPlatformCharset> pcs =
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUnicodeDecoder> decoder;
nsCOMPtr<nsICharsetConverterManager> ccm =
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString charset;
rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!charset.LowerCaseEqualsLiteral("utf-8")) {
rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
NS_ENSURE_SUCCESS(rv, rv);
ConvertToUTF8(decoder, mFileName);
ConvertToUTF8(decoder, mFullPath);
}
// The description of the plug-in and the various MIME type descriptions
// should be encoded in the standard plain text file encoding for this system.
// XXX should we add kPlatformCharsetSel_PluginResource?
rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!charset.LowerCaseEqualsLiteral("utf-8")) {
rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
NS_ENSURE_SUCCESS(rv, rv);
ConvertToUTF8(decoder, mName);
ConvertToUTF8(decoder, mDescription);
for (PRUint32 i = 0; i < mMimeDescriptionArray.Length(); ++i) {
ConvertToUTF8(decoder, mMimeDescriptionArray[i]);
}
}
return NS_OK;
}
void nsPluginTag::SetHost(nsPluginHost * aHost)
{
mPluginHost = aHost;
}
NS_IMETHODIMP
nsPluginTag::GetDescription(nsACString& aDescription)
{
aDescription = mDescription;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetFilename(nsACString& aFileName)
{
aFileName = mFileName;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetVersion(nsACString& aVersion)
{
aVersion = mVersion;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetName(nsACString& aName)
{
aName = mName;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetDisabled(PRBool* aDisabled)
{
*aDisabled = !HasFlag(NS_PLUGIN_FLAG_ENABLED);
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::SetDisabled(PRBool aDisabled)
{
if (HasFlag(NS_PLUGIN_FLAG_ENABLED) == !aDisabled)
return NS_OK;
if (aDisabled)
UnMark(NS_PLUGIN_FLAG_ENABLED);
else
Mark(NS_PLUGIN_FLAG_ENABLED);
mPluginHost->UpdatePluginInfo(this);
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetBlocklisted(PRBool* aBlocklisted)
{
*aBlocklisted = HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::SetBlocklisted(PRBool aBlocklisted)
{
if (HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED) == aBlocklisted)
return NS_OK;
if (aBlocklisted)
Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
else
UnMark(NS_PLUGIN_FLAG_BLOCKLISTED);
mPluginHost->UpdatePluginInfo(nsnull);
return NS_OK;
}
// helper struct for asynchronous handling of plugin unloading
class nsPluginUnloadEvent : public nsRunnable {
public:
@ -946,7 +330,7 @@ NS_IMETHODIMP nsPluginUnloadEvent::Run()
}
// unload plugin asynchronously if possible, otherwise just unload now
nsresult PostPluginUnloadEvent(PRLibrary* aLibrary)
nsresult nsPluginHost::PostPluginUnloadEvent(PRLibrary* aLibrary)
{
nsCOMPtr<nsIRunnable> ev = new nsPluginUnloadEvent(aLibrary);
if (ev && NS_SUCCEEDED(NS_DispatchToCurrentThread(ev)))
@ -958,99 +342,6 @@ nsresult PostPluginUnloadEvent(PRLibrary* aLibrary)
return NS_ERROR_FAILURE;
}
void nsPluginTag::TryUnloadPlugin()
{
if (mEntryPoint) {
mEntryPoint->Shutdown();
mEntryPoint = nsnull;
}
// before we unload check if we are allowed to, see bug #61388
if (mLibrary && mCanUnloadLibrary) {
// NPAPI plugins can be unloaded now if they don't use XPConnect
if (!mXPConnected) {
// unload the plugin asynchronously by posting a PLEvent
PostPluginUnloadEvent(mLibrary);
}
else {
// add library to the unused library list to handle it later
if (mPluginHost)
mPluginHost->AddUnusedLibrary(mLibrary);
}
}
// we should zero it anyway, it is going to be unloaded by
// CleanUnsedLibraries before we need to call the library
// again so the calling code should not be fooled and reload
// the library fresh
mLibrary = nsnull;
// Remove mime types added to the category manager
// only if we were made 'active' by setting the host
if (mPluginHost) {
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
}
}
void nsPluginTag::Mark(PRUint32 mask)
{
PRBool wasEnabled = IsEnabled();
mFlags |= mask;
// Update entries in the category manager if necessary.
if (mPluginHost && wasEnabled != IsEnabled()) {
if (wasEnabled)
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
else
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
}
}
void nsPluginTag::UnMark(PRUint32 mask)
{
PRBool wasEnabled = IsEnabled();
mFlags &= ~mask;
// Update entries in the category manager if necessary.
if (mPluginHost && wasEnabled != IsEnabled()) {
if (wasEnabled)
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
else
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
}
}
PRBool nsPluginTag::HasFlag(PRUint32 flag)
{
return (mFlags & flag) != 0;
}
PRUint32 nsPluginTag::Flags()
{
return mFlags;
}
PRBool nsPluginTag::IsEnabled()
{
return HasFlag(NS_PLUGIN_FLAG_ENABLED) && !HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
}
PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
{
NS_ENSURE_TRUE(aPluginTag, PR_FALSE);
if ((!mName.Equals(aPluginTag->mName)) ||
(!mDescription.Equals(aPluginTag->mDescription)) ||
(mVariants != aPluginTag->mVariants))
return PR_FALSE;
if (mVariants && mMimeTypeArray && aPluginTag->mMimeTypeArray) {
for (PRInt32 i = 0; i < mVariants; i++) {
if (PL_strcmp(mMimeTypeArray[i], aPluginTag->mMimeTypeArray[i]) != 0)
return PR_FALSE;
}
}
return PR_TRUE;
}
class nsPluginStreamListenerPeer;
class nsPluginStreamInfo : public nsINPAPIPluginStreamInfo
@ -3345,80 +2636,6 @@ nsresult nsPluginHost::AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
return NS_OK;
}
void
nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
nsPluginTag::nsRegisterType aType)
{
if (!mMimeTypeArray)
return;
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
mFileName.get(), aType == ePluginUnregister ? "yes" : "no"));
nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
if (!catMan)
return;
const char *contractId = "@mozilla.org/content/plugin/document-loader-factory;1";
nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!psvc)
return; // NS_ERROR_OUT_OF_MEMORY
// A preference controls whether or not the full page plugin is disabled for
// a particular type. The string must be in the form:
// type1,type2,type3,type4
// Note: need an actual interface to control this and subsequent disabling
// (and other plugin host settings) so applications can reliably disable
// plugins - without relying on implementation details such as prefs/category
// manager entries.
nsXPIDLCString overrideTypes;
psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
nsCAutoString overrideTypesFormatted;
overrideTypesFormatted.Assign(',');
overrideTypesFormatted += overrideTypes;
overrideTypesFormatted.Append(',');
nsACString::const_iterator start, end;
for (int i = 0; i < mVariants; i++) {
if (aType == ePluginUnregister) {
nsXPIDLCString value;
if (NS_SUCCEEDED(catMan->GetCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
getter_Copies(value)))) {
// Only delete the entry if a plugin registered for it
if (strcmp(value, contractId) == 0) {
catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
PR_TRUE);
}
}
} else {
overrideTypesFormatted.BeginReading(start);
overrideTypesFormatted.EndReading(end);
nsDependentCString mimeType(mMimeTypeArray[i]);
nsCAutoString commaSeparated;
commaSeparated.Assign(',');
commaSeparated += mimeType;
commaSeparated.Append(',');
if (!FindInReadable(commaSeparated, start, end)) {
catMan->AddCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
contractId,
PR_FALSE, /* persist: broken by bug 193031 */
aOverrideInternalTypes, /* replace if we're told to */
nsnull);
}
}
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
mMimeTypeArray[i], mFileName.get()));
}
}
NS_IMETHODIMP nsPluginHost::SetUpPluginInstance(const char *aMimeType,
nsIURI *aURL,
nsIPluginInstanceOwner *aOwner)

View File

@ -60,134 +60,17 @@
#include "nsTArray.h"
#include "nsTObserverArray.h"
#include "nsITimer.h"
#include "nsPluginTags.h"
class nsNPAPIPlugin;
class nsIComponentManager;
class nsIFile;
class nsIChannel;
class nsPluginHost;
// Remember that flags are written out to pluginreg.dat, be careful
// changing their meaning.
#define NS_PLUGIN_FLAG_ENABLED 0x0001 // is this plugin enabled?
// no longer used 0x0002 // reuse only if regenerating pluginreg.dat
#define NS_PLUGIN_FLAG_FROMCACHE 0x0004 // this plugintag info was loaded from cache
#define NS_PLUGIN_FLAG_UNWANTED 0x0008 // this is an unwanted plugin
#define NS_PLUGIN_FLAG_BLOCKLISTED 0x0010 // this is a blocklisted plugin
#if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
#define MAC_CARBON_PLUGINS
#endif
// A linked-list of plugin information that is used for instantiating plugins
// and reflecting plugin information into JavaScript.
class nsPluginTag : public nsIPluginTag
{
public:
enum nsRegisterType {
ePluginRegister,
ePluginUnregister
};
NS_DECL_ISUPPORTS
NS_DECL_NSIPLUGINTAG
nsPluginTag(nsPluginTag* aPluginTag);
nsPluginTag(nsPluginInfo* aPluginInfo);
nsPluginTag(const char* aName,
const char* aDescription,
const char* aFileName,
const char* aFullPath,
const char* aVersion,
const char* const* aMimeTypes,
const char* const* aMimeDescriptions,
const char* const* aExtensions,
PRInt32 aVariants,
PRInt64 aLastModifiedTime = 0,
PRBool aCanUnload = PR_TRUE,
PRBool aArgsAreUTF8 = PR_FALSE);
~nsPluginTag();
void SetHost(nsPluginHost * aHost);
void TryUnloadPlugin();
void Mark(PRUint32 mask);
void UnMark(PRUint32 mask);
PRBool HasFlag(PRUint32 flag);
PRUint32 Flags();
PRBool Equals(nsPluginTag* aPluginTag);
PRBool IsEnabled();
void RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
nsRegisterType aType = ePluginRegister);
nsRefPtr<nsPluginTag> mNext;
nsPluginHost *mPluginHost;
nsCString mName; // UTF-8
nsCString mDescription; // UTF-8
PRInt32 mVariants;
char **mMimeTypeArray;
nsTArray<nsCString> mMimeDescriptionArray; // UTF-8
char **mExtensionsArray;
PRLibrary *mLibrary;
nsCOMPtr<nsIPlugin> mEntryPoint;
PRPackedBool mCanUnloadLibrary;
PRPackedBool mXPConnected;
PRPackedBool mIsJavaPlugin;
PRPackedBool mIsNPRuntimeEnabledJavaPlugin;
nsCString mFileName; // UTF-8
nsCString mFullPath; // UTF-8
nsCString mVersion; // UTF-8
PRInt64 mLastModifiedTime;
private:
PRUint32 mFlags;
nsresult EnsureMembersAreUTF8();
};
struct nsPluginInstanceTag
{
nsPluginInstanceTag* mNext;
char* mURL;
nsRefPtr<nsPluginTag> mPluginTag;
nsIPluginInstance* mInstance;
PRTime mllStopTime;
PRPackedBool mStopped;
PRPackedBool mDefaultPlugin;
PRPackedBool mXPConnected;
// Array holding all opened stream listeners for this entry
nsCOMPtr <nsISupportsArray> mStreams;
nsPluginInstanceTag(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance,
const char * url,
PRBool aDefaultPlugin);
~nsPluginInstanceTag();
void setStopped(PRBool stopped);
};
class nsPluginInstanceTagList
{
public:
nsPluginInstanceTag *mFirst;
nsPluginInstanceTag *mLast;
PRInt32 mCount;
nsPluginInstanceTagList();
~nsPluginInstanceTagList();
void shutdown();
PRBool add(nsPluginInstanceTag *plugin);
PRBool remove(nsPluginInstanceTag *plugin);
nsPluginInstanceTag *find(nsIPluginInstance *instance);
nsPluginInstanceTag *find(const char *mimetype);
nsPluginInstanceTag *findStopped(const char *url);
PRUint32 getStoppedCount();
nsPluginInstanceTag *findOldestStopped();
void removeAllStopped();
void stopRunning(nsISupportsArray *aReloadDocs, nsPluginTag *aPluginTag);
PRBool IsLastInstance(nsPluginInstanceTag *plugin);
};
class nsPluginHost : public nsIPluginHost,
public nsIObserver,
public nsITimerCallback,
@ -274,6 +157,8 @@ public:
static nsresult GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt);
static nsresult PostPluginUnloadEvent(PRLibrary* aLibrary);
void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible);
void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);

View File

@ -0,0 +1,842 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sean Echevarria <sean@beatnik.com>
* Håkan Waara <hwaara@chello.se>
* Josh Aas <josh@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsPluginTags.h"
#include "prlink.h"
#include "plstr.h"
#include "nsIPluginInstanceOwner.h"
#include "nsIDocument.h"
#include "nsServiceManagerUtils.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsPluginsDir.h"
#include "nsPluginHost.h"
#include "nsIUnicodeDecoder.h"
#include "nsIPlatformCharset.h"
#include "nsICharsetConverterManager.h"
#include "nsPluginLogging.h"
#include "nsICategoryManager.h"
inline char* new_str(const char* str)
{
if (str == nsnull)
return nsnull;
char* result = new char[strlen(str) + 1];
if (result != nsnull)
return strcpy(result, str);
return result;
}
/* nsPluginTag */
nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
: mPluginHost(nsnull),
mName(aPluginTag->mName),
mDescription(aPluginTag->mDescription),
mVariants(aPluginTag->mVariants),
mMimeTypeArray(nsnull),
mMimeDescriptionArray(aPluginTag->mMimeDescriptionArray),
mExtensionsArray(nsnull),
mLibrary(nsnull),
mCanUnloadLibrary(PR_TRUE),
mXPConnected(PR_FALSE),
mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin),
mFileName(aPluginTag->mFileName),
mFullPath(aPluginTag->mFullPath),
mVersion(aPluginTag->mVersion),
mLastModifiedTime(0),
mFlags(NS_PLUGIN_FLAG_ENABLED)
{
if (aPluginTag->mMimeTypeArray != nsnull) {
mMimeTypeArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
}
if (aPluginTag->mExtensionsArray != nsnull) {
mExtensionsArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
}
}
nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
: mPluginHost(nsnull),
mName(aPluginInfo->fName),
mDescription(aPluginInfo->fDescription),
mVariants(aPluginInfo->fVariantCount),
mMimeTypeArray(nsnull),
mExtensionsArray(nsnull),
mLibrary(nsnull),
#ifdef XP_MACOSX
mCanUnloadLibrary(!aPluginInfo->fBundle),
#else
mCanUnloadLibrary(PR_TRUE),
#endif
mXPConnected(PR_FALSE),
mIsJavaPlugin(PR_FALSE),
mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
mFileName(aPluginInfo->fFileName),
mFullPath(aPluginInfo->fFullPath),
mVersion(aPluginInfo->fVersion),
mLastModifiedTime(0),
mFlags(NS_PLUGIN_FLAG_ENABLED)
{
if (aPluginInfo->fMimeTypeArray != nsnull) {
mMimeTypeArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++) {
if (mIsJavaPlugin && aPluginInfo->fMimeTypeArray[i] &&
strcmp(aPluginInfo->fMimeTypeArray[i],
"application/x-java-vm-npruntime") == 0) {
mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
// Stop processing here, any mimetypes after the magic "I'm a
// NPRuntime enabled Java plugin" mimetype will be ignored.
mVariants = i;
break;
}
mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
mIsJavaPlugin = PR_TRUE;
}
}
if (aPluginInfo->fMimeDescriptionArray != nsnull) {
for (int i = 0; i < mVariants; i++) {
// we should cut off the list of suffixes which the mime
// description string may have, see bug 53895
// it is usually in form "some description (*.sf1, *.sf2)"
// so we can search for the opening round bracket
char cur = '\0';
char pre = '\0';
char * p = PL_strrchr(aPluginInfo->fMimeDescriptionArray[i], '(');
if (p && (p != aPluginInfo->fMimeDescriptionArray[i])) {
if ((p - 1) && *(p - 1) == ' ') {
pre = *(p - 1);
*(p - 1) = '\0';
} else {
cur = *p;
*p = '\0';
}
}
mMimeDescriptionArray.AppendElement(
aPluginInfo->fMimeDescriptionArray[i]);
// restore the original string
if (cur != '\0')
*p = cur;
if (pre != '\0')
*(p - 1) = pre;
}
} else {
mMimeDescriptionArray.SetLength(mVariants);
}
if (aPluginInfo->fExtensionArray != nsnull) {
mExtensionsArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
}
EnsureMembersAreUTF8();
}
nsPluginTag::nsPluginTag(const char* aName,
const char* aDescription,
const char* aFileName,
const char* aFullPath,
const char* aVersion,
const char* const* aMimeTypes,
const char* const* aMimeDescriptions,
const char* const* aExtensions,
PRInt32 aVariants,
PRInt64 aLastModifiedTime,
PRBool aCanUnload,
PRBool aArgsAreUTF8)
: mPluginHost(nsnull),
mName(aName),
mDescription(aDescription),
mVariants(aVariants),
mMimeTypeArray(nsnull),
mExtensionsArray(nsnull),
mLibrary(nsnull),
mCanUnloadLibrary(aCanUnload),
mXPConnected(PR_FALSE),
mIsJavaPlugin(PR_FALSE),
mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
mFileName(aFileName),
mFullPath(aFullPath),
mVersion(aVersion),
mLastModifiedTime(aLastModifiedTime),
mFlags(0) // Caller will read in our flags from cache
{
if (aVariants) {
mMimeTypeArray = new char*[mVariants];
mExtensionsArray = new char*[mVariants];
for (PRInt32 i = 0; i < aVariants; ++i) {
if (mIsJavaPlugin && aMimeTypes[i] &&
strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) {
mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
// Stop processing here, any mimetypes after the magic "I'm a
// NPRuntime enabled Java plugin" mimetype will be ignored.
mVariants = i;
break;
}
mMimeTypeArray[i] = new_str(aMimeTypes[i]);
mMimeDescriptionArray.AppendElement(aMimeDescriptions[i]);
mExtensionsArray[i] = new_str(aExtensions[i]);
if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
mIsJavaPlugin = PR_TRUE;
}
}
if (!aArgsAreUTF8)
EnsureMembersAreUTF8();
}
nsPluginTag::~nsPluginTag()
{
NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
if (mMimeTypeArray) {
for (int i = 0; i < mVariants; i++)
delete[] mMimeTypeArray[i];
delete[] (mMimeTypeArray);
mMimeTypeArray = nsnull;
}
if (mExtensionsArray) {
for (int i = 0; i < mVariants; i++)
delete[] mExtensionsArray[i];
delete[] (mExtensionsArray);
mExtensionsArray = nsnull;
}
}
NS_IMPL_ISUPPORTS1(nsPluginTag, nsIPluginTag)
static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
nsAFlatCString& aString)
{
PRInt32 numberOfBytes = aString.Length();
PRInt32 outUnicodeLen;
nsAutoString buffer;
nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
&outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
if (!EnsureStringLength(buffer, outUnicodeLen))
return NS_ERROR_OUT_OF_MEMORY;
rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
buffer.BeginWriting(), &outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
buffer.SetLength(outUnicodeLen);
CopyUTF16toUTF8(buffer, aString);
return NS_OK;
}
nsresult nsPluginTag::EnsureMembersAreUTF8()
{
nsresult rv;
nsCOMPtr<nsIPlatformCharset> pcs =
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUnicodeDecoder> decoder;
nsCOMPtr<nsICharsetConverterManager> ccm =
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString charset;
rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!charset.LowerCaseEqualsLiteral("utf-8")) {
rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
NS_ENSURE_SUCCESS(rv, rv);
ConvertToUTF8(decoder, mFileName);
ConvertToUTF8(decoder, mFullPath);
}
// The description of the plug-in and the various MIME type descriptions
// should be encoded in the standard plain text file encoding for this system.
// XXX should we add kPlatformCharsetSel_PluginResource?
rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!charset.LowerCaseEqualsLiteral("utf-8")) {
rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
NS_ENSURE_SUCCESS(rv, rv);
ConvertToUTF8(decoder, mName);
ConvertToUTF8(decoder, mDescription);
for (PRUint32 i = 0; i < mMimeDescriptionArray.Length(); ++i) {
ConvertToUTF8(decoder, mMimeDescriptionArray[i]);
}
}
return NS_OK;
}
void nsPluginTag::SetHost(nsPluginHost * aHost)
{
mPluginHost = aHost;
}
NS_IMETHODIMP
nsPluginTag::GetDescription(nsACString& aDescription)
{
aDescription = mDescription;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetFilename(nsACString& aFileName)
{
aFileName = mFileName;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetVersion(nsACString& aVersion)
{
aVersion = mVersion;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetName(nsACString& aName)
{
aName = mName;
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetDisabled(PRBool* aDisabled)
{
*aDisabled = !HasFlag(NS_PLUGIN_FLAG_ENABLED);
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::SetDisabled(PRBool aDisabled)
{
if (HasFlag(NS_PLUGIN_FLAG_ENABLED) == !aDisabled)
return NS_OK;
if (aDisabled)
UnMark(NS_PLUGIN_FLAG_ENABLED);
else
Mark(NS_PLUGIN_FLAG_ENABLED);
mPluginHost->UpdatePluginInfo(this);
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::GetBlocklisted(PRBool* aBlocklisted)
{
*aBlocklisted = HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
return NS_OK;
}
NS_IMETHODIMP
nsPluginTag::SetBlocklisted(PRBool aBlocklisted)
{
if (HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED) == aBlocklisted)
return NS_OK;
if (aBlocklisted)
Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
else
UnMark(NS_PLUGIN_FLAG_BLOCKLISTED);
mPluginHost->UpdatePluginInfo(nsnull);
return NS_OK;
}
void
nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
nsPluginTag::nsRegisterType aType)
{
if (!mMimeTypeArray)
return;
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
mFileName.get(), aType == ePluginUnregister ? "yes" : "no"));
nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
if (!catMan)
return;
const char *contractId = "@mozilla.org/content/plugin/document-loader-factory;1";
nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!psvc)
return; // NS_ERROR_OUT_OF_MEMORY
// A preference controls whether or not the full page plugin is disabled for
// a particular type. The string must be in the form:
// type1,type2,type3,type4
// Note: need an actual interface to control this and subsequent disabling
// (and other plugin host settings) so applications can reliably disable
// plugins - without relying on implementation details such as prefs/category
// manager entries.
nsXPIDLCString overrideTypes;
psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
nsCAutoString overrideTypesFormatted;
overrideTypesFormatted.Assign(',');
overrideTypesFormatted += overrideTypes;
overrideTypesFormatted.Append(',');
nsACString::const_iterator start, end;
for (int i = 0; i < mVariants; i++) {
if (aType == ePluginUnregister) {
nsXPIDLCString value;
if (NS_SUCCEEDED(catMan->GetCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
getter_Copies(value)))) {
// Only delete the entry if a plugin registered for it
if (strcmp(value, contractId) == 0) {
catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
PR_TRUE);
}
}
} else {
overrideTypesFormatted.BeginReading(start);
overrideTypesFormatted.EndReading(end);
nsDependentCString mimeType(mMimeTypeArray[i]);
nsCAutoString commaSeparated;
commaSeparated.Assign(',');
commaSeparated += mimeType;
commaSeparated.Append(',');
if (!FindInReadable(commaSeparated, start, end)) {
catMan->AddCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
contractId,
PR_FALSE, /* persist: broken by bug 193031 */
aOverrideInternalTypes, /* replace if we're told to */
nsnull);
}
}
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
mMimeTypeArray[i], mFileName.get()));
}
}
void nsPluginTag::Mark(PRUint32 mask)
{
PRBool wasEnabled = IsEnabled();
mFlags |= mask;
// Update entries in the category manager if necessary.
if (mPluginHost && wasEnabled != IsEnabled()) {
if (wasEnabled)
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
else
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
}
}
void nsPluginTag::UnMark(PRUint32 mask)
{
PRBool wasEnabled = IsEnabled();
mFlags &= ~mask;
// Update entries in the category manager if necessary.
if (mPluginHost && wasEnabled != IsEnabled()) {
if (wasEnabled)
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
else
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
}
}
PRBool nsPluginTag::HasFlag(PRUint32 flag)
{
return (mFlags & flag) != 0;
}
PRUint32 nsPluginTag::Flags()
{
return mFlags;
}
PRBool nsPluginTag::IsEnabled()
{
return HasFlag(NS_PLUGIN_FLAG_ENABLED) && !HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
}
PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
{
NS_ENSURE_TRUE(aPluginTag, PR_FALSE);
if ((!mName.Equals(aPluginTag->mName)) ||
(!mDescription.Equals(aPluginTag->mDescription)) ||
(mVariants != aPluginTag->mVariants))
return PR_FALSE;
if (mVariants && mMimeTypeArray && aPluginTag->mMimeTypeArray) {
for (PRInt32 i = 0; i < mVariants; i++) {
if (PL_strcmp(mMimeTypeArray[i], aPluginTag->mMimeTypeArray[i]) != 0)
return PR_FALSE;
}
}
return PR_TRUE;
}
void nsPluginTag::TryUnloadPlugin()
{
if (mEntryPoint) {
mEntryPoint->Shutdown();
mEntryPoint = nsnull;
}
// before we unload check if we are allowed to, see bug #61388
if (mLibrary && mCanUnloadLibrary) {
// NPAPI plugins can be unloaded now if they don't use XPConnect
if (!mXPConnected) {
// unload the plugin asynchronously by posting a PLEvent
nsPluginHost::PostPluginUnloadEvent(mLibrary);
}
else {
// add library to the unused library list to handle it later
if (mPluginHost)
mPluginHost->AddUnusedLibrary(mLibrary);
}
}
// we should zero it anyway, it is going to be unloaded by
// CleanUnsedLibraries before we need to call the library
// again so the calling code should not be fooled and reload
// the library fresh
mLibrary = nsnull;
// Remove mime types added to the category manager
// only if we were made 'active' by setting the host
if (mPluginHost) {
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
}
}
/* nsPluginInstanceTag */
nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance,
const char * url,
PRBool aDefaultPlugin)
{
mNext = nsnull;
mPluginTag = aPluginTag;
mURL = PL_strdup(url);
mInstance = aInstance;
if (aInstance)
NS_ADDREF(aInstance);
mXPConnected = PR_FALSE;
mDefaultPlugin = aDefaultPlugin;
mStopped = PR_FALSE;
mllStopTime = LL_ZERO;
}
nsPluginInstanceTag::~nsPluginInstanceTag()
{
mPluginTag = nsnull;
if (mInstance) {
nsCOMPtr<nsIPluginInstanceOwner> owner;
mInstance->GetOwner(getter_AddRefs(owner));
if (owner)
owner->SetInstance(nsnull);
mInstance->InvalidateOwner();
NS_RELEASE(mInstance);
}
PL_strfree(mURL);
}
void nsPluginInstanceTag::setStopped(PRBool stopped)
{
mStopped = stopped;
if (mStopped) // plugin instance is told to stop
mllStopTime = PR_Now();
else
mllStopTime = LL_ZERO;
}
/* nsPluginInstanceTagList */
nsPluginInstanceTagList::nsPluginInstanceTagList()
{
mFirst = nsnull;
mLast = nsnull;
mCount = 0;
}
nsPluginInstanceTagList::~nsPluginInstanceTagList()
{
if (!mFirst)
return;
shutdown();
}
void nsPluginInstanceTagList::shutdown()
{
if (!mFirst)
return;
for (nsPluginInstanceTag * plugin = mFirst; plugin != nsnull;) {
nsPluginInstanceTag * next = plugin->mNext;
remove(plugin);
plugin = next;
}
mFirst = nsnull;
mLast = nsnull;
}
PRInt32 nsPluginInstanceTagList::add(nsPluginInstanceTag * plugin)
{
if (!mFirst) {
mFirst = plugin;
mLast = plugin;
mFirst->mNext = nsnull;
}
else {
mLast->mNext = plugin;
mLast = plugin;
}
mLast->mNext = nsnull;
mCount++;
return mCount;
}
PRBool nsPluginInstanceTagList::IsLastInstance(nsPluginInstanceTag * plugin)
{
if (!plugin)
return PR_FALSE;
if (!plugin->mPluginTag)
return PR_FALSE;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if ((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
return PR_FALSE;
}
return PR_TRUE;
}
PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin)
{
if (!mFirst)
return PR_FALSE;
nsPluginInstanceTag * prev = nsnull;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (p == plugin) {
PRBool lastInstance = IsLastInstance(p);
if (p == mFirst)
mFirst = p->mNext;
else
prev->mNext = p->mNext;
if (prev && !prev->mNext)
mLast = prev;
if (lastInstance) {
nsRefPtr<nsPluginTag> pluginTag = p->mPluginTag;
delete p;
if (pluginTag) {
nsresult rv;
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
PRBool unloadPluginsASAP = PR_FALSE;
rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
pluginTag->TryUnloadPlugin();
} else {
NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
}
} else {
delete p;
}
mCount--;
return PR_TRUE;
}
prev = p;
}
return PR_FALSE;
}
// This method terminates all running instances of plugins and collects their
// documents to be returned through an array. This method is used
// when we are shutting down or when a plugins.refresh(1) happens.
// If aPluginTag is given, then only that plugin is terminated
void nsPluginInstanceTagList::stopRunning(nsISupportsArray* aReloadDocs,
nsPluginTag* aPluginTag)
{
if (!mFirst)
return;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (!p->mStopped && p->mInstance &&
(!aPluginTag || aPluginTag == p->mPluginTag)) {
p->mInstance->SetWindow(nsnull);
p->mInstance->Stop();
p->setStopped(PR_TRUE);
// If we've been passed an array to return, lets collect all our documents,
// removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
// to kickstart our instances.
if (aReloadDocs && p->mInstance) {
nsCOMPtr<nsIPluginInstanceOwner> owner;
p->mInstance->GetOwner(getter_AddRefs(owner));
if (owner) {
nsCOMPtr<nsIDocument> doc;
owner->GetDocument(getter_AddRefs(doc));
if (doc && aReloadDocs->IndexOf(doc) == -1) // don't allow for duplicates
aReloadDocs->AppendElement(doc);
}
}
}
}
}
void nsPluginInstanceTagList::removeAllStopped()
{
if (!mFirst)
return;
nsPluginInstanceTag * next = nsnull;
for (nsPluginInstanceTag * p = mFirst; p != nsnull;) {
next = p->mNext;
if (p->mStopped)
remove(p);
p = next;
}
return;
}
nsPluginInstanceTag * nsPluginInstanceTagList::find(nsIPluginInstance* instance)
{
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (p->mInstance == instance)
return p;
}
return nsnull;
}
nsPluginInstanceTag * nsPluginInstanceTagList::find(const char * mimetype)
{
PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
// give it some special treatment for the default plugin first
// because we cannot tell the default plugin by asking instance for a mime type
if (defaultplugin && p->mDefaultPlugin)
return p;
if (!p->mInstance)
continue;
const char* mt;
nsresult rv = p->mInstance->GetMIMEType(&mt);
if (NS_FAILED(rv))
continue;
if (PL_strcasecmp(mt, mimetype) == 0)
return p;
}
return nsnull;
}
nsPluginInstanceTag * nsPluginInstanceTagList::findStopped(const char * url)
{
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (!PL_strcmp(url, p->mURL) && p->mStopped)
return p;
}
return nsnull;
}
PRUint32 nsPluginInstanceTagList::getStoppedCount()
{
PRUint32 stoppedCount = 0;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (p->mStopped)
stoppedCount++;
}
return stoppedCount;
}
nsPluginInstanceTag * nsPluginInstanceTagList::findOldestStopped()
{
nsPluginInstanceTag * res = nsnull;
PRInt64 llTime = LL_MAXINT;
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
if (!p->mStopped)
continue;
if (LL_CMP(p->mllStopTime, <, llTime)) {
llTime = p->mllStopTime;
res = p;
}
}
return res;
}

View File

@ -0,0 +1,172 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Josh Aas <josh@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsPluginTags_h_
#define nsPluginTags_h_
#include "nscore.h"
#include "prtypes.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIPluginTag.h"
#include "nsIPlugin.h"
#include "nsIPluginInstance.h"
#include "nsISupportsArray.h"
class nsPluginHost;
struct PRLibrary;
struct nsPluginInfo;
// Remember that flags are written out to pluginreg.dat, be careful
// changing their meaning.
#define NS_PLUGIN_FLAG_ENABLED 0x0001 // is this plugin enabled?
// no longer used 0x0002 // reuse only if regenerating pluginreg.dat
#define NS_PLUGIN_FLAG_FROMCACHE 0x0004 // this plugintag info was loaded from cache
#define NS_PLUGIN_FLAG_UNWANTED 0x0008 // this is an unwanted plugin
#define NS_PLUGIN_FLAG_BLOCKLISTED 0x0010 // this is a blocklisted plugin
// A linked-list of plugin information that is used for instantiating plugins
// and reflecting plugin information into JavaScript.
class nsPluginTag : public nsIPluginTag
{
public:
enum nsRegisterType {
ePluginRegister,
ePluginUnregister
};
NS_DECL_ISUPPORTS
NS_DECL_NSIPLUGINTAG
nsPluginTag(nsPluginTag* aPluginTag);
nsPluginTag(nsPluginInfo* aPluginInfo);
nsPluginTag(const char* aName,
const char* aDescription,
const char* aFileName,
const char* aFullPath,
const char* aVersion,
const char* const* aMimeTypes,
const char* const* aMimeDescriptions,
const char* const* aExtensions,
PRInt32 aVariants,
PRInt64 aLastModifiedTime = 0,
PRBool aCanUnload = PR_TRUE,
PRBool aArgsAreUTF8 = PR_FALSE);
~nsPluginTag();
void SetHost(nsPluginHost * aHost);
void TryUnloadPlugin();
void Mark(PRUint32 mask);
void UnMark(PRUint32 mask);
PRBool HasFlag(PRUint32 flag);
PRUint32 Flags();
PRBool Equals(nsPluginTag* aPluginTag);
PRBool IsEnabled();
void RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
nsRegisterType aType = ePluginRegister);
nsRefPtr<nsPluginTag> mNext;
nsPluginHost *mPluginHost;
nsCString mName; // UTF-8
nsCString mDescription; // UTF-8
PRInt32 mVariants;
char **mMimeTypeArray;
nsTArray<nsCString> mMimeDescriptionArray; // UTF-8
char **mExtensionsArray;
PRLibrary *mLibrary;
nsCOMPtr<nsIPlugin> mEntryPoint;
PRPackedBool mCanUnloadLibrary;
PRPackedBool mXPConnected;
PRPackedBool mIsJavaPlugin;
PRPackedBool mIsNPRuntimeEnabledJavaPlugin;
nsCString mFileName; // UTF-8
nsCString mFullPath; // UTF-8
nsCString mVersion; // UTF-8
PRInt64 mLastModifiedTime;
private:
PRUint32 mFlags;
nsresult EnsureMembersAreUTF8();
};
struct nsPluginInstanceTag
{
nsPluginInstanceTag* mNext;
char* mURL;
nsRefPtr<nsPluginTag> mPluginTag;
nsIPluginInstance* mInstance;
PRTime mllStopTime;
PRPackedBool mStopped;
PRPackedBool mDefaultPlugin;
PRPackedBool mXPConnected;
// Array holding all opened stream listeners for this entry
nsCOMPtr <nsISupportsArray> mStreams;
nsPluginInstanceTag(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance,
const char * url,
PRBool aDefaultPlugin);
~nsPluginInstanceTag();
void setStopped(PRBool stopped);
};
class nsPluginInstanceTagList
{
public:
nsPluginInstanceTag *mFirst;
nsPluginInstanceTag *mLast;
PRInt32 mCount;
nsPluginInstanceTagList();
~nsPluginInstanceTagList();
void shutdown();
PRBool add(nsPluginInstanceTag *plugin);
PRBool remove(nsPluginInstanceTag *plugin);
nsPluginInstanceTag *find(nsIPluginInstance *instance);
nsPluginInstanceTag *find(const char *mimetype);
nsPluginInstanceTag *findStopped(const char *url);
PRUint32 getStoppedCount();
nsPluginInstanceTag *findOldestStopped();
void removeAllStopped();
void stopRunning(nsISupportsArray *aReloadDocs, nsPluginTag *aPluginTag);
PRBool IsLastInstance(nsPluginInstanceTag *plugin);
};
#endif // nsPluginTags_h_