Commit a1e36d1d authored by Ting-Yu Lin's avatar Ting-Yu Lin
Browse files

Bug 1421105 Part 2 - Implement column-span for block and inline frames. r=bzbarsky,dbaron

Other frames calling InitAndWrapInColumnSetFrameIfNeeded() needs to be
modified to support column-span (bug 1489295).

Depends on D5208

Differential Revision: https://phabricator.services.mozilla.com/D5209

--HG--
extra : moz-landing-system : lando
parent fe1ce98c
Loading
Loading
Loading
Loading
+456 −12
Original line number Diff line number Diff line
@@ -843,6 +843,15 @@ public:
  nsContainerFrame* GetGeometricParent(const nsStyleDisplay& aStyleDisplay,
                                       nsContainerFrame* aContentParentFrame) const;

  // Collect absolute frames in mAbsoluteItems which are proper descendants
  // of aNewParent, and reparent them to aNewParent.
  //
  // Note: This function does something unusual that moves absolute items
  // after their frames are constructed under a column hierarchy which has
  // column-span elements. Do not use this if you're not dealing with
  // columns.
  void ReparentAbsoluteItems(nsContainerFrame* aNewParent);

  /**
   * Function to add a new frame to the right frame list.  This MUST be called
   * on frames before their children have been processed if the frames might
@@ -1158,6 +1167,43 @@ nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay& aStyleDisplay,
  return aContentParentFrame;
}

void
nsFrameConstructorState::ReparentAbsoluteItems(nsContainerFrame* aNewParent)
{
  // Bug 1491727: This function might not conform to the spec. See
  // https://github.com/w3c/csswg-drafts/issues/1894.

  MOZ_ASSERT(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),
             "Restrict the usage under column hierarchy.");

  nsFrameList newAbsoluteItems;

  nsIFrame* current = mAbsoluteItems.FirstChild();
  while (current) {
    nsIFrame* placeholder = current->GetPlaceholderFrame();

    if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
      nsIFrame* next = current->GetNextSibling();
      mAbsoluteItems.RemoveFrame(current);
      newAbsoluteItems.AppendFrame(aNewParent, current);
      current = next;
    } else {
      current = current->GetNextSibling();
    }
  }

  if (newAbsoluteItems.NotEmpty()) {
    // ~nsFrameConstructorSaveState() will move newAbsoluteItems to
    // aNewParent's absolute child list.
    nsFrameConstructorSaveState absoluteSaveState;

    // It doesn't matter whether aNewParent has position style or not. Caller
    // won't call us if we can't have absolute children.
    PushAbsoluteContainingBlock(aNewParent, aNewParent, absoluteSaveState);
    mAbsoluteItems.SetFrames(newAbsoluteItems);
  }
}

nsAbsoluteItems*
nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
                                                bool aCanBePositioned,
@@ -8497,6 +8543,12 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
    newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
  }

  // A continuation of a frame which has a multi-column ancestor also has
  // multi-column ancestor.
  if (aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
    newFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
  }

  if (nextInFlow) {
    nextInFlow->SetPrevInFlow(newFrame);
    newFrame->SetNextInFlow(nextInFlow);
@@ -10937,20 +10989,106 @@ nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
                                      nsIFrame*                aPositionedFrameForAbsPosContainer,
                                      PendingBinding*          aPendingBinding)
{
  // Create column wrapper if necessary
  // If a block frame is in a multi-column subtree, its children may need to
  // be chopped into runs of blocks containing column-spans and runs of
  // blocks containing no column-spans. Each run containing column-spans
  // will be wrapped by an anonymous block. See CreateColumnSpanSiblings() for
  // the implementation.
  //
  // If a block frame is a multi-column container, its children will need to
  // be processed as above. Moreover, it creates a ColumnSetWrapperFrame as
  // its outermost frame, and its children which have no
  // -moz-column-span-wrapper pseudo will be wrapped in ColumnSetFrames. See
  // FinishBuildingColumns() for the implementation.
  //
  // The multi-column subtree maintains the following invariants:
  //
  // 1) All the frames have the frame state bit
  //    NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR set, except for top-level
  //    ColumnSetWrapperFrame and those children in the column-span subtrees.
  //
  // 2) The first and last frame under ColumnSetWrapperFrame are always
  //    ColumnSetFrame.
  //
  // 3) ColumnSetFrames are linked together as continuations.
  //
  // 4) Those column-span wrappers are linked together alternately with the
  //    original block frame and the original block's continuations. That
  //    is, original block frame -> column-span wrapper -> original block
  //    frame's continuation -> column-span wrapper -> ...
  //
  //    This is very similar to what we do with block-inside-inline
  //    splitting, except here we can use continuations rather than the
  //    IBSibling linkage since the frames are the same type.
  //
  // For example, this HTML
  //  <div id="x" style="column-count: 2;">
  //    <div style="column-span: all">a</div>
  //    <div id="y">
  //      b
  //      <div style="column-span: all">c</div>
  //      <div style="column-span: all">d</div>
  //      e
  //    </div>
  //  </div>
  //  <div style="column-span: all">f</div>
  //
  //  yields the following frame tree.
  //
  // A) ColumnSetWrapper (original style)
  // B)   ColumnSet (-moz-column-set)   <-- always created by BeginBuildingColumns
  // C)     Block (-moz-column-content)
  // D)   Block (-moz-column-span-wrapper, created by x)
  // E)     Block (div)
  // F)       Text ("a")
  // G)   ColumnSet (-moz-column-set)
  // H)     Block (-moz-column-content, created by x)
  // I)       Block (div, y)
  // J)         Text ("b")
  // K)   Block (-moz-column-span-wrapper, created by x)
  // L)     Block (-moz-column-span-wrapper, created by y)
  // M)       Block (div, new BFC)
  // N)         Text ("c")
  // O)       Block (div, new BFC)
  // P)         Text ("d")
  // Q)   ColumnSet (-moz-column-set)
  // R)     Block (-moz-column-content, created by x)
  // S)       Block (div, y)
  // T)         Text ("e")
  // U) Block (div, new BFC)   <-- not in multi-column hierarchy
  // V)   Text ("f")
  //
  // ColumnSet linkage described in 3): B -> G -> Q
  //
  // Column-span linkage described in 4): C -> D -> H -> K -> R  and  I -> L -> S
  //

  nsBlockFrame* blockFrame = do_QueryFrame(*aNewFrame);
  MOZ_ASSERT(blockFrame->IsBlockFrame() || blockFrame->IsDetailsFrame(),
             "not a block frame nor a details frame?");

  // Create column hierarchy if necessary.
  const bool needsColumn =
    aComputedStyle->StyleColumn()->IsColumnContainerStyle();
  if (needsColumn) {
    *aNewFrame =
    InitAndWrapInColumnSetFrameIfNeeded(aState, aContent, aParentFrame,
                                        blockFrame, aComputedStyle);
      BeginBuildingColumns(aState, aContent, aParentFrame, blockFrame, aComputedStyle);

  if (blockFrame != *aNewFrame) {
    // blockFrame is wrapped in nsColumnSetFrame.
    if (aPositionedFrameForAbsPosContainer == blockFrame) {
      aPositionedFrameForAbsPosContainer = *aNewFrame;
    }
  } else {
    // No need to create column hierarchy. Initialize block frame.
    blockFrame->SetComputedStyleWithoutNotification(aComputedStyle);
    InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);

    if (StaticPrefs::layout_css_column_span_enabled()) {
      if (blockFrame->IsColumnSpan()) {
        // Per spec, a column-span always establishes a new block formatting
        // context.
        blockFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
      }
    }
  }

  aState.AddChild(*aNewFrame, aFrameItems, aContent,
@@ -10976,14 +11114,69 @@ nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
    aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
  }

  // Ensure all the children in the multi-column subtree are tagged with
  // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR, except for those children in the
  // column-span subtree. InitAndRestoreFrame() will add
  // mAdditionalStateBits for us.
  AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
  if (StaticPrefs::layout_css_column_span_enabled()) {
    if (needsColumn) {
      aState.mAdditionalStateBits |= NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR;
    } else if (blockFrame->IsColumnSpan()) {
      aState.mAdditionalStateBits &= ~NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR;
    }
  }

  // Process the child content
  nsFrameItems childItems;
  ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true,
                  childItems, true, aPendingBinding);

  if (!StaticPrefs::layout_css_column_span_enabled()) {
    // Set the frame's initial child list
    blockFrame->SetInitialChildList(kPrincipalList, childItems);
    CreateBulletFrameForListItemIfNeeded(blockFrame);
    return;
  }

  if (!MayNeedToCreateColumnSpanSiblings(blockFrame, childItems)) {
    // No need to create column-span siblings.
    blockFrame->SetInitialChildList(kPrincipalList, childItems);
    return;
  }

  // Extract any initial non-column-span kids, and put them in block frame's
  // child list.
  nsFrameList initialNonColumnSpanKids =
    childItems.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
  blockFrame->SetInitialChildList(kPrincipalList, initialNonColumnSpanKids);
  if (childItems.IsEmpty()) {
    // No more column-span kids need to be processed.
    return;
  }

  nsFrameList columnSpanSiblings =
    CreateColumnSpanSiblings(aState, blockFrame, childItems,
                             aPositionedFrameForAbsPosContainer);

  if (needsColumn) {
    // We're constructing a column container; need to finish building it.
    FinishBuildingColumns(aState, *aNewFrame, blockFrame, columnSpanSiblings);
  } else {
    // We're constructing a normal block which has column-span children in a
    // column hierarchy such as "x" in the following example.
    //
    // <div style="column-count: 2">
    //   <div id="x">
    //     <div>normal child</div>
    //     <div style="column-span">spanner</div>
    //   </div>
    // </div>
    aFrameItems.AppendFrames(nullptr, columnSpanSiblings);
  }

  MOZ_ASSERT(columnSpanSiblings.IsEmpty(),
             "The column-span siblings should be moved to the proper place!");
}

void
@@ -11015,6 +11208,218 @@ nsCSSFrameConstructor::CreateBulletFrameForListItemIfNeeded(
  }
}

nsContainerFrame*
nsCSSFrameConstructor::BeginBuildingColumns(
  nsFrameConstructorState& aState,
  nsIContent* aContent,
  nsContainerFrame* aParentFrame,
  nsContainerFrame* aColumnContent,
  ComputedStyle* aComputedStyle)
{
  MOZ_ASSERT(aColumnContent->IsBlockFrame() || aColumnContent->IsDetailsFrame(),
             "aColumnContent should either be a block frame or a details frame.");
  MOZ_ASSERT(aComputedStyle->StyleColumn()->IsColumnContainerStyle(),
             "No need to build a column hierarchy!");

  if (!StaticPrefs::layout_css_column_span_enabled()) {
    // Preserve the old behavior which supports no column-span.
    // Wrap the block frame in a ColumnSetFrame.
    nsContainerFrame* columnSetFrame =
      NS_NewColumnSetFrame(mPresShell, aComputedStyle,
                           nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
    InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
    SetInitialSingleChild(columnSetFrame, aColumnContent);

    RefPtr<ComputedStyle> anonBlockStyle = mPresShell->StyleSet()->
      ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent(),
                                         aComputedStyle);
    aColumnContent->SetComputedStyleWithoutNotification(anonBlockStyle);
    InitAndRestoreFrame(aState, aContent, columnSetFrame, aColumnContent);

    return columnSetFrame;
  }

  // The initial column hierarchy looks like this:
  //
  // ColumnSetWrapper (original style)
  //   ColumnSet (-moz-column-set)
  //     Block (-moz-column-content)
  //
  nsBlockFrame* columnSetWrapper =
    NS_NewColumnSetWrapperFrame(mPresShell, aComputedStyle,
                                nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
  InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetWrapper);

  RefPtr<ComputedStyle> columnSetStyle = mPresShell->StyleSet()->
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnSet(),
                                       aComputedStyle);
  nsContainerFrame* columnSet =
    NS_NewColumnSetFrame(mPresShell, columnSetStyle,
                         nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
  InitAndRestoreFrame(aState, aContent, columnSetWrapper, columnSet);
  columnSet->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);

  RefPtr<ComputedStyle> blockStyle = mPresShell->StyleSet()->
    ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent(),
                                       columnSetStyle);
  aColumnContent->SetComputedStyleWithoutNotification(blockStyle);
  InitAndRestoreFrame(aState, aContent, columnSet, aColumnContent);
  aColumnContent->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);

  // Set up the parent-child chain.
  SetInitialSingleChild(columnSetWrapper, columnSet);
  SetInitialSingleChild(columnSet, aColumnContent);

  return columnSetWrapper;
}

void
nsCSSFrameConstructor::FinishBuildingColumns(
  nsFrameConstructorState& aState,
  nsContainerFrame* aColumnSetWrapper,
  nsContainerFrame* aColumnContent,
  nsFrameList& aColumnContentSiblings)
{
  MOZ_ASSERT(StaticPrefs::layout_css_column_span_enabled(),
             "Call this only when layout.css.column-span.enabled is true!");

  nsContainerFrame* prevColumnSet = aColumnContent->GetParent();

  MOZ_ASSERT(prevColumnSet->IsColumnSetFrame() &&
             prevColumnSet->GetParent() == aColumnSetWrapper,
             "Should have established column hierarchy!");

  nsFrameItems finalItems;
  while (aColumnContentSiblings.NotEmpty()) {
    nsIFrame* f = aColumnContentSiblings.RemoveFirstChild();
    if (f->IsColumnSpan()) {
      // Do nothing for column-span wrappers. Just move it to the final
      // items.
      finalItems.AddChild(f);
    } else {
      auto* continuingColumnSet = static_cast<nsContainerFrame*>(
        CreateContinuingFrame(mPresShell->GetPresContext(),
                              prevColumnSet,
                              aColumnSetWrapper,
                              false));
      f->SetParent(continuingColumnSet);
      SetInitialSingleChild(continuingColumnSet, f);
      finalItems.AddChild(continuingColumnSet);
      prevColumnSet = continuingColumnSet;
    }
  }

  finalItems.ApplySetParent(aColumnSetWrapper);
  aColumnSetWrapper->AppendFrames(kPrincipalList, finalItems);
}

bool
nsCSSFrameConstructor::MayNeedToCreateColumnSpanSiblings(
  nsContainerFrame* aBlockFrame,
  const nsFrameList& aChildList)
{
  MOZ_ASSERT(StaticPrefs::layout_css_column_span_enabled(),
             "Call this only when layout.css.column-span.enabled is true!");

  if (aBlockFrame->IsColumnSpan() ||
      !aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
    // The children of a column-span never need to be further processed even
    // if there is a nested column-span child. Because a column-span always
    // creates its own block formatting context, a nested column-span child
    // won't be in the same block formatting context with the nearest
    // multi-column ancestor. This is the same case as if the column-span is
    // outside of a multi-column hierarchy.
    return false;
  }

  if (aChildList.IsEmpty()) {
    // No child needs to be processed.
    return false;
  }

  if (aBlockFrame->IsDetailsFrame()) {
    // Not dealing with details frame for now.
    return false;
  }

  if (aBlockFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
    // No need to deal with an out-of-flow frame because column-span applies
    // only to in-flow elements per spec.
    return false;
  }

  // Need to actually look into the child items.
  return true;
}

nsFrameItems
nsCSSFrameConstructor::CreateColumnSpanSiblings(nsFrameConstructorState& aState,
                                                nsContainerFrame* aInitialBlock,
                                                nsFrameList& aChildList,
                                                nsIFrame* aPositionedFrame)
{
  MOZ_ASSERT(!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock());

  nsIContent* const content = aInitialBlock->GetContent();
  ComputedStyle* const initialBlockStyle = aInitialBlock->Style();
  nsContainerFrame* const parentFrame = aInitialBlock->GetParent();

  nsFrameItems siblings;
  nsContainerFrame* lastNewBlock = aInitialBlock;
  do {
    MOZ_ASSERT(aChildList.NotEmpty(), "Why call this if child list is empty?");
    MOZ_ASSERT(aChildList.FirstChild()->IsColumnSpan(),
               "Must have the child starting with column-span!");

    // Grab the consecutive column-span kids, and reparent them into a
    // block frame.
    RefPtr<ComputedStyle> columnSpanWrapperStyle = mPresShell->StyleSet()->
      ResolveNonInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnSpanWrapper());
    nsBlockFrame* columnSpanWrapper =
      NS_NewBlockFrame(mPresShell, columnSpanWrapperStyle);
    InitAndRestoreFrame(aState, content, parentFrame, columnSpanWrapper, false);
    columnSpanWrapper->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);

    nsFrameList columnSpanKids =
      aChildList.Split([](nsIFrame* f) { return !f->IsColumnSpan(); });
    columnSpanKids.ApplySetParent(columnSpanWrapper);
    columnSpanWrapper->SetInitialChildList(kPrincipalList, columnSpanKids);
    if (aPositionedFrame) {
      aState.ReparentAbsoluteItems(columnSpanWrapper);
    }

    lastNewBlock->SetNextContinuation(columnSpanWrapper);
    columnSpanWrapper->SetPrevContinuation(lastNewBlock);
    siblings.AddChild(columnSpanWrapper);

    // Grab the consecutive non-column-span kids, and reparent them into a
    // block frame.
    nsBlockFrame* nonColumnSpanWrapper =
      NS_NewBlockFrame(mPresShell, initialBlockStyle);
    InitAndRestoreFrame(aState, content, parentFrame, nonColumnSpanWrapper, false);
    nonColumnSpanWrapper->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);

    if (aChildList.NotEmpty()) {
      nsFrameList nonColumnSpanKids =
        aChildList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });

      nonColumnSpanKids.ApplySetParent(nonColumnSpanWrapper);
      nonColumnSpanWrapper->SetInitialChildList(kPrincipalList, nonColumnSpanKids);
      if (aPositionedFrame) {
        aState.ReparentAbsoluteItems(nonColumnSpanWrapper);
      }
    }

    columnSpanWrapper->SetNextContinuation(nonColumnSpanWrapper);
    nonColumnSpanWrapper->SetPrevContinuation(columnSpanWrapper);
    siblings.AddChild(nonColumnSpanWrapper);

    lastNewBlock = nonColumnSpanWrapper;
  } while (aChildList.NotEmpty());

  return siblings;
}

nsIFrame*
nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
                                       FrameConstructionItem&   aItem,
@@ -11027,6 +11432,11 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
  // contain the runs of blocks, inline frames with our style for the runs of
  // inlines, and put all these frames, in order, into aFrameItems.
  //
  // When there are column-span blocks in a run of blocks, instead of
  // creating an anonymous block to wrap them, we create multiple anonymous
  // blocks that are continuations of each other, wrapping runs of
  // non-column-spans and runs of column-spans.
  //
  // We return the the first one.  The whole setup is called an {ib}
  // split; in what follows "frames in the split" refers to the anonymous blocks
  // and inlines that contain our children.
@@ -11034,14 +11444,23 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
  // {ib} splits maintain the following invariants:
  // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
  //    set.
  //
  // 2) Each frame in the split has the nsIFrame::IBSplitSibling
  //    property pointing to the next frame in the split, except for the last
  //    one, which does not have it set.
  //
  // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
  //    property pointing to the previous frame in the split, except for the
  //    first one, which does not have it set.
  //
  // 4) The first and last frame in the split are always inlines.
  //
  // 5) The frames wrapping runs of non-column-spans and runs of
  //    column-spans are linked together by continuations.
  //
  // 6) The first and last frame in the chains of blocks are always wrapping
  //    non-column-spans. Both of them are created even if they're empty.
  //
  // An invariant that is NOT maintained is that the wrappers are actually
  // linked via GetNextSibling linkage.  A simple example is an inline
  // containing an inline that contains a block.  The three parts of the inner
@@ -11183,10 +11602,35 @@ nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
    // and the start of our next inline's kids
    nsFrameList blockKids =
      aChildItems.Split([](nsIFrame* f) { return f->IsInlineOutside(); });

    if (!StaticPrefs::layout_css_column_span_enabled() ||
        !aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
      MoveChildrenTo(aInitialInline, blockFrame, blockKids);

      SetFrameIsIBSplit(lastNewInline, blockFrame);
      aSiblings.AddChild(blockFrame);
    } else {
      // Extract any initial non-column-span frames, and put them in
      // blockFrame's child list.
      nsFrameList initialNonColumnSpanKids =
        blockKids.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
      MoveChildrenTo(aInitialInline, blockFrame, initialNonColumnSpanKids);

      SetFrameIsIBSplit(lastNewInline, blockFrame);
      aSiblings.AddChild(blockFrame);

      if (blockKids.NotEmpty()) {
        // Add NS_FRAME_PART_OF_IBSPLIT bit to all the wrapper frames
        // created by CreateColumnSpanSiblings.
        AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
        aState.mAdditionalStateBits |= NS_FRAME_PART_OF_IBSPLIT;

        nsFrameItems columnSpanSiblings =
          CreateColumnSpanSiblings(aState, blockFrame, blockKids,
                                   aIsAbsPosCB ? aInitialInline : nullptr);
        aSiblings.AppendFrames(nullptr, columnSpanSiblings);
      }
    }

    // Now grab the initial inlines in aChildItems and put them into an inline
    // frame.
+76 −0

File changed.

Preview size limit exceeded, changes collapsed.

+35 −1
Original line number Diff line number Diff line
@@ -33,6 +33,36 @@ ColumnSetWrapperFrame::ColumnSetWrapperFrame(ComputedStyle* aStyle)
{
}

void
ColumnSetWrapperFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
{
  MOZ_ASSERT(!GetPrevContinuation(),
             "Who set NS_FRAME_OWNS_ANON_BOXES on our continuations?");

  // It's sufficient to append the first ColumnSet child, which is the first
  // continuation of the directly owned anon boxes.
  nsIFrame* columnSet = PrincipalChildList().FirstChild();
  MOZ_ASSERT(columnSet && columnSet->IsColumnSetFrame(),
             "The first child should always be ColumnSet!");
  aResult.AppendElement(OwnedAnonBox(columnSet));

#ifdef DEBUG
  // All the other ColumnSets are the continuation of the first ColumnSet;
  // the -moz-column-span-wrappers are the continuations of other blocks in
  // -moz-column-span-contents.
  for (nsIFrame* child : PrincipalChildList()) {
    if (child == columnSet) {
      // Skip testing the first child.
      continue;
    }
    MOZ_ASSERT((child->IsColumnSetFrame() ||
                child->Style()->GetPseudo() == nsCSSAnonBoxes::columnSpanWrapper()) &&
               child->GetPrevContinuation(),
               "Prev continuation is not set properly?");
  }
#endif
}

#ifdef DEBUG_FRAME_DUMP
nsresult
ColumnSetWrapperFrame::GetFrameName(nsAString& aResult) const
@@ -48,7 +78,11 @@ void
ColumnSetWrapperFrame::AppendFrames(ChildListID aListID,
                                    nsFrameList& aFrameList)
{
  MOZ_ASSERT_UNREACHABLE("Unsupported operation!");
#ifdef DEBUG
  MOZ_ASSERT(!mFinishedBuildingColumns, "Should only call once!");
  mFinishedBuildingColumns = true;
#endif

  nsBlockFrame::AppendFrames(aListID, aFrameList);
}

+8 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ public:
                                                     ComputedStyle* aStyle,
                                                     nsFrameState aStateFlags);

  void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;

#ifdef DEBUG_FRAME_DUMP
  nsresult GetFrameName(nsAString& aResult) const override;
#endif
@@ -48,6 +50,12 @@ public:
private:
  explicit ColumnSetWrapperFrame(ComputedStyle* aStyle);
  ~ColumnSetWrapperFrame() override = default;

#ifdef DEBUG
  // True if frame constructor has finished building this frame and all of
  // its descendants.
  bool mFinishedBuildingColumns = false;
#endif
};

} // namespace mozilla
+10 −2
Original line number Diff line number Diff line
@@ -224,7 +224,15 @@ FRAME_STATE_BIT(Generic, 42, NS_FRAME_FONT_INFLATION_FLOW_ROOT)
// this does not include nsSVGOuterSVGFrame since it takes part is CSS layout.
FRAME_STATE_BIT(Generic, 43, NS_FRAME_SVG_LAYOUT)

// Bits 44 and 45 are currently unused, but be kind and check with bug 1465474
// This bit is set if a frame has a multi-column ancestor (i.e.
// ColumnSetWrapperFrame) within the same block formatting context. A
// top-level ColumnSetWrapperFrame doesn't have this bit set, whereas a
// ColumnSetWrapperFrame nested inside a column does have this bit set. All
// the children of the column-spans do not have this bit set because they
// are in a new block formatting context created by column-spans.
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 :-)

// This bit indicates that we're tracking visibility for this frame, and that
@@ -285,7 +293,7 @@ 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: Bits 44 and 45 are currently unused.
// NOTE: Currently unused and available bit(s): 45.


// == Frame state bits that apply to box frames ===============================
Loading