Bug 1284350. Backed out changeset 69abdc731a99 (Bug 1261554 (Part 1) - Prepare for implementing in-displayport visibility tracking. r=mstange) a=ritu
authorTimothy Nikkel <tnikkel@gmail.com>
Thu, 15 Sep 2016 16:22:56 -0500
changeset 350243 53201fc8cef406434e9a95d0ab7a5c38fe03b30d
parent 350242 4e26bcdac4bc02a052d13449e756cd44a9e69023
child 350244 29c2a9c386032eadee2a6a9f0adda4f49fa298e4
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, ritu
bugs1284350, 1261554
milestone50.0a2
Bug 1284350. Backed out changeset 69abdc731a99 (Bug 1261554 (Part 1) - Prepare for implementing in-displayport visibility tracking. r=mstange) a=ritu
dom/base/nsImageLoadingContent.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/generic/Visibility.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/svg/SVGFEImageFrame.cpp
layout/svg/nsSVGImageFrame.cpp
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -271,31 +271,32 @@ nsImageLoadingContent::OnUnlockedDraw()
     return;
   }
 
   nsIFrame* frame = GetOurPrimaryFrame();
   if (!frame) {
     return;
   }
 
-  if (frame->IsVisibleOrMayBecomeVisibleSoon()) {
-    return;  // Nothing to do.
+  if (frame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE) {
+    // This frame is already marked visible; there's nothing to do.
+    return;
   }
 
   nsPresContext* presContext = frame->PresContext();
   if (!presContext) {
     return;
   }
 
   nsIPresShell* presShell = presContext->PresShell();
   if (!presShell) {
     return;
   }
 
-  presShell->MarkFrameVisibleInDisplayPort(frame);
+  presShell->EnsureFrameInApproximatelyVisibleList(frame);
 }
 
 nsresult
 nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
 {
   bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
   if (requestFlag) {
     nsLayoutUtils::RegisterImageRequest(GetFramePresContext(),
@@ -512,17 +513,17 @@ nsImageLoadingContent::FrameDestroyed(ns
                                           &mPendingRequestRegistered);
   }
 
   UntrackImage(mCurrentRequest);
   UntrackImage(mPendingRequest);
 
   nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
   if (presShell) {
-    presShell->MarkFrameNonvisible(aFrame);
+    presShell->RemoveFrameFromApproximatelyVisibleList(aFrame);
   }
 }
 
 /* static */
 nsContentPolicyType
 nsImageLoadingContent::PolicyTypeForLoad(ImageLoadType aImageLoadType)
 {
   if (aImageLoadType == eImageLoadType_Imageset) {
@@ -1428,23 +1429,22 @@ nsImageLoadingContent::UnbindFromTree(bo
     doc->UnblockOnload(false);
 }
 
 void
 nsImageLoadingContent::OnVisibilityChange(Visibility aNewVisibility,
                                           const Maybe<OnNonvisible>& aNonvisibleAction)
 {
   switch (aNewVisibility) {
-    case Visibility::MAY_BECOME_VISIBLE:
-    case Visibility::IN_DISPLAYPORT:
+    case Visibility::APPROXIMATELY_VISIBLE:
       TrackImage(mCurrentRequest);
       TrackImage(mPendingRequest);
       break;
 
-    case Visibility::NONVISIBLE:
+    case Visibility::APPROXIMATELY_NONVISIBLE:
       UntrackImage(mCurrentRequest, aNonvisibleAction);
       UntrackImage(mPendingRequest, aNonvisibleAction);
       break;
 
     case Visibility::UNTRACKED:
       MOZ_ASSERT_UNREACHABLE("Shouldn't notify for untracked visibility");
       break;
   }
@@ -1460,21 +1460,21 @@ nsImageLoadingContent::TrackImage(imgIRe
              "Why haven't we heard of this request?");
 
   nsIDocument* doc = GetOurCurrentDoc();
   if (!doc) {
     return;
   }
 
   // We only want to track this request if we're visible. Ordinarily we check
-  // whether our frame considers itself visible, but in cases where
+  // the visible count, but that requires a frame; in cases where
   // GetOurPrimaryFrame() cannot obtain a frame (e.g. <feImage>), we assume
   // we're visible if FrameCreated() was called.
   nsIFrame* frame = GetOurPrimaryFrame();
-  if ((frame && !frame->IsVisibleOrMayBecomeVisibleSoon()) ||
+  if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) ||
       (!frame && !mFrameCreateCalled)) {
     return;
   }
 
   if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
     mCurrentRequestFlags |= REQUEST_IS_TRACKED;
     doc->AddImage(mCurrentRequest);
   }
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -41,16 +41,17 @@
 #include "nsRegionFwd.h"
 #include "mozFlushType.h"
 #include "nsWeakReference.h"
 #include <stdio.h> // for FILE definition
 #include "nsChangeHint.h"
 #include "nsRefPtrHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsPresArena.h"
+#include "nsIImageLoadingContent.h"
 #include "nsMargin.h"
 #include "nsFrameState.h"
 #include "Units.h"
 
 #ifdef MOZ_B2G
 #include "nsIHardwareKeyHandler.h"
 #endif
 
@@ -1602,22 +1603,21 @@ public:
   virtual void ScheduleApproximateFrameVisibilityUpdateNow() = 0;
 
   /// Clears the current list of approximately visible frames on this pres shell
   /// and replaces it with frames that are in the display list @aList.
   virtual void RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList) = 0;
   virtual void RebuildApproximateFrameVisibility(nsRect* aRect = nullptr,
                                                  bool aRemoveOnly = false) = 0;
 
-  /// Adds @aFrame to the list of frames which were visible within the
-  /// displayport during the last paint.
-  virtual void MarkFrameVisibleInDisplayPort(nsIFrame* aFrame) = 0;
+  /// Ensures @aFrame is in the list of approximately visible frames.
+  virtual void EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) = 0;
 
-  /// Marks @aFrame nonvisible and removes it from all lists of visible frames.
-  virtual void MarkFrameNonvisible(nsIFrame* aFrame) = 0;
+  /// Removes @aFrame from the list of approximately visible frames if present.
+  virtual void RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) = 0;
 
   /// Whether we should assume all frames are visible.
   virtual bool AssumeAllFramesVisible() = 0;
 
 
   /**
    * Returns whether the document's style set's rule processor for the
    * specified level of the cascade is shared by multiple style sets.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1181,19 +1181,18 @@ PresShell::Destroy()
   if (mDelayedPaintTimer) {
     mDelayedPaintTimer->Cancel();
     mDelayedPaintTimer = nullptr;
   }
 
   mSynthMouseMoveEvent.Revoke();
 
   mUpdateApproximateFrameVisibilityEvent.Revoke();
-  mNotifyCompositorOfVisibleRegionsChangeEvent.Revoke();
-
-  ClearVisibleFramesSets(Some(OnNonvisible::DISCARD_IMAGES));
+
+  ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
 
   if (mCaret) {
     mCaret->Terminate();
     mCaret = nullptr;
   }
 
   if (mSelection) {
     mSelection->DisconnectFromPresShell();
@@ -4601,83 +4600,16 @@ PresShell::StyleRuleRemoved(StyleSheetHa
 }
 
 nsIFrame*
 PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const
 {
   return mFrameConstructor->GetPlaceholderFrameFor(aFrame);
 }
 
-void
-PresShell::NotifyCompositorOfVisibleRegionsChange()
-{
-  mNotifyCompositorOfVisibleRegionsChangeEvent.Revoke();
-
-  if (!mVisibleRegions) {
-    return;
-  }
-
-  // Retrieve the layers ID and pres shell ID.
-  TabChild* tabChild = TabChild::GetFrom(this);
-  if (!tabChild) {
-    return;
-  }
-
-  const uint64_t layersId = tabChild->LayersId();
-  const uint32_t presShellId = GetPresShellId();
-
-  // Retrieve the CompositorBridgeChild.
-  LayerManager* layerManager = GetLayerManager();
-  if (!layerManager) {
-    return;
-  }
-
-  ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager();
-  if (!clientLayerManager) {
-    return;
-  }
-
-  CompositorBridgeChild* compositorChild = clientLayerManager->GetCompositorBridgeChild();
-  if (!compositorChild) {
-    return;
-  }
-
-  // XXX(seth): Right now we're just treating MAY_BECOME_VISIBLE and
-  // IN_DISPLAYPORT regions the same when visualizing them. In part 2 we'll
-  // update the visualization to display them differently.
-
-  // Clear the old visible regions associated with this document.
-  compositorChild->SendClearApproximatelyVisibleRegions(layersId, presShellId);
-
-  // Send the new visible regions to the compositor.
-  for (auto iter = mVisibleRegions->mApproximate.ConstIter();
-      !iter.Done();
-      iter.Next()) {
-    const ViewID viewId = iter.Key();
-    const CSSIntRegion* region = iter.UserData();
-    MOZ_ASSERT(region);
-
-    const ScrollableLayerGuid guid(layersId, presShellId, viewId);
-
-    compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region);
-  }
-
-  for (auto iter = mVisibleRegions->mInDisplayPort.ConstIter();
-      !iter.Done();
-      iter.Next()) {
-    const ViewID viewId = iter.Key();
-    const CSSIntRegion* region = iter.UserData();
-    MOZ_ASSERT(region);
-
-    const ScrollableLayerGuid guid(layersId, presShellId, viewId);
-
-    compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region);
-  }
-}
-
 nsresult
 PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
                           nscolor aBackgroundColor,
                           gfxContext* aThebesContext)
 {
   NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
 
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
@@ -5716,24 +5648,27 @@ PresShell::ProcessSynthMouseMoveEvent(bo
     shell->DispatchSynthMouseMove(&event, !aFromScroll);
   }
 
   if (!aFromScroll) {
     mSynthMouseMoveEvent.Forget();
   }
 }
 
-void
-PresShell::AddFrameToVisibleRegions(nsIFrame* aFrame, VisibilityCounter aForCounter)
-{
-  if (!mVisibleRegions) {
+static void
+AddFrameToVisibleRegions(nsIFrame* aFrame,
+                         nsViewManager* aViewManager,
+                         Maybe<VisibleRegions>& aVisibleRegions)
+{
+  if (!aVisibleRegions) {
     return;
   }
 
   MOZ_ASSERT(aFrame);
+  MOZ_ASSERT(aViewManager);
 
   // Retrieve the view ID for this frame (which we obtain from the enclosing
   // scrollable frame).
   nsIScrollableFrame* scrollableFrame =
     nsLayoutUtils::GetNearestScrollableFrame(aFrame,
                                              nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE |
                                              nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT);
   if (!scrollableFrame) {
@@ -5758,32 +5693,30 @@ PresShell::AddFrameToVisibleRegions(nsIF
   nsLayoutUtils::TransformResult result =
     nsLayoutUtils::TransformRect(aFrame,
                                  scrollableFrame->GetScrolledFrame(),
                                  frameRectInScrolledFrameSpace);
   if (result != nsLayoutUtils::TransformResult::TRANSFORM_SUCCEEDED) {
     return;
   }
 
-  VisibleRegions& regions = aForCounter == VisibilityCounter::MAY_BECOME_VISIBLE
-                          ? mVisibleRegions->mApproximate
-                          : mVisibleRegions->mInDisplayPort;
-  CSSIntRegion* regionForView = regions.LookupOrAdd(viewID);
+  CSSIntRegion* regionForView = aVisibleRegions->LookupOrAdd(viewID);
   MOZ_ASSERT(regionForView);
 
   regionForView->OrWith(CSSPixel::FromAppUnitsRounded(frameRectInScrolledFrameSpace));
 }
 
 /* static */ void
-PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList)
+PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList,
+                                                Maybe<VisibleRegions>& aVisibleRegions)
 {
   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
     nsDisplayList* sublist = item->GetChildren();
     if (sublist) {
-      MarkFramesInListApproximatelyVisible(*sublist);
+      MarkFramesInListApproximatelyVisible(*sublist, aVisibleRegions);
       continue;
     }
 
     nsIFrame* frame = item->Frame();
     MOZ_ASSERT(frame);
 
     if (!frame->TrackingVisibility()) {
       continue;
@@ -5791,143 +5724,160 @@ PresShell::MarkFramesInListApproximately
 
     // Use the presshell containing the frame.
     auto* presShell = static_cast<PresShell*>(frame->PresContext()->PresShell());
     uint32_t count = presShell->mApproximatelyVisibleFrames.Count();
     MOZ_ASSERT(!presShell->AssumeAllFramesVisible());
     presShell->mApproximatelyVisibleFrames.PutEntry(frame);
     if (presShell->mApproximatelyVisibleFrames.Count() > count) {
       // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
-      frame->IncVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE);
-    }
-
-    presShell->AddFrameToVisibleRegions(frame, VisibilityCounter::MAY_BECOME_VISIBLE);
+      frame->IncApproximateVisibleCount();
+    }
+
+    AddFrameToVisibleRegions(frame, presShell->mViewManager, aVisibleRegions);
+  }
+}
+
+static void
+NotifyCompositorOfVisibleRegionsChange(PresShell* aPresShell,
+                                       const Maybe<VisibleRegions>& aRegions)
+{
+  if (!aRegions) {
+    return;
+  }
+
+  MOZ_ASSERT(aPresShell);
+
+  // Retrieve the layers ID and pres shell ID.
+  TabChild* tabChild = TabChild::GetFrom(aPresShell);
+  if (!tabChild) {
+    return;
+  }
+
+  const uint64_t layersId = tabChild->LayersId();
+  const uint32_t presShellId = aPresShell->GetPresShellId();
+
+  // Retrieve the CompositorBridgeChild.
+  LayerManager* layerManager = aPresShell->GetLayerManager();
+  if (!layerManager) {
+    return;
+  }
+
+  ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager();
+  if (!clientLayerManager) {
+    return;
+  }
+
+  CompositorBridgeChild* compositorChild = clientLayerManager->GetCompositorBridgeChild();
+  if (!compositorChild) {
+    return;
+  }
+
+  // Clear the old approximately visible regions associated with this document.
+  compositorChild->SendClearApproximatelyVisibleRegions(layersId, presShellId);
+
+  // Send the new approximately visible regions to the compositor.
+  for (auto iter = aRegions->ConstIter(); !iter.Done(); iter.Next()) {
+    const ViewID viewId = iter.Key();
+    const CSSIntRegion* region = iter.UserData();
+    MOZ_ASSERT(region);
+
+    const ScrollableLayerGuid guid(layersId, presShellId, viewId);
+
+    compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region);
   }
 }
 
 /* static */ void
-PresShell::DecVisibleCount(const VisibleFrames& aFrames,
-                           VisibilityCounter aCounter,
-                           Maybe<OnNonvisible> aNonvisibleAction /* = Nothing() */)
-{
-  for (auto iter = aFrames.ConstIter(); !iter.Done(); iter.Next()) {
+PresShell::DecApproximateVisibleCount(VisibleFrames& aFrames,
+                                      Maybe<OnNonvisible> aNonvisibleAction
+                                        /* = Nothing() */)
+{
+  for (auto iter = aFrames.Iter(); !iter.Done(); iter.Next()) {
     nsIFrame* frame = iter.Get()->GetKey();
     // Decrement the frame's visible count if we're still tracking its
     // visibility. (We may not be, if the frame disabled visibility tracking
     // after we added it to the visible frames list.)
     if (frame->TrackingVisibility()) {
-      frame->DecVisibilityCount(aCounter, aNonvisibleAction);
-    }
-  }
-}
-
-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 = aForCounter == VisibilityCounter::MAY_BECOME_VISIBLE
-                            ? mVisibleRegions->mApproximate
-                            : mVisibleRegions->mInDisplayPort;
-    regions.Clear();
-    return;
-  }
-
-  mVisibleRegions = MakeUnique<VisibleRegionsContainer>();
+      frame->DecApproximateVisibleCount(aNonvisibleAction);
+    }
+  }
 }
 
 void
 PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList)
 {
   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
   mApproximateFrameVisibilityVisited = true;
 
   // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
   // them in oldApproxVisibleFrames.
   VisibleFrames oldApproximatelyVisibleFrames;
   mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
 
-  InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::MAY_BECOME_VISIBLE);
-
-  MarkFramesInListApproximatelyVisible(aList);
-
-  DecVisibleCount(oldApproximatelyVisibleFrames,
-                  VisibilityCounter::MAY_BECOME_VISIBLE);
-
-  NotifyCompositorOfVisibleRegionsChange();
+  // If we're visualizing visible regions, create a VisibleRegions object to
+  // store information about them. The functions we call will populate this
+  // object and send it to the compositor only if it's Some(), so we don't
+  // need to check the prefs everywhere.
+  Maybe<VisibleRegions> visibleRegions;
+  if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
+    visibleRegions.emplace();
+  }
+
+  MarkFramesInListApproximatelyVisible(aList, visibleRegions);
+
+  DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
+
+  NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
 }
 
 /* static */ void
-PresShell::ClearVisibleFramesForUnvisitedPresShells(nsView* aView, bool aClear)
+PresShell::ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear)
 {
   nsViewManager* vm = aView->GetViewManager();
   if (aClear) {
     PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell());
     if (!presShell->mApproximateFrameVisibilityVisited) {
-      presShell->ClearVisibleFramesSets();
+      presShell->ClearApproximatelyVisibleFramesList();
     }
     presShell->mApproximateFrameVisibilityVisited = false;
   }
   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
-    ClearVisibleFramesForUnvisitedPresShells(v, v->GetViewManager() != vm);
-  }
-}
-
-void
-PresShell::ClearVisibleFramesSets(Maybe<OnNonvisible> aNonvisibleAction
-                                    /* = Nothing() */)
-{
-  DecVisibleCount(mApproximatelyVisibleFrames,
-                  VisibilityCounter::MAY_BECOME_VISIBLE,
-                  aNonvisibleAction);
+    ClearApproximateFrameVisibilityVisited(v, v->GetViewManager() != vm);
+  }
+}
+
+void
+PresShell::ClearApproximatelyVisibleFramesList(Maybe<OnNonvisible> aNonvisibleAction
+                                                 /* = Nothing() */)
+{
+  DecApproximateVisibleCount(mApproximatelyVisibleFrames, aNonvisibleAction);
   mApproximatelyVisibleFrames.Clear();
-
-  DecVisibleCount(mInDisplayPortFrames,
-                  VisibilityCounter::IN_DISPLAYPORT,
-                  aNonvisibleAction);
-  mInDisplayPortFrames.Clear();
-
-  if (mVisibleRegions) {
-    mVisibleRegions->mApproximate.Clear();
-    mVisibleRegions->mInDisplayPort.Clear();
-    NotifyCompositorOfVisibleRegionsChange();
-  }
 }
 
 void
 PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
                                                    const nsRect& aRect,
+                                                   Maybe<VisibleRegions>& aVisibleRegions,
                                                    bool aRemoveOnly /* = false */)
 {
   MOZ_ASSERT(aFrame->PresContext()->PresShell() == this, "wrong presshell");
 
   if (aFrame->TrackingVisibility() &&
       aFrame->StyleVisibility()->IsVisible() &&
-      (!aRemoveOnly || aFrame->IsVisibleOrMayBecomeVisibleSoon())) {
+      (!aRemoveOnly || aFrame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE)) {
     MOZ_ASSERT(!AssumeAllFramesVisible());
     uint32_t count = mApproximatelyVisibleFrames.Count();
     mApproximatelyVisibleFrames.PutEntry(aFrame);
     if (mApproximatelyVisibleFrames.Count() > count) {
       // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
-      aFrame->IncVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE);
-    }
-
-    AddFrameToVisibleRegions(aFrame, VisibilityCounter::MAY_BECOME_VISIBLE);
+      aFrame->IncApproximateVisibleCount();
+    }
+
+    AddFrameToVisibleRegions(aFrame, mViewManager, aVisibleRegions);
   }
 
   nsSubDocumentFrame* subdocFrame = do_QueryFrame(aFrame);
   if (subdocFrame) {
     nsIPresShell* presShell = subdocFrame->GetSubdocumentPresShellForPainting(
       nsSubDocumentFrame::IGNORE_PAINT_SUPPRESSION);
     if (presShell && !presShell->AssumeAllFramesVisible()) {
       nsRect rect = aRect;
@@ -5986,17 +5936,17 @@ PresShell::MarkFramesInSubtreeApproximat
           nsRect out;
           if (nsDisplayTransform::UntransformRect(r, overflow, child, &out)) {
             r = out;
           } else {
             r.SetEmpty();
           }
         }
       }
-      MarkFramesInSubtreeApproximatelyVisible(child, r);
+      MarkFramesInSubtreeApproximatelyVisible(child, r, aVisibleRegions);
     }
   }
 }
 
 void
 PresShell::RebuildApproximateFrameVisibility(nsRect* aRect,
                                              bool aRemoveOnly /* = false */)
 {
@@ -6008,29 +5958,35 @@ PresShell::RebuildApproximateFrameVisibi
     return;
   }
 
   // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
   // them in oldApproximatelyVisibleFrames.
   VisibleFrames oldApproximatelyVisibleFrames;
   mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
 
-  InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::MAY_BECOME_VISIBLE);
+  // If we're visualizing visible regions, create a VisibleRegions object to
+  // store information about them. The functions we call will populate this
+  // object and send it to the compositor only if it's Some(), so we don't
+  // need to check the prefs everywhere.
+  Maybe<VisibleRegions> visibleRegions;
+  if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
+    visibleRegions.emplace();
+  }
 
   nsRect vis(nsPoint(0, 0), rootFrame->GetSize());
   if (aRect) {
     vis = *aRect;
   }
 
-  MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, aRemoveOnly);
-
-  DecVisibleCount(oldApproximatelyVisibleFrames,
-                  VisibilityCounter::MAY_BECOME_VISIBLE);
-
-  NotifyCompositorOfVisibleRegionsChange();
+  MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, visibleRegions, aRemoveOnly);
+
+  DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
+
+  NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
 }
 
 void
 PresShell::UpdateApproximateFrameVisibility()
 {
   DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ false);
 }
 
@@ -6044,22 +6000,22 @@ PresShell::DoUpdateApproximateFrameVisib
 
   if (mHaveShutDown || mIsDestroying) {
     return;
   }
 
   // call update on that frame
   nsIFrame* rootFrame = GetRootFrame();
   if (!rootFrame) {
-    ClearVisibleFramesSets(Some(OnNonvisible::DISCARD_IMAGES));
+    ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
     return;
   }
 
   RebuildApproximateFrameVisibility(/* aRect = */ nullptr, aRemoveOnly);
-  ClearVisibleFramesForUnvisitedPresShells(rootFrame->GetView(), true);
+  ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
 
 #ifdef DEBUG_FRAME_VISIBILITY_DISPLAY_LIST
   // This can be used to debug the frame walker by comparing beforeFrameList
   // and mApproximatelyVisibleFrames in RebuildFrameVisibilityDisplayList to see if
   // they produce the same results (mApproximatelyVisibleFrames holds the frames the
   // display list thinks are visible, beforeFrameList holds the frames the
   // frame walker thinks are visible).
   nsDisplayListBuilder builder(rootFrame, nsDisplayListBuilderMode::FRAME_VISIBILITY, false);
@@ -6079,17 +6035,17 @@ PresShell::DoUpdateApproximateFrameVisib
   builder.IgnorePaintSuppression();
   builder.EnterPresShell(rootFrame, updateRect);
   nsDisplayList list;
   rootFrame->BuildDisplayListForStackingContext(&builder, updateRect, &list);
   builder.LeavePresShell(rootFrame, updateRect);
 
   RebuildApproximateFrameVisibilityDisplayList(list);
 
-  ClearVisibleFramesForUnvisitedPresShells(rootFrame->GetView(), true);
+  ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
 
   list.DeleteAll();
 #endif
 }
 
 bool
 PresShell::AssumeAllFramesVisible()
 {
@@ -6184,85 +6140,70 @@ PresShell::ScheduleApproximateFrameVisib
   RefPtr<nsRunnableMethod<PresShell> > ev =
     NewRunnableMethod(this, &PresShell::UpdateApproximateFrameVisibility);
   if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
     mUpdateApproximateFrameVisibilityEvent = ev;
   }
 }
 
 void
-PresShell::MarkFrameVisibleInDisplayPort(nsIFrame* aFrame)
+PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame)
 {
   if (!aFrame->TrackingVisibility()) {
     return;
   }
 
   if (AssumeAllFramesVisible()) {
-    if (aFrame->GetVisibility() != Visibility::IN_DISPLAYPORT) {
-      aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
-    }
+    aFrame->IncApproximateVisibleCount();
     return;
   }
 
 #ifdef DEBUG
   // Make sure it's in this pres shell.
   nsCOMPtr<nsIContent> content = aFrame->GetContent();
   if (content) {
     PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
     MOZ_ASSERT(!shell || shell == this, "wrong shell");
   }
 #endif
 
-  if (!mInDisplayPortFrames.Contains(aFrame)) {
+  if (!mApproximatelyVisibleFrames.Contains(aFrame)) {
     MOZ_ASSERT(!AssumeAllFramesVisible());
-    mInDisplayPortFrames.PutEntry(aFrame);
-    aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
-  }
-
-  AddFrameToVisibleRegions(aFrame, VisibilityCounter::IN_DISPLAYPORT);
-}
-
-static void
-RemoveFrameFromVisibleSet(nsIFrame* aFrame,
-                          VisibleFrames& aSet,
-                          VisibilityCounter aCounter)
-{
-  uint32_t count = aSet.Count();
-  aSet.RemoveEntry(aFrame);
-
-  if (aFrame->TrackingVisibility() && aSet.Count() < count) {
-    aFrame->DecVisibilityCount(aCounter);
-  }
-
-}
-
-void
-PresShell::MarkFrameNonvisible(nsIFrame* aFrame)
+    mApproximatelyVisibleFrames.PutEntry(aFrame);
+    aFrame->IncApproximateVisibleCount();
+  }
+}
+
+void
+PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame)
 {
 #ifdef DEBUG
   // Make sure it's in this pres shell.
   nsCOMPtr<nsIContent> content = aFrame->GetContent();
   if (content) {
     PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
     MOZ_ASSERT(!shell || shell == this, "wrong shell");
   }
 #endif
 
   if (AssumeAllFramesVisible()) {
     MOZ_ASSERT(mApproximatelyVisibleFrames.Count() == 0,
-               "Shouldn't have any frames in the approximate visibility set");
-    MOZ_ASSERT(mInDisplayPortFrames.Count() == 0,
-               "Shouldn't have any frames in the in-displayport visibility set");
-    return;
-  }
-
-  RemoveFrameFromVisibleSet(aFrame, mApproximatelyVisibleFrames,
-                            VisibilityCounter::MAY_BECOME_VISIBLE);
-  RemoveFrameFromVisibleSet(aFrame, mInDisplayPortFrames,
-                            VisibilityCounter::IN_DISPLAYPORT);
+               "Shouldn't have any frames in the table");
+    return;
+  }
+
+  uint32_t count = mApproximatelyVisibleFrames.Count();
+  mApproximatelyVisibleFrames.RemoveEntry(aFrame);
+
+  if (aFrame->TrackingVisibility() &&
+      mApproximatelyVisibleFrames.Count() < count) {
+    // aFrame was in the hashtable, and we're still tracking its visibility,
+    // so we need to decrement its visible count.
+    aFrame->DecApproximateVisibleCount();
+  }
 }
 
 class nsAutoNotifyDidPaint
 {
 public:
   nsAutoNotifyDidPaint(PresShell* aShell, uint32_t aFlags)
     : mShell(aShell), mFlags(aFlags)
   {
@@ -9077,17 +9018,16 @@ FreezeSubDocument(nsIDocument *aDocument
 
   return true;
 }
 
 void
 PresShell::Freeze()
 {
   mUpdateApproximateFrameVisibilityEvent.Revoke();
-  mNotifyCompositorOfVisibleRegionsChangeEvent.Revoke();
 
   MaybeReleaseCapturingContent();
 
   mDocument->EnumerateActivityObservers(FreezeElement, nullptr);
 
   if (mCaret) {
     SetCaretEnabled(false);
   }
@@ -11128,21 +11068,16 @@ PresShell::AddSizeOfIncludingThis(Malloc
                                   size_t *aPresContextSize)
 {
   mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize);
   *aPresShellSize += aMallocSizeOf(this);
   if (mCaret) {
     *aPresShellSize += mCaret->SizeOfIncludingThis(aMallocSizeOf);
   }
   *aPresShellSize += mApproximatelyVisibleFrames.ShallowSizeOfExcludingThis(aMallocSizeOf);
-  *aPresShellSize += mInDisplayPortFrames.ShallowSizeOfExcludingThis(aMallocSizeOf);
-  *aPresShellSize += mVisibleRegions
-                   ? mVisibleRegions->mApproximate.ShallowSizeOfExcludingThis(aMallocSizeOf) +
-                     mVisibleRegions->mInDisplayPort.ShallowSizeOfExcludingThis(aMallocSizeOf)
-                   : 0;
   *aPresShellSize += mFramesToDirty.ShallowSizeOfExcludingThis(aMallocSizeOf);
   *aPresShellSize += aArenaObjectsSize->mOther;
 
   if (nsStyleSet* styleSet = StyleSet()->GetAsGecko()) {
     *aStyleSetsSize += styleSet->SizeOfIncludingThis(aMallocSizeOf);
   } else {
     NS_WARNING("ServoStyleSets do not support memory measurements yet");
   }
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -33,17 +33,16 @@
 #include "nsRefreshDriver.h"
 #include "TouchManager.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/UniquePtr.h"
 #include "MobileViewportManager.h"
-#include "Visibility.h"
 #include "ZoomConstraintsClient.h"
 
 class nsRange;
 
 struct RangePaintInfo;
 struct nsCallbackEventRequest;
 #ifdef MOZ_REFLOW_PERF
 class ReflowCountMgr;
@@ -77,18 +76,16 @@ class PresShell final : public nsIPresSh
                         public nsIObserver,
                         public nsSupportsWeakReference
 {
   template <typename T> using Maybe = mozilla::Maybe<T>;
   using Nothing = mozilla::Nothing;
   using OnNonvisible = mozilla::OnNonvisible;
   using RawSelectionType = mozilla::RawSelectionType;
   using SelectionType = mozilla::SelectionType;
-  template <typename T> using UniquePtr = mozilla::UniquePtr<T>;
-  using VisibilityCounter = mozilla::VisibilityCounter;
   using VisibleFrames = mozilla::VisibleFrames;
   using VisibleRegions = mozilla::VisibleRegions;
 
 public:
   PresShell();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
@@ -410,18 +407,18 @@ public:
 
   void ScheduleApproximateFrameVisibilityUpdateSoon() override;
   void ScheduleApproximateFrameVisibilityUpdateNow() override;
 
   void RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList) override;
   void RebuildApproximateFrameVisibility(nsRect* aRect = nullptr,
                                          bool aRemoveOnly = false) override;
 
-  void MarkFrameVisibleInDisplayPort(nsIFrame* aFrame) override;
-  void MarkFrameNonvisible(nsIFrame* aFrame) override;
+  void EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) override;
+  void RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) override;
 
   bool AssumeAllFramesVisible() override;
 
 
   virtual void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot) override;
 
   virtual void DispatchAfterKeyboardEvent(nsINode* aTarget,
                                           const mozilla::WidgetKeyboardEvent& aEvent,
@@ -773,56 +770,35 @@ protected:
 
   //////////////////////////////////////////////////////////////////////////////
   // Approximate frame visibility tracking implementation.
   //////////////////////////////////////////////////////////////////////////////
 
   void UpdateApproximateFrameVisibility();
   void DoUpdateApproximateFrameVisibility(bool aRemoveOnly);
 
-  void ClearVisibleFramesSets(Maybe<OnNonvisible> aNonvisibleAction = Nothing());
-  static void ClearVisibleFramesForUnvisitedPresShells(nsView* aView, bool aClear);
-  static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList);
+  void ClearApproximatelyVisibleFramesList(Maybe<mozilla::OnNonvisible> aNonvisibleAction
+                                             = Nothing());
+  static void ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear);
+  static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList,
+                                                   Maybe<VisibleRegions>& aVisibleRegions);
   void MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
                                                const nsRect& aRect,
+                                               Maybe<VisibleRegions>& aVisibleRegions,
                                                bool aRemoveOnly = false);
 
-  void DecVisibleCount(const VisibleFrames& aFrames,
-                       VisibilityCounter aCounter,
-                       Maybe<OnNonvisible> aNonvisibleAction = Nothing());
-
-  void InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter aForCounter);
-  void AddFrameToVisibleRegions(nsIFrame* aFrame, VisibilityCounter aForCounter);
-  void NotifyCompositorOfVisibleRegionsChange();
+  void DecApproximateVisibleCount(VisibleFrames& aFrames,
+                                  Maybe<OnNonvisible> aNonvisibleAction = Nothing());
 
   nsRevocableEventPtr<nsRunnableMethod<PresShell>> mUpdateApproximateFrameVisibilityEvent;
-  nsRevocableEventPtr<nsRunnableMethod<PresShell>> mNotifyCompositorOfVisibleRegionsChangeEvent;
 
   // A set of frames that were visible or could be visible soon at the time
   // that we last did an approximate frame visibility update.
   VisibleFrames mApproximatelyVisibleFrames;
 
-  // A set of frames that were visible in the displayport the last time we painted.
-  VisibleFrames mInDisplayPortFrames;
-
-  struct VisibleRegionsContainer
-  {
-    // The approximately visible regions calculated during the last update to
-    // approximate frame visibility.
-    VisibleRegions mApproximate;
-
-    // The in-displayport visible regions calculated during the last paint.
-    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;
-
 
   //////////////////////////////////////////////////////////////////////////////
   // Methods for dispatching KeyboardEvent and BeforeAfterKeyboardEvent.
   //////////////////////////////////////////////////////////////////////////////
 
   void HandleKeyboardEvent(nsINode* aTarget,
                            mozilla::WidgetKeyboardEvent& aEvent,
                            bool aEmbeddedCancelled,
--- a/layout/generic/Visibility.h
+++ b/layout/generic/Visibility.h
@@ -13,45 +13,31 @@
 #ifndef mozilla_layout_generic_Visibility_h
 #define mozilla_layout_generic_Visibility_h
 
 namespace mozilla {
 
 // Visibility states for frames.
 enum class Visibility : uint8_t
 {
-  // We're not tracking visibility for this frame.
+  // Indicates that we're not tracking visibility for this frame.
   UNTRACKED,
 
-  // This frame is nonvisible - i.e., it was not within the displayport as of
-  // the last paint (in which case it'd be IN_DISPLAYPORT) and our heuristics
-  // aren't telling us that it may become visible soon (in which case it'd be
-  // MAY_BECOME_VISIBLE).
-  NONVISIBLE,
-
-  // This frame is nonvisible now, but our heuristics tell us it may become
-  // visible soon. These heuristics are updated on a relatively slow timer, so a
-  // frame being marked MAY_BECOME_VISIBLE does not imply any particular
-  // relationship between the frame and the displayport.
-  MAY_BECOME_VISIBLE,
+  // Indicates that the frame is probably nonvisible. Visible frames *may* be
+  // APPROXIMATELY_NONVISIBLE because approximate visibility is not updated
+  // synchronously. Some truly nonvisible frames may be marked
+  // APPROXIMATELY_VISIBLE instead if our heuristics lead us to think they may
+  // be visible soon.
+  APPROXIMATELY_NONVISIBLE,
 
-  // This frame was within the displayport as of the last paint. That doesn't
-  // necessarily mean that the frame is visible - it may still lie outside the
-  // viewport - but it does mean that the user may scroll the frame into view
-  // asynchronously at any time (due to APZ), so for most purposes such a frame
-  // should be treated as truly visible.
-  IN_DISPLAYPORT
-};
-
-// The subset of the states in @Visibility which have a per-frame counter. This
-// is used in the implementation of visibility tracking.
-enum class VisibilityCounter : uint8_t
-{
-  MAY_BECOME_VISIBLE,
-  IN_DISPLAYPORT
+  // Indicates that the frame is either visible now or is likely to be visible
+  // soon according to our heuristics. As with APPROXIMATELY_NONVISIBLE, it's
+  // important to note that approximately visibility is not updated
+  // synchronously, so this information may be out of date.
+  APPROXIMATELY_VISIBLE
 };
 
 // Requested actions when frames transition to the nonvisible state.
 enum class OnNonvisible : uint8_t
 {
   DISCARD_IMAGES  // Discard images associated with the frame.
 };
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -410,17 +410,17 @@ nsFrame::nsFrame(nsStyleContext* aContex
   mStyleContext->FrameAddRef();
 #endif
 }
 
 nsFrame::~nsFrame()
 {
   MOZ_COUNT_DTOR(nsFrame);
 
-  MOZ_ASSERT(!IsVisibleOrMayBecomeVisibleSoon(),
+  MOZ_ASSERT(GetVisibility() != Visibility::APPROXIMATELY_VISIBLE,
              "Visible nsFrame is being destroyed");
 
   NS_IF_RELEASE(mContent);
 #ifdef DEBUG
   mStyleContext->FrameRelease();
 #endif
   mStyleContext->Release();
 }
@@ -549,17 +549,17 @@ nsFrame::Init(nsIContent*       aContent
     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
                        NS_FRAME_GENERATED_CONTENT |
                        NS_FRAME_IS_SVG_TEXT |
                        NS_FRAME_IN_POPUP |
                        NS_FRAME_IS_NONDISPLAY);
 
     if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) {
       // Assume all frames in popups are visible.
-      IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+      IncApproximateVisibleCount();
     }
   }
   const nsStyleDisplay *disp = StyleDisplay();
   if (disp->HasTransform(this) ||
       nsLayoutUtils::HasRelevantAnimationOfProperty(this,
                                                     eCSSProperty_transform)) {
     // The frame gets reconstructed if we toggle the -moz-transform
     // property, so we can set this bit here and then ignore it.
@@ -604,17 +604,17 @@ nsFrame::Init(nsIContent*       aContent
   }
 
   if (aContent && aContent->GetProperty(nsGkAtoms::vr_state) != nullptr) {
     AddStateBits(NS_FRAME_HAS_VR_CONTENT);
   }
 
   if (PresContext()->PresShell()->AssumeAllFramesVisible() &&
       TrackingVisibility()) {
-    IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+    IncApproximateVisibleCount();
   }
 
   DidSetStyleContext(nullptr);
 
   if (::IsXULBoxWrapped(this))
     ::InitBoxMetrics(this, false);
 }
 
@@ -722,18 +722,18 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
   // Disable visibility tracking. Note that we have to do this before calling
   // NotifyDestroyingFrame(), which will clear frame properties and make us lose
   // track of whether we were previously visible or not.
   // XXX(seth): It'd be ideal to assert that we're already marked nonvisible
   // here, but it's unfortunately tricky to guarantee in the face of things like
   // frame reconstruction induced by style changes.
   DisableVisibilityTracking();
 
-  // Ensure that we're not in the visible list anymore.
-  PresContext()->GetPresShell()->MarkFrameNonvisible(this);
+  // Ensure that we're not in the approximately visible list anymore.
+  PresContext()->GetPresShell()->RemoveFrameFromApproximatelyVisibleList(this);
 
   shell->NotifyDestroyingFrame(this);
 
   if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
     shell->ClearFrameRefs(this);
   }
 
   if (view) {
@@ -1472,55 +1472,45 @@ nsIFrame::GetCrossDocChildLists(nsTArray
         nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
         nsIFrame::kPrincipalList));
     }
   }
 
   GetChildLists(aLists);
 }
 
-static Visibility
-VisibilityStateAsVisibility(const nsIFrame::VisibilityState& aState)
-{
-  if (aState.mInDisplayPortCounter > 0) {
-    return Visibility::IN_DISPLAYPORT;  // Takes priority over MAY_BECOME_VISIBLE.
-  }
-  if (aState.mApproximateCounter > 0) {
-    return Visibility::MAY_BECOME_VISIBLE;
-  }
-  return Visibility::NONVISIBLE;
-}
-
 Visibility
 nsIFrame::GetVisibility() const
 {
   if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
     return Visibility::UNTRACKED;
   }
 
   bool isSet = false;
   FrameProperties props = Properties();
-  VisibilityState state = props.Get(VisibilityStateProperty(), &isSet);
+  uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet);
 
   MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
                     "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
 
-  return VisibilityStateAsVisibility(state);
+  return visibleCount > 0
+       ? Visibility::APPROXIMATELY_VISIBLE
+       : Visibility::APPROXIMATELY_NONVISIBLE;
 }
 
 void
 nsIFrame::UpdateVisibilitySynchronously()
 {
   nsIPresShell* presShell = PresContext()->PresShell();
   if (!presShell) {
     return;
   }
 
   if (presShell->AssumeAllFramesVisible()) {
-    presShell->MarkFrameVisibleInDisplayPort(this);
+    presShell->EnsureFrameInApproximatelyVisibleList(this);
     return;
   }
 
   bool visible = true;
   nsIFrame* f = GetParent();
   nsRect rect = GetRectRelativeToSelf();
   nsIFrame* rectFrame = this;
   while (f) {
@@ -1551,19 +1541,19 @@ nsIFrame::UpdateVisibilitySynchronously(
       if (parent && parent->PresContext()->IsChrome()) {
         break;
       }
     }
     f = parent;
   }
 
   if (visible) {
-    presShell->MarkFrameVisibleInDisplayPort(this);
+    presShell->EnsureFrameInApproximatelyVisibleList(this);
   } else {
-    presShell->MarkFrameNonvisible(this);
+    presShell->RemoveFrameFromApproximatelyVisibleList(this);
   }
 }
 
 void
 nsIFrame::EnableVisibilityTracking()
 {
   if (GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED) {
     return;  // Nothing to do.
@@ -1572,17 +1562,17 @@ nsIFrame::EnableVisibilityTracking()
   FrameProperties props = Properties();
   MOZ_ASSERT(!props.Has(VisibilityStateProperty()),
              "Shouldn't have a VisibilityStateProperty value "
              "if NS_FRAME_VISIBILITY_IS_TRACKED is not set");
 
   // Add the state bit so we know to track visibility for this frame, and
   // initialize the frame property.
   AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
-  props.Set(VisibilityStateProperty(), VisibilityState{0, 0});
+  props.Set(VisibilityStateProperty(), 0);
 
   nsIPresShell* presShell = PresContext()->PresShell();
   if (!presShell) {
     return;
   }
 
   // Schedule a visibility update. This method will virtually always be called
   // when layout has changed anyway, so it's very unlikely that any additional
@@ -1595,97 +1585,76 @@ void
 nsIFrame::DisableVisibilityTracking()
 {
   if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
     return;  // Nothing to do.
   }
 
   bool isSet = false;
   FrameProperties props = Properties();
-  VisibilityState state = props.Remove(VisibilityStateProperty(), &isSet);
+  uint32_t visibleCount = props.Remove(VisibilityStateProperty(), &isSet);
 
   MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
                     "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
 
   RemoveStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
 
-  Visibility previousVisibility = VisibilityStateAsVisibility(state);
-  if (previousVisibility == Visibility::NONVISIBLE) {
-    return;  // We were already nonvisible.
+  if (visibleCount == 0) {
+    return;  // We were nonvisible.
   }
 
   // We were visible, so send an OnVisibilityChange() notification.
-  OnVisibilityChange(Visibility::NONVISIBLE);
+  OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE);
 }
 
 void
-nsIFrame::DecVisibilityCount(VisibilityCounter aCounter,
-                             Maybe<OnNonvisible> aNonvisibleAction /* = Nothing() */)
+nsIFrame::DecApproximateVisibleCount(Maybe<OnNonvisible> aNonvisibleAction
+                                       /* = Nothing() */)
 {
   MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
 
   bool isSet = false;
   FrameProperties props = Properties();
-  VisibilityState state = props.Get(VisibilityStateProperty(), &isSet);
+  uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet);
 
   MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
                     "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
-  MOZ_ASSERT_IF(aCounter == VisibilityCounter::MAY_BECOME_VISIBLE,
-                state.mApproximateCounter > 0);
-  MOZ_ASSERT_IF(aCounter == VisibilityCounter::IN_DISPLAYPORT,
-                state.mInDisplayPortCounter > 0);
-
-  Visibility previousVisibility = VisibilityStateAsVisibility(state);
-
-  if (aCounter == VisibilityCounter::MAY_BECOME_VISIBLE) {
-    state.mApproximateCounter--;
-  } else {
-    state.mInDisplayPortCounter--;
-  }
-
-  props.Set(VisibilityStateProperty(), state);
-
-  Visibility newVisibility = VisibilityStateAsVisibility(state);
-  if (newVisibility == previousVisibility) {
-    return;  // Nothing changed.
-  }
-
-  // Our visibility just changed, so send an OnVisibilityChange() notification.
-  OnVisibilityChange(newVisibility, aNonvisibleAction);
+  MOZ_ASSERT(visibleCount > 0, "Frame is already nonvisible and we're "
+                               "decrementing its visible count?");
+
+  visibleCount--;
+  props.Set(VisibilityStateProperty(), visibleCount);
+  if (visibleCount > 0) {
+    return;
+  }
+
+  // We just became nonvisible, so send an OnVisibilityChange() notification.
+  OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE, aNonvisibleAction);
 }
 
 void
-nsIFrame::IncVisibilityCount(VisibilityCounter aCounter)
+nsIFrame::IncApproximateVisibleCount()
 {
   MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
 
   bool isSet = false;
   FrameProperties props = Properties();
-  VisibilityState state = props.Get(VisibilityStateProperty(), &isSet);
+  uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet);
 
   MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
                     "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
 
-  Visibility previousVisibility = VisibilityStateAsVisibility(state);
-
-  if (aCounter == VisibilityCounter::MAY_BECOME_VISIBLE) {
-    state.mApproximateCounter++;
-  } else {
-    state.mInDisplayPortCounter++;
-  }
-
-  props.Set(VisibilityStateProperty(), state);
-
-  Visibility newVisibility = VisibilityStateAsVisibility(state);
-  if (newVisibility == previousVisibility) {
-    return;  // Nothing changed.
-  }
-
-  // Our visibility just changed, so send an OnVisibilityChange() notification.
-  OnVisibilityChange(newVisibility);
+  visibleCount++;
+  props.Set(VisibilityStateProperty(), visibleCount);
+  if (visibleCount > 1) {
+    return;
+  }
+
+  // We just became visible, so send an OnVisibilityChange() notification.
+  OnVisibilityChange(Visibility::APPROXIMATELY_VISIBLE);
 }
 
 void
 nsIFrame::OnVisibilityChange(Visibility aNewVisibility,
                              Maybe<OnNonvisible> aNonvisibleAction
                                /* = Nothing() */)
 {
   // XXX(seth): In bug 1218990 we'll implement visibility tracking for CSS
@@ -9270,17 +9239,17 @@ nsFrame::BoxMetrics() const
 }
 
 /* static */ void
 nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
 {
   if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) &&
       aFrame->TrackingVisibility()) {
     // Assume all frames in popups are visible.
-    aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+    aFrame->IncApproximateVisibleCount();
   }
 
   aFrame->AddStateBits(NS_FRAME_IN_POPUP);
 
   AutoTArray<nsIFrame::ChildList,4> childListArray;
   aFrame->GetCrossDocChildLists(&childListArray);
 
   nsIFrame::ChildListArrayIterator lists(childListArray);
@@ -9300,17 +9269,17 @@ nsIFrame::RemoveInPopupStateBitFromDesce
     return;
   }
 
   aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
 
   if (aFrame->TrackingVisibility()) {
     // We assume all frames in popups are visible, so this decrement balances
     // out the increment in AddInPopupStateBitToDescendants above.
-    aFrame->DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+    aFrame->DecApproximateVisibleCount();
   }
 
   AutoTArray<nsIFrame::ChildList,4> childListArray;
   aFrame->GetCrossDocChildLists(&childListArray);
 
   nsIFrame::ChildListArrayIterator lists(childListArray);
   for (; !lists.IsDone(); lists.Next()) {
     nsFrameList::Enumerator childFrames(lists.CurrentList());
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -422,17 +422,16 @@ public:
   template <typename T> using Maybe = mozilla::Maybe<T>;
   using Nothing = mozilla::Nothing;
   using OnNonvisible = mozilla::OnNonvisible;
   template<typename T=void>
   using PropertyDescriptor = const mozilla::FramePropertyDescriptor<T>*;
   using ReflowInput = mozilla::ReflowInput;
   using ReflowOutput = mozilla::ReflowOutput;
   using Visibility = mozilla::Visibility;
-  using VisibilityCounter = mozilla::VisibilityCounter;
 
   typedef mozilla::FrameProperties FrameProperties;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layout::FrameChildList ChildList;
   typedef mozilla::layout::FrameChildListID ChildListID;
   typedef mozilla::layout::FrameChildListIDs ChildListIDs;
   typedef mozilla::layout::FrameChildListIterator ChildListIterator;
   typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator;
@@ -1109,44 +1108,29 @@ public:
   {
     return bool(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
   }
 
   /// @return the visibility state of this frame. See the Visibility enum
   /// for the possible return values and their meanings.
   Visibility GetVisibility() const;
 
-  /// @return true if this frame is either in the displayport now or may
-  /// become visible soon.
-  bool IsVisibleOrMayBecomeVisibleSoon() const
-  {
-    Visibility visibility = GetVisibility();
-    return visibility == Visibility::MAY_BECOME_VISIBLE ||
-           visibility == Visibility::IN_DISPLAYPORT;
-  }
-
   /// Update the visibility state of this frame synchronously.
   /// XXX(seth): Avoid using this method; we should be relying on the refresh
   /// driver for visibility updates. This method, which replaces
   /// nsLayoutUtils::UpdateApproximateFrameVisibility(), exists purely as a
   /// temporary measure to avoid changing behavior during the transition from
   /// the old image visibility code.
   void UpdateVisibilitySynchronously();
 
-  struct VisibilityState
-  {
-    unsigned int mApproximateCounter : 16;
-    unsigned int mInDisplayPortCounter : 16;
-  };
-
-  // A frame property which stores the visibility state of this frame, which
-  // consists of a VisibilityState value that stores counters for each type of
-  // visibility we track. When the visibility of this frame is not being
-  // tracked, this property is absent.
-  NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, VisibilityState);
+  // A frame property which stores the visibility state of this frame. Right
+  // now that consists of an approximate visibility counter represented as a
+  // uint32_t. When the visibility of this frame is not being tracked, this
+  // property is absent.
+  NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, uint32_t);
 
 protected:
 
   /**
    * Subclasses can call this method to enable visibility tracking for this frame.
    *
    * If visibility tracking was previously disabled, this will schedule an
    * update an asynchronous update of visibility.
@@ -1181,39 +1165,31 @@ protected:
 
 public:
 
   ///////////////////////////////////////////////////////////////////////////////
   // Internal implementation for the approximate frame visibility API.
   ///////////////////////////////////////////////////////////////////////////////
 
   /**
-   * We track the visibility of frames using counters; if any of the counters
-   * are non-zero, then the frame is considered visible. Using counters allows
-   * us to account for situations where the frame may be visible in more than
-   * one place (for example, via -moz-element), and it simplifies the
+   * We track the approximate visibility of frames using a counter; if it's
+   * non-zero, then the frame is considered visible. Using a counter allows us
+   * to account for situations where the frame may be visible in more than one
+   * place (for example, via -moz-element), and it simplifies the
    * implementation of our approximate visibility tracking algorithms.
    *
-   * There are two visibility counters for each frame: the approximate counter
-   * (which is based on our heuristics for which frames may become visible
-   * "soon"), and the in-displayport counter (which records if the frame was
-   * within the displayport at the last paint).
-   *
-   *
-   * @param aCounter          Which counter to increment or decrement.
    * @param aNonvisibleAction A requested action if the frame has become
    *                          nonvisible. If Nothing(), no action is
    *                          requested. If DISCARD_IMAGES is specified, the
    *                          frame is requested to ask any images it's
    *                          associated with to discard their surfaces if
    *                          possible.
    */
-  void DecVisibilityCount(VisibilityCounter aCounter,
-                          Maybe<OnNonvisible> aNonvisibleAction = Nothing());
-  void IncVisibilityCount(VisibilityCounter aCounter);
+  void DecApproximateVisibleCount(Maybe<OnNonvisible> aNonvisibleAction = Nothing());
+  void IncApproximateVisibleCount();
 
 
   /**
    * Get the specified child list.
    *
    * @param   aListID identifies the requested child list.
    * @return  the child list.  If the requested list is unsupported by this
    *          frame type, an empty list will be returned.
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -713,17 +713,17 @@ nsImageFrame::MaybeDecodeForPredictedSiz
   if (!mImage) {
     return;  // Nothing to do yet.
   }
 
   if (mComputedSize.IsEmpty()) {
     return;  // We won't draw anything, so no point in decoding.
   }
 
-  if (!IsVisibleOrMayBecomeVisibleSoon()) {
+  if (GetVisibility() != Visibility::APPROXIMATELY_VISIBLE) {
     return;  // We're not visible, so don't decode.
   }
 
   // OK, we're ready to decode. Compute the scale to the screen...
   nsIPresShell* presShell = PresContext()->GetPresShell();
   LayoutDeviceToScreenScale2D resolutionToScreen(
       presShell->GetCumulativeResolution()
     * nsLayoutUtils::GetTransformToAncestorScaleExcludingAnimated(this));
@@ -2096,18 +2096,17 @@ nsImageFrame::OnVisibilityChange(Visibil
   if (!imageLoader) {
     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
     nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
-  if (aNewVisibility == Visibility::MAY_BECOME_VISIBLE ||
-      aNewVisibility == Visibility::IN_DISPLAYPORT) {
+  if (aNewVisibility == Visibility::APPROXIMATELY_VISIBLE) {
     MaybeDecodeForPredictedSize();
   }
 
   nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
 nsIAtom*
 nsImageFrame::GetType() const
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -79,17 +79,17 @@ NS_NewSVGFEImageFrame(nsIPresShell* aPre
   return new (aPresShell) SVGFEImageFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(SVGFEImageFrame)
 
 /* virtual */ void
 SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
-  DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+  DecApproximateVisibleCount();
 
   nsCOMPtr<nsIImageLoadingContent> imageLoader =
     do_QueryInterface(nsFrame::mContent);
   if (imageLoader) {
     imageLoader->FrameDestroyed(this);
   }
 
   nsFrame::DestroyFrom(aDestructRoot);
@@ -102,17 +102,17 @@ SVGFEImageFrame::Init(nsIContent*       
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::feImage),
                "Trying to construct an SVGFEImageFrame for a "
                "content element that doesn't support the right interfaces");
 
   nsFrame::Init(aContent, aParent, aPrevInFlow);
 
   // We assume that feImage's are always visible.
-  IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+  IncApproximateVisibleCount();
 
   nsCOMPtr<nsIImageLoadingContent> imageLoader =
     do_QueryInterface(nsFrame::mContent);
   if (imageLoader) {
     imageLoader->FrameCreated(this);
   }
 }
 
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -154,17 +154,17 @@ nsSVGImageFrame::Init(nsIContent*       
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::image),
                "Content is not an SVG image!");
 
   nsSVGPathGeometryFrame::Init(aContent, aParent, aPrevInFlow);
 
   if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
     // Non-display frames are likely to be patterns, masks or the like.
     // Treat them as always visible.
-    IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+    IncApproximateVisibleCount();
   }
 
   mListener = new nsSVGImageListener(this);
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (!imageLoader) {
     NS_RUNTIMEABORT("Why is this not an image loading content?");
   }
 
@@ -174,17 +174,17 @@ nsSVGImageFrame::Init(nsIContent*       
 
   imageLoader->AddObserver(mListener);
 }
 
 /* virtual */ void
 nsSVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
-    DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+    DecApproximateVisibleCount();
   }
 
   if (mReflowCallbackPosted) {
     PresContext()->PresShell()->CancelReflowCallback(this);
     mReflowCallbackPosted = false;
   }
 
   nsCOMPtr<nsIImageLoadingContent> imageLoader =