Merge backout of changeset 33031c875984, bug 90268. r=josh
authorJosh Aas <joshmoz@gmail.com>
Tue, 30 Aug 2011 02:11:57 -0400
changeset 77477 1a4a5fcf0a7623120a7734b14fae949f233dbd3f
parent 77475 b61af4d7dc7ca8c1ba5138876f969e36819a333f (current diff)
parent 77476 d5a0f6ad8bbd11e72a0ef0a524ecff7b4cdc7244 (diff)
child 77479 e6591ea9b27b4f3a652a11645aa63ccfae67603e
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjosh
bugs90268
milestone9.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
Merge backout of changeset 33031c875984, bug 90268. r=josh
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
dom/base/nsDOMClassInfo.cpp
dom/plugins/test/mochitest/test_display_none.html
dom/plugins/test/mochitest/test_instance_re-parent-windowed.html
dom/plugins/test/mochitest/test_instance_re-parent.html
dom/plugins/test/mochitest/test_instance_unparent1.html
dom/plugins/test/mochitest/test_instance_unparent2.html
dom/plugins/test/mochitest/test_instance_unparent3.html
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1658,23 +1658,16 @@ public:
    * Utility method for getElementsByClassName.  aRootNode is the node (either
    * document or element), which getElementsByClassName was called on.
    */
   static nsresult GetElementsByClassName(nsINode* aRootNode,
                                          const nsAString& aClasses,
                                          nsIDOMNodeList** aReturn);
 
   /**
-   * Returns the widget for this document if there is one. Looks at all ancestor
-   * documents to try to find a widget, so for example this can still find a
-   * widget for documents in display:none frames that have no presentation.
-   */
-  static nsIWidget *WidgetForDocument(nsIDocument *aDoc);
-
-  /**
    * Returns a layer manager to use for the given document. Basically we
    * look up the document hierarchy for the first document which has
    * a presentation with an associated widget, and use that widget's
    * layer manager.
    *
    * @param aDoc the document for which to return a layer manager.
    * @param aAllowRetaining an outparam that states whether the returned
    * layer manager should be used for retained layers
--- a/content/base/public/nsIObjectLoadingContent.idl
+++ b/content/base/public/nsIObjectLoadingContent.idl
@@ -46,17 +46,17 @@ interface nsIDOMClientRect;
 %{C++
 #include "nsNPAPIPluginInstance.h"
 %}
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
 /**
  * This interface represents a content node that loads objects.
  */
-[scriptable, uuid(6D8914C7-0E22-4452-8962-11B69BBE84D7)]
+[scriptable, uuid(107e8048-d00f-4711-bd21-97184ccae0b1)]
 interface nsIObjectLoadingContent : nsISupports
 {
   const unsigned long TYPE_LOADING  = 0;
   const unsigned long TYPE_IMAGE    = 1;
   const unsigned long TYPE_PLUGIN   = 2;
   const unsigned long TYPE_DOCUMENT = 3;
   const unsigned long TYPE_NULL     = 4;
 
@@ -82,35 +82,47 @@ interface nsIObjectLoadingContent : nsIS
   /**
    * Returns the plugin instance if it has already been instantiated. This
    * will never instantiate the plugin and so is safe to call even when
    * content script must not execute.
    */
   [noscript] readonly attribute nsNPAPIPluginInstancePtr pluginInstance;
 
   /**
+   * Makes sure that a frame for this object exists, and that the plugin is
+   * instantiated. This method does nothing if the type is not #TYPE_PLUGIN.
+   * There is no guarantee that there will be a frame after this method is
+   * called; for example, the node may have a display:none style. If plugin
+   * instantiation is possible, it will be done synchronously by this method,
+   * and the plugin instance will be returned. A success return value does not
+   * necessarily mean that the instance is nonnull.
+   *
+   * This is a noscript method because it is internal and will go away once
+   * plugin loading moves to content.
+   *
+   * @note If there is an error instantiating the plugin, this method will
+   * trigger fallback to replacement content, and the type will change (and
+   * this method will return a failure code)
+   */
+  [noscript] nsNPAPIPluginInstancePtr ensureInstantiation();
+
+  /**
    * Tells the content about an associated object frame.
    * This can be called multiple times for different frames.
    *
    * This is noscript because this is an internal method that will go away, and
    * because nsIObjectFrame is unscriptable.
    */
   [noscript] void hasNewFrame(in nsIObjectFrame aFrame);
 
-  [noscript] void disconnectFrame();
-
   /**
    * If this object is in going to be printed, this method
    * returns the nsIObjectFrame object which should be used when
    * printing the plugin. The returned nsIFrame is in the original document,
    * not in the static clone.
    */
   [noscript] nsIFrame getPrintFrame();
 
   [noscript] void pluginCrashed(in nsIPluginTag pluginTag,
                                 in AString pluginDumpID,
                                 in AString browserDumpID,
                                 in boolean submittedCrashReport);
-
-  [noscript] void stopPluginInstance();
-
-  [noscript] void startPluginInstance();
 };
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5512,18 +5512,19 @@ nsContentUtils::PlatformToDOMLineBreaks(
                              NS_LITERAL_STRING("\n").get());
 
     // Mac linebreaks: Map any remaining CR to LF:
     aString.ReplaceSubstring(NS_LITERAL_STRING("\r").get(),
                              NS_LITERAL_STRING("\n").get());
   }
 }
 
-nsIWidget *
-nsContentUtils::WidgetForDocument(nsIDocument *aDoc)
+static already_AddRefed<LayerManager>
+LayerManagerForDocumentInternal(nsIDocument *aDoc, bool aRequirePersistent,
+                                bool* aAllowRetaining)
 {
   nsIDocument* doc = aDoc;
   nsIDocument* displayDoc = doc->GetDisplayDocument();
   if (displayDoc) {
     doc = displayDoc;
   }
 
   nsIPresShell* shell = doc->GetShell();
@@ -5548,41 +5549,33 @@ nsContentUtils::WidgetForDocument(nsIDoc
 
   if (shell) {
     nsIViewManager* VM = shell->GetViewManager();
     if (VM) {
       nsIView* rootView = VM->GetRootView();
       if (rootView) {
         nsIView* displayRoot = nsIViewManager::GetDisplayRootFor(rootView);
         if (displayRoot) {
-          return displayRoot->GetNearestWidget(nsnull);
+          nsIWidget* widget = displayRoot->GetNearestWidget(nsnull);
+          if (widget) {
+            nsRefPtr<LayerManager> manager =
+              widget->
+                GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT : 
+                                                     nsIWidget::LAYER_MANAGER_CURRENT,
+                                aAllowRetaining);
+            return manager.forget();
+          }
         }
       }
     }
   }
 
   return nsnull;
 }
 
-static already_AddRefed<LayerManager>
-LayerManagerForDocumentInternal(nsIDocument *aDoc, bool aRequirePersistent,
-                                bool* aAllowRetaining)
-{
-  nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc);
-  if (widget) {
-    nsRefPtr<LayerManager> manager =
-      widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT : 
-                              nsIWidget::LAYER_MANAGER_CURRENT,
-                              aAllowRetaining);
-    return manager.forget();
-  }
-
-  return nsnull;
-}
-
 already_AddRefed<LayerManager>
 nsContentUtils::LayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining)
 {
   return LayerManagerForDocumentInternal(aDoc, false, aAllowRetaining);
 }
 
 already_AddRefed<LayerManager>
 nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining)
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -168,17 +168,16 @@
 #include "nsIXMLContentSink.h"
 #include "nsContentErrors.h"
 #include "nsIXULDocument.h"
 #include "nsIPrompt.h"
 #include "nsIPropertyBag2.h"
 #include "nsIDOMPageTransitionEvent.h"
 #include "nsFrameLoader.h"
 #include "nsEscape.h"
-#include "nsObjectLoadingContent.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 
 #include "mozAutoDocUpdate.h"
 #include "nsGlobalWindow.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "nsDOMNavigationTiming.h"
@@ -3743,21 +3742,16 @@ NotifyActivityChanged(nsIContent *aConte
 {
 #ifdef MOZ_MEDIA
   nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
   if (domMediaElem) {
     nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
     mediaElem->NotifyOwnerDocumentActivityChanged();
   }
 #endif
-  nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aContent));
-  if (objectLoadingContent) {
-    nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
-    olc->NotifyOwnerDocumentActivityChanged();
-  }
 }
 
 void
 nsIDocument::SetContainer(nsISupports* aContainer)
 {
   mDocumentContainer = do_GetWeakReference(aContainer);
   EnumerateFreezableElements(NotifyActivityChanged, nsnull);
 }
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -61,17 +61,16 @@
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 #include "nsImageLoadingContent.h"
 #include "jsobj.h"
 #include "jsgc.h"
 #include "xpcpublic.h"
-#include "nsObjectLoadingContent.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
 // |nsIDocument* doc|
 // NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use.
 // If you change how this macro behave please update AttributeChildRemoved.
 #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
@@ -571,30 +570,25 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
 #endif
           if (elm->MayHaveTouchEventListener()) {
             window->SetHasTouchEventListeners();
           }
         }
       }
     }
 
+#ifdef MOZ_MEDIA
     if (wasRegistered && oldDoc != newDoc) {
-#ifdef MOZ_MEDIA
       nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
       if (domMediaElem) {
         nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aNode);
         mediaElem->NotifyOwnerDocumentActivityChanged();
       }
+    }
 #endif
-      nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode));
-      if (objectLoadingContent) {
-        nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
-        olc->NotifyOwnerDocumentActivityChanged();
-      }
-    }
 
     // nsImageLoadingContent needs to know when its document changes
     if (oldDoc != newDoc) {
       nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aNode));
       if (imageContent)
         imageContent->NotifyOwnerDocumentChanged(oldDoc);
     }
 
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -64,17 +64,16 @@
 #include "nsIStreamConverterService.h"
 #include "nsIURILoader.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebNavigationInfo.h"
 #include "nsIScriptChannel.h"
 #include "nsIBlocklistService.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
-#include "nsIAppShell.h"
 
 #include "nsPluginError.h"
 
 // Util headers
 #include "prlog.h"
 
 #include "nsAutoPtr.h"
 #include "nsCURILoader.h"
@@ -93,100 +92,91 @@
 #include "nsFrameLoader.h"
 
 #include "nsObjectLoadingContent.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 #include "mozilla/dom/Element.h"
-#include "nsObjectFrame.h"
-#include "nsDOMClassInfo.h"
-
-#include "nsWidgetsCID.h"
-#include "nsContentCID.h"
-static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
 #endif
 
 #define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG)
 
 class nsAsyncInstantiateEvent : public nsRunnable {
 public:
+  // This stores both the content and the frame so that Instantiate calls can be
+  // avoided if the frame changed in the meantime.
   nsObjectLoadingContent *mContent;
+  nsWeakFrame             mFrame;
   nsCString               mContentType;
   nsCOMPtr<nsIURI>        mURI;
 
   nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent,
+                          nsIFrame* aFrame,
                           const nsCString& aType,
                           nsIURI* aURI)
-  : mContent(aContent), mContentType(aType), mURI(aURI)
+    : mContent(aContent), mFrame(aFrame), mContentType(aType), mURI(aURI)
   {
     static_cast<nsIObjectLoadingContent *>(mContent)->AddRef();
   }
 
   ~nsAsyncInstantiateEvent()
   {
     static_cast<nsIObjectLoadingContent *>(mContent)->Release();
   }
 
   NS_IMETHOD Run();
 };
 
 NS_IMETHODIMP
 nsAsyncInstantiateEvent::Run()
 {
-  // do nothing if we've been revoked
-  if (mContent->mPendingInstantiateEvent != this) {
+  // Check if we've been "revoked"
+  if (mContent->mPendingInstantiateEvent != this)
     return NS_OK;
-  }
   mContent->mPendingInstantiateEvent = nsnull;
 
-  if (LOG_ENABLED()) {
-    nsCAutoString spec;
-    if (mURI) {
-      mURI->GetSpec(spec);
-    }
-    LOG(("OBJLC [%p]: Handling Instantiate event: Type=<%s> URI=%p<%s>\n",
-         mContent, mContentType.get(), mURI.get(), spec.get()));
+  // Make sure that we still have the right frame (NOTE: we don't need to check
+  // the type here - GetExistingFrame() only returns object frames, and that
+  // means we're a plugin)
+  // Also make sure that we still refer to the same data.
+  nsIObjectFrame* frame = mContent->
+    GetExistingFrame(nsObjectLoadingContent::eFlushContent);
+
+  nsIFrame* objectFrame = nsnull;
+  if (frame) {
+    objectFrame = do_QueryFrame(frame);
   }
 
-  return mContent->InstantiatePluginInstance(mContentType.get(), mURI.get());
-}
+  if (objectFrame &&
+      mFrame.GetFrame() == objectFrame &&
+      mContent->mURI == mURI &&
+      mContent->mContentType.Equals(mContentType)) {
+    if (LOG_ENABLED()) {
+      nsCAutoString spec;
+      if (mURI) {
+        mURI->GetSpec(spec);
+      }
+      LOG(("OBJLC [%p]: Handling Instantiate event: Type=<%s> URI=%p<%s>\n",
+           mContent, mContentType.get(), mURI.get(), spec.get()));
+    }
 
-// Checks to see if the content for a plugin instance has a parent.
-// The plugin instance is stopped if there is no parent.
-class InDocCheckEvent : public nsRunnable {
-public:
-  nsCOMPtr<nsIContent> mContent;
-
-  InDocCheckEvent(nsIContent* aContent)
-  : mContent(aContent)
-  {
+    nsresult rv = mContent->Instantiate(frame, mContentType, mURI);
+    if (NS_FAILED(rv)) {
+      mContent->Fallback(PR_TRUE);
+    }
+  } else {
+    LOG(("OBJLC [%p]: Discarding event, data changed\n", mContent));
   }
 
-  ~InDocCheckEvent()
-  {
-  }
-
-  NS_IMETHOD Run();
-};
-
-NS_IMETHODIMP
-InDocCheckEvent::Run()
-{
-  if (!mContent->IsInDoc()) {
-    nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(mContent);
-    if (olc) {
-      olc->StopPluginInstance();
-    }
-  }
   return NS_OK;
 }
 
 /**
  * A task for firing PluginNotFound and PluginBlocklisted DOM Events.
  */
 class nsPluginErrorEvent : public nsRunnable {
 public:
@@ -335,79 +325,16 @@ nsPluginCrashedEvent::Run()
   }
   variant->SetAsBool(mSubmittedCrashReport);
   containerEvent->SetData(NS_LITERAL_STRING("submittedCrashReport"), variant);
 
   nsEventDispatcher::DispatchDOMEvent(mContent, nsnull, event, nsnull, nsnull);
   return NS_OK;
 }
 
-class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  
-  nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
-  : mInstanceOwner(aInstanceOwner)
-  {
-    NS_ASSERTION(aInstanceOwner, "need an owner");
-  }
-  
-  // nsRunnable
-  NS_IMETHOD Run();
-  
-  // nsITimerCallback
-  NS_IMETHOD Notify(nsITimer *timer);
-  
-private:  
-  nsCOMPtr<nsITimer> mTimer;
-  nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
-};
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsStopPluginRunnable, nsRunnable, nsITimerCallback)
-
-NS_IMETHODIMP
-nsStopPluginRunnable::Notify(nsITimer *aTimer)
-{
-  return Run();
-}
-
-NS_IMETHODIMP
-nsStopPluginRunnable::Run()
-{
-  // InitWithCallback calls Release before AddRef so we need to hold a
-  // strong ref on 'this' since we fall through to this scope if it fails.
-  nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
-  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
-  if (appShell) {
-    PRUint32 currentLevel = 0;
-    appShell->GetEventloopNestingLevel(&currentLevel);
-    if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
-      if (!mTimer)
-        mTimer = do_CreateInstance("@mozilla.org/timer;1");
-      if (mTimer) {
-        // Fire 100ms timer to try to tear down this plugin as quickly as
-        // possible once the nesting level comes back down.
-        nsresult rv = mTimer->InitWithCallback(this, 100, nsITimer::TYPE_ONE_SHOT);
-        if (NS_SUCCEEDED(rv)) {
-          return rv;
-        }
-      }
-      NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
-               "time). Stopping the plugin now, this might crash.");
-    }
-  }
-
-  mTimer = nsnull;
-
-  nsObjectLoadingContent::DoStopPlugin(mInstanceOwner, PR_FALSE);
-
-  return NS_OK;
-}
-
 class AutoNotifier {
   public:
     AutoNotifier(nsObjectLoadingContent* aContent, PRBool aNotify) :
       mContent(aContent), mNotify(aNotify) {
         mOldType = aContent->Type();
         mOldState = aContent->ObjectState();
     }
     ~AutoNotifier() {
@@ -564,163 +491,16 @@ nsObjectLoadingContent::nsObjectLoadingC
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   DestroyImageLoadingContent();
   if (mFrameLoader) {
     mFrameLoader->Destroy();
   }
 }
 
-nsresult
-nsObjectLoadingContent::InstantiatePluginInstance(nsIChannel* aChannel, nsIStreamListener** aStreamListener)
-{
-  if (mInstanceOwner) {
-    return NS_OK;
-  }
-
-  mInstanceOwner = new nsPluginInstanceOwner();
-  if (!mInstanceOwner) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsObjectFrame* objectFrame = GetExistingFrame(eFlushLayout);
-
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-  nsresult rv = mInstanceOwner->Init(objectFrame, thisContent);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
-  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (objectFrame) {
-    nsWeakFrame weakFrame(objectFrame);
-
-    objectFrame->SetInstanceOwner(mInstanceOwner.get());
-
-    // This must be done before instantiating the plugin instance
-    objectFrame->FixupWindow(objectFrame->GetContentRectRelativeToSelf().Size());
-    if (weakFrame.IsAlive()) {
-      // Ensure we redraw when a plugin instance is instantiated
-      objectFrame->Invalidate(objectFrame->GetContentRectRelativeToSelf());
-    }
-  }
-
-  return pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
-}
-
-nsresult
-nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI)
-{
-  if (mInstanceOwner) {
-    return NS_OK;
-  }
-  
-  nsCString typeToUse(aMimeType);
-  if (typeToUse.IsEmpty() && aURI) {
-    IsPluginEnabledByExtension(aURI, typeToUse);
-  }
-
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-
-  nsCOMPtr<nsIURI> baseURI;
-  if (!aURI) {
-    // We need some URI. If we have nothing else, use the base URI.
-    // XXX(biesi): The code used to do this. Not sure why this is correct...
-    GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
-    aURI = baseURI;
-  }
-
-  mInstanceOwner = new nsPluginInstanceOwner();
-  if (!mInstanceOwner)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  nsObjectFrame *objectFrame = GetExistingFrame(eFlushLayout);
-
-  nsresult rv = mInstanceOwner->Init(objectFrame, thisContent);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // get the nsIPluginHost service
-  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
-  nsPluginHost* pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
-  if (NS_FAILED(rv))
-    return rv;
-
-  // If you add early return(s), be sure to balance this call to
-  // appShell->SuspendNative() with additional call(s) to
-  // appShell->ReturnNative().
-  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
-  if (appShell) {
-    appShell->SuspendNative();
-  }
-
-  nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(thisContent->GetCurrentDoc()));
-  PRBool fullPageMode = PR_FALSE;
-  if (pDoc) {
-    pDoc->GetWillHandleInstantiation(&fullPageMode);
-  }
-
-  if (fullPageMode) {
-    nsCOMPtr<nsIStreamListener> stream;
-    rv = pluginHost->InstantiateFullPagePlugin(aMimeType, aURI, mInstanceOwner, getter_AddRefs(stream));
-    if (NS_SUCCEEDED(rv)) {
-      pDoc->SetStreamListener(stream);
-    }
-  } else {   /* embedded mode */
-    rv = pluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI, mInstanceOwner);
-  }
-
-  // Note that |this| may very well be destroyed already!
-
-  if (appShell) {
-    appShell->ResumeNative();
-  }
-
-  // Set up scripting interfaces.
-  NotifyContentObjectWrapper();
-
-  // This is necessary here for some reason.
-  if (NS_SUCCEEDED(rv) && objectFrame) {
-    objectFrame->CallSetWindow();
-  }
-
-  nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
-  GetPluginInstance(getter_AddRefs(pluginInstance));
-  if (pluginInstance) {
-    nsCOMPtr<nsIPluginTag> pluginTag;
-    pluginHost->GetPluginTagForInstance(pluginInstance, getter_AddRefs(pluginTag));
-
-    nsCOMPtr<nsIBlocklistService> blocklist =
-    do_GetService("@mozilla.org/extensions/blocklist;1");
-    if (blocklist) {
-      PRUint32 blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
-      blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
-                                         EmptyString(), &blockState);
-      if (blockState == nsIBlocklistService::STATE_OUTDATED)
-        FirePluginError(thisContent, ePluginOutdated);
-    }
-  }
-
-  return rv;
-}
-
-void
-nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
-{
-  if (!mInstanceOwner) {
-    return;
-  }
-
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-  nsIDocument* ownerDoc = thisContent->GetOwnerDoc();
-  if (ownerDoc && !ownerDoc->IsActive()) {
-    StopPluginInstance();
-  }
-}
-
 // nsIRequestObserver
 NS_IMETHODIMP
 nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
                                        nsISupports *aContext)
 {
   if (aRequest != mChannel) {
     // This is a bit of an edge case - happens when a new load starts before the
     // previous one got here
@@ -747,32 +527,35 @@ nsObjectLoadingContent::OnStartRequest(n
   rv = chan->GetContentType(channelType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
     channelType = APPLICATION_OCTET_STREAM;
     chan->SetContentType(channelType);
   }
 
-  // We want to use the channel type unless one of the following is true:
+  // We want to use the channel type unless one of the following is
+  // true:
   //
   // 1) The channel type is application/octet-stream and we have a
   //    type hint and the type hint is not a document type.
   // 2) Our type hint is a type that we support with a plugin.
+
   if ((channelType.EqualsASCII(APPLICATION_OCTET_STREAM) && 
        !mContentType.IsEmpty() &&
        GetTypeOfContent(mContentType) != eType_Document) ||
       // Need to check IsSupportedPlugin() in addition to GetTypeOfContent()
       // because otherwise the default plug-in's catch-all behavior would
       // confuse things.
       (IsSupportedPlugin(mContentType) && 
        GetTypeOfContent(mContentType) == eType_Plugin)) {
     // Set the type we'll use for dispatch on the channel.  Otherwise we could
     // end up trying to dispatch to a nsFrameLoader, which will complain that
     // it couldn't find a way to handle application/octet-stream
+
     nsCAutoString typeHint, dummy;
     NS_ParseContentType(mContentType, typeHint, dummy);
     if (!typeHint.IsEmpty()) {
       chan->SetContentType(typeHint);
     }
   } else {
     mContentType = channelType;
   }
@@ -899,23 +682,52 @@ nsObjectLoadingContent::OnStartRequest(n
       nsCOMPtr<nsIURILoader>
         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID, &rv));
       NS_ENSURE_SUCCESS(rv, rv);
       rv = uriLoader->OpenChannel(chan, nsIURILoader::DONT_RETARGET, req,
                                   getter_AddRefs(mFinalListener));
       break;
     }
     case eType_Plugin:
-        mInstantiating = PR_TRUE;
-        rv = InstantiatePluginInstance(chan, getter_AddRefs(mFinalListener));
+      mInstantiating = PR_TRUE;
+      if (mType != newType) {
+        // This can go away once plugin loading moves to content (bug 90268)
+        mType = newType;
+        notifier.Notify();
+      }
+      nsIObjectFrame* frame;
+      frame = GetExistingFrame(eFlushLayout);
+      if (!frame) {
+        // Do nothing in this case: This is probably due to a display:none
+        // frame. If we ever get a frame, HasNewFrame will do the right thing.
+        // Abort the load though, we have no use for the data.
         mInstantiating = PR_FALSE;
+        return NS_BINDING_ABORTED;
+      }
+
+      {
+        nsIFrame *nsiframe = do_QueryFrame(frame);
+
+        nsWeakFrame weakFrame(nsiframe);
+
+        rv = frame->Instantiate(chan, getter_AddRefs(mFinalListener));
+
+        mInstantiating = PR_FALSE;
+
+        if (!weakFrame.IsAlive()) {
+          // The frame was destroyed while instantiating. Abort the load.
+          return NS_BINDING_ABORTED;
+        }
+      }
+
       break;
     case eType_Loading:
       NS_NOTREACHED("Should not have a loading type here!");
     case eType_Null:
+      LOG(("OBJLC [%p]: Unsupported type, falling back\n", this));
       // Need to fallback here (instead of using the case below), so that we can
       // set mFallbackReason without it being overwritten. This is also why we
       // return early.
       Fallback(PR_FALSE);
 
       PluginSupportState pluginState = GetPluginSupportState(thisContent,
                                                              mContentType);
       // Do nothing, but fire the plugin not found event if needed
@@ -925,31 +737,41 @@ nsObjectLoadingContent::OnStartRequest(n
       }
       return NS_BINDING_ABORTED;
   }
 
   if (mFinalListener) {
     mType = newType;
     rv = mFinalListener->OnStartRequest(aRequest, aContext);
     if (NS_FAILED(rv)) {
+      LOG(("OBJLC [%p]: mFinalListener->OnStartRequest failed (%08x), falling back\n",
+           this, rv));
 #ifdef XP_MACOSX
       // Shockwave on Mac is special and returns an error here even when it
       // handles the content
       if (mContentType.EqualsLiteral("application/x-director")) {
+        LOG(("OBJLC [%p]: (ignoring)\n", this));
         rv = NS_OK; // otherwise, the AutoFallback will make us fall back
         return NS_BINDING_ABORTED;
       }
 #endif
       Fallback(PR_FALSE);
     } else if (mType == eType_Plugin) {
-      TryNotifyContentObjectWrapper();
+      nsIObjectFrame* frame = GetExistingFrame(eFlushContent);
+      if (frame) {
+        // We have to notify the wrapper here instead of right after
+        // Instantiate because the plugin only gets instantiated by
+        // OnStartRequest, not by Instantiate.
+        frame->TryNotifyContentObjectWrapper();
+      }
     }
     return rv;
   }
 
+  LOG(("OBJLC [%p]: Found no listener, falling back\n", this));
   Fallback(PR_FALSE);
   return NS_BINDING_ABORTED;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::OnStopRequest(nsIRequest *aRequest,
                                       nsISupports *aContext,
                                       nsresult aStatusCode)
@@ -1019,59 +841,174 @@ nsObjectLoadingContent::GetActualType(ns
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetDisplayedType(PRUint32* aType)
 {
   *aType = mType;
   return NS_OK;
 }
 
+
 NS_IMETHODIMP
-nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
+nsObjectLoadingContent::EnsureInstantiation(nsNPAPIPluginInstance** aInstance)
 {
-  // Not having an instance yet is OK.
-  if (!mInstanceOwner) {
+  // Must set our out parameter to null as we have various early returns with
+  // an NS_OK result.
+  *aInstance = nsnull;
+
+  if (mType != eType_Plugin) {
     return NS_OK;
   }
 
-  // Disconnect any existing frame
-  DisconnectFrame();
+  nsIObjectFrame* frame = GetExistingFrame(eFlushContent);
+  if (frame) {
+    // If we have a frame, we may have pending instantiate events; revoke
+    // them.
+    if (mPendingInstantiateEvent) {
+      LOG(("OBJLC [%p]: Revoking pending instantiate event\n", this));
+      mPendingInstantiateEvent = nsnull;
+    }
+  } else {
+    // mInstantiating is true if we're in LoadObject; we shouldn't
+    // recreate frames in that case, we'd confuse that function.
+    if (mInstantiating) {
+      return NS_OK;
+    }
+
+    // Trigger frame construction
+    mInstantiating = PR_TRUE;
+
+    nsCOMPtr<nsIContent> thisContent = 
+      do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+    NS_ASSERTION(thisContent, "must be a content");
+
+    nsIDocument* doc = thisContent->GetCurrentDoc();
+    if (!doc) {
+      // Nothing we can do while plugin loading is done in layout...
+      mInstantiating = PR_FALSE;
+      return NS_OK;
+    }
+
+    doc->FlushPendingNotifications(Flush_Frames);
+
+    mInstantiating = PR_FALSE;
 
-  // Set up relationship between instance owner and frame.
-  nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
-  mInstanceOwner->SetFrame(objFrame);
-  objFrame->SetInstanceOwner(mInstanceOwner);
+    frame = GetExistingFrame(eFlushContent);
+    if (!frame) {
+      return NS_OK;
+    }
+  }
+
+  nsIFrame *nsiframe = do_QueryFrame(frame);
+
+  if (nsiframe->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+    // A frame for this plugin element already exists now, but it has
+    // not been reflowed yet. Force a reflow now so that we don't end
+    // up initializing a plugin before knowing its size. Also re-fetch
+    // the frame, as flushing can cause the frame to be deleted.
+    frame = GetExistingFrame(eFlushLayout);
 
-  // Set up new frame to draw.
-  objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
-  objFrame->Invalidate(objFrame->GetContentRectRelativeToSelf());
+    if (!frame) {
+      return NS_OK;
+    }
+
+    nsiframe = do_QueryFrame(frame);
+  }
+
+  nsWeakFrame weakFrame(nsiframe);
 
-  return NS_OK;
+  // We may have a plugin instance already; if so, do nothing
+  nsresult rv = frame->GetPluginInstance(aInstance);
+  if (!*aInstance && weakFrame.IsAlive()) {
+    rv = Instantiate(frame, mContentType, mURI);
+    if (NS_SUCCEEDED(rv) && weakFrame.IsAlive()) {
+      rv = frame->GetPluginInstance(aInstance);
+    } else {
+      Fallback(PR_TRUE);
+    }
+  }
+  return rv;
 }
 
 NS_IMETHODIMP
-nsObjectLoadingContent::DisconnectFrame()
+nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
 {
-  if (mInstanceOwner) {
-    mInstanceOwner->SetFrame(nsnull);
+  LOG(("OBJLC [%p]: Got frame %p (mInstantiating=%i)\n", this, aFrame,
+       mInstantiating));
+
+  nsCOMPtr<nsIContent> thisContent = 
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  NS_ASSERTION(thisContent, "must be a content");
+  nsIDocument* doc = thisContent->GetOwnerDoc();
+  if (!doc || doc->IsStaticDocument() || doc->IsBeingUsedAsImage()) {
+    return NS_OK;
+  }
+
+  // "revoke" any existing instantiate event as it likely has out of
+  // date data (frame pointer etc).
+  mPendingInstantiateEvent = nsnull;
+
+  nsRefPtr<nsNPAPIPluginInstance> instance;
+  aFrame->GetPluginInstance(getter_AddRefs(instance));
+
+  if (instance) {
+    // The frame already has a plugin instance, that means the plugin
+    // has already been instantiated.
+
+    return NS_OK;
   }
 
+  if (!mInstantiating && mType == eType_Plugin) {
+    // Asynchronously call Instantiate
+    // This can go away once plugin loading moves to content
+    // This must be done asynchronously to ensure that the frame is correctly
+    // initialized (has a view etc)
+
+    // When in a plugin document, the document will take care of calling
+    // instantiate
+    nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(GetOurDocument()));
+    if (pDoc) {
+      PRBool willHandleInstantiation;
+      pDoc->GetWillHandleInstantiation(&willHandleInstantiation);
+      if (willHandleInstantiation) {
+        return NS_OK;
+      }
+    }
+
+    nsIFrame* frame = do_QueryFrame(aFrame);
+    nsCOMPtr<nsIRunnable> event =
+      new nsAsyncInstantiateEvent(this, frame, mContentType, mURI);
+    if (!event) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    LOG(("                 dispatching event\n"));
+    nsresult rv = NS_DispatchToCurrentThread(event);
+    if (NS_FAILED(rv)) {
+      NS_ERROR("failed to dispatch nsAsyncInstantiateEvent");
+    } else {
+      // Remember this event.  This is a weak reference that will be cleared
+      // when the event runs.
+      mPendingInstantiateEvent = event;
+    }
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
 {
   *aInstance = nsnull;
 
-  if (!mInstanceOwner) {
+  nsIObjectFrame* objFrame = GetExistingFrame(eDontFlush);
+  if (!objFrame) {
     return NS_OK;
   }
 
-  return mInstanceOwner->GetInstance(aInstance);
+  return objFrame->GetPluginInstance(aInstance);
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
                                                   PRUint32* aType)
 {
   *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType));
   return NS_OK;
@@ -1224,27 +1161,31 @@ nsObjectLoadingContent::UpdateFallbackSt
 }
 
 nsresult
 nsObjectLoadingContent::LoadObject(nsIURI* aURI,
                                    PRBool aNotify,
                                    const nsCString& aTypeHint,
                                    PRBool aForceLoad)
 {
+  LOG(("OBJLC [%p]: Loading object: URI=<%p> notify=%i type=<%s> forceload=%i\n",
+       this, aURI, aNotify, aTypeHint.get(), aForceLoad));
+
   if (mURI && aURI && !aForceLoad) {
     PRBool equal;
     nsresult rv = mURI->Equals(aURI, &equal);
     if (NS_SUCCEEDED(rv) && equal) {
       // URI didn't change, do nothing
       return NS_OK;
     }
   }
 
   // Need to revoke any potentially pending instantiate events
   if (mType == eType_Plugin && mPendingInstantiateEvent) {
+    LOG(("OBJLC [%p]: Revoking pending instantiate event\n", this));
     mPendingInstantiateEvent = nsnull;
   }
 
   AutoNotifier notifier(this, aNotify);
 
   // AutoSetInstantiatingToFalse is instantiated after AutoNotifier, so that if
   // the AutoNotifier triggers frame construction, events can be posted as
   // appropriate.
@@ -1373,17 +1314,17 @@ nsObjectLoadingContent::LoadObject(nsIUR
         // Don't notify, because we will take care of that ourselves.
         if (aURI) {
           rv = LoadImage(aURI, aForceLoad, PR_FALSE);
         } else {
           rv = NS_ERROR_NOT_AVAILABLE;
         }
         break;
       case eType_Plugin:
-        rv = StartPluginInstance();
+        rv = TryInstantiate(mContentType, mURI);
         break;
       case eType_Document:
         if (aURI) {
           rv = mFrameLoader->LoadURI(aURI);
         } else {
           rv = NS_ERROR_NOT_AVAILABLE;
         }
         break;
@@ -1408,25 +1349,27 @@ nsObjectLoadingContent::LoadObject(nsIUR
     if (!classid.IsEmpty()) {
       hasID = PR_TRUE;
       isSupportedClassID = NS_SUCCEEDED(TypeForClassID(classid, typeForID));
     }
   }
 
   if (hasID && !isSupportedClassID) {
     // We have a class ID and it's unsupported.  Fallback in that case.
+    LOG(("OBJLC [%p]: invalid classid\n", this));
     rv = NS_ERROR_NOT_AVAILABLE;
     return NS_OK;
   }
 
   if (isSupportedClassID ||
       (!aURI && !aTypeHint.IsEmpty() &&
        GetTypeOfContent(aTypeHint) == eType_Plugin)) {
     // No URI, but we have a type. The plugin will handle the load.
     // Or: supported class id, plugin will handle the load.
+    LOG(("OBJLC [%p]: (classid) Changing type from %u to eType_Plugin\n", this, mType));
     mType = eType_Plugin;
 
     // At this point, the stored content type
     // must be equal to our type hint. Similar,
     // our URI must be the requested URI.
     // (->Equals would suffice, but == is cheaper
     // and handles NULL)
     NS_ASSERTION(mContentType.Equals(aTypeHint), "mContentType wrong!");
@@ -1440,44 +1383,46 @@ nsObjectLoadingContent::LoadObject(nsIUR
       // here instead of the plugin URI for instantiation via class ID, so I
       // continue to do so. Why that is, no idea...
       GetObjectBaseURI(thisContent, getter_AddRefs(mURI));
       if (!mURI) {
         mURI = aURI;
       }
     }
 
-    // rv is references by a stack-based object, need to assign here
-    rv = StartPluginInstance();
-
-    return rv;
+    rv = TryInstantiate(mContentType, mURI);
+    return NS_OK;
   }
 
   if (!aURI) {
     // No URI and if we have got this far no enabled plugin supports the type
+    LOG(("OBJLC [%p]: no URI\n", this));
     rv = NS_ERROR_NOT_AVAILABLE;
 
     // We should only notify the UI if there is at least a type to go on for
     // finding a plugin to use, unless it's a supported image or document type.
     if (!aTypeHint.IsEmpty() && GetTypeOfContent(aTypeHint) == eType_Null) {
       UpdateFallbackState(thisContent, fallback, aTypeHint);
     }
 
     return NS_OK;
   }
 
   // E.g. mms://
   if (!CanHandleURI(aURI)) {
+    LOG(("OBJLC [%p]: can't handle URI\n", this));
     if (aTypeHint.IsEmpty()) {
       rv = NS_ERROR_NOT_AVAILABLE;
       return NS_OK;
     }
 
     if (IsSupportedPlugin(aTypeHint)) {
       mType = eType_Plugin;
+
+      rv = TryInstantiate(aTypeHint, aURI);
     } else {
       rv = NS_ERROR_NOT_AVAILABLE;
       // No plugin to load, notify of the failure.
       UpdateFallbackState(thisContent, fallback, aTypeHint);
     }
 
     return NS_OK;
   }
@@ -1553,46 +1498,36 @@ nsObjectLoadingContent::GetCapabilities(
          eSupportPlugins |
          eSupportDocuments |
          eSupportSVG;
 }
 
 void
 nsObjectLoadingContent::Fallback(PRBool aNotify)
 {
+  LOG(("OBJLC [%p]: Falling back (Notify=%i)\n", this, aNotify));
+
   AutoNotifier notifier(this, aNotify);
 
   UnloadContent();
 }
 
 void
 nsObjectLoadingContent::RemovedFromDocument()
 {
+  LOG(("OBJLC [%p]: Removed from doc\n", this));
   if (mFrameLoader) {
     // XXX This is very temporary and must go away
     mFrameLoader->Destroy();
     mFrameLoader = nsnull;
 
     // Clear the current URI, so that LoadObject doesn't think that we
     // have already loaded the content.
     mURI = nsnull;
   }
-
-  // When a plugin instance node is removed from the document 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 stop
-  // the plugin.
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-  nsCOMPtr<nsIRunnable> event = new InDocCheckEvent(thisContent);
-
-  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
-  if (appShell) {
-    appShell->RunInStableState(event);
-  }
 }
 
 /* static */
 void
 nsObjectLoadingContent::Traverse(nsObjectLoadingContent *tmp,
                                  nsCycleCollectionTraversalCallback &cb)
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameLoader");
@@ -1847,20 +1782,22 @@ nsObjectLoadingContent::GetObjectBaseURI
     nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
                                               thisContent->GetOwnerDoc(),
                                               baseURI);
   } else {
     baseURI.swap(*aURI);
   }
 }
 
-nsObjectFrame*
+nsIObjectFrame*
 nsObjectLoadingContent::GetExistingFrame(FlushType aFlushType)
 {
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  nsCOMPtr<nsIContent> thisContent = 
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  NS_ASSERTION(thisContent, "must be a content");
 
   nsIFrame* frame;
   do {
     frame = thisContent->GetPrimaryFrame();
     if (!frame) {
       return nsnull;
     }
 
@@ -1875,17 +1812,17 @@ nsObjectLoadingContent::GetExistingFrame
     mozFlushType flushType =
       aFlushType == eFlushLayout ? Flush_Layout : Flush_ContentAndNotify;
     doc->FlushPendingNotifications(flushType);
 
     aFlushType = eDontFlush;
   } while (1);
 
   nsIObjectFrame* objFrame = do_QueryFrame(frame);
-  return static_cast<nsObjectFrame*>(objFrame);
+  return objFrame;
 }
 
 void
 nsObjectLoadingContent::HandleBeingBlockedByContentPolicy(nsresult aStatus,
                                                           PRInt16 aRetval)
 {
   // Must call UnloadContent first, as it overwrites
   // mSuppressed/mUserDisabled. It also takes care of setting the type to
@@ -1895,16 +1832,115 @@ nsObjectLoadingContent::HandleBeingBlock
     if (aRetval == nsIContentPolicy::REJECT_TYPE) {
       mUserDisabled = PR_TRUE;
     } else if (aRetval == nsIContentPolicy::REJECT_SERVER) {
       mSuppressed = PR_TRUE;
     }
   }
 }
 
+nsresult
+nsObjectLoadingContent::TryInstantiate(const nsACString& aMIMEType,
+                                       nsIURI* aURI)
+{
+  nsIObjectFrame* frame = GetExistingFrame(eFlushContent);
+  if (!frame) {
+    LOG(("OBJLC [%p]: No frame yet\n", this));
+    return NS_OK; // Not a failure to have no frame
+  }
+
+  nsRefPtr<nsNPAPIPluginInstance> instance;
+  frame->GetPluginInstance(getter_AddRefs(instance));
+
+  if (!instance) {
+    // The frame has no plugin instance yet. If the frame hasn't been
+    // reflowed yet, do nothing as once the reflow happens we'll end up
+    // instantiating the plugin with the correct size n' all (which
+    // isn't known until we've done the first reflow). But if the
+    // frame does have a plugin instance already, be sure to
+    // re-instantiate the plugin as its source or whatnot might have
+    // chanced since it was instantiated.
+    nsIFrame* iframe = do_QueryFrame(frame);
+    if (iframe->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+      LOG(("OBJLC [%p]: Frame hasn't been reflowed yet\n", this));
+      return NS_OK; // Not a failure to have no frame
+    }
+  }
+
+  return Instantiate(frame, aMIMEType, aURI);
+}
+
+nsresult
+nsObjectLoadingContent::Instantiate(nsIObjectFrame* aFrame,
+                                    const nsACString& aMIMEType,
+                                    nsIURI* aURI)
+{
+  NS_ASSERTION(aFrame, "Must have a frame here");
+
+  // We're instantiating now, invalidate any pending async instantiate
+  // calls.
+  mPendingInstantiateEvent = nsnull;
+
+  // Mark that we're instantiating now so that we don't end up
+  // re-entering instantiation code.
+  PRBool oldInstantiatingValue = mInstantiating;
+  mInstantiating = PR_TRUE;
+
+  nsCString typeToUse(aMIMEType);
+  if (typeToUse.IsEmpty() && aURI) {
+    IsPluginEnabledByExtension(aURI, typeToUse);
+  }
+
+  nsCOMPtr<nsIContent> thisContent = 
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  NS_ASSERTION(thisContent, "must be a content");
+  
+  nsCOMPtr<nsIURI> baseURI;
+  if (!aURI) {
+    // We need some URI. If we have nothing else, use the base URI.
+    // XXX(biesi): The code used to do this. Not sure why this is correct...
+    GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
+    aURI = baseURI;
+  }
+
+  nsIFrame *nsiframe = do_QueryFrame(aFrame);
+  nsWeakFrame weakFrame(nsiframe);
+
+  // We'll always have a type or a URI by the time we get here
+  NS_ASSERTION(aURI || !typeToUse.IsEmpty(), "Need a URI or a type");
+  LOG(("OBJLC [%p]: Calling [%p]->Instantiate(<%s>, %p)\n", this, aFrame,
+       typeToUse.get(), aURI));
+  nsresult rv = aFrame->Instantiate(typeToUse.get(), aURI);
+
+  mInstantiating = oldInstantiatingValue;
+
+  nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
+  if (weakFrame.IsAlive()) {
+    aFrame->GetPluginInstance(getter_AddRefs(pluginInstance));
+  }
+  if (pluginInstance) {
+    nsCOMPtr<nsIPluginTag> pluginTag;
+    nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+    static_cast<nsPluginHost*>(host.get())->
+      GetPluginTagForInstance(pluginInstance, getter_AddRefs(pluginTag));
+
+    nsCOMPtr<nsIBlocklistService> blocklist =
+      do_GetService("@mozilla.org/extensions/blocklist;1");
+    if (blocklist) {
+      PRUint32 blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
+      blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
+                                         EmptyString(), &blockState);
+      if (blockState == nsIBlocklistService::STATE_OUTDATED)
+        FirePluginError(thisContent, ePluginOutdated);
+    }
+  }
+
+  return rv;
+}
+
 /* static */ PluginSupportState
 nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
                                               const nsCString& aContentType)
 {
   if (!aContent->IsHTML()) {
     return ePluginOtherState;
   }
 
@@ -1959,17 +1995,20 @@ nsObjectLoadingContent::CreateStaticClon
 {
   nsImageLoadingContent::CreateStaticImageClone(aDest);
 
   aDest->mType = mType;
   nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
   if (thisObj->mPrintFrame.IsAlive()) {
     aDest->mPrintFrame = thisObj->mPrintFrame;
   } else {
-    aDest->mPrintFrame = const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame(eDontFlush);
+    nsIObjectFrame* frame =
+      const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame(eDontFlush);
+    nsIFrame* f = do_QueryFrame(frame);
+    aDest->mPrintFrame = f;
   }
 
   if (mFrameLoader) {
     nsCOMPtr<nsIContent> content =
       do_QueryInterface(static_cast<nsIImageLoadingContent*>((aDest)));
     nsFrameLoader* fl = nsFrameLoader::Create(content, PR_FALSE);
     if (fl) {
       aDest->mFrameLoader = fl;
@@ -2010,188 +2049,8 @@ nsObjectLoadingContent::PluginCrashed(ns
                                                       NS_ConvertUTF8toUTF16(pluginFilename),
                                                       submittedCrashReport);
   nsresult rv = NS_DispatchToCurrentThread(ev);
   if (NS_FAILED(rv)) {
     NS_WARNING("failed to dispatch nsPluginCrashedEvent");
   }
   return NS_OK;
 }
-
-NS_IMETHODIMP
-nsObjectLoadingContent::StartPluginInstance()
-{
-  // OK to have an instance already.
-  if (mInstanceOwner) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-  nsIDocument* doc = thisContent->GetOwnerDoc();
-  if (!doc || doc->IsStaticDocument() || doc->IsBeingUsedAsImage()) {
-    return NS_OK;
-  }
-
-  // We always start plugins on a runnable.
-  // We don't want a script blocker on the stack during instantiation.
-  nsCOMPtr<nsIRunnable> event = new nsAsyncInstantiateEvent(this, mContentType, mURI);
-  if (!event) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsresult rv = NS_DispatchToCurrentThread(event);
-  if (NS_SUCCEEDED(rv)) {
-    // Remember this event.  This is a weak reference that will be cleared
-    // when the event runs.
-    mPendingInstantiateEvent = event;
-  }
-
-  return rv;
-}
-
-static PRBool
-DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
-{
-#if (MOZ_PLATFORM_MAEMO==5)
-  // Don't delay stop on Maemo/Hildon (bug 530739).
-  if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
-    return PR_FALSE;
-#endif
-  
-  // Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
-  // XStandard (bug 430219), CMISS Zinc (bug 429604).
-  if (aDelayedStop
-#if !(defined XP_WIN || defined MOZ_X11)
-      && !aInstanceOwner->MatchPluginName("QuickTime")
-      && !aInstanceOwner->MatchPluginName("Flip4Mac")
-      && !aInstanceOwner->MatchPluginName("XStandard plugin")
-      && !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
-#endif
-      ) {
-    nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(aInstanceOwner);
-    NS_DispatchToCurrentThread(evt);
-    return PR_TRUE;
-  }
-  return PR_FALSE;
-}
-
-void
-nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
-{
-  nsRefPtr<nsNPAPIPluginInstance> inst;
-  aInstanceOwner->GetInstance(getter_AddRefs(inst));
-  if (inst) {
-    NPWindow *win;
-    aInstanceOwner->GetWindow(win);
-    
-    nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
-    if (window) {
-      nsRefPtr<nsNPAPIPluginInstance> nullinst;
-      window->CallSetWindow(nullinst);
-    } else {
-      inst->SetWindow(nsnull);
-    }
-
-    if (DoDelayedStop(aInstanceOwner, aDelayedStop)) {
-      return;
-    }
-
-#if defined(XP_MACOSX)
-    aInstanceOwner->HidePluginWindow();
-#endif
-    
-    nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
-    NS_ASSERTION(pluginHost, "Without a pluginHost, how can we have an instance to destroy?");
-    static_cast<nsPluginHost*>(pluginHost.get())->StopPluginInstance(inst);
-
-    if (window) {
-      window->SetPluginWidget(nsnull);
-    }
-  }
-  
-  aInstanceOwner->Destroy();
-}
-
-NS_IMETHODIMP
-nsObjectLoadingContent::StopPluginInstance()
-{
-  if (!mInstanceOwner) {
-    return NS_OK;
-  }
-
-  DisconnectFrame();
-
-  PRBool delayedStop = PR_FALSE;
-#ifdef XP_WIN
-  // Force delayed stop for Real plugin only; see bug 420886, 426852.
-  nsRefPtr<nsNPAPIPluginInstance> inst;
-  mInstanceOwner->GetInstance(getter_AddRefs(inst));
-  if (inst) {
-    const char* mime = nsnull;
-    if (NS_SUCCEEDED(inst->GetMIMEType(&mime)) && mime) {
-      if (strcmp(mime, "audio/x-pn-realaudio-plugin") == 0) {
-        delayedStop = PR_TRUE;
-      }      
-    }
-  }
-#endif
-
-  DoStopPlugin(mInstanceOwner, delayedStop);
-
-  mInstanceOwner = nsnull;
-
-  return NS_OK;
-}
-
-void
-nsObjectLoadingContent::TryNotifyContentObjectWrapper()
-{
-  if (!mInstanceOwner) {
-    return;
-  }
-
-  nsRefPtr<nsNPAPIPluginInstance> inst;
-  mInstanceOwner->GetInstance(getter_AddRefs(inst));
-  if (!inst) {
-    return;
-  }
-
-  NotifyContentObjectWrapper();
-}
-
-void
-nsObjectLoadingContent::NotifyContentObjectWrapper()
-{
-  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-
-  nsCOMPtr<nsIDocument> doc = thisContent->GetDocument();
-  if (!doc)
-    return;
-  
-  nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
-  if (!sgo)
-    return;
-  
-  nsIScriptContext *scx = sgo->GetContext();
-  if (!scx)
-    return;
-  
-  JSContext *cx = (JSContext *)scx->GetNativeContext();
-  
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-  nsContentUtils::XPConnect()->
-  GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), thisContent,
-                                 NS_GET_IID(nsISupports),
-                                 getter_AddRefs(wrapper));
-  
-  if (!wrapper) {
-    // Nothing to do here if there's no wrapper for mContent. The proto
-    // chain will be fixed appropriately when the wrapper is created.
-    return;
-  }
-  
-  JSObject *obj = nsnull;
-  nsresult rv = wrapper->GetJSObject(&obj);
-  if (NS_FAILED(rv))
-    return;
-  
-  nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
-}
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -48,25 +48,21 @@
 #include "nsImageLoadingContent.h"
 #include "nsIStreamListener.h"
 #include "nsFrameLoader.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIRunnable.h"
 #include "nsIFrame.h"
-#include "nsPluginInstanceOwner.h"
-#include "nsIThreadInternal.h"
 
 class nsAsyncInstantiateEvent;
-class nsStopPluginRunnable;
 class AutoNotifier;
 class AutoFallback;
 class AutoSetInstantiatingToFalse;
-class nsObjectFrame;
 
 enum PluginSupportState {
   ePluginUnsupported,  // The plugin is not supported (e.g. not installed)
   ePluginDisabled,     // The plugin has been explicitly disabled by the user
   ePluginBlocklisted,  // The plugin is blocklisted and disabled
   ePluginOutdated,     // The plugin is considered outdated, but not disabled
   ePluginOtherState,   // Something else (e.g. uninitialized or not a plugin)
   ePluginCrashed
@@ -95,18 +91,16 @@ class nsObjectLoadingContent : public ns
                              , public nsIFrameLoaderOwner
                              , public nsIObjectLoadingContent
                              , public nsIInterfaceRequestor
                              , public nsIChannelEventSink
 {
   friend class AutoNotifier;
   friend class AutoFallback;
   friend class AutoSetInstantiatingToFalse;
-  friend class nsStopPluginRunnable;
-  friend class nsAsyncInstantiateEvent;
 
   public:
     // This enum's values must be the same as the constants on
     // nsIObjectLoadingContent
     enum ObjectType {
       eType_Loading  = TYPE_LOADING,  ///< Type not yet known
       eType_Image    = TYPE_IMAGE,    ///< This content is an image
       eType_Plugin   = TYPE_PLUGIN,   ///< This content is a plugin
@@ -139,26 +133,17 @@ class nsObjectLoadingContent : public ns
      * NS_EVENT_STATE_SUPPRESSED representing the current state of the object.
      */
     nsEventStates ObjectState() const;
 
     void SetIsNetworkCreated(PRBool aNetworkCreated)
     {
       mNetworkCreated = aNetworkCreated;
     }
-
-    // Both "InstantiatePluginInstance" methods can flush layout.
-    nsresult InstantiatePluginInstance(nsIChannel* aChannel,
-                                       nsIStreamListener** aStreamListener);
-    nsresult InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI);
-
-    void NotifyOwnerDocumentActivityChanged();
-
   protected:
-
     /**
      * Load the object from the given URI.
      * @param aURI       The URI to load.
      * @param aNotify If true, nsIDocumentObserver state change notifications
      *                will be sent as needed.
      * @param aTypeHint  MIME Type hint. Overridden by the server unless this
      *                   class has the eOverrideServerType capability.
      * @param aForceLoad If true, the object will be refetched even if the URI
@@ -236,24 +221,17 @@ class nsObjectLoadingContent : public ns
      * XXX This is a temporary workaround for docshell suckyness
      */
     void RemovedFromDocument();
 
     static void Traverse(nsObjectLoadingContent *tmp,
                          nsCycleCollectionTraversalCallback &cb);
 
     void CreateStaticClone(nsObjectLoadingContent* aDest) const;
-  
-    static void DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop);
-
   private:
-
-    void TryNotifyContentObjectWrapper();
-    void NotifyContentObjectWrapper();
-
     /**
      * Check whether the given request represents a successful load.
      */
     static PRBool IsSuccessfulRequest(nsIRequest* aRequest);
 
     /**
      * Check whether the URI can be handled internally.
      */
@@ -322,27 +300,43 @@ class nsObjectLoadingContent : public ns
      *   eFlushLayout is needed in some cases by plug-ins to ensure
      *   that NPP_SetWindow() gets called (from nsObjectFrame::DidReflow).
      */
     enum FlushType {
       eFlushContent,
       eFlushLayout,
       eDontFlush
     };
-    nsObjectFrame* GetExistingFrame(FlushType aFlushType);
+    nsIObjectFrame* GetExistingFrame(FlushType aFlushType);
 
     /**
      * Handle being blocked by a content policy.  aStatus is the nsresult
      * return value of the Should* call, while aRetval is what it returned in
      * its out parameter.
      */
     void HandleBeingBlockedByContentPolicy(nsresult aStatus,
                                            PRInt16 aRetval);
 
     /**
+     * Checks if we have a frame that's ready for instantiation, and
+     * if so, calls Instantiate(). Note that this can cause the frame
+     * to be deleted while we're instantiating the plugin.
+     */
+    nsresult TryInstantiate(const nsACString& aMIMEType, nsIURI* aURI);
+
+    /**
+     * Instantiates the plugin. This differs from
+     * GetFrame()->Instantiate() in that it ensures that the URI will
+     * be non-null, and that a MIME type will be passed. Note that
+     * this can cause the frame to be deleted while we're
+     * instantiating the plugin.
+     */
+    nsresult Instantiate(nsIObjectFrame* aFrame, const nsACString& aMIMEType, nsIURI* aURI);
+
+    /**
      * Get the plugin support state for the given content node and MIME type.
      * This is used for purposes of determining whether to fire PluginNotFound
      * events etc.  aContentType is the MIME type we ended up with.
      *
      * This should only be called if the type of this content is eType_Null.
      */
     static PluginSupportState
       GetPluginSupportState(nsIContent* aContent,
@@ -415,12 +409,13 @@ class nsObjectLoadingContent : public ns
     // it may lose the flag.
     PRPackedBool                mNetworkCreated : 1;
 
     // A specific state that caused us to fallback
     PluginSupportState          mFallbackReason;
 
     nsWeakFrame                 mPrintFrame;
 
-    nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
+    friend class nsAsyncInstantiateEvent;
 };
 
+
 #endif
--- a/content/html/document/src/PluginDocument.cpp
+++ b/content/html/document/src/PluginDocument.cpp
@@ -42,17 +42,16 @@
 #include "nsIObjectFrame.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIPropertyBag2.h"
 #include "mozilla/dom/Element.h"
-#include "nsObjectLoadingContent.h"
 
 namespace mozilla {
 namespace dom {
 
 class PluginDocument : public MediaDocument
                      , public nsIPluginDocument
 {
 public:
@@ -140,23 +139,30 @@ PluginStreamListener::SetupPlugin()
     return NS_BINDING_ABORTED;
   }
 
   // Flush out layout before we go to instantiate, because some
   // plug-ins depend on NPP_SetWindow() being called early enough and
   // nsObjectFrame does that at the end of reflow.
   shell->FlushPendingNotifications(Flush_Layout);
 
-  nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(embed));
-  if (!olc) {
+  nsIFrame* frame = embed->GetPrimaryFrame();
+  if (!frame) {
+    mPluginDoc->AllowNormalInstantiation();
+    return NS_OK;
+  }
+
+  nsIObjectFrame* objFrame = do_QueryFrame(frame);
+  if (!objFrame) {
+    mPluginDoc->AllowNormalInstantiation();
     return NS_ERROR_UNEXPECTED;
   }
-  nsObjectLoadingContent* olcc = static_cast<nsObjectLoadingContent*>(olc.get());
-  nsresult rv = olcc->InstantiatePluginInstance(mPluginDoc->GetType().get(),
-                                                mDocument->nsIDocument::GetDocumentURI());
+
+  nsresult rv = objFrame->Instantiate(mPluginDoc->GetType().get(),
+                                      mDocument->nsIDocument::GetDocumentURI());
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Now that we're done, allow normal instantiation in the future
   // (say if there's a reframe of this entire presentation).
   mPluginDoc->AllowNormalInstantiation();
 
@@ -344,17 +350,17 @@ PluginDocument::SetStreamListener(nsIStr
 NS_IMETHODIMP
 PluginDocument::Print()
 {
   NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE);
 
   nsIObjectFrame* objectFrame =
     do_QueryFrame(mPluginContent->GetPrimaryFrame());
   if (objectFrame) {
-    nsRefPtr<nsNPAPIPluginInstance> pi;
+    nsCOMPtr<nsNPAPIPluginInstance> pi;
     objectFrame->GetPluginInstance(getter_AddRefs(pi));
     if (pi) {
       NPPrint npprint;
       npprint.mode = NP_FULL;
       npprint.print.fullPrint.pluginPrinted = PR_FALSE;
       npprint.print.fullPrint.printOne = PR_FALSE;
       npprint.print.fullPrint.platformPrint = nsnull;
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -9225,17 +9225,24 @@ nsHTMLPluginObjElementSH::GetPluginInsta
   *_result = nsnull;
 
   nsCOMPtr<nsIContent> content(do_QueryWrappedNative(wrapper, obj));
   NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
 
   nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(content));
   NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
 
-  return objlc->GetPluginInstance(_result);
+  // If it's not safe to run script we'll only return the instance if it
+  // exists.
+  if (!nsContentUtils::IsSafeToRunScript()) {
+    return objlc->GetPluginInstance(_result);
+  }
+
+  // Make sure that there is a plugin
+  return objlc->EnsureInstantiation(_result);
 }
 
 // Check if proto is already in obj's prototype chain.
 
 static PRBool
 IsObjInProtoChain(JSContext *cx, JSObject *obj, JSObject *proto)
 {
   JSObject *o = obj;
@@ -9329,19 +9336,30 @@ nsHTMLPluginObjElementSH::SetupProtoChai
   JSObject *pi_obj = nsnull; // XPConnect-wrapped peer object, when we get it.
   JSObject *pi_proto = nsnull; // 'pi.__proto__'
 
   rv = GetPluginJSObject(cx, obj, pi, &pi_obj, &pi_proto);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!pi_obj) {
     // Didn't get a plugin instance JSObject, nothing we can do then.
+
     return NS_OK;
   }
 
+  if (IsObjInProtoChain(cx, obj, pi_obj)) {
+    // We must have re-entered ::PostCreate() from nsObjectFrame()
+    // (through the EnsureInstantiation() call in
+    // GetPluginInstanceIfSafe()), this means that we've already done what
+    // we're about to do in this function so we can just return here.
+
+    return NS_OK;
+  }
+
+
   // If we got an xpconnect-wrapped plugin object, set obj's
   // prototype's prototype to the scriptable plugin.
 
   JSObject *my_proto = nsnull;
 
   // Get 'this.__proto__'
   rv = wrapper->GetJSObjectPrototype(&my_proto);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -75,16 +75,17 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
 #ifdef NP_NO_QUICKDRAW
     mDrawingModel(NPDrawingModelCoreGraphics),
 #else
     mDrawingModel(NPDrawingModelQuickDraw),
 #endif
 #endif
     mRunning(NOT_STARTED),
     mWindowless(PR_FALSE),
+    mWindowlessLocal(PR_FALSE),
     mTransparent(PR_FALSE),
     mUsesDOMForCursor(PR_FALSE),
     mInPluginInitCall(PR_FALSE),
     mPlugin(plugin),
     mMIMEType(nsnull),
     mOwner(nsnull),
     mCurrentPluginEvent(nsnull),
 #if defined(MOZ_X11) || defined(XP_WIN) || defined(XP_MACOSX)
@@ -654,16 +655,22 @@ NPError nsNPAPIPluginInstance::SetWindow
     if (!PL_strncasecmp(mMIMEType, silverlight.get(), silverlight.Length())) {
       mTransparent = PR_TRUE;
     }
   }
 
   return NPERR_NO_ERROR;
 }
 
+NPError nsNPAPIPluginInstance::SetWindowlessLocal(PRBool aWindowlessLocal)
+{
+  mWindowlessLocal = aWindowlessLocal;
+  return NPERR_NO_ERROR;
+}
+
 NPError nsNPAPIPluginInstance::SetTransparent(PRBool aTransparent)
 {
   mTransparent = aTransparent;
   return NPERR_NO_ERROR;
 }
 
 NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(PRBool aUsesDOMForCursor)
 {
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -119,16 +119,18 @@ public:
 
   nsresult GetNPP(NPP * aNPP);
 
   void SetURI(nsIURI* uri);
   nsIURI* GetURI();
 
   NPError SetWindowless(PRBool aWindowless);
 
+  NPError SetWindowlessLocal(PRBool aWindowlessLocal);
+
   NPError SetTransparent(PRBool aTransparent);
 
   NPError SetWantsAllNetworkStreams(PRBool aWantsAllNetworkStreams);
 
   NPError SetUsesDOMForCursor(PRBool aUsesDOMForCursor);
   PRBool UsesDOMForCursor();
 
 #ifdef XP_MACOSX
@@ -207,16 +209,17 @@ protected:
     RUNNING,
     DESTROYING,
     DESTROYED
   } mRunning;
 
   // these are used to store the windowless properties
   // which the browser will later query
   PRPackedBool mWindowless;
+  PRPackedBool mWindowlessLocal;
   PRPackedBool mTransparent;
   PRPackedBool mUsesDOMForCursor;
 
 public:
   // True while creating the plugin, or calling NPP_SetWindow() on it.
   PRPackedBool mInPluginInitCall;
 
   nsXPIDLCString mFakeURL;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -3652,16 +3652,22 @@ nsPluginHost::CreateTempFileToPost(const
 
 nsresult
 nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
 {
   return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
 }
 
 nsresult
+nsPluginHost::DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
+{
+  return PLUG_DeletePluginNativeWindow(aPluginNativeWindow);
+}
+
+nsresult
 nsPluginHost::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner)
 {
   // Pass PR_FALSE as the second arg, we want the answer to be the
   // same here whether the Java plugin is enabled or not.
   nsPluginTag *plugin = FindPluginForType("application/x-java-vm", PR_FALSE);
 
   if (!plugin || !plugin->mIsNPRuntimeEnabledJavaPlugin) {
     // No NPRuntime enabled Java plugin found, no point in
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -143,16 +143,17 @@ public:
                    const char* postHeaders);
 
   nsresult FindProxyForURL(const char* url, char* *result);
   nsresult UserAgent(const char **retstring);
   nsresult ParsePostBufferToFixHeaders(const char *inPostData, PRUint32 inPostDataLen,
                                        char **outPostData, PRUint32 *outPostDataLen);
   nsresult CreateTempFileToPost(const char *aPostDataURL, nsIFile **aTmpFile);
   nsresult NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow);
+  nsresult DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow);
   nsresult InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner);
 
   void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible);
   void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);
 
   nsresult GetPluginName(nsNPAPIPluginInstance *aPluginInstance, const char** aPluginName);
   nsresult StopPluginInstance(nsNPAPIPluginInstance* aInstance);
   nsresult HandleBadPlugin(PRLibrary* aLibrary, nsNPAPIPluginInstance *aInstance);
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -94,17 +94,16 @@ using mozilla::DefaultXDisplay;
 #include "nsFocusManager.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIScrollableFrame.h"
 
 #include "nsContentCID.h"
 static NS_DEFINE_CID(kRangeCID, NS_RANGE_CID);
 
 #include "nsWidgetsCID.h"
-static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #ifdef XP_WIN
 #include <wtypes.h>
 #include <winuser.h>
 #endif
 
 #ifdef XP_MACOSX
@@ -173,17 +172,17 @@ nsPluginInstanceOwner::NotifyPaintWaiter
     // receive it immediately
     mWaitingForPaint = nsContentUtils::AddScriptRunner(event);
   }
 }
 
 #ifdef XP_MACOSX
 static void DrawPlugin(ImageContainer* aContainer, void* aPluginInstanceOwner)
 {
-  nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetFrame();
+  nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetOwner();
   if (frame) {
     frame->UpdateImageLayer(aContainer, gfxRect(0,0,0,0));
   }
 }
 
 static void OnDestroyImage(void* aPluginInstanceOwner)
 {
   nsPluginInstanceOwner* owner = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner);
@@ -280,26 +279,24 @@ nsPluginInstanceOwner::GetCurrentImageSi
   return size;
 }
 
 nsPluginInstanceOwner::nsPluginInstanceOwner()
 {
   // create nsPluginNativeWindow object, it is derived from NPWindow
   // struct and allows to manipulate native window procedure
   nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
-  mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());  
-  if (mPluginHost)
-    mPluginHost->NewPluginNativeWindow(&mPluginWindow);
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());  
+  if (pluginHost)
+    pluginHost->NewPluginNativeWindow(&mPluginWindow);
   else
     mPluginWindow = nsnull;
 
   mObjectFrame = nsnull;
-  mContent = nsnull;
   mTagText = nsnull;
-  mWidgetCreationComplete = PR_FALSE;
 #ifdef XP_MACOSX
   memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
 #ifndef NP_NO_QUICKDRAW
   memset(&mQDPluginPortCopy, 0, sizeof(NP_Port));
 #endif
   mInCGPaintLevel = 0;
   mSentInitialTopLevelWindowEvent = PR_FALSE;
   mColorProfile = nsnull;
@@ -308,16 +305,17 @@ nsPluginInstanceOwner::nsPluginInstanceO
   mContentFocused = PR_FALSE;
   mWidgetVisible = PR_TRUE;
   mPluginWindowVisible = PR_FALSE;
   mPluginDocumentActiveState = PR_TRUE;
   mNumCachedAttrs = 0;
   mNumCachedParams = 0;
   mCachedAttrParamNames = nsnull;
   mCachedAttrParamValues = nsnull;
+  mDestroyWidget = PR_FALSE;
 
 #ifdef XP_MACOSX
 #ifndef NP_NO_QUICKDRAW
   mEventModel = NPEventModelCarbon;
 #else
   mEventModel = NPEventModelCocoa;
 #endif
 #endif
@@ -364,18 +362,23 @@ nsPluginInstanceOwner::~nsPluginInstance
     mCachedAttrParamValues = nsnull;
   }
 
   if (mTagText) {
     NS_Free(mTagText);
     mTagText = nsnull;
   }
 
-  PLUG_DeletePluginNativeWindow(mPluginWindow);
-  mPluginWindow = nsnull;
+  // clean up plugin native window object
+  nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+  if (pluginHost) {
+    pluginHost->DeletePluginNativeWindow(mPluginWindow);
+    mPluginWindow = nsnull;
+  }
 
   if (mInstance) {
     mInstance->InvalidateOwner();
   }
 }
 
 NS_IMPL_ISUPPORTS3(nsPluginInstanceOwner,
                    nsIPluginInstanceOwner,
@@ -1100,16 +1103,17 @@ nsresult nsPluginInstanceOwner::EnsureCa
 {
   if (mCachedAttrParamValues)
     return NS_OK;
 
   NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
                     !mCachedAttrParamNames,
                   "re-cache of attrs/params not implemented! use the DOM "
                     "node directy instead");
+  NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
 
   // Convert to a 16-bit count. Subtract 2 in case we add an extra
   // "src" or "wmode" entry below.
   PRUint32 cattrs = mContent->GetAttrCount();
   if (cattrs < 0x0000FFFD) {
     mNumCachedAttrs = static_cast<PRUint16>(cattrs);
   } else {
     mNumCachedAttrs = 0xFFFD;
@@ -1172,16 +1176,19 @@ nsresult nsPluginInstanceOwner::EnsureCa
               ourParams.AppendObject(domelement);
             }
           }
         }
       }
     }
   }
 
+  // We're done with DOM method calls now. Make sure we still have a frame.
+  NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_OUT_OF_MEMORY);
+
   // Convert to a 16-bit count.
   PRUint32 cparams = ourParams.Count();
   if (cparams < 0x0000FFFF) {
     mNumCachedParams = static_cast<PRUint16>(cparams);
   } else {
     mNumCachedParams = 0xFFFF;
   }
 
@@ -2443,25 +2450,80 @@ nsPluginInstanceOwner::Destroy()
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragleave"), this, PR_TRUE);
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragexit"), this, PR_TRUE);
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, PR_TRUE);
   mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, PR_TRUE);
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, PR_TRUE);
 
   if (mWidget) {
     nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
-    if (pluginWidget) {
+    if (pluginWidget)
       pluginWidget->SetPluginInstanceOwner(nsnull);
-    }
-    mWidget->Destroy();
+
+    if (mDestroyWidget)
+      mWidget->Destroy();
   }
 
   return NS_OK;
 }
 
+/*
+ * Prepare to stop 
+ */
+void
+nsPluginInstanceOwner::PrepareToStop(PRBool aDelayedStop)
+{
+  // Drop image reference because the child may destroy the surface after we return.
+  nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
+  if (container) {
+#ifdef XP_MACOSX
+    nsRefPtr<Image> image = container->GetCurrentImage();
+    if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
+      // Undo what we did to the current image in SetCurrentImage().
+      MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
+      oglImage->SetUpdateCallback(nsnull, nsnull);
+      oglImage->SetDestroyCallback(nsnull);
+      // If we have a current image here, its destructor hasn't yet been
+      // called, so OnDestroyImage() can't yet have been called.  So we need
+      // to do ourselves what OnDestroyImage() would have done.
+      NS_RELEASE_THIS();
+    }
+#endif
+    container->SetCurrentImage(nsnull);
+  }
+
+#if defined(XP_WIN) || defined(MOZ_X11)
+  if (aDelayedStop && mWidget) {
+    // To delay stopping a plugin we need to reparent the plugin
+    // so that we can safely tear down the
+    // plugin after its frame (and view) is gone.
+
+    // Also hide and disable the widget to avoid it from appearing in
+    // odd places after reparenting it, but before it gets destroyed.
+    mWidget->Show(PR_FALSE);
+    mWidget->Enable(PR_FALSE);
+
+    // Reparent the plugins native window. This relies on the widget
+    // and plugin et al not holding any other references to its
+    // parent.
+    mWidget->SetParent(nsnull);
+
+    mDestroyWidget = PR_TRUE;
+  }
+#endif
+
+  // Unregister scroll position listeners
+  for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
+    nsIScrollableFrame* sf = do_QueryFrame(f);
+    if (sf) {
+      sf->RemoveScrollPositionListener(this);
+    }
+  }
+}
+
 // Paints are handled differently, so we just simulate an update event.
 
 #ifdef XP_MACOSX
 void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
 {
   if (!mInstance || !mObjectFrame)
     return;
  
@@ -2787,29 +2849,35 @@ void nsPluginInstanceOwner::StartTimer(P
 }
 
 void nsPluginInstanceOwner::CancelTimer()
 {
   mPluginHost->RemoveIdleTimeTarget(this);
 }
 #endif
 
-nsresult nsPluginInstanceOwner::Init(nsObjectFrame* aFrame, nsIContent* aContent)
+nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
+                                     nsObjectFrame* aFrame,
+                                     nsIContent*    aContent)
 {
   mLastEventloopNestingLevel = GetEventloopNestingLevel();
 
+  mObjectFrame = aFrame;
   mContent = aContent;
 
-  if (aFrame) {
-    SetFrame(aFrame);
-    // Some plugins require a specific sequence of shutdown and startup when
-    // a page is reloaded. Shutdown happens usually when the last instance
-    // is destroyed. Here we make sure the plugin instance in the old
-    // document is destroyed before we try to create the new one.
-    aFrame->PresContext()->EnsureVisible();
+  nsWeakFrame weakFrame(aFrame);
+
+  // Some plugins require a specific sequence of shutdown and startup when
+  // a page is reloaded. Shutdown happens usually when the last instance
+  // is destroyed. Here we make sure the plugin instance in the old
+  // document is destroyed before we try to create the new one.
+  aPresContext->EnsureVisible();
+
+  if (!weakFrame.IsAlive()) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
   // register context menu listener
   mCXMenuListener = new nsPluginDOMContextMenuListener();
   if (mCXMenuListener) {    
     mCXMenuListener->Init(aContent);
   }
 
@@ -2839,16 +2907,26 @@ nsresult nsPluginInstanceOwner::Init(nsO
   mContent->AddEventListener(NS_LITERAL_STRING("drag"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("dragenter"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("dragover"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, PR_TRUE);
   mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, PR_TRUE);
+  
+  // Register scroll position listeners
+  // We need to register a scroll position listener on every scrollable
+  // frame up to the top
+  for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
+    nsIScrollableFrame* sf = do_QueryFrame(f);
+    if (sf) {
+      sf->AddScrollPositionListener(this);
+    }
+  }
 
   return NS_OK; 
 }
 
 void* nsPluginInstanceOwner::GetPluginPortFromWidget()
 {
 //!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
 
@@ -2880,109 +2958,98 @@ void nsPluginInstanceOwner::ReleasePlugi
   }
 #endif
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
 {
   NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
 
-  nsresult rv = NS_ERROR_FAILURE;
-
-  // Can't call this twice!
-  if (mWidget) {
-    NS_WARNING("Trying to create a plugin widget twice!");
-    return NS_ERROR_FAILURE;
-  }
-
-  PRBool windowless = PR_FALSE;
-  mInstance->IsWindowless(&windowless);
-  if (!windowless && !nsIWidget::UsePuppetWidgets()) {
-    // Try to get a parent widget, on some platforms widget creation will fail without
-    // a parent.
-    nsCOMPtr<nsIWidget> parentWidget;
-    if (mContent) {
-      nsIDocument *doc = mContent->GetOwnerDoc();
-      if (doc) {
-        parentWidget = nsContentUtils::WidgetForDocument(doc);        
-      }
-    }
-
-    mWidget = do_CreateInstance(kWidgetCID, &rv);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    nsWidgetInitData initData;
-    initData.mWindowType = eWindowType_plugin;
-    initData.mUnicode = PR_FALSE;
-    initData.clipChildren = PR_TRUE;
-    initData.clipSiblings = PR_TRUE;
-    rv = mWidget->Create(parentWidget.get(), nsnull, nsIntRect(0,0,0,0),
-                         nsnull, nsnull, nsnull, nsnull, &initData);
-    if (NS_FAILED(rv)) {
-      mWidget->Destroy();
-      mWidget = nsnull;
-      return rv;
-    }
-
-    mWidget->EnableDragDrop(PR_TRUE);
-    mWidget->Show(PR_FALSE);
-    mWidget->Enable(PR_FALSE);
-  }
+  nsresult  rv = NS_ERROR_FAILURE;
 
   if (mObjectFrame) {
-    // This has to be called even if we don't have a widget! The object
-    // frame will do windowless setup.
-    mObjectFrame->SetWidget(mWidget);
-  }
-
-  if (windowless) {
-    mPluginWindow->type = NPWindowTypeDrawable;
-    
-    // this needs to be a HDC according to the spec, but I do
-    // not see the right way to release it so let's postpone
-    // passing HDC till paint event when it is really
-    // needed. Change spec?
-    mPluginWindow->window = nsnull;
+    if (!mWidget) {
+      PRBool windowless = PR_FALSE;
+      mInstance->IsWindowless(&windowless);
+
+      // always create widgets in Twips, not pixels
+      nsPresContext* context = mObjectFrame->PresContext();
+      rv = mObjectFrame->CreateWidget(context->DevPixelsToAppUnits(mPluginWindow->width),
+                                      context->DevPixelsToAppUnits(mPluginWindow->height),
+                                      windowless);
+      if (NS_OK == rv) {
+        mWidget = mObjectFrame->GetWidget();
+
+        if (PR_TRUE == windowless) {
+          mPluginWindow->type = NPWindowTypeDrawable;
+
+          // this needs to be a HDC according to the spec, but I do
+          // not see the right way to release it so let's postpone
+          // passing HDC till paint event when it is really
+          // needed. Change spec?
+          mPluginWindow->window = nsnull;
 #ifdef MOZ_X11
-    // Fill in the display field.
-    NPSetWindowCallbackStruct* ws_info = 
-    static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
-    ws_info->display = DefaultXDisplay();
-    
-    nsCAutoString description;
-    GetPluginDescription(description);
-    NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
-    mFlash10Quirks = StringBeginsWith(description, flash10Head);
+          // Fill in the display field.
+          NPSetWindowCallbackStruct* ws_info = 
+            static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
+          ws_info->display = DefaultXDisplay();
+
+          nsCAutoString description;
+          GetPluginDescription(description);
+          NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
+          mFlash10Quirks = StringBeginsWith(description, flash10Head);
 #endif
-  } else if (mWidget) {    
-    // mPluginWindow->type is used in |GetPluginPort| so it must
-    // be initialized first
-    mPluginWindow->type = NPWindowTypeWindow;
-    mPluginWindow->window = GetPluginPortFromWidget();
-    
+
+          // Changing to windowless mode changes the NPWindow geometry.
+          mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
+        } else if (mWidget) {
+          nsIWidget* parent = mWidget->GetParent();
+          NS_ASSERTION(parent, "Plugin windows must not be toplevel");
+          // Set the plugin window to have an empty cliprect. The cliprect
+          // will be reset when nsRootPresContext::UpdatePluginGeometry
+          // runs later. The plugin window does need to have the correct
+          // size here. GetEmptyClipConfiguration will probably give it the
+          // size, but just in case we haven't been reflowed or something, set
+          // the size explicitly.
+          nsAutoTArray<nsIWidget::Configuration,1> configuration;
+          mObjectFrame->GetEmptyClipConfiguration(&configuration);
+          if (configuration.Length() > 0) {
+            configuration[0].mBounds.width = mPluginWindow->width;
+            configuration[0].mBounds.height = mPluginWindow->height;
+          }
+          parent->ConfigureChildren(configuration);
+
+          // mPluginWindow->type is used in |GetPluginPort| so it must
+          // be initialized first
+          mPluginWindow->type = NPWindowTypeWindow;
+          mPluginWindow->window = GetPluginPortFromWidget();
+
 #ifdef MAC_CARBON_PLUGINS
-    // start the idle timer.
-    StartTimer(PR_TRUE);
+          // start the idle timer.
+          StartTimer(PR_TRUE);
 #endif
-    
-    // tell the plugin window about the widget
-    mPluginWindow->SetPluginWidget(mWidget);
-    
-    // tell the widget about the current plugin instance owner.
-    nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
-    if (pluginWidget) {
-      pluginWidget->SetPluginInstanceOwner(this);
+
+          // tell the plugin window about the widget
+          mPluginWindow->SetPluginWidget(mWidget);
+
+          // tell the widget about the current plugin instance owner.
+          nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
+          if (pluginWidget)
+            pluginWidget->SetPluginInstanceOwner(this);
+        }
+      }
     }
   }
 
-  mWidgetCreationComplete = PR_TRUE;
-
-  return NS_OK;
+  return rv;
+}
+
+void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
+{
+  mPluginHost = static_cast<nsPluginHost*>(aHost);
 }
 
 // Mac specific code to fix up the port location and clipping region
 #ifdef XP_MACOSX
 
 void* nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
 {
   if (!mWidget || !mPluginWindow || !mInstance || !mObjectFrame)
@@ -3216,95 +3283,16 @@ nsPluginInstanceOwner::CallSetWindow()
     mAsyncHidePluginWindow = true;
     mInstance->AsyncSetWindow(mPluginWindow);
   } else {
     mAsyncHidePluginWindow = false;
     mInstance->SetWindow(mPluginWindow);
   }
 }
 
-void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
-{
-  // Don't do anything if the frame situation hasn't changed.
-  if (mObjectFrame == aFrame) {
-    return;
-  }
-
-  // Deal with things that depend on whether or not we used to have a frame.
-  if (mObjectFrame) {
-    // We have an old frame.
-    // Drop image reference because the child may destroy the surface after we return.
-    nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
-    if (container) {
-#ifdef XP_MACOSX
-      nsRefPtr<Image> image = container->GetCurrentImage();
-      if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
-        // Undo what we did to the current image in SetCurrentImage().
-        MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
-        oglImage->SetUpdateCallback(nsnull, nsnull);
-        oglImage->SetDestroyCallback(nsnull);
-        // If we have a current image here, its destructor hasn't yet been
-        // called, so OnDestroyImage() can't yet have been called.  So we need
-        // to do ourselves what OnDestroyImage() would have done.
-        NS_RELEASE_THIS();
-      }
-#endif
-      container->SetCurrentImage(nsnull);
-    }
-
-    // If we had an old frame and we're not going to have a new one then
-    // we should unregister for some things.
-    if (!aFrame) {
-      // Unregister scroll position listeners
-      for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
-        nsIScrollableFrame* sf = do_QueryFrame(f);
-        if (sf) {
-          sf->RemoveScrollPositionListener(this);
-        }
-      }
-    }
-
-    // Make sure the old frame isn't holding a reference to us.
-    mObjectFrame->SetInstanceOwner(nsnull);
-  } else {
-    if (aFrame) {
-      // We didn't have an object frame before but we do now!
-      // We need to register a scroll position listener on every scrollable
-      // frame up to the top
-      for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
-        nsIScrollableFrame* sf = do_QueryFrame(f);
-        if (sf) {
-          sf->AddScrollPositionListener(this);
-        }
-      }
-    }
-  }
-
-  // Swap in the new frame (or no frame)
-  mObjectFrame = aFrame;
-
-  // Set up a new frame
-  if (mObjectFrame) {    
-    mObjectFrame->SetInstanceOwner(this);
-    // Can only call SetWidget on an object frame once. Don't do it here unless
-    // widget creation is complete. Whether or not one was actually created and
-    // mWidget is NULL is irrelevant.
-    if (mWidgetCreationComplete) {
-      mObjectFrame->SetWidget(mWidget);
-    }
-    mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
-    mObjectFrame->Invalidate(mObjectFrame->GetContentRectRelativeToSelf());
-  }
-}
-
-nsObjectFrame* nsPluginInstanceOwner::GetFrame()
-{
-  return mObjectFrame;
-}
-
 // Little helper function to resolve relative URL in
 // |value| for certain inputs of |name|
 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
 {
   if (name.LowerCaseEqualsLiteral("pluginurl") ||
       name.LowerCaseEqualsLiteral("pluginspage")) {        
     nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
     nsAutoString newURL;
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -127,17 +127,19 @@ public:
   
   // nsIDOMEventListener interfaces 
   NS_DECL_NSIDOMEVENTLISTENER
   
   nsresult MouseDown(nsIDOMEvent* aKeyEvent);
   nsresult KeyPress(nsIDOMEvent* aKeyEvent);
 
   nsresult Destroy();  
-
+  
+  void PrepareToStop(PRBool aDelayedStop);
+  
 #ifdef XP_WIN
   void Paint(const RECT& aDirty, HDC aDC);
 #elif defined(XP_MACOSX)
   void Paint(const gfxRect& aDirtyRect, CGContextRef cgContext);  
   void RenderCoreAnimation(CGContextRef aCGContext, int aWidth, int aHeight);
   void DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext);
 #elif defined(MOZ_X11)
   void Paint(gfxContext* aContext,
@@ -154,21 +156,24 @@ public:
   void SendIdleEvent();
   
   // nsIScrollPositionListener interface
   virtual void ScrollPositionWillChange(nscoord aX, nscoord aY);
   virtual void ScrollPositionDidChange(nscoord aX, nscoord aY);
   
   //locals
   
-  nsresult Init(nsObjectFrame* aFrame, nsIContent* aContent);
+  nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
+                nsIContent* aContent);
   
   void* GetPluginPortFromWidget();
   void ReleasePluginPort(void* pluginPort);
-
+  
+  void SetPluginHost(nsIPluginHost* aHost);
+  
   nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
   
 #ifdef XP_MACOSX
   enum { ePluginPaintEnable, ePluginPaintDisable };
   
   NPDrawingModel GetDrawingModel();
   PRBool IsRemoteDrawingCoreAnimation();
   NPEventModel GetEventModel();
@@ -197,20 +202,25 @@ public:
   void BeginCGPaint();
   void EndCGPaint();
 #else // XP_MACOSX
   void UpdateWindowPositionAndClipRect(PRBool aSetWindow);
   void UpdateWindowVisibility(PRBool aVisible);
   void UpdateDocumentActiveState(PRBool aIsActive);
 #endif // XP_MACOSX
   void CallSetWindow();
-
-  void SetFrame(nsObjectFrame *aFrame);
-  nsObjectFrame* GetFrame();
-
+  
+  void SetOwner(nsObjectFrame *aOwner)
+  {
+    mObjectFrame = aOwner;
+  }
+  nsObjectFrame* GetOwner() {
+    return mObjectFrame;
+  }
+  
   PRUint32 GetLastEventloopNestingLevel() const {
     return mLastEventloopNestingLevel; 
   }
   
   static PRUint32 GetEventloopNestingLevel();
   
   void ConsiderNewEventloopNestingLevel() {
     PRUint32 currentLevel = GetEventloopNestingLevel();
@@ -293,21 +303,20 @@ private:
     return NS_SUCCEEDED(mInstance->GetImageSize(&size)) &&
     size == nsIntSize(mPluginWindow->width, mPluginWindow->height);
   }
   
   void FixUpURLS(const nsString &name, nsAString &value);
   
   nsPluginNativeWindow       *mPluginWindow;
   nsRefPtr<nsNPAPIPluginInstance> mInstance;
-  nsObjectFrame              *mObjectFrame;
-  nsIContent                 *mContent; // WEAK, content owns us
+  nsObjectFrame              *mObjectFrame; // owns nsPluginInstanceOwner
+  nsCOMPtr<nsIContent>        mContent;
   nsCString                   mDocumentBase;
   char                       *mTagText;
-  PRBool                      mWidgetCreationComplete;
   nsCOMPtr<nsIWidget>         mWidget;
   nsRefPtr<nsPluginHost>      mPluginHost;
   
 #ifdef XP_MACOSX
   NP_CGContext                              mCGPluginPortCopy;
 #ifndef NP_NO_QUICKDRAW
   NP_Port                                   mQDPluginPortCopy;
 #endif
@@ -333,17 +342,20 @@ private:
   PRPackedBool                mPluginPortChanged;
 #endif
 #ifdef MOZ_X11
   // Used with windowless plugins only, initialized in CreateWidget().
   PRPackedBool                mFlash10Quirks;
 #endif
   PRPackedBool                mPluginWindowVisible;
   PRPackedBool                mPluginDocumentActiveState;
-
+  
+  // If true, destroy the widget on destruction. Used when plugin stop
+  // is being delayed to a safer point in time.
+  PRPackedBool                mDestroyWidget;
   PRUint16          mNumCachedAttrs;
   PRUint16          mNumCachedParams;
   char              **mCachedAttrParamNames;
   char              **mCachedAttrParamValues;
   
 #ifdef XP_MACOSX
   NPEventModel mEventModel;
 #endif
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -97,21 +97,16 @@ include $(topsrcdir)/config/rules.mk
   test_bug539565-2.html \
   test_enumerate.html \
   test_npruntime_construct.html \
   307-xo-redirect.sjs \
   test_redirect_handling.html \
   test_zero_opacity.html \
   test_NPPVpluginWantsAllNetworkStreams.html \
   test_npruntime_npnsetexception.html \
-  test_display_none.html \
-  test_instance_re-parent.html \
-  test_instance_unparent1.html \
-  test_instance_unparent2.html \
-  test_instance_unparent3.html \
   $(NULL)
 
 #  test_plugin_scroll_painting.html \ bug 596491
 
 ifeq ($(OS_ARCH),WINNT)
 _MOCHITEST_FILES += \
   test_windowed_invalidate.html \
   $(NULL)
@@ -126,17 +121,16 @@ endif
   test_npruntime.xul   \
   test_privatemode.xul \
   test_wmode.xul \
   test_bug479979.xul \
   $(NULL)
 
 ifneq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 _MOCHITEST_FILES += \
-  test_instance_re-parent-windowed.html \
   test_visibility.html \
   $(NULL)
 
 ifneq ($(OS_ARCH),WINNT)
 _MOCHICHROME_FILES += \
   test_xulbrowser_plugin_visibility.xul \
   xulbrowser_plugin_visibility.xul \
   plugin_visibility_loader.html \
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_display_none.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Test npruntime and paint count for instance in a display:none div</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="startTest()">
-  <p id="display"></p>
-
-  <div style="display: none;">
-    <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
-  </div>
-
-  <script type="application/javascript;version=1.8">
-  SimpleTest.waitForExplicitFinish();
-
-  function startTest() {
-    var paintCount = -1;
-    var exceptionThrown = false;
-
-    var p = document.getElementById('plugin1');
-    try {
-      paintCount = p.getPaintCount();
-    } catch (e) {
-      exceptionThrown = true;
-    }
-
-    is(paintCount, 0, "Paint count test.");
-    is(exceptionThrown, false, "Exception test.");
-
-    SimpleTest.finish();
-  }
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_instance_re-parent-windowed.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Test re-parentinging an instance's DOM node</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="startTest()">
-  <p id="display"></p>
-
-  <div id="div1">
-    <embed id="plugin1" type="application/x-test" width="200" height="200" wmode="window"></embed>
-  </div>
-  <div id="div2">
-  </div>
-
-  <script type="application/javascript;version=1.8">
-  SimpleTest.waitForExplicitFinish();
-
-  var destroyed = false;
-  function onDestroy() {
-    destroyed = true;
-  }
-
-  function startTest() {
-    var exceptionThrown = false;
-
-    var p = document.getElementById('plugin1');
-    var d1 = document.getElementById('div1');
-    var d2 = document.getElementById('div2');
-
-    p.startWatchingInstanceCount();
-    p.callOnDestroy(onDestroy);
-
-    try {
-      d1.removeChild(p);
-    } catch (e) {
-      exceptionThrown = true;
-    }
-    is(exceptionThrown, false, "Testing for exception after removeChild.");
-
-    try {
-      d2.appendChild(p);
-    } catch (e) {
-      exceptionThrown = true;
-    }
-    is(exceptionThrown, false, "Testing for exception after appendChild.");
-
-    is(destroyed, false, "No instances should have been destroyed at this point.");
-    is(p.getInstanceCount(), 0, "No new instances should have been created at this point.");
-
-    p.stopWatchingInstanceCount();
-
-    SimpleTest.finish();
-  }
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_instance_re-parent.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Test re-parentinging an instance's DOM node</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="startTest()">
-  <p id="display"></p>
-
-  <div id="div1">
-    <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
-  </div>
-  <div id="div2">
-  </div>
-
-  <script type="application/javascript;version=1.8">
-  SimpleTest.waitForExplicitFinish();
-
-  var destroyed = false;
-  function onDestroy() {
-    destroyed = true;
-  }
-
-  function startTest() {
-    var exceptionThrown = false;
-
-    var p = document.getElementById('plugin1');
-    var d1 = document.getElementById('div1');
-    var d2 = document.getElementById('div2');
-
-    p.startWatchingInstanceCount();
-    p.callOnDestroy(onDestroy);
-
-    try {
-      d1.removeChild(p);
-    } catch (e) {
-      exceptionThrown = true;
-    }
-    is(exceptionThrown, false, "Testing for exception after removeChild.");
-
-    try {
-      d2.appendChild(p);
-    } catch (e) {
-      exceptionThrown = true;
-    }
-    is(exceptionThrown, false, "Testing for exception after appendChild.");
-
-    is(destroyed, false, "No instances should have been destroyed at this point.");
-    is(p.getInstanceCount(), 0, "No new instances should have been created at this point.");
-
-    p.stopWatchingInstanceCount();
-
-    SimpleTest.finish();
-  }
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_instance_unparent1.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Test removing an instance's DOM node</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="startTest()">
-  <p id="display"></p>
-
-  <div id="div1">
-    <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
-  </div>
-
-  <script type="application/javascript;version=1.8">
-  SimpleTest.waitForExplicitFinish();
-
-  var destroyed = false;
-  function onDestroy() {
-    destroyed = true;
-  }
-
-  function checkPluginAlreadyDestroyed() {
-    is(destroyed, true, "Plugin instance should have been destroyed.");
-    SimpleTest.finish();
-  }
-
-  function startTest() {
-    var p1 = document.getElementById('plugin1');
-    var d1 = document.getElementById('div1');
-
-    p1.callOnDestroy(onDestroy);
-
-    setTimeout(checkPluginAlreadyDestroyed, 0);
-
-    d1.removeChild(p1);
-  }
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_instance_unparent2.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Test removing an instance's DOM node</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="startTest()">
-  <p id="display"></p>
-
-  <div id="div1">
-    <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
-  </div>
-
-  <div id="div2">
-    <div id="div3">
-        <embed id="plugin2" type="application/x-test" width="200" height="200"></embed>
-    </div>
-  </div>
-
-  <script type="application/javascript;version=1.8">
-  SimpleTest.waitForExplicitFinish();
-
-  var destroyed = false;
-  function onDestroy() {
-    destroyed = true;
-  }
-
-  function checkPluginAlreadyDestroyed() {
-    is(destroyed, true, "Plugin instance should have been destroyed.");
-    SimpleTest.finish();
-  }
-
-  function startTest() {
-    var p1 = document.getElementById('plugin1');
-    var d1 = document.getElementById('div1');
-
-    p1.callOnDestroy(onDestroy);
-
-    setTimeout(checkPluginAlreadyDestroyed, 0);
-
-    // Get two parent check events to run.
-    d1.removeChild(p1);
-    d1.appendChild(p1);
-    d1.removeChild(p1);
-  }
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/plugins/test/mochitest/test_instance_unparent3.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Test removing an instance's DOM node</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="startTest()">
-  <p id="display"></p>
-
-  <div id="div1">
-    <div id="div2">
-      <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
-    </div<
-  </div>
-
-  <script type="application/javascript;version=1.8">
-  SimpleTest.waitForExplicitFinish();
-
-  var destroyed = false;
-  function onDestroy() {
-    destroyed = true;
-  }
-
-  function checkPluginAlreadyDestroyed() {
-    is(destroyed, true, "Plugin instance should have been destroyed.");
-    SimpleTest.finish();
-  }
-
-  function startTest() {
-    var p1 = document.getElementById('plugin1');
-    var d1 = document.getElementById('div1');
-    var d2 = document.getElementById('div2');
-
-    p1.callOnDestroy(onDestroy);
-
-    setTimeout(checkPluginAlreadyDestroyed, 0);
-
-    d1.removeChild(d2);
-  }
-  </script>
-</body>
-</html>
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7576,19 +7576,20 @@ nsresult
 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
 {
   return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
 }
 
 static void
 FreezeElement(nsIContent *aContent, void * /* unused */)
 {
-  nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
-  if (olc) {
-    olc->StopPluginInstance();
+  nsIFrame *frame = aContent->GetPrimaryFrame();
+  nsIObjectFrame *objectFrame = do_QueryFrame(frame);
+  if (objectFrame) {
+    objectFrame->StopPlugin();
   }
 }
 
 static PRBool
 FreezeSubDocument(nsIDocument *aDocument, void *aData)
 {
   nsIPresShell *shell = aDocument->GetShell();
   if (shell)
@@ -7656,19 +7657,20 @@ PresShell::FireOrClearDelayedEvents(PRBo
       mDelayedEvents.Clear();
     }
   }
 }
 
 static void
 ThawElement(nsIContent *aContent, void *aShell)
 {
-  nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
-  if (olc) {
-    olc->StartPluginInstance();
+  nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(aContent));
+  if (objlc) {
+    nsRefPtr<nsNPAPIPluginInstance> inst;
+    objlc->EnsureInstantiation(getter_AddRefs(inst));
   }
 }
 
 static PRBool
 ThawSubDocument(nsIDocument *aDocument, void *aData)
 {
   nsIPresShell *shell = aDocument->GetShell();
   if (shell)
--- a/layout/generic/nsIObjectFrame.h
+++ b/layout/generic/nsIObjectFrame.h
@@ -50,16 +50,52 @@ class nsNPAPIPluginInstance;
 class nsIObjectFrame : public nsQueryFrame
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsIObjectFrame)
 
   NS_IMETHOD GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance) = 0;
 
   /**
+   * Instantiate a plugin for a channel, returning a stream listener for the
+   * data.
+   *
+   * @note Calling this method can delete the frame, so don't assume
+   *       the frame is alive after this call returns.
+   */
+  virtual nsresult Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener) = 0;
+
+  /**
+   * @note Calling this method can delete the frame, so don't assume
+   *       the frame is alive after this call returns.
+   */
+  virtual void TryNotifyContentObjectWrapper() = 0;
+
+  /**
+   * Instantiate a plugin that loads the data itself.
+   * @param aMimeType Type of the plugin to instantiate. May be null.
+   * @param aURI      URI of the plugin data. May be null.
+   * @note            Only one of aURI and aMimeType may be null.
+   *                  If aURI is null, aMimeType must not be the empty string.
+   * @note XXX this method is here only temporarily, until plugins are loaded
+   *       from content.
+   *
+   * @note Calling this method can delete the frame, so don't assume
+   *       the frame is alive after this call returns.
+   */
+  virtual nsresult Instantiate(const char* aMimeType, nsIURI* aURI) = 0;
+
+  /**
+   * Stops and unloads the plugin. Makes the frame ready to receive another
+   * Instantiate() call. It is safe to call this method even when no plugin
+   * is currently active in this frame.
+   */
+  virtual void StopPlugin() = 0;
+
+  /**
    * Get the native widget for the plugin, if any.
    */
   virtual nsIWidget* GetWidget() = 0;
 
   /**
    * Update plugin active state. Frame should update if it is on an active tab
    * or not and forward that information to the plugin to make it possible to
    * throttle down plugin instance in non active case.
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -317,43 +317,57 @@ nsObjectFrame::CreateAccessible()
 NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
 {
   *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget();
   return NS_OK;
 }
 #endif
 #endif
 
+static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
+
 NS_IMETHODIMP 
 nsObjectFrame::Init(nsIContent*      aContent,
                     nsIFrame*        aParent,
                     nsIFrame*        aPrevInFlow)
 {
+  NS_PRECONDITION(aContent, "How did that happen?");
+  mPreventInstantiation =
+    (aContent->GetCurrentDoc()->GetDisplayDocument() != nsnull);
+
   PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
          ("Initializing nsObjectFrame %p for content %p\n", this, aContent));
 
   nsresult rv = nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
 
   return rv;
 }
 
 void
 nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
-  // Tell content owner of the instance to disconnect its frame.
-  nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
-  NS_ASSERTION(objContent, "Why not an object loading content?");
-  objContent->DisconnectFrame();
+  NS_ASSERTION(!mPreventInstantiation ||
+               (mContent && mContent->GetCurrentDoc()->GetDisplayDocument()),
+               "about to crash due to bug 136927");
+
+  // we need to finish with the plugin before native window is destroyed
+  // doing this in the destructor is too late.
+  StopPluginInternal(PR_TRUE);
+
+  // StopPluginInternal might have disowned the widget; if it has,
+  // mWidget will be null.
+  if (mWidget) {
+    mInnerView->DetachWidgetEventHandler(mWidget);
+    mWidget->Destroy();
+  }
 
   if (mBackgroundSink) {
     mBackgroundSink->Destroy();
   }
 
-  SetInstanceOwner(nsnull);
-
   nsObjectFrameSuper::DestroyFrom(aDestructRoot);
 }
 
 /* virtual */ void
 nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   if (HasView()) {
     nsIView* view = GetView();
@@ -378,31 +392,40 @@ nsObjectFrame::GetType() const
 NS_IMETHODIMP
 nsObjectFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
 }
 #endif
 
 nsresult
-nsObjectFrame::SetWidget(nsIWidget *aWidget)
+nsObjectFrame::CreateWidget(nscoord aWidth,
+                            nscoord aHeight,
+                            PRBool  aViewOnly)
 {
-  mWidget = aWidget;
-
   nsIView* view = GetView();
   NS_ASSERTION(view, "Object frames must have views");  
   if (!view) {
-    return NS_ERROR_FAILURE;
+    return NS_OK;       //XXX why OK? MMP
+  }
+
+  PRBool needsWidget = !aViewOnly;
+  PRBool canCreateWidget = !nsIWidget::UsePuppetWidgets();
+  if (needsWidget && !canCreateWidget) {
+    NS_WARNING("Can't use native widgets, and can't hand a plugins a PuppetWidget");
   }
 
   nsIViewManager* viewMan = view->GetViewManager();
   // mark the view as hidden since we don't know the (x,y) until Paint
   // XXX is the above comment correct?
   viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
 
+  nsRefPtr<nsDeviceContext> dx;
+  viewMan->GetDeviceContext(*getter_AddRefs(dx));
+
   //this is ugly. it was ripped off from didreflow(). MMP
   // Position and size view relative to its parent, not relative to our
   // parent frame (our parent frame may not have a view).
   
   nsIView* parentWithView;
   nsPoint origin;
   nsRect r(0, 0, mRect.width, mRect.height);
 
@@ -410,119 +433,113 @@ nsObjectFrame::SetWidget(nsIWidget *aWid
   viewMan->ResizeView(view, r);
   viewMan->MoveViewTo(view, origin.x, origin.y);
 
   nsRootPresContext* rpc = PresContext()->GetRootPresContext();
   if (!rpc) {
     return NS_ERROR_FAILURE;
   }
 
-  if (mWidget) {
+  if (needsWidget && !mWidget && canCreateWidget) {
     // XXX this breaks plugins in popups ... do we care?
-    nsIWidget* parentWidget = rpc->PresShell()->FrameManager()->GetRootFrame()->GetNearestWidget();
-    if (!parentWidget) {
+    nsIWidget* parentWidget =
+      rpc->PresShell()->FrameManager()->GetRootFrame()->GetNearestWidget();
+    if (!parentWidget)
       return NS_ERROR_FAILURE;
-    }
 
     mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
     if (!mInnerView) {
       NS_ERROR("Could not create inner view");
       return NS_ERROR_OUT_OF_MEMORY;
     }
     viewMan->InsertChild(view, mInnerView, nsnull, PR_TRUE);
 
-    mWidget->SetParent(parentWidget);
-    mWidget->Show(PR_TRUE);
-    mWidget->Enable(PR_TRUE);
-
-    // Set the plugin window to have an empty cliprect. The cliprect
-    // will be reset when nsRootPresContext::UpdatePluginGeometry
-    // runs later. The plugin window does need to have the correct
-    // size here. GetEmptyClipConfiguration will probably give it the
-    // size, but just in case we haven't been reflowed or something, set
-    // the size explicitly.
-    nsAutoTArray<nsIWidget::Configuration,1> configuration;
-    GetEmptyClipConfiguration(&configuration);
-    NS_ASSERTION(configuration.Length() > 0, "Empty widget configuration array!");
-    configuration[0].mBounds.width = mRect.width;
-    configuration[0].mBounds.height = mRect.height;
-    parentWidget->ConfigureChildren(configuration);
-
-    nsRefPtr<nsDeviceContext> dx;
-    viewMan->GetDeviceContext(*getter_AddRefs(dx));
+    nsresult rv;
+    mWidget = do_CreateInstance(kWidgetCID, &rv);
+    if (NS_FAILED(rv))
+      return rv;
+
+    nsWidgetInitData initData;
+    initData.mWindowType = eWindowType_plugin;
+    initData.mUnicode = PR_FALSE;
+    initData.clipChildren = PR_TRUE;
+    initData.clipSiblings = PR_TRUE;
+    // We want mWidget to be able to deliver events to us, especially on
+    // Mac where events to the plugin are routed through Gecko. So we
+    // allow the view to attach its event handler to mWidget even though
+    // mWidget isn't the view's designated widget.
     EVENT_CALLBACK eventHandler = mInnerView->AttachWidgetEventHandler(mWidget);
-    mWidget->SetEventCallback(eventHandler, dx);
+    rv = mWidget->Create(parentWidget, nsnull, nsIntRect(0,0,0,0),
+                         eventHandler, dx, nsnull, nsnull, &initData);
+    if (NS_FAILED(rv)) {
+      mWidget->Destroy();
+      mWidget = nsnull;
+      return rv;
+    }
+
+    mWidget->EnableDragDrop(PR_TRUE);
 
     // If this frame has an ancestor with a widget which is not
     // the root prescontext's widget, then this plugin should not be
     // displayed, so don't show the widget. If we show the widget, the
     // plugin may appear in the main window. In Web content this would
     // only happen with a plugin in a XUL popup.
     if (parentWidget == GetNearestWidget()) {
       mWidget->Show(PR_TRUE);
 #ifdef XP_MACOSX
       // On Mac, we need to invalidate ourselves since even windowed
       // plugins are painted through Thebes and we need to ensure
       // the Thebes layer containing the plugin is updated.
       Invalidate(GetContentRectRelativeToSelf());
 #endif
     }
-    
+  }
+
+  if (mWidget) {
     rpc->RegisterPluginForGeometryUpdates(this);
     rpc->RequestUpdatePluginGeometry(this);
-    
+
     // Here we set the background color for this widget because some plugins will use 
     // the child window background color when painting. If it's not set, it may default to gray
     // Sometimes, a frame doesn't have a background color or is transparent. In this
     // case, walk up the frame tree until we do find a frame with a background color
     for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
       nscolor bgcolor =
-      frame->GetVisitedDependentColor(eCSSProperty_background_color);
+        frame->GetVisitedDependentColor(eCSSProperty_background_color);
       if (NS_GET_A(bgcolor) > 0) {  // make sure we got an actual color
         mWidget->SetBackgroundColor(bgcolor);
         break;
       }
     }
 
 #ifdef XP_MACOSX
     // Now that we have a widget we want to set the event model before
     // any events are processed.
     nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
-    if (!pluginWidget) {
+    if (!pluginWidget)
       return NS_ERROR_FAILURE;
-    }
     pluginWidget->SetPluginEventModel(mInstanceOwner->GetEventModel());
     pluginWidget->SetPluginDrawingModel(mInstanceOwner->GetDrawingModel());
 
     if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation) {
       mInstanceOwner->SetupCARefresh();
     }
 #endif
   } else {
-    // Changing to windowless mode changes the NPWindow geometry.
-    FixupWindow(GetContentRectRelativeToSelf().Size());
-
 #ifndef XP_MACOSX
     rpc->RegisterPluginForGeometryUpdates(this);
     rpc->RequestUpdatePluginGeometry(this);
 #endif
   }
 
   if (!IsHidden()) {
     viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
   }
 
-#ifdef ACCESSIBILITY
-  nsAccessibilityService* accService = nsIPresShell::AccService();
-  if (accService) {
-    accService->RecreateAccessible(PresContext()->PresShell(), mContent);
-  }
-#endif
-
-  return NS_OK;
+  return (needsWidget && !canCreateWidget) ? NS_ERROR_NOT_AVAILABLE : NS_OK;
 }
 
 #define EMBED_DEF_WIDTH 240
 #define EMBED_DEF_HEIGHT 200
 
 /* virtual */ nscoord
 nsObjectFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
 {
@@ -671,16 +688,60 @@ nsObjectFrame::ReflowFinished()
 }
 
 void
 nsObjectFrame::ReflowCallbackCanceled()
 {
   mReflowCallbackPosted = PR_FALSE;
 }
 
+nsresult
+nsObjectFrame::InstantiatePlugin(nsPluginHost* aPluginHost, 
+                                 const char* aMimeType,
+                                 nsIURI* aURI)
+{
+  NS_ASSERTION(mPreventInstantiation,
+               "Instantiation should be prevented here!");
+
+  // If you add early return(s), be sure to balance this call to
+  // appShell->SuspendNative() with additional call(s) to
+  // appShell->ReturnNative().
+  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
+  if (appShell) {
+    appShell->SuspendNative();
+  }
+
+  NS_ASSERTION(mContent, "We should have a content node.");
+
+  nsIDocument* doc = mContent->GetOwnerDoc();
+  nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
+  PRBool fullPageMode = PR_FALSE;
+  if (pDoc) {
+    pDoc->GetWillHandleInstantiation(&fullPageMode);
+  }
+
+  nsresult rv;
+  if (fullPageMode) {  /* full-page mode */
+    nsCOMPtr<nsIStreamListener> stream;
+    rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI, mInstanceOwner, getter_AddRefs(stream));
+    if (NS_SUCCEEDED(rv))
+      pDoc->SetStreamListener(stream);
+  } else {   /* embedded mode */
+    rv = aPluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI, mInstanceOwner);
+  }
+
+  // Note that |this| may very well be destroyed already!
+
+  if (appShell) {
+    appShell->ResumeNative();
+  }
+
+  return rv;
+}
+
 void
 nsObjectFrame::FixupWindow(const nsSize& aSize)
 {
   nsPresContext* presContext = PresContext();
 
   if (!mInstanceOwner)
     return;
 
@@ -766,48 +827,16 @@ nsObjectFrame::CallSetWindow(PRBool aChe
   else {
     rv = window->CallSetWindow(pi);
   }
 
   mInstanceOwner->ReleasePluginPort(window->window);
   return rv;
 }
 
-void
-nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
-{
-  mInstanceOwner = aOwner;
-  if (!mInstanceOwner) {
-    nsRootPresContext* rpc = PresContext()->GetRootPresContext();
-    if (rpc) {
-      if (mWidget) {
-        if (mInnerView) {
-          mInnerView->DetachWidgetEventHandler(mWidget);
-        }
-
-        rpc->UnregisterPluginForGeometryUpdates(this);
-        // Make sure the plugin is hidden in case an update of plugin geometry
-        // hasn't happened since this plugin became hidden.
-        nsIWidget* parent = mWidget->GetParent();
-        if (parent) {
-          nsTArray<nsIWidget::Configuration> configurations;
-          this->GetEmptyClipConfiguration(&configurations);
-          parent->ConfigureChildren(configurations);
-
-          mWidget->SetParent(nsnull);
-        }
-      } else {
-#ifndef XP_MACOSX
-        rpc->UnregisterPluginForGeometryUpdates(this);
-#endif
-      }
-    }
-  }
-}
-
 PRBool
 nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
 {
   if (aTabIndex)
     *aTabIndex = -1;
   return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
 }
 
@@ -2043,21 +2072,410 @@ nsObjectFrame::HandlePress(nsPresContext
 }
 #endif
 
 nsresult
 nsObjectFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
 {
   *aPluginInstance = nsnull;
 
-  if (!mInstanceOwner) {
+  if (!mInstanceOwner)
+    return NS_OK;
+  
+  return mInstanceOwner->GetInstance(aPluginInstance);
+}
+
+nsresult
+nsObjectFrame::PrepareInstanceOwner()
+{
+  nsWeakFrame weakFrame(this);
+
+  // First, have to stop any possibly running plugins.
+  StopPluginInternal(PR_FALSE);
+
+  if (!weakFrame.IsAlive()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here");
+
+  mInstanceOwner = new nsPluginInstanceOwner();
+
+  PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
+         ("Created new instance owner %p for frame %p\n", mInstanceOwner.get(),
+          this));
+
+  // Note, |this| may very well be gone after this call.
+  return mInstanceOwner->Init(PresContext(), this, GetContent());
+}
+
+nsresult
+nsObjectFrame::Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener)
+{
+  if (mPreventInstantiation) {
+    return NS_OK;
+  }
+  
+  // Note: If PrepareInstanceOwner() returns an error, |this| may very
+  // well be deleted already.
+  nsresult rv = PrepareInstanceOwner();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  mInstanceOwner->SetPluginHost(pluginHostCOM);
+
+  // This must be done before instantiating the plugin
+  FixupWindow(GetContentRectRelativeToSelf().Size());
+
+  // Ensure we redraw when a plugin is instantiated
+  Invalidate(GetContentRectRelativeToSelf());
+
+  nsWeakFrame weakFrame(this);
+
+  NS_ASSERTION(!mPreventInstantiation, "Say what?");
+  mPreventInstantiation = PR_TRUE;
+  rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
+
+  if (!weakFrame.IsAlive()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  NS_ASSERTION(mPreventInstantiation,
+               "Instantiation should still be prevented!");
+  mPreventInstantiation = PR_FALSE;
+
+#ifdef ACCESSIBILITY
+  nsAccessibilityService* accService = nsIPresShell::AccService();
+  if (accService) {
+    accService->RecreateAccessible(PresContext()->PresShell(), mContent);
+  }
+#endif
+
+  return rv;
+}
+
+nsresult
+nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
+{
+  PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
+         ("nsObjectFrame::Instantiate(%s) called on frame %p\n", aMimeType,
+          this));
+
+  if (mPreventInstantiation) {
     return NS_OK;
   }
 
-  return mInstanceOwner->GetInstance(aPluginInstance);
+  // XXXbz can aMimeType ever actually be null here?  If not, either
+  // the callers are wrong (and passing "" instead of null) or we can
+  // remove the codepaths dealing with null aMimeType in
+  // InstantiateEmbeddedPlugin.
+  NS_ASSERTION(aMimeType || aURI, "Need a type or a URI!");
+
+  // Note: If PrepareInstanceOwner() returns an error, |this| may very
+  // well be deleted already.
+  nsresult rv = PrepareInstanceOwner();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsWeakFrame weakFrame(this);
+
+  // This must be done before instantiating the plugin
+  FixupWindow(GetContentRectRelativeToSelf().Size());
+
+  // Ensure we redraw when a plugin is instantiated
+  Invalidate(GetContentRectRelativeToSelf());
+
+  // get the nsIPluginHost service
+  nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
+  if (NS_FAILED(rv))
+    return rv;
+  mInstanceOwner->SetPluginHost(pluginHost);
+
+  NS_ASSERTION(!mPreventInstantiation, "Say what?");
+  mPreventInstantiation = PR_TRUE;
+
+  rv = InstantiatePlugin(static_cast<nsPluginHost*>(pluginHost.get()), aMimeType, aURI);
+
+  if (!weakFrame.IsAlive()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  // finish up
+  if (NS_SUCCEEDED(rv)) {
+    TryNotifyContentObjectWrapper();
+
+    if (!weakFrame.IsAlive()) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    CallSetWindow();
+  }
+
+  NS_ASSERTION(mPreventInstantiation,
+               "Instantiation should still be prevented!");
+
+#ifdef ACCESSIBILITY
+  nsAccessibilityService* accService = nsIPresShell::AccService();
+  if (accService) {
+    accService->RecreateAccessible(PresContext()->PresShell(), mContent);
+  }
+#endif
+
+  mPreventInstantiation = PR_FALSE;
+
+  return rv;
+}
+
+void
+nsObjectFrame::TryNotifyContentObjectWrapper()
+{
+  nsRefPtr<nsNPAPIPluginInstance> inst;
+  mInstanceOwner->GetInstance(getter_AddRefs(inst));
+  if (inst) {
+    // The plugin may have set up new interfaces; we need to mess with our JS
+    // wrapper.  Note that we DO NOT want to call this if there is no plugin
+    // instance!  That would just reenter Instantiate(), trying to create
+    // said plugin instance.
+    NotifyContentObjectWrapper();
+  }
+}
+
+class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
+    : mInstanceOwner(aInstanceOwner)
+  {
+    NS_ASSERTION(aInstanceOwner, "need an owner");
+  }
+
+  // nsRunnable
+  NS_IMETHOD Run();
+
+  // nsITimerCallback
+  NS_IMETHOD Notify(nsITimer *timer);
+
+private:  
+  nsCOMPtr<nsITimer> mTimer;
+  nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
+};
+
+NS_IMPL_ISUPPORTS_INHERITED1(nsStopPluginRunnable, nsRunnable, nsITimerCallback)
+
+#if defined(XP_WIN)
+static const char*
+GetMIMEType(nsNPAPIPluginInstance *aPluginInstance)
+{
+  if (aPluginInstance) {
+    const char* mime = nsnull;
+    if (NS_SUCCEEDED(aPluginInstance->GetMIMEType(&mime)) && mime)
+      return mime;
+  }
+  return "";
+}
+#endif // XP_WIN
+
+static PRBool
+DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
+{
+#if (MOZ_PLATFORM_MAEMO==5)
+  // Don't delay stop on Maemo/Hildon (bug 530739).
+  if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
+    return PR_FALSE;
+#endif
+
+  // Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
+  // XStandard (bug 430219), CMISS Zinc (bug 429604).
+  if (aDelayedStop
+#if !(defined XP_WIN || defined MOZ_X11)
+      && !aInstanceOwner->MatchPluginName("QuickTime")
+      && !aInstanceOwner->MatchPluginName("Flip4Mac")
+      && !aInstanceOwner->MatchPluginName("XStandard plugin")
+      && !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
+#endif
+      ) {
+    nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(aInstanceOwner);
+    NS_DispatchToCurrentThread(evt);
+    return PR_TRUE;
+  }
+  return PR_FALSE;
+}
+
+static void
+DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
+{
+  nsRefPtr<nsNPAPIPluginInstance> inst;
+  aInstanceOwner->GetInstance(getter_AddRefs(inst));
+  if (inst) {
+    NPWindow *win;
+    aInstanceOwner->GetWindow(win);
+    nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
+    nsRefPtr<nsNPAPIPluginInstance> nullinst;
+
+    if (window) 
+      window->CallSetWindow(nullinst);
+    else 
+      inst->SetWindow(nsnull);
+    
+    if (DoDelayedStop(aInstanceOwner, aDelayedStop))
+      return;
+
+#if defined(XP_MACOSX)
+    aInstanceOwner->HidePluginWindow();
+#endif
+
+    nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
+    NS_ASSERTION(pluginHost, "Without a pluginHost, how can we have an instance to destroy?");
+    static_cast<nsPluginHost*>(pluginHost.get())->StopPluginInstance(inst);
+
+    // the frame is going away along with its widget so tell the
+    // window to forget its widget too
+    if (window)
+      window->SetPluginWidget(nsnull);
+  }
+
+  aInstanceOwner->Destroy();
+}
+
+NS_IMETHODIMP
+nsStopPluginRunnable::Notify(nsITimer *aTimer)
+{
+  return Run();
+}
+
+NS_IMETHODIMP
+nsStopPluginRunnable::Run()
+{
+  // InitWithCallback calls Release before AddRef so we need to hold a
+  // strong ref on 'this' since we fall through to this scope if it fails.
+  nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
+  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
+  if (appShell) {
+    PRUint32 currentLevel = 0;
+    appShell->GetEventloopNestingLevel(&currentLevel);
+    if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
+      if (!mTimer)
+        mTimer = do_CreateInstance("@mozilla.org/timer;1");
+      if (mTimer) {
+        // Fire 100ms timer to try to tear down this plugin as quickly as
+        // possible once the nesting level comes back down.
+        nsresult rv = mTimer->InitWithCallback(this, 100, nsITimer::TYPE_ONE_SHOT);
+        if (NS_SUCCEEDED(rv)) {
+          return rv;
+        }
+      }
+      NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
+               "time). Stopping the plugin now, this might crash.");
+    }
+  }
+
+  mTimer = nsnull;
+
+  DoStopPlugin(mInstanceOwner, PR_FALSE);
+
+  return NS_OK;
+}
+
+void
+nsObjectFrame::StopPlugin()
+{
+  PRBool delayedStop = PR_FALSE;
+#ifdef XP_WIN
+  nsRefPtr<nsNPAPIPluginInstance> inst;
+  if (mInstanceOwner)
+    mInstanceOwner->GetInstance(getter_AddRefs(inst));
+  if (inst) {
+    // Delayed stop for Real plugin only; see bug 420886, 426852.
+    const char* pluginType = ::GetMIMEType(inst);
+    delayedStop = strcmp(pluginType, "audio/x-pn-realaudio-plugin") == 0;
+  }
+#endif
+  StopPluginInternal(delayedStop);
+}
+
+void
+nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
+{
+  if (!mInstanceOwner) {
+    return;
+  }
+
+  nsRootPresContext* rpc = PresContext()->GetRootPresContext();
+  if (!rpc) {
+    NS_ASSERTION(PresContext()->PresShell()->IsFrozen(),
+                 "unable to unregister the plugin frame");
+  }
+  else if (mWidget) {
+    rpc->UnregisterPluginForGeometryUpdates(this);
+
+    // Make sure the plugin is hidden in case an update of plugin geometry
+    // hasn't happened since this plugin became hidden.
+    nsIWidget* parent = mWidget->GetParent();
+    if (parent) {
+      nsTArray<nsIWidget::Configuration> configurations;
+      GetEmptyClipConfiguration(&configurations);
+      parent->ConfigureChildren(configurations);
+    }
+  }
+  else {
+#ifndef XP_MACOSX
+    rpc->UnregisterPluginForGeometryUpdates(this);
+#endif
+  }
+
+  // Transfer the reference to the instance owner onto the stack so
+  // that if we do end up re-entering this code, or if we unwind back
+  // here witha deleted frame (this), we can still continue to stop
+  // the plugin. Note that due to that, the ordering of the code in
+  // this function is extremely important.
+
+  nsRefPtr<nsPluginInstanceOwner> owner;
+  owner.swap(mInstanceOwner);
+
+  // Make sure that our windowless rect has been zeroed out, so if we
+  // get reinstantiated we'll send the right messages to the plug-in.
+  mWindowlessRect.SetEmpty();
+
+  PRBool oldVal = mPreventInstantiation;
+  mPreventInstantiation = PR_TRUE;
+
+  nsWeakFrame weakFrame(this);
+
+#if defined(XP_WIN) || defined(MOZ_X11)
+  if (aDelayedStop && mWidget) {
+    // If we're asked to do a delayed stop it means we're stopping the
+    // plugin because we're destroying the frame. In that case, disown
+    // the widget.
+    mInnerView->DetachWidgetEventHandler(mWidget);
+    mWidget = nsnull;
+  }
+#endif
+
+  // From this point on, |this| could have been deleted, so don't
+  // touch it!
+  owner->PrepareToStop(aDelayedStop);
+
+  DoStopPlugin(owner, aDelayedStop);
+
+  // If |this| is still alive, reset mPreventInstantiation.
+  if (weakFrame.IsAlive()) {
+    NS_ASSERTION(mPreventInstantiation,
+                 "Instantiation should still be prevented!");
+
+    mPreventInstantiation = oldVal;
+  }
+
+  // Break relationship between frame and plugin instance owner
+  owner->SetOwner(nsnull);
 }
 
 NS_IMETHODIMP
 nsObjectFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor)
 {
   if (!mInstanceOwner) {
     return NS_ERROR_FAILURE;
   }
@@ -2081,16 +2499,53 @@ nsObjectFrame::SetIsDocumentActive(PRBoo
 {
 #ifndef XP_MACOSX
   if (mInstanceOwner) {
     mInstanceOwner->UpdateDocumentActiveState(aIsActive);
   }
 #endif
 }
 
+void
+nsObjectFrame::NotifyContentObjectWrapper()
+{
+  nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
+  if (!doc)
+    return;
+
+  nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
+  if (!sgo)
+    return;
+
+  nsIScriptContext *scx = sgo->GetContext();
+  if (!scx)
+    return;
+
+  JSContext *cx = (JSContext *)scx->GetNativeContext();
+
+  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
+  nsContentUtils::XPConnect()->
+    GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), mContent,
+                                   NS_GET_IID(nsISupports),
+                                   getter_AddRefs(wrapper));
+
+  if (!wrapper) {
+    // Nothing to do here if there's no wrapper for mContent. The proto
+    // chain will be fixed appropriately when the wrapper is created.
+    return;
+  }
+
+  JSObject *obj = nsnull;
+  nsresult rv = wrapper->GetJSObject(&obj);
+  if (NS_FAILED(rv))
+    return;
+
+  nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
+}
+
 // static
 nsIObjectFrame *
 nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
 {
   nsIFrame* child = aRoot->GetFirstPrincipalChild();
 
   while (child) {
     nsIObjectFrame* outFrame = do_QueryFrame(child);
--- a/layout/generic/nsObjectFrame.h
+++ b/layout/generic/nsObjectFrame.h
@@ -35,16 +35,20 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* rendering objects for replaced elements implemented by a plugin */
 
 #ifndef nsObjectFrame_h___
 #define nsObjectFrame_h___
 
+#ifdef XP_WIN
+#include <windows.h>
+#endif
+
 #include "nsPluginInstanceOwner.h"
 #include "nsIObjectFrame.h"
 #include "nsFrame.h"
 #include "nsRegion.h"
 #include "nsDisplayList.h"
 #include "nsIReflowCallback.h"
 #include "Layers.h"
 #include "ImageLayers.h"
@@ -115,18 +119,29 @@ public:
   NS_IMETHOD GetFrameName(nsAString& aResult) const;
 #endif
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot);
 
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
 
   NS_METHOD GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance);
+  virtual nsresult Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener);
+  virtual nsresult Instantiate(const char* aMimeType, nsIURI* aURI);
+  virtual void TryNotifyContentObjectWrapper();
+  virtual void StopPlugin();
+  virtual void SetIsDocumentActive(PRBool aIsActive);
 
-  virtual void SetIsDocumentActive(PRBool aIsActive);
+  /*
+   * Stop a plugin instance. If aDelayedStop is true, the plugin will
+   * be stopped at a later point when it's safe to do so (i.e. not
+   * while destroying the frame tree). Delayed stopping is only
+   * implemented on Win32 for now.
+   */
+  void StopPluginInternal(PRBool aDelayedStop);
 
   NS_IMETHOD GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor);
 
   // Compute the desired position of the plugin's widget, on the assumption
   // that it is not visible (clipped out or covered by opaque content).
   // This will only be called for plugins which have been registered
   // with the root pres context for geometry updates.
   // The widget, its new position, size and (empty) clip region are appended
@@ -143,17 +158,17 @@ public:
 #ifdef ACCESSIBILITY
   virtual already_AddRefed<nsAccessible> CreateAccessible();
 #ifdef XP_WIN
   NS_IMETHOD GetPluginPort(HWND *aPort);
 #endif
 #endif
 
   //local methods
-  nsresult SetWidget(nsIWidget *aWidget);
+  nsresult CreateWidget(nscoord aWidth, nscoord aHeight, PRBool aViewOnly);
 
   // for a given aRoot, this walks the frame tree looking for the next outFrame
   static nsIObjectFrame* GetNextObjectFrame(nsPresContext* aPresContext,
                                             nsIFrame* aRoot);
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
   virtual void ReflowCallbackCanceled();
@@ -189,59 +204,69 @@ public:
   /**
    * If aContent has a nsObjectFrame, then set it up after a DocShell swap.
    * @see nsSubDocumentFrame::EndSwapDocShells.
    */
   static void EndSwapDocShells(nsIContent* aContent, void*);
 
   nsIWidget* GetWidget() { return mWidget; }
 
-  /**
-   * Adjust the plugin's idea of its size, using aSize as its new size.
-   * (aSize must be in twips)
-   */
-  void FixupWindow(const nsSize& aSize);
-
-  /*
-   * Sets up the plugin window and calls SetWindow on the plugin.
-   */
-  nsresult CallSetWindow(PRBool aCheckIsHidden = PR_TRUE);
-
-  void SetInstanceOwner(nsPluginInstanceOwner* aOwner);
-
 protected:
   nsObjectFrame(nsStyleContext* aContext);
   virtual ~nsObjectFrame();
 
   // NOTE:  This frame class does not inherit from |nsLeafFrame|, so
   // this is not a virtual method implementation.
   void GetDesiredSize(nsPresContext* aPresContext,
                       const nsHTMLReflowState& aReflowState,
                       nsHTMLReflowMetrics& aDesiredSize);
 
+  nsresult InstantiatePlugin(nsPluginHost* aPluginHost, 
+                             const char* aMimetype,
+                             nsIURI* aURL);
+
+  /**
+   * Adjust the plugin's idea of its size, using aSize as its new size.
+   * (aSize must be in twips)
+   */
+  void FixupWindow(const nsSize& aSize);
+
+  /**
+   * Sets up the plugin window and calls SetWindow on the plugin.
+   */
+  nsresult CallSetWindow(PRBool aCheckIsHidden = PR_TRUE);
+
   PRBool IsFocusable(PRInt32 *aTabIndex = nsnull, PRBool aWithMouse = PR_FALSE);
 
   // check attributes and optionally CSS to see if we should display anything
   PRBool IsHidden(PRBool aCheckVisibilityStyle = PR_TRUE) const;
 
   PRBool IsOpaque() const;
   PRBool IsTransparentMode() const;
 
+  void NotifyContentObjectWrapper();
+
   nsIntPoint GetWindowOriginInPixels(PRBool aWindowless);
 
   static void PaintPrintPlugin(nsIFrame* aFrame,
                                nsRenderingContext* aRenderingContext,
                                const nsRect& aDirtyRect, nsPoint aPt);
   void PrintPlugin(nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect);
   void PaintPlugin(nsDisplayListBuilder* aBuilder,
                    nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect, const nsRect& aPluginRect);
 
   /**
+   * Makes sure that mInstanceOwner is valid and without a current plugin
+   * instance. Essentially, this prepares the frame to receive a new plugin.
+   */
+  NS_HIDDEN_(nsresult) PrepareInstanceOwner();
+
+  /**
    * Get the widget geometry for the plugin. aRegion is in some appunits
    * coordinate system whose origin is device-pixel-aligned (if possible),
    * and aPluginOrigin gives the top-left of the plugin frame's content-rect
    * in that coordinate system. It doesn't matter what that coordinate
    * system actually is, as long as aRegion and aPluginOrigin are consistent.
    * This will append a Configuration object to aConfigurations
    * containing the widget, its desired position, size and clip region.
    */
@@ -261,27 +286,32 @@ private:
   public:
     PluginEventNotifier(const nsString &aEventType) : 
       mEventType(aEventType) {}
     
     NS_IMETHOD Run();
   private:
     nsString mEventType;
   };
-
-  nsPluginInstanceOwner*          mInstanceOwner; // WEAK
+  
+  nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
   nsIView*                        mInnerView;
   nsCOMPtr<nsIWidget>             mWidget;
   nsIntRect                       mWindowlessRect;
   /**
    * This is owned by the ReadbackLayer for this nsObjectFrame. It is
    * automatically cleared if the PluginBackgroundSink is destroyed.
    */
   PluginBackgroundSink*           mBackgroundSink;
 
+  // For assertions that make it easier to determine if a crash is due
+  // to the underlying problem described in bug 136927, and to prevent
+  // reentry into instantiation.
+  PRBool mPreventInstantiation;
+
   PRPackedBool mReflowCallbackPosted;
 
   // A reference to the ImageContainer which contains the current frame
   // of plugin to display.
   nsRefPtr<ImageContainer> mImageContainer;
 };
 
 class nsDisplayPlugin : public nsDisplayItem {
--- a/layout/generic/nsPluginUtilsOSX.mm
+++ b/layout/generic/nsPluginUtilsOSX.mm
@@ -152,22 +152,17 @@ NPError NS_NPAPI_ShowCocoaContextMenu(vo
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NPERR_GENERIC_ERROR);
 }
 
 NPBool NS_NPAPI_ConvertPointCocoa(void* inView,
                                   double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
                                   double *destX, double *destY, NPCoordinateSpace destSpace)
 {
-  // Plugins don't always have a view/frame. It would be odd to ask for a point conversion
-  // without a view, so we'll warn about it, but it's technically OK.
-  if (!inView) {
-    NS_WARNING("Must have a native view to convert coordinates.");
-    return PR_FALSE;
-  }
+  NS_ASSERTION(inView, "Must have a native view to convert coordinates.");
 
   // Caller has to want a result.
   if (!destX && !destY)
     return PR_FALSE;
 
   if (sourceSpace == destSpace) {
     if (destX)
       *destX = sourceX;