Bug 1261752. Part 3. r=mats a=ritu
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 10 May 2016 22:58:47 -0500
changeset 332873 65b8174889df723c25260306e0a1b00157470d9c
parent 332872 30b2b24080072a24703e01054b56091753a415b7
child 332874 1836352e593204c8f32755553d0c3c7ba1c5f744
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats, ritu
bugs1261752
milestone48.0a2
Bug 1261752. Part 3. r=mats a=ritu
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
@@ -688,25 +688,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
@@ -3982,16 +3982,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
@@ -2116,18 +2121,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)) {
@@ -2146,30 +2150,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);
     }
@@ -2220,16 +2225,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;
@@ -2290,16 +2302,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
@@ -420,16 +420,17 @@ private:
     bool               DispatchCommandEvent(nsIAtom* aCommand);
     bool               DispatchContentCommandEvent(mozilla::EventMessage aMsg);
     bool               CheckForRollup(gdouble aMouseX, gdouble aMouseY,
                                       bool aIsWheel, bool aAlwaysRollup);
     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
@@ -286,16 +286,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;