Bug 90268: Change plugin instance ownership from layout to content. r=roc r=bsmedberg
authorJosh Aas <joshmoz@gmail.com>
Tue, 31 Jan 2012 16:55:54 -0500
changeset 88723 15b00ab7f22d745ef331d89e766a261c770fd1d3
parent 88722 b506d48ef7aa28b66ca63d8dc8e5d8ce075fa73d
child 88724 1410782d557d170b081db3f847599b976462eabe
push id783
push userlsblakk@mozilla.com
push dateTue, 24 Apr 2012 17:33:42 +0000
treeherdermozilla-beta@11faed19f136 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, bsmedberg
bugs90268
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 90268: Change plugin instance ownership from layout to content. r=roc r=bsmedberg
content/base/public/nsContentUtils.h
content/base/public/nsIObjectLoadingContent.idl
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsNodeUtils.cpp
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/html/document/src/PluginDocument.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/plugins/base/nsIPluginInstanceOwner.idl
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
dom/plugins/base/nsPluginStreamListenerPeer.cpp
dom/plugins/base/nsPluginStreamListenerPeer.h
dom/plugins/test/mochitest/Makefile.in
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
dom/plugins/test/reftest/reftest.list
layout/base/nsPresShell.cpp
layout/generic/nsIObjectFrame.h
layout/generic/nsObjectFrame.cpp
layout/generic/nsObjectFrame.h
layout/generic/nsPluginUtilsOSX.mm
widget/nsIWidget.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1708,16 +1708,23 @@ 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(e5330f90-91a3-41d7-b29e-af38a23a6602)]
+[scriptable, uuid(6D8914C7-0E22-4452-8962-11B69BBE84D7)]
 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,42 +82,26 @@ 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();
 
@@ -126,9 +110,14 @@ interface nsIObjectLoadingContent : nsIS
                                 in AString browserDumpID,
                                 in boolean submittedCrashReport);
 
   /**
    * This method will play a plugin that has been stopped by the
    * click-to-play plugins feature.
    */
   void playPlugin();
+
+  [noscript] void stopPluginInstance();
+
+  [noscript] void syncStartPluginInstance();
+  [noscript] void asyncStartPluginInstance();
 };
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5840,19 +5840,18 @@ 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());
   }
 }
 
-static already_AddRefed<LayerManager>
-LayerManagerForDocumentInternal(nsIDocument *aDoc, bool aRequirePersistent,
-                                bool* aAllowRetaining)
+nsIWidget *
+nsContentUtils::WidgetForDocument(nsIDocument *aDoc)
 {
   nsIDocument* doc = aDoc;
   nsIDocument* displayDoc = doc->GetDisplayDocument();
   if (displayDoc) {
     doc = displayDoc;
   }
 
   nsIPresShell* shell = doc->GetShell();
@@ -5877,33 +5876,41 @@ LayerManagerForDocumentInternal(nsIDocum
 
   if (shell) {
     nsIViewManager* VM = shell->GetViewManager();
     if (VM) {
       nsIView* rootView = VM->GetRootView();
       if (rootView) {
         nsIView* displayRoot = nsIViewManager::GetDisplayRootFor(rootView);
         if (displayRoot) {
-          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 displayRoot->GetNearestWidget(nsnull);
         }
       }
     }
   }
 
   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
@@ -171,16 +171,17 @@
 #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"
@@ -3750,16 +3751,21 @@ 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
@@ -60,16 +60,17 @@
 #include "nsBindingManager.h"
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 #include "nsImageLoadingContent.h"
 #include "jsgc.h"
 #include "nsWrapperCacheInlines.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_)      \
@@ -561,25 +562,30 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
           }
           if (elm->MayHaveMouseEnterLeaveEventListener()) {
             window->SetHasMouseEnterLeaveEventListeners();
           }
         }
       }
     }
 
+    if (wasRegistered && oldDoc != newDoc) {
 #ifdef MOZ_MEDIA
-    if (wasRegistered && oldDoc != newDoc) {
       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();
+      }
     }
-#endif
 
     // 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,16 +64,17 @@
 #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,93 +94,88 @@
 
 #include "nsObjectLoadingContent.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 #include "mozilla/dom/Element.h"
 #include "sampler.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)
 
 #include "mozilla/Preferences.h"
 
 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), mFrame(aFrame), mContentType(aType), mURI(aURI)
+  nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
+  : mContent(aContent)
   {
     static_cast<nsIObjectLoadingContent *>(mContent)->AddRef();
   }
 
   ~nsAsyncInstantiateEvent()
   {
     static_cast<nsIObjectLoadingContent *>(mContent)->Release();
   }
 
   NS_IMETHOD Run();
 };
 
 NS_IMETHODIMP
 nsAsyncInstantiateEvent::Run()
 {
-  // Check if we've been "revoked"
-  if (mContent->mPendingInstantiateEvent != this)
+  // do nothing if we've been revoked
+  if (mContent->mPendingInstantiateEvent != this) {
     return NS_OK;
+  }
   mContent->mPendingInstantiateEvent = nsnull;
 
-  // 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);
+  return mContent->SyncStartPluginInstance();
+}
 
-  nsIFrame* objectFrame = nsnull;
-  if (frame) {
-    objectFrame = do_QueryFrame(frame);
+// 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)
+  {
   }
 
-  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()));
-    }
-
-    nsresult rv = mContent->Instantiate(frame, mContentType, mURI);
-    if (NS_FAILED(rv)) {
-      mContent->Fallback(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:
@@ -331,16 +327,79 @@ 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, false);
+
+  return NS_OK;
+}
+
 class AutoNotifier {
   public:
     AutoNotifier(nsObjectLoadingContent* aContent, bool aNotify) :
       mContent(aContent), mNotify(aNotify) {
         mOldType = aContent->Type();
         mOldState = aContent->ObjectState();
     }
     ~AutoNotifier() {
@@ -488,34 +547,155 @@ nsObjectLoadingContent::nsObjectLoadingC
   , mChannel(nsnull)
   , mType(eType_Loading)
   , mInstantiating(false)
   , mUserDisabled(false)
   , mSuppressed(false)
   , mNetworkCreated(true)
   // If plugins.click_to_play is false, plugins should always play
   , mShouldPlay(!mozilla::Preferences::GetBool("plugins.click_to_play", false))
+  , mSrcStreamLoadInitiated(false)
   , mFallbackReason(ePluginOtherState)
 {
 }
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   DestroyImageLoadingContent();
   if (mFrameLoader) {
     mFrameLoader->Destroy();
   }
 }
 
+nsresult
+nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI)
+{
+  // Don't do anything if we already have an active instance.
+  if (mInstanceOwner) {
+    return NS_OK;
+  }
+
+  // Don't allow re-entry into initialization code.
+  if (mInstantiating) {
+    return NS_OK;
+  }
+  mInstantiating = true;
+  AutoSetInstantiatingToFalse autoInstantiating(this);
+
+  // Instantiating an instance can result in script execution, which
+  // can destroy this DOM object. Don't allow that for the scope
+  // of this method.
+  nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+
+  nsCString typeToUse(aMimeType);
+  if (typeToUse.IsEmpty() && aURI) {
+    IsPluginEnabledByExtension(aURI, typeToUse, mShouldPlay);
+  }
+
+  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;
+  }
+
+  // Flush layout so that the plugin is initialized with the latest information.
+  nsIDocument* doc = thisContent->GetCurrentDoc();
+  if (!doc) {
+    return NS_ERROR_FAILURE;
+  }
+  doc->FlushPendingNotifications(Flush_Layout);
+
+  nsresult rv = NS_ERROR_FAILURE;
+  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(doc));
+  bool fullPageMode = false;
+  if (pDoc) {
+    pDoc->GetWillHandleInstantiation(&fullPageMode);
+  }
+
+  if (fullPageMode) {
+    nsCOMPtr<nsIStreamListener> stream;
+    rv = pluginHost->InstantiateFullPagePlugin(aMimeType, aURI, this, getter_AddRefs(mInstanceOwner), getter_AddRefs(stream));
+    if (NS_SUCCEEDED(rv)) {
+      pDoc->SetStreamListener(stream);
+    }
+  } else {
+    rv = pluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI, this, getter_AddRefs(mInstanceOwner));
+  }
+
+  if (appShell) {
+    appShell->ResumeNative();
+  }
+
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Set up scripting interfaces.
+  NotifyContentObjectWrapper();
+
+  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 NS_OK;
+}
+
+void
+nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
+{
+  if (!mInstanceOwner) {
+    return;
+  }
+
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  nsIDocument* ownerDoc = thisContent->OwnerDoc();
+  if (!ownerDoc->IsActive()) {
+    StopPluginInstance();
+  }
+}
+
 // nsIRequestObserver
 NS_IMETHODIMP
 nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
                                        nsISupports *aContext)
 {
   SAMPLE_LABEL("nsObjectLoadingContent", "OnStartRequest");
+
+  mSrcStreamLoadInitiated = true;
+
   if (aRequest != mChannel || !aRequest) {
     // This is a bit of an edge case - happens when a new load starts before the
     // previous one got here
     return NS_BINDING_ABORTED;
   }
 
   AutoNotifier notifier(this, true);
 
@@ -537,35 +717,32 @@ 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, mShouldPlay) && 
        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;
   }
@@ -688,53 +865,28 @@ 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 = 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 = false;
-        return NS_BINDING_ABORTED;
+    case eType_Plugin: {
+      nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+      nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+      if (!pluginHost) {
+        return NS_ERROR_NOT_AVAILABLE;
       }
-
-      {
-        nsIFrame *nsiframe = do_QueryFrame(frame);
-
-        nsWeakFrame weakFrame(nsiframe);
-
-        rv = frame->Instantiate(chan, getter_AddRefs(mFinalListener));
-
-        mInstantiating = false;
-
-        if (!weakFrame.IsAlive()) {
-          // The frame was destroyed while instantiating. Abort the load.
-          return NS_BINDING_ABORTED;
-        }
-      }
-
+      pluginHost->InstantiatePluginForChannel(chan, this, getter_AddRefs(mFinalListener));
       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(false);
 
       PluginSupportState pluginState = GetPluginSupportState(thisContent,
                                                              mContentType);
       // Do nothing, but fire the plugin not found event if needed
@@ -744,41 +896,31 @@ 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(false);
     } else if (mType == eType_Plugin) {
-      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();
-      }
+      NotifyContentObjectWrapper();
     }
     return rv;
   }
 
-  LOG(("OBJLC [%p]: Found no listener, falling back\n", this));
   Fallback(false);
   return NS_BINDING_ABORTED;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::OnStopRequest(nsIRequest *aRequest,
                                       nsISupports *aContext,
                                       nsresult aStatusCode)
@@ -855,174 +997,59 @@ nsObjectLoadingContent::GetActualType(ns
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetDisplayedType(PRUint32* aType)
 {
   *aType = mType;
   return NS_OK;
 }
 
-
 NS_IMETHODIMP
-nsObjectLoadingContent::EnsureInstantiation(nsNPAPIPluginInstance** aInstance)
+nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
 {
-  // Must set our out parameter to null as we have various early returns with
-  // an NS_OK result.
-  *aInstance = nsnull;
-
-  if (mType != eType_Plugin) {
+  // Not having an instance yet is OK, but try to start one now that
+  // we have a frame.
+  if (!mInstanceOwner) {
+    AsyncStartPluginInstance();
     return NS_OK;
   }
 
-  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 = 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 = false;
-      return NS_OK;
-    }
-
-    doc->FlushPendingNotifications(Flush_Frames);
-
-    mInstantiating = false;
+  // Disconnect any existing frame
+  DisconnectFrame();
 
-    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 relationship between instance owner and frame.
+  nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
+  mInstanceOwner->SetFrame(objFrame);
 
-    if (!frame) {
-      return NS_OK;
-    }
-
-    nsiframe = do_QueryFrame(frame);
-  }
-
-  nsWeakFrame weakFrame(nsiframe);
+  // Set up new frame to draw.
+  objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
+  objFrame->Invalidate(objFrame->GetContentRectRelativeToSelf());
 
-  // 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(true);
-    }
-  }
-  return rv;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
+nsObjectLoadingContent::DisconnectFrame()
 {
-  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->OwnerDoc();
-  if (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) {
-      bool 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;
-    }
+  if (mInstanceOwner) {
+    mInstanceOwner->SetFrame(nsnull);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
 {
   *aInstance = nsnull;
 
-  nsIObjectFrame* objFrame = GetExistingFrame(eDontFlush);
-  if (!objFrame) {
+  if (!mInstanceOwner) {
     return NS_OK;
   }
 
-  return objFrame->GetPluginInstance(aInstance);
+  return mInstanceOwner->GetInstance(aInstance);
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
                                                   PRUint32* aType)
 {
   *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType));
   return NS_OK;
@@ -1114,18 +1141,16 @@ nsresult
 nsObjectLoadingContent::LoadObject(const nsAString& aURI,
                                    bool aNotify,
                                    const nsCString& aTypeHint,
                                    bool aForceLoad)
 {
   LOG(("OBJLC [%p]: Loading object: URI string=<%s> notify=%i type=<%s> forceload=%i\n",
        this, NS_ConvertUTF16toUTF8(aURI).get(), aNotify, aTypeHint.get(), aForceLoad));
 
-  NS_ASSERTION(!mInstantiating, "LoadObject was reentered?");
-
   // Avoid StringToURI in order to use the codebase attribute as base URI
   nsCOMPtr<nsIContent> thisContent = 
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   NS_ASSERTION(thisContent, "must be a content");
 
   nsIDocument* doc = thisContent->OwnerDoc();
   nsCOMPtr<nsIURI> baseURI;
   GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
@@ -1160,43 +1185,36 @@ nsObjectLoadingContent::UpdateFallbackSt
 }
 
 nsresult
 nsObjectLoadingContent::LoadObject(nsIURI* aURI,
                                    bool aNotify,
                                    const nsCString& aTypeHint,
                                    bool 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) {
-    bool equal;
-    nsresult rv = mURI->Equals(aURI, &equal);
-    if (NS_SUCCEEDED(rv) && equal) {
-      // URI didn't change, do nothing
-      return NS_OK;
+  // Only do a URI equality check for things that aren't stopped plugins.
+  // This is because we still need to load again if the plugin has been stopped.
+  if (mType == eType_Document || mType == eType_Image || mInstanceOwner) {
+    if (mURI && aURI && !aForceLoad) {
+      bool 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.
-  NS_ASSERTION(!mInstantiating, "LoadObject was reentered?");
-  mInstantiating = true;
-  AutoSetInstantiatingToFalse autoset(this);
-
   mUserDisabled = mSuppressed = false;
 
   mURI = aURI;
   mContentType = aTypeHint;
 
   nsCOMPtr<nsIContent> thisContent = 
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   NS_ASSERTION(thisContent, "must be a content");
@@ -1314,17 +1332,17 @@ nsObjectLoadingContent::LoadObject(nsIUR
         // Don't notify, because we will take care of that ourselves.
         if (aURI) {
           rv = LoadImage(aURI, aForceLoad, false);
         } else {
           rv = NS_ERROR_NOT_AVAILABLE;
         }
         break;
       case eType_Plugin:
-        rv = TryInstantiate(mContentType, mURI);
+        rv = AsyncStartPluginInstance();
         break;
       case eType_Document:
         if (aURI) {
           rv = mFrameLoader->LoadURI(aURI);
         } else {
           rv = NS_ERROR_NOT_AVAILABLE;
         }
         break;
@@ -1349,27 +1367,25 @@ nsObjectLoadingContent::LoadObject(nsIUR
     if (!classid.IsEmpty()) {
       hasID = 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!");
@@ -1383,46 +1399,44 @@ 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 = TryInstantiate(mContentType, mURI);
-    return NS_OK;
+    // rv is references by a stack-based object, need to assign here
+    rv = AsyncStartPluginInstance();
+
+    return rv;
   }
 
   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, mShouldPlay)) {
       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;
   }
@@ -1489,36 +1503,46 @@ nsObjectLoadingContent::GetCapabilities(
          eSupportPlugins |
          eSupportDocuments |
          eSupportSVG;
 }
 
 void
 nsObjectLoadingContent::Fallback(bool 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");
@@ -1773,47 +1797,23 @@ nsObjectLoadingContent::GetObjectBaseURI
     nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
                                               thisContent->OwnerDoc(),
                                               baseURI);
   } else {
     baseURI.swap(*aURI);
   }
 }
 
-nsIObjectFrame*
-nsObjectLoadingContent::GetExistingFrame(FlushType aFlushType)
+nsObjectFrame*
+nsObjectLoadingContent::GetExistingFrame()
 {
-  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;
-    }
-
-    if (aFlushType == eDontFlush) {
-      break;
-    }
-    
-    // OK, let's flush out and try again.  Note that we want to reget
-    // the document, etc, since flushing might run script.
-    nsIDocument* doc = thisContent->GetCurrentDoc();
-    NS_ASSERTION(doc, "Frame but no document?");
-    mozFlushType flushType =
-      aFlushType == eFlushLayout ? Flush_Layout : Flush_ContentAndNotify;
-    doc->FlushPendingNotifications(flushType);
-
-    aFlushType = eDontFlush;
-  } while (1);
-
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  nsIFrame* frame = thisContent->GetPrimaryFrame();
   nsIObjectFrame* objFrame = do_QueryFrame(frame);
-  return objFrame;
+  return static_cast<nsObjectFrame*>(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
@@ -1823,115 +1823,16 @@ nsObjectLoadingContent::HandleBeingBlock
     if (aRetval == nsIContentPolicy::REJECT_TYPE) {
       mUserDisabled = true;
     } else if (aRetval == nsIContentPolicy::REJECT_SERVER) {
       mSuppressed = 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.
-  bool oldInstantiatingValue = mInstantiating;
-  mInstantiating = true;
-
-  nsCString typeToUse(aMIMEType);
-  if (typeToUse.IsEmpty() && aURI) {
-    IsPluginEnabledByExtension(aURI, typeToUse, mShouldPlay);
-  }
-
-  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;
   }
 
@@ -1985,20 +1886,17 @@ nsObjectLoadingContent::CreateStaticClon
 {
   nsImageLoadingContent::CreateStaticImageClone(aDest);
 
   aDest->mType = mType;
   nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
   if (thisObj->mPrintFrame.IsAlive()) {
     aDest->mPrintFrame = thisObj->mPrintFrame;
   } else {
-    nsIObjectFrame* frame =
-      const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame(eDontFlush);
-    nsIFrame* f = do_QueryFrame(frame);
-    aDest->mPrintFrame = f;
+    aDest->mPrintFrame = const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame();
   }
 
   if (mFrameLoader) {
     nsCOMPtr<nsIContent> content =
       do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
     nsFrameLoader* fl = nsFrameLoader::Create(content->AsElement(), false);
     if (fl) {
       aDest->mFrameLoader = fl;
@@ -2041,16 +1939,179 @@ nsObjectLoadingContent::PluginCrashed(ns
   nsresult rv = NS_DispatchToCurrentThread(ev);
   if (NS_FAILED(rv)) {
     NS_WARNING("failed to dispatch nsPluginCrashedEvent");
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsObjectLoadingContent::SyncStartPluginInstance()
+{
+  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
+               "Must be able to run script in order to instantiate a plugin instance!");
+
+  // Don't even attempt to start an instance unless the content is in the document.
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  if (!thisContent->IsInDoc()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return InstantiatePluginInstance(mContentType.get(), mURI.get());
+}
+
+NS_IMETHODIMP
+nsObjectLoadingContent::AsyncStartPluginInstance()
+{
+  // OK to have an instance already.
+  if (mInstanceOwner) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  nsIDocument* doc = thisContent->OwnerDoc();
+  if (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);
+  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 bool
+DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop)
+{
+#if (MOZ_PLATFORM_MAEMO==5)
+  // Don't delay stop on Maemo/Hildon (bug 530739).
+  if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
+    return 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 true;
+  }
+  return false;
+}
+
+void
+nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop)
+{
+  nsRefPtr<nsNPAPIPluginInstance> inst;
+  aInstanceOwner->GetInstance(getter_AddRefs(inst));
+  if (inst) {
+    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);
+  }
+  
+  aInstanceOwner->Destroy();
+}
+
+NS_IMETHODIMP
+nsObjectLoadingContent::StopPluginInstance()
+{
+  if (!mInstanceOwner) {
+    return NS_OK;
+  }
+
+  DisconnectFrame();
+
+  bool delayedStop = 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 = true;
+      }      
+    }
+  }
+#endif
+
+  DoStopPlugin(mInstanceOwner, delayedStop);
+
+  mInstanceOwner = nsnull;
+
+  return NS_OK;
+}
+
+void
+nsObjectLoadingContent::NotifyContentObjectWrapper()
+{
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+
+  nsCOMPtr<nsIDocument> doc = thisContent->GetDocument();
+  if (!doc)
+    return;
+  
+  nsIScriptGlobalObject *sgo = doc->GetScopeObject();
+  if (!sgo)
+    return;
+  
+  nsIScriptContext *scx = sgo->GetContext();
+  if (!scx)
+    return;
+  
+  JSContext *cx = 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);
+}
+
+NS_IMETHODIMP
 nsObjectLoadingContent::PlayPlugin()
 {
   if (!nsContentUtils::IsCallerChrome())
     return NS_OK;
 
   mShouldPlay = true;
   return LoadObject(mURI, true, mContentType, true);
 }
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -48,21 +48,25 @@
 #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,
@@ -92,16 +96,18 @@ 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
@@ -134,16 +140,24 @@ class nsObjectLoadingContent : public ns
      * NS_EVENT_STATE_SUPPRESSED representing the current state of the object.
      */
     nsEventStates ObjectState() const;
 
     void SetIsNetworkCreated(bool aNetworkCreated)
     {
       mNetworkCreated = aNetworkCreated;
     }
+
+    // Can flush layout.
+    nsresult InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI);
+
+    void NotifyOwnerDocumentActivityChanged();
+
+    bool SrcStreamLoadInitiated() { return mSrcStreamLoadInitiated; };
+
   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.
@@ -222,17 +236,23 @@ 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, bool aDelayedStop);
+
   private:
+
+    void NotifyContentObjectWrapper();
+
     /**
      * Check whether the given request represents a successful load.
      */
     static bool IsSuccessfulRequest(nsIRequest* aRequest);
 
     /**
      * Check whether the URI can be handled internally.
      */
@@ -283,61 +303,30 @@ class nsObjectLoadingContent : public ns
      * Gets the base URI to be used for this object. This differs from
      * nsIContent::GetBaseURI in that it takes codebase attributes into
      * account.
      */
     void GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI);
 
 
     /**
-     * Gets the frame that's associated with this content node in
-     * presentation 0. Always returns null if the node doesn't currently
-     * have a frame.
-     *
-     * @param aFlush When eFlushContent will flush content notifications
-     *               before returning a non-null value.
-     *               When eFlushLayout will flush layout and content
-     *               notifications before returning a non-null value.
-     *               When eDontFlush will never flush.
-     *         
-     *   eFlushLayout is needed in some cases by plug-ins to ensure
-     *   that NPP_SetWindow() gets called (from nsObjectFrame::DidReflow).
+     * Gets the frame that's associated with this content node.
+     * Does not flush.
      */
-    enum FlushType {
-      eFlushContent,
-      eFlushLayout,
-      eDontFlush
-    };
-    nsIObjectFrame* GetExistingFrame(FlushType aFlushType);
+    nsObjectFrame* GetExistingFrame();
 
     /**
      * 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,
@@ -409,18 +398,21 @@ class nsObjectLoadingContent : public ns
     // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
     // Used to keep track of whether or not a plugin should be played.
     // This is used for click-to-play plugins.
     bool                        mShouldPlay : 1;
 
+    // Used to indicate that a stream for a src/data attribute has been
+    // initiated so that we don't do it twice.
+    bool mSrcStreamLoadInitiated;
+
     // A specific state that caused us to fallback
     PluginSupportState          mFallbackReason;
 
     nsWeakFrame                 mPrintFrame;
 
-    friend class nsAsyncInstantiateEvent;
+    nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
 };
 
-
 #endif
--- a/content/html/document/src/PluginDocument.cpp
+++ b/content/html/document/src/PluginDocument.cpp
@@ -42,16 +42,17 @@
 #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"
 #include "sampler.h"
 
 namespace mozilla {
 namespace dom {
 
 class PluginDocument : public MediaDocument
                      , public nsIPluginDocument
 {
@@ -141,30 +142,23 @@ 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);
 
-  nsIFrame* frame = embed->GetPrimaryFrame();
-  if (!frame) {
-    mPluginDoc->AllowNormalInstantiation();
-    return NS_OK;
-  }
-
-  nsIObjectFrame* objFrame = do_QueryFrame(frame);
-  if (!objFrame) {
-    mPluginDoc->AllowNormalInstantiation();
+  nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(embed));
+  if (!olc) {
     return NS_ERROR_UNEXPECTED;
   }
-
-  nsresult rv = objFrame->Instantiate(mPluginDoc->GetType().get(),
-                                      mDocument->nsIDocument::GetDocumentURI());
+  nsObjectLoadingContent* olcc = static_cast<nsObjectLoadingContent*>(olc.get());
+  nsresult rv = olcc->InstantiatePluginInstance(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();
 
@@ -352,17 +346,17 @@ PluginDocument::SetStreamListener(nsIStr
 NS_IMETHODIMP
 PluginDocument::Print()
 {
   NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE);
 
   nsIObjectFrame* objectFrame =
     do_QueryFrame(mPluginContent->GetPrimaryFrame());
   if (objectFrame) {
-    nsCOMPtr<nsNPAPIPluginInstance> pi;
+    nsRefPtr<nsNPAPIPluginInstance> pi;
     objectFrame->GetPluginInstance(getter_AddRefs(pi));
     if (pi) {
       NPPrint npprint;
       npprint.mode = NP_FULL;
       npprint.print.fullPrint.pluginPrinted = false;
       npprint.print.fullPrint.printOne = false;
       npprint.print.fullPrint.platformPrint = nsnull;
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -9554,61 +9554,47 @@ nsHTMLSelectElementSH::SetProperty(nsIXP
     return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return NS_OK;
 }
 
 
 // HTMLObject/EmbedElement helper
-
+// Keep in mind that it is OK for this to fail to return an instance. Don't return a
+// failure result unless something truly exceptional has happened.
 // static
 nsresult
 nsHTMLPluginObjElementSH::GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *wrapper,
                                                   JSObject *obj,
                                                   nsNPAPIPluginInstance **_result)
 {
   *_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");
 
-  // If it's not safe to run script we'll only return the instance if it
-  // exists.
+  nsresult rv = objlc->GetPluginInstance(_result);
+  if (NS_SUCCEEDED(rv) && *_result) {
+    return rv;
+  }
+
+  // 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 bool
-IsObjInProtoChain(JSContext *cx, JSObject *obj, JSObject *proto)
-{
-  JSObject *o = obj;
-
-  JSAutoRequest ar(cx);
-
-  while (o) {
-    JSObject *p = ::JS_GetPrototype(cx, o);
-
-    if (p == proto) {
-      return true;
-    }
-
-    o = p;
-  }
-
-  return false;
+    return rv;
+  }
+
+  // We don't care if this actually starts the plugin or not, we just want to
+  // try to start it now if possible.
+  objlc->SyncStartPluginInstance();
+
+  return objlc->GetPluginInstance(_result);
 }
 
 class nsPluginProtoChainInstallRunner : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
 
   nsPluginProtoChainInstallRunner(nsIXPConnectWrappedNative* wrapper,
@@ -9680,30 +9666,19 @@ 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/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -527,17 +527,17 @@ NS_IMETHODIMP
 nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow)
 {
   aWindow = nsnull;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDummyJavaPluginOwner::SetWindow()
+nsDummyJavaPluginOwner::CallSetWindow()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode)
 {
   // This is wrong, but there's no better alternative.
--- a/dom/plugins/base/nsIPluginInstanceOwner.idl
+++ b/dom/plugins/base/nsIPluginInstanceOwner.idl
@@ -139,10 +139,10 @@ interface nsIPluginInstanceOwner : nsISu
 
 %{C++
   virtual void SendIdleEvent() = 0;
 %}
 
   /**
    * Call NPP_SetWindow on the plugin.
    */
-  void setWindow();
+  void callSetWindow();
 };
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -88,17 +88,16 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
 #endif
 #endif
 #ifdef MOZ_WIDGET_ANDROID
     mSurface(nsnull),
     mANPDrawingModel(0),
 #endif
     mRunning(NOT_STARTED),
     mWindowless(false),
-    mWindowlessLocal(false),
     mTransparent(false),
     mCached(false),
     mUsesDOMForCursor(false),
     mInPluginInitCall(false),
     mPlugin(plugin),
     mMIMEType(nsnull),
     mOwner(nsnull),
     mCurrentPluginEvent(nsnull),
@@ -681,22 +680,16 @@ NPError nsNPAPIPluginInstance::SetWindow
     if (!PL_strncasecmp(mMIMEType, silverlight.get(), silverlight.Length())) {
       mTransparent = true;
     }
   }
 
   return NPERR_NO_ERROR;
 }
 
-NPError nsNPAPIPluginInstance::SetWindowlessLocal(bool aWindowlessLocal)
-{
-  mWindowlessLocal = aWindowlessLocal;
-  return NPERR_NO_ERROR;
-}
-
 NPError nsNPAPIPluginInstance::SetTransparent(bool aTransparent)
 {
   mTransparent = aTransparent;
   return NPERR_NO_ERROR;
 }
 
 NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(bool aUsesDOMForCursor)
 {
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -130,18 +130,16 @@ public:
 
   nsresult GetNPP(NPP * aNPP);
 
   void SetURI(nsIURI* uri);
   nsIURI* GetURI();
 
   NPError SetWindowless(bool aWindowless);
 
-  NPError SetWindowlessLocal(bool aWindowlessLocal);
-
   NPError SetTransparent(bool aTransparent);
 
   NPError SetWantsAllNetworkStreams(bool aWantsAllNetworkStreams);
 
   NPError SetUsesDOMForCursor(bool aUsesDOMForCursor);
   bool UsesDOMForCursor();
 
 #ifdef XP_MACOSX
@@ -239,17 +237,16 @@ protected:
     RUNNING,
     DESTROYING,
     DESTROYED
   } mRunning;
 
   // these are used to store the windowless properties
   // which the browser will later query
   bool mWindowless;
-  bool mWindowlessLocal;
   bool mTransparent;
   bool mCached;
   bool mUsesDOMForCursor;
 
 public:
   // True while creating the plugin, or calling NPP_SetWindow() on it.
   bool mInPluginInitCall;
 
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -147,16 +147,17 @@
 #include "nsIDocShell.h"
 #include "nsPluginNativeWindow.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
+#include "nsIImageLoadingContent.h"
 #include "mozilla/Preferences.h"
 
 #if defined(XP_WIN)
 #include "nsIWindowMediator.h"
 #include "nsIBaseWindow.h"
 #include "windows.h"
 #include "winbase.h"
 #endif
@@ -934,90 +935,103 @@ nsPluginHost::GetPluginTempDir(nsIFile *
 
     tmpDir.swap(sPluginTempDir);
   }
 
   return sPluginTempDir->Clone(aDir);
 }
 
 nsresult nsPluginHost::InstantiatePluginForChannel(nsIChannel* aChannel,
-                                                   nsIPluginInstanceOwner* aOwner,
+                                                   nsObjectLoadingContent* aContent,
                                                    nsIStreamListener** aListener)
 {
-  NS_PRECONDITION(aChannel && aOwner,
+  NS_PRECONDITION(aChannel && aContent,
                   "Invalid arguments to InstantiatePluginForChannel");
   nsCOMPtr<nsIURI> uri;
   nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
   if (NS_FAILED(rv))
     return rv;
 
 #ifdef PLUGIN_LOGGING
   if (PR_LOG_TEST(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL)) {
     nsCAutoString urlSpec;
     uri->GetAsciiSpec(urlSpec);
 
     PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-           ("nsPluginHost::InstantiatePluginForChannel Begin owner=%p, url=%s\n",
-           aOwner, urlSpec.get()));
+           ("nsPluginHost::InstantiatePluginForChannel Begin content=%p, url=%s\n",
+           aContent, urlSpec.get()));
 
     PR_LogFlush();
   }
 #endif
 
   // Note that we're not setting up a plugin instance here; the stream
   // listener's OnStartRequest will handle doing that.
 
-  return NewEmbeddedPluginStreamListener(uri, aOwner, nsnull, aListener);
+  return NewEmbeddedPluginStreamListener(uri, aContent, nsnull, aListener);
 }
 
 nsresult
 nsPluginHost::InstantiateEmbeddedPlugin(const char *aMimeType, nsIURI* aURL,
-                                        nsIPluginInstanceOwner* aOwner)
+                                        nsObjectLoadingContent *aContent,
+                                        nsPluginInstanceOwner** aOwner)
 {
   NS_ENSURE_ARG_POINTER(aOwner);
 
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec;
   if (aURL)
     aURL->GetAsciiSpec(urlSpec);
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-        ("nsPluginHost::InstantiateEmbeddedPlugin Begin mime=%s, owner=%p, url=%s\n",
-        aMimeType, aOwner, urlSpec.get()));
+        ("nsPluginHost::InstantiateEmbeddedPlugin Begin mime=%s, url=%s\n",
+        aMimeType, urlSpec.get()));
 
   PR_LogFlush();
 #endif
 
-  nsresult rv;
-  nsCOMPtr<nsIPluginTagInfo> pti;
-  nsPluginTagType tagType;
-
-  rv = aOwner->QueryInterface(kIPluginTagInfoIID, getter_AddRefs(pti));
-
-  if (rv != NS_OK)
+  nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
+  if (!instanceOwner) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
+  nsresult rv = instanceOwner->Init(ourContent);
+  if (NS_FAILED(rv)) {
     return rv;
-
+  }
+
+  nsCOMPtr<nsIPluginTagInfo> pti;
+  rv = instanceOwner->QueryInterface(kIPluginTagInfoIID, getter_AddRefs(pti));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsPluginTagType tagType;
   rv = pti->GetTagType(&tagType);
-
-  if ((rv != NS_OK) || !((tagType == nsPluginTagType_Embed)
-                        || (tagType == nsPluginTagType_Applet)
-                        || (tagType == nsPluginTagType_Object))) {
+  if (NS_FAILED(rv)) {
     return rv;
   }
 
+  if (tagType != nsPluginTagType_Embed &&
+      tagType != nsPluginTagType_Applet &&
+      tagType != nsPluginTagType_Object) {
+    return NS_ERROR_FAILURE;
+  }
+
   // Security checks. Can't do security checks without a URI - hopefully the plugin
   // will take care of that.
   if (aURL) {
     nsCOMPtr<nsIScriptSecurityManager> secMan =
                     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     if (NS_FAILED(rv))
       return rv; // Better fail if we can't do security checks
 
     nsCOMPtr<nsIDocument> doc;
-    aOwner->GetDocument(getter_AddRefs(doc));
+    instanceOwner->GetDocument(getter_AddRefs(doc));
     if (!doc)
       return NS_ERROR_NULL_POINTER;
 
     rv = secMan->CheckLoadURIWithPrincipal(doc->NodePrincipal(), aURL, 0);
     if (NS_FAILED(rv))
       return rv;
 
     nsCOMPtr<nsIDOMElement> elem;
@@ -1055,107 +1069,128 @@ nsPluginHost::InstantiateEmbeddedPlugin(
       ToLowerCase(contractID);
       nsCOMPtr<nsIProtocolHandler> handler = do_GetService(contractID.get());
       if (handler)
         bCanHandleInternally = true;
   }
 
   // if we don't have a MIME type at this point, we still have one more chance by
   // opening the stream and seeing if the server hands one back
-  if (!aMimeType)
-    return bCanHandleInternally ? NewEmbeddedPluginStream(aURL, aOwner, nsnull) : NS_ERROR_FAILURE;
-
-  rv = SetUpPluginInstance(aMimeType, aURL, aOwner);
-
-  if (NS_FAILED(rv))
+  if (!aMimeType) {
+    if (bCanHandleInternally && !aContent->SrcStreamLoadInitiated()) {
+      NewEmbeddedPluginStream(aURL, aContent, nsnull);
+    }
     return NS_ERROR_FAILURE;
+  }
+
+  rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
+  if (NS_FAILED(rv)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsRefPtr<nsNPAPIPluginInstance> instance;
-  rv = aOwner->GetInstance(getter_AddRefs(instance));
-  // if we have a failure error, it means we found a plugin for the mimetype,
-  // but we had a problem with the entry point
-  if (rv == NS_ERROR_FAILURE)
+  rv = instanceOwner->GetInstance(getter_AddRefs(instance));
+  if (NS_FAILED(rv)) {
     return rv;
+  }
 
   if (instance) {
-    aOwner->CreateWidget();
+    instanceOwner->CreateWidget();
 
     // If we've got a native window, the let the plugin know about it.
-    aOwner->SetWindow();
+    instanceOwner->CallSetWindow();
 
     // create an initial stream with data
     // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
-    bool havedata = false;
-
-    nsCOMPtr<nsIPluginTagInfo> pti(do_QueryInterface(aOwner, &rv));
-
-    if (pti) {
-      const char *value;
-      havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
-      // no need to check for "data" as it would have been converted to "src"
+    // no need to check for "data" as it would have been converted to "src"
+    const char *value;
+    bool havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
+    if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoadInitiated()) {
+      NewEmbeddedPluginStream(aURL, nsnull, instance.get());
     }
-
-    if (havedata && !isJava && bCanHandleInternally)
-      rv = NewEmbeddedPluginStream(aURL, aOwner, instance.get());
   }
 
+  // At this point we consider instantiation to be successful. Do not return an error.
+  instanceOwner.forget(aOwner);
+
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec2;
   if (aURL != nsnull) aURL->GetAsciiSpec(urlSpec2);
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-        ("nsPluginHost::InstantiateEmbeddedPlugin Finished mime=%s, rv=%d, owner=%p, url=%s\n",
-        aMimeType, rv, aOwner, urlSpec2.get()));
+        ("nsPluginHost::InstantiateEmbeddedPlugin Finished mime=%s, rv=%d, url=%s\n",
+        aMimeType, rv, urlSpec2.get()));
 
   PR_LogFlush();
 #endif
 
-  return rv;
+  return NS_OK;
 }
 
 nsresult nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
                                                  nsIURI* aURI,
-                                                 nsIPluginInstanceOwner *aOwner,
+                                                 nsObjectLoadingContent *aContent,
+                                                 nsPluginInstanceOwner **aOwner,
                                                  nsIStreamListener **aStreamListener)
 {
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec;
   aURI->GetSpec(urlSpec);
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
-  ("nsPluginHost::InstantiateFullPagePlugin Begin mime=%s, owner=%p, url=%s\n",
-  aMimeType, aOwner, urlSpec.get()));
+  ("nsPluginHost::InstantiateFullPagePlugin Begin mime=%s, url=%s\n",
+  aMimeType, urlSpec.get()));
 #endif
 
-  nsresult rv = SetUpPluginInstance(aMimeType, aURI, aOwner);
-
-  if (NS_OK == rv) {
-    nsRefPtr<nsNPAPIPluginInstance> instance;
-    aOwner->GetInstance(getter_AddRefs(instance));
-
-    NPWindow* win = nsnull;
-    aOwner->GetWindow(win);
-
-    if (win && instance) {
-      aOwner->CreateWidget();
-
-      // If we've got a native window, the let the plugin know about it.
-      aOwner->SetWindow();
-
-      rv = NewFullPagePluginStream(aURI, instance.get(), aStreamListener);
-
-      // If we've got a native window, the let the plugin know about it.
-      aOwner->SetWindow();
-    }
+  nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
+  if (!instanceOwner) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
+  nsresult rv = instanceOwner->Init(ourContent);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = SetUpPluginInstance(aMimeType, aURI, instanceOwner);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsRefPtr<nsNPAPIPluginInstance> instance;
+  instanceOwner->GetInstance(getter_AddRefs(instance));
+  if (!instance) {
+    return NS_ERROR_FAILURE;
   }
 
+  NPWindow* win = nsnull;
+  instanceOwner->GetWindow(win);
+  if (!win) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Set up any widget that might be required.
+  instanceOwner->CreateWidget();
+  instanceOwner->CallSetWindow();
+
+  rv = NewFullPagePluginStream(aURI, instance.get(), aStreamListener);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Call SetWindow again in case something changed.
+  instanceOwner->CallSetWindow();
+
+  instanceOwner.forget(aOwner);
+
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
-  ("nsPluginHost::InstantiateFullPagePlugin End mime=%s, rv=%d, owner=%p, url=%s\n",
-  aMimeType, rv, aOwner, urlSpec.get()));
-
-  return rv;
+  ("nsPluginHost::InstantiateFullPagePlugin End mime=%s, rv=%d, url=%s\n",
+  aMimeType, rv, urlSpec.get()));
+
+  return NS_OK;
 }
 
 nsPluginTag*
 nsPluginHost::FindTagForLibrary(PRLibrary* aLibrary)
 {
   nsPluginTag* pluginTag;
   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     if (pluginTag->mLibrary == aLibrary) {
@@ -3260,17 +3295,17 @@ nsPluginHost::StopPluginInstance(nsNPAPI
     mInstances.RemoveElement(aInstance);
     OnPluginInstanceDestroyed(pluginTag);
   }
 
   return NS_OK;
 }
 
 nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
-                                                       nsIPluginInstanceOwner *aOwner,
+                                                       nsObjectLoadingContent *aContent,
                                                        nsNPAPIPluginInstance* aInstance,
                                                        nsIStreamListener** aListener)
 {
   if (!aURL)
     return NS_OK;
 
   nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
   if (!listener)
@@ -3278,41 +3313,45 @@ nsresult nsPluginHost::NewEmbeddedPlugin
 
   nsresult rv;
 
   // if we have an instance, everything has been set up
   // if we only have an owner, then we need to pass it in
   // so the listener can set up the instance later after
   // we've determined the mimetype of the stream
   if (aInstance)
-    rv = listener->InitializeEmbedded(aURL, aInstance);
-  else if (aOwner != nsnull)
-    rv = listener->InitializeEmbedded(aURL, nsnull, aOwner);
+    rv = listener->InitializeEmbedded(aURL, aInstance, nsnull);
+  else if (aContent)
+    rv = listener->InitializeEmbedded(aURL, nsnull, aContent);
   else
     rv = NS_ERROR_ILLEGAL_VALUE;
+
   if (NS_SUCCEEDED(rv))
     NS_ADDREF(*aListener = listener);
 
   return rv;
 }
 
 // Called by InstantiateEmbeddedPlugin()
 nsresult nsPluginHost::NewEmbeddedPluginStream(nsIURI* aURL,
-                                               nsIPluginInstanceOwner *aOwner,
+                                               nsObjectLoadingContent *aContent,
                                                nsNPAPIPluginInstance* aInstance)
 {
+  NS_ASSERTION(!aContent || !aInstance, "Don't pass both content and an instance to NewEmbeddedPluginStream!");
+
   nsCOMPtr<nsIStreamListener> listener;
-  nsresult rv = NewEmbeddedPluginStreamListener(aURL, aOwner, aInstance,
+  nsresult rv = NewEmbeddedPluginStreamListener(aURL, aContent, aInstance,
                                                 getter_AddRefs(listener));
   if (NS_SUCCEEDED(rv)) {
     nsCOMPtr<nsIDocument> doc;
     nsCOMPtr<nsILoadGroup> loadGroup;
-    if (aOwner) {
-      rv = aOwner->GetDocument(getter_AddRefs(doc));
-      if (NS_SUCCEEDED(rv) && doc) {
+    if (aContent) {
+      nsCOMPtr<nsIContent> aIContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
+      doc = aIContent->GetDocument();
+      if (doc) {
         loadGroup = doc->GetDocumentLoadGroup();
       }
     }
     nsCOMPtr<nsIChannel> channel;
     rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull, loadGroup, nsnull);
     if (NS_SUCCEEDED(rv)) {
       // if this is http channel, set referrer, some servers are configured
       // to reject requests without referrer set, see bug 157796
@@ -3716,22 +3755,16 @@ 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 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", 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
@@ -64,16 +64,18 @@
 #include "nsIIDNService.h"
 #include "nsCRT.h"
 
 class nsNPAPIPlugin;
 class nsIComponentManager;
 class nsIFile;
 class nsIChannel;
 class nsPluginNativeWindow;
+class nsObjectLoadingContent;
+class nsPluginInstanceOwner;
 
 #if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
 #define MAC_CARBON_PLUGINS
 #endif
 
 class nsInvalidPluginTag : public nsISupports
 {
 public:
@@ -107,17 +109,17 @@ public:
   NS_DECL_NSIPLUGINHOST
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
 
   nsresult Init();
   nsresult Destroy();
   nsresult LoadPlugins();
   nsresult InstantiatePluginForChannel(nsIChannel* aChannel,
-                                       nsIPluginInstanceOwner* aOwner,
+                                       nsObjectLoadingContent* aContent,
                                        nsIStreamListener** aListener);
   nsresult SetUpPluginInstance(const char *aMimeType,
                                nsIURI *aURL,
                                nsIPluginInstanceOwner *aOwner);
   nsresult IsPluginEnabledForType(const char* aMimeType);
   nsresult IsPluginEnabledForType(const char* aMimeType,
                                   bool aShouldPlay);
   nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
@@ -147,17 +149,16 @@ 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, bool isVisible);
   void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);
 
   nsresult GetPluginName(nsNPAPIPluginInstance *aPluginInstance, const char** aPluginName);
   nsresult StopPluginInstance(nsNPAPIPluginInstance* aInstance);
   nsresult HandleBadPlugin(PRLibrary* aLibrary, nsNPAPIPluginInstance *aInstance);
@@ -217,39 +218,41 @@ public:
   void DestroyRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag);
 
   // Return the tag for |aLibrary| if found, nsnull if not.
   nsPluginTag* FindTagForLibrary(PRLibrary* aLibrary);
 
   // The last argument should be false if we already have an in-flight stream
   // and don't need to set up a new stream.
   nsresult InstantiateEmbeddedPlugin(const char *aMimeType, nsIURI* aURL,
-                                     nsIPluginInstanceOwner* aOwner);
+                                     nsObjectLoadingContent *aContent,
+                                     nsPluginInstanceOwner** aOwner);
 
   nsresult InstantiateFullPagePlugin(const char *aMimeType,
                                      nsIURI* aURI,
-                                     nsIPluginInstanceOwner *aOwner,
+                                     nsObjectLoadingContent *aContent,
+                                     nsPluginInstanceOwner **aOwner,
                                      nsIStreamListener **aStreamListener);
 
   // Does not accept NULL and should never fail.
   nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin);
 
   nsresult GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin);
 
 private:
   nsresult
   TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner);
 
   nsresult
-  NewEmbeddedPluginStreamListener(nsIURI* aURL, nsIPluginInstanceOwner *aOwner,
+  NewEmbeddedPluginStreamListener(nsIURI* aURL, nsObjectLoadingContent *aContent,
                                   nsNPAPIPluginInstance* aInstance,
                                   nsIStreamListener** aListener);
 
   nsresult
-  NewEmbeddedPluginStream(nsIURI* aURL, nsIPluginInstanceOwner *aOwner, nsNPAPIPluginInstance* aInstance);
+  NewEmbeddedPluginStream(nsIURI* aURL, nsObjectLoadingContent *aContent, nsNPAPIPluginInstance* aInstance);
 
   nsresult
   NewFullPagePluginStream(nsIURI* aURI,
                           nsNPAPIPluginInstance *aInstance,
                           nsIStreamListener **aStreamListener);
 
   // Return an nsPluginTag for this type, if any.  If aCheckEnabled is
   // true, only enabled plugins will be returned.
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -89,19 +89,21 @@ using mozilla::DefaultXDisplay;
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsIAppShell.h"
 #include "nsIDOMHTMLAppletElement.h"
 #include "nsAttrName.h"
 #include "nsIFocusManager.h"
 #include "nsFocusManager.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIScrollableFrame.h"
+#include "nsIImageLoadingContent.h"
 
 #include "nsContentCID.h"
 #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
@@ -180,17 +182,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)->GetOwner();
+  nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetFrame();
   if (frame) {
     frame->UpdateImageLayer(aContainer, gfxRect(0,0,0,0));
   }
 }
 
 static void OnDestroyImage(void* aPluginInstanceOwner)
 {
   nsPluginInstanceOwner* owner = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner);
@@ -252,34 +254,47 @@ nsPluginInstanceOwner::EndUpdateBackgrou
     mInstance->EndUpdateBackground(aContext, &rect);
   }
 }
 
 bool
 nsPluginInstanceOwner::UseAsyncRendering()
 {
 #ifdef XP_MACOSX
-  nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
+  if (mUseAsyncRendering) {
+    return true;
+  }
+
+  nsRefPtr<ImageContainer> container;
+  if (mObjectFrame) {
+    container = mObjectFrame->GetImageContainer();
+  }
 #endif
 
   bool useAsyncRendering;
   bool result = (mInstance &&
           NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
           useAsyncRendering &&
 #ifdef XP_MACOSX
           container &&
           container->GetBackendType() == 
                   LayerManager::LAYERS_OPENGL
 #else
           (!mPluginWindow ||
            mPluginWindow->type == NPWindowTypeDrawable)
 #endif
           );
 
-    return result;
+#ifdef XP_MACOSX
+  if (result) {
+    mUseAsyncRendering = true;
+  }
+#endif
+
+  return result;
 }
 
 nsIntSize
 nsPluginInstanceOwner::GetCurrentImageSize()
 {
   nsIntSize size(0,0);
   if (mInstance) {
     mInstance->GetImageSize(&size);
@@ -287,24 +302,26 @@ 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);
-  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());  
-  if (pluginHost)
-    pluginHost->NewPluginNativeWindow(&mPluginWindow);
+  mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());  
+  if (mPluginHost)
+    mPluginHost->NewPluginNativeWindow(&mPluginWindow);
   else
     mPluginWindow = nsnull;
 
   mObjectFrame = nsnull;
+  mContent = nsnull;
   mTagText = nsnull;
+  mWidgetCreationComplete = false;
 #ifdef XP_MACOSX
   memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
 #ifndef NP_NO_QUICKDRAW
   memset(&mQDPluginPortCopy, 0, sizeof(NP_Port));
 #endif
   mInCGPaintLevel = 0;
   mSentInitialTopLevelWindowEvent = false;
   mColorProfile = nsnull;
@@ -313,24 +330,24 @@ nsPluginInstanceOwner::nsPluginInstanceO
   mContentFocused = false;
   mWidgetVisible = true;
   mPluginWindowVisible = false;
   mPluginDocumentActiveState = true;
   mNumCachedAttrs = 0;
   mNumCachedParams = 0;
   mCachedAttrParamNames = nsnull;
   mCachedAttrParamValues = nsnull;
-  mDestroyWidget = false;
 
 #ifdef XP_MACOSX
 #ifndef NP_NO_QUICKDRAW
   mEventModel = NPEventModelCarbon;
 #else
   mEventModel = NPEventModelCocoa;
 #endif
+  mUseAsyncRendering = false;
 #endif
 
   mWaitingForPaint = false;
 
 #ifdef MOZ_WIDGET_ANDROID
   mPluginViewAdded = false;
   mLastPluginRect = gfxRect(0, 0, 0, 0);
 #endif
@@ -375,23 +392,18 @@ nsPluginInstanceOwner::~nsPluginInstance
     mCachedAttrParamValues = nsnull;
   }
 
   if (mTagText) {
     NS_Free(mTagText);
     mTagText = 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;
-  }
+  PLUG_DeletePluginNativeWindow(mPluginWindow);
+  mPluginWindow = nsnull;
 
   if (mInstance) {
     mInstance->InvalidateOwner();
   }
 }
 
 NS_IMPL_ISUPPORTS3(nsPluginInstanceOwner,
                    nsIPluginInstanceOwner,
@@ -485,24 +497,39 @@ nsresult nsPluginInstanceOwner::GetInsta
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
                                             const char *aTarget,
                                             nsIInputStream *aPostStream,
                                             void *aHeadersData,
                                             PRUint32 aHeadersDataLen)
 {
-  NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(mContent, NS_ERROR_NULL_POINTER);
 
   if (mContent->IsEditable()) {
     return NS_OK;
   }
 
+  nsIDocument *doc = mContent->GetCurrentDoc();
+  if (!doc) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsIPresShell *presShell = doc->GetShell();
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsPresContext *presContext = presShell->GetPresContext();
+  if (!presContext) {
+    return NS_ERROR_FAILURE;
+  }
+
   // the container of the pres context will give us the link handler
-  nsCOMPtr<nsISupports> container = mObjectFrame->PresContext()->GetContainer();
+  nsCOMPtr<nsISupports> container = presContext->GetContainer();
   NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
   nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
   NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
 
   nsAutoString  unitarget;
   unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
 
   nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
@@ -740,22 +767,16 @@ NS_IMETHODIMP nsPluginInstanceOwner::Set
 #ifdef XP_MACOSX
   mEventModel = static_cast<NPEventModel>(eventModel);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
-NS_IMETHODIMP nsPluginInstanceOwner::SetWindow()
-{
-  NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
-  return mObjectFrame->CallSetWindow(false);
-}
-
 NPError nsPluginInstanceOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
 {
   if (!menu || !event)
     return NPERR_GENERIC_ERROR;
 
 #ifdef XP_MACOSX
   if (GetEventModel() != NPEventModelCocoa)
     return NPERR_INCOMPATIBLE_VERSION_ERROR;
@@ -1087,17 +1108,16 @@ 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;
@@ -1160,19 +1180,16 @@ 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;
   }
 
@@ -2725,85 +2742,30 @@ nsPluginInstanceOwner::Destroy()
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, true);
   mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, true);
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true);
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
   mContent->RemoveEventListener(NS_LITERAL_STRING("text"), this, true);
 #endif
 
   if (mWidget) {
+    if (mPluginWindow) {
+      mPluginWindow->SetPluginWidget(nsnull);
+    }
+
     nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
-    if (pluginWidget)
+    if (pluginWidget) {
       pluginWidget->SetPluginInstanceOwner(nsnull);
-
-    if (mDestroyWidget)
-      mWidget->Destroy();
+    }
+    mWidget->Destroy();
   }
 
   return NS_OK;
 }
 
-/*
- * Prepare to stop 
- */
-void
-nsPluginInstanceOwner::PrepareToStop(bool 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(false);
-    mWidget->Enable(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 = true;
-  }
-#endif
-
-#ifdef MOZ_WIDGET_ANDROID
-  RemovePluginView();
-#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;
  
@@ -3201,35 +3163,34 @@ void nsPluginInstanceOwner::StartTimer(b
 }
 
 void nsPluginInstanceOwner::CancelTimer()
 {
   mPluginHost->RemoveIdleTimeTarget(this);
 }
 #endif
 
-nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
-                                     nsObjectFrame* aFrame,
-                                     nsIContent*    aContent)
+nsresult nsPluginInstanceOwner::Init(nsIContent* aContent)
 {
   mLastEventloopNestingLevel = GetEventloopNestingLevel();
 
-  mObjectFrame = aFrame;
   mContent = aContent;
 
-  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;
+  // Get a frame, don't reflow. If a reflow was necessary it should have been
+  // done at a higher level than this (content).
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  nsIObjectFrame* iObjFrame = do_QueryFrame(frame);
+  nsObjectFrame* objFrame =  static_cast<nsObjectFrame*>(iObjFrame);
+  if (objFrame) {
+    SetFrame(objFrame);
+    // 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.
+    objFrame->PresContext()->EnsureVisible();
   }
 
   // register context menu listener
   mCXMenuListener = new nsPluginDOMContextMenuListener();
   if (mCXMenuListener) {    
     mCXMenuListener->Init(aContent);
   }
 
@@ -3262,26 +3223,16 @@ nsresult nsPluginInstanceOwner::Init(nsP
   mContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, true);
   mContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, true);
   mContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, true);
   mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, true);
   mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, true);
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
   mContent->AddEventListener(NS_LITERAL_STRING("text"), this, true);
 #endif
-  
-  // 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 !!!
 
@@ -3313,98 +3264,105 @@ void nsPluginInstanceOwner::ReleasePlugi
   }
 #endif
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
 {
   NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
 
-  nsresult  rv = NS_ERROR_FAILURE;
+    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;
+  }
+  
+  bool windowless = 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;
+    nsIDocument *doc = nsnull;
+    if (mContent) {
+      doc = mContent->OwnerDoc();
+      parentWidget = nsContentUtils::WidgetForDocument(doc);
+    }
+
+    mWidget = do_CreateInstance(kWidgetCID, &rv);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    nsWidgetInitData initData;
+    initData.mWindowType = eWindowType_plugin;
+    initData.mUnicode = false;
+    initData.clipChildren = true;
+    initData.clipSiblings = true;
+    rv = mWidget->Create(parentWidget.get(), nsnull, nsIntRect(0,0,0,0),
+                         nsnull, nsnull, &initData);
+    if (NS_FAILED(rv)) {
+      mWidget->Destroy();
+      mWidget = nsnull;
+      return rv;
+    }
+
+    mWidget->EnableDragDrop(true);
+    mWidget->Show(false);
+    mWidget->Enable(false);
+  }
 
   if (mObjectFrame) {
-    if (!mWidget) {
-      bool windowless = false;
-      mInstance->IsWindowless(&windowless);
-      nsIDocument *doc = mContent ? mContent->OwnerDoc() : nsnull;
-      // 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 (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;
+    // NULL widget is fine, will result in windowless setup.
+    mObjectFrame->PrepForDrawing(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;
 #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
-
-          // 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();
-
+  } else if (mWidget) {
+    // 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(true);
+    // start the idle timer.
+    StartTimer(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);
     }
   }
 
-  return rv;
-}
-
-void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
-{
-  mPluginHost = static_cast<nsPluginHost*>(aHost);
+  mWidgetCreationComplete = true;
+
+  return NS_OK;
 }
 
 // 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)
@@ -3500,31 +3458,41 @@ void* nsPluginInstanceOwner::FixUpPlugin
 
   // if the clip rect changed, call SetWindow()
   // (RealPlayer needs this to draw correctly)
   if (mPluginWindow->clipRect.left    != oldClipRect.left   ||
       mPluginWindow->clipRect.top     != oldClipRect.top    ||
       mPluginWindow->clipRect.right   != oldClipRect.right  ||
       mPluginWindow->clipRect.bottom  != oldClipRect.bottom)
   {
-    CallSetWindow();
+    if (UseAsyncRendering()) {
+      mInstance->AsyncSetWindow(mPluginWindow);
+    }
+    else {
+      mPluginWindow->CallSetWindow(mInstance);
+    }
     mPluginPortChanged = false;
 #ifdef MAC_CARBON_PLUGINS
     // if the clipRect is of size 0, make the null timer fire less often
     CancelTimer();
     if (mPluginWindow->clipRect.left == mPluginWindow->clipRect.right ||
         mPluginWindow->clipRect.top == mPluginWindow->clipRect.bottom) {
       StartTimer(false);
     }
     else {
       StartTimer(true);
     }
 #endif
   } else if (mPluginPortChanged) {
-    CallSetWindow();
+    if (UseAsyncRendering()) {
+      mInstance->AsyncSetWindow(mPluginWindow);
+    }
+    else {
+      mPluginWindow->CallSetWindow(mInstance);
+    }
     mPluginPortChanged = false;
   }
 
   // After the first NPP_SetWindow call we need to send an initial
   // top-level window focus event.
   if (eventModel == NPEventModelCocoa && !mSentInitialTopLevelWindowEvent) {
     // Set this before calling ProcessEvent to avoid endless recursion.
     mSentInitialTopLevelWindowEvent = true;
@@ -3556,17 +3524,17 @@ nsPluginInstanceOwner::HidePluginWindow(
 {
   if (!mPluginWindow || !mInstance) {
     return;
   }
 
   mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
   mPluginWindow->clipRect.right  = mPluginWindow->clipRect.left;
   mWidgetVisible = false;
-  if (mAsyncHidePluginWindow) {
+  if (UseAsyncRendering()) {
     mInstance->AsyncSetWindow(mPluginWindow);
   } else {
     mInstance->SetWindow(mPluginWindow);
   }
 }
 
 #else // XP_MACOSX
 
@@ -3626,29 +3594,108 @@ nsPluginInstanceOwner::UpdateWindowVisib
 void
 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
 {
   mPluginDocumentActiveState = aIsActive;
   UpdateWindowPositionAndClipRect(true);
 }
 #endif // XP_MACOSX
 
-void
+NS_IMETHODIMP
 nsPluginInstanceOwner::CallSetWindow()
 {
-  if (!mInstance)
+  if (mObjectFrame) {
+    mObjectFrame->CallSetWindow(false);
+  } else if (mInstance) {
+    if (UseAsyncRendering()) {
+      mInstance->AsyncSetWindow(mPluginWindow);
+    } else {
+      mInstance->SetWindow(mPluginWindow);
+    }
+  }
+
+  return NS_OK;
+}
+
+void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
+{
+  // Don't do anything if the frame situation hasn't changed.
+  if (mObjectFrame == aFrame) {
     return;
-
-  if (UseAsyncRendering()) {
-    mAsyncHidePluginWindow = true;
-    mInstance->AsyncSetWindow(mPluginWindow);
+  }
+
+  // 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 {
-    mAsyncHidePluginWindow = false;
-    mInstance->SetWindow(mPluginWindow);
+    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 PrepForDrawing on an object frame once. Don't do it here unless
+    // widget creation is complete. Doesn't matter if we actually have a widget.
+    if (mWidgetCreationComplete) {
+      mObjectFrame->PrepForDrawing(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")) {        
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -130,19 +130,17 @@ public:
   
   nsresult MouseDown(nsIDOMEvent* aKeyEvent);
   nsresult KeyPress(nsIDOMEvent* aKeyEvent);
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
   nsresult Text(nsIDOMEvent* aTextEvent);
 #endif
 
   nsresult Destroy();  
-  
-  void PrepareToStop(bool 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) || defined(ANDROID)
   void Paint(gfxContext* aContext,
@@ -159,24 +157,21 @@ public:
   void SendIdleEvent();
   
   // nsIScrollPositionListener interface
   virtual void ScrollPositionWillChange(nscoord aX, nscoord aY);
   virtual void ScrollPositionDidChange(nscoord aX, nscoord aY);
   
   //locals
   
-  nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
-                nsIContent* aContent);
+  nsresult Init(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();
   bool IsRemoteDrawingCoreAnimation();
   NPEventModel GetEventModel();
@@ -205,26 +200,20 @@ public:
   // CoreGraphics drawing model).
   void BeginCGPaint();
   void EndCGPaint();
 #else // XP_MACOSX
   void UpdateWindowPositionAndClipRect(bool aSetWindow);
   void UpdateWindowVisibility(bool aVisible);
   void UpdateDocumentActiveState(bool aIsActive);
 #endif // XP_MACOSX
-  void CallSetWindow();
-  
-  void SetOwner(nsObjectFrame *aOwner)
-  {
-    mObjectFrame = aOwner;
-  }
-  nsObjectFrame* GetOwner() {
-    return mObjectFrame;
-  }
-  
+
+  void SetFrame(nsObjectFrame *aFrame);
+  nsObjectFrame* GetFrame();
+
   PRUint32 GetLastEventloopNestingLevel() const {
     return mLastEventloopNestingLevel; 
   }
   
   static PRUint32 GetEventloopNestingLevel();
   
   void ConsiderNewEventloopNestingLevel() {
     PRUint32 currentLevel = GetEventloopNestingLevel();
@@ -313,20 +302,21 @@ private:
   bool AddPluginView(const gfxRect& aRect);
   void RemovePluginView();
   bool mPluginViewAdded;
   gfxRect mLastPluginRect;
 #endif 
  
   nsPluginNativeWindow       *mPluginWindow;
   nsRefPtr<nsNPAPIPluginInstance> mInstance;
-  nsObjectFrame              *mObjectFrame; // owns nsPluginInstanceOwner
-  nsCOMPtr<nsIContent>        mContent;
+  nsObjectFrame              *mObjectFrame;
+  nsIContent                 *mContent; // WEAK, content owns us
   nsCString                   mDocumentBase;
   char                       *mTagText;
+  bool                        mWidgetCreationComplete;
   nsCOMPtr<nsIWidget>         mWidget;
   nsRefPtr<nsPluginHost>      mPluginHost;
   
 #ifdef XP_MACOSX
   NP_CGContext                              mCGPluginPortCopy;
 #ifndef NP_NO_QUICKDRAW
   NP_Port                                   mQDPluginPortCopy;
 #endif
@@ -352,27 +342,29 @@ private:
   bool                        mPluginPortChanged;
 #endif
 #ifdef MOZ_X11
   // Used with windowless plugins only, initialized in CreateWidget().
   bool                        mFlash10Quirks;
 #endif
   bool                        mPluginWindowVisible;
   bool                        mPluginDocumentActiveState;
-  
-  // If true, destroy the widget on destruction. Used when plugin stop
-  // is being delayed to a safer point in time.
-  bool                        mDestroyWidget;
+
   PRUint16          mNumCachedAttrs;
   PRUint16          mNumCachedParams;
   char              **mCachedAttrParamNames;
   char              **mCachedAttrParamValues;
   
 #ifdef XP_MACOSX
   NPEventModel mEventModel;
+  // This is a hack! UseAsyncRendering() can incorrectly return false
+  // when we don't have an object frame (possible as of bug 90268).
+  // We hack around this by always returning true if we've ever
+  // returned true.
+  bool mUseAsyncRendering;
 #endif
   
   // pointer to wrapper for nsIDOMContextMenuListener
   nsRefPtr<nsPluginDOMContextMenuListener> mCXMenuListener;
   
   nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
   nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
   nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -381,17 +381,17 @@ nsresult nsPluginStreamListenerPeer::Ini
 
 /* Called by NewEmbeddedPluginStream() - if this is called, we weren't
  * able to load the plugin, so we need to load it later once we figure
  * out the mimetype.  In order to load it later, we need the plugin
  * instance owner.
  */
 nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
                                                         nsNPAPIPluginInstance* aInstance,
-                                                        nsIPluginInstanceOwner *aOwner)
+                                                        nsObjectLoadingContent *aContent)
 {
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec;
   aURL->GetSpec(urlSpec);
   
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
          ("nsPluginStreamListenerPeer::InitializeEmbedded url=%s\n", urlSpec.get()));
   
@@ -399,17 +399,17 @@ nsresult nsPluginStreamListenerPeer::Ini
 #endif
   
   mURL = aURL;
   
   if (aInstance) {
     NS_ASSERTION(mPluginInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbedded mPluginInstance != nsnull");
     mPluginInstance = aInstance;
   } else {
-    mOwner = aOwner;
+    mContent = aContent;
   }
   
   mPendingRequests = 1;
   
   mDataForwardToRequest = new nsHashtable(16, false);
   if (!mDataForwardToRequest)
     return NS_ERROR_FAILURE;
   
@@ -572,27 +572,16 @@ nsPluginStreamListenerPeer::OnStartReque
 
       if (!bWantsAllNetworkStreams) {
         mRequestFailed = true;
         return NS_ERROR_FAILURE;
       }
     }
   }
   
-  // do a little sanity check to make sure our frame isn't gone
-  // by getting the tag type and checking for an error, we can determine if
-  // the frame is gone
-  if (mOwner) {
-    nsCOMPtr<nsIPluginTagInfo> pti = do_QueryInterface(mOwner);
-    NS_ENSURE_TRUE(pti, NS_ERROR_FAILURE);
-    nsPluginTagType tagType;
-    if (NS_FAILED(pti->GetTagType(&tagType)))
-      return NS_ERROR_FAILURE;  // something happened to our object frame, so bail!
-  }
-  
   // Get the notification callbacks from the channel and save it as
   // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
   // we'll create channel for byte range request.
   nsCOMPtr<nsIInterfaceRequestor> callbacks;
   channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
   if (callbacks)
     mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);
   
@@ -637,47 +626,31 @@ nsPluginStreamListenerPeer::OnStartReque
   
 #ifdef PLUGIN_LOGGING
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
          ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
           this, request, aContentType.get(), mURLSpec.get()));
   
   PR_LogFlush();
 #endif
-  
-  NPWindow* window = nsnull;
-  
-  // if we don't have an nsNPAPIPluginInstance (mPluginInstance), it means
-  // we weren't able to load a plugin previously because we
-  // didn't have the mimetype.  Now that we do (aContentType),
-  // we'll try again with SetUpPluginInstance()
-  // which is called by InstantiateEmbeddedPlugin()
-  // NOTE: we don't want to try again if we didn't get the MIME type this time
-  
-  if (!mPluginInstance && mOwner && !aContentType.IsEmpty()) {
-    nsRefPtr<nsNPAPIPluginInstance> pluginInstRefPtr;
-    mOwner->GetInstance(getter_AddRefs(pluginInstRefPtr));
-    mPluginInstance = pluginInstRefPtr.get();
 
-    mOwner->GetWindow(window);
-    if (!mPluginInstance && window) {
-      nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
-      rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
-      if (NS_SUCCEEDED(rv)) {
-        mOwner->GetInstance(getter_AddRefs(pluginInstRefPtr));
-        mPluginInstance = pluginInstRefPtr.get();
-        if (mPluginInstance) {
-          mOwner->CreateWidget();
-          // If we've got a native window, the let the plugin know about it.
-          mOwner->SetWindow();
-        }
+  // If we don't have an instance yet it means we weren't able to load
+  // a plugin previously because we didn't have the mimetype. Try again
+  // if we have a mime type now.
+  if (!mPluginInstance && mContent && !aContentType.IsEmpty()) {
+    nsObjectLoadingContent *olc = static_cast<nsObjectLoadingContent*>(mContent.get());
+    rv = olc->InstantiatePluginInstance(aContentType.get(), aURL.get());
+    if (NS_SUCCEEDED(rv)) {
+      rv = olc->GetPluginInstance(getter_AddRefs(mPluginInstance));
+      if (NS_FAILED(rv)) {
+        return rv;
       }
     }
   }
-  
+
   // Set up the stream listener...
   rv = SetUpStreamListener(request, aURL);
   if (NS_FAILED(rv)) return rv;
   
   return rv;
 }
 
 NS_IMETHODIMP nsPluginStreamListenerPeer::OnProgress(nsIRequest *request,
@@ -864,17 +837,17 @@ nsresult nsPluginStreamListenerPeer::Ser
     // Should call GetPluginPort() here.
     // This part is copied from nsPluginInstanceOwner::GetPluginPort(). 
     nsCOMPtr<nsIWidget> widget;
     ((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
     if (widget) {
       window->window = widget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
     }
 #endif
-    owner->SetWindow();
+    owner->CallSetWindow();
   }
   
   mSeekable = false;
   mPStreamListener->OnStartBinding(this);
   mStreamOffset = 0;
   
   // force the plugin to use stream as file
   mStreamType = NP_ASFILE;
--- a/dom/plugins/base/nsPluginStreamListenerPeer.h
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.h
@@ -47,16 +47,17 @@
 #include "nsIProgressEventSink.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsWeakReference.h"
 #include "nsNPAPIPluginStreamListener.h"
 #include "nsHashtable.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
+#include "nsObjectLoadingContent.h"
 
 class nsIChannel;
 
 /**
  * When a plugin requests opens multiple requests to the same URL and
  * the request must be satified by saving a file to disk, each stream
  * listener holds a reference to the backing file: the file is only removed
  * when all the listeners are done.
@@ -108,34 +109,34 @@ public:
   
   // Called by GetURL and PostURL (via NewStream)
   nsresult Initialize(nsIURI *aURL,
                       nsNPAPIPluginInstance *aInstance,
                       nsIPluginStreamListener *aListener);
   
   nsresult InitializeEmbedded(nsIURI *aURL,
                               nsNPAPIPluginInstance* aInstance,
-                              nsIPluginInstanceOwner *aOwner = nsnull);
+                              nsObjectLoadingContent *aContent);
   
   nsresult InitializeFullPage(nsIURI* aURL, nsNPAPIPluginInstance *aInstance);
 
   nsresult OnFileAvailable(nsIFile* aFile);
   
   nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
   
   nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; }
   
 private:
   nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
   nsresult SetupPluginCacheFile(nsIChannel* channel);
   nsresult GetInterfaceGlobal(const nsIID& aIID, void** result);
 
   nsCOMPtr<nsIURI> mURL;
   nsCString mURLSpec; // Have to keep this member because GetURL hands out char*
-  nsCOMPtr<nsIPluginInstanceOwner> mOwner;
+  nsCOMPtr<nsIObjectLoadingContent> mContent;
   nsRefPtr<nsNPAPIPluginStreamListener> mPStreamListener;
 
   // Set to true if we request failed (like with a HTTP response of 404)
   bool                    mRequestFailed;
   
   /*
    * Set to true after nsIPluginStreamListener::OnStartBinding() has
    * been called.  Checked in ::OnStopRequest so we can call the
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -100,16 +100,20 @@ include $(topsrcdir)/config/rules.mk
   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_NPNVdocumentOrigin.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)
@@ -124,16 +128,17 @@ 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 \
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_re-parent-windowed.html
@@ -0,0 +1,59 @@
+<!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>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_re-parent.html
@@ -0,0 +1,86 @@
+<!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="runTests()">
+  <p id="display"></p>
+
+  <div id="div1">
+    <!-- This embed has to have a "src" attribute. Part of this test involves seeing if we
+         properly restart plugins that have been added back to a document without a change
+         in URL. Not re-loading an object when the URL hasn't changed is a shortcut used for
+         some object types. Without a URL, this won't be tested. -->
+    <embed id="plugin1" src="loremipsum.txt" type="application/x-test" width="200" height="200"></embed>
+  </div>
+  <div id="div2">
+  </div>
+
+  <script type="application/javascript;version=1.8">
+  SimpleTest.waitForExplicitFinish();
+
+  var exceptionThrown = false;
+  var p = document.getElementById('plugin1');
+  var d1 = document.getElementById('div1');
+  var d2 = document.getElementById('div2');
+
+  var destroyed = false;
+  function onDestroy() {
+    destroyed = true;
+  }
+
+  function testsFinished() {
+    p.stopWatchingInstanceCount();
+    SimpleTest.finish();
+  }
+
+  function continueTests2() {
+    try {
+      is(p.getInstanceCount(), 1, "One new instance should have been created at this point.");
+    } catch (e) {
+      exceptionThrown = true;
+    }
+    is(exceptionThrown, false, "Testing for exception getting instance count from plugin.");
+
+    testsFinished();
+  }
+
+  function continueTests1() {
+    // Adding to the document will kick off the plugin load. Need to have a timeout
+    // before we can safely call into it.
+    d2.appendChild(p);
+    setTimeout('continueTests2();', 0);
+  }
+
+  function runTests() {
+    // First tests involve moving the instance from one div to another.
+    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.");
+
+    // Now remove the instance from the document and let it die.
+    d2.removeChild(p);
+    setTimeout('continueTests1();', 0);
+  }
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_unparent1.html
@@ -0,0 +1,41 @@
+<!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>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_unparent2.html
@@ -0,0 +1,50 @@
+<!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>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_unparent3.html
@@ -0,0 +1,44 @@
+<!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/dom/plugins/test/reftest/reftest.list
+++ b/dom/plugins/test/reftest/reftest.list
@@ -2,18 +2,19 @@
 random-if(!haveTestPlugin) != plugin-sanity.html about:blank
 fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
 fails-if(!haveTestPlugin) == plugin-alpha-zindex.html div-alpha-zindex.html
 fails-if(!haveTestPlugin) == plugin-alpha-opacity.html div-alpha-opacity.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html # bug 629430
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html # bug 629430
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) skip-if(Android) == border-padding-3.html border-padding-3-ref.html # bug 629430
-random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367
-random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html
+# The following two "pluginproblemui-direction" tests are unreliable on all platforms. They should be re-written or replaced.
+#random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367
+#random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html
 fails-if(!haveTestPlugin) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
 fails-if(!haveTestPlugin) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-1-step.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-2-step.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-5-step.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-10-step.html plugin-background-ref.html
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7272,20 +7272,19 @@ nsresult
 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
 {
   return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
 }
 
 static void
 FreezeElement(nsIContent *aContent, void * /* unused */)
 {
-  nsIFrame *frame = aContent->GetPrimaryFrame();
-  nsIObjectFrame *objectFrame = do_QueryFrame(frame);
-  if (objectFrame) {
-    objectFrame->StopPlugin();
+  nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
+  if (olc) {
+    olc->StopPluginInstance();
   }
 }
 
 static bool
 FreezeSubDocument(nsIDocument *aDocument, void *aData)
 {
   nsIPresShell *shell = aDocument->GetShell();
   if (shell)
@@ -7353,20 +7352,19 @@ PresShell::FireOrClearDelayedEvents(bool
       mDelayedEvents.Clear();
     }
   }
 }
 
 static void
 ThawElement(nsIContent *aContent, void *aShell)
 {
-  nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(aContent));
-  if (objlc) {
-    nsRefPtr<nsNPAPIPluginInstance> inst;
-    objlc->EnsureInstantiation(getter_AddRefs(inst));
+  nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
+  if (olc) {
+    olc->AsyncStartPluginInstance();
   }
 }
 
 static bool
 ThawSubDocument(nsIDocument *aDocument, void *aData)
 {
   nsIPresShell *shell = aDocument->GetShell();
   if (shell)
--- a/layout/generic/nsIObjectFrame.h
+++ b/layout/generic/nsIObjectFrame.h
@@ -50,52 +50,16 @@ 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
@@ -318,57 +318,43 @@ 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)
 {
-  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(true);
-
-  // StopPluginInternal might have disowned the widget; if it has,
-  // mWidget will be null.
-  if (mWidget) {
-    mInnerView->DetachWidgetEventHandler(mWidget);
-    mWidget->Destroy();
-  }
+  // 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();
 
   if (mBackgroundSink) {
     mBackgroundSink->Destroy();
   }
 
+  SetInstanceOwner(nsnull);
+
   nsObjectFrameSuper::DestroyFrom(aDestructRoot);
 }
 
 /* virtual */ void
 nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   if (HasView()) {
     nsIView* view = GetView();
@@ -393,40 +379,31 @@ nsObjectFrame::GetType() const
 NS_IMETHODIMP
 nsObjectFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
 }
 #endif
 
 nsresult
-nsObjectFrame::CreateWidget(nscoord aWidth,
-                            nscoord aHeight,
-                            bool    aViewOnly)
+nsObjectFrame::PrepForDrawing(nsIWidget *aWidget)
 {
+  mWidget = aWidget;
+
   nsIView* view = GetView();
   NS_ASSERTION(view, "Object frames must have views");  
   if (!view) {
-    return NS_OK;       //XXX why OK? MMP
-  }
-
-  bool needsWidget = !aViewOnly;
-  bool canCreateWidget = !nsIWidget::UsePuppetWidgets();
-  if (needsWidget && !canCreateWidget) {
-    NS_WARNING("Can't use native widgets, and can't hand a plugins a PuppetWidget");
+    return NS_ERROR_FAILURE;
   }
 
   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);
 
@@ -434,72 +411,61 @@ nsObjectFrame::CreateWidget(nscoord aWid
   viewMan->ResizeView(view, r);
   viewMan->MoveViewTo(view, origin.x, origin.y);
 
   nsRootPresContext* rpc = PresContext()->GetRootPresContext();
   if (!rpc) {
     return NS_ERROR_FAILURE;
   }
 
-  if (needsWidget && !mWidget && canCreateWidget) {
+  if (mWidget) {
     // 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, true);
 
-    nsresult rv;
-    mWidget = do_CreateInstance(kWidgetCID, &rv);
-    if (NS_FAILED(rv))
-      return rv;
+    mWidget->SetParent(parentWidget);
+    mWidget->Show(true);
+    mWidget->Enable(true);
 
-    nsWidgetInitData initData;
-    initData.mWindowType = eWindowType_plugin;
-    initData.mUnicode = false;
-    initData.clipChildren = true;
-    initData.clipSiblings = 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.
+    // 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));
     EVENT_CALLBACK eventHandler = mInnerView->AttachWidgetEventHandler(mWidget);
-    rv = mWidget->Create(parentWidget, nsnull, nsIntRect(0,0,0,0),
-                         eventHandler, dx, &initData);
-    if (NS_FAILED(rv)) {
-      mWidget->Destroy();
-      mWidget = nsnull;
-      return rv;
-    }
-
-    mWidget->EnableDragDrop(true);
+    mWidget->SetEventCallback(eventHandler, dx);
 
-    // 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.
+#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.
     if (parentWidget == GetNearestWidget()) {
-      mWidget->Show(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()) {
@@ -520,27 +486,37 @@ nsObjectFrame::CreateWidget(nscoord aWid
     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);
   }
 
-  return (needsWidget && !canCreateWidget) ? NS_ERROR_NOT_AVAILABLE : NS_OK;
+#ifdef ACCESSIBILITY
+  nsAccessibilityService* accService = nsIPresShell::AccService();
+  if (accService) {
+    accService->RecreateAccessible(PresContext()->PresShell(), mContent);
+  }
+#endif
+
+  return NS_OK;
 }
 
 #define EMBED_DEF_WIDTH 240
 #define EMBED_DEF_HEIGHT 200
 
 /* virtual */ nscoord
 nsObjectFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
 {
@@ -689,61 +665,16 @@ nsObjectFrame::ReflowFinished()
 }
 
 void
 nsObjectFrame::ReflowCallbackCanceled()
 {
   mReflowCallbackPosted = false;
 }
 
-nsresult
-nsObjectFrame::InstantiatePlugin(nsPluginHost* aPluginHost, 
-                                 const char* aMimeType,
-                                 nsIURI* aURI)
-{
-  SAMPLE_LABEL("nsObjectFrame", "InstantiatePlugin");
-  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->OwnerDoc();
-  nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
-  bool fullPageMode = 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;
 
@@ -843,16 +774,50 @@ nsObjectFrame::CallSetWindow(bool aCheck
     rv = window->CallSetWindow(pi);
   }
 
   instanceOwnerRef->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->Show(false);
+          mWidget->Enable(false);
+          mWidget->SetParent(nsnull);
+        }
+      } else {
+#ifndef XP_MACOSX
+        rpc->UnregisterPluginForGeometryUpdates(this);
+#endif
+      }
+    }
+  }
+}
+
 bool
 nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
 {
   if (aTabIndex)
     *aTabIndex = -1;
   return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
 }
 
@@ -2125,414 +2090,21 @@ nsObjectFrame::HandlePress(nsPresContext
 }
 #endif
 
 nsresult
 nsObjectFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
 {
   *aPluginInstance = nsnull;
 
-  if (!mInstanceOwner)
-    return NS_OK;
-  
-  return mInstanceOwner->GetInstance(aPluginInstance);
-}
-
-nsresult
-nsObjectFrame::PrepareInstanceOwner()
-{
-  nsWeakFrame weakFrame(this);
-
-  // First, have to stop any possibly running plugins.
-  StopPluginInternal(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)
-{
-  SAMPLE_LABEL("plugin", "nsObjectFrame::Instantiate");
-  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 = true;
-  rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
-
-  if (!weakFrame.IsAlive()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  NS_ASSERTION(mPreventInstantiation,
-               "Instantiation should still be prevented!");
-  mPreventInstantiation = 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)
-{
-  SAMPLE_LABEL("plugin", "nsObjectFrame::Instantiate");
-  PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
-         ("nsObjectFrame::Instantiate(%s) called on frame %p\n", aMimeType,
-          this));
-
-  if (mPreventInstantiation) {
+  if (!mInstanceOwner) {
     return NS_OK;
   }
 
-  // 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 = 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 = 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 bool
-DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop)
-{
-#if (MOZ_PLATFORM_MAEMO==5)
-  // Don't delay stop on Maemo/Hildon (bug 530739).
-  if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
-    return 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 true;
-  }
-  return false;
-}
-
-static void
-DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop)
-{
-  SAMPLE_LABEL("plugin", "DoStopPlugin");
-  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()
-{
-  SAMPLE_LABEL("plugin", "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, false);
-
-  return NS_OK;
-}
-
-void
-nsObjectFrame::StopPlugin()
-{
-  bool delayedStop = 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(bool 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();
-
-  bool oldVal = mPreventInstantiation;
-  mPreventInstantiation = 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);
+  return mInstanceOwner->GetInstance(aPluginInstance);
 }
 
 NS_IMETHODIMP
 nsObjectFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor)
 {
   if (!mInstanceOwner) {
     return NS_ERROR_FAILURE;
   }
@@ -2556,53 +2128,16 @@ nsObjectFrame::SetIsDocumentActive(bool 
 {
 #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 = 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,20 +35,16 @@
  *
  * ***** 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"
@@ -119,30 +115,19 @@ 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(bool 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(bool 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
   // as a Configuration record to aConfigurations.
@@ -158,17 +143,17 @@ public:
 #ifdef ACCESSIBILITY
   virtual already_AddRefed<nsAccessible> CreateAccessible();
 #ifdef XP_WIN
   NS_IMETHOD GetPluginPort(HWND *aPort);
 #endif
 #endif
 
   //local methods
-  nsresult CreateWidget(nscoord aWidth, nscoord aHeight, bool aViewOnly);
+  nsresult PrepForDrawing(nsIWidget *aWidget);
 
   // for a given aRoot, this walks the frame tree looking for the next outFrame
   static nsIObjectFrame* GetNextObjectFrame(nsPresContext* aPresContext,
                                             nsIFrame* aRoot);
 
   // nsIReflowCallback
   virtual bool ReflowFinished();
   virtual void ReflowCallbackCanceled();
@@ -204,69 +189,59 @@ 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(bool aCheckIsHidden = 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(bool aCheckIsHidden = true);
-
   bool IsFocusable(PRInt32 *aTabIndex = nsnull, bool aWithMouse = false);
 
   // check attributes and optionally CSS to see if we should display anything
   bool IsHidden(bool aCheckVisibilityStyle = true) const;
 
   bool IsOpaque() const;
   bool IsTransparentMode() const;
 
-  void NotifyContentObjectWrapper();
-
   nsIntPoint GetWindowOriginInPixels(bool 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.
    */
@@ -286,32 +261,27 @@ private:
   public:
     PluginEventNotifier(const nsString &aEventType) : 
       mEventType(aEventType) {}
     
     NS_IMETHOD Run();
   private:
     nsString mEventType;
   };
-  
-  nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
+
+  nsPluginInstanceOwner*          mInstanceOwner; // WEAK
   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.
-  bool mPreventInstantiation;
-
   bool 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,17 +152,22 @@ 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)
 {
-  NS_ASSERTION(inView, "Must have a native view to convert coordinates.");
+  // 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 false;
+  }
 
   // Caller has to want a result.
   if (!destX && !destY)
     return false;
 
   if (sourceSpace == destSpace) {
     if (destX)
       *destX = sourceX;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -113,18 +113,19 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #endif
 
 #define NS_IWIDGET_IID \
-  { 0xba20ac65, 0xb2a6, 0x4052, \
-    { 0xa4, 0xcb, 0x65, 0x40, 0xf8, 0x87, 0x9c, 0x55 } }
+  { 0x3fa36ce2, 0x472d, 0x4bff, \
+    { 0xb1, 0xe4, 0xc3, 0xe3, 0x19, 0x24, 0xa1, 0xe4 } }
+
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
 #define NS_STYLE_WINDOW_SHADOW_MENU             2
@@ -474,16 +475,24 @@ class nsIWidget : public nsISupports {
     virtual already_AddRefed<nsIWidget>
     CreateChild(const nsIntRect  &aRect,
                 EVENT_CALLBACK   aHandleEventFunction,
                 nsDeviceContext  *aContext,
                 nsWidgetInitData *aInitData = nsnull,
                 bool             aForceUseIWidgetParent = false) = 0;
 
     /**
+     * Set the event callback for a widget. If a device context is not
+     * provided then the existing device context will remain, it will
+     * not be nulled out.
+     */
+    NS_IMETHOD SetEventCallback(EVENT_CALLBACK aEventFunction,
+                                nsDeviceContext *aContext) = 0;
+
+    /**
      * Attach to a top level widget. 
      *
      * In cases where a top level chrome widget is being used as a content
      * container, attach a secondary event callback and update the device
      * context. The primary event callback will continue to be called, so the
      * owning base window will continue to function.
      *
      * aViewEventFunction Event callback that will receive mirrored
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -257,16 +257,33 @@ nsBaseWidget::CreateChild(const nsIntRec
                                   aHandleEventFunction,
                                   aContext, aInitData))) {
     return widget.forget();
   }
 
   return nsnull;
 }
 
+NS_IMETHODIMP
+nsBaseWidget::SetEventCallback(EVENT_CALLBACK aEventFunction,
+                               nsDeviceContext *aContext)
+{
+  NS_ASSERTION(aEventFunction, "Must have valid event callback!");
+
+  mEventCallback = aEventFunction;
+
+  if (aContext) {
+    NS_IF_RELEASE(mContext);
+    mContext = aContext;
+    NS_ADDREF(mContext);
+  }
+
+  return NS_OK;
+}
+
 // Attach a view to our widget which we'll send events to. 
 NS_IMETHODIMP
 nsBaseWidget::AttachViewToTopLevel(EVENT_CALLBACK aViewEventFunction,
                                    nsDeviceContext *aContext)
 {
   NS_ASSERTION((mWindowType == eWindowType_toplevel ||
                 mWindowType == eWindowType_dialog ||
                 mWindowType == eWindowType_invisible ||
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -174,16 +174,17 @@ public:
   NS_IMETHOD              OnDefaultButtonLoaded(const nsIntRect &aButtonRect) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta, bool aIsHorizontal, PRInt32 &aOverriddenDelta);
   virtual already_AddRefed<nsIWidget>
   CreateChild(const nsIntRect  &aRect,
               EVENT_CALLBACK   aHandleEventFunction,
               nsDeviceContext *aContext,
               nsWidgetInitData *aInitData = nsnull,
               bool             aForceUseIWidgetParent = false);
+  NS_IMETHOD              SetEventCallback(EVENT_CALLBACK aEventFunction, nsDeviceContext *aContext);
   NS_IMETHOD              AttachViewToTopLevel(EVENT_CALLBACK aViewEventFunction, nsDeviceContext *aContext);
   virtual ViewWrapper*    GetAttachedViewPtr();
   NS_IMETHOD              SetAttachedViewPtr(ViewWrapper* aViewWrapper);
   NS_IMETHOD              RegisterTouchWindow();
   NS_IMETHOD              UnregisterTouchWindow();
 
   nsPopupLevel PopupLevel() { return mPopupLevel; }