tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsInlineFrame.cpp (41739B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* rendering object for CSS display:inline objects */
      8 
      9 #include "nsInlineFrame.h"
     10 
     11 #include "gfxContext.h"
     12 #include "mozilla/ComputedStyle.h"
     13 #include "mozilla/Likely.h"
     14 #include "mozilla/PresShell.h"
     15 #include "mozilla/RestyleManager.h"
     16 #include "mozilla/SVGTextFrame.h"
     17 #include "mozilla/ServoStyleSet.h"
     18 #include "nsBlockFrame.h"
     19 #include "nsCSSAnonBoxes.h"
     20 #include "nsDisplayList.h"
     21 #include "nsGkAtoms.h"
     22 #include "nsLayoutUtils.h"
     23 #include "nsLineLayout.h"
     24 #include "nsPlaceholderFrame.h"
     25 #include "nsPresContext.h"
     26 #include "nsPresContextInlines.h"
     27 #include "nsStyleChangeList.h"
     28 
     29 #ifdef DEBUG
     30 #  undef NOISY_PUSHING
     31 #endif
     32 
     33 using namespace mozilla;
     34 using namespace mozilla::layout;
     35 
     36 //////////////////////////////////////////////////////////////////////
     37 
     38 // Basic nsInlineFrame methods
     39 
     40 nsInlineFrame* NS_NewInlineFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
     41  return new (aPresShell) nsInlineFrame(aStyle, aPresShell->GetPresContext());
     42 }
     43 
     44 NS_IMPL_FRAMEARENA_HELPERS(nsInlineFrame)
     45 
     46 NS_QUERYFRAME_HEAD(nsInlineFrame)
     47  NS_QUERYFRAME_ENTRY(nsInlineFrame)
     48 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
     49 
     50 #ifdef DEBUG_FRAME_DUMP
     51 nsresult nsInlineFrame::GetFrameName(nsAString& aResult) const {
     52  return MakeFrameName(u"Inline"_ns, aResult);
     53 }
     54 #endif
     55 
     56 void nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey,
     57                                    bool aRebuildDisplayItems) {
     58  if (IsInSVGTextSubtree()) {
     59    nsIFrame* svgTextFrame = nsLayoutUtils::GetClosestFrameOfType(
     60        GetParent(), LayoutFrameType::SVGText);
     61    svgTextFrame->InvalidateFrame();
     62    return;
     63  }
     64  nsContainerFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
     65 }
     66 
     67 void nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect,
     68                                            uint32_t aDisplayItemKey,
     69                                            bool aRebuildDisplayItems) {
     70  if (IsInSVGTextSubtree()) {
     71    nsIFrame* svgTextFrame = nsLayoutUtils::GetClosestFrameOfType(
     72        GetParent(), LayoutFrameType::SVGText);
     73    svgTextFrame->InvalidateFrame();
     74    return;
     75  }
     76  nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey,
     77                                            aRebuildDisplayItems);
     78 }
     79 
     80 /* virtual */
     81 bool nsInlineFrame::IsSelfEmpty() {
     82 #if 0
     83  // I used to think inline frames worked this way, but it seems they
     84  // don't.  At least not in our codebase.
     85  if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
     86    return false;
     87  }
     88 #endif
     89  const nsStyleMargin* margin = StyleMargin();
     90  const nsStyleBorder* border = StyleBorder();
     91  const nsStylePadding* padding = StylePadding();
     92  const auto anchorResolutionParams = AnchorPosResolutionParams::From(this);
     93  // Block-start and -end ignored, since they shouldn't affect things, but this
     94  // doesn't really match with nsLineLayout.cpp's setting of
     95  // ZeroEffectiveSpanBox, anymore, so what should this really be?
     96  WritingMode wm = GetWritingMode();
     97  bool haveStart, haveEnd;
     98 
     99  const auto IsMarginZero = [](const nsStyleMargin& aStyleMargin,
    100                               mozilla::Side aSide,
    101                               const AnchorPosResolutionParams& aParams) {
    102    const auto margin = aStyleMargin.GetMargin(aSide, aParams);
    103    if (!margin->IsLengthPercentage()) {
    104      return true;
    105    }
    106    const auto& lp = margin->AsLengthPercentage();
    107    return lp.Resolve(nscoord_MAX) == 0 && lp.Resolve(0) == 0;
    108  };
    109 
    110  auto HaveSide = [&](mozilla::Side aSide) -> bool {
    111    return border->GetComputedBorderWidth(aSide) != 0 ||
    112           !nsLayoutUtils::IsPaddingZero(padding->mPadding.Get(aSide)) ||
    113           !IsMarginZero(*margin, aSide, anchorResolutionParams);
    114  };
    115  // Initially set up haveStart and haveEnd in terms of visual (LTR/TTB)
    116  // coordinates; we'll exchange them later if bidi-RTL is in effect to
    117  // get logical start and end flags.
    118  if (wm.IsVertical()) {
    119    haveStart = HaveSide(eSideTop);
    120    haveEnd = HaveSide(eSideBottom);
    121  } else {
    122    haveStart = HaveSide(eSideLeft);
    123    haveEnd = HaveSide(eSideRight);
    124  }
    125  if (haveStart || haveEnd) {
    126    // We skip this block and return false for box-decoration-break:clone since
    127    // in that case all the continuations will have the border/padding/margin.
    128    if (HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT) &&
    129        StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Slice) {
    130      // When direction=rtl, we need to consider logical rather than visual
    131      // start and end, so swap the flags.
    132      if (wm.IsBidiRTL()) {
    133        std::swap(haveStart, haveEnd);
    134      }
    135      // For ib-split frames, ignore things we know we'll skip in GetSkipSides.
    136      // XXXbz should we be doing this for non-ib-split frames too, in a more
    137      // general way?
    138 
    139      // Get the first continuation eagerly, as a performance optimization, to
    140      // avoid having to get it twice..
    141      nsIFrame* firstCont = FirstContinuation();
    142      return (!haveStart || firstCont->FrameIsNonFirstInIBSplit()) &&
    143             (!haveEnd || firstCont->FrameIsNonLastInIBSplit());
    144    }
    145    return false;
    146  }
    147  return true;
    148 }
    149 
    150 bool nsInlineFrame::IsEmpty() {
    151  if (!IsSelfEmpty()) {
    152    return false;
    153  }
    154 
    155  for (nsIFrame* kid : mFrames) {
    156    if (!kid->IsEmpty()) {
    157      return false;
    158    }
    159  }
    160 
    161  return true;
    162 }
    163 
    164 nscoord nsInlineFrame::GetCaretBaseline() const {
    165  if (mBaseline == 0 && mRect.IsEmpty()) {
    166    nsBlockFrame* container = do_QueryFrame(FindLineContainer());
    167    // TODO(emilio): Ideally we'd want to find out if only our line is empty,
    168    // but that's non-trivial to do, and realistically empty inlines and text
    169    // will get placed into a non-empty line unless all lines are empty, I
    170    // believe...
    171    if (container && container->LinesAreEmpty()) {
    172      nscoord blockSize = container->ContentBSize(GetWritingMode());
    173      return GetFontMetricsDerivedCaretBaseline(blockSize);
    174    }
    175  }
    176  return nsIFrame::GetCaretBaseline();
    177 }
    178 
    179 nsIFrame::FrameSearchResult nsInlineFrame::PeekOffsetCharacter(
    180    bool aForward, int32_t* aOffset, PeekOffsetCharacterOptions aOptions) {
    181  // Override the implementation in nsFrame, to skip empty inline frames
    182  NS_ASSERTION(aOffset && *aOffset <= 1, "aOffset out of range");
    183  int32_t startOffset = *aOffset;
    184  if (startOffset < 0) {
    185    startOffset = 1;
    186  }
    187  if (aForward == (startOffset == 0)) {
    188    // We're before the frame and moving forward, or after it and moving
    189    // backwards: skip to the other side, but keep going.
    190    *aOffset = 1 - startOffset;
    191  }
    192  return CONTINUE;
    193 }
    194 
    195 void nsInlineFrame::Destroy(DestroyContext& aContext) {
    196  nsFrameList* overflowFrames = GetOverflowFrames();
    197  if (overflowFrames) {
    198    // Fixup the parent pointers for any child frames on the OverflowList.
    199    // nsIFrame::DestroyFrom depends on that to find the sticky scroll
    200    // container (an ancestor).
    201    overflowFrames->ApplySetParent(this);
    202  }
    203  nsContainerFrame::Destroy(aContext);
    204 }
    205 
    206 void nsInlineFrame::StealFrame(nsIFrame* aChild) {
    207  if (MaybeStealOverflowContainerFrame(aChild)) {
    208    return;
    209  }
    210 
    211  nsInlineFrame* parent = this;
    212  do {
    213    if (parent->mFrames.StartRemoveFrame(aChild)) {
    214      return;
    215    }
    216 
    217    // We didn't find the child in our principal child list.
    218    // Maybe it's on the overflow list?
    219    nsFrameList* frameList = parent->GetOverflowFrames();
    220    if (frameList && frameList->ContinueRemoveFrame(aChild)) {
    221      if (frameList->IsEmpty()) {
    222        parent->DestroyOverflowList();
    223      }
    224      return;
    225    }
    226 
    227    // Due to our "lazy reparenting" optimization 'aChild' might not actually
    228    // be on any of our child lists, but instead in one of our next-in-flows.
    229    parent = static_cast<nsInlineFrame*>(parent->GetNextInFlow());
    230  } while (parent);
    231 
    232  MOZ_ASSERT_UNREACHABLE("nsInlineFrame::StealFrame: can't find aChild");
    233 }
    234 
    235 void nsInlineFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
    236                                     const nsDisplayListSet& aLists) {
    237  BuildDisplayListForInline(aBuilder, aLists);
    238 
    239  // The sole purpose of this is to trigger display of the selection
    240  // window for Named Anchors, which don't have any children and
    241  // normally don't have any size, but in Editor we use CSS to display
    242  // an image to represent this "hidden" element.
    243  if (!mFrames.FirstChild()) {
    244    DisplaySelectionOverlay(aBuilder, aLists.Content());
    245  }
    246 }
    247 
    248 //////////////////////////////////////////////////////////////////////
    249 // Reflow methods
    250 
    251 /* virtual */
    252 void nsInlineFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput,
    253                                      InlineMinISizeData* aData) {
    254  DoInlineMinISize(aInput, aData);
    255 }
    256 
    257 /* virtual */
    258 void nsInlineFrame::AddInlinePrefISize(const IntrinsicSizeInput& aInput,
    259                                       InlinePrefISizeData* aData) {
    260  DoInlinePrefISize(aInput, aData);
    261 }
    262 
    263 /* virtual */
    264 nsIFrame::SizeComputationResult nsInlineFrame::ComputeSize(
    265    const SizeComputationInput& aSizingInput, WritingMode aWM,
    266    const LogicalSize& aCBSize, nscoord aAvailableISize,
    267    const LogicalSize& aMargin, const LogicalSize& aBorderPadding,
    268    const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) {
    269  // Inlines and text don't compute size before reflow.
    270  return {LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
    271          AspectRatioUsage::None};
    272 }
    273 
    274 nsRect nsInlineFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const {
    275  // be conservative
    276  if (Style()->HasTextDecorationLines()) {
    277    return InkOverflowRect();
    278  }
    279  return ComputeSimpleTightBounds(aDrawTarget);
    280 }
    281 
    282 static void ReparentChildListStyle(nsPresContext* aPresContext,
    283                                   const nsFrameList::Slice& aFrames,
    284                                   nsIFrame* aParentFrame) {
    285  RestyleManager* restyleManager = aPresContext->RestyleManager();
    286 
    287  for (nsIFrame* f : aFrames) {
    288    NS_ASSERTION(f->GetParent() == aParentFrame, "Bogus parentage");
    289    restyleManager->ReparentComputedStyleForFirstLine(f);
    290    nsLayoutUtils::MarkDescendantsDirty(f);
    291  }
    292 }
    293 
    294 void nsInlineFrame::Reflow(nsPresContext* aPresContext,
    295                           ReflowOutput& aReflowOutput,
    296                           const ReflowInput& aReflowInput,
    297                           nsReflowStatus& aStatus) {
    298  MarkInReflow();
    299  DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
    300  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
    301 
    302  if (!aReflowInput.mLineLayout) {
    303    NS_ERROR("must have non-null aReflowInput.mLineLayout");
    304    return;
    305  }
    306  if (IsFrameTreeTooDeep(aReflowInput, aReflowOutput, aStatus)) {
    307    return;
    308  }
    309 
    310  bool lazilySetParentPointer = false;
    311 
    312  // Check for an overflow list with our prev-in-flow
    313  nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow();
    314  if (prevInFlow) {
    315    AutoFrameListPtr prevOverflowFrames(aPresContext,
    316                                        prevInFlow->StealOverflowFrames());
    317    if (prevOverflowFrames) {
    318      // Check if we should do the lazilySetParentPointer optimization.
    319      // Only do it in simple cases where we're being reflowed for the
    320      // first time, nothing (e.g. bidi resolution) has already given
    321      // us children, and there's no next-in-flow, so all our frames
    322      // will be taken from prevOverflowFrames.
    323      if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() &&
    324          !GetNextInFlow()) {
    325        // If our child list is empty, just put the new frames into it.
    326        // Note that we don't set the parent pointer for the new frames. Instead
    327        // wait to do this until we actually reflow the frame. If the overflow
    328        // list contains thousands of frames this is a big performance issue
    329        // (see bug #5588)
    330        mFrames = std::move(*prevOverflowFrames);
    331        lazilySetParentPointer = true;
    332      } else {
    333        // Insert the new frames at the beginning of the child list
    334        // and set their parent pointer
    335        const nsFrameList::Slice& newFrames =
    336            mFrames.InsertFrames(this, nullptr, std::move(*prevOverflowFrames));
    337        // If our prev in flow was under the first continuation of a first-line
    338        // frame then we need to reparent the ComputedStyles to remove the
    339        // the special first-line styling. In the lazilySetParentPointer case
    340        // we reparent the ComputedStyles when we set their parents in
    341        // nsInlineFrame::ReflowFrames and nsInlineFrame::ReflowInlineFrame.
    342        if (aReflowInput.mLineLayout->GetInFirstLine()) {
    343          ReparentChildListStyle(aPresContext, newFrames, this);
    344        }
    345      }
    346    }
    347  }
    348 
    349  // It's also possible that we have an overflow list for ourselves
    350 #ifdef DEBUG
    351  if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
    352    // If it's our initial reflow, then we should not have an overflow list.
    353    // However, add an assertion in case we get reflowed more than once with
    354    // the initial reflow reason
    355    nsFrameList* overflowFrames = GetOverflowFrames();
    356    NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(),
    357                 "overflow list is not empty for initial reflow");
    358  }
    359 #endif
    360  if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
    361    DrainSelfOverflowListInternal(aReflowInput.mLineLayout->GetInFirstLine());
    362  }
    363 
    364  // Set our own reflow input (additional state above and beyond aReflowInput).
    365  InlineReflowInput irs;
    366  irs.mPrevFrame = nullptr;
    367  irs.mLineContainer = aReflowInput.mLineLayout->LineContainerFrame();
    368  irs.mLineLayout = aReflowInput.mLineLayout;
    369  irs.mNextInFlow = (nsInlineFrame*)GetNextInFlow();
    370  irs.mSetParentPointer = lazilySetParentPointer;
    371 
    372  if (mFrames.IsEmpty()) {
    373    // Try to pull over one frame before starting so that we know
    374    // whether we have an anonymous block or not.
    375    (void)PullOneFrame(aPresContext, irs);
    376  }
    377 
    378  ReflowFrames(aPresContext, aReflowInput, irs, aReflowOutput, aStatus);
    379 
    380  ReflowAbsoluteFrames(aPresContext, aReflowOutput, aReflowInput, aStatus);
    381 
    382  // Note: the line layout code will properly compute our
    383  // overflow-rect state for us.
    384 }
    385 
    386 nsresult nsInlineFrame::AttributeChanged(int32_t aNameSpaceID,
    387                                         nsAtom* aAttribute,
    388                                         AttrModType aModType) {
    389  nsresult rv =
    390      nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
    391 
    392  if (NS_FAILED(rv)) {
    393    return rv;
    394  }
    395 
    396  if (IsInSVGTextSubtree()) {
    397    SVGTextFrame* f = static_cast<SVGTextFrame*>(
    398        nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText));
    399    f->HandleAttributeChangeInDescendant(mContent->AsElement(), aNameSpaceID,
    400                                         aAttribute);
    401  }
    402 
    403  return NS_OK;
    404 }
    405 
    406 bool nsInlineFrame::DrainSelfOverflowListInternal(bool aInFirstLine) {
    407  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
    408  if (!overflowFrames || overflowFrames->IsEmpty()) {
    409    return false;
    410  }
    411 
    412  // The frames on our own overflowlist may have been pushed by a
    413  // previous lazilySetParentPointer Reflow so we need to ensure the
    414  // correct parent pointer.  This is sometimes skipped by Reflow.
    415  nsIFrame* firstChild = overflowFrames->FirstChild();
    416  RestyleManager* restyleManager = PresContext()->RestyleManager();
    417  for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
    418    f->SetParent(this);
    419    if (MOZ_UNLIKELY(aInFirstLine)) {
    420      restyleManager->ReparentComputedStyleForFirstLine(f);
    421      nsLayoutUtils::MarkDescendantsDirty(f);
    422    }
    423  }
    424  mFrames.AppendFrames(nullptr, std::move(*overflowFrames));
    425  return true;
    426 }
    427 
    428 /* virtual */
    429 bool nsInlineFrame::DrainSelfOverflowList() {
    430  nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this);
    431  // Add the eInFirstLine flag if we have a ::first-line ancestor frame.
    432  // No need to look further than the nearest line container though.
    433  bool inFirstLine = false;
    434  for (nsIFrame* p = GetParent(); p != lineContainer; p = p->GetParent()) {
    435    if (p->IsLineFrame()) {
    436      inFirstLine = true;
    437      break;
    438    }
    439  }
    440  return DrainSelfOverflowListInternal(inFirstLine);
    441 }
    442 
    443 /* virtual */
    444 bool nsInlineFrame::CanContinueTextRun() const {
    445  // We can continue a text run through an inline frame
    446  return true;
    447 }
    448 
    449 /* virtual */
    450 void nsInlineFrame::PullOverflowsFromPrevInFlow() {
    451  nsInlineFrame* prevInFlow = static_cast<nsInlineFrame*>(GetPrevInFlow());
    452  if (prevInFlow) {
    453    nsPresContext* presContext = PresContext();
    454    AutoFrameListPtr prevOverflowFrames(presContext,
    455                                        prevInFlow->StealOverflowFrames());
    456    if (prevOverflowFrames) {
    457      mFrames.InsertFrames(this, nullptr, std::move(*prevOverflowFrames));
    458    }
    459  }
    460 }
    461 
    462 void nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
    463                                 const ReflowInput& aReflowInput,
    464                                 InlineReflowInput& irs,
    465                                 ReflowOutput& aReflowOutput,
    466                                 nsReflowStatus& aStatus) {
    467  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
    468 
    469  nsLineLayout* lineLayout = aReflowInput.mLineLayout;
    470  bool inFirstLine = aReflowInput.mLineLayout->GetInFirstLine();
    471  RestyleManager* restyleManager = aPresContext->RestyleManager();
    472  WritingMode frameWM = aReflowInput.GetWritingMode();
    473  WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode();
    474  LogicalMargin framePadding =
    475      aReflowInput.ComputedLogicalBorderPadding(frameWM);
    476  nscoord startEdge = 0;
    477  const bool boxDecorationBreakClone = MOZ_UNLIKELY(
    478      StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone);
    479  // Don't offset by our start borderpadding if we have a prev continuation or
    480  // if we're in a part of an {ib} split other than the first one. For
    481  // box-decoration-break:clone we always offset our start since all
    482  // continuations have border/padding.
    483  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
    484      boxDecorationBreakClone) {
    485    startEdge = framePadding.IStart(frameWM);
    486  }
    487  nscoord availableISize = aReflowInput.AvailableISize();
    488  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
    489               "should no longer use available widths");
    490  // Subtract off inline axis border+padding from availableISize
    491  availableISize -= startEdge;
    492  availableISize -= framePadding.IEnd(frameWM);
    493  lineLayout->BeginSpan(this, &aReflowInput, startEdge,
    494                        startEdge + availableISize, &mBaseline);
    495 
    496  // First reflow our principal children.
    497  nsIFrame* frame = mFrames.FirstChild();
    498  bool done = false;
    499  while (frame) {
    500    // Check if we should lazily set the child frame's parent pointer.
    501    if (irs.mSetParentPointer) {
    502      nsIFrame* child = frame;
    503      do {
    504        child->SetParent(this);
    505        if (inFirstLine) {
    506          restyleManager->ReparentComputedStyleForFirstLine(child);
    507          nsLayoutUtils::MarkDescendantsDirty(child);
    508        }
    509        // We also need to do the same for |frame|'s next-in-flows that are in
    510        // the sibling list. Otherwise, if we reflow |frame| and it's complete
    511        // we'll crash when trying to delete its next-in-flow.
    512        // This scenario doesn't happen often, but it can happen.
    513        nsIFrame* nextSibling = child->GetNextSibling();
    514        child = child->GetNextInFlow();
    515        if (MOZ_UNLIKELY(child)) {
    516          while (child != nextSibling && nextSibling) {
    517            nextSibling = nextSibling->GetNextSibling();
    518          }
    519          if (!nextSibling) {
    520            child = nullptr;
    521          }
    522        }
    523        MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
    524      } while (child);
    525 
    526      // Fix the parent pointer for ::first-letter child frame next-in-flows,
    527      // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
    528      nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
    529      if (realFrame->IsLetterFrame()) {
    530        nsIFrame* child = realFrame->PrincipalChildList().FirstChild();
    531        if (child) {
    532          NS_ASSERTION(child->IsTextFrame(), "unexpected frame type");
    533          nsIFrame* nextInFlow = child->GetNextInFlow();
    534          for (; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
    535            NS_ASSERTION(nextInFlow->IsTextFrame(), "unexpected frame type");
    536            if (mFrames.ContainsFrame(nextInFlow)) {
    537              nextInFlow->SetParent(this);
    538              if (inFirstLine) {
    539                restyleManager->ReparentComputedStyleForFirstLine(nextInFlow);
    540                nsLayoutUtils::MarkDescendantsDirty(nextInFlow);
    541              }
    542            } else {
    543 #ifdef DEBUG
    544              // Once we find a next-in-flow that isn't ours none of the
    545              // remaining next-in-flows should be either.
    546              for (; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
    547                NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
    548                             "unexpected letter frame flow");
    549              }
    550 #endif
    551              break;
    552            }
    553          }
    554        }
    555      }
    556    }
    557    MOZ_ASSERT(frame->GetParent() == this);
    558 
    559    if (!done) {
    560      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
    561      ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus);
    562      done = aStatus.IsInlineBreak() ||
    563             (!reflowingFirstLetter && aStatus.IsIncomplete());
    564      if (done) {
    565        if (!irs.mSetParentPointer) {
    566          break;
    567        }
    568        // Keep reparenting the remaining siblings, but don't reflow them.
    569        nsFrameList* pushedFrames = GetOverflowFrames();
    570        if (pushedFrames && pushedFrames->FirstChild() == frame) {
    571          // Don't bother if |frame| was pushed to our overflow list.
    572          break;
    573        }
    574      } else {
    575        irs.mPrevFrame = frame;
    576      }
    577    }
    578    frame = frame->GetNextSibling();
    579  }
    580 
    581  // Attempt to pull frames from our next-in-flow until we can't
    582  if (!done && GetNextInFlow()) {
    583    while (true) {
    584      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
    585      if (!frame) {  // Could be non-null if we pulled a first-letter frame and
    586                     // it created a continuation, since we don't push those.
    587        frame = PullOneFrame(aPresContext, irs);
    588      }
    589 #ifdef NOISY_PUSHING
    590      printf("%p pulled up %p\n", this, frame);
    591 #endif
    592      if (!frame) {
    593        break;
    594      }
    595      ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus);
    596      if (aStatus.IsInlineBreak() ||
    597          (!reflowingFirstLetter && aStatus.IsIncomplete())) {
    598        break;
    599      }
    600      irs.mPrevFrame = frame;
    601      frame = frame->GetNextSibling();
    602    }
    603  }
    604 
    605  NS_ASSERTION(!aStatus.IsComplete() || !GetOverflowFrames(),
    606               "We can't be complete AND have overflow frames!");
    607 
    608  // If after reflowing our children they take up no area then make
    609  // sure that we don't either.
    610  //
    611  // Note: CSS demands that empty inline elements still affect the
    612  // line-height calculations. However, continuations of an inline
    613  // that are empty we force to empty so that things like collapsed
    614  // whitespace in an inline element don't affect the line-height.
    615  aReflowOutput.ISize(lineWM) = lineLayout->EndSpan(this);
    616 
    617  // Compute final width.
    618 
    619  // XXX Note that that the padding start and end are in the frame's
    620  //     writing mode, but the metrics' inline-size is in the line's
    621  //     writing mode. This makes sense if the line and frame are both
    622  //     vertical or both horizontal, but what should happen with
    623  //     orthogonal inlines?
    624 
    625  // Make sure to not include our start border and padding if we have a prev
    626  // continuation or if we're in a part of an {ib} split other than the first
    627  // one.  For box-decoration-break:clone we always include our start border
    628  // and padding since all continuations have them.
    629  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
    630      boxDecorationBreakClone) {
    631    aReflowOutput.ISize(lineWM) += framePadding.IStart(frameWM);
    632  }
    633 
    634  /*
    635   * We want to only apply the end border and padding if we're the last
    636   * continuation and either not in an {ib} split or the last part of it.  To
    637   * be the last continuation we have to be complete (so that we won't get a
    638   * next-in-flow) and have no non-fluid continuations on our continuation
    639   * chain.  For box-decoration-break:clone we always apply the end border and
    640   * padding since all continuations have them.
    641   */
    642  if ((aStatus.IsComplete() && !LastInFlow()->GetNextContinuation() &&
    643       !FrameIsNonLastInIBSplit()) ||
    644      boxDecorationBreakClone) {
    645    aReflowOutput.ISize(lineWM) += framePadding.IEnd(frameWM);
    646  }
    647 
    648  nsLayoutUtils::SetBSizeFromFontMetrics(this, aReflowOutput, framePadding,
    649                                         lineWM, frameWM);
    650 
    651  // For now our overflow area is zero. The real value will be
    652  // computed in |nsLineLayout::RelativePositionFrames|.
    653  aReflowOutput.mOverflowAreas.Clear();
    654 
    655 #ifdef NOISY_FINAL_SIZE
    656  ListTag(stdout);
    657  printf(": metrics=%d,%d ascent=%d\n", aReflowOutput.Width(),
    658         aReflowOutput.Height(), aReflowOutput.BlockStartAscent());
    659 #endif
    660 }
    661 
    662 // Returns whether there's any remaining frame to pull.
    663 /* static */
    664 bool nsInlineFrame::HasFramesToPull(nsInlineFrame* aNextInFlow) {
    665  while (aNextInFlow) {
    666    if (!aNextInFlow->mFrames.IsEmpty()) {
    667      return true;
    668    }
    669    if (const nsFrameList* overflow = aNextInFlow->GetOverflowFrames()) {
    670      if (!overflow->IsEmpty()) {
    671        return true;
    672      }
    673    }
    674    aNextInFlow = static_cast<nsInlineFrame*>(aNextInFlow->GetNextInFlow());
    675  }
    676  return false;
    677 }
    678 
    679 void nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
    680                                      const ReflowInput& aReflowInput,
    681                                      InlineReflowInput& irs, nsIFrame* aFrame,
    682                                      nsReflowStatus& aStatus) {
    683  nsLineLayout* lineLayout = aReflowInput.mLineLayout;
    684  bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
    685  bool pushedFrame;
    686  aStatus.Reset();
    687  lineLayout->ReflowFrame(aFrame, aStatus, nullptr, pushedFrame);
    688 
    689  if (aStatus.IsInlineBreakBefore()) {
    690    if (aFrame != mFrames.FirstChild()) {
    691      // Change break-before status into break-after since we have
    692      // already placed at least one child frame. This preserves the
    693      // break-type so that it can be propagated upward.
    694      UsedClear oldClearType = aStatus.FloatClearType();
    695      aStatus.Reset();
    696      aStatus.SetIncomplete();
    697      aStatus.SetInlineLineBreakAfter(oldClearType);
    698      PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
    699    } else {
    700      // Preserve reflow status when breaking-before our first child
    701      // and propagate it upward without modification.
    702    }
    703    return;
    704  }
    705 
    706  // Create a next-in-flow if needed.
    707  if (!aStatus.IsFullyComplete()) {
    708    CreateNextInFlow(aFrame);
    709  }
    710 
    711  if (aStatus.IsInlineBreakAfter()) {
    712    nsIFrame* nextFrame = aFrame->GetNextSibling();
    713    if (nextFrame) {
    714      aStatus.SetIncomplete();
    715      PushFrames(aPresContext, nextFrame, aFrame, irs);
    716    } else {
    717      // We must return an incomplete status if there are more child
    718      // frames remaining in a next-in-flow that follows this frame.
    719      if (HasFramesToPull(static_cast<nsInlineFrame*>(GetNextInFlow()))) {
    720        aStatus.SetIncomplete();
    721      }
    722    }
    723    return;
    724  }
    725 
    726  if (!aStatus.IsFullyComplete() && !reflowingFirstLetter) {
    727    nsIFrame* nextFrame = aFrame->GetNextSibling();
    728    if (nextFrame) {
    729      PushFrames(aPresContext, nextFrame, aFrame, irs);
    730    }
    731  }
    732 }
    733 
    734 nsIFrame* nsInlineFrame::PullOneFrame(nsPresContext* aPresContext,
    735                                      InlineReflowInput& irs) {
    736  nsIFrame* frame = nullptr;
    737  nsInlineFrame* nextInFlow = irs.mNextInFlow;
    738 
    739 #ifdef DEBUG
    740  bool willPull = HasFramesToPull(nextInFlow);
    741 #endif
    742 
    743  while (nextInFlow) {
    744    frame = nextInFlow->mFrames.FirstChild();
    745    if (!frame) {
    746      // The nextInFlow's principal list has no frames, try its overflow list.
    747      nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
    748      if (overflowFrames) {
    749        frame = overflowFrames->RemoveFirstChild();
    750        if (overflowFrames->IsEmpty()) {
    751          // We're stealing the only frame - delete the overflow list.
    752          nextInFlow->DestroyOverflowList();
    753        } else {
    754          // We leave the remaining frames on the overflow list (rather than
    755          // putting them on nextInFlow's principal list) so we don't have to
    756          // set up the parent for them.
    757        }
    758        // ReparentFloatsForInlineChild needs it to be on a child list -
    759        // we remove it again below.
    760        nextInFlow->mFrames = nsFrameList(frame, frame);
    761      }
    762    }
    763 
    764    if (frame) {
    765      // If our block has no next continuation, then any floats belonging to
    766      // the pulled frame must belong to our block already. This check ensures
    767      // we do no extra work in the common non-vertical-breaking case.
    768      if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
    769        // The blockChildren.ContainsFrame check performed by
    770        // ReparentFloatsForInlineChild will be fast because frame's ancestor
    771        // will be the first child of its containing block.
    772        ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
    773      }
    774      nextInFlow->mFrames.RemoveFirstChild();
    775      // nsFirstLineFrame::PullOneFrame calls ReparentComputedStyle.
    776 
    777      mFrames.InsertFrame(this, irs.mPrevFrame, frame);
    778      if (irs.mLineLayout) {
    779        irs.mLineLayout->SetDirtyNextLine();
    780      }
    781      break;
    782    }
    783    nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
    784    irs.mNextInFlow = nextInFlow;
    785  }
    786 
    787  MOZ_ASSERT(!!frame == willPull);
    788  return frame;
    789 }
    790 
    791 void nsInlineFrame::PushFrames(nsPresContext* aPresContext,
    792                               nsIFrame* aFromChild, nsIFrame* aPrevSibling,
    793                               InlineReflowInput& aState) {
    794 #ifdef NOISY_PUSHING
    795  printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n", this,
    796         aFromChild, aPrevSibling);
    797 #endif
    798 
    799  PushChildrenToOverflow(aFromChild, aPrevSibling);
    800  if (aState.mLineLayout) {
    801    aState.mLineLayout->SetDirtyNextLine();
    802  }
    803 }
    804 
    805 //////////////////////////////////////////////////////////////////////
    806 
    807 LogicalSides nsInlineFrame::GetLogicalSkipSides() const {
    808  LogicalSides skip(mWritingMode);
    809  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
    810                   StyleBoxDecorationBreak::Clone)) {
    811    return skip;
    812  }
    813 
    814  if (!IsFirst()) {
    815    nsInlineFrame* prev = (nsInlineFrame*)GetPrevContinuation();
    816    if (HasAnyStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
    817        (prev && (prev->mRect.height || prev->mRect.width))) {
    818      // Prev continuation is not empty therefore we don't render our start
    819      // border edge.
    820      skip += LogicalSide::IStart;
    821    } else {
    822      // If the prev continuation is empty, then go ahead and let our start
    823      // edge border render.
    824    }
    825  }
    826  if (!IsLast()) {
    827    nsInlineFrame* next = (nsInlineFrame*)GetNextContinuation();
    828    if (HasAnyStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
    829        (next && (next->mRect.height || next->mRect.width))) {
    830      // Next continuation is not empty therefore we don't render our end
    831      // border edge.
    832      skip += LogicalSide::IEnd;
    833    } else {
    834      // If the next continuation is empty, then go ahead and let our end
    835      // edge border render.
    836    }
    837  }
    838 
    839  if (HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) {
    840    // All but the last part of an {ib} split should skip the "end" side (as
    841    // determined by this frame's direction) and all but the first part of such
    842    // a split should skip the "start" side.  But figuring out which part of
    843    // the split we are involves getting our first continuation, which might be
    844    // expensive.  So don't bother if we already have the relevant bits set.
    845    if (skip != LogicalSides(mWritingMode, LogicalSides::IBoth)) {
    846      // We're missing one of the skip bits, so check whether we need to set it.
    847      // Only get the first continuation once, as an optimization.
    848      nsIFrame* firstContinuation = FirstContinuation();
    849      if (firstContinuation->FrameIsNonLastInIBSplit()) {
    850        skip += LogicalSide::IEnd;
    851      }
    852      if (firstContinuation->FrameIsNonFirstInIBSplit()) {
    853        skip += LogicalSide::IStart;
    854      }
    855    }
    856  }
    857 
    858  return skip;
    859 }
    860 
    861 Maybe<nscoord> nsInlineFrame::GetNaturalBaselineBOffset(
    862    WritingMode aWM, BaselineSharingGroup aBaselineGroup,
    863    BaselineExportContext) const {
    864  if (aBaselineGroup == BaselineSharingGroup::Last) {
    865    return Nothing{};
    866  }
    867  // TODO(dshin): Some functions seem to rely on this returning
    868  // NS_INTRINSIC_ISIZE_UNKNOWN. e.g. /css/css-pseudo/target-text-008.html
    869  return Some(mBaseline);
    870 }
    871 
    872 #ifdef ACCESSIBILITY
    873 a11y::AccType nsInlineFrame::AccessibleType() {
    874  // FIXME(emilio): This is broken, if the image has its default `display` value
    875  // overridden. Should be somewhere else.
    876  if (mContent->IsHTMLElement(
    877          nsGkAtoms::img)) {  // Create accessible for broken <img>
    878    return a11y::eHyperTextType;
    879  }
    880 
    881  return a11y::eNoType;
    882 }
    883 #endif
    884 
    885 void nsInlineFrame::UpdateStyleOfOwnedAnonBoxesForIBSplit(
    886    ServoRestyleState& aRestyleState) {
    887  MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OWNS_ANON_BOXES),
    888             "Why did we get called?");
    889  MOZ_ASSERT(HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT),
    890             "Why did we have the NS_FRAME_OWNS_ANON_BOXES bit set?");
    891  // Note: this assert _looks_ expensive, but it's cheap in all the cases when
    892  // it passes!
    893  MOZ_ASSERT(nsLayoutUtils::FirstContinuationOrIBSplitSibling(this) == this,
    894             "Only the primary frame of the inline in a block-inside-inline "
    895             "split should have NS_FRAME_OWNS_ANON_BOXES");
    896  MOZ_ASSERT(mContent->GetPrimaryFrame() == this,
    897             "We should be the primary frame for our element");
    898 
    899  nsIFrame* blockFrame = GetProperty(nsIFrame::IBSplitSibling());
    900  MOZ_ASSERT(blockFrame, "Why did we have an IB split?");
    901 
    902  // The later inlines need to get our style.
    903  ComputedStyle* ourStyle = Style();
    904 
    905  // The anonymous block's style inherits from ours, and we already have our new
    906  // ComputedStyle.
    907  RefPtr<ComputedStyle> newContext =
    908      aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
    909          PseudoStyleType::mozBlockInsideInlineWrapper, ourStyle);
    910 
    911  // We're guaranteed that newContext only differs from the old ComputedStyle on
    912  // the block in things they might inherit from us.  And changehint processing
    913  // guarantees walking the continuation and ib-sibling chains, so our existing
    914  // changehint being in aChangeList is good enough.  So we don't need to touch
    915  // aChangeList at all here.
    916 
    917  while (blockFrame) {
    918    MOZ_ASSERT(!blockFrame->GetPrevContinuation(),
    919               "Must be first continuation");
    920 
    921    MOZ_ASSERT(blockFrame->Style()->GetPseudoType() ==
    922                   PseudoStyleType::mozBlockInsideInlineWrapper,
    923               "Unexpected kind of ComputedStyle");
    924 
    925    for (nsIFrame* cont = blockFrame; cont;
    926         cont = cont->GetNextContinuation()) {
    927      cont->SetComputedStyle(newContext);
    928    }
    929 
    930    nsIFrame* nextInline = blockFrame->GetProperty(nsIFrame::IBSplitSibling());
    931    MOZ_ASSERT(nextInline, "There is always a trailing inline in an IB split");
    932 
    933    for (nsIFrame* cont = nextInline; cont;
    934         cont = cont->GetNextContinuation()) {
    935      cont->SetComputedStyle(ourStyle);
    936    }
    937    blockFrame = nextInline->GetProperty(nsIFrame::IBSplitSibling());
    938  }
    939 }
    940 
    941 //////////////////////////////////////////////////////////////////////
    942 
    943 // nsLineFrame implementation
    944 
    945 nsFirstLineFrame* NS_NewFirstLineFrame(PresShell* aPresShell,
    946                                       ComputedStyle* aStyle) {
    947  return new (aPresShell)
    948      nsFirstLineFrame(aStyle, aPresShell->GetPresContext());
    949 }
    950 
    951 NS_IMPL_FRAMEARENA_HELPERS(nsFirstLineFrame)
    952 
    953 void nsFirstLineFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
    954                            nsIFrame* aPrevInFlow) {
    955  nsInlineFrame::Init(aContent, aParent, aPrevInFlow);
    956  if (!aPrevInFlow) {
    957    MOZ_ASSERT(Style()->GetPseudoType() == PseudoStyleType::firstLine);
    958    return;
    959  }
    960 
    961  // This frame is a continuation - fixup the computed style if aPrevInFlow
    962  // is the first-in-flow (the only one with a ::first-line pseudo).
    963  if (aPrevInFlow->Style()->GetPseudoType() == PseudoStyleType::firstLine) {
    964    MOZ_ASSERT(FirstInFlow() == aPrevInFlow);
    965    // Create a new ComputedStyle that is a child of the parent
    966    // ComputedStyle thus removing the ::first-line style. This way
    967    // we behave as if an anonymous (unstyled) span was the child
    968    // of the parent frame.
    969    ComputedStyle* parentContext = aParent->Style();
    970    RefPtr<ComputedStyle> newSC =
    971        PresContext()->StyleSet()->ResolveInheritingAnonymousBoxStyle(
    972            PseudoStyleType::mozLineFrame, parentContext);
    973    SetComputedStyle(newSC);
    974  } else {
    975    MOZ_ASSERT(FirstInFlow() != aPrevInFlow);
    976    MOZ_ASSERT(aPrevInFlow->Style()->GetPseudoType() ==
    977               PseudoStyleType::mozLineFrame);
    978  }
    979 }
    980 
    981 #ifdef DEBUG_FRAME_DUMP
    982 nsresult nsFirstLineFrame::GetFrameName(nsAString& aResult) const {
    983  return MakeFrameName(u"Line"_ns, aResult);
    984 }
    985 #endif
    986 
    987 nsIFrame* nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext,
    988                                         InlineReflowInput& irs) {
    989  nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs);
    990  if (frame && !GetPrevInFlow()) {
    991    // We are a first-line frame. Fixup the child frames
    992    // style-context that we just pulled.
    993    NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?");
    994    aPresContext->RestyleManager()->ReparentComputedStyleForFirstLine(frame);
    995    nsLayoutUtils::MarkDescendantsDirty(frame);
    996  }
    997  return frame;
    998 }
    999 
   1000 void nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
   1001                              ReflowOutput& aReflowOutput,
   1002                              const ReflowInput& aReflowInput,
   1003                              nsReflowStatus& aStatus) {
   1004  MarkInReflow();
   1005  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
   1006 
   1007  if (nullptr == aReflowInput.mLineLayout) {
   1008    return;  // XXX does this happen? why?
   1009  }
   1010 
   1011  // Check for an overflow list with our prev-in-flow
   1012  nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow();
   1013  if (prevInFlow) {
   1014    AutoFrameListPtr prevOverflowFrames(aPresContext,
   1015                                        prevInFlow->StealOverflowFrames());
   1016    if (prevOverflowFrames) {
   1017      // Reparent the new frames and their ComputedStyles.
   1018      const nsFrameList::Slice& newFrames =
   1019          mFrames.InsertFrames(this, nullptr, std::move(*prevOverflowFrames));
   1020      ReparentChildListStyle(aPresContext, newFrames, this);
   1021    }
   1022  }
   1023 
   1024  // It's also possible that we have an overflow list for ourselves.
   1025  DrainSelfOverflowList();
   1026 
   1027  // Set our own reflow input (additional state above and beyond aReflowInput).
   1028  InlineReflowInput irs;
   1029  irs.mPrevFrame = nullptr;
   1030  irs.mLineContainer = aReflowInput.mLineLayout->LineContainerFrame();
   1031  irs.mLineLayout = aReflowInput.mLineLayout;
   1032  irs.mNextInFlow = (nsInlineFrame*)GetNextInFlow();
   1033 
   1034  bool wasEmpty = mFrames.IsEmpty();
   1035  if (wasEmpty) {
   1036    // Try to pull over one frame before starting so that we know
   1037    // whether we have an anonymous block or not.
   1038    PullOneFrame(aPresContext, irs);
   1039  }
   1040 
   1041  if (nullptr == GetPrevInFlow()) {
   1042    // XXX This is pretty sick, but what we do here is to pull-up, in
   1043    // advance, all of the next-in-flows children. We re-resolve their
   1044    // style while we are at at it so that when we reflow they have
   1045    // the right style.
   1046    //
   1047    // All of this is so that text-runs reflow properly.
   1048    irs.mPrevFrame = mFrames.LastChild();
   1049    for (;;) {
   1050      nsIFrame* frame = PullOneFrame(aPresContext, irs);
   1051      if (!frame) {
   1052        break;
   1053      }
   1054      irs.mPrevFrame = frame;
   1055    }
   1056    irs.mPrevFrame = nullptr;
   1057  }
   1058 
   1059  NS_ASSERTION(!aReflowInput.mLineLayout->GetInFirstLine(),
   1060               "Nested first-line frames? BOGUS");
   1061  aReflowInput.mLineLayout->SetInFirstLine(true);
   1062  ReflowFrames(aPresContext, aReflowInput, irs, aReflowOutput, aStatus);
   1063  aReflowInput.mLineLayout->SetInFirstLine(false);
   1064 
   1065  ReflowAbsoluteFrames(aPresContext, aReflowOutput, aReflowInput, aStatus);
   1066 
   1067  // Note: the line layout code will properly compute our overflow state for us
   1068 }
   1069 
   1070 /* virtual */
   1071 void nsFirstLineFrame::PullOverflowsFromPrevInFlow() {
   1072  nsFirstLineFrame* prevInFlow =
   1073      static_cast<nsFirstLineFrame*>(GetPrevInFlow());
   1074  if (prevInFlow) {
   1075    nsPresContext* presContext = PresContext();
   1076    AutoFrameListPtr prevOverflowFrames(presContext,
   1077                                        prevInFlow->StealOverflowFrames());
   1078    if (prevOverflowFrames) {
   1079      // Assume that our prev-in-flow has the same line container that we do.
   1080      const nsFrameList::Slice& newFrames =
   1081          mFrames.InsertFrames(this, nullptr, std::move(*prevOverflowFrames));
   1082      ReparentChildListStyle(presContext, newFrames, this);
   1083    }
   1084  }
   1085 }
   1086 
   1087 /* virtual */
   1088 bool nsFirstLineFrame::DrainSelfOverflowList() {
   1089  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
   1090  if (overflowFrames) {
   1091    bool result = !overflowFrames->IsEmpty();
   1092    const nsFrameList::Slice& newFrames =
   1093        mFrames.AppendFrames(nullptr, std::move(*overflowFrames));
   1094    ReparentChildListStyle(PresContext(), newFrames, this);
   1095    return result;
   1096  }
   1097  return false;
   1098 }