From f760c5576bb500d25c7f957bc9521cb0c372003e Mon Sep 17 00:00:00 2001 From: "peterlubczynski%netscape.com" Date: Wed, 3 Jul 2002 21:03:51 +0000 Subject: [PATCH] Fixing bug 148458: Netscape Radio crashes using Real Player if another plugin is being installed in another window because scripting any plugin in other window after plugins.refresh(1) causes this crash when plugin has been unloaded - N70PR1 [@ NPPL3260.DLL - XPTC_InvokeByIndex] r=av, sr=jst git-svn-id: svn://10.0.0.236/trunk@124632 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/modules/plugin/base/src/Makefile.in | 1 + mozilla/modules/plugin/base/src/makefile.win | 1 + .../plugin/base/src/nsPluginHostImpl.cpp | 151 +++++++++++++++++- .../plugin/base/src/nsPluginHostImpl.h | 3 +- .../plugin/base/src/nsPluginViewer.cpp | 13 +- 5 files changed, 163 insertions(+), 6 deletions(-) diff --git a/mozilla/modules/plugin/base/src/Makefile.in b/mozilla/modules/plugin/base/src/Makefile.in index 9c2d2ca4bbc..ee292c2ccdf 100644 --- a/mozilla/modules/plugin/base/src/Makefile.in +++ b/mozilla/modules/plugin/base/src/Makefile.in @@ -55,6 +55,7 @@ REQUIRES = xpcom \ webbrwsr \ windowwatcher \ imglib2 \ + layout \ $(NULL) # for xlib port REQUIRES += xlibxtbin xlibrgb diff --git a/mozilla/modules/plugin/base/src/makefile.win b/mozilla/modules/plugin/base/src/makefile.win index 3ca466cb897..e147acce10c 100644 --- a/mozilla/modules/plugin/base/src/makefile.win +++ b/mozilla/modules/plugin/base/src/makefile.win @@ -55,6 +55,7 @@ REQUIRES = xpcom \ windowwatcher \ gfx \ imglib2 \ + layout \ $(NULL) DEFINES =-D_IMPL_NS_PLUGIN -DWIN32_LEAN_AND_MEAN diff --git a/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp b/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp index 5d4fcf6fe48..2fdb5acbdbd 100644 --- a/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp +++ b/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp @@ -154,6 +154,13 @@ #include "nsDefaultPlugin.h" #include "nsWeakReference.h" #include "nsIDOMElement.h" +#include "nsIStyleSet.h" +#include "nsIStyleFrameConstruction.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIWebNavigation.h" +#include "nsISupportsArray.h" +#include "nsIDocShell.h" #ifdef XP_UNIX #if defined(MOZ_WIDGET_GTK) @@ -351,6 +358,96 @@ void DisplayNoDefaultPluginDialog(const char *mimeType, nsIPrompt *prompt) return; } +//////////////////////////////////////////////////////////////////////// +// Little helper struct to asynchronously reframe any presentations (embedded) +// or reload any documents (full-page), that contained plugins +// which were shutdown as a result of a plugins.refresh(1) +struct nsPluginDocReframeEvent: public PLEvent { + nsPluginDocReframeEvent (nsISupportsArray* aDocs) { mDocs = aDocs; } + nsresult HandlePluginDocReframeEvent(); + nsCOMPtr mDocs; +}; + +nsresult nsPluginDocReframeEvent::HandlePluginDocReframeEvent() { + NS_ENSURE_TRUE(mDocs, NS_ERROR_FAILURE); + + PRUint32 c; + mDocs->Count(&c); + + // for each document (which previously had a running instance), tell + // the frame constructor to rebuild + for (PRUint32 i = 0; i < c; i++) { + nsCOMPtr doc (do_QueryElementAt(mDocs, i)); + if (doc) { + nsCOMPtr shell; + doc->GetShellAt(0, getter_AddRefs(shell)); + + // if this document has a presentation shell, then it has frames and can be reframed + if (shell) { + nsCOMPtr pc; + nsCOMPtr set; + shell->GetPresContext(getter_AddRefs(pc)); + shell->GetStyleSet(getter_AddRefs(set)); + if (pc && set) { + nsCOMPtr fc; + set->GetStyleFrameConstruction(getter_AddRefs(fc)); + if (fc) + + /** + * A reframe will cause a fresh object frame, instance owner, and instance + * to be created. Reframing of the entire document is necessary as we may have + * recently found new plugins and we want a shot at trying to use them instead + * of leaving alternate renderings. + * We do not want to completely reload all the documents that had running plugins + * because we could possibly trigger a script to run in the unload event handler + * which may want to access our defunct plugin and cause us to crash. + */ + + fc->ReconstructDocElementHierarchy(pc); // causes reframe of document + } + } else { // no pres shell --> full-page plugin + + /** + * This document does not have a presentation shell. It may be a full-page plugin. + * Full-page plugins don't really have the same problem of crashing because they + * are not currently scriptable. However, they do leave a non-painting, defunct + * window which doesn't look good. A reload of the page for full-page plugins + * is needed to kickstart the instance. + */ + + nsCOMPtr gso; + doc->GetScriptGlobalObject(getter_AddRefs(gso)); + if (gso) { + nsCOMPtr docShell; + gso->GetDocShell(getter_AddRefs(docShell)); + nsCOMPtr webNav (do_QueryInterface(docShell)); + if (webNav) + webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE); + + else NS_WARNING("refreshing plugins: couldn't get webnav or docshell from gso"); + } else NS_WARNING("refreshing plugins: could not get the global script object -- did the plugin set it?"); + } + } + } + + return mDocs->Clear(); +} + + + + +//---------------------------------------------------------------------- +static void* PR_CALLBACK HandlePluginDocReframePLEvent(PLEvent* aEvent) +{ + nsPluginDocReframeEvent* event = NS_REINTERPRET_CAST(nsPluginDocReframeEvent*, aEvent); + event->HandlePluginDocReframeEvent(); + return nsnull; +} +static void PR_CALLBACK DestroyPluginDocReframePLEvent(PLEvent* aEvent) +{ + delete aEvent; +} + //////////////////////////////////////////////////////////////////////// nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag, @@ -566,7 +663,10 @@ PRBool nsActivePluginList::remove(nsActivePlugin * plugin) //////////////////////////////////////////////////////////////////////// -void nsActivePluginList::stopRunning() +// 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. +void nsActivePluginList::stopRunning(nsISupportsArray* aReloadDocs) { if(mFirst == nsnull) return; @@ -593,6 +693,21 @@ void nsActivePluginList::stopRunning() } doCallSetWindowAfterDestroy = PR_FALSE; 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->mPeer) { + nsPluginInstancePeerImpl * peer = (nsPluginInstancePeerImpl *)p->mPeer; + nsCOMPtr owner; + peer->GetOwner(*getter_AddRefs(owner)); + if (owner) { + nsCOMPtr doc; + owner->GetDocument(getter_AddRefs(doc)); + if (doc && aReloadDocs->IndexOf(doc) == -1) // don't allow for duplicates + aReloadDocs->AppendElement(doc); + } + } } } } @@ -2695,10 +2810,15 @@ nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) // if no changed detected, return an appropriate error code if (!pluginschanged) return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED; + + nsCOMPtr instsToReload; if(reloadPages) { - // stop any running plugins - mActivePluginList.stopRunning(); + NS_NewISupportsArray(getter_AddRefs(instsToReload)); + + // Then stop any running plugin instances but hold on to the documents in the array + // We are going to need to restart the instances in these documents later + mActivePluginList.stopRunning(instsToReload); } // clean active plugin list @@ -2737,6 +2857,29 @@ nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) // load them again rv = LoadPlugins(); + // If we have shut down any plugin instances, we've now got to restart them. + // Post an event to do the rest as we are going to be destroying the frame tree and we also want + // any posted unload events to finish + PRUint32 c; + if (reloadPages && + instsToReload && + NS_SUCCEEDED(instsToReload->Count(&c)) && + c > 0) { + nsCOMPtr eventService(do_GetService(kEventQueueServiceCID)); + if (eventService) { + nsCOMPtr eventQueue; + eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue)); + if (eventQueue) { + nsPluginDocReframeEvent * ev = new nsPluginDocReframeEvent(instsToReload); + if (ev) { + PL_InitEvent(ev, nsnull, HandlePluginDocReframePLEvent, DestroyPluginDocReframePLEvent); + eventQueue->PostEvent(ev); + } + } + } + + } + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::ReloadPlugins End active_instance_count=%d\n", mActivePluginList.mCount)); @@ -3256,7 +3399,7 @@ NS_IMETHODIMP nsPluginHostImpl::Destroy(void) // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow // for those plugins who want it - mActivePluginList.stopRunning(); + mActivePluginList.stopRunning(nsnull); // at this point nsIPlugin::Shutdown calls will be performed if needed mActivePluginList.shut(); diff --git a/mozilla/modules/plugin/base/src/nsPluginHostImpl.h b/mozilla/modules/plugin/base/src/nsPluginHostImpl.h index 97c2c829617..488210957b1 100644 --- a/mozilla/modules/plugin/base/src/nsPluginHostImpl.h +++ b/mozilla/modules/plugin/base/src/nsPluginHostImpl.h @@ -61,6 +61,7 @@ class nsIFile; class nsIChannel; class nsIRegistry; class nsPluginHostImpl; +class nsISupportsArray; /** * A linked-list of plugin information that is used for @@ -152,7 +153,7 @@ public: PRUint32 getStoppedCount(); nsActivePlugin * findOldestStopped(); void removeAllStopped(); - void stopRunning(); + void stopRunning(nsISupportsArray* aReloadDocs); PRBool IsLastInstance(nsActivePlugin * plugin); }; diff --git a/mozilla/modules/plugin/base/src/nsPluginViewer.cpp b/mozilla/modules/plugin/base/src/nsPluginViewer.cpp index 91d0cfdc9f8..fb694001816 100644 --- a/mozilla/modules/plugin/base/src/nsPluginViewer.cpp +++ b/mozilla/modules/plugin/base/src/nsPluginViewer.cpp @@ -65,7 +65,7 @@ #include "nsGUIEvent.h" #include "nsIPluginViewer.h" #include "nsContentCID.h" - +#include "nsIScriptGlobalObject.h" #include "nsITimer.h" #include "nsITimerCallback.h" @@ -326,6 +326,17 @@ PluginViewerImpl::StartLoad(nsIRequest* request, nsIStreamListener*& aResult) GetURI(getter_AddRefs(uri)); if (uri) mDocument->SetDocumentURL(uri); + + // we're going to need the docshell later to reload this full-page plugin in the event of a plugins refresh + // so stuff it in the document we created + nsCOMPtr global (do_GetInterface(mContainer)); + if (global) { + mDocument->SetScriptGlobalObject(global); + nsCOMPtr domdoc(do_QueryInterface(mDocument)); + if (domdoc) + global->SetNewDocument(domdoc, PR_TRUE); + } + } nsRect r;