Bug 1157784. Avoid compositing at the same time as WM_SETTEXT. f=jimm
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 13 May 2015 16:05:35 -0400
changeset 243755 82ddfd3ddce00175739c74cdf32863886c8abc50
parent 243754 7fcf6bf43eda78d42b098cc2b24c032ebd29b34e
child 243756 83152f78784a73268cb4532c9fb6f49f3a2c2ecb
push id28753
push userkwierso@gmail.com
push dateThu, 14 May 2015 22:33:43 +0000
treeherdermozilla-central@07e2e15703cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1157784
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1157784. Avoid compositing at the same time as WM_SETTEXT. f=jimm 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
@@ -4696,22 +4698,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.
@@ -7551,16 +7560,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
@@ -446,16 +446,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;
@@ -582,16 +584,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: