Bug 1284350 - Revert "Bug 1269937 - Manage updating visible frames and regions using RAII. r=mstange". a=lizzard
☠☠ backed out by ab6b685c5249 ☠ ☠
authorSeth Fowler <mark.seth.fowler@gmail.com>
Fri, 08 Jul 2016 17:54:47 -0700
changeset 341889 46963dffa40a98fc1cf17bd85c0397fca80889ec
parent 341888 d44a440ae78d1184f942db0298777f5afe09a807
child 341890 095bb628a66a10a1ef2108702f026ba521131de5
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, lizzard
bugs1284350, 1269937
milestone49.0a2
Bug 1284350 - Revert "Bug 1269937 - Manage updating visible frames and regions using RAII. r=mstange". a=lizzard This reverts commit 835b752617b3b05e2168a0e03e46087d7f3b2d66.
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -21,17 +21,16 @@
 #include "mozilla/Logging.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/IMEStateManager.h"
-#include "mozilla/InitializerList.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Snprintf.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/UniquePtr.h"
@@ -206,20 +205,16 @@
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 using namespace mozilla::tasktracer;
 #endif
 
 #define ANCHOR_SCROLL_FLAGS \
   (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
 
-  // define the scalfactor of drag and drop images
-  // relative to the max screen height/width
-#define RELATIVE_SCALEFACTOR 0.0925f
-
 using std::initializer_list;
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
@@ -4757,24 +4752,24 @@ PresShell::RenderDocument(const nsRect& 
     flags |= PaintFrameFlags::PAINT_DOCUMENT_RELATIVE;
   }
 
   // Don't let drawWindow blow away our retained layer tree
   if ((flags & PaintFrameFlags::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) {
     flags &= ~PaintFrameFlags::PAINT_WIDGET_LAYERS;
   }
 
-  // We don't update the visible regions here because we're not painting to
-  // the window, and hence there should be no change.
-
   nsLayoutUtils::PaintFrame(&rc, rootFrame, nsRegion(aRect),
                             aBackgroundColor,
                             nsDisplayListBuilderMode::PAINTING,
                             flags);
 
+  // We don't call NotifyCompositorOfVisibleRegionsChange here because we're
+  // not painting to the window, and hence there should be no change.
+
   return NS_OK;
 }
 
 /*
  * Clip the display list aList to a range. Returns the clipped
  * rectangle surrounding the range.
  */
 nsRect
@@ -5816,160 +5811,61 @@ ForAllTrackedFramesInVisibleSet(const Vi
     // not be, if the frame disabled visibility tracking after we added it to
     // the visible frames list.)
     if (frame->TrackingVisibility()) {
       aFunc(frame);
     }
   }
 }
 
-/**
- * This RAII class automatically handles updating visible frames sets. It also
- * handles updating visible regions (used for the APZ minimap debugger) when
- * the appropriate prefs are enabled.
- *
- * Because we don't want to cause unnecessary IPC traffic between the content
- * process and the compositor process, avoid nesting multiple
- * AutoUpdateVisibility instances. Instead, pass a list of VisibilityCounters
- * for all the types of visibility you want to update to
- * AutoUpdateVisibility's constructor.
- *
- * Normally the compositor is notified of new visible regions synchronously;
- * however, this is not safe within a layers transaction. In that situation,
- * specify Notify::eAsync to delay notifying the compositor until the
- * transaction is complete. Regardless, the visible frame sets themselves are
- * always updating synchronously.
- */
-struct MOZ_STACK_CLASS AutoUpdateVisibility
-{
-  enum class Notify
-  {
-    eSync,
-    eAsync
-  };
-
-  AutoUpdateVisibility(PresShell* aPresShell,
-                       std::initializer_list<VisibilityCounter> aCounters,
-                       Maybe<OnNonvisible> aNonvisibleAction = Nothing())
-    : AutoUpdateVisibility(aPresShell, Notify::eSync, aCounters, aNonvisibleAction)
-  { }
-
-  AutoUpdateVisibility(PresShell* aPresShell,
-                       Notify aNotifyStrategy,
-                       std::initializer_list<VisibilityCounter> aCounters,
-                       Maybe<OnNonvisible> aNonvisibleAction = Nothing())
-    : mNonvisibleAction(aNonvisibleAction)
-    , mPresShell(aPresShell)
-    , mNotifyStrategy(aNotifyStrategy)
-  {
-    // Clear the visible frames sets we're updating, but save the old set so
-    // we can decrement their counter later. This is how we mark frames
-    // nonvisible if they don't end up in the set during the visibility
-    // update.
-    for (VisibilityCounter counter : aCounters) {
-      switch (counter) {
-        case VisibilityCounter::MAY_BECOME_VISIBLE:
-          mOldApproximatelyVisibleFrames.emplace();
-          mPresShell->mApproximatelyVisibleFrames.SwapElements(*mOldApproximatelyVisibleFrames);
-          break;
-
-        case VisibilityCounter::IN_DISPLAYPORT:
-          mOldInDisplayPortFrames.emplace();
-          mPresShell->mInDisplayPortFrames.SwapElements(*mOldInDisplayPortFrames);
-          break;
-      }
-    }
-
-    // If we're not visualizing visible regions, we're done.
-    if (!gfxPrefs::APZMinimap() ||
-        !gfxPrefs::APZMinimapVisibilityEnabled()) {
-      mPresShell->mVisibleRegions = nullptr;
-      return;
-    }
-
-    // We're visualizing visible regions, so initialize a
-    // VisibleRegionsContainer to store them. Visibility-related functions we
-    // call will only do the work of populating this object and sending it to
-    // the compositor if we've created it, so we don't need to check the prefs
-    // everywhere.
-
-    if (mPresShell->mVisibleRegions) {
-      // Clear the regions we're about to update. We don't want to clear them
-      // all - we only clear the ones being updated. Otherwise, different
-      // visibility tracking methods will interfere with each other.
-      for (VisibilityCounter counter : aCounters) {
-        VisibleRegions& regions =
-          mPresShell->mVisibleRegions->ForCounter(counter);
-        regions.Clear();
-      }
-
-      return;
-    }
-
-    mPresShell->mVisibleRegions =
-      MakeUnique<PresShell::VisibleRegionsContainer>();
-  }
-
-  ~AutoUpdateVisibility()
-  {
-    // Decrement the counters for the old visible frames sets now. If they
-    // didn't get incremented during the visibility update, this will mark
-    // them nonvisible.
-    if (mOldApproximatelyVisibleFrames) {
-      ForAllTrackedFramesInVisibleSet(*mOldApproximatelyVisibleFrames, [&](nsIFrame* aFrame) {
-        aFrame->DecVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE,
-                                   mNonvisibleAction);
-      });
-    }
-    if (mOldInDisplayPortFrames) {
-      ForAllTrackedFramesInVisibleSet(*mOldInDisplayPortFrames, [&](nsIFrame* aFrame) {
-        aFrame->DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT,
-                                   mNonvisibleAction);
-      });
-    }
-
-    // If we're not visualizing visible regions, we're done.
-    if (!mPresShell->mVisibleRegions) {
-      return;
-    }
-
-    if (mNotifyStrategy == Notify::eSync) {
-      mPresShell->NotifyCompositorOfVisibleRegionsChange();
-      return;
-    }
-
-    if (mPresShell->mNotifyCompositorOfVisibleRegionsChangeEvent.IsPending()) {
-      return;  // An async notify is already pending.
-    }
-
-    // Asynchronously notify the compositor of the new visible regions.
-    RefPtr<nsRunnableMethod<PresShell>> event =
-      NewRunnableMethod(mPresShell, &PresShell::NotifyCompositorOfVisibleRegionsChange);
-    if (NS_SUCCEEDED(NS_DispatchToMainThread(event))) {
-      mPresShell->mNotifyCompositorOfVisibleRegionsChangeEvent = event;
-    }
-  }
-
-private:
-  Maybe<VisibleFrames> mOldApproximatelyVisibleFrames;
-  Maybe<VisibleFrames> mOldInDisplayPortFrames;
-  Maybe<OnNonvisible> mNonvisibleAction;
-  PresShell* mPresShell;
-  Notify mNotifyStrategy;
-};
+void
+PresShell::InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter aForCounter)
+{
+  // If we're visualizing visible regions, initialize a
+  // VisibleRegionsContainer to store them.  Visibility-related functions we
+  // call will only do the work of populating this object and sending it to
+  // the compositor if we've created it, so we don't need to check the prefs
+  // everywhere.
+  if (!gfxPrefs::APZMinimap() ||
+      !gfxPrefs::APZMinimapVisibilityEnabled()) {
+    mVisibleRegions = nullptr;
+    return;
+  }
+
+  if (mVisibleRegions) {
+    // Clear the regions we're about to update. We don't want to clear both,
+    // or the two visibility tracking methods will interfere with each other.
+    VisibleRegions& regions = mVisibleRegions->ForCounter(aForCounter);
+    regions.Clear();
+    return;
+  }
+
+  mVisibleRegions = MakeUnique<VisibleRegionsContainer>();
+}
 
 void
 PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList)
 {
   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
   mApproximateFrameVisibilityVisited = true;
 
-  AutoUpdateVisibility update(this, { VisibilityCounter::MAY_BECOME_VISIBLE });
+  // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
+  // them in oldApproxVisibleFrames.
+  VisibleFrames oldApproximatelyVisibleFrames;
+  mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
+
+  InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::MAY_BECOME_VISIBLE);
 
   MarkFramesInListApproximatelyVisible(aList);
+
+  ForAllTrackedFramesInVisibleSet(oldApproximatelyVisibleFrames, [&](nsIFrame* aFrame) {
+    aFrame->DecVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE);
+  });
+
+  NotifyCompositorOfVisibleRegionsChange();
 }
 
 /* static */ void
 PresShell::ClearVisibleFramesForUnvisitedPresShells(nsView* aView, bool aClear)
 {
   nsViewManager* vm = aView->GetViewManager();
   if (aClear) {
     PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell());
@@ -5982,22 +5878,31 @@ PresShell::ClearVisibleFramesForUnvisite
     ClearVisibleFramesForUnvisitedPresShells(v, v->GetViewManager() != vm);
   }
 }
 
 void
 PresShell::ClearVisibleFramesSets(Maybe<OnNonvisible> aNonvisibleAction
                                     /* = Nothing() */)
 {
-  // Do an empty update, which will clear any existing visible frames and
-  // regions.
-  AutoUpdateVisibility update(this, {
-    VisibilityCounter::MAY_BECOME_VISIBLE,
-    VisibilityCounter::IN_DISPLAYPORT
-  }, aNonvisibleAction);
+  ForAllTrackedFramesInVisibleSet(mApproximatelyVisibleFrames, [&](nsIFrame* aFrame) {
+    aFrame->DecVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE, aNonvisibleAction);
+  });
+  ForAllTrackedFramesInVisibleSet(mInDisplayPortFrames, [&](nsIFrame* aFrame) {
+    aFrame->DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT, aNonvisibleAction);
+  });
+
+  mApproximatelyVisibleFrames.Clear();
+  mInDisplayPortFrames.Clear();
+
+  if (mVisibleRegions) {
+    mVisibleRegions->mApproximate.Clear();
+    mVisibleRegions->mInDisplayPort.Clear();
+    NotifyCompositorOfVisibleRegionsChange();
+  }
 }
 
 void
 PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
                                                    const nsRect& aRect,
                                                    bool aRemoveOnly /* = false */)
 {
   MOZ_ASSERT(aFrame->PresContext()->PresShell() == this, "wrong presshell");
@@ -6094,24 +5999,35 @@ PresShell::RebuildApproximateFrameVisibi
   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
   mApproximateFrameVisibilityVisited = true;
 
   nsIFrame* rootFrame = GetRootFrame();
   if (!rootFrame) {
     return;
   }
 
-  AutoUpdateVisibility update(this, { VisibilityCounter::MAY_BECOME_VISIBLE });
+  // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
+  // them in oldApproximatelyVisibleFrames.
+  VisibleFrames oldApproximatelyVisibleFrames;
+  mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
+
+  InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::MAY_BECOME_VISIBLE);
 
   nsRect vis(nsPoint(0, 0), rootFrame->GetSize());
   if (aRect) {
     vis = *aRect;
   }
 
   MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, aRemoveOnly);
+
+  ForAllTrackedFramesInVisibleSet(oldApproximatelyVisibleFrames, [&](nsIFrame* aFrame) {
+    aFrame->DecVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE);
+  });
+
+  NotifyCompositorOfVisibleRegionsChange();
 }
 
 void
 PresShell::UpdateApproximateFrameVisibility()
 {
   DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ false);
 }
 
@@ -6528,24 +6444,43 @@ PresShell::Paint(nsView*        aViewToP
     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
   }
   if (mNextPaintCompressed) {
     flags |= PaintFrameFlags::PAINT_COMPRESSED;
     mNextPaintCompressed = false;
   }
 
   if (frame) {
-    AutoUpdateVisibility update(this, AutoUpdateVisibility::Notify::eAsync, {
-      VisibilityCounter::IN_DISPLAYPORT
-    });
+    // Remove the entries of the mInDisplayPortFrames hashtable and put them
+    // in oldInDisplayPortFrames.
+    VisibleFrames oldInDisplayPortFrames;
+    mInDisplayPortFrames.SwapElements(oldInDisplayPortFrames);
+
+    InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::IN_DISPLAYPORT);
 
     // We can paint directly into the widget using its layer manager.
     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
                               nsDisplayListBuilderMode::PAINTING, flags);
 
+    ForAllTrackedFramesInVisibleSet(oldInDisplayPortFrames, [&](nsIFrame* aFrame) {
+      aFrame->DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+    });
+
+    if (mVisibleRegions &&
+        !mNotifyCompositorOfVisibleRegionsChangeEvent.IsPending()) {
+      // Asynchronously notify the compositor of the new visible regions,
+      // since this is happening during a paint and updating the visible
+      // regions triggers a recomposite.
+      RefPtr<nsRunnableMethod<PresShell>> event =
+        NewRunnableMethod(this, &PresShell::NotifyCompositorOfVisibleRegionsChange);
+      if (NS_SUCCEEDED(NS_DispatchToMainThread(event))) {
+        mNotifyCompositorOfVisibleRegionsChangeEvent = event;
+      }
+    }
+
     return;
   }
 
   RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
   if (root) {
     nsPresContext* pc = GetPresContext();
     nsIntRect bounds =
       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -820,18 +820,16 @@ protected:
     VisibleRegions mInDisplayPort;
   };
 
   // The most recent visible regions we've computed. Only non-null if the APZ
   // minimap visibility visualization was enabled during the last visibility
   // update.
   UniquePtr<VisibleRegionsContainer> mVisibleRegions;
 
-  friend struct AutoUpdateVisibility;
-
 
   //////////////////////////////////////////////////////////////////////////////
   // Methods for dispatching KeyboardEvent and BeforeAfterKeyboardEvent.
   //////////////////////////////////////////////////////////////////////////////
 
   void HandleKeyboardEvent(nsINode* aTarget,
                            mozilla::WidgetKeyboardEvent& aEvent,
                            bool aEmbeddedCancelled,