Bug 1159042 - p2. Allow reflow roots to have overflow, and allow that overflow to change during reflow - r=dbaron,dholbert
☠☠ backed out by d5a15c64bd40 ☠ ☠
authorL. David Baron <dbaron@dbaron.org>
Sun, 25 Nov 2018 22:07:39 +0000
changeset 507374 3a86c3e65d440cee062e7ab2446b9f1c35c6fe28
parent 507373 845bc8316b05f3186d87e143c110f7f768625836
child 507375 6a5191742ca1666d8ca6412993195a9096604128
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron, dholbert
bugs1159042
milestone65.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 1159042 - p2. Allow reflow roots to have overflow, and allow that overflow to change during reflow - r=dbaron,dholbert Differential Revision: https://phabricator.services.mozilla.com/D9488
layout/base/PresShell.cpp
layout/base/PresShell.h
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -91,16 +91,17 @@
 #include "nsRegion.h"
 #include "nsAutoLayoutPhase.h"
 #ifdef MOZ_GECKO_PROFILER
 #include "AutoProfilerStyleMarker.h"
 #endif
 #ifdef MOZ_REFLOW_PERF
 #include "nsFontMetrics.h"
 #endif
+#include "OverflowChangedTracker.h"
 #include "PositionedEventTargeting.h"
 
 #include "nsIReflowCallback.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsFocusManager.h"
 #include "nsIObjectFrame.h"
 #include "nsIObjectLoadingContent.h"
@@ -2016,26 +2017,26 @@ PresShell::ResizeReflowIgnoreOverride(ns
         nsAutoCauseReflowNotifier crNotifier(this);
         WillDoReflow();
 
         // Kick off a top-down reflow
         AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
         nsViewManager::AutoDisableRefresh refreshBlocker(viewManager);
 
         mDirtyRoots.RemoveElement(rootFrame);
-        DoReflow(rootFrame, true);
+        DoReflow(rootFrame, true, nullptr);
 
         if (shrinkToFit) {
           const bool reflowAgain = wm.IsVertical() ?
                                 mPresContext->GetVisibleArea().width > aWidth :
                                 mPresContext->GetVisibleArea().height > aHeight;
 
           if (reflowAgain) {
             mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
-            DoReflow(rootFrame, true);
+            DoReflow(rootFrame, true, nullptr);
           }
         }
       }
 
       // the first DoReflow above should've set our bsize if it was
       // NS_UNCONSTRAINEDSIZE, and the isize shouldn't be NS_UNCONSTRAINEDSIZE
       // anyway
       NS_ASSERTION(
@@ -8893,17 +8894,18 @@ PresShell::ScheduleReflowOffTimer()
         "sReflowContinueCallback",
         mDocument->EventTargetFor(TaskCategory::Other));
     return NS_SUCCEEDED(rv);
   }
   return true;
 }
 
 bool
-PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
+PresShell::DoReflow(nsIFrame* target, bool aInterruptible,
+                    OverflowChangedTracker* aOverflowTracker)
 {
 #ifdef MOZ_GECKO_PROFILER
   nsIURI* uri = mDocument->GetDocumentURI();
   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
     "PresShell::DoReflow", LAYOUT,
     uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A"));
 #endif
 
@@ -8941,16 +8943,20 @@ PresShell::DoReflow(nsIFrame* target, bo
 
   if (mReflowContinueTimer) {
     mReflowContinueTimer->Cancel();
     mReflowContinueTimer = nullptr;
   }
 
   const bool isRoot = target == mFrameConstructor->GetRootFrame();
 
+  MOZ_ASSERT(isRoot || aOverflowTracker,
+             "caller must provide overflow tracker when reflowing "
+             "non-root frames");
+
   // CreateReferenceRenderingContext can return nullptr
   RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
 
 #ifdef DEBUG
   mCurrentReflowRoot = target;
 #endif
 
   // If the target frame is the root of the frame hierarchy, then
@@ -8959,16 +8965,21 @@ PresShell::DoReflow(nsIFrame* target, bo
   WritingMode wm = target->GetWritingMode();
   LogicalSize size(wm);
   if (isRoot) {
     size = LogicalSize(wm, mPresContext->GetVisibleArea().Size());
   } else {
     size = target->GetLogicalSize();
   }
 
+  nsOverflowAreas oldOverflow; // initialized and used only when !isRoot
+  if (!isRoot) {
+    oldOverflow = target->GetOverflowAreas();
+  }
+
   NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
                "reflow roots should never split");
 
   // Don't pass size directly to the reflow state, since a
   // constrained height implies page/column breaking.
   LogicalSize reflowSize(wm, size.ISize(wm), NS_UNCONSTRAINEDSIZE);
   ReflowInput reflowInput(mPresContext, target, rcx, reflowSize,
                                 ReflowInput::CALLER_WILL_INIT);
@@ -9027,22 +9038,16 @@ PresShell::DoReflow(nsIFrame* target, bo
   // height was unconstrained to start with.
   nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.Width(), desiredSize.Height());
   NS_ASSERTION((isRoot &&
                 size.BSize(wm) == NS_UNCONSTRAINEDSIZE) ||
                (desiredSize.ISize(wm) == size.ISize(wm) &&
                 desiredSize.BSize(wm) == size.BSize(wm)),
                "non-root frame's desired size changed during an "
                "incremental reflow");
-  NS_ASSERTION(isRoot ||
-               desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget),
-               "non-root reflow roots must not have visible overflow");
-  NS_ASSERTION(isRoot ||
-               desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget),
-               "non-root reflow roots must not have scrollable overflow");
   NS_ASSERTION(status.IsEmpty(),
                "reflow roots should never split");
 
   target->SetSize(boundsRelativeToTarget.Size());
 
   // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
   // because for root frames (where they could be different, since root frames
   // are allowed to have overflow) the root view bounds need to match the
@@ -9058,16 +9063,22 @@ PresShell::DoReflow(nsIFrame* target, bo
   if (isRoot && size.BSize(wm) == NS_UNCONSTRAINEDSIZE) {
     mPresContext->SetVisibleArea(boundsRelativeToTarget);
   }
 
 #ifdef DEBUG
   mCurrentReflowRoot = nullptr;
 #endif
 
+  if (!isRoot && oldOverflow != target->GetOverflowAreas()) {
+    // The overflow area changed.  Propagate this change to ancestors.
+    aOverflowTracker->AddFrame(target->GetParent(),
+                               OverflowChangedTracker::CHILDREN_CHANGED);
+  }
+
   NS_ASSERTION(mPresContext->HasPendingInterrupt() ||
                mFramesToDirty.Count() == 0,
                "Why do we need to dirty anything if not interrupted?");
 
   mIsReflowing = false;
   bool interrupted = mPresContext->HasPendingInterrupt();
   if (interrupted) {
     // Make sure target gets reflowed again.
@@ -9174,37 +9185,41 @@ PresShell::ProcessReflowCommands(bool aI
 
     // Scope for the reflow entry point
     {
       nsAutoScriptBlocker scriptBlocker;
       WillDoReflow();
       AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
       nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
 
+      OverflowChangedTracker overflowTracker;
+
       do {
         // Send an incremental reflow notification to the target frame.
         int32_t idx = mDirtyRoots.Length() - 1;
         nsIFrame *target = mDirtyRoots[idx];
         mDirtyRoots.RemoveElementAt(idx);
 
         if (!NS_SUBTREE_DIRTY(target)) {
           // It's not dirty anymore, which probably means the notification
           // was posted in the middle of a reflow (perhaps with a reflow
           // root in the middle).  Don't do anything.
           continue;
         }
 
-        interrupted = !DoReflow(target, aInterruptible);
+        interrupted = !DoReflow(target, aInterruptible, &overflowTracker);
 
         // Keep going until we're out of reflow commands, or we've run
         // past our deadline, or we're interrupted.
       } while (!interrupted && !mDirtyRoots.IsEmpty() &&
                (!aInterruptible || PR_IntervalNow() < deadline));
 
       interrupted = !mDirtyRoots.IsEmpty();
+
+      overflowTracker.Flush();
     }
 
     // Exiting the scriptblocker might have killed us
     if (!mIsDestroying) {
       DidDoReflow(aInterruptible);
     }
 
     // DidDoReflow might have killed us
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -46,16 +46,17 @@ class AutoPointerEventTargetUpdater;
 namespace mozilla {
 
 namespace dom {
 class Element;
 class Selection;
 }  // namespace dom
 
 class EventDispatchingCallback;
+class OverflowChangedTracker;
 
 // A set type for tracking visible frames, for use by the visibility code in
 // PresShell. The set contains nsIFrame* pointers.
 typedef nsTHashtable<nsPtrHashKey<nsIFrame>> VisibleFrames;
 
 // This is actually pref-controlled, but we use this value if we fail
 // to get the pref for any reason.
 #ifdef MOZ_WIDGET_ANDROID
@@ -446,17 +447,20 @@ private:
   // called off a timer, otherwise it is called directly.
   void     MaybeScheduleReflow();
   // Actually schedules a reflow.  This should only be called by
   // MaybeScheduleReflow and the reflow timer ScheduleReflowOffTimer
   // sets up.
   void     ScheduleReflow();
 
   // DoReflow returns whether the reflow finished without interruption
-  bool DoReflow(nsIFrame* aFrame, bool aInterruptible);
+  // If aFrame is not the root frame, the caller must pass a non-null
+  // aOverflowTracker.
+  bool DoReflow(nsIFrame* aFrame, bool aInterruptible,
+                mozilla::OverflowChangedTracker* aOverflowTracker);
 #ifdef DEBUG
   void DoVerifyReflow();
   void VerifyHasDirtyRootAncestor(nsIFrame* aFrame);
 #endif
 
   // Helper for ScrollContentIntoView
   void DoScrollContentIntoView();