Bug 1261752. Part 3. r=mats
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 10 May 2016 22:58:47 -0500
changeset 335920 433c854c4bb5d5ee4820f4622d16b7e9840ccab3
parent 335919 ed485cc76a622813190f3da12d27f79032bdbade
child 335921 df02e8e8e169d16c030a2c8c1419528ef6b3ea81
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs1261752
milestone49.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 1261752. Part 3. r=mats
layout/forms/nsComboboxControlFrame.cpp
view/nsViewManager.cpp
widget/PuppetWidget.cpp
widget/cocoa/nsChildView.mm
widget/gonk/nsWindow.cpp
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/qt/nsWindow.cpp
widget/qt/nsWindow.h
widget/windows/nsWindowGfx.cpp
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -1477,17 +1477,21 @@ nsComboboxControlFrame::Rollup(uint32_t 
   if (weakFrame.IsAlive()) {
     mListControlFrame->CaptureMouseEvents(false);
   }
 
   if (aFlush && weakFrame.IsAlive()) {
     // The popup's visibility doesn't update until the minimize animation has
     // finished, so call UpdateWidgetGeometry to update it right away.
     nsViewManager* viewManager = mDropdownFrame->GetView()->GetViewManager();
-    viewManager->UpdateWidgetGeometry();
+    viewManager->UpdateWidgetGeometry(); // might destroy us
+  }
+
+  if (!weakFrame.IsAlive()) {
+    return consume;
   }
 
   if (aLastRolledUp) {
     *aLastRolledUp = GetContent();
   }
   return consume;
 }
 
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -703,25 +703,26 @@ void nsViewManager::InvalidateViews(nsVi
   while (nullptr != childView)  {
     childView->GetViewManager()->InvalidateViews(childView);
     childView = childView->GetNextSibling();
   }
 }
 
 void nsViewManager::WillPaintWindow(nsIWidget* aWidget)
 {
-  if (aWidget) {
-    nsView* view = nsView::GetViewFor(aWidget);
-    LayerManager *manager = aWidget->GetLayerManager();
+  RefPtr<nsIWidget> widget(aWidget);
+  if (widget) {
+    nsView* view = nsView::GetViewFor(widget);
+    LayerManager* manager = widget->GetLayerManager();
     if (view &&
         (view->ForcedRepaint() || !manager->NeedsWidgetInvalidation())) {
       ProcessPendingUpdates();
       // Re-get the view pointer here since the ProcessPendingUpdates might have
       // destroyed it during CallWillPaintOnObservers.
-      view = nsView::GetViewFor(aWidget);
+      view = nsView::GetViewFor(widget);
       if (view) {
         view->SetForcedRepaint(false);
       }
     }
   }
 
   nsCOMPtr<nsIPresShell> shell = mPresShell;
   if (shell) {
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -1025,16 +1025,18 @@ PuppetWidget::Paint()
     return NS_OK;
 
   LayoutDeviceIntRegion region = mDirtyRegion;
 
   // reset repaint tracking
   mDirtyRegion.SetEmpty();
   mPaintTask.Revoke();
 
+  RefPtr<PuppetWidget> strongThis(this);
+
   GetCurrentWidgetListener()->WillPaintWindow(this);
 
   if (GetCurrentWidgetListener()) {
 #ifdef DEBUG
     debug_DumpPaintEvent(stderr, this, region.ToUnknownRegion(),
                          "PuppetWidget", 0);
 #endif
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -3981,16 +3981,18 @@ NSEvent* gLastDragMouseDownEvent = nil;
     NSNumber* pointer = (NSNumber*) [aWidgetArray objectAtIndex:i];
     nsIWidget* widget = (nsIWidget*) [pointer unsignedIntegerValue];
     NS_RELEASE(widget);
   }
 }
 
 - (void)viewWillDraw
 {
+  nsAutoRetainCocoaObject kungFuDeathGrip(self);
+
   if (mGeckoChild) {
     // The OS normally *will* draw our NSWindow, no matter what we do here.
     // But Gecko can delete our parent widget(s) (along with mGeckoChild)
     // while processing a paint request, which closes our NSWindow and
     // makes the OS throw an NSInternalInconsistencyException assertion when
     // it tries to draw it.  Sometimes the OS also aborts the browser process.
     // So we need to retain our parent(s) here and not release it/them until
     // the next time through the main thread's run loop.  When we do this we
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -100,35 +100,35 @@ nsWindow::DoDraw(void)
     RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen();
     const nsTArray<nsWindow*>& windows = screen->GetTopWindows();
 
     if (windows.IsEmpty()) {
         LOG("  no window to draw, bailing");
         return;
     }
 
-    nsWindow *targetWindow = (nsWindow *)windows[0];
+    RefPtr<nsWindow> targetWindow = (nsWindow *)windows[0];
     while (targetWindow->GetLastChild()) {
         targetWindow = (nsWindow *)targetWindow->GetLastChild();
     }
 
     nsIWidgetListener* listener = targetWindow->GetWidgetListener();
     if (listener) {
         listener->WillPaintWindow(targetWindow);
     }
 
-    LayerManager* lm = targetWindow->GetLayerManager();
-    if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
-        // No need to do anything, the compositor will handle drawing
-    } else {
-        NS_RUNTIMEABORT("Unexpected layer manager type");
-    }
-
     listener = targetWindow->GetWidgetListener();
     if (listener) {
+        LayerManager* lm = targetWindow->GetLayerManager();
+        if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
+            // No need to do anything, the compositor will handle drawing
+        } else {
+            NS_RUNTIMEABORT("Unexpected layer manager type");
+        }
+
         listener->DidPaintWindow();
     }
 }
 
 void
 nsWindow::ConfigureAPZControllerThread()
 {
     APZThreadUtils::SetControllerThread(CompositorBridgeParent::CompositorLoop());
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -547,26 +547,31 @@ nsWindow::DispatchResized()
 void
 nsWindow::MaybeDispatchResized()
 {
     if (mNeedsDispatchResized && !mIsDestroyed) {
         DispatchResized();
     }
 }
 
+nsIWidgetListener*
+nsWindow::GetListener()
+{
+    return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+}
+
 nsresult
 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
     debug_DumpEvent(stdout, aEvent->mWidget, aEvent,
                     "something", 0);
 #endif
     aStatus = nsEventStatus_eIgnore;
-    nsIWidgetListener* listener =
-        mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+    nsIWidgetListener* listener = GetListener();
     if (listener) {
       aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
     }
 
     return NS_OK;
 }
 
 void
@@ -2114,18 +2119,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
     if (mIsDestroyed) {
         return FALSE;
     }
 
     // Windows that are not visible will be painted after they become visible.
     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
         return FALSE;
 
-    nsIWidgetListener *listener =
-        mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+    nsIWidgetListener *listener = GetListener();
     if (!listener)
         return FALSE;
 
     LayoutDeviceIntRegion exposeRegion;
 #if (MOZ_WIDGET_GTK == 2)
     if (!ExtractExposeRegion(exposeRegion, aEvent)) {
 #else
     if (!ExtractExposeRegion(exposeRegion, cr)) {
@@ -2144,30 +2148,31 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 
     if (clientLayers && mCompositorBridgeParent) {
         // We need to paint to the screen even if nothing changed, since if we
         // don't have a compositing window manager, our pixels could be stale.
         clientLayers->SetNeedsComposite(true);
         clientLayers->SendInvalidRegion(region.ToUnknownRegion());
     }
 
+    RefPtr<nsWindow> strongThis(this);
+
     // Dispatch WillPaintWindow notification to allow scripts etc. to run
     // before we paint
     {
         listener->WillPaintWindow(this);
 
         // If the window has been destroyed during the will paint notification,
         // there is nothing left to do.
         if (!mGdkWindow)
             return TRUE;
 
         // Re-get the listener since the will paint notification might have
         // killed it.
-        listener =
-            mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+        listener = GetListener();
         if (!listener)
             return FALSE;
     }
 
     if (clientLayers && mCompositorBridgeParent && clientLayers->NeedsComposite()) {
         mCompositorBridgeParent->ScheduleRenderOnCompositorThread();
         clientLayers->SetNeedsComposite(false);
     }
@@ -2218,16 +2223,23 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 
     if (region.IsEmpty()) {
         return TRUE;
     }
 
     // If this widget uses OMTC...
     if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
         listener->PaintWindow(this, region);
+
+        // Re-get the listener since the will paint notification might have
+        // killed it.
+        listener = GetListener();
+        if (!listener)
+            return TRUE;
+
         listener->DidPaintWindow();
         return TRUE;
     }
 
     BufferMode layerBuffering = BufferMode::BUFFERED;
     RefPtr<DrawTarget> dt = GetDrawTarget(region, &layerBuffering);
     if (!dt || !dt->IsValid()) {
         return FALSE;
@@ -2288,16 +2300,23 @@ nsWindow::OnExposeEvent(cairo_t *cr)
             gdk_screen_get_rgba_visual(screen)) {
           // If our draw target is unbuffered and we use an alpha channel,
           // clear the image beforehand to ensure we don't get artifacts from a
           // reused SHM image. See bug 1258086.
           dt->ClearRect(Rect(boundsRect));
         }
         AutoLayerManagerSetup setupLayerManager(this, ctx, layerBuffering);
         painted = listener->PaintWindow(this, region);
+
+        // Re-get the listener since the will paint notification might have
+        // killed it.
+        listener = GetListener();
+        if (!listener)
+            return TRUE;
+
       }
     }
 
 #ifdef MOZ_X11
     // PaintWindow can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (shaped) {
         if (MOZ_LIKELY(!mIsDestroyed)) {
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -425,16 +425,17 @@ private:
     {
       CheckForRollup(0, 0, false, true);
     }
 
     bool               GetDragInfo(mozilla::WidgetMouseEvent* aMouseEvent,
                                    GdkWindow** aWindow, gint* aButton,
                                    gint* aRootX, gint* aRootY);
     void               ClearCachedResources();
+    nsIWidgetListener* GetListener();
 
     GtkWidget          *mShell;
     MozContainer       *mContainer;
     GdkWindow          *mGdkWindow;
 
     uint32_t            mHasMappedToplevel : 1,
                         mIsFullyObscured : 1,
                         mRetryPointerGrab : 1;
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -856,39 +856,54 @@ nsWindow::SetTitle(const nsAString& aTit
 
     mWidget->setTitle(qStr);
 
     return NS_OK;
 }
 
 // EVENTS
 
+nsIWidgetListener*
+nsWindow::GetPaintListener()
+{
+    return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+}
+
 void
 nsWindow::OnPaint()
 {
     LOGDRAW(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this));
-    nsIWidgetListener* listener =
-        mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+    nsIWidgetListener* listener = GetPaintListener();
     if (!listener) {
         return;
     }
 
     listener->WillPaintWindow(this);
 
+    nsIWidgetListener* listener = GetPaintListener();
+    if (!listener) {
+        return;
+    }
+
     switch (GetLayerManager()->GetBackendType()) {
         case mozilla::layers::LayersBackend::LAYERS_CLIENT: {
             LayoutDeviceIntRegion region(
               LayoutDeviceIntRect(0, 0, mWidget->width(), mWidget->height()));
             listener->PaintWindow(this, region);
             break;
         }
         default:
             NS_ERROR("Invalid layer manager");
     }
 
+    nsIWidgetListener* listener = GetPaintListener();
+    if (!listener) {
+        return;
+    }
+
     listener->DidPaintWindow();
 }
 
 nsEventStatus
 nsWindow::moveEvent(QMoveEvent* aEvent)
 {
     LOG(("configure event [%p] %d %d\n", (void *)this,
         aEvent->pos().x(),  aEvent->pos().y()));
--- a/widget/qt/nsWindow.h
+++ b/widget/qt/nsWindow.h
@@ -248,16 +248,17 @@ private:
 
 private:
     typedef struct {
         QPointF pos;
         Qt::KeyboardModifiers modifiers;
         bool needDispatch;
     } MozCachedMoveEvent;
 
+    nsIWidgetListener* GetPaintListener();
     bool               CheckForRollup(double aMouseX, double aMouseY, bool aIsWheel);
     void*              SetupPluginPort(void);
     nsresult           SetWindowIconList(const nsTArray<nsCString> &aIconList);
     void               SetDefaultIcon(void);
 
     nsEventStatus      DispatchCommandEvent(nsIAtom* aCommand);
     nsEventStatus      DispatchContentCommandEvent(mozilla::EventMessage aMsg);
     void               SetSoftwareKeyboardState(bool aOpen, const InputContextAction& aAction);
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -271,16 +271,18 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
 
   if (clientLayerManager && mCompositorBridgeParent) {
     // We need to paint to the screen even if nothing changed, since if we
     // don't have a compositing window manager, our pixels could be stale.
     clientLayerManager->SetNeedsComposite(true);
     clientLayerManager->SendInvalidRegion(region);
   }
 
+  RefPtr<nsWindow> strongThis(this);
+
   nsIWidgetListener* listener = GetPaintListener();
   if (listener) {
     listener->WillPaintWindow(this);
   }
   // Re-get the listener since the will paint notification may have killed it.
   listener = GetPaintListener();
   if (!listener) {
     return false;