Bug 1159042 - p5. Add NS_FRAME_DYNAMIC_REFLOW_ROOT on frames that we can dynamically make reflow roots - r=dholbert
☠☠ backed out by d5a15c64bd40 ☠ ☠
authorL. David Baron <dbaron@dbaron.org>
Mon, 26 Nov 2018 23:21:54 +0000
changeset 507377 db0e173a6ed2ed65c22a2e60bc3f358e3d19d82c
parent 507376 080b9ceee8eca10edabc249172d7f113c3642873
child 507378 fe77c09dee3107e675162b760a6efa9b5f0bcce3
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)
reviewersdholbert
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 - p5. Add NS_FRAME_DYNAMIC_REFLOW_ROOT on frames that we can dynamically make reflow roots - r=dholbert Differential Revision: https://phabricator.services.mozilla.com/D9491
layout/generic/ReflowInput.cpp
layout/generic/ReflowInput.h
layout/generic/nsFrameStateBits.h
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -424,16 +424,17 @@ ReflowInput::Init(nsPresContext*     aPr
   LogicalSize cbSize(mWritingMode, -1, -1);
   if (aContainingBlockSize) {
     cbSize = *aContainingBlockSize;
   }
 
   InitConstraints(aPresContext, cbSize, aBorder, aPadding, type);
 
   InitResizeFlags(aPresContext, type);
+  InitDynamicReflowRoot();
 
   nsIFrame *parent = mFrame->GetParent();
   if (parent &&
       (parent->GetStateBits() & NS_FRAME_IN_CONSTRAINED_BSIZE) &&
       !(parent->IsScrollFrame() &&
         parent->StyleDisplay()->mOverflowY != NS_STYLE_OVERFLOW_HIDDEN)) {
     mFrame->AddStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
   } else if (type == LayoutFrameType::SVGForeignObject) {
@@ -827,16 +828,110 @@ ReflowInput::InitResizeFlags(nsPresConte
   }
   if (mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) {
     // If we're reflowing everything, then we'll find out if we need
     // to re-set this.
     mFrame->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
   }
 }
 
+static inline bool
+IsIntrinsicKeyword(const nsStyleCoord& aCoord)
+{
+  if (aCoord.GetUnit() != eStyleUnit_Enumerated) {
+    return false;
+  }
+
+  // All of the keywords except for '-moz-available' depend on intrinsic sizes.
+  return aCoord.GetIntValue() != NS_STYLE_WIDTH_AVAILABLE;
+}
+
+void
+ReflowInput::InitDynamicReflowRoot()
+{
+  auto display = mStyleDisplay->mDisplay;
+  if (mFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
+      nsStyleDisplay::IsRubyDisplayType(display) ||
+      mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE ||
+      display == StyleDisplay::Table ||
+      display == StyleDisplay::TableCaption ||
+      display == StyleDisplay::InlineTable ||
+      (mFrame->GetParent() && mFrame->GetParent()->IsXULBoxFrame())) {
+    // We have a display type where 'width' and 'height' don't actually
+    // set the width or height (i.e., the size depends on content).
+    NS_ASSERTION(!(mFrame->GetStateBits() & NS_FRAME_DYNAMIC_REFLOW_ROOT),
+                 "should not have dynamic reflow root bit");
+    return;
+  }
+
+  bool canBeDynamicReflowRoot = true;
+
+  // We can't do this if our used 'width' and 'height' might be influenced by
+  // content.
+  // FIXME: For display:block, we should probably optimize inline-size
+  // being auto.
+  // FIXME: Other flex and grid cases?
+  const nsStyleCoord& width = mStylePosition->mWidth;
+  const nsStyleCoord& height = mStylePosition->mHeight;
+  if (!width.IsCoordPercentCalcUnit() ||
+      width.HasPercent() ||
+      !height.IsCoordPercentCalcUnit() ||
+      height.HasPercent() ||
+      IsIntrinsicKeyword(mStylePosition->mMinWidth) ||
+      IsIntrinsicKeyword(mStylePosition->mMaxWidth) ||
+      IsIntrinsicKeyword(mStylePosition->mMinHeight) ||
+      IsIntrinsicKeyword(mStylePosition->mMaxHeight) ||
+      ((mStylePosition->mMinWidth.GetUnit() == eStyleUnit_Auto ||
+        mStylePosition->mMinHeight.GetUnit() == eStyleUnit_Auto) &&
+       mFrame->IsFlexOrGridItem())) {
+    canBeDynamicReflowRoot = false;
+  }
+
+  if (mFrame->IsFlexItem()) {
+    // If our flex-basis is 'auto', it'll defer to 'width' (or 'height') which
+    // we've already checked. Otherwise, it preempts them, so we need to
+    // perform the same "could-this-value-be-influenced-by-content" checks that
+    // we performed for 'width' and 'height' above.
+    const nsStyleCoord& flexBasis = mStylePosition->mFlexBasis;
+    if (flexBasis.GetUnit() != eStyleUnit_Auto &&
+        (!flexBasis.IsCoordPercentCalcUnit() || flexBasis.HasPercent())) {
+      canBeDynamicReflowRoot = false;
+    }
+  }
+
+  if (!mFrame->IsFixedPosContainingBlock()) {
+    // We can't treat this frame as a reflow root, since dynamic changes
+    // to absolutely-positioned frames inside of it require that we
+    // reflow the placeholder before we reflow the absolutely positioned
+    // frame.
+    // FIXME:  Alternatively, we could sort the reflow roots in
+    // PresShell::ProcessReflowCommands by depth in the tree, from
+    // deepest to least deep.  However, for performance (FIXME) we
+    // should really be sorting them in the opposite order!
+    canBeDynamicReflowRoot = false;
+  } else {
+    MOZ_ASSERT(mFrame->IsAbsPosContainingBlock(),
+               "we need the frame to be both an abs-pos and fixed-pos cb");
+  }
+
+  // If we participate in a container's block reflow context, or margins
+  // can collapse through us, we can't be a dynamic reflow root.
+  if (canBeDynamicReflowRoot &&
+      mFrame->IsFrameOfType(nsIFrame::eBlockFrame) &&
+      !mFrame->HasAllStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT)) {
+    canBeDynamicReflowRoot = false;
+  }
+
+  if (canBeDynamicReflowRoot) {
+    mFrame->AddStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
+  } else {
+    mFrame->RemoveStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
+  }
+}
+
 nscoord
 ReflowInput::GetContainingBlockContentISize(WritingMode aWritingMode) const
 {
   if (!mCBReflowInput) {
     return 0;
   }
   return mCBReflowInput->GetWritingMode().IsOrthogonalTo(aWritingMode)
     ? mCBReflowInput->ComputedBSize()
--- a/layout/generic/ReflowInput.h
+++ b/layout/generic/ReflowInput.h
@@ -958,16 +958,17 @@ public:
                                        void* aValue);
 #endif
 
 protected:
   void InitFrameType(LayoutFrameType aFrameType);
   void InitCBReflowInput();
   void InitResizeFlags(nsPresContext* aPresContext,
                        mozilla::LayoutFrameType aFrameType);
+  void InitDynamicReflowRoot();
 
   void InitConstraints(nsPresContext* aPresContext,
                        const mozilla::LogicalSize& aContainingBlockSize,
                        const nsMargin* aBorder,
                        const nsMargin* aPadding,
                        mozilla::LayoutFrameType aFrameType);
 
   // Returns the nearest containing block or block frame (whether or not
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -230,18 +230,19 @@ FRAME_STATE_BIT(Generic, 43, NS_FRAME_SV
 // ColumnSetWrapperFrame nested inside a column does have this bit set.
 //
 // All the children of the column-spanners or any other type of frames which
 // create their own block formatting context do not have this bit set because
 // they are not in the same block formatting context created by a multi-column
 // ancestor.
 FRAME_STATE_BIT(Generic, 44, NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)
 
-// Bits 45 is currently unused, but be kind and check with bug 1465474
-// first please :-)
+// If this bit is set, then reflow may be dispatched from the current
+// frame instead of the root frame.
+FRAME_STATE_BIT(Generic, 45, NS_FRAME_DYNAMIC_REFLOW_ROOT)
 
 // This bit indicates that we're tracking visibility for this frame, and that
 // the frame has a VisibilityStateProperty property.
 FRAME_STATE_BIT(Generic, 46, NS_FRAME_VISIBILITY_IS_TRACKED)
 
 // The frame is a descendant of SVGTextFrame and is thus used for SVG
 // text layout.
 FRAME_STATE_BIT(Generic, 47, NS_FRAME_IS_SVG_TEXT)
@@ -291,17 +292,19 @@ FRAME_STATE_BIT(Generic, 58, NS_FRAME_MA
 // This state bit is set on frames within token MathML elements if the
 // token represents an <mi> tag whose inner HTML consists of a single
 // non-whitespace character to allow special rendering behaviour.
 FRAME_STATE_BIT(Generic, 59, NS_FRAME_IS_IN_SINGLE_CHAR_MI)
 
 // NOTE: Bits 20-31 and 60-63 of the frame state are reserved for specific
 // frame classes.
 
-// NOTE: Currently unused and available bit(s): 45.
+// NOTE: No more unused bits. If needed, investigate removing obsolete bits by
+// adjusting logic, or moving infrequently-used bits elsewhere. If more space
+// for frame state is still needed, look for bit field gaps in nsIFrame.
 
 
 // == Frame state bits that apply to box frames ===============================
 
 FRAME_STATE_GROUP(Box, nsBoxFrame)
 
 FRAME_STATE_BIT(Box, 20, NS_STATE_BOX_CHILD_RESERVED)
 FRAME_STATE_BIT(Box, 21, NS_STATE_STACK_NOT_POSITIONED)