Bug 1424094: Remove second argument for GetLastIBSplitSibling, and always append to the last continuation of an IB split. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 08 Dec 2017 00:24:36 +0100
changeset 709678 671d1e1f335e03011f95c24aac3b4aa00455f69b
parent 709677 73ecd6472f6fca6cba5c6a80f08a8551c5d3ea5c
child 743476 d599b818f3bf8023c82126266d6d17e0bdcab16a
push id92710
push userbmo:emilio@crisal.io
push dateFri, 08 Dec 2017 13:47:08 +0000
reviewersmats
bugs1424094
milestone59.0a1
Bug 1424094: Remove second argument for GetLastIBSplitSibling, and always append to the last continuation of an IB split. r?mats The LastContinuation stuff behavior was what we did before the other patches, so let's do that all the time to avoid surprises, though unfortunately I don't have test-cases. This effectively restores exactly the same behavior we had before all my frame constructor patches, just with less code. MozReview-Commit-ID: IkQ3H3rtlQM
layout/base/nsCSSFrameConstructor.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -550,25 +550,21 @@ static nsContainerFrame* GetIBSplitPrevS
 
   // We only store the ib-split sibling annotation with the first
   // frame in the continuation chain. Walk back to find that frame now.
   return aFrame->FirstContinuation()->
            GetProperty(nsIFrame::IBSplitPrevSibling());
 }
 
 static nsContainerFrame*
-GetLastIBSplitSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline)
-{
-  for (nsIFrame *frame = aFrame, *next; ; frame = next) {
+GetLastIBSplitSibling(nsIFrame* aFrame)
+{
+  for (nsIFrame* frame = aFrame, *next; ; frame = next) {
     next = GetIBSplitSibling(frame);
-    if (!next ||
-        (!aReturnEmptyTrailingInline && !next->PrincipalChildList().FirstChild() &&
-         !GetIBSplitSibling(next))) {
-      NS_ASSERTION(!next || !frame->IsInlineOutside(),
-                   "Should have a block here!");
+    if (!next) {
       return static_cast<nsContainerFrame*>(frame);
     }
   }
   NS_NOTREACHED("unreachable code");
   return nullptr;
 }
 
 static void
@@ -6487,16 +6483,44 @@ FindAppendPrevSibling(nsIFrame* aParentF
                "next sibling must be on the principal child list here");
     return aNextSibling->GetPrevSibling();
   }
 
   return aParentFrame->GetChildList(kPrincipalList).LastChild();
 }
 
 /**
+ * Finds the right parent frame to append content to aParentFrame.
+ *
+ * Cannot return or receive null.
+ */
+static nsContainerFrame*
+ContinuationToAppendTo(nsContainerFrame* aParentFrame)
+{
+  MOZ_ASSERT(aParentFrame);
+
+  if (IsFramePartOfIBSplit(aParentFrame)) {
+    // 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.
+    //
+    // Always make sure to look at the last continuation of the frame for the
+    // {ib} case, even if that continuation is empty.
+    //
+    // We don't do this for the non-ib-split-frame case, since in the other
+    // cases appending to the last nonempty continuation is fine and in fact not
+    // doing that can confuse code that doesn't know to pull kids from
+    // continuations other than its next one.
+    return static_cast<nsContainerFrame*>(GetLastIBSplitSibling(aParentFrame)->LastContinuation());
+  }
+
+  return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
+}
+
+/**
  * This function will get the next sibling for a frame insert operation given
  * the parent and previous sibling.  aPrevSibling may be null.
  */
 static nsIFrame*
 GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
 {
   if (aPrevSibling) {
     return aPrevSibling->GetNextSibling();
@@ -6779,17 +6803,17 @@ nsCSSFrameConstructor::AdjustSiblingFram
     MOZ_ASSERT(aSibling);
   }
 
   MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
   if (aDirection == SiblingDirection::Backward) {
     // The frame may be a ib-split frame (a split inline frame that contains a
     // block).  Get the last part of that split.
     if (IsFramePartOfIBSplit(aSibling)) {
-      aSibling = GetLastIBSplitSibling(aSibling, true);
+      aSibling = GetLastIBSplitSibling(aSibling);
     }
 
     // The frame may have a continuation. If so, we want the last
     // non-overflow-container continuation as our previous sibling.
     aSibling = aSibling->GetTailContinuation();
   }
 
   if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
@@ -6921,28 +6945,20 @@ nsCSSFrameConstructor::GetInsertionPrevS
       iter.Seek(aEndSkipChild);
       iter.GetPreviousChild();
     }
     if (nsIFrame* nextSibling = FindNextSibling(iter, childDisplay)) {
       aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
     } else {
       // No previous or next sibling, so treat this like an appended frame.
       *aIsAppend = true;
-      if (IsFramePartOfIBSplit(aInsertion->mParentFrame)) {
-        // Since we're appending, we'll walk to the last anonymous frame
-        // that was created for the broken inline frame. We can walk to the
-        // trailing inline, since we know this is a real append, and not an
-        // insert (that would've been handled by `FindNextSibling`).
-        aInsertion->mParentFrame =
-          GetLastIBSplitSibling(aInsertion->mParentFrame, true);
-      }
-      // Get continuation that parents the last child.
       aInsertion->mParentFrame =
-        nsLayoutUtils::LastContinuationWithChild(aInsertion->mParentFrame);
-      // Deal with fieldsets
+        ::ContinuationToAppendTo(aInsertion->mParentFrame);
+
+      // Deal with fieldsets.
       aInsertion->mParentFrame =
         ::GetAdjustedParentFrame(aInsertion->mParentFrame, aChild);
       prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr);
     }
   }
 
   *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
   return prevSibling;
@@ -7523,75 +7539,44 @@ nsCSSFrameConstructor::ContentAppended(n
 
   if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
     LAYOUT_PHASE_TEMP_EXIT();
     RecreateFramesForContent(parentFrame->GetContent(), aInsertionKind);
     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.
-  const bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
-  if (parentIBSplit) {
 #ifdef DEBUG
-    if (gNoisyContentUpdates) {
-      printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
-      nsFrame::ListTag(stdout, parentFrame);
-      printf(" is ib-split\n");
-    }
+  if (gNoisyContentUpdates && IsFramePartOfIBSplit(parentFrame)) {
+    printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
+    nsFrame::ListTag(stdout, parentFrame);
+    printf(" is ib-split\n");
+  }
 #endif
 
-    // Since we're appending, we'll walk to the last anonymous frame
-    // that was created for the broken inline frame.  But don't walk
-    // to the trailing inline if it's empty; stop at the block.
-    parentFrame = GetLastIBSplitSibling(parentFrame, false);
-  }
-
-  // Get continuation that parents the last child.  This MUST be done
-  // before the AdjustAppendParentForAfterContent call.
-  parentFrame = nsLayoutUtils::LastContinuationWithChild(parentFrame);
-
   // We should never get here with fieldsets or details, since they have
   // multiple insertion points.
   MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
              "Parent frame should not be fieldset or details!");
 
   // Deal with possible :after generated content on the parent, or display:
   // contents.
   nsIFrame* nextSibling = nullptr;
   if (GetDisplayContentsStyleFor(insertion.mContainer) ||
       nsLayoutUtils::GetAfterFrame(insertion.mContainer)) {
     FlattenedChildIterator iter(insertion.mContainer);
     iter.Seek(insertion.mContainer->GetLastChild());
     StyleDisplay unused = UNSET_DISPLAY;
     nextSibling = FindNextSibling(iter, unused);
-  }
-
-  if (nextSibling) {
-    parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
-  } else if (parentIBSplit) {
-    // We might be in a situation where the last part of the {ib} split was
-    // empty.  Since we have no ::after pseudo-element, we do in fact want to be
-    // appending to that last part, so advance to it if needed.  Note that here
-    // aParentFrame is the result of a GetLastIBSplitSibling call, so must be
-    // either the last or next to last ib-split sibling.
-    if (nsContainerFrame* trailingInline = GetIBSplitSibling(parentFrame)) {
-      parentFrame = trailingInline;
-    }
-
-    // Always make sure to look at the last continuation of the frame
-    // for the {ib} case, even if that continuation is empty.  We
-    // don't do this for the non-ib-split-frame case, since in the
-    // other cases appending to the last nonempty continuation is fine
-    // and in fact not doing that can confuse code that doesn't know
-    // to pull kids from continuations other than its next one.
+    if (nextSibling) {
+      parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
+    }
+  } else {
     parentFrame =
-      static_cast<nsContainerFrame*>(parentFrame->LastContinuation());
+      ::ContinuationToAppendTo(parentFrame);
   }
 
   nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
 
   // See if the containing block has :first-letter style applied.
   const bool haveFirstLetterStyle =
     containingBlock && HasFirstLetterStyle(containingBlock);
 
@@ -7680,17 +7665,17 @@ nsCSSFrameConstructor::ContentAppended(n
     return;
   }
   LAYOUT_PHASE_TEMP_REENTER();
 
   // If the parent is a block frame, and we're not in a special case
   // where frames can be moved around, determine if the list is for the
   // start or end of the block.
   if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
-      !haveFirstLineStyle && !parentIBSplit) {
+      !haveFirstLineStyle && !IsFramePartOfIBSplit(parentFrame)) {
     items.SetLineBoundaryAtStart(!prevSibling ||
                                  !prevSibling->IsInlineOutside() ||
                                  prevSibling->IsBrFrame());
     // :after content can't be <br> so no need to check it
     //
     // FIXME(emilio): A display: contents sibling could! Write a test-case and
     // fix.
     items.SetLineBoundaryAtEnd(