Bug 889614 - Fix regression in plugin reparenting. r=josh
authorJohn Schoenick <jschoenick@mozilla.com>
Mon, 22 Jul 2013 15:08:09 -0700
changeset 152346 78209b0be503c242ef192a72cc0cc909250e0b11
parent 152345 750c29cf4f8f5393f138f4c578d29939e84ec32c
child 152347 ef4b58b54480800f4aa2f450db4094a5eb997982
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjosh
bugs889614
milestone25.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 889614 - Fix regression in plugin reparenting. r=josh
content/base/src/nsObjectLoadingContent.cpp
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -128,17 +128,17 @@ private:
 
 NS_IMETHODIMP
 nsAsyncInstantiateEvent::Run()
 {
   nsObjectLoadingContent *objLC =
     static_cast<nsObjectLoadingContent *>(mContent.get());
 
   // If objLC is no longer tracking this event, we've been canceled or
-  // superceded
+  // superseded
   if (objLC->mPendingInstantiateEvent != this) {
     return NS_OK;
   }
   objLC->mPendingInstantiateEvent = nullptr;
 
   return objLC->SyncStartPluginInstance();
 }
 
@@ -161,38 +161,52 @@ private:
 
 NS_IMETHODIMP
 CheckPluginStopEvent::Run()
 {
   nsObjectLoadingContent *objLC =
     static_cast<nsObjectLoadingContent *>(mContent.get());
 
   // If objLC is no longer tracking this event, we've been canceled or
-  // superceded
+  // superseded. We clear this before we finish - either by calling
+  // UnloadObject/StopPluginInstance, or directly if we took no action.
   if (objLC->mPendingCheckPluginStopEvent != this) {
     return NS_OK;
   }
-  objLC->mPendingCheckPluginStopEvent = nullptr;
 
   nsCOMPtr<nsIContent> content =
     do_QueryInterface(static_cast<nsIImageLoadingContent *>(objLC));
   if (!InActiveDocument(content)) {
     // Unload the object entirely
     LOG(("OBJLC [%p]: Unloading plugin outside of document", this));
     objLC->UnloadObject();
     return NS_OK;
   }
 
   if (!content->GetPrimaryFrame()) {
+    LOG(("OBJLC [%p]: CheckPluginStopEvent - No frame, flushing layout", this));
+    nsIDocument* currentDoc = content->GetCurrentDoc();
+    if (currentDoc) {
+      currentDoc->FlushPendingNotifications(Flush_Layout);
+      if (objLC->mPendingCheckPluginStopEvent != this ||
+          content->GetPrimaryFrame()) {
+        LOG(("OBJLC [%p]: Event superseded or frame gained during layout flush",
+             this));
+        objLC->mPendingCheckPluginStopEvent = nullptr;
+        return NS_OK;
+      }
+    }
     // Still no frame, suspend plugin. HasNewFrame will restart us when we
     // become rendered again
     LOG(("OBJLC [%p]: Stopping plugin that lost frame", this));
     // Okay to leave loaded as a plugin, but stop the unrendered instance
     objLC->StopPluginInstance();
   }
+
+  objLC->mPendingCheckPluginStopEvent = nullptr;
   return NS_OK;
 }
 
 /**
  * Helper task for firing simple events
  */
 class nsSimplePluginEvent : public nsRunnable {
 public:
@@ -885,17 +899,16 @@ nsObjectLoadingContent::OnStartRequest(n
 
   LOG(("OBJLC [%p]: Channel OnStartRequest", this));
 
   if (aRequest != mChannel || !aRequest) {
     // happens when a new load starts before the previous one got here
     return NS_BINDING_ABORTED;
   }
 
-  NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
   // If we already switched to type plugin, this channel can just be passed to
   // the final listener.
   if (mType == eType_Plugin) {
     if (!mInstanceOwner) {
       // We drop mChannel when stopping plugins, so something is wrong
       NS_NOTREACHED("Opened a channel in plugin mode, but don't have a plugin");
       return NS_BINDING_ABORTED;
     }
@@ -907,16 +920,17 @@ nsObjectLoadingContent::OnStartRequest(n
     }
   }
 
   // Otherwise we should be state loading, and call LoadObject with the channel
   if (mType != eType_Loading) {
     NS_NOTREACHED("Should be type loading at this point");
     return NS_BINDING_ABORTED;
   }
+  NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
   NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
 
   mChannelLoaded = true;
 
   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
   NS_ASSERTION(chan, "Why is our request not a channel?");
 
   nsCOMPtr<nsIURI> uri;