Bug 615417. Postpone AsyncSetWindow processing until we're not in the middle of painting the plugin. r=bsmedberg a=pavlov
authorRobert O'Callahan <robert@ocallahan.org>
Sun, 05 Dec 2010 21:57:33 +0000
changeset 58646 2a6dd48ee44c31bae041fc891ef690d6245073d3
parent 58645 43dd46547be61bb5acd4930ffbde5d46ae215396
child 58647 d0b7c821c18ae9671a47992e0e40d7742545224b
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbsmedberg, pavlov
bugs615417
milestone2.0b8pre
Bug 615417. Postpone AsyncSetWindow processing until we're not in the middle of painting the plugin. r=bsmedberg a=pavlov
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginInstanceChild.h
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -137,16 +137,17 @@ PluginInstanceChild::PluginInstanceChild
     , mDrawingModel(NPDrawingModelCoreGraphics)
     , mCurrentEvent(nsnull)
 #endif
     , mLayersRendering(false)
     , mAccumulatedInvalidRect(0,0,0,0)
     , mIsTransparent(false)
     , mSurfaceType(gfxASurface::SurfaceTypeMax)
     , mCurrentInvalidateTask(nsnull)
+    , mCurrentAsyncSetWindowTask(nsnull)
     , mPendingPluginCall(false)
     , mDoAlphaExtraction(false)
     , mSurfaceDifferenceRect(0,0,0,0)
 #ifdef MOZ_X11
     , mFlash10Quirks(false)
 #endif
 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
     , mMaemoImageRendering(PR_FALSE)
@@ -809,16 +810,19 @@ PluginInstanceChild::AnswerNPP_HandleEve
     NS_RUNTIMEABORT("NPP_HandleEvent_IOSurface is a OSX-only message");
     return false;
 }
 #endif
 
 bool
 PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
 {
+    NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
+                 "Shouldn't be receiving WindowPosChanged with layer rendering");
+
 #ifdef OS_WIN
     int16_t dontcare;
     return AnswerNPP_HandleEvent(event, &dontcare);
 #else
     NS_RUNTIMEABORT("WindowPosChanged is a windows-only message");
     return false;
 #endif
 }
@@ -857,16 +861,18 @@ XVisualIDToInfo(Display* aDisplay, Visua
 bool
 PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
 {
     PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
                       FULLFUNCTION,
                       aWindow.window,
                       aWindow.x, aWindow.y,
                       aWindow.width, aWindow.height));
+    NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
+                 "Shouldn't be receiving NPP_SetWindow with layer rendering");
     AssertPluginThread();
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     // The minimum info is sent over IPC to allow this
     // code to determine the rest.
 
     mWindow.window = reinterpret_cast<void*>(aWindow.window);
     mWindow.x = aWindow.x;
@@ -876,18 +882,16 @@ PluginInstanceChild::AnswerNPP_SetWindow
     mWindow.clipRect = aWindow.clipRect;
     mWindow.type = aWindow.type;
 
     mWsInfo.colormap = aWindow.colormap;
     if (!XVisualIDToInfo(mWsInfo.display, aWindow.visualID,
                          &mWsInfo.visual, &mWsInfo.depth))
         return false;
 
-    mLayersRendering = false;
-
 #ifdef MOZ_WIDGET_GTK2
     if (gtk_check_version(2,18,7) != NULL) { // older
         if (aWindow.type == NPWindowTypeWindow) {
             GdkWindow* socket_window = gdk_window_lookup(aWindow.window);
             if (socket_window) {
                 // A GdkWindow for the socket already exists.  Need to
                 // workaround https://bugzilla.gnome.org/show_bug.cgi?id=607061
                 // See wrap_gtk_plug_embedded in PluginModuleChild.cpp.
@@ -2163,16 +2167,53 @@ PluginInstanceChild::NPN_NewStream(NPMIM
 bool
 PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
                                         const NPRemoteWindow& aWindow)
 {
     AssertPluginThread();
 
     NS_ASSERTION(!aWindow.window, "Remote window should be null.");
 
+    if (mCurrentAsyncSetWindowTask) {
+        mCurrentAsyncSetWindowTask->Cancel();
+        mCurrentAsyncSetWindowTask = nsnull;
+    }
+
+    if (mPendingPluginCall) {
+        // We shouldn't process this now. Run it later.
+        mCurrentAsyncSetWindowTask =
+            NewRunnableMethod<PluginInstanceChild,
+                              void (PluginInstanceChild::*)(const gfxSurfaceType&, const NPRemoteWindow&, bool),
+                              gfxSurfaceType, NPRemoteWindow, bool>
+                (this, &PluginInstanceChild::DoAsyncSetWindow,
+                 aSurfaceType, aWindow, true);
+        MessageLoop::current()->PostTask(FROM_HERE, mCurrentAsyncSetWindowTask);
+    } else {
+        DoAsyncSetWindow(aSurfaceType, aWindow, false);
+    }
+
+    return true;
+}
+
+void
+PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
+                                      const NPRemoteWindow& aWindow,
+                                      bool aIsAsync)
+{
+    AssertPluginThread();
+    NS_ASSERTION(!aWindow.window, "Remote window should be null.");
+    NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!");
+
+    if (aIsAsync) {
+        if (!mCurrentAsyncSetWindowTask) {
+            return;
+        }
+        mCurrentAsyncSetWindowTask = nsnull;
+    }
+
     mWindow.window = NULL;
     if (mWindow.width != aWindow.width || mWindow.height != aWindow.height) {
         mCurrentSurface = nsnull;
         mHelperSurface = nsnull;
         mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
     }
     if (mWindow.clipRect.top != aWindow.clipRect.top ||
         mWindow.clipRect.left != aWindow.clipRect.left ||
@@ -2199,18 +2240,16 @@ PluginInstanceChild::RecvAsyncSetWindow(
         CreateWinlessPopupSurrogate();
     if (mQuirks & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
         SetupFlashMsgThrottle();
 #endif
 
     if (!mAccumulatedInvalidRect.IsEmpty()) {
         AsyncShowPluginFrame();
     }
-
-    return true;
 }
 
 static inline gfxRect
 GfxFromNsRect(const nsIntRect& aRect)
 {
     return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
 }
 
@@ -2958,16 +2997,20 @@ PluginInstanceChild::AnswerNPP_Destroy(N
         mPendingAsyncCalls.TruncateLength(0);
     }
 
     mTimers.Clear();
     if (mCurrentInvalidateTask) {
         mCurrentInvalidateTask->Cancel();
         mCurrentInvalidateTask = nsnull;
     }
+    if (mCurrentAsyncSetWindowTask) {
+        mCurrentAsyncSetWindowTask->Cancel();
+        mCurrentAsyncSetWindowTask = nsnull;
+    }
 
     PluginModuleChild::current()->NPP_Destroy(this);
     mData.ndata = 0;
 
     mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
     mDeletingHash->Init();
     PluginModuleChild::current()->FindNPObjectsForInstance(this);
 
--- a/dom/plugins/PluginInstanceChild.h
+++ b/dom/plugins/PluginInstanceChild.h
@@ -98,16 +98,21 @@ protected:
     virtual bool
     AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, const uint32_t& surface, int16_t* handled);
 
     // Async rendering
     virtual bool
     RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
                        const NPRemoteWindow& aWindow);
 
+    virtual void
+    DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
+                     const NPRemoteWindow& aWindow,
+                     bool aIsAsync);
+
     NS_OVERRIDE
     virtual bool
     AnswerPaint(const NPRemoteEvent& event, int16_t* handled)
     {
         PaintTracker pt;
         return AnswerNPP_HandleEvent(event, handled);
     }
 
@@ -490,16 +495,19 @@ private:
     bool mIsTransparent;
 
     // Surface type optimized of parent process
     gfxSurfaceType mSurfaceType;
 
     // Keep InvalidateRect task pointer to be able Cancel it on Destroy
     CancelableTask *mCurrentInvalidateTask;
 
+    // Keep AsyncSetWindow task pointer to be able to Cancel it on Destroy
+    CancelableTask *mCurrentAsyncSetWindowTask;
+
     // True while plugin-child in plugin call
     // Use to prevent plugin paint re-enter
     bool mPendingPluginCall;
 
     // On some platforms, plugins may not support rendering to a surface with
     // alpha, or not support rendering to an image surface.
     // In those cases we need to draw to a temporary platform surface; we cache
     // that surface here.