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 85844 15b00ab7f22d745ef331d89e766a261c770fd1d3
parent 85843 b506d48ef7aa28b66ca63d8dc8e5d8ce075fa73d
child 85845 1410782d557d170b081db3f847599b976462eabe
push idunknown
push userunknown
push dateunknown
reviewersroc, bsmedberg
bugs90268
milestone13.0a1
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; }