Bug 946658. r=tn a=abillings
authorMats Palmgren <matspal@gmail.com>
Mon, 10 Mar 2014 21:28:32 +0000
changeset 183249 28d2834f0617b361be951a6b1dcfa5e77986ef37
parent 183248 ab90efe51b6ede2c56a96ce688d8f1ec2ff19338
child 183250 910ef9ba00d73201a7ddd7ff383cf89b0958564d
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, abillings
bugs946658
milestone29.0a2
Bug 946658. r=tn a=abillings
view/public/nsViewManager.h
view/src/nsViewManager.cpp
--- a/view/public/nsViewManager.h
+++ b/view/public/nsViewManager.h
@@ -7,16 +7,17 @@
 #define nsViewManager_h___
 
 #include "nscore.h"
 #include "nsView.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsVoidArray.h"
 #include "nsDeviceContext.h"
+#include "nsTArray.h"
 #include "mozilla/EventForwards.h"
 
 class nsIWidget;
 struct nsRect;
 class nsRegion;
 class nsDeviceContext;
 class nsIPresShell;
 
@@ -322,16 +323,20 @@ private:
   static uint32_t gLastUserEventTime;
 
   /* Update the cached RootViewManager pointer on this view manager. */
   void InvalidateHierarchy();
   void FlushPendingInvalidates();
 
   void ProcessPendingUpdatesForView(nsView *aView,
                                     bool aFlushDirtyRegion = true);
+  void ProcessPendingUpdatesRecurse(nsView* aView,
+                                    nsTArray<nsCOMPtr<nsIWidget> >& aWidgets);
+  void ProcessPendingUpdatesPaint(nsIWidget* aWidget);
+
   void FlushDirtyRegionToWidget(nsView* aView);
   /**
    * Call WillPaint() on all view observers under this vm root.
    */
   void CallWillPaintOnObservers();
   void ReparentChildWidgets(nsView* aView, nsIWidget *aNewWidget);
   void ReparentWidgets(nsView* aView, nsView *aParent);
   void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -360,84 +360,114 @@ void nsViewManager::Refresh(nsView *aVie
   }
 
   if (RootViewManager()->mRecursiveRefreshPending) {
     RootViewManager()->mRecursiveRefreshPending = false;
     InvalidateAllViews();
   }
 }
 
-void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
-                                                 bool aFlushDirtyRegion)
+void
+nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
+                                            bool aFlushDirtyRegion)
 {
   NS_ASSERTION(IsRootVM(), "Updates will be missed");
-
-  // Protect against a null-view.
-  nsViewManager* viewManager = aView ? aView->GetViewManager() : nullptr;
-  if (!aView || !viewManager) {
+  if (!aView) {
     return;
   }
 
-  nsIPresShell* presShell = viewManager->mPresShell;
-  if (presShell && presShell->IsNeverPainting()) {
+  nsCOMPtr<nsIPresShell> rootShell(mPresShell);
+  nsTArray<nsCOMPtr<nsIWidget> > widgets;
+  aView->GetViewManager()->ProcessPendingUpdatesRecurse(aView, widgets);
+  for (uint32_t i = 0; i < widgets.Length(); ++i) {
+    nsView* view = nsView::GetViewFor(widgets[i]);
+    if (view) {
+      view->ResetWidgetBounds(false, true);
+    }
+  }
+  if (rootShell->GetViewManager() != this) {
+    return; // 'this' might have been destroyed
+  }
+  if (aFlushDirtyRegion) {
+    nsAutoScriptBlocker scriptBlocker;
+    SetPainting(true);
+    for (uint32_t i = 0; i < widgets.Length(); ++i) {
+      nsIWidget* widget = widgets[i];
+      nsView* view = nsView::GetViewFor(widget);
+      if (view) {
+        view->GetViewManager()->ProcessPendingUpdatesPaint(widget);
+      }
+    }
+    SetPainting(false);
+  }
+}
+
+void
+nsViewManager::ProcessPendingUpdatesRecurse(nsView* aView,
+                                            nsTArray<nsCOMPtr<nsIWidget> >& aWidgets)
+{
+  if (mPresShell && mPresShell->IsNeverPainting()) {
     return;
   }
 
-  if (aView->HasWidget()) {
-    aView->ResetWidgetBounds(false, true);
-  }
-
-  // process pending updates in child view.
   for (nsView* childView = aView->GetFirstChild(); childView;
        childView = childView->GetNextSibling()) {
-    ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
+    childView->GetViewManager()->
+      ProcessPendingUpdatesRecurse(childView, aWidgets);
   }
 
-  // Push out updates after we've processed the children; ensures that
-  // damage is applied based on the final widget geometry
-  if (aFlushDirtyRegion) {
-    nsIWidget *widget = aView->GetWidget();
-    if (widget && widget->NeedsPaint()) {
-      // If an ancestor widget was hidden and then shown, we could
-      // have a delayed resize to handle.
-      for (nsViewManager *vm = viewManager; vm;
-           vm = vm->mRootView->GetParent()
-                  ? vm->mRootView->GetParent()->GetViewManager()
-                  : nullptr) {
-        if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-            vm->mRootView->IsEffectivelyVisible() &&
-            vm->mPresShell && vm->mPresShell->IsVisible()) {
-          vm->FlushDelayedResize(true);
-        }
+  nsIWidget* widget = aView->GetWidget();
+  if (widget) {
+    aWidgets.AppendElement(widget);
+  } else {
+    FlushDirtyRegionToWidget(aView);
+  }
+}
+
+void
+nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget)
+{
+  if (aWidget->NeedsPaint()) {
+    // If an ancestor widget was hidden and then shown, we could
+    // have a delayed resize to handle.
+    for (nsViewManager *vm = this; vm;
+         vm = vm->mRootView->GetParent()
+           ? vm->mRootView->GetParent()->GetViewManager()
+           : nullptr) {
+      if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+          vm->mRootView->IsEffectivelyVisible() &&
+          vm->mPresShell && vm->mPresShell->IsVisible()) {
+        vm->FlushDelayedResize(true);
       }
-      NS_ASSERTION(aView->HasWidget(), "FlushDelayedResize removed our widget!");
+    }
+    nsView* view = nsView::GetViewFor(aWidget);
+    if (!view) {
+      NS_ERROR("FlushDelayedResize destroyed the nsView?");
+      return;
+    }
 
-      if (presShell) {
+    if (mPresShell) {
 #ifdef MOZ_DUMP_PAINTING
-        if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
-          printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", presShell, aView, widget);
-        }
-#endif
-        nsAutoScriptBlocker scriptBlocker;
-        SetPainting(true);
-        presShell->Paint(aView, nsRegion(), nsIPresShell::PAINT_LAYERS);
-#ifdef MOZ_DUMP_PAINTING
-        if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
-          printf_stderr("---- PAINT END ----\n");
-        }
+      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
+        printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n",
+                      mPresShell, view, aWidget);
+      }
 #endif
 
-        aView->SetForcedRepaint(false);
-        SetPainting(false);
+      mPresShell->Paint(view, nsRegion(), nsIPresShell::PAINT_LAYERS);
+      view->SetForcedRepaint(false);
+
+#ifdef MOZ_DUMP_PAINTING
+      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
+        printf_stderr("---- PAINT END ----\n");
       }
-      viewManager->FlushDirtyRegionToWidget(aView);
-    } else {
-      viewManager->FlushDirtyRegionToWidget(aView);
+#endif
     }
   }
+  FlushDirtyRegionToWidget(nsView::GetViewFor(aWidget));
 }
 
 void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
 {
   NS_ASSERTION(aView->GetViewManager() == this,
                "FlushDirtyRegionToWidget called on view we don't own");
 
   if (!aView->HasNonEmptyDirtyRegion())