Bug 1157784 - Avoid compositing at the same time as WM_SETTEXT. r=bas, f=jimm, a=sledru
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 13 May 2015 16:05:35 -0400
changeset 274637 2ee7143aea47039d586e864e9ea2858212656421
parent 274636 add2083dc0ffccb44b0bf91d5157f390efd1a1ff
child 274638 869b7584d26d274475127e2cc5808e63286fe8c6
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, sledru
bugs1157784
milestone40.0a2
Bug 1157784 - Avoid compositing at the same time as WM_SETTEXT. r=bas, f=jimm, a=sledru The innards of Windows don't always recheck that the window is visible and it will forget to redraw if we Present at the same time that the window is invisible.
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -399,16 +399,18 @@ nsWindow::nsWindow() : nsWindowBase()
 
     Preferences::AddBoolVarCache(&gIsPointerEventsEnabled,
                                  "dom.w3c_pointer_events.enabled",
                                  gIsPointerEventsEnabled);
   } // !sInstanceCount
 
   mIdleService = nullptr;
 
+  ::InitializeCriticalSection(&mPresentLock);
+
   sInstanceCount++;
 }
 
 nsWindow::~nsWindow()
 {
   mInDtor = true;
 
   // If the widget was released without calling Destroy() then the native window still
@@ -434,16 +436,17 @@ nsWindow::~nsWindow()
     IMEHandler::Terminate();
     NS_IF_RELEASE(sCursorImgContainer);
     if (sIsOleInitialized) {
       ::OleFlushClipboard();
       ::OleUninitialize();
       sIsOleInitialized = FALSE;
     }
   }
+  ::DeleteCriticalSection(&mPresentLock);
 
   NS_IF_RELEASE(mNativeDragTarget);
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
 
 /**************************************************************
  *
@@ -4679,22 +4682,29 @@ nsWindow::ProcessMessage(UINT msg, WPARA
        */
 
       if (!mCustomNonClient || mNonClientMargins.top == -1)
         break;
 
       {
         // From msdn, the way around this is to disable the visible state
         // temporarily. We need the text to be set but we don't want the
-        // redraw to occur.
+        // redraw to occur. However, we need to make sure that we don't
+        // do this at the same time that a Present is happening.
+        //
+        // To do this we take mPresentLock in nsWindow::PreRender and
+        // if that lock is taken we wait before doing WM_SETTEXT
+        EnterCriticalSection(&mPresentLock);
         DWORD style = GetWindowLong(mWnd, GWL_STYLE);
         SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE);
         *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd,
                                      msg, wParam, lParam);
         SetWindowLong(mWnd, GWL_STYLE, style);
+        LeaveCriticalSection(&mPresentLock);
+
         return true;
       }
 
     case WM_NCACTIVATE:
     {
       /*
        * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
        * through WM_NCPAINT via InvalidateNonClientRegion.
@@ -7533,16 +7543,31 @@ void nsWindow::PickerClosed()
   if (!mPickerDisplayCount)
     return;
   mPickerDisplayCount--;
   if (!mPickerDisplayCount && mDestroyCalled) {
     Destroy();
   }
 }
 
+bool nsWindow::PreRender(LayerManagerComposite*)
+{
+  // This can block waiting for WM_SETTEXT to finish
+  // Using PreRender is unnecessarily pessimistic because
+  // we technically only need to block during the present call
+  // not all of compositor rendering
+  EnterCriticalSection(&mPresentLock);
+  return true;
+}
+
+void nsWindow::PostRender(LayerManagerComposite*)
+{
+  LeaveCriticalSection(&mPresentLock);
+}
+
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: ChildWindow impl.
  **
  ** Child window overrides.
  **
  **************************************************************
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -445,16 +445,18 @@ protected:
   virtual nsresult        SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
                                               bool aIntersectWithExisting) override;
   nsIntRegion             GetRegionToPaint(bool aForceFullRepaint, 
                                            PAINTSTRUCT ps, HDC aDC);
   static void             ActivateOtherWindowHelper(HWND aWnd);
   void                    ClearCachedResources();
   nsIWidgetListener*      GetPaintListener();
   static bool             IsRenderMode(gfxWindowsPlatform::RenderMode aMode);
+  virtual bool            PreRender(LayerManagerComposite*) override;
+  virtual void            PostRender(LayerManagerComposite*) override;
 
 protected:
   nsCOMPtr<nsIWidget>   mParent;
   nsIntSize             mLastSize;
   nsIntPoint            mLastPoint;
   HWND                  mWnd;
   WNDPROC               mPrevWndProc;
   HBRUSH                mBrush;
@@ -578,16 +580,18 @@ protected:
 
   // For converting native event times to timestamps we record the time of the
   // first received event in each time scale.
   static DWORD     sFirstEventTime;
   static TimeStamp sFirstEventTimeStamp;
 
   static bool sNeedsToInitMouseWheelSettings;
   static void InitMouseWheelScrollData();
+
+  CRITICAL_SECTION mPresentLock;
 };
 
 /**
  * A child window is a window with different style.
  */
 class ChildWindow : public nsWindow {
 
 public: