Flush layout before starting to pump data into plug-ins if we started the data
authorbzbarsky@mit.edu
Thu, 02 Aug 2007 10:54:36 -0700
changeset 4164 81977eb555a1ab6a8a0db9f7f5e277dc1af32487
parent 4163 49ae8a12c5fb58b9b4430a371c69b856a21b1b35
child 4165 6302937dbcdb96a93ecc13efe3ec6320d110bd43
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs381512
milestone1.9a7pre
Flush layout before starting to pump data into plug-ins if we started the data load ourselves. Fixes various issues with a number of plug-ins that expect NPP_SetWindow() to have been called before NPP_WriteReady or NPP_Write. Bug 381512, r=biesi, sr=jst
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/html/document/src/nsPluginDocument.cpp
layout/generic/nsObjectFrame.cpp
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -123,17 +123,17 @@ nsAsyncInstantiateEvent::Run()
   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 - GetFrame() only returns object frames, and that means we're
   // a plugin)
   // Also make sure that we still refer to the same data.
-  if (mContent->GetFrame() == mFrame &&
+  if (mContent->GetFrame(PR_FALSE) == mFrame &&
       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",
@@ -450,17 +450,17 @@ nsObjectLoadingContent::OnStartRequest(n
     case eType_Plugin:
       mInstantiating = PR_TRUE;
       if (mType != newType) {
         // This can go away once plugin loading moves to content (bug 90268)
         mType = newType;
         notifier.Notify();
       }
       nsIObjectFrame* frame;
-      frame = GetFrame();
+      frame = GetFrame(PR_TRUE);
       if (!frame) {
         // Do nothing in this case: This is probably due to a display:none
         // frame. If we ever get a frame, HasNewFrame will do the right thing.
         // Abort the load though, we have no use for the data.
         mInstantiating = PR_FALSE;
         return NS_BINDING_ABORTED;
       }
       rv = frame->Instantiate(chan, getter_AddRefs(mFinalListener));
@@ -572,17 +572,17 @@ nsObjectLoadingContent::EnsureInstantiat
   // Must set our out parameter to null as we have various early returns with
   // an NS_OK result.
   *aInstance = nsnull;
 
   if (mType != eType_Plugin) {
     return NS_OK;
   }
 
-  nsIObjectFrame* frame = GetFrame();
+  nsIObjectFrame* frame = GetFrame(PR_FALSE);
   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 {
@@ -609,17 +609,17 @@ nsObjectLoadingContent::EnsureInstantiat
     nsPresShellIterator iter(doc);
     nsCOMPtr<nsIPresShell> shell;
     while ((shell = iter.GetNextShell())) {
       shell->RecreateFramesFor(thisContent);
     }
 
     mInstantiating = PR_FALSE;
 
-    frame = GetFrame();
+    frame = GetFrame(PR_FALSE);
     if (!frame) {
       return NS_OK;
     }
   }
 
   // We may have a plugin instance already; if so, do nothing
   nsresult rv = frame->GetPluginInstance(*aInstance);
   if (!*aInstance) {
@@ -1364,17 +1364,17 @@ nsObjectLoadingContent::GetObjectBaseURI
                                               thisContent->GetOwnerDoc(),
                                               baseURI);
   } else {
     baseURI.swap(*aURI);
   }
 }
 
 nsIObjectFrame*
-nsObjectLoadingContent::GetFrame()
+nsObjectLoadingContent::GetFrame(PRBool aFlushLayout)
 {
   nsCOMPtr<nsIContent> thisContent = 
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   NS_ASSERTION(thisContent, "must be a content");
 
   PRBool flushed = PR_FALSE;
   nsIFrame* frame;
   do {
@@ -1394,30 +1394,32 @@ nsObjectLoadingContent::GetFrame()
     }
 
     if (flushed) {
       break;
     }
     
     // OK, let's flush out and try again.  Note that we want to reget
     // the document, etc, since flushing might run script.
-    doc->FlushPendingNotifications(Flush_ContentAndNotify);
+    mozFlushType flushType =
+      aFlushLayout ? Flush_Layout : Flush_ContentAndNotify;
+    doc->FlushPendingNotifications(flushType);
 
     flushed = PR_TRUE;
   } while (1);
 
   nsIObjectFrame* objFrame;
   CallQueryInterface(frame, &objFrame);
   return objFrame;
 }
 
 nsresult
 nsObjectLoadingContent::Instantiate(const nsACString& aMIMEType, nsIURI* aURI)
 {
-  nsIObjectFrame* frame = GetFrame();
+  nsIObjectFrame* frame = GetFrame(PR_FALSE);
   if (!frame) {
     LOG(("OBJLC [%p]: Attempted to instantiate, but have no frame\n", this));
     return NS_OK; // Not a failure to have no frame
   }
 
   nsCString typeToUse(aMIMEType);
   if (typeToUse.IsEmpty() && aURI) {
     IsPluginEnabledByExtension(aURI, typeToUse);
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -272,19 +272,22 @@ 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.
+     * presentation 0.  If aFlushLayout is true, this function will
+     * flush layout before trying to get the frame.  This is needed
+     * in some cases by plug-ins to ensure that NPP_SetWindow() gets
+     * called (from nsObjectFrame::DidReflow).
      */
-    nsIObjectFrame* GetFrame();
+    nsIObjectFrame* GetFrame(PRBool aFlushLayout);
 
     /**
      * 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.
      */
     nsresult Instantiate(const nsACString& aMIMEType, nsIURI* aURI);
 
--- a/content/html/document/src/nsPluginDocument.cpp
+++ b/content/html/document/src/nsPluginDocument.cpp
@@ -91,25 +91,30 @@ class nsPluginStreamListener : public ns
 NS_IMETHODIMP
 nsPluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
 {
   nsresult rv = nsMediaDocumentStreamListener::OnStartRequest(request, ctxt);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  nsIContent* embed = mPluginDoc->GetPluginContent();
+  nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent();
 
   // Now we have a frame for our <embed>, start the load
   nsIPresShell* shell = mDocument->GetPrimaryShell();
   if (!shell) {
     // Can't instantiate w/o a shell
     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 = shell->GetPrimaryFrameFor(embed);
   if (!frame) {
     return rv;
   }
 
   nsIObjectFrame* objFrame;
   CallQueryInterface(frame, &objFrame);
   if (!objFrame) {
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -962,17 +962,17 @@ nsObjectFrame::DidReflow(nsPresContext* 
   }
   else
 #endif
   {
     window->window = mInstanceOwner->GetPluginPort();
   }
 
   // this will call pi->SetWindow and take care of window subclassing
-  // if needed, see bug 132759
+  // if needed, see bug 132759.
   window->CallSetWindow(pi);
 
   mInstanceOwner->ReleasePluginPort((nsPluginPort *)window->window);
 
   return rv;
 }
 
 static void PaintPrintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,