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;