Bug 1396018: Don't pass aFlags all the way through RecreateFramesForContent. r=bz
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 01 Sep 2017 16:10:49 +0200
changeset 428855 911c5220cc3e74419f1163aa3caba121ee651167
parent 428854 5c18cf6c6ebdb79c12ef9941e3fe6c37cde2fef6
child 428856 6b0b2d0e08aae0baa13dc198ad14c4ea051c11df
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1396018
milestone57.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 1396018: Don't pass aFlags all the way through RecreateFramesForContent. r=bz We currently use the aFlags argument of ContentRemoved for two purposes: (1) To determine when a frame is being removed due to its element being removed from the DOM, so we reframe its now-possibly-no-longer-suppressed whitespace siblings as needed. In other cases, our ContentRemoved call will be followed by a ContentInserted call, which will end up doing AddTextItemIfNeeded() to generate the relevant textframes if they're necessary. Since we only need to tell apart the "DOM removal" and "anything else" cases, we don't need to thread the aFlags argument through all the ways ContentRemoved can call itself (on an ancestor). All those cases should just be treated as "not DOM removal". In particular, even if the original call _was_ for a DOM removal, if we convert it to an ancestor reframe, which will call ContentInserted on the ancestor as well, we don't need to do anything with text siblings of the ancestor. (2) To save the frame tree state from DestroyFramesFor, but the frame tree state is unconditionally captured on RecreateFramesForContent, so we only need to care about it in the original ContentRemoved call. Because of that, we can move that to the callsite, patch incoming for that. MozReview-Commit-ID: Gy5IhUysBlz Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
layout/base/GeckoRestyleManager.cpp
layout/base/PresShell.cpp
layout/base/RestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -219,18 +219,17 @@ GeckoRestyleManager::RestyleElement(Elem
         return;
       }
     }
   }
 
   if (aMinHint & nsChangeHint_ReconstructFrame) {
     FrameConstructor()->RecreateFramesForContent(
       aElement,
-      nsCSSFrameConstructor::InsertionKind::Sync,
-      nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION);
+      nsCSSFrameConstructor::InsertionKind::Sync);
   } else if (aPrimaryFrame) {
     ComputeAndProcessStyleChange(aPrimaryFrame, aMinHint, aRestyleTracker,
                                  aRestyleHint, aRestyleHintData);
   } else if (aRestyleHint & ~eRestyle_LaterSiblings) {
     // We're restyling an element with no frame, so we should try to
     // make one if its new style says it should have one.  But in order
     // to try to honor the restyle hint (which we'd like to do so that,
     // for example, an animation-only style flush doesn't flush other
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4504,16 +4504,17 @@ PresShell::ContentRemoved(nsIDocument *a
     nsIPresShell::PointerCaptureInfo* data = iter.UserData();
     if (data && data->mPendingContent &&
         nsContentUtils::ContentIsDescendantOf(data->mPendingContent, aChild)) {
       nsIPresShell::ReleasePointerCapturingContent(iter.Key());
     }
   }
 
   mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
+                                    nsCSSFrameConstructor::InsertionKind::Async,
                                     nsCSSFrameConstructor::REMOVE_CONTENT);
 
   if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
     MOZ_ASSERT(container == aDocument);
     NotifyFontSizeInflationEnabledIsDirty();
   }
 
   VERIFY_STYLE_TREE;
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1499,19 +1499,17 @@ RestyleManager::ProcessRestyledFrames(ns
       // restyle we're processing here is an animation restyle, but
       // the style resolution we will do for the frame construction
       // happens async when we're not in an animation restyle already,
       // problems could arise.
       // We could also have problems with triggering of CSS transitions
       // on elements whose frames are reconstructed, since we depend on
       // the reconstruction happening synchronously.
       frameConstructor->RecreateFramesForContent(
-        content,
-        nsCSSFrameConstructor::InsertionKind::Sync,
-        nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION);
+        content, nsCSSFrameConstructor::InsertionKind::Sync);
     } else {
       NS_ASSERTION(frame, "This shouldn't happen");
 
       if (!frame->FrameMaintainsOverflow()) {
         // frame does not maintain overflow rects, so avoid calling
         // FinishAndStoreOverflow on it:
         hint &= ~(nsChangeHint_UpdateOverflow |
                   nsChangeHint_ChildrenOnlyTransform |
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -6415,18 +6415,17 @@ IsRootBoxFrame(nsIFrame *aFrame)
 void
 nsCSSFrameConstructor::ReconstructDocElementHierarchy()
 {
   Element* rootElement = mDocument->GetRootElement();
   if (!rootElement) {
     /* nothing to do */
     return;
   }
-  RecreateFramesForContent(rootElement, InsertionKind::Sync,
-                           REMOVE_FOR_RECONSTRUCTION);
+  RecreateFramesForContent(rootElement, InsertionKind::Sync);
 }
 
 nsContainerFrame*
 nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame,
                                                   ContainingBlockType aType)
 {
   // Starting with aFrame, look for a frame that is absolutely positioned or
   // relatively positioned (and transformed, if aType is FIXED)
@@ -7536,18 +7535,17 @@ nsCSSFrameConstructor::MaybeRecreateForF
   if (aParentFrame->IsFrameSetFrame()) {
     // Check whether we have any kids we care about.
     for (nsIContent* cur = aStartChild;
          cur != aEndChild;
          cur = cur->GetNextSibling()) {
       if (IsSpecialFramesetChild(cur)) {
         // Just reframe the parent, since framesets are weird like that.
         RecreateFramesForContent(aParentFrame->GetContent(),
-                                 InsertionKind::Sync,
-                                 REMOVE_FOR_RECONSTRUCTION);
+                                 InsertionKind::Sync);
         return true;
       }
     }
   }
   return false;
 }
 
 void
@@ -7685,18 +7683,17 @@ nsCSSFrameConstructor::ContentAppended(n
 
   if (isNewShadowTreeContent) {
     // Recreate frames if content is appended into a ShadowRoot
     // because children of ShadowRoot are rendered in place of children
     // of the host.
     //XXXsmaug This is super unefficient!
     nsIContent* bindingParent = aContainer->GetBindingParent();
     LAYOUT_PHASE_TEMP_EXIT();
-    RecreateFramesForContent(bindingParent, InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+    RecreateFramesForContent(bindingParent, InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   LAYOUT_PHASE_TEMP_EXIT();
   InsertionPoint insertion =
     GetRangeInsertionPoint(aContainer, aFirstNewContent, nullptr,
                            aAllowLazyConstruction, aForReconstruction);
@@ -7717,19 +7714,17 @@ nsCSSFrameConstructor::ContentAppended(n
     // Nothing to do here; we shouldn't be constructing kids of leaves
     // Clear lazy bits so we don't try to construct again.
     ClearLazyBits(aFirstNewContent, nullptr);
     return;
   }
 
   if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
     LAYOUT_PHASE_TEMP_EXIT();
-    RecreateFramesForContent(parentFrame->GetContent(),
-                             InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+    RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   // If the frame we are manipulating is a ib-split frame (that is, one
   // that's been created as a result of a block-in-inline situation) then we
   // need to append to the last ib-split sibling, not to the frame itself.
   bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
@@ -8170,18 +8165,17 @@ nsCSSFrameConstructor::ContentRangeInser
 
   if (isNewShadowTreeContent) {
     // Recreate frames if content is inserted into a ShadowRoot
     // because children of ShadowRoot are rendered in place of
     // the children of the host.
     //XXXsmaug This is super unefficient!
     nsIContent* bindingParent = aContainer->GetBindingParent();
     LAYOUT_PHASE_TEMP_EXIT();
-    RecreateFramesForContent(bindingParent, InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+    RecreateFramesForContent(bindingParent, InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   InsertionPoint insertion;
   if (isSingleInsert) {
     // See if we have an XBL insertion point. If so, then that's our
     // real parent frame; if not, then the frame hasn't been built yet
@@ -8234,50 +8228,47 @@ nsCSSFrameConstructor::ContentRangeInser
     // Just reframe the parent, since figuring out whether this
     // should be the new legend and then handling it is too complex.
     // We could do a little better here --- check if the fieldset already
     // has a legend which occurs earlier in its child list than this node,
     // and if so, proceed. But we'd have to extend nsFieldSetFrame
     // to locate this legend in the inserted frames and extract it.
     LAYOUT_PHASE_TEMP_EXIT();
     RecreateFramesForContent(insertion.mParentFrame->GetContent(),
-                             InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+                             InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   // We should only get here with details when doing a single insertion because
   // we treat details frame as if it has multiple insertion points.
   MOZ_ASSERT(isSingleInsert || frameType != LayoutFrameType::Details);
   if (frameType == LayoutFrameType::Details) {
     // When inserting an element into <details>, just reframe the details frame
     // and let it figure out where the element should be laid out. It might seem
     // expensive to recreate the entire details frame, but it's the simplest way
     // to handle the insertion.
     LAYOUT_PHASE_TEMP_EXIT();
     RecreateFramesForContent(insertion.mParentFrame->GetContent(),
-                             InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+                             InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   // Don't construct kids of leaves
   if (insertion.mParentFrame->IsLeaf()) {
     // Clear lazy bits so we don't try to construct again.
     ClearLazyBits(aStartChild, aEndChild);
     return;
   }
 
   if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
     LAYOUT_PHASE_TEMP_EXIT();
     RecreateFramesForContent(insertion.mParentFrame->GetContent(),
-                             InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+                             InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   Maybe<TreeMatchContext> matchContext;
   if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
     matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
     matchContext->InitAncestors(aContainer ? aContainer->AsElement() : nullptr);
@@ -8608,28 +8599,27 @@ nsCSSFrameConstructor::ContentRangeInser
   }
 #endif
 }
 
 bool
 nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
                                       nsIContent* aChild,
                                       nsIContent* aOldNextSibling,
+                                      InsertionKind aInsertionKind,
                                       RemoveFlags aFlags)
 {
   MOZ_ASSERT(aChild);
   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   NS_PRECONDITION(mUpdateCount != 0,
                   "Should be in an update while destroying frames");
-
-  // Only recreate sync if we're already in frame construction, that is,
-  // recreate async for XBL DOM changes, and normal content removals.
-  const InsertionKind insertionKind = (aFlags == REMOVE_FOR_RECONSTRUCTION)
-                                        ? InsertionKind::Sync
-                                        : InsertionKind::Async;
+  // We only want to recreate sync if we're already in frame construction, that
+  // is, recreate async for XBL DOM changes, and normal content removals.
+  MOZ_ASSERT(aFlags == REMOVE_FOR_RECONSTRUCTION ||
+             aInsertionKind == InsertionKind::Async);
 
   nsPresContext* presContext = mPresShell->GetPresContext();
   MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
 
   if (aChild->IsHTMLElement(nsGkAtoms::body) ||
       (!aContainer && aChild->IsElement())) {
     // We might be removing the element that we propagated viewport scrollbar
     // styles from.  Recompute those. (This clause covers two of the three
@@ -8670,27 +8660,28 @@ nsCSSFrameConstructor::ContentRemoved(ns
       MOZ_ASSERT(ancestor, "we can't have a display: contents subtree root!");
     }
 
     nsIFrame* ancestorFrame = ancestor->GetPrimaryFrame();
     if (ancestorFrame->GetProperty(nsIFrame::GenConProperty())) {
       // XXXmats Can we recreate frames only for the ::after/::before content?
       // XXX Perhaps even only those that belong to the aChild sub-tree?
       LAYOUT_PHASE_TEMP_EXIT();
-      RecreateFramesForContent(ancestor, insertionKind, aFlags);
+      RecreateFramesForContent(ancestor, aInsertionKind);
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
     }
 
     FlattenedChildIterator iter(aChild);
     for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
       if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
         LAYOUT_PHASE_TEMP_EXIT();
         bool didReconstruct =
-          ContentRemoved(aChild, c, nullptr, aFlags);
+          ContentRemoved(aChild, c, nullptr, aInsertionKind,
+                         REMOVE_FOR_RECONSTRUCTION);
         LAYOUT_PHASE_TEMP_REENTER();
         if (didReconstruct) {
           return true;
         }
       }
     }
     UnregisterDisplayContentsStyleFor(aChild, aContainer);
     return false;
@@ -8733,76 +8724,73 @@ nsCSSFrameConstructor::ContentRemoved(ns
       !aContainer->IsInNativeAnonymousSubtree() &&
       !aChild->IsInNativeAnonymousSubtree()) {
     // Recreate frames if content is removed from a ShadowRoot because it may
     // contain an insertion point which can change how the host is rendered.
     //
     // XXXsmaug This is super unefficient!
     nsIContent* bindingParent = aContainer->GetBindingParent();
     LAYOUT_PHASE_TEMP_EXIT();
-    RecreateFramesForContent(bindingParent, insertionKind, aFlags);
+    RecreateFramesForContent(bindingParent, aInsertionKind);
     LAYOUT_PHASE_TEMP_REENTER();
     return true;
   }
 
   if (aFlags == REMOVE_DESTROY_FRAMES) {
     CaptureStateForFramesOf(aChild, mTempFrameTreeState);
   }
 
   if (childFrame) {
     InvalidateCanvasIfNeeded(mPresShell, aChild);
 
     // See whether we need to remove more than just childFrame
     LAYOUT_PHASE_TEMP_EXIT();
-    if (MaybeRecreateContainerForFrameRemoval(
-          childFrame, insertionKind, aFlags)) {
+    if (MaybeRecreateContainerForFrameRemoval(childFrame, aInsertionKind)) {
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
     }
     LAYOUT_PHASE_TEMP_REENTER();
 
     // Get the childFrame's parent frame
     nsIFrame* parentFrame = childFrame->GetParent();
     LayoutFrameType parentType = parentFrame->Type();
 
     if (parentType == LayoutFrameType::FrameSet &&
         IsSpecialFramesetChild(aChild)) {
       // Just reframe the parent, since framesets are weird like that.
       LAYOUT_PHASE_TEMP_EXIT();
-      RecreateFramesForContent(parentFrame->GetContent(), insertionKind,
-                               aFlags);
+      RecreateFramesForContent(parentFrame->GetContent(), aInsertionKind);
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
     }
 
     // If we're a child of MathML, then we should reframe the MathML content.
     // If we're non-MathML, then we would be wrapped in a block so we need to
     // check our grandparent in that case.
     nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
                                          ? parentFrame->GetParent()
                                          : parentFrame;
     if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
       LAYOUT_PHASE_TEMP_EXIT();
-      RecreateFramesForContent(parentFrame->GetContent(), insertionKind, aFlags);
+      RecreateFramesForContent(parentFrame->GetContent(), aInsertionKind);
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
     }
 
     // Undo XUL wrapping if it's no longer needed.
     // (If we're in the XUL block-wrapping situation, parentFrame is the
     // wrapper frame.)
     nsIFrame* grandparentFrame = parentFrame->GetParent();
     if (grandparentFrame && grandparentFrame->IsXULBoxFrame() &&
         (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
         // check if this frame is the only one needing wrapping
         aChild == AnyKidsNeedBlockParent(parentFrame->PrincipalChildList().FirstChild()) &&
         !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
       LAYOUT_PHASE_TEMP_EXIT();
-      RecreateFramesForContent(grandparentFrame->GetContent(), insertionKind,
-                               aFlags);
+      RecreateFramesForContent(grandparentFrame->GetContent(), aInsertionKind);
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
     }
 
 #ifdef ACCESSIBILITY
     if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
       accService->ContentRemoved(mPresShell, aChild);
     }
@@ -9007,18 +8995,17 @@ nsCSSFrameConstructor::CharacterDataChan
       (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
        aContent->TextIsOnlyWhitespace())) {
 #ifdef DEBUG
     nsIFrame* frame = aContent->GetPrimaryFrame();
     NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
                  "Bit should never be set on generated content");
 #endif
     LAYOUT_PHASE_TEMP_EXIT();
-    RecreateFramesForContent(aContent, InsertionKind::Sync,
-                             REMOVE_FOR_RECONSTRUCTION);
+    RecreateFramesForContent(aContent, InsertionKind::Sync);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   // Find the child frame
   nsIFrame* frame = aContent->GetPrimaryFrame();
 
   // Notify the first frame that maps the content. It will generate a reflow
@@ -9686,18 +9673,17 @@ nsCSSFrameConstructor::MaybeRecreateFram
     }
     const nsStyleDisplay* oldDisp = oldContext->PeekStyleDisplay();
     if (oldDisp &&
         DefinitelyEqualURIsAndPrincipal(disp->mBinding, oldDisp->mBinding)) {
       return newContext;
     }
   }
 
-  RecreateFramesForContent(aElement, InsertionKind::Sync,
-                           REMOVE_FOR_RECONSTRUCTION);
+  RecreateFramesForContent(aElement, InsertionKind::Sync);
   return nullptr;
 }
 
 static bool
 IsWhitespaceFrame(nsIFrame* aFrame)
 {
   MOZ_ASSERT(aFrame, "invalid argument");
   return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
@@ -9731,18 +9717,17 @@ FindPreviousNonWhitespaceSibling(nsIFram
     f = f->GetPrevSibling();
   } while (f && IsWhitespaceFrame(f));
   return f;
 }
 
 bool
 nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
   nsIFrame* aFrame,
-  InsertionKind aInsertionKind,
-  RemoveFlags aFlags)
+  InsertionKind aInsertionKind)
 {
   NS_PRECONDITION(aFrame, "Must have a frame");
   NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
   NS_PRECONDITION(aFrame == aFrame->FirstContinuation(),
                   "aFrame not the result of GetPrimaryFrame()?");
 
   if (IsFramePartOfIBSplit(aFrame)) {
     // The removal functions can't handle removal of an {ib} split directly; we
@@ -9751,25 +9736,24 @@ nsCSSFrameConstructor::MaybeRecreateCont
     if (gNoisyContentUpdates) {
       printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
              "frame=");
       nsFrame::ListTag(stdout, aFrame);
       printf(" is ib-split\n");
     }
 #endif
 
-    ReframeContainingBlock(aFrame, aInsertionKind, aFlags);
+    ReframeContainingBlock(aFrame, aInsertionKind);
     return true;
   }
 
   nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
   if (insertionFrame && insertionFrame->IsLegendFrame() &&
       aFrame->GetParent()->IsFieldSetFrame()) {
-    RecreateFramesForContent(aFrame->GetParent()->GetContent(), aInsertionKind,
-                             aFlags);
+    RecreateFramesForContent(aFrame->GetParent()->GetContent(), aInsertionKind);
     return true;
   }
 
   nsIFrame* inFlowFrame =
     (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
       aFrame->GetPlaceholderFrame() : aFrame;
   MOZ_ASSERT(inFlowFrame, "How did that happen?");
   MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
@@ -9783,17 +9767,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
 
     // Unlike adding summary element cases, we need to check children of the
     // parent details frame since at this moment the summary element has been
     // already removed from the parent details element's child list.
     if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) {
       // When removing a summary, we should reframe the parent details frame to
       // ensure that another summary is used or the default summary is
       // generated.
-      RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
+      RecreateFramesForContent(parent->GetContent(), aInsertionKind);
       return true;
     }
   }
 
   // Now check for possibly needing to reconstruct due to a pseudo parent
   // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
   // need to be checked here, since all other types of parent will be catched
   // by "Check ruby containers" section below.
@@ -9806,17 +9790,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
          parent->PrincipalChildList().OnlyChild()) ||
         // If we're a table-column-group, then the OnlyChild check above is
         // not going to catch cases when we're the first child.
         (inFlowFrame->IsTableColGroupFrame() &&
          parent->GetChildList(nsIFrame::kColGroupList).FirstChild() == inFlowFrame) ||
         // Similar if we're a table-caption.
         (inFlowFrame->IsTableCaption() &&
          parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
-      RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
+      RecreateFramesForContent(parent->GetContent(), aInsertionKind);
       return true;
     }
   }
 
   // Might need to reconstruct things if this frame's nextSibling is a table
   // or ruby pseudo, since removal of this frame might mean that this pseudo
   // needs to get merged with the frame's prevSibling if that's also a table
   // or ruby pseudo.
@@ -9835,33 +9819,33 @@ nsCSSFrameConstructor::MaybeRecreateCont
                "frame=");
         nsFrame::ListTag(stdout, aFrame);
         printf(" has a table pseudo next sibling of different type and a "
                "table pseudo prevsibling\n");
       }
 #endif
       // Good enough to recreate frames for aFrame's parent's content; even if
       // aFrame's parent is a pseudo, that'll be the right content node.
-      RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
+      RecreateFramesForContent(parent->GetContent(), aInsertionKind);
       return true;
     }
   }
 
   // Check ruby containers
   LayoutFrameType parentType = parent->Type();
   if (parentType == LayoutFrameType::Ruby ||
       RubyUtils::IsRubyContainerBox(parentType)) {
     // In ruby containers, pseudo frames may be created from
     // whitespaces or even nothing. There are two cases we actually
     // need to handle here, but hard to check exactly:
     // 1. Status of spaces beside the frame may vary, and related
     //    frames may be constructed or destroyed accordingly.
     // 2. The type of the first child of a ruby frame determines
     //    whether a pseudo ruby base container should exist.
-    RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
+    RecreateFramesForContent(parent->GetContent(), aInsertionKind);
     return true;
   }
 
   // Might need to reconstruct things if the removed frame's nextSibling is an
   // anonymous flex item.  The removed frame might've been what divided two
   // runs of inline content into two anonymous flex items, which would now
   // need to be merged.
   // NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
@@ -9874,17 +9858,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
     if (gNoisyContentUpdates) {
       printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
              "frame=");
       nsFrame::ListTag(stdout, aFrame);
       printf(" has an anonymous flex item as its next sibling\n");
     }
 #endif // DEBUG
     // Recreate frames for the flex container (the removed frame's parent)
-    RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
+    RecreateFramesForContent(parent->GetContent(), aInsertionKind);
     return true;
   }
 
   // Might need to reconstruct things if the removed frame's nextSibling is
   // null and its parent is an anonymous flex item. (This might be the last
   // remaining child of that anonymous flex item, which can then go away.)
   if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
     AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
@@ -9892,18 +9876,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
     if (gNoisyContentUpdates) {
       printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
              "frame=");
       nsFrame::ListTag(stdout, aFrame);
       printf(" has an anonymous flex item as its parent\n");
     }
 #endif // DEBUG
     // Recreate frames for the flex container (the removed frame's grandparent)
-    RecreateFramesForContent(parent->GetParent()->GetContent(), aInsertionKind,
-                             aFlags);
+    RecreateFramesForContent(parent->GetParent()->GetContent(), aInsertionKind);
     return true;
   }
 
 #ifdef MOZ_XUL
   if (aFrame->IsPopupSetFrame()) {
     nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
     if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
       ReconstructDocElementHierarchy();
@@ -9913,17 +9896,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
 #endif
 
   // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
   // a non-fluid continuation, i.e. it was split by bidi resolution
   if (!inFlowFrame->GetPrevSibling() &&
       !inFlowFrame->GetNextSibling() &&
       ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
        (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
-    RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
+    RecreateFramesForContent(parent->GetContent(), aInsertionKind);
     return true;
   }
 
   // We might still need to reconstruct things if the parent of inFlowFrame is
   // ib-split, since in that case the removal of aFrame might affect the
   // splitting of its parent.
   if (!IsFramePartOfIBSplit(parent)) {
     return false;
@@ -9949,17 +9932,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
   if (gNoisyContentUpdates) {
     printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
            "frame=");
     nsFrame::ListTag(stdout, parent);
     printf(" is ib-split\n");
   }
 #endif
 
-  ReframeContainingBlock(parent, aInsertionKind, aFlags);
+  ReframeContainingBlock(parent, aInsertionKind);
   return true;
 }
 
 void
 nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent)
 {
   nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
 
@@ -9970,18 +9953,17 @@ nsCSSFrameConstructor::UpdateTableCellSp
 
   if (cellFrame) {
     cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
   }
 }
 
 void
 nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
-                                                InsertionKind aInsertionKind,
-                                                RemoveFlags aFlags)
+                                                InsertionKind aInsertionKind)
 {
   MOZ_ASSERT(aInsertionKind != InsertionKind::Async || aContent->IsElement());
   MOZ_ASSERT(aContent);
 
   // If there is no document, we don't want to recreate frames for it.  (You
   // shouldn't generally be giving this method content without a document
   // anyway).
   // Rebuilding the frame tree can have bad effects, especially if it's the
@@ -10010,17 +9992,17 @@ nsCSSFrameConstructor::RecreateFramesFor
       frame = parentContentFrame;
     }
   }
 
   if (frame) {
     nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
     if (nonGeneratedAncestor->GetContent() != aContent) {
       return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
-                                      aInsertionKind, aFlags);
+                                      aInsertionKind);
     }
 
     if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
       // Recreate the frames for the entire nsIAnonymousContentCreator tree
       // since |frame| or one of its descendants may need an nsStyleContext
       // that associates it to a CSS pseudo-element, and only the
       // nsIAnonymousContentCreator that created this content knows how to make
       // that happen.
@@ -10030,34 +10012,32 @@ nsCSSFrameConstructor::RecreateFramesFor
         ancestor = nsLayoutUtils::GetParentOrPlaceholderFor(ancestor);
       }
       NS_ASSERTION(acc, "Where is the nsIAnonymousContentCreator? We may fail "
                         "to recreate its content correctly");
       // nsSVGUseFrame is special, and we know this is unnecessary for it.
       if (!ancestor->IsSVGUseFrame()) {
         NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
                      "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
-        return RecreateFramesForContent(ancestor->GetContent(), aInsertionKind,
-                                        aFlags);
+        return RecreateFramesForContent(ancestor->GetContent(), aInsertionKind);
       }
     }
 
     nsIFrame* parent = frame->GetParent();
     nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
     // If the parent frame is a leaf then the subsequent insert will fail to
     // create a frame, so we need to recreate the parent content. This happens
     // with native anonymous content from the editor.
     if (parent && parent->IsLeaf() && parentContent &&
         parentContent != aContent) {
-      return RecreateFramesForContent(parentContent, aInsertionKind, aFlags);
-    }
-  }
-
-  if (frame &&
-      MaybeRecreateContainerForFrameRemoval(frame, aInsertionKind, aFlags)) {
+      return RecreateFramesForContent(parentContent, aInsertionKind);
+    }
+  }
+
+  if (frame && MaybeRecreateContainerForFrameRemoval(frame, aInsertionKind)) {
     return;
   }
 
   nsINode* containerNode = aContent->GetParentNode();
   // XXXbz how can containerNode be null here?
   if (containerNode) {
     // Before removing the frames associated with the content object,
     // ask them to save their state onto a temporary state object.
@@ -10068,17 +10048,18 @@ nsCSSFrameConstructor::RecreateFramesFor
     //
     // FIXME(emilio): Do we need a strong ref here?
     nsCOMPtr<nsIContent> container = aContent->GetParent();
 
     // Remove the frames associated with the content object.
     nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ?
       nullptr : aContent->GetNextSibling();
     bool didReconstruct =
-      ContentRemoved(container, aContent, nextSibling, aFlags);
+      ContentRemoved(container, aContent, nextSibling, aInsertionKind,
+                     REMOVE_FOR_RECONSTRUCTION);
 
     if (!didReconstruct) {
       if (aInsertionKind == InsertionKind::Async) {
         // XXXmats doesn't frame state need to be restored in this case too?
         RestyleManager()->PostRestyleEvent(aContent->AsElement(),
                                            nsRestyleHint(0),
                                            nsChangeHint_ReconstructFrame);
       } else {
@@ -10100,16 +10081,17 @@ nsCSSFrameConstructor::DestroyFramesFor(
 {
   MOZ_ASSERT(aElement && aElement->GetParentNode());
 
   nsIContent* nextSibling =
     aElement->IsRootOfAnonymousSubtree() ? nullptr : aElement->GetNextSibling();
   return ContentRemoved(aElement->GetParent(),
                         aElement,
                         nextSibling,
+                        InsertionKind::Async,
                         REMOVE_DESTROY_FRAMES);
 }
 
 //////////////////////////////////////////////////////////////////////
 
 // Block frame construction code
 
 already_AddRefed<nsStyleContext>
@@ -12792,18 +12774,17 @@ nsCSSFrameConstructor::WipeContainingBlo
   // Before we go and append the frames, we must check for several
   // special situations.
 
   // Situation #1 is a XUL frame that contains frames that are required
   // to be wrapped in blocks.
   if (aFrame->IsXULBoxFrame() &&
       !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
       aItems.AnyItemsNeedBlockParent()) {
-    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
-                             REMOVE_FOR_RECONSTRUCTION);
+    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
     return true;
   }
 
   nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
 
   // Situation #2 is a flex or grid container frame into which we're inserting
   // new inline non-replaced children, adjacent to an existing anonymous
   // flex or grid item.
@@ -12812,31 +12793,28 @@ nsCSSFrameConstructor::WipeContainingBlo
       frameType == LayoutFrameType::GridContainer) {
     FCItemIterator iter(aItems);
 
     // Check if we're adding to-be-wrapped content right *after* an existing
     // anonymous flex or grid item (which would need to absorb this content).
     const bool isWebkitBox = IsFlexContainerForLegacyBox(aFrame);
     if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
         iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
-      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
-                               REMOVE_FOR_RECONSTRUCTION);
+      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
       return true;
     }
 
     // Check if we're adding to-be-wrapped content right *before* an existing
     // anonymous flex or grid item (which would need to absorb this content).
     if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
       // Jump to the last entry in the list
       iter.SetToEnd();
       iter.Prev();
       if (iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
-        RecreateFramesForContent(aFrame->GetContent(),
-                                 InsertionKind::Async,
-                                 REMOVE_FOR_RECONSTRUCTION);
+        RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
         return true;
       }
     }
   }
 
   // Situation #3 is an anonymous flex or grid item that's getting new children
   // who don't want to be wrapped.
   if (IsAnonymousFlexOrGridItem(aFrame)) {
@@ -12856,18 +12834,17 @@ nsCSSFrameConstructor::WipeContainingBlo
     // they're perfectly happy to go here -- they won't cause a reframe.
     nsIFrame* containerFrame = aFrame->GetParent();
     const bool isWebkitBox = IsFlexContainerForLegacyBox(containerFrame);
     if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState,
                                                   isWebkitBox)) {
       // We hit something that _doesn't_ need an anonymous flex item!
       // Rebuild the flex container to bust it out.
       RecreateFramesForContent(containerFrame->GetContent(),
-                               InsertionKind::Async,
-                               REMOVE_FOR_RECONSTRUCTION);
+                               InsertionKind::Async);
       return true;
     }
 
     // If we get here, then everything in |aItems| needs to be wrapped in
     // an anonymous flex or grid item.  That's where it's already going - good!
   }
 
   // Situation #4 is a ruby-related frame that's getting new children.
@@ -12880,18 +12857,17 @@ nsCSSFrameConstructor::WipeContainingBlo
   //    their sibling changes.
   // 2) The first effective child of a ruby frame must always be a ruby
   //    base container. It should be created or destroyed accordingly.
   if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
       RubyUtils::IsRubyContainerBox(frameType)) {
     // We want to optimize it better, and avoid reframing as much as
     // possible. But given the cases above, and the fact that a ruby
     // usually won't be very large, it should be fine to reframe it.
-    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
-                             REMOVE_FOR_RECONSTRUCTION);
+    RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
     return true;
   }
 
   // Situation #5 is a case when table pseudo-frames don't work out right
   ParentType parentType = GetParentType(aFrame);
   // If all the kids want a parent of the type that aFrame is, then we're all
   // set to go.  Indeed, there won't be any table pseudo-frames created between
   // aFrame and the kids, so those won't need to be merged with any table
@@ -13047,18 +13023,17 @@ nsCSSFrameConstructor::WipeContainingBlo
     // it might be empty, so recheck that too.
     if (aItems.IsEmpty()) {
       return false;
     }
 
     if (!aItems.AllWantParentType(parentType)) {
       // Reframing aFrame->GetContent() is good enough, since the content of
       // table pseudo-frames is the ancestor content.
-      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
-                               REMOVE_FOR_RECONSTRUCTION);
+      RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
       return true;
     }
   }
 
   // Now we have several cases involving {ib} splits.  Put them all in a
   // do/while with breaks to take us to the "go and reconstruct" code.
   do {
     if (IsInlineFrame(aFrame)) {
@@ -13136,25 +13111,23 @@ nsCSSFrameConstructor::WipeContainingBlo
 
   nsIContent *blockContent = aContainingBlock->GetContent();
 #ifdef DEBUG
   if (gNoisyContentUpdates) {
     printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
            static_cast<void*>(blockContent));
   }
 #endif
-  RecreateFramesForContent(blockContent, InsertionKind::Async,
-                           REMOVE_FOR_RECONSTRUCTION);
+  RecreateFramesForContent(blockContent, InsertionKind::Async);
   return true;
 }
 
 void
 nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
-                                              InsertionKind aInsertionKind,
-                                              RemoveFlags aFlags)
+                                              InsertionKind aInsertionKind)
 {
 
 #ifdef DEBUG
   // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
   // so I want to see when it is happening!  Unfortunately, it is happening way to often because
   // so much content on the web causes block-in-inline frame situations and we handle them
   // very poorly
   if (gNoisyContentUpdates) {
@@ -13186,26 +13159,24 @@ nsCSSFrameConstructor::ReframeContaining
 
     // And get the containingBlock's content
     if (nsIContent* blockContent = containingBlock->GetContent()) {
 #ifdef DEBUG
       if (gNoisyContentUpdates) {
         printf("  ==> blockContent=%p\n", static_cast<void*>(blockContent));
       }
 #endif
-      RecreateFramesForContent(blockContent->AsElement(), aInsertionKind,
-                               REMOVE_FOR_RECONSTRUCTION);
+      RecreateFramesForContent(blockContent->AsElement(), aInsertionKind);
       return;
     }
   }
 
   // If we get here, we're screwed!
   RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
-                           aInsertionKind,
-                           REMOVE_FOR_RECONSTRUCTION);
+                           aInsertionKind);
 }
 
 void
 nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
 {
   {
     nsAutoScriptBlocker scriptBlocker;
     BeginUpdate();
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -294,16 +294,29 @@ private:
                             nsIContent* aStartChild,
                             nsIContent* aEndChild,
                             nsILayoutHistoryState* aFrameState,
                             bool aAllowLazyConstruction,
                             bool aForReconstruction,
                             TreeMatchContext* aProvidedTreeMatchContext);
 
 public:
+  /**
+   * Whether insertion should be done synchronously or asynchronously.
+   *
+   * Generally, insertion is synchronous if we're reconstructing something from
+   * frame construction/reconstruction, and async if we're removing stuff, like
+   * from ContentRemoved.
+   */
+  enum class InsertionKind
+  {
+    Sync,
+    Async,
+  };
+
   // FIXME(emilio): How important is it to keep the frame tree state around for
   // REMOVE_DESTROY_FRAMES?
   //
   // Seems like otherwise we could just remove it.
   enum RemoveFlags {
     REMOVE_CONTENT, REMOVE_FOR_RECONSTRUCTION, REMOVE_DESTROY_FRAMES };
   /**
    * Recreate or destroy frames for aChild in aContainer.
@@ -319,16 +332,17 @@ public:
    * responsible for doing that, on the content returned in aDestroyedFramesFor.
    * The layout frame state is guarranted to be captured for the removed frames
    * only when aFlags == REMOVE_DESTROY_FRAMES, otherwise it will only be
    * captured if we reconstructed frames for an ancestor.
    */
   bool ContentRemoved(nsIContent* aContainer,
                       nsIContent* aChild,
                       nsIContent* aOldNextSibling,
+                      InsertionKind aInsertionKind,
                       RemoveFlags aFlags);
 
   void CharacterDataChanged(nsIContent* aContent,
                             CharacterDataChangeInfo* aInfo);
 
   // If aContent is a text node that has been optimized away due to being
   // whitespace next to a block boundary (or for some other reason), stop
   // doing that and create a frame for it if it should have one. This recreates
@@ -1777,51 +1791,36 @@ private:
    * Do nothing for other types of style changes, except for undisplayed nodes
    * (display:none/contents) which will have their style context updated in the
    * frame manager undisplayed maps.
    * @return null if frames were recreated, the new style context otherwise
    */
   nsStyleContext* MaybeRecreateFramesForElement(Element* aElement);
 
   /**
-   * Whether insertion should be done synchronously or asynchronously.
-   *
-   * Generally, insertion is synchronous if we're reconstructing something from
-   * frame construction/reconstruction, and async if we're removing stuff, like
-   * from ContentRemoved.
-   */
-  enum class InsertionKind
-  {
-    Sync,
-    Async,
-  };
-
-  /**
    * Recreate frames for aContent.
    * @param aContent the content to recreate frames for
    * @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
    */
   void RecreateFramesForContent(nsIContent*   aContent,
-                                InsertionKind aInsertionKind,
-                                RemoveFlags   aFlags);
+                                InsertionKind aInsertionKind);
 
   /**
    *  Handles change of rowspan and colspan attributes on table cells.
    */
   void UpdateTableCellSpans(nsIContent* aContent);
 
   // If removal of aFrame from the frame tree requires reconstruction of some
   // containing block (either of aFrame or of its parent) due to {ib} splits or
   // table pseudo-frames, recreate the relevant frame subtree.  The return value
   // indicates whether this happened.  aFrame must be the result of a
   // GetPrimaryFrame() call on a content node (which means its parent is also
   // not null).
   bool MaybeRecreateContainerForFrameRemoval(nsIFrame*     aFrame,
-                                             InsertionKind aInsertionKind,
-                                             RemoveFlags   aFlags);
+                                             InsertionKind aInsertionKind);
 
   nsIFrame* CreateContinuingOuterTableFrame(nsIPresShell*     aPresShell,
                                             nsPresContext*    aPresContext,
                                             nsIFrame*         aFrame,
                                             nsContainerFrame* aParentFrame,
                                             nsIContent*       aContent,
                                             nsStyleContext*   aStyleContext);
 
@@ -1935,19 +1934,17 @@ private:
   // otherwise
   bool WipeContainingBlock(nsFrameConstructorState& aState,
                              nsIFrame*                aContainingBlock,
                              nsIFrame*                aFrame,
                              FrameConstructionItemList& aItems,
                              bool                     aIsAppend,
                              nsIFrame*                aPrevSibling);
 
-  void ReframeContainingBlock(nsIFrame*     aFrame,
-                              InsertionKind aInsertionKind,
-                              RemoveFlags   aFlags);
+  void ReframeContainingBlock(nsIFrame* aFrame, InsertionKind aInsertionKind);
 
   //----------------------------------------
 
   // Methods support :first-letter style
 
   nsFirstLetterFrame*
   CreateFloatingLetterFrame(nsFrameConstructorState& aState,
                             nsIContent*              aTextContent,