Bug 1269934 - Handle visible frame sets more generically in PresShell. r=mstange
authorSeth Fowler <mark.seth.fowler@gmail.com>
Wed, 11 May 2016 19:27:27 -0700
changeset 297080 4517cddd204ee56e5ef8ca9dbd7aed6efe911895
parent 297079 e9df21facccf419f73123fd675b9dc9823a854d2
child 297081 45c3308d49c95e37c8d1e4855231baa976a7fe9a
push id30251
push usercbook@mozilla.com
push dateThu, 12 May 2016 09:54:48 +0000
treeherdermozilla-central@c3f5e6079284 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1269934
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1269934 - Handle visible frame sets more generically in PresShell. r=mstange
dom/base/nsImageLoadingContent.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/generic/nsFrame.cpp
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -286,17 +286,17 @@ nsImageLoadingContent::OnUnlockedDraw()
     return;
   }
 
   nsIPresShell* presShell = presContext->PresShell();
   if (!presShell) {
     return;
   }
 
-  presShell->MarkFrameVisibleInDisplayPort(frame);
+  presShell->MarkFrameVisible(frame, VisibilityCounter::IN_DISPLAYPORT);
 }
 
 nsresult
 nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
 {
   bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
   if (requestFlag) {
     nsLayoutUtils::RegisterImageRequest(GetFramePresContext(),
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -42,16 +42,17 @@
 #include "nsWeakReference.h"
 #include <stdio.h> // for FILE definition
 #include "nsChangeHint.h"
 #include "nsRefPtrHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsPresArena.h"
 #include "nsMargin.h"
 #include "nsFrameState.h"
+#include "Visibility.h"
 
 #ifdef MOZ_B2G
 #include "nsIHardwareKeyHandler.h"
 #endif
 
 class nsDocShell;
 class nsIDocument;
 class nsIFrame;
@@ -180,16 +181,17 @@ enum nsRectVisibility {
 class nsIPresShell : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRESSHELL_IID)
 
 protected:
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::gfx::SourceSurface SourceSurface;
+  using VisibilityCounter = mozilla::VisibilityCounter;
 
   enum eRenderFlag {
     STATE_IGNORING_VIEWPORT_SCROLLING = 0x1,
     STATE_DRAWWINDOW_NOT_FLUSHING = 0x2
   };
   typedef uint8_t RenderFlags; // for storing the above flags
 
 public:
@@ -1587,21 +1589,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;
+  /// Adds @aFrame to the visible frames set specified by @aCounter.
+  /// VisibilityCounter::MAY_BECOME_VISIBLE is not a valid argument.
+  virtual void MarkFrameVisible(nsIFrame* aFrame, VisibilityCounter aCounter) = 0;
 
-  /// Marks @aFrame nonvisible and removes it from all lists of visible frames.
+  /// Marks @aFrame nonvisible and removes it from all sets of visible frames.
   virtual void MarkFrameNonvisible(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
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5702,19 +5702,17 @@ 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;
+  VisibleRegions& regions = mVisibleRegions->ForCounter(aForCounter);
   CSSIntRegion* regionForView = regions.LookupOrAdd(viewID);
   MOZ_ASSERT(regionForView);
 
   regionForView->OrWith(CSSPixel::FromAppUnitsRounded(frameRectInScrolledFrameSpace));
 }
 
 /* static */ void
 PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList)
@@ -5775,19 +5773,17 @@ PresShell::InitVisibleRegionsIfVisualiza
       !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;
+    VisibleRegions& regions = mVisibleRegions->ForCounter(aForCounter);
     regions.Clear();
     return;
   }
 
   mVisibleRegions = MakeUnique<VisibleRegionsContainer>();
 }
 
 void
@@ -6128,45 +6124,51 @@ PresShell::ScheduleApproximateFrameVisib
   RefPtr<nsRunnableMethod<PresShell> > ev =
     NewRunnableMethod(this, &PresShell::UpdateApproximateFrameVisibility);
   if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
     mUpdateApproximateFrameVisibilityEvent = ev;
   }
 }
 
 void
-PresShell::MarkFrameVisibleInDisplayPort(nsIFrame* aFrame)
-{
+PresShell::MarkFrameVisible(nsIFrame* aFrame, VisibilityCounter aCounter)
+{
+  MOZ_ASSERT(aCounter != VisibilityCounter::MAY_BECOME_VISIBLE,
+             "MAY_BECOME_VISIBLE should only be managed from within PresShell");
+
   if (!aFrame->TrackingVisibility()) {
     return;
   }
 
   if (AssumeAllFramesVisible()) {
+    // Force to maximum visibility (IN_DISPLAYPORT) regardless of aCounter's value.
     if (aFrame->GetVisibility() != Visibility::IN_DISPLAYPORT) {
       aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
     }
     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)) {
+  VisibleFrames& frameSet = VisibleFramesForCounter(aCounter);
+
+  if (!frameSet.Contains(aFrame)) {
     MOZ_ASSERT(!AssumeAllFramesVisible());
-    mInDisplayPortFrames.PutEntry(aFrame);
-    aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
-  }
-
-  AddFrameToVisibleRegions(aFrame, VisibilityCounter::IN_DISPLAYPORT);
+    frameSet.PutEntry(aFrame);
+    aFrame->IncVisibilityCount(aCounter);
+  }
+
+  AddFrameToVisibleRegions(aFrame, aCounter);
 }
 
 static void
 RemoveFrameFromVisibleSet(nsIFrame* aFrame,
                           VisibleFrames& aSet,
                           VisibilityCounter aCounter)
 {
   uint32_t count = aSet.Count();
--- 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;
@@ -400,17 +399,17 @@ 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 MarkFrameVisible(nsIFrame* aFrame, VisibilityCounter aCounter) override;
   void MarkFrameNonvisible(nsIFrame* aFrame) override;
 
   bool AssumeAllFramesVisible() override;
 
 
   virtual void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot) override;
 
   virtual void DispatchAfterKeyboardEvent(nsINode* aTarget,
@@ -784,25 +783,43 @@ protected:
 
   void InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter aForCounter);
   void AddFrameToVisibleRegions(nsIFrame* aFrame, VisibilityCounter aForCounter);
   void NotifyCompositorOfVisibleRegionsChange();
 
   nsRevocableEventPtr<nsRunnableMethod<PresShell>> mUpdateApproximateFrameVisibilityEvent;
   nsRevocableEventPtr<nsRunnableMethod<PresShell>> mNotifyCompositorOfVisibleRegionsChangeEvent;
 
+  VisibleFrames& VisibleFramesForCounter(VisibilityCounter aCounter)
+  {
+    switch (aCounter)
+    {
+      case VisibilityCounter::MAY_BECOME_VISIBLE: return mApproximatelyVisibleFrames;
+      case VisibilityCounter::IN_DISPLAYPORT:     return mInDisplayPortFrames;
+    }
+  }
+
   // 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
   {
+    VisibleRegions& ForCounter(VisibilityCounter aCounter)
+    {
+      switch (aCounter)
+      {
+        case VisibilityCounter::MAY_BECOME_VISIBLE: return mApproximate;
+        case VisibilityCounter::IN_DISPLAYPORT:     return mInDisplayPort;
+      }
+    }
+
     // 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;
   };
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1497,17 +1497,17 @@ void
 nsIFrame::UpdateVisibilitySynchronously()
 {
   nsIPresShell* presShell = PresContext()->PresShell();
   if (!presShell) {
     return;
   }
 
   if (presShell->AssumeAllFramesVisible()) {
-    presShell->MarkFrameVisibleInDisplayPort(this);
+    presShell->MarkFrameVisible(this, VisibilityCounter::IN_DISPLAYPORT);
     return;
   }
 
   bool visible = true;
   nsIFrame* f = GetParent();
   nsRect rect = GetRectRelativeToSelf();
   nsIFrame* rectFrame = this;
   while (f) {
@@ -1538,17 +1538,17 @@ nsIFrame::UpdateVisibilitySynchronously(
       if (parent && parent->PresContext()->IsChrome()) {
         break;
       }
     }
     f = parent;
   }
 
   if (visible) {
-    presShell->MarkFrameVisibleInDisplayPort(this);
+    presShell->MarkFrameVisible(this, VisibilityCounter::IN_DISPLAYPORT);
   } else {
     presShell->MarkFrameNonvisible(this);
   }
 }
 
 void
 nsIFrame::EnableVisibilityTracking()
 {
@@ -2720,17 +2720,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
       !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
     return;
 
   // Since we're now sure that we're adding this frame to the display list
   // (which means we're painting it, modulo occlusion), mark it as visible
   // within the displayport.
   if (aBuilder->IsPaintingToWindow() && child->TrackingVisibility()) {
     nsIPresShell* shell = child->PresContext()->PresShell();
-    shell->MarkFrameVisibleInDisplayPort(child);
+    shell->MarkFrameVisible(child, VisibilityCounter::IN_DISPLAYPORT);
   }
 
   // Child is composited if it's transformed, partially transparent, or has
   // SVG effects or a blend mode..
   const nsStyleDisplay* disp = child->StyleDisplay();
   const nsStyleEffects* effects = child->StyleEffects();
   const nsStylePosition* pos = child->StylePosition();
   bool isVisuallyAtomic = child->HasOpacity()