Bug 1467363: Protect access to mTransparentSurface with a lock. r=rhunt
authorBas Schouten <bschouten@mozilla.com>
Thu, 21 Jun 2018 22:17:48 +0200
changeset 809870 98bac674e9bc6346b4d3253771e98846782dbeeb
parent 809869 9253a827f52d262efee2f659095d38cf0b44fd0f
child 809871 0c2fc5ab4511f9f2c0a9dc7c4606ad8911daec8b
push id113833
push userbmo:ato@sny.no
push dateSat, 23 Jun 2018 12:17:51 +0000
reviewersrhunt
bugs1467363
milestone62.0a1
Bug 1467363: Protect access to mTransparentSurface with a lock. r=rhunt MozReview-Commit-ID: 6E9YpDIcuQk
widget/windows/WinCompositorWidget.cpp
widget/windows/WinCompositorWidget.h
widget/windows/nsWindowGfx.cpp
--- a/widget/windows/WinCompositorWidget.cpp
+++ b/widget/windows/WinCompositorWidget.cpp
@@ -14,23 +14,25 @@
 #include "WinCompositorWindowThread.h"
 
 #include <ddraw.h>
 
 namespace mozilla {
 namespace widget {
 
 using namespace mozilla::gfx;
+using namespace mozilla;
 
 WinCompositorWidget::WinCompositorWidget(const WinCompositorWidgetInitData& aInitData,
                                          const layers::CompositorOptions& aOptions)
  : CompositorWidget(aOptions)
  , mWidgetKey(aInitData.widgetKey()),
    mWnd(reinterpret_cast<HWND>(aInitData.hWnd())),
    mCompositorWnd(nullptr),
+   mTransparentSurfaceLock("mTransparentSurfaceLock"),
    mTransparencyMode(aInitData.transparencyMode()),
    mMemoryDC(nullptr),
    mCompositeDC(nullptr),
    mLockedBackBufferData(nullptr)
 {
   MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
 
   // mNotDeferEndRemoteDrawing is set on the main thread during init,
@@ -43,16 +45,17 @@ WinCompositorWidget::WinCompositorWidget
 WinCompositorWidget::~WinCompositorWidget()
 {
   DestroyCompositorWindow();
 }
 
 void
 WinCompositorWidget::OnDestroyWindow()
 {
+  MutexAutoLock lock(mTransparentSurfaceLock);
   mTransparentSurface = nullptr;
   mMemoryDC = nullptr;
 }
 
 bool
 WinCompositorWidget::PreRender(WidgetRenderingContext* aContext)
 {
   // This can block waiting for WM_SETTEXT to finish
@@ -79,16 +82,18 @@ WinCompositorWidget::GetClientSize()
   return LayoutDeviceIntSize(
     r.right - r.left,
     r.bottom - r.top);
 }
 
 already_AddRefed<gfx::DrawTarget>
 WinCompositorWidget::StartRemoteDrawing()
 {
+  MutexAutoLock lock(mTransparentSurfaceLock);
+
   MOZ_ASSERT(!mCompositeDC);
 
   RefPtr<gfxASurface> surf;
   if (mTransparencyMode == eTransparencyTransparent) {
     surf = EnsureTransparentSurface();
   }
 
   // Must call this after EnsureTransparentSurface(), since it could update
@@ -239,57 +244,61 @@ void
 WinCompositorWidget::LeavePresentLock()
 {
   mPresentLock.Leave();
 }
 
 RefPtr<gfxASurface>
 WinCompositorWidget::EnsureTransparentSurface()
 {
+  mTransparentSurfaceLock.AssertCurrentThreadOwns();
   MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
 
   IntSize size = GetClientSize().ToUnknownSize();
   if (!mTransparentSurface || mTransparentSurface->GetSize() != size) {
     mTransparentSurface = nullptr;
     mMemoryDC = nullptr;
     CreateTransparentSurface(size);
   }
 
   RefPtr<gfxASurface> surface = mTransparentSurface;
   return surface.forget();
 }
 
 void
 WinCompositorWidget::CreateTransparentSurface(const gfx::IntSize& aSize)
 {
+  mTransparentSurfaceLock.AssertCurrentThreadOwns();
   MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
   RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(aSize, SurfaceFormat::A8R8G8B8_UINT32);
   mTransparentSurface = surface;
   mMemoryDC = surface->GetDC();
 }
 
 void
 WinCompositorWidget::UpdateTransparency(nsTransparencyMode aMode)
 {
+  MutexAutoLock lock(mTransparentSurfaceLock);
   if (mTransparencyMode == aMode) {
     return;
   }
 
   mTransparencyMode = aMode;
   mTransparentSurface = nullptr;
   mMemoryDC = nullptr;
 
   if (mTransparencyMode == eTransparencyTransparent) {
     EnsureTransparentSurface();
   }
 }
 
 void
 WinCompositorWidget::ClearTransparentWindow()
 {
+  MutexAutoLock lock(mTransparentSurfaceLock);
   if (!mTransparentSurface) {
     return;
   }
 
   EnsureTransparentSurface();
 
   IntSize size = mTransparentSurface->GetSize();
   if (!size.IsEmpty()) {
--- a/widget/windows/WinCompositorWidget.h
+++ b/widget/windows/WinCompositorWidget.h
@@ -5,16 +5,17 @@
 
 #ifndef widget_windows_WinCompositorWidget_h
 #define widget_windows_WinCompositorWidget_h
 
 #include "CompositorWidget.h"
 #include "gfxASurface.h"
 #include "mozilla/gfx/CriticalSection.h"
 #include "mozilla/gfx/Point.h"
+#include "mozilla/Mutex.h"
 #include "nsIWidget.h"
 
 class nsWindow;
 
 namespace mozilla {
 namespace widget {
 
 class PlatformCompositorWidgetDelegate
@@ -101,16 +102,18 @@ public:
   HWND GetCompositorHwnd() const {
     return mCompositorWnd;
   }
 
   void EnsureCompositorWindow();
   void DestroyCompositorWindow();
   void UpdateCompositorWndSizeIfNecessary();
 
+  mozilla::Mutex& GetTransparentSurfaceLock() { return mTransparentSurfaceLock; }
+
 protected:
 
 private:
   HDC GetWindowSurface();
   void FreeWindowSurface(HDC dc);
 
   void CreateTransparentSurface(const gfx::IntSize& aSize);
 
@@ -119,16 +122,17 @@ private:
   HWND mWnd;
 
   HWND mCompositorWnd;
   LayoutDeviceIntSize mLastCompositorWndSize;
 
   gfx::CriticalSection mPresentLock;
 
   // Transparency handling.
+  mozilla::Mutex mTransparentSurfaceLock;
   nsTransparencyMode mTransparencyMode;
   RefPtr<gfxASurface> mTransparentSurface;
   HDC mMemoryDC;
   HDC mCompositeDC;
 
   // Locked back buffer of BasicCompositor
   uint8_t* mLockedBackBufferData;
 
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -320,16 +320,18 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
     switch (GetLayerManager()->GetBackendType()) {
       case LayersBackend::LAYERS_BASIC:
         {
           RefPtr<gfxASurface> targetSurface;
 
 #if defined(MOZ_XUL)
           // don't support transparency for non-GDI rendering, for now
           if (eTransparencyTransparent == mTransparencyMode) {
+            // This mutex needs to be held when EnsureTransparentSurface is called.
+            MutexAutoLock lock(mBasicLayersSurface->GetTransparentSurfaceLock());
             targetSurface = mBasicLayersSurface->EnsureTransparentSurface();
           }
 #endif
 
           RefPtr<gfxWindowsSurface> targetSurfaceWin;
           if (!targetSurface)
           {
             uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 :