Bug 975098 - Checks for stopping a plugin should consider that we might be nested inside InstantiatePluginInstance. r=bsmedberg
authorJohn Schoenick <jschoenick@mozilla.com>
Thu, 20 Feb 2014 13:34:06 -0800
changeset 173203 25de9f31826128f85ebd541e25ecefef4f1a5e77
parent 173202 e8036c3e0a7b242a3dbaa51d9308973635d83a2a
child 173204 65d3cda9a1a95f9587f41a4c0803ee3c6c1c665c
push id40953
push userjschoenick@mozilla.com
push dateWed, 12 Mar 2014 18:48:16 +0000
treeherdermozilla-inbound@549cc0c0672f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs975098
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 975098 - Checks for stopping a plugin should consider that we might be nested inside InstantiatePluginInstance. r=bsmedberg
content/base/src/nsObjectLoadingContent.cpp
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -698,17 +698,17 @@ nsObjectLoadingContent::UnbindFromTree(b
   nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
 
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
   MOZ_ASSERT(thisContent);
   nsIDocument* ownerDoc = thisContent->OwnerDoc();
   ownerDoc->RemovePlugin(this);
 
-  if (mType == eType_Plugin && mInstanceOwner) {
+  if (mType == eType_Plugin && (mInstanceOwner || mInstantiating)) {
     // we'll let the plugin continue to run at least until we get back to
     // the event loop. If we get back to the event loop and the node
     // has still not been added back to the document then we tear down the
     // plugin
     QueueCheckPluginStopEvent();
   } else if (mType != eType_Image) {
     // nsImageLoadingContent handles the image case.
     // Reset state and clear pending events
@@ -739,17 +739,17 @@ nsObjectLoadingContent::nsObjectLoadingC
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   // Should have been unbound from the tree at this point, and
   // CheckPluginStopEvent keeps us alive
   if (mFrameLoader) {
     NS_NOTREACHED("Should not be tearing down frame loaders at this point");
     mFrameLoader->Destroy();
   }
-  if (mInstanceOwner) {
+  if (mInstanceOwner || mInstantiating) {
     // This is especially bad as delayed stop will try to hold on to this
     // object...
     NS_NOTREACHED("Should not be tearing down a plugin at this point!");
     StopPluginInstance();
   }
   DestroyImageLoadingContent();
 }
 
@@ -904,17 +904,17 @@ nsObjectLoadingContent::InstantiatePlugi
 void
 nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
 {
   // XXX(johns): We cannot touch plugins or run arbitrary script from this call,
   //             as nsDocument is in a non-reentrant state.
 
   // If we have a plugin we want to queue an event to stop it unless we are
   // moved into an active document before returning to the event loop.
-  if (mInstanceOwner)
+  if (mInstanceOwner || mInstantiating)
     QueueCheckPluginStopEvent();
 }
 
 // nsIRequestObserver
 NS_IMETHODIMP
 nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
                                        nsISupports *aContext)
 {
@@ -1068,18 +1068,20 @@ nsObjectLoadingContent::HasNewFrame(nsIO
   if (mType != eType_Plugin) {
     return NS_OK;
   }
 
   if (!aFrame) {
     // Lost our frame. If we aren't going to be getting a new frame, e.g. we've
     // become display:none, we'll want to stop the plugin. Queue a
     // CheckPluginStopEvent
-    if (mInstanceOwner) {
-      mInstanceOwner->SetFrame(nullptr);
+    if (mInstanceOwner || mInstantiating) {
+      if (mInstanceOwner) {
+        mInstanceOwner->SetFrame(nullptr);
+      }
       QueueCheckPluginStopEvent();
     }
     return NS_OK;
   }
 
   // Have a new frame
 
   if (!mInstanceOwner) {
@@ -2821,16 +2823,20 @@ nsObjectLoadingContent::DoStopPlugin(nsP
 
 NS_IMETHODIMP
 nsObjectLoadingContent::StopPluginInstance()
 {
   // Clear any pending events
   mPendingInstantiateEvent = nullptr;
   mPendingCheckPluginStopEvent = nullptr;
 
+  // If we're currently instantiating, clearing this will cause
+  // InstantiatePluginInstance's re-entrance check to destroy the created plugin
+  mInstantiating = false;
+
   if (!mInstanceOwner) {
     return NS_OK;
   }
 
   if (mChannel) {
     // The plugin has already used data from this channel, we'll need to
     // re-open it to handle instantiating again, even if we don't invalidate
     // our loaded state.