LCOV - code coverage report
Current view: top level - layout/generic - nsBlockFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1169 3385 34.5 %
Date: 2017-07-14 16:53:18 Functions: 89 176 50.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : // vim:cindent:ts=2:et:sw=2:
       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             : /*
       8             :  * rendering object for CSS display:block, inline-block, and list-item
       9             :  * boxes, also used for various anonymous boxes
      10             :  */
      11             : 
      12             : #include "nsBlockFrame.h"
      13             : 
      14             : #include "gfxContext.h"
      15             : 
      16             : #include "mozilla/DebugOnly.h"
      17             : #include "mozilla/Maybe.h"
      18             : #include "mozilla/UniquePtr.h"
      19             : 
      20             : #include "nsCOMPtr.h"
      21             : #include "nsAbsoluteContainingBlock.h"
      22             : #include "nsBlockReflowContext.h"
      23             : #include "BlockReflowInput.h"
      24             : #include "nsBulletFrame.h"
      25             : #include "nsFontMetrics.h"
      26             : #include "nsLineBox.h"
      27             : #include "nsLineLayout.h"
      28             : #include "nsPlaceholderFrame.h"
      29             : #include "nsStyleConsts.h"
      30             : #include "nsFrameManager.h"
      31             : #include "nsPresContext.h"
      32             : #include "nsIPresShell.h"
      33             : #include "nsStyleContext.h"
      34             : #include "nsHTMLParts.h"
      35             : #include "nsGkAtoms.h"
      36             : #include "nsGenericHTMLElement.h"
      37             : #include "nsAttrValueInlines.h"
      38             : #include "mozilla/Sprintf.h"
      39             : #include "nsFloatManager.h"
      40             : #include "prenv.h"
      41             : #include "plstr.h"
      42             : #include "nsError.h"
      43             : #include "nsIScrollableFrame.h"
      44             : #include <algorithm>
      45             : #ifdef ACCESSIBILITY
      46             : #include "nsIDOMHTMLDocument.h"
      47             : #endif
      48             : #include "nsLayoutUtils.h"
      49             : #include "nsDisplayList.h"
      50             : #include "nsCSSAnonBoxes.h"
      51             : #include "nsCSSFrameConstructor.h"
      52             : #include "TextOverflow.h"
      53             : #include "nsIFrameInlines.h"
      54             : #include "CounterStyleManager.h"
      55             : #include "nsISelection.h"
      56             : #include "mozilla/dom/HTMLDetailsElement.h"
      57             : #include "mozilla/dom/HTMLSummaryElement.h"
      58             : #include "mozilla/ServoRestyleManager.h"
      59             : #include "mozilla/ServoStyleSet.h"
      60             : #include "mozilla/StyleSetHandle.h"
      61             : #include "mozilla/StyleSetHandleInlines.h"
      62             : #include "mozilla/Telemetry.h"
      63             : 
      64             : #include "nsBidiPresUtils.h"
      65             : 
      66             : #include <inttypes.h>
      67             : 
      68             : static const int MIN_LINES_NEEDING_CURSOR = 20;
      69             : 
      70             : static const char16_t kDiscCharacter = 0x2022;
      71             : 
      72             : using namespace mozilla;
      73             : using namespace mozilla::css;
      74             : using namespace mozilla::dom;
      75             : using namespace mozilla::layout;
      76             : using ShapeType = nsFloatManager::ShapeType;
      77             : typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
      78             : 
      79           0 : static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock)
      80             : {
      81           0 :   nsLineList::iterator line = aBlock->LinesBegin();
      82           0 :   nsLineList::iterator endLine = aBlock->LinesEnd();
      83           0 :   while (line != endLine) {
      84           0 :     if (line->IsBlock()) {
      85           0 :       nsIFrame* f = line->mFirstChild;
      86           0 :       nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(f);
      87           0 :       if (bf) {
      88           0 :         MarkAllDescendantLinesDirty(bf);
      89             :       }
      90             :     }
      91           0 :     line->MarkDirty();
      92           0 :     ++line;
      93             :   }
      94           0 : }
      95             : 
      96           0 : static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock)
      97             : {
      98           0 :   nsBlockFrame* blockWithFloatMgr = aBlock;
      99           0 :   while (!(blockWithFloatMgr->GetStateBits() & NS_BLOCK_FLOAT_MGR)) {
     100           0 :     nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(blockWithFloatMgr->GetParent());
     101           0 :     if (!bf) {
     102           0 :       break;
     103             :     }
     104           0 :     blockWithFloatMgr = bf;
     105             :   }
     106             : 
     107             :   // Mark every line at and below the line where the float was
     108             :   // dirty, and mark their lines dirty too. We could probably do
     109             :   // something more efficient --- e.g., just dirty the lines that intersect
     110             :   // the float vertically.
     111           0 :   MarkAllDescendantLinesDirty(blockWithFloatMgr);
     112           0 : }
     113             : 
     114             : /**
     115             :  * Returns true if aFrame is a block that has one or more float children.
     116             :  */
     117           6 : static bool BlockHasAnyFloats(nsIFrame* aFrame)
     118             : {
     119           6 :   nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
     120           6 :   if (!block)
     121           6 :     return false;
     122           0 :   if (block->GetChildList(nsIFrame::kFloatList).FirstChild())
     123           0 :     return true;
     124             : 
     125           0 :   nsLineList::iterator line = block->LinesBegin();
     126           0 :   nsLineList::iterator endLine = block->LinesEnd();
     127           0 :   while (line != endLine) {
     128           0 :     if (line->IsBlock() && BlockHasAnyFloats(line->mFirstChild))
     129           0 :       return true;
     130           0 :     ++line;
     131             :   }
     132           0 :   return false;
     133             : }
     134             : 
     135             : #ifdef DEBUG
     136             : #include "nsBlockDebugFlags.h"
     137             : 
     138             : bool nsBlockFrame::gLamePaintMetrics;
     139             : bool nsBlockFrame::gLameReflowMetrics;
     140             : bool nsBlockFrame::gNoisy;
     141             : bool nsBlockFrame::gNoisyDamageRepair;
     142             : bool nsBlockFrame::gNoisyIntrinsic;
     143             : bool nsBlockFrame::gNoisyReflow;
     144             : bool nsBlockFrame::gReallyNoisyReflow;
     145             : bool nsBlockFrame::gNoisyFloatManager;
     146             : bool nsBlockFrame::gVerifyLines;
     147             : bool nsBlockFrame::gDisableResizeOpt;
     148             : 
     149             : int32_t nsBlockFrame::gNoiseIndent;
     150             : 
     151             : struct BlockDebugFlags {
     152             :   const char* name;
     153             :   bool* on;
     154             : };
     155             : 
     156             : static const BlockDebugFlags gFlags[] = {
     157             :   { "reflow", &nsBlockFrame::gNoisyReflow },
     158             :   { "really-noisy-reflow", &nsBlockFrame::gReallyNoisyReflow },
     159             :   { "intrinsic", &nsBlockFrame::gNoisyIntrinsic },
     160             :   { "float-manager", &nsBlockFrame::gNoisyFloatManager },
     161             :   { "verify-lines", &nsBlockFrame::gVerifyLines },
     162             :   { "damage-repair", &nsBlockFrame::gNoisyDamageRepair },
     163             :   { "lame-paint-metrics", &nsBlockFrame::gLamePaintMetrics },
     164             :   { "lame-reflow-metrics", &nsBlockFrame::gLameReflowMetrics },
     165             :   { "disable-resize-opt", &nsBlockFrame::gDisableResizeOpt },
     166             : };
     167             : #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
     168             : 
     169             : static void
     170           0 : ShowDebugFlags()
     171             : {
     172           0 :   printf("Here are the available GECKO_BLOCK_DEBUG_FLAGS:\n");
     173           0 :   const BlockDebugFlags* bdf = gFlags;
     174           0 :   const BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
     175           0 :   for (; bdf < end; bdf++) {
     176           0 :     printf("  %s\n", bdf->name);
     177             :   }
     178           0 :   printf("Note: GECKO_BLOCK_DEBUG_FLAGS is a comma separated list of flag\n");
     179           0 :   printf("names (no whitespace)\n");
     180           0 : }
     181             : 
     182             : void
     183          34 : nsBlockFrame::InitDebugFlags()
     184             : {
     185             :   static bool firstTime = true;
     186          34 :   if (firstTime) {
     187           2 :     firstTime = false;
     188           2 :     char* flags = PR_GetEnv("GECKO_BLOCK_DEBUG_FLAGS");
     189           2 :     if (flags) {
     190           0 :       bool error = false;
     191             :       for (;;) {
     192           0 :         char* cm = PL_strchr(flags, ',');
     193           0 :         if (cm) *cm = '\0';
     194             : 
     195           0 :         bool found = false;
     196           0 :         const BlockDebugFlags* bdf = gFlags;
     197           0 :         const BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
     198           0 :         for (; bdf < end; bdf++) {
     199           0 :           if (PL_strcasecmp(bdf->name, flags) == 0) {
     200           0 :             *(bdf->on) = true;
     201           0 :             printf("nsBlockFrame: setting %s debug flag on\n", bdf->name);
     202           0 :             gNoisy = true;
     203           0 :             found = true;
     204           0 :             break;
     205             :           }
     206             :         }
     207           0 :         if (!found) {
     208           0 :           error = true;
     209             :         }
     210             : 
     211           0 :         if (!cm) break;
     212           0 :         *cm = ',';
     213           0 :         flags = cm + 1;
     214           0 :       }
     215           0 :       if (error) {
     216           0 :         ShowDebugFlags();
     217             :       }
     218             :     }
     219             :   }
     220          34 : }
     221             : 
     222             : #endif
     223             : 
     224             : //----------------------------------------------------------------------
     225             : 
     226             : // Debugging support code
     227             : 
     228             : #ifdef DEBUG
     229             : const char* nsBlockFrame::kReflowCommandType[] = {
     230             :   "ContentChanged",
     231             :   "StyleChanged",
     232             :   "ReflowDirty",
     233             :   "Timeout",
     234             :   "UserDefined",
     235             : };
     236             : 
     237             : const char*
     238           0 : nsBlockFrame::LineReflowStatusToString(LineReflowStatus aLineReflowStatus) const
     239             : {
     240           0 :   switch (aLineReflowStatus) {
     241           0 :     case LineReflowStatus::OK: return "LINE_REFLOW_OK";
     242           0 :     case LineReflowStatus::Stop: return "LINE_REFLOW_STOP";
     243           0 :     case LineReflowStatus::RedoNoPull: return "LINE_REFLOW_REDO_NO_PULL";
     244           0 :     case LineReflowStatus::RedoMoreFloats: return "LINE_REFLOW_REDO_MORE_FLOATS";
     245           0 :     case LineReflowStatus::RedoNextBand: return "LINE_REFLOW_REDO_NEXT_BAND";
     246           0 :     case LineReflowStatus::Truncated: return "LINE_REFLOW_TRUNCATED";
     247             :   }
     248           0 :   return "unknown";
     249             : }
     250             : 
     251             : #endif
     252             : 
     253             : #ifdef REFLOW_STATUS_COVERAGE
     254             : static void
     255             : RecordReflowStatus(bool aChildIsBlock, nsReflowStatus aFrameReflowStatus)
     256             : {
     257             :   static uint32_t record[2];
     258             : 
     259             :   // 0: child-is-block
     260             :   // 1: child-is-inline
     261             :   int index = 0;
     262             :   if (!aChildIsBlock) index |= 1;
     263             : 
     264             :   // Compute new status
     265             :   uint32_t newS = record[index];
     266             :   if (aFrameReflowStatus.IsInlineBreak()) {
     267             :     if (aFrameReflowStatus.IsInlineBreakBefore()) {
     268             :       newS |= 1;
     269             :     }
     270             :     else if (aFrameReflowStatus.IsIncomplete()) {
     271             :       newS |= 2;
     272             :     }
     273             :     else {
     274             :       newS |= 4;
     275             :     }
     276             :   }
     277             :   else if (aFrameReflowStatus.IsIncomplete()) {
     278             :     newS |= 8;
     279             :   }
     280             :   else {
     281             :     newS |= 16;
     282             :   }
     283             : 
     284             :   // Log updates to the status that yield different values
     285             :   if (record[index] != newS) {
     286             :     record[index] = newS;
     287             :     printf("record(%d): %02x %02x\n", index, record[0], record[1]);
     288             :   }
     289             : }
     290             : #endif
     291             : 
     292           0 : NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(OverflowLinesProperty,
     293             :                                                  nsBlockFrame::FrameLines)
     294           0 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowOutOfFlowsProperty)
     295           0 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(PushedFloatProperty)
     296           0 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OutsideBulletProperty)
     297           0 : NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(InsideBulletProperty, nsBulletFrame)
     298         162 : NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BlockEndEdgeOfChildrenProperty, nscoord)
     299             : 
     300             : //----------------------------------------------------------------------
     301             : 
     302             : nsBlockFrame*
     303          29 : NS_NewBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     304             : {
     305          29 :   return new (aPresShell) nsBlockFrame(aContext);
     306             : }
     307             : 
     308             : nsBlockFrame*
     309          16 : NS_NewBlockFormattingContext(nsIPresShell* aPresShell,
     310             :                              nsStyleContext* aStyleContext)
     311             : {
     312          16 :   nsBlockFrame* blockFrame = NS_NewBlockFrame(aPresShell, aStyleContext);
     313          16 :   blockFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
     314          16 :   return blockFrame;
     315             : }
     316             : 
     317          29 : NS_IMPL_FRAMEARENA_HELPERS(nsBlockFrame)
     318             : 
     319          10 : nsBlockFrame::~nsBlockFrame()
     320             : {
     321          10 : }
     322             : 
     323             : void
     324          10 : nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot)
     325             : {
     326          10 :   ClearLineCursor();
     327          10 :   DestroyAbsoluteFrames(aDestructRoot);
     328          10 :   mFloats.DestroyFramesFrom(aDestructRoot);
     329          10 :   nsPresContext* presContext = PresContext();
     330          10 :   nsIPresShell* shell = presContext->PresShell();
     331          10 :   nsLineBox::DeleteLineList(presContext, mLines, aDestructRoot,
     332          10 :                             &mFrames);
     333             : 
     334          10 :   if (HasPushedFloats()) {
     335           0 :     SafelyDestroyFrameListProp(aDestructRoot, shell,
     336           0 :                                PushedFloatProperty());
     337           0 :     RemoveStateBits(NS_BLOCK_HAS_PUSHED_FLOATS);
     338             :   }
     339             : 
     340             :   // destroy overflow lines now
     341          10 :   FrameLines* overflowLines = RemoveOverflowLines();
     342          10 :   if (overflowLines) {
     343           0 :     nsLineBox::DeleteLineList(presContext, overflowLines->mLines,
     344           0 :                               aDestructRoot, &overflowLines->mFrames);
     345           0 :     delete overflowLines;
     346             :   }
     347             : 
     348          10 :   if (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) {
     349           0 :     SafelyDestroyFrameListProp(aDestructRoot, shell,
     350           0 :                                OverflowOutOfFlowsProperty());
     351           0 :     RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
     352             :   }
     353             : 
     354          10 :   if (HasOutsideBullet()) {
     355           0 :     SafelyDestroyFrameListProp(aDestructRoot, shell,
     356           0 :                                OutsideBulletProperty());
     357           0 :     RemoveStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
     358             :   }
     359             : 
     360          10 :   nsContainerFrame::DestroyFrom(aDestructRoot);
     361          10 : }
     362             : 
     363             : /* virtual */ nsILineIterator*
     364          12 : nsBlockFrame::GetLineIterator()
     365             : {
     366          12 :   nsLineIterator* it = new nsLineIterator;
     367          12 :   if (!it)
     368           0 :     return nullptr;
     369             : 
     370          12 :   const nsStyleVisibility* visibility = StyleVisibility();
     371          12 :   nsresult rv = it->Init(mLines, visibility->mDirection == NS_STYLE_DIRECTION_RTL);
     372          12 :   if (NS_FAILED(rv)) {
     373           0 :     delete it;
     374           0 :     return nullptr;
     375             :   }
     376          12 :   return it;
     377             : }
     378             : 
     379         990 : NS_QUERYFRAME_HEAD(nsBlockFrame)
     380         769 :   NS_QUERYFRAME_ENTRY(nsBlockFrame)
     381         221 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
     382             : 
     383             : nsSplittableType
     384           0 : nsBlockFrame::GetSplittableType() const
     385             : {
     386           0 :   return NS_FRAME_SPLITTABLE_NON_RECTANGULAR;
     387             : }
     388             : 
     389             : #ifdef DEBUG_FRAME_DUMP
     390             : void
     391           0 : nsBlockFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
     392             : {
     393           0 :   nsCString str;
     394           0 :   ListGeneric(str, aPrefix, aFlags);
     395             : 
     396           0 :   fprintf_stderr(out, "%s<\n", str.get());
     397             : 
     398           0 :   nsCString pfx(aPrefix);
     399           0 :   pfx += "  ";
     400             : 
     401             :   // Output the lines
     402           0 :   if (!mLines.empty()) {
     403           0 :     ConstLineIterator line = LinesBegin(), line_end = LinesEnd();
     404           0 :     for ( ; line != line_end; ++line) {
     405           0 :       line->List(out, pfx.get(), aFlags);
     406             :     }
     407             :   }
     408             : 
     409             :   // Output the overflow lines.
     410           0 :   const FrameLines* overflowLines = GetOverflowLines();
     411           0 :   if (overflowLines && !overflowLines->mLines.empty()) {
     412           0 :     fprintf_stderr(out, "%sOverflow-lines %p/%p <\n", pfx.get(), overflowLines, &overflowLines->mFrames);
     413           0 :     nsCString nestedPfx(pfx);
     414           0 :     nestedPfx += "  ";
     415           0 :     ConstLineIterator line = overflowLines->mLines.begin(),
     416           0 :                       line_end = overflowLines->mLines.end();
     417           0 :     for ( ; line != line_end; ++line) {
     418           0 :       line->List(out, nestedPfx.get(), aFlags);
     419             :     }
     420           0 :     fprintf_stderr(out, "%s>\n", pfx.get());
     421             :   }
     422             : 
     423             :   // skip the principal list - we printed the lines above
     424             :   // skip the overflow list - we printed the overflow lines above
     425           0 :   ChildListIterator lists(this);
     426           0 :   ChildListIDs skip(kPrincipalList | kOverflowList);
     427           0 :   for (; !lists.IsDone(); lists.Next()) {
     428           0 :     if (skip.Contains(lists.CurrentID())) {
     429           0 :       continue;
     430             :     }
     431           0 :     fprintf_stderr(out, "%s%s %p <\n", pfx.get(),
     432             :       mozilla::layout::ChildListName(lists.CurrentID()),
     433           0 :       &GetChildList(lists.CurrentID()));
     434           0 :     nsCString nestedPfx(pfx);
     435           0 :     nestedPfx += "  ";
     436           0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
     437           0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
     438           0 :       nsIFrame* kid = childFrames.get();
     439           0 :       kid->List(out, nestedPfx.get(), aFlags);
     440             :     }
     441           0 :     fprintf_stderr(out, "%s>\n", pfx.get());
     442             :   }
     443             : 
     444           0 :   fprintf_stderr(out, "%s>\n", aPrefix);
     445           0 : }
     446             : 
     447             : nsresult
     448           0 : nsBlockFrame::GetFrameName(nsAString& aResult) const
     449             : {
     450           0 :   return MakeFrameName(NS_LITERAL_STRING("Block"), aResult);
     451             : }
     452             : #endif
     453             : 
     454             : #ifdef DEBUG
     455             : nsFrameState
     456           0 : nsBlockFrame::GetDebugStateBits() const
     457             : {
     458             :   // We don't want to include our cursor flag in the bits the
     459             :   // regression tester looks at
     460           0 :   return nsContainerFrame::GetDebugStateBits() & ~NS_BLOCK_HAS_LINE_CURSOR;
     461             : }
     462             : #endif
     463             : 
     464             : void
     465          33 : nsBlockFrame::InvalidateFrame(uint32_t aDisplayItemKey)
     466             : {
     467          33 :   if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     468           0 :     NS_ASSERTION(GetParent()->IsSVGTextFrame(),
     469             :                  "unexpected block frame in SVG text");
     470           0 :     GetParent()->InvalidateFrame();
     471           0 :     return;
     472             :   }
     473          33 :   nsContainerFrame::InvalidateFrame(aDisplayItemKey);
     474             : }
     475             : 
     476             : void
     477           0 : nsBlockFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
     478             : {
     479           0 :   if (nsSVGUtils::IsInSVGTextSubtree(this)) {
     480           0 :     NS_ASSERTION(GetParent()->IsSVGTextFrame(),
     481             :                  "unexpected block frame in SVG text");
     482           0 :     GetParent()->InvalidateFrame();
     483           0 :     return;
     484             :   }
     485           0 :   nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
     486             : }
     487             : 
     488             : nscoord
     489          30 : nsBlockFrame::GetLogicalBaseline(WritingMode aWM) const
     490             : {
     491             :   auto lastBaseline =
     492          30 :     BaselineBOffset(aWM, BaselineSharingGroup::eLast, AlignmentContext::eInline);
     493          30 :   return BSize(aWM) - lastBaseline;
     494             : }
     495             : 
     496             : bool
     497          30 : nsBlockFrame::GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
     498             :                                         BaselineSharingGroup aBaselineGroup,
     499             :                                         nscoord*             aBaseline) const
     500             : {
     501          30 :   if (aBaselineGroup == BaselineSharingGroup::eFirst) {
     502           0 :     return nsLayoutUtils::GetFirstLineBaseline(aWM, this, aBaseline);
     503             :   }
     504             : 
     505          60 :   for (ConstReverseLineIterator line = LinesRBegin(), line_end = LinesREnd();
     506             :        line != line_end; ++line) {
     507          30 :     if (line->IsBlock()) {
     508             :       nscoord offset;
     509           0 :       nsIFrame* kid = line->mFirstChild;
     510           0 :       if (kid->GetVerticalAlignBaseline(aWM, &offset)) {
     511             :         // Ignore relative positioning for baseline calculations.
     512           0 :         const nsSize& sz = line->mContainerSize;
     513           0 :         offset += kid->GetLogicalNormalPosition(aWM, sz).B(aWM);
     514           0 :         *aBaseline = BSize(aWM) - offset;
     515           0 :         return true;
     516             :       }
     517             :     } else {
     518             :       // XXX Is this the right test?  We have some bogus empty lines
     519             :       // floating around, but IsEmpty is perhaps too weak.
     520          30 :       if (line->BSize() != 0 || !line->IsEmpty()) {
     521           0 :         *aBaseline = BSize(aWM) - (line->BStart() + line->GetLogicalAscent());
     522           0 :         return true;
     523             :       }
     524             :     }
     525             :   }
     526          30 :   return false;
     527             : }
     528             : 
     529             : nscoord
     530           0 : nsBlockFrame::GetCaretBaseline() const
     531             : {
     532           0 :   nsRect contentRect = GetContentRect();
     533           0 :   nsMargin bp = GetUsedBorderAndPadding();
     534             : 
     535           0 :   if (!mLines.empty()) {
     536           0 :     ConstLineIterator line = LinesBegin();
     537           0 :     const nsLineBox* firstLine = line;
     538           0 :     if (firstLine->GetChildCount()) {
     539           0 :       return bp.top + firstLine->mFirstChild->GetCaretBaseline();
     540             :     }
     541             :   }
     542           0 :   float inflation = nsLayoutUtils::FontSizeInflationFor(this);
     543             :   RefPtr<nsFontMetrics> fm =
     544           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, inflation);
     545             :   nscoord lineHeight =
     546           0 :     ReflowInput::CalcLineHeight(GetContent(), StyleContext(),
     547           0 :                                       contentRect.height, inflation);
     548           0 :   const WritingMode wm = GetWritingMode();
     549           0 :   return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight,
     550           0 :                                                 wm.IsLineInverted()) + bp.top;
     551             : }
     552             : 
     553             : /////////////////////////////////////////////////////////////////////////////
     554             : // Child frame enumeration
     555             : 
     556             : const nsFrameList&
     557         703 : nsBlockFrame::GetChildList(ChildListID aListID) const
     558             : {
     559         703 :   switch (aListID) {
     560             :     case kPrincipalList:
     561          43 :       return mFrames;
     562             :     case kOverflowList: {
     563           0 :       FrameLines* overflowLines = GetOverflowLines();
     564           0 :       return overflowLines ? overflowLines->mFrames : nsFrameList::EmptyList();
     565             :     }
     566             :     case kFloatList:
     567         330 :       return mFloats;
     568             :     case kOverflowOutOfFlowList: {
     569           0 :       const nsFrameList* list = GetOverflowOutOfFlows();
     570           0 :       return list ? *list : nsFrameList::EmptyList();
     571             :     }
     572             :     case kPushedFloatsList: {
     573         330 :       const nsFrameList* list = GetPushedFloats();
     574         330 :       return list ? *list : nsFrameList::EmptyList();
     575             :     }
     576             :     case kBulletList: {
     577           0 :       const nsFrameList* list = GetOutsideBulletList();
     578           0 :       return list ? *list : nsFrameList::EmptyList();
     579             :     }
     580             :     default:
     581           0 :       return nsContainerFrame::GetChildList(aListID);
     582             :   }
     583             : }
     584             : 
     585             : void
     586         342 : nsBlockFrame::GetChildLists(nsTArray<ChildList>* aLists) const
     587             : {
     588         342 :   nsContainerFrame::GetChildLists(aLists);
     589         342 :   FrameLines* overflowLines = GetOverflowLines();
     590         342 :   if (overflowLines) {
     591           0 :     overflowLines->mFrames.AppendIfNonempty(aLists, kOverflowList);
     592             :   }
     593         342 :   const nsFrameList* list = GetOverflowOutOfFlows();
     594         342 :   if (list) {
     595           0 :     list->AppendIfNonempty(aLists, kOverflowOutOfFlowList);
     596             :   }
     597         342 :   mFloats.AppendIfNonempty(aLists, kFloatList);
     598         342 :   list = GetOutsideBulletList();
     599         342 :   if (list) {
     600           0 :     list->AppendIfNonempty(aLists, kBulletList);
     601             :   }
     602         342 :   list = GetPushedFloats();
     603         342 :   if (list) {
     604           0 :     list->AppendIfNonempty(aLists, kPushedFloatsList);
     605             :   }
     606         342 : }
     607             : 
     608             : /* virtual */ bool
     609         103 : nsBlockFrame::IsFloatContainingBlock() const
     610             : {
     611         103 :   return true;
     612             : }
     613             : 
     614             : static void
     615           0 : ReparentFrame(nsIFrame* aFrame, nsContainerFrame* aOldParent,
     616             :               nsContainerFrame* aNewParent)
     617             : {
     618           0 :   NS_ASSERTION(aOldParent == aFrame->GetParent(),
     619             :                "Parent not consistent with expectations");
     620             : 
     621           0 :   aFrame->SetParent(aNewParent);
     622             : 
     623             :   // When pushing and pulling frames we need to check for whether any
     624             :   // views need to be reparented
     625           0 :   nsContainerFrame::ReparentFrameView(aFrame, aOldParent, aNewParent);
     626           0 : }
     627             : 
     628             : static void
     629           0 : ReparentFrames(nsFrameList& aFrameList, nsContainerFrame* aOldParent,
     630             :                nsContainerFrame* aNewParent)
     631             : {
     632           0 :   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
     633           0 :     ReparentFrame(e.get(), aOldParent, aNewParent);
     634             :   }
     635           0 : }
     636             : 
     637             : /**
     638             :  * Remove the first line from aFromLines and adjust the associated frame list
     639             :  * aFromFrames accordingly.  The removed line is assigned to *aOutLine and
     640             :  * a frame list with its frames is assigned to *aOutFrames, i.e. the frames
     641             :  * that were extracted from the head of aFromFrames.
     642             :  * aFromLines must contain at least one line, the line may be empty.
     643             :  * @return true if aFromLines becomes empty
     644             :  */
     645             : static bool
     646           0 : RemoveFirstLine(nsLineList& aFromLines, nsFrameList& aFromFrames,
     647             :                 nsLineBox** aOutLine, nsFrameList* aOutFrames)
     648             : {
     649           0 :   nsLineList_iterator removedLine = aFromLines.begin();
     650           0 :   *aOutLine = removedLine;
     651           0 :   nsLineList_iterator next = aFromLines.erase(removedLine);
     652           0 :   bool isLastLine = next == aFromLines.end();
     653           0 :   nsIFrame* lastFrame = isLastLine ? aFromFrames.LastChild()
     654           0 :                                    : next->mFirstChild->GetPrevSibling();
     655           0 :   nsFrameList::FrameLinkEnumerator linkToBreak(aFromFrames, lastFrame);
     656           0 :   *aOutFrames = aFromFrames.ExtractHead(linkToBreak);
     657           0 :   return isLastLine;
     658             : }
     659             : 
     660             : //////////////////////////////////////////////////////////////////////
     661             : // Reflow methods
     662             : 
     663             : /* virtual */ void
     664          48 : nsBlockFrame::MarkIntrinsicISizesDirty()
     665             : {
     666          48 :   nsBlockFrame* dirtyBlock = static_cast<nsBlockFrame*>(FirstContinuation());
     667          48 :   dirtyBlock->mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
     668          48 :   dirtyBlock->mPrefWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
     669          48 :   if (!(GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)) {
     670           0 :     for (nsIFrame* frame = dirtyBlock; frame;
     671           0 :          frame = frame->GetNextContinuation()) {
     672           0 :       frame->AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
     673             :     }
     674             :   }
     675             : 
     676          48 :   nsContainerFrame::MarkIntrinsicISizesDirty();
     677          48 : }
     678             : 
     679             : void
     680         233 : nsBlockFrame::CheckIntrinsicCacheAgainstShrinkWrapState()
     681             : {
     682         233 :   nsPresContext *presContext = PresContext();
     683         233 :   if (!nsLayoutUtils::FontSizeInflationEnabled(presContext)) {
     684         233 :     return;
     685             :   }
     686             :   bool inflationEnabled =
     687           0 :     !presContext->mInflationDisabledForShrinkWrap;
     688           0 :   if (inflationEnabled !=
     689           0 :       !!(GetStateBits() & NS_BLOCK_FRAME_INTRINSICS_INFLATED)) {
     690           0 :     mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
     691           0 :     mPrefWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
     692           0 :     if (inflationEnabled) {
     693           0 :       AddStateBits(NS_BLOCK_FRAME_INTRINSICS_INFLATED);
     694             :     } else {
     695           0 :       RemoveStateBits(NS_BLOCK_FRAME_INTRINSICS_INFLATED);
     696             :     }
     697             :   }
     698             : }
     699             : 
     700             : /* virtual */ nscoord
     701         125 : nsBlockFrame::GetMinISize(gfxContext *aRenderingContext)
     702             : {
     703         125 :   nsIFrame* firstInFlow = FirstContinuation();
     704         125 :   if (firstInFlow != this)
     705           0 :     return firstInFlow->GetMinISize(aRenderingContext);
     706             : 
     707         250 :   DISPLAY_MIN_WIDTH(this, mMinWidth);
     708             : 
     709         125 :   CheckIntrinsicCacheAgainstShrinkWrapState();
     710             : 
     711         125 :   if (mMinWidth != NS_INTRINSIC_WIDTH_UNKNOWN)
     712          90 :     return mMinWidth;
     713             : 
     714             : #ifdef DEBUG
     715          35 :   if (gNoisyIntrinsic) {
     716           0 :     IndentBy(stdout, gNoiseIndent);
     717           0 :     ListTag(stdout);
     718           0 :     printf(": GetMinISize\n");
     719             :   }
     720          70 :   AutoNoisyIndenter indenter(gNoisyIntrinsic);
     721             : #endif
     722             : 
     723          70 :   for (nsBlockFrame* curFrame = this; curFrame;
     724          35 :        curFrame = static_cast<nsBlockFrame*>(curFrame->GetNextContinuation())) {
     725          35 :     curFrame->LazyMarkLinesDirty();
     726             :   }
     727             : 
     728          35 :   if (RenumberList()) {
     729           0 :     AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     730             :   }
     731          35 :   if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
     732          35 :     ResolveBidi();
     733          70 :   InlineMinISizeData data;
     734          70 :   for (nsBlockFrame* curFrame = this; curFrame;
     735          35 :        curFrame = static_cast<nsBlockFrame*>(curFrame->GetNextContinuation())) {
     736          70 :     for (LineIterator line = curFrame->LinesBegin(), line_end = curFrame->LinesEnd();
     737             :       line != line_end; ++line)
     738             :     {
     739             : #ifdef DEBUG
     740          35 :       if (gNoisyIntrinsic) {
     741           0 :         IndentBy(stdout, gNoiseIndent);
     742           0 :         printf("line (%s%s)\n",
     743           0 :                line->IsBlock() ? "block" : "inline",
     744           0 :                line->IsEmpty() ? ", empty" : "");
     745             :       }
     746          70 :       AutoNoisyIndenter lineindent(gNoisyIntrinsic);
     747             : #endif
     748          35 :       if (line->IsBlock()) {
     749           0 :         data.ForceBreak();
     750           0 :         data.mCurrentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
     751           0 :                         line->mFirstChild, nsLayoutUtils::MIN_ISIZE);
     752           0 :         data.ForceBreak();
     753             :       } else {
     754          70 :         if (!curFrame->GetPrevContinuation() &&
     755          35 :             line == curFrame->LinesBegin()) {
     756             :           // Only add text-indent if it has no percentages; using a
     757             :           // percentage basis of 0 unconditionally would give strange
     758             :           // behavior for calc(10%-3px).
     759          35 :           const nsStyleCoord &indent = StyleText()->mTextIndent;
     760          35 :           if (indent.ConvertsToLength())
     761          35 :             data.mCurrentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
     762             :         }
     763             :         // XXX Bug NNNNNN Should probably handle percentage text-indent.
     764             : 
     765          35 :         data.mLine = &line;
     766          35 :         data.SetLineContainer(curFrame);
     767          35 :         nsIFrame *kid = line->mFirstChild;
     768          70 :         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
     769             :              ++i, kid = kid->GetNextSibling()) {
     770          35 :           kid->AddInlineMinISize(aRenderingContext, &data);
     771             :         }
     772             :       }
     773             : #ifdef DEBUG
     774          35 :       if (gNoisyIntrinsic) {
     775           0 :         IndentBy(stdout, gNoiseIndent);
     776           0 :         printf("min: [prevLines=%d currentLine=%d]\n",
     777           0 :                data.mPrevLines, data.mCurrentLine);
     778             :       }
     779             : #endif
     780             :     }
     781             :   }
     782          35 :   data.ForceBreak();
     783             : 
     784          35 :   mMinWidth = data.mPrevLines;
     785          35 :   return mMinWidth;
     786             : }
     787             : 
     788             : /* virtual */ nscoord
     789         108 : nsBlockFrame::GetPrefISize(gfxContext *aRenderingContext)
     790             : {
     791         108 :   nsIFrame* firstInFlow = FirstContinuation();
     792         108 :   if (firstInFlow != this)
     793           0 :     return firstInFlow->GetPrefISize(aRenderingContext);
     794             : 
     795         216 :   DISPLAY_PREF_WIDTH(this, mPrefWidth);
     796             : 
     797         108 :   CheckIntrinsicCacheAgainstShrinkWrapState();
     798             : 
     799         108 :   if (mPrefWidth != NS_INTRINSIC_WIDTH_UNKNOWN)
     800          76 :     return mPrefWidth;
     801             : 
     802             : #ifdef DEBUG
     803          32 :   if (gNoisyIntrinsic) {
     804           0 :     IndentBy(stdout, gNoiseIndent);
     805           0 :     ListTag(stdout);
     806           0 :     printf(": GetPrefISize\n");
     807             :   }
     808          64 :   AutoNoisyIndenter indenter(gNoisyIntrinsic);
     809             : #endif
     810             : 
     811          64 :   for (nsBlockFrame* curFrame = this; curFrame;
     812          32 :        curFrame = static_cast<nsBlockFrame*>(curFrame->GetNextContinuation())) {
     813          32 :     curFrame->LazyMarkLinesDirty();
     814             :   }
     815             : 
     816          32 :   if (RenumberList()) {
     817           0 :     AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     818             :   }
     819          32 :   if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
     820          32 :     ResolveBidi();
     821          64 :   InlinePrefISizeData data;
     822          64 :   for (nsBlockFrame* curFrame = this; curFrame;
     823          32 :        curFrame = static_cast<nsBlockFrame*>(curFrame->GetNextContinuation())) {
     824          64 :     for (LineIterator line = curFrame->LinesBegin(), line_end = curFrame->LinesEnd();
     825             :          line != line_end; ++line)
     826             :     {
     827             : #ifdef DEBUG
     828          32 :       if (gNoisyIntrinsic) {
     829           0 :         IndentBy(stdout, gNoiseIndent);
     830           0 :         printf("line (%s%s)\n",
     831           0 :                line->IsBlock() ? "block" : "inline",
     832           0 :                line->IsEmpty() ? ", empty" : "");
     833             :       }
     834          64 :       AutoNoisyIndenter lineindent(gNoisyIntrinsic);
     835             : #endif
     836          32 :       if (line->IsBlock()) {
     837             :         StyleClear breakType;
     838           0 :         if (!data.mLineIsEmpty || BlockCanIntersectFloats(line->mFirstChild)) {
     839           0 :           breakType = StyleClear::Both;
     840             :         } else {
     841           0 :           breakType = line->mFirstChild->
     842           0 :             StyleDisplay()->PhysicalBreakType(data.mLineContainerWM);
     843             :         }
     844           0 :         data.ForceBreak(breakType);
     845           0 :         data.mCurrentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
     846           0 :                         line->mFirstChild, nsLayoutUtils::PREF_ISIZE);
     847           0 :         data.ForceBreak();
     848             :       } else {
     849          64 :         if (!curFrame->GetPrevContinuation() &&
     850          32 :             line == curFrame->LinesBegin()) {
     851             :           // Only add text-indent if it has no percentages; using a
     852             :           // percentage basis of 0 unconditionally would give strange
     853             :           // behavior for calc(10%-3px).
     854          32 :           const nsStyleCoord &indent = StyleText()->mTextIndent;
     855          32 :           if (indent.ConvertsToLength()) {
     856          32 :             nscoord length = indent.ToLength();
     857          32 :             if (length != 0) {
     858           0 :               data.mCurrentLine += length;
     859           0 :               data.mLineIsEmpty = false;
     860             :             }
     861             :           }
     862             :         }
     863             :         // XXX Bug NNNNNN Should probably handle percentage text-indent.
     864             : 
     865          32 :         data.mLine = &line;
     866          32 :         data.SetLineContainer(curFrame);
     867          32 :         nsIFrame *kid = line->mFirstChild;
     868          64 :         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
     869             :              ++i, kid = kid->GetNextSibling()) {
     870          32 :           kid->AddInlinePrefISize(aRenderingContext, &data);
     871             :         }
     872             :       }
     873             : #ifdef DEBUG
     874          32 :       if (gNoisyIntrinsic) {
     875           0 :         IndentBy(stdout, gNoiseIndent);
     876           0 :         printf("pref: [prevLines=%d currentLine=%d]\n",
     877           0 :                data.mPrevLines, data.mCurrentLine);
     878             :       }
     879             : #endif
     880             :     }
     881             :   }
     882          32 :   data.ForceBreak();
     883             : 
     884          32 :   mPrefWidth = data.mPrevLines;
     885          32 :   return mPrefWidth;
     886             : }
     887             : 
     888             : nsRect
     889           0 : nsBlockFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
     890             : {
     891             :   // be conservative
     892           0 :   if (StyleContext()->HasTextDecorationLines()) {
     893           0 :     return GetVisualOverflowRect();
     894             :   }
     895           0 :   return ComputeSimpleTightBounds(aDrawTarget);
     896             : }
     897             : 
     898             : /* virtual */ nsresult
     899           0 : nsBlockFrame::GetPrefWidthTightBounds(gfxContext* aRenderingContext,
     900             :                                       nscoord* aX,
     901             :                                       nscoord* aXMost)
     902             : {
     903           0 :   nsIFrame* firstInFlow = FirstContinuation();
     904           0 :   if (firstInFlow != this) {
     905           0 :     return firstInFlow->GetPrefWidthTightBounds(aRenderingContext, aX, aXMost);
     906             :   }
     907             : 
     908           0 :   *aX = 0;
     909           0 :   *aXMost = 0;
     910             : 
     911             :   nsresult rv;
     912           0 :   InlinePrefISizeData data;
     913           0 :   for (nsBlockFrame* curFrame = this; curFrame;
     914           0 :        curFrame = static_cast<nsBlockFrame*>(curFrame->GetNextContinuation())) {
     915           0 :     for (LineIterator line = curFrame->LinesBegin(), line_end = curFrame->LinesEnd();
     916             :          line != line_end; ++line)
     917             :     {
     918             :       nscoord childX, childXMost;
     919           0 :       if (line->IsBlock()) {
     920           0 :         data.ForceBreak();
     921           0 :         rv = line->mFirstChild->GetPrefWidthTightBounds(aRenderingContext,
     922           0 :                                                         &childX, &childXMost);
     923           0 :         NS_ENSURE_SUCCESS(rv, rv);
     924           0 :         *aX = std::min(*aX, childX);
     925           0 :         *aXMost = std::max(*aXMost, childXMost);
     926             :       } else {
     927           0 :         if (!curFrame->GetPrevContinuation() &&
     928           0 :             line == curFrame->LinesBegin()) {
     929             :           // Only add text-indent if it has no percentages; using a
     930             :           // percentage basis of 0 unconditionally would give strange
     931             :           // behavior for calc(10%-3px).
     932           0 :           const nsStyleCoord &indent = StyleText()->mTextIndent;
     933           0 :           if (indent.ConvertsToLength()) {
     934           0 :             data.mCurrentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
     935             :           }
     936             :         }
     937             :         // XXX Bug NNNNNN Should probably handle percentage text-indent.
     938             : 
     939           0 :         data.mLine = &line;
     940           0 :         data.SetLineContainer(curFrame);
     941           0 :         nsIFrame *kid = line->mFirstChild;
     942           0 :         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
     943             :              ++i, kid = kid->GetNextSibling()) {
     944             :           rv = kid->GetPrefWidthTightBounds(aRenderingContext, &childX,
     945           0 :                                             &childXMost);
     946           0 :           NS_ENSURE_SUCCESS(rv, rv);
     947           0 :           *aX = std::min(*aX, data.mCurrentLine + childX);
     948           0 :           *aXMost = std::max(*aXMost, data.mCurrentLine + childXMost);
     949           0 :           kid->AddInlinePrefISize(aRenderingContext, &data);
     950             :         }
     951             :       }
     952             :     }
     953             :   }
     954           0 :   data.ForceBreak();
     955             : 
     956           0 :   return NS_OK;
     957             : }
     958             : 
     959             : /**
     960             :  * Return whether aNewAvailableSpace is smaller *on either side*
     961             :  * (inline-start or inline-end) than aOldAvailableSpace, so that we know
     962             :  * if we need to redo layout on an line, replaced block, or block
     963             :  * formatting context, because its height (which we used to compute
     964             :  * aNewAvailableSpace) caused it to intersect additional floats.
     965             :  */
     966             : static bool
     967          75 : AvailableSpaceShrunk(WritingMode aWM,
     968             :                      const LogicalRect& aOldAvailableSpace,
     969             :                      const LogicalRect& aNewAvailableSpace,
     970             :                      bool aCanGrow /* debug-only */)
     971             : {
     972          75 :   if (aNewAvailableSpace.ISize(aWM) == 0) {
     973             :     // Positions are not significant if the inline size is zero.
     974          19 :     return aOldAvailableSpace.ISize(aWM) != 0;
     975             :   }
     976          56 :   if (aCanGrow) {
     977           0 :     NS_ASSERTION(aNewAvailableSpace.IStart(aWM) <=
     978             :                    aOldAvailableSpace.IStart(aWM) ||
     979             :                  aNewAvailableSpace.IEnd(aWM) <= aOldAvailableSpace.IEnd(aWM),
     980             :                  "available space should not shrink on the start side and "
     981             :                  "grow on the end side");
     982           0 :     NS_ASSERTION(aNewAvailableSpace.IStart(aWM) >=
     983             :                    aOldAvailableSpace.IStart(aWM) ||
     984             :                  aNewAvailableSpace.IEnd(aWM) >= aOldAvailableSpace.IEnd(aWM),
     985             :                  "available space should not grow on the start side and "
     986             :                  "shrink on the end side");
     987             :   } else {
     988          56 :     NS_ASSERTION(aOldAvailableSpace.IStart(aWM) <=
     989             :                  aNewAvailableSpace.IStart(aWM) &&
     990             :                  aOldAvailableSpace.IEnd(aWM) >=
     991             :                  aNewAvailableSpace.IEnd(aWM),
     992             :                  "available space should never grow");
     993             :   }
     994             :   // Have we shrunk on either side?
     995         112 :   return aNewAvailableSpace.IStart(aWM) > aOldAvailableSpace.IStart(aWM) ||
     996         112 :          aNewAvailableSpace.IEnd(aWM) < aOldAvailableSpace.IEnd(aWM);
     997             : }
     998             : 
     999             : static LogicalSize
    1000           0 : CalculateContainingBlockSizeForAbsolutes(WritingMode aWM,
    1001             :                                          const ReflowInput& aReflowInput,
    1002             :                                          LogicalSize aFrameSize)
    1003             : {
    1004             :   // The issue here is that for a 'height' of 'auto' the reflow state
    1005             :   // code won't know how to calculate the containing block height
    1006             :   // because it's calculated bottom up. So we use our own computed
    1007             :   // size as the dimensions.
    1008           0 :   nsIFrame* frame = aReflowInput.mFrame;
    1009             : 
    1010           0 :   LogicalSize cbSize(aFrameSize);
    1011             :     // Containing block is relative to the padding edge
    1012             :   const LogicalMargin& border =
    1013           0 :     LogicalMargin(aWM, aReflowInput.ComputedPhysicalBorderPadding() -
    1014           0 :                        aReflowInput.ComputedPhysicalPadding());
    1015           0 :   cbSize.ISize(aWM) -= border.IStartEnd(aWM);
    1016           0 :   cbSize.BSize(aWM) -= border.BStartEnd(aWM);
    1017             : 
    1018           0 :   if (frame->GetParent()->GetContent() == frame->GetContent() &&
    1019           0 :       !frame->GetParent()->IsCanvasFrame()) {
    1020             :     // We are a wrapped frame for the content (and the wrapper is not the
    1021             :     // canvas frame, whose size is not meaningful here).
    1022             :     // Use the container's dimensions, if they have been precomputed.
    1023             :     // XXX This is a hack! We really should be waiting until the outermost
    1024             :     // frame is fully reflowed and using the resulting dimensions, even
    1025             :     // if they're intrinsic.
    1026             :     // In fact we should be attaching absolute children to the outermost
    1027             :     // frame and not always sticking them in block frames.
    1028             : 
    1029             :     // First, find the reflow state for the outermost frame for this
    1030             :     // content, except for fieldsets where the inner anonymous frame has
    1031             :     // the correct padding area with the legend taken into account.
    1032           0 :     const ReflowInput* aLastRI = &aReflowInput;
    1033           0 :     const ReflowInput* lastButOneRI = &aReflowInput;
    1034           0 :     while (aLastRI->mParentReflowInput &&
    1035           0 :            aLastRI->mParentReflowInput->mFrame->GetContent() == frame->GetContent() &&
    1036           0 :            !aLastRI->mParentReflowInput->mFrame->IsFieldSetFrame()) {
    1037           0 :       lastButOneRI = aLastRI;
    1038           0 :       aLastRI = aLastRI->mParentReflowInput;
    1039             :     }
    1040           0 :     if (aLastRI != &aReflowInput) {
    1041             :       // Scrollbars need to be specifically excluded, if present, because they are outside the
    1042             :       // padding-edge. We need better APIs for getting the various boxes from a frame.
    1043           0 :       nsIScrollableFrame* scrollFrame = do_QueryFrame(aLastRI->mFrame);
    1044           0 :       nsMargin scrollbars(0,0,0,0);
    1045           0 :       if (scrollFrame) {
    1046           0 :         scrollbars =
    1047           0 :           scrollFrame->GetDesiredScrollbarSizes(aLastRI->mFrame->PresContext(),
    1048           0 :                                                 aLastRI->mRenderingContext);
    1049           0 :         if (!lastButOneRI->mFlags.mAssumingHScrollbar) {
    1050           0 :           scrollbars.top = scrollbars.bottom = 0;
    1051             :         }
    1052           0 :         if (!lastButOneRI->mFlags.mAssumingVScrollbar) {
    1053           0 :           scrollbars.left = scrollbars.right = 0;
    1054             :         }
    1055             :       }
    1056             :       // We found a reflow state for the outermost wrapping frame, so use
    1057             :       // its computed metrics if available, converted to our writing mode
    1058           0 :       WritingMode lastWM = aLastRI->GetWritingMode();
    1059             :       LogicalSize lastRISize =
    1060           0 :         LogicalSize(lastWM,
    1061             :                     aLastRI->ComputedISize(),
    1062           0 :                     aLastRI->ComputedBSize()).ConvertTo(aWM, lastWM);
    1063             :       LogicalMargin lastRIPadding =
    1064           0 :         aLastRI->ComputedLogicalPadding().ConvertTo(aWM, lastWM);
    1065           0 :       LogicalMargin logicalScrollbars(aWM, scrollbars);
    1066           0 :       if (lastRISize.ISize(aWM) != NS_UNCONSTRAINEDSIZE) {
    1067           0 :         cbSize.ISize(aWM) = std::max(0, lastRISize.ISize(aWM) +
    1068           0 :                                         lastRIPadding.IStartEnd(aWM) -
    1069           0 :                                         logicalScrollbars.IStartEnd(aWM));
    1070             :       }
    1071           0 :       if (lastRISize.BSize(aWM) != NS_UNCONSTRAINEDSIZE) {
    1072           0 :         cbSize.BSize(aWM) = std::max(0, lastRISize.BSize(aWM) +
    1073           0 :                                         lastRIPadding.BStartEnd(aWM) -
    1074           0 :                                         logicalScrollbars.BStartEnd(aWM));
    1075             :       }
    1076             :     }
    1077             :   }
    1078             : 
    1079           0 :   return cbSize;
    1080             : }
    1081             : 
    1082             : void
    1083         162 : nsBlockFrame::Reflow(nsPresContext*           aPresContext,
    1084             :                      ReflowOutput&     aMetrics,
    1085             :                      const ReflowInput& aReflowInput,
    1086             :                      nsReflowStatus&          aStatus)
    1087             : {
    1088         162 :   MarkInReflow();
    1089         162 :   DO_GLOBAL_REFLOW_COUNT("nsBlockFrame");
    1090         324 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
    1091             : #ifdef DEBUG
    1092         162 :   if (gNoisyReflow) {
    1093           0 :     IndentBy(stdout, gNoiseIndent);
    1094           0 :     ListTag(stdout);
    1095           0 :     printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n",
    1096             :            aReflowInput.AvailableISize(), aReflowInput.AvailableBSize(),
    1097           0 :            aReflowInput.ComputedISize(), aReflowInput.ComputedBSize());
    1098             :   }
    1099         324 :   AutoNoisyIndenter indent(gNoisy);
    1100         162 :   PRTime start = 0; // Initialize these variablies to silence the compiler.
    1101         162 :   int32_t ctc = 0;        // We only use these if they are set (gLameReflowMetrics).
    1102         162 :   if (gLameReflowMetrics) {
    1103           0 :     start = PR_Now();
    1104           0 :     ctc = nsLineBox::GetCtorCount();
    1105             :   }
    1106             : #endif
    1107             : 
    1108         162 :   const ReflowInput *reflowInput = &aReflowInput;
    1109         162 :   WritingMode wm = aReflowInput.GetWritingMode();
    1110         162 :   nscoord consumedBSize = ConsumedBSize(wm);
    1111         162 :   nscoord effectiveComputedBSize = GetEffectiveComputedBSize(aReflowInput,
    1112         162 :                                                              consumedBSize);
    1113         324 :   Maybe<ReflowInput> mutableReflowInput;
    1114             :   // If we have non-auto block size, we're clipping our kids and we fit,
    1115             :   // make sure our kids fit too.
    1116         324 :   if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE &&
    1117         162 :       aReflowInput.ComputedBSize() != NS_AUTOHEIGHT &&
    1118           0 :       ShouldApplyOverflowClipping(this, aReflowInput.mStyleDisplay)) {
    1119           0 :     LogicalMargin blockDirExtras = aReflowInput.ComputedLogicalBorderPadding();
    1120           0 :     if (GetLogicalSkipSides().BStart()) {
    1121           0 :       blockDirExtras.BStart(wm) = 0;
    1122             :     } else {
    1123             :       // Block-end margin never causes us to create continuations, so we
    1124             :       // don't need to worry about whether it fits in its entirety.
    1125           0 :       blockDirExtras.BStart(wm) +=
    1126           0 :         aReflowInput.ComputedLogicalMargin().BStart(wm);
    1127             :     }
    1128             : 
    1129           0 :     if (effectiveComputedBSize + blockDirExtras.BStartEnd(wm) <=
    1130           0 :         aReflowInput.AvailableBSize()) {
    1131           0 :       mutableReflowInput.emplace(aReflowInput);
    1132           0 :       mutableReflowInput->AvailableBSize() = NS_UNCONSTRAINEDSIZE;
    1133           0 :       reflowInput = mutableReflowInput.ptr();
    1134             :     }
    1135             :   }
    1136             : 
    1137             :   // See comment below about oldSize. Use *only* for the
    1138             :   // abs-pos-containing-block-size-change optimization!
    1139         162 :   nsSize oldSize = GetSize();
    1140             : 
    1141             :   // Should we create a float manager?
    1142         324 :   nsAutoFloatManager autoFloatManager(const_cast<ReflowInput&>(*reflowInput));
    1143             : 
    1144             :   // XXXldb If we start storing the float manager in the frame rather
    1145             :   // than keeping it around only during reflow then we should create it
    1146             :   // only when there are actually floats to manage.  Otherwise things
    1147             :   // like tables will gain significant bloat.
    1148         162 :   bool needFloatManager = nsBlockFrame::BlockNeedsFloatManager(this);
    1149         162 :   if (needFloatManager)
    1150         152 :     autoFloatManager.CreateFloatManager(aPresContext);
    1151             : 
    1152             :   // OK, some lines may be reflowed. Blow away any saved line cursor
    1153             :   // because we may invalidate the nondecreasing
    1154             :   // overflowArea.VisualOverflow().y/yMost invariant, and we may even
    1155             :   // delete the line with the line cursor.
    1156         162 :   ClearLineCursor();
    1157             : 
    1158         162 :   if (IsFrameTreeTooDeep(*reflowInput, aMetrics, aStatus)) {
    1159           0 :     return;
    1160             :   }
    1161             : 
    1162             : #ifdef DEBUG
    1163             :   // Between when we drain pushed floats and when we complete reflow,
    1164             :   // we're allowed to have multiple continuations of the same float on
    1165             :   // our floats list, since a first-in-flow might get pushed to a later
    1166             :   // continuation of its containing block.  But it's not permitted
    1167             :   // outside that time.
    1168         162 :   nsLayoutUtils::AssertNoDuplicateContinuations(this, mFloats);
    1169             : #endif
    1170             : 
    1171             :   // ALWAYS drain overflow. We never want to leave the previnflow's
    1172             :   // overflow lines hanging around; block reflow depends on the
    1173             :   // overflow line lists being cleared out between reflow passes.
    1174         162 :   DrainOverflowLines();
    1175             : 
    1176             :   bool blockStartMarginRoot, blockEndMarginRoot;
    1177         162 :   IsMarginRoot(&blockStartMarginRoot, &blockEndMarginRoot);
    1178             : 
    1179             :   // Cache the consumed height in the block reflow state so that we don't have
    1180             :   // to continually recompute it.
    1181             :   BlockReflowInput state(*reflowInput, aPresContext, this,
    1182             :                            blockStartMarginRoot, blockEndMarginRoot,
    1183         324 :                            needFloatManager, consumedBSize);
    1184             : 
    1185         162 :   if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
    1186         162 :     static_cast<nsBlockFrame*>(FirstContinuation())->ResolveBidi();
    1187             : 
    1188         162 :   if (RenumberList()) {
    1189           0 :     AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
    1190             :   }
    1191             : 
    1192             :   // Handle paginated overflow (see nsContainerFrame.h)
    1193         324 :   nsOverflowAreas ocBounds;
    1194         162 :   nsReflowStatus ocStatus;
    1195         162 :   if (GetPrevInFlow()) {
    1196           0 :     ReflowOverflowContainerChildren(aPresContext, *reflowInput, ocBounds, 0,
    1197           0 :                                     ocStatus);
    1198             :   }
    1199             : 
    1200             :   // Now that we're done cleaning up our overflow container lists, we can
    1201             :   // give |state| its nsOverflowContinuationTracker.
    1202         162 :   nsOverflowContinuationTracker tracker(this, false);
    1203         162 :   state.mOverflowTracker = &tracker;
    1204             : 
    1205             :   // Drain & handle pushed floats
    1206         162 :   DrainPushedFloats();
    1207         324 :   nsOverflowAreas fcBounds;
    1208         162 :   nsReflowStatus fcStatus;
    1209         162 :   ReflowPushedFloats(state, fcBounds, fcStatus);
    1210             : 
    1211             :   // If we're not dirty (which means we'll mark everything dirty later)
    1212             :   // and our inline-size has changed, mark the lines dirty that we need to
    1213             :   // mark dirty for a resize reflow.
    1214         162 :   if (!(GetStateBits() & NS_FRAME_IS_DIRTY) && reflowInput->IsIResize()) {
    1215          27 :     PrepareResizeReflow(state);
    1216             :   }
    1217             : 
    1218             :   // The same for percentage text-indent, except conditioned on the
    1219             :   // parent resizing.
    1220         424 :   if (!(GetStateBits() & NS_FRAME_IS_DIRTY) &&
    1221         200 :       reflowInput->mCBReflowInput &&
    1222         131 :       reflowInput->mCBReflowInput->IsIResize() &&
    1223         193 :       reflowInput->mStyleText->mTextIndent.HasPercent() &&
    1224           0 :       !mLines.empty()) {
    1225           0 :     mLines.front()->MarkDirty();
    1226             :   }
    1227             : 
    1228         162 :   LazyMarkLinesDirty();
    1229             : 
    1230         162 :   mState &= ~NS_FRAME_FIRST_REFLOW;
    1231             : 
    1232             :   // Now reflow...
    1233         162 :   ReflowDirtyLines(state);
    1234             : 
    1235             :   // If we have a next-in-flow, and that next-in-flow has pushed floats from
    1236             :   // this frame from a previous iteration of reflow, then we should not return
    1237             :   // a status with IsFullyComplete() equals to true, since we actually have
    1238             :   // overflow, it's just already been handled.
    1239             : 
    1240             :   // NOTE: This really shouldn't happen, since we _should_ pull back our floats
    1241             :   // and reflow them, but just in case it does, this is a safety precaution so
    1242             :   // we don't end up with a placeholder pointing to frames that have already
    1243             :   // been deleted as part of removing our next-in-flow.
    1244             :   // XXXmats maybe this code isn't needed anymore?
    1245             :   // XXXmats (layout/generic/crashtests/600100.xhtml doesn't crash without it)
    1246         162 :   if (state.mReflowStatus.IsFullyComplete()) {
    1247         162 :     nsBlockFrame* nif = static_cast<nsBlockFrame*>(GetNextInFlow());
    1248         162 :     while (nif) {
    1249           0 :       if (nif->HasPushedFloatsFromPrevContinuation()) {
    1250           0 :         if (nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
    1251           0 :           state.mReflowStatus.SetOverflowIncomplete();
    1252             :         } else {
    1253           0 :           state.mReflowStatus.SetIncomplete();
    1254             :         }
    1255           0 :         break;
    1256             :       }
    1257             : 
    1258           0 :       nif = static_cast<nsBlockFrame*>(nif->GetNextInFlow());
    1259             :     }
    1260             :   }
    1261             : 
    1262         162 :   state.mReflowStatus.MergeCompletionStatusFrom(ocStatus);
    1263         162 :   state.mReflowStatus.MergeCompletionStatusFrom(fcStatus);
    1264             : 
    1265             :   // If we end in a BR with clear and affected floats continue,
    1266             :   // we need to continue, too.
    1267         324 :   if (NS_UNCONSTRAINEDSIZE != reflowInput->AvailableBSize() &&
    1268         162 :       state.mReflowStatus.IsComplete() &&
    1269           0 :       state.FloatManager()->ClearContinues(FindTrailingClear())) {
    1270           0 :     state.mReflowStatus.SetIncomplete();
    1271             :   }
    1272             : 
    1273         162 :   if (!state.mReflowStatus.IsFullyComplete()) {
    1274           0 :     if (HasOverflowLines() || HasPushedFloats()) {
    1275           0 :       state.mReflowStatus.SetNextInFlowNeedsReflow();
    1276             :     }
    1277             : 
    1278             : #ifdef DEBUG_kipp
    1279             :     ListTag(stdout); printf(": block is not fully complete\n");
    1280             : #endif
    1281             :   }
    1282             : 
    1283             :   // Place the "marker" (bullet) frame if it is placed next to a block
    1284             :   // child.
    1285             :   //
    1286             :   // According to the CSS2 spec, section 12.6.1, the "marker" box
    1287             :   // participates in the height calculation of the list-item box's
    1288             :   // first line box.
    1289             :   //
    1290             :   // There are exactly two places a bullet can be placed: near the
    1291             :   // first or second line. It's only placed on the second line in a
    1292             :   // rare case: an empty first line followed by a second line that
    1293             :   // contains a block (example: <LI>\n<P>... ). This is where
    1294             :   // the second case can happen.
    1295         486 :   if (HasOutsideBullet() && !mLines.empty() &&
    1296           0 :       (mLines.front()->IsBlock() ||
    1297           0 :        (0 == mLines.front()->BSize() &&
    1298           0 :         mLines.front() != mLines.back() &&
    1299         162 :         mLines.begin().next()->IsBlock()))) {
    1300             :     // Reflow the bullet
    1301           0 :     ReflowOutput reflowOutput(aReflowInput);
    1302             :     // XXX Use the entire line when we fix bug 25888.
    1303             :     nsLayoutUtils::LinePosition position;
    1304           0 :     WritingMode wm = aReflowInput.GetWritingMode();
    1305           0 :     bool havePosition = nsLayoutUtils::GetFirstLinePosition(wm, this,
    1306           0 :                                                             &position);
    1307           0 :     nscoord lineBStart = havePosition ?
    1308             :       position.mBStart :
    1309           0 :       reflowInput->ComputedLogicalBorderPadding().BStart(wm);
    1310           0 :     nsIFrame* bullet = GetOutsideBullet();
    1311           0 :     ReflowBullet(bullet, state, reflowOutput, lineBStart);
    1312           0 :     NS_ASSERTION(!BulletIsEmpty() || reflowOutput.BSize(wm) == 0,
    1313             :                  "empty bullet took up space");
    1314             : 
    1315           0 :     if (havePosition && !BulletIsEmpty()) {
    1316             :       // We have some lines to align the bullet with.
    1317             : 
    1318             :       // Doing the alignment using the baseline will also cater for
    1319             :       // bullets that are placed next to a child block (bug 92896)
    1320             : 
    1321             :       // Tall bullets won't look particularly nice here...
    1322           0 :       LogicalRect bbox = bullet->GetLogicalRect(wm, reflowOutput.PhysicalSize());
    1323           0 :       bbox.BStart(wm) = position.mBaseline - reflowOutput.BlockStartAscent();
    1324           0 :       bullet->SetRect(wm, bbox, reflowOutput.PhysicalSize());
    1325             :     }
    1326             :     // Otherwise just leave the bullet where it is, up against our
    1327             :     // block-start padding.
    1328             :   }
    1329             : 
    1330         162 :   CheckFloats(state);
    1331             : 
    1332             :   // Compute our final size
    1333             :   nscoord blockEndEdgeOfChildren;
    1334         162 :   ComputeFinalSize(*reflowInput, state, aMetrics, &blockEndEdgeOfChildren);
    1335             : 
    1336             :   // If the block direction is right-to-left, we need to update the bounds of
    1337             :   // lines that were placed relative to mContainerSize during reflow, as
    1338             :   // we typically do not know the true container size until we've reflowed all
    1339             :   // its children. So we use a dummy mContainerSize during reflow (see
    1340             :   // BlockReflowInput's constructor) and then fix up the positions of the
    1341             :   // lines here, once the final block size is known.
    1342             :   //
    1343             :   // Note that writing-mode:vertical-rl is the only case where the block
    1344             :   // logical direction progresses in a negative physical direction, and
    1345             :   // therefore block-dir coordinate conversion depends on knowing the width
    1346             :   // of the coordinate space in order to translate between the logical and
    1347             :   // physical origins.
    1348         162 :   if (wm.IsVerticalRL()) {
    1349           0 :     nsSize containerSize = aMetrics.PhysicalSize();
    1350           0 :     nscoord deltaX = containerSize.width - state.ContainerSize().width;
    1351           0 :     if (deltaX != 0) {
    1352           0 :       for (LineIterator line = LinesBegin(), end = LinesEnd();
    1353             :            line != end; line++) {
    1354           0 :         UpdateLineContainerSize(line, containerSize);
    1355             :       }
    1356           0 :       for (nsIFrame* f : mFloats) {
    1357           0 :         nsPoint physicalDelta(deltaX, 0);
    1358           0 :         f->MovePositionBy(physicalDelta);
    1359             :       }
    1360           0 :       nsFrameList* bulletList = GetOutsideBulletList();
    1361           0 :       if (bulletList) {
    1362           0 :         nsPoint physicalDelta(deltaX, 0);
    1363           0 :         for (nsIFrame* f : *bulletList) {
    1364           0 :           f->MovePositionBy(physicalDelta);
    1365             :         }
    1366             :       }
    1367             :     }
    1368             :   }
    1369             : 
    1370         324 :   nsRect areaBounds = nsRect(0, 0, aMetrics.Width(), aMetrics.Height());
    1371         324 :   ComputeOverflowAreas(areaBounds, reflowInput->mStyleDisplay,
    1372         324 :                        blockEndEdgeOfChildren, aMetrics.mOverflowAreas);
    1373             :   // Factor overflow container child bounds into the overflow area
    1374         162 :   aMetrics.mOverflowAreas.UnionWith(ocBounds);
    1375             :   // Factor pushed float child bounds into the overflow area
    1376         162 :   aMetrics.mOverflowAreas.UnionWith(fcBounds);
    1377             : 
    1378             :   // Let the absolutely positioned container reflow any absolutely positioned
    1379             :   // child frames that need to be reflowed, e.g., elements with a percentage
    1380             :   // based width/height
    1381             :   // We want to do this under either of two conditions:
    1382             :   //  1. If we didn't do the incremental reflow above.
    1383             :   //  2. If our size changed.
    1384             :   // Even though it's the padding edge that's the containing block, we
    1385             :   // can use our rect (the border edge) since if the border style
    1386             :   // changed, the reflow would have been targeted at us so we'd satisfy
    1387             :   // condition 1.
    1388             :   // XXX checking oldSize is bogus, there are various reasons we might have
    1389             :   // reflowed but our size might not have been changed to what we
    1390             :   // asked for (e.g., we ended up being pushed to a new page)
    1391             :   // When WillReflowAgainForClearance is true, we will reflow again without
    1392             :   // resetting the size. Because of this, we must not reflow our abs-pos children
    1393             :   // in that situation --- what we think is our "new size"
    1394             :   // will not be our real new size. This also happens to be more efficient.
    1395         162 :   WritingMode parentWM = aMetrics.GetWritingMode();
    1396         162 :   if (HasAbsolutelyPositionedChildren()) {
    1397           0 :     nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
    1398           0 :     bool haveInterrupt = aPresContext->HasPendingInterrupt();
    1399           0 :     if (reflowInput->WillReflowAgainForClearance() ||
    1400             :         haveInterrupt) {
    1401             :       // Make sure that when we reflow again we'll actually reflow all the abs
    1402             :       // pos frames that might conceivably depend on our size (or all of them,
    1403             :       // if we're dirty right now and interrupted; in that case we also need
    1404             :       // to mark them all with NS_FRAME_IS_DIRTY).  Sadly, we can't do much
    1405             :       // better than that, because we don't really know what our size will be,
    1406             :       // and it might in fact not change on the followup reflow!
    1407           0 :       if (haveInterrupt && (GetStateBits() & NS_FRAME_IS_DIRTY)) {
    1408           0 :         absoluteContainer->MarkAllFramesDirty();
    1409             :       } else {
    1410           0 :         absoluteContainer->MarkSizeDependentFramesDirty();
    1411             :       }
    1412             :     } else {
    1413             :       LogicalSize containingBlockSize =
    1414             :         CalculateContainingBlockSizeForAbsolutes(parentWM, *reflowInput,
    1415           0 :                                                  aMetrics.Size(parentWM));
    1416             : 
    1417             :       // Mark frames that depend on changes we just made to this frame as dirty:
    1418             :       // Now we can assume that the padding edge hasn't moved.
    1419             :       // We need to reflow the absolutes if one of them depends on
    1420             :       // its placeholder position, or the containing block size in a
    1421             :       // direction in which the containing block size might have
    1422             :       // changed.
    1423             : 
    1424             :       // XXX "width" and "height" in this block will become ISize and BSize
    1425             :       // when nsAbsoluteContainingBlock is logicalized
    1426           0 :       bool cbWidthChanged = aMetrics.Width() != oldSize.width;
    1427           0 :       bool isRoot = !GetContent()->GetParent();
    1428             :       // If isRoot and we have auto height, then we are the initial
    1429             :       // containing block and the containing block height is the
    1430             :       // viewport height, which can't change during incremental
    1431             :       // reflow.
    1432             :       bool cbHeightChanged =
    1433           0 :         !(isRoot && NS_UNCONSTRAINEDSIZE == reflowInput->ComputedHeight()) &&
    1434           0 :         aMetrics.Height() != oldSize.height;
    1435             : 
    1436           0 :       nsRect containingBlock(nsPoint(0, 0),
    1437           0 :                              containingBlockSize.GetPhysicalSize(parentWM));
    1438           0 :       AbsPosReflowFlags flags = AbsPosReflowFlags::eConstrainHeight;
    1439           0 :       if (cbWidthChanged) {
    1440           0 :         flags |= AbsPosReflowFlags::eCBWidthChanged;
    1441             :       }
    1442           0 :       if (cbHeightChanged) {
    1443           0 :         flags |= AbsPosReflowFlags::eCBHeightChanged;
    1444             :       }
    1445             :       // Setup the line cursor here to optimize line searching for
    1446             :       // calculating hypothetical position of absolutely-positioned
    1447             :       // frames. The line cursor is immediately cleared afterward to
    1448             :       // avoid affecting the display list generation.
    1449           0 :       AutoLineCursorSetup autoLineCursor(this);
    1450           0 :       absoluteContainer->Reflow(this, aPresContext, *reflowInput,
    1451             :                                 state.mReflowStatus,
    1452             :                                 containingBlock, flags,
    1453           0 :                                 &aMetrics.mOverflowAreas);
    1454             :     }
    1455             :   }
    1456             : 
    1457         162 :   FinishAndStoreOverflow(&aMetrics, reflowInput->mStyleDisplay);
    1458             : 
    1459         162 :   aStatus = state.mReflowStatus;
    1460             : 
    1461             : #ifdef DEBUG
    1462             :   // Between when we drain pushed floats and when we complete reflow,
    1463             :   // we're allowed to have multiple continuations of the same float on
    1464             :   // our floats list, since a first-in-flow might get pushed to a later
    1465             :   // continuation of its containing block.  But it's not permitted
    1466             :   // outside that time.
    1467         162 :   nsLayoutUtils::AssertNoDuplicateContinuations(this, mFloats);
    1468             : 
    1469         162 :   if (gNoisyReflow) {
    1470           0 :     IndentBy(stdout, gNoiseIndent);
    1471           0 :     ListTag(stdout);
    1472           0 :     printf(": status=%s metrics=%d,%d carriedMargin=%d",
    1473           0 :            ToString(aStatus).c_str(),
    1474           0 :            aMetrics.ISize(parentWM), aMetrics.BSize(parentWM),
    1475           0 :            aMetrics.mCarriedOutBEndMargin.get());
    1476           0 :     if (HasOverflowAreas()) {
    1477           0 :       printf(" overflow-vis={%d,%d,%d,%d}",
    1478           0 :              aMetrics.VisualOverflow().x,
    1479           0 :              aMetrics.VisualOverflow().y,
    1480           0 :              aMetrics.VisualOverflow().width,
    1481           0 :              aMetrics.VisualOverflow().height);
    1482           0 :       printf(" overflow-scr={%d,%d,%d,%d}",
    1483           0 :              aMetrics.ScrollableOverflow().x,
    1484           0 :              aMetrics.ScrollableOverflow().y,
    1485           0 :              aMetrics.ScrollableOverflow().width,
    1486           0 :              aMetrics.ScrollableOverflow().height);
    1487             :     }
    1488           0 :     printf("\n");
    1489             :   }
    1490             : 
    1491         162 :   if (gLameReflowMetrics) {
    1492           0 :     PRTime end = PR_Now();
    1493             : 
    1494           0 :     int32_t ectc = nsLineBox::GetCtorCount();
    1495           0 :     int32_t numLines = mLines.size();
    1496           0 :     if (!numLines) numLines = 1;
    1497             :     PRTime delta, perLineDelta, lines;
    1498           0 :     lines = int64_t(numLines);
    1499           0 :     delta = end - start;
    1500           0 :     perLineDelta = delta / lines;
    1501             : 
    1502           0 :     ListTag(stdout);
    1503             :     char buf[400];
    1504           0 :     SprintfLiteral(buf,
    1505             :                    ": %" PRId64 " elapsed (%" PRId64 " per line) (%d lines; %d new lines)",
    1506           0 :                    delta, perLineDelta, numLines, ectc - ctc);
    1507           0 :     printf("%s\n", buf);
    1508             :   }
    1509             : #endif
    1510             : 
    1511             : #ifdef EARLY_BETA_OR_EARLIER
    1512             :   // Bug 1358299 START: Remove this code after the 56 merge date.
    1513             :   static bool sIsTelemetryEnabled;
    1514             :   static bool sTelemetryPrefCached = false;
    1515             : 
    1516         162 :   if (!sTelemetryPrefCached) {
    1517           2 :     sTelemetryPrefCached = true;
    1518             :     Preferences::AddBoolVarCache(&sIsTelemetryEnabled,
    1519           2 :                                  "toolkit.telemetry.enabled");
    1520             :   }
    1521             : 
    1522         162 :   if (sIsTelemetryEnabled) {
    1523             :     // Collect data for the BOX_ALIGN_PROPS_IN_BLOCKS_FLAG probe.
    1524           0 :     auto IsStyleNormalOrAuto = [](uint16_t value)->bool {
    1525           0 :       return ((value == NS_STYLE_ALIGN_NORMAL) ||
    1526           0 :               (value == NS_STYLE_ALIGN_AUTO));
    1527             :     };
    1528             : 
    1529             :     // First check this frame for non-default values of the css-align properties
    1530             :     // that apply to block containers.
    1531             :     // Note: we check here for non-default "justify-items", though technically
    1532             :     // that'd only affect rendering if some child has "justify-self:auto".
    1533             :     // (It's safe to assume that's likely, since it's the default value that
    1534             :     // a child would have.) We also pass in nullptr for the parent style context
    1535             :     // because an accurate parameter is slower and only necessary to detect a
    1536             :     // narrow edge case with the "legacy" keyword.
    1537           0 :     const nsStylePosition* stylePosition = reflowInput->mStylePosition;
    1538           0 :     if (!IsStyleNormalOrAuto(stylePosition->mJustifyContent) ||
    1539           0 :         !IsStyleNormalOrAuto(stylePosition->mAlignContent) ||
    1540           0 :         !IsStyleNormalOrAuto(stylePosition->ComputedJustifyItems(nullptr))) {
    1541           0 :       Telemetry::Accumulate(Telemetry::BOX_ALIGN_PROPS_IN_BLOCKS_FLAG, true);
    1542             :     } else {
    1543             :       // If not already flagged by the parent, now check justify-self of the
    1544             :       // block-level child frames.
    1545           0 :       for (nsBlockFrame::LineIterator line = LinesBegin();
    1546           0 :            line != LinesEnd(); ++line) {
    1547           0 :         if (line->IsBlock() &&
    1548           0 :             !IsStyleNormalOrAuto(line->mFirstChild->StylePosition()->mJustifySelf)) {
    1549           0 :           Telemetry::Accumulate(Telemetry::BOX_ALIGN_PROPS_IN_BLOCKS_FLAG, true);
    1550           0 :           break;
    1551             :         }
    1552             :       }
    1553             :     }
    1554             :   }
    1555             :   // Bug 1358299 END
    1556             : #endif
    1557             : 
    1558         162 :   NS_FRAME_SET_TRUNCATION(aStatus, (*reflowInput), aMetrics);
    1559             : }
    1560             : 
    1561             : bool
    1562          10 : nsBlockFrame::CheckForCollapsedBEndMarginFromClearanceLine()
    1563             : {
    1564          10 :   LineIterator begin = LinesBegin();
    1565          10 :   LineIterator line = LinesEnd();
    1566             : 
    1567             :   while (true) {
    1568          10 :     if (begin == line) {
    1569           9 :       return false;
    1570             :     }
    1571           1 :     --line;
    1572           1 :     if (line->BSize() != 0 || !line->CachedIsEmpty()) {
    1573           1 :       return false;
    1574             :     }
    1575           0 :     if (line->HasClearance()) {
    1576           0 :       return true;
    1577             :     }
    1578             :   }
    1579             :   // not reached
    1580             : }
    1581             : 
    1582             : void
    1583         162 : nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
    1584             :                                BlockReflowInput&  aState,
    1585             :                                ReflowOutput&      aMetrics,
    1586             :                                nscoord*           aBEndEdgeOfChildren)
    1587             : {
    1588         162 :   WritingMode wm = aState.mReflowInput.GetWritingMode();
    1589         162 :   const LogicalMargin& borderPadding = aState.BorderPadding();
    1590             : #ifdef NOISY_FINAL_SIZE
    1591             :   ListTag(stdout);
    1592             :   printf(": mBCoord=%d mIsBEndMarginRoot=%s mPrevBEndMargin=%d bp=%d,%d\n",
    1593             :          aState.mBCoord, aState.mFlags.mIsBEndMarginRoot ? "yes" : "no",
    1594             :          aState.mPrevBEndMargin.get(),
    1595             :          borderPadding.BStart(wm), borderPadding.BEnd(wm));
    1596             : #endif
    1597             : 
    1598             :   // Compute final inline size
    1599         162 :   LogicalSize finalSize(wm);
    1600         324 :   finalSize.ISize(wm) =
    1601         162 :     NSCoordSaturatingAdd(NSCoordSaturatingAdd(borderPadding.IStart(wm),
    1602             :                                               aReflowInput.ComputedISize()),
    1603             :                          borderPadding.IEnd(wm));
    1604             : 
    1605             :   // Return block-end margin information
    1606             :   // rbs says he hit this assertion occasionally (see bug 86947), so
    1607             :   // just set the margin to zero and we'll figure out why later
    1608             :   //NS_ASSERTION(aMetrics.mCarriedOutBEndMargin.IsZero(),
    1609             :   //             "someone else set the margin");
    1610         162 :   nscoord nonCarriedOutBDirMargin = 0;
    1611         162 :   if (!aState.mFlags.mIsBEndMarginRoot) {
    1612             :     // Apply rule from CSS 2.1 section 8.3.1. If we have some empty
    1613             :     // line with clearance and a non-zero block-start margin and all
    1614             :     // subsequent lines are empty, then we do not allow our children's
    1615             :     // carried out block-end margin to be carried out of us and collapse
    1616             :     // with our own block-end margin.
    1617          10 :     if (CheckForCollapsedBEndMarginFromClearanceLine()) {
    1618             :       // Convert the children's carried out margin to something that
    1619             :       // we will include in our height
    1620           0 :       nonCarriedOutBDirMargin = aState.mPrevBEndMargin.get();
    1621           0 :       aState.mPrevBEndMargin.Zero();
    1622             :     }
    1623          10 :     aMetrics.mCarriedOutBEndMargin = aState.mPrevBEndMargin;
    1624             :   } else {
    1625         152 :     aMetrics.mCarriedOutBEndMargin.Zero();
    1626             :   }
    1627             : 
    1628         162 :   nscoord blockEndEdgeOfChildren = aState.mBCoord + nonCarriedOutBDirMargin;
    1629             :   // Shrink wrap our height around our contents.
    1630         172 :   if (aState.mFlags.mIsBEndMarginRoot ||
    1631          10 :       NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize()) {
    1632             :     // When we are a block-end-margin root make sure that our last
    1633             :     // childs block-end margin is fully applied. We also do this when
    1634             :     // we have a computed height, since in that case the carried out
    1635             :     // margin is not going to be applied anywhere, so we should note it
    1636             :     // here to be included in the overflow area.
    1637             :     // Apply the margin only if there's space for it.
    1638         156 :     if (blockEndEdgeOfChildren < aState.mReflowInput.AvailableBSize())
    1639             :     {
    1640             :       // Truncate block-end margin if it doesn't fit to our available BSize.
    1641         156 :       blockEndEdgeOfChildren =
    1642         468 :         std::min(blockEndEdgeOfChildren + aState.mPrevBEndMargin.get(),
    1643         468 :                aState.mReflowInput.AvailableBSize());
    1644             :     }
    1645             :   }
    1646         162 :   if (aState.mFlags.mBlockNeedsFloatManager) {
    1647             :     // Include the float manager's state to properly account for the
    1648             :     // block-end margin of any floated elements; e.g., inside a table cell.
    1649             :     nscoord floatHeight =
    1650         152 :       aState.ClearFloats(blockEndEdgeOfChildren, StyleClear::Both,
    1651         152 :                          nullptr, nsFloatManager::DONT_CLEAR_PUSHED_FLOATS);
    1652         152 :     blockEndEdgeOfChildren = std::max(blockEndEdgeOfChildren, floatHeight);
    1653             :   }
    1654             : 
    1655         324 :   if (NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize()
    1656         162 :       && (!GetParent()->IsColumnSetFrame() ||
    1657           0 :           aReflowInput.mParentReflowInput->AvailableBSize() == NS_UNCONSTRAINEDSIZE)) {
    1658          88 :     ComputeFinalBSize(aReflowInput, &aState.mReflowStatus,
    1659          44 :                       aState.mBCoord + nonCarriedOutBDirMargin,
    1660          44 :                       borderPadding, finalSize, aState.mConsumedBSize);
    1661          44 :     if (!aState.mReflowStatus.IsComplete()) {
    1662             :       // Use the current height; continuations will take up the rest.
    1663             :       // Do extend the height to at least consume the available
    1664             :       // height, otherwise our left/right borders (for example) won't
    1665             :       // extend all the way to the break.
    1666           0 :       finalSize.BSize(wm) = std::max(aReflowInput.AvailableBSize(),
    1667           0 :                                      aState.mBCoord + nonCarriedOutBDirMargin);
    1668             :       // ... but don't take up more block size than is available
    1669             :       nscoord effectiveComputedBSize =
    1670           0 :         GetEffectiveComputedBSize(aReflowInput, aState.ConsumedBSize());
    1671           0 :       finalSize.BSize(wm) =
    1672           0 :         std::min(finalSize.BSize(wm),
    1673           0 :                  borderPadding.BStart(wm) + effectiveComputedBSize);
    1674             :       // XXX It's pretty wrong that our bottom border still gets drawn on
    1675             :       // on its own on the last-in-flow, even if we ran out of height
    1676             :       // here. We need GetSkipSides to check whether we ran out of content
    1677             :       // height in the current frame, not whether it's last-in-flow.
    1678             :     }
    1679             : 
    1680             :     // Don't carry out a block-end margin when our BSize is fixed.
    1681          44 :     aMetrics.mCarriedOutBEndMargin.Zero();
    1682             :   }
    1683         118 :   else if (aState.mReflowStatus.IsComplete()) {
    1684         118 :     nscoord contentBSize = blockEndEdgeOfChildren - borderPadding.BStart(wm);
    1685         118 :     nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
    1686         118 :     if (autoBSize != contentBSize) {
    1687             :       // Our min- or max-bsize value made our bsize change.  Don't carry out
    1688             :       // our kids' block-end margins.
    1689          46 :       aMetrics.mCarriedOutBEndMargin.Zero();
    1690             :     }
    1691         118 :     autoBSize += borderPadding.BStart(wm) + borderPadding.BEnd(wm);
    1692         118 :     finalSize.BSize(wm) = autoBSize;
    1693             :   }
    1694             :   else {
    1695           0 :     NS_ASSERTION(aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
    1696             :       "Shouldn't be incomplete if availableBSize is UNCONSTRAINED.");
    1697           0 :     finalSize.BSize(wm) = std::max(aState.mBCoord,
    1698           0 :                                    aReflowInput.AvailableBSize());
    1699           0 :     if (aReflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
    1700             :       // This should never happen, but it does. See bug 414255
    1701           0 :       finalSize.BSize(wm) = aState.mBCoord;
    1702             :     }
    1703             :   }
    1704             : 
    1705         162 :   if (IS_TRUE_OVERFLOW_CONTAINER(this)) {
    1706           0 :     if (aState.mReflowStatus.IsIncomplete()) {
    1707             :       // Overflow containers can only be overflow complete.
    1708             :       // Note that auto height overflow containers have no normal children
    1709           0 :       NS_ASSERTION(finalSize.BSize(wm) == 0,
    1710             :                    "overflow containers must be zero-block-size");
    1711           0 :       aState.mReflowStatus.SetOverflowIncomplete();
    1712             :     }
    1713         324 :   } else if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE &&
    1714         162 :              !aState.mReflowStatus.IsInlineBreakBefore() &&
    1715           0 :              aState.mReflowStatus.IsComplete()) {
    1716             :     // Currently only used for grid items, but could be used in other contexts.
    1717             :     // The FragStretchBSizeProperty is our expected non-fragmented block-size
    1718             :     // we should stretch to (for align-self:stretch etc).  In some fragmentation
    1719             :     // cases though, the last fragment (this frame since we're complete), needs
    1720             :     // to have extra size applied because earlier fragments consumed too much of
    1721             :     // our computed size due to overflowing their containing block.  (E.g. this
    1722             :     // ensures we fill the last row when a multi-row grid item is fragmented).
    1723             :     bool found;
    1724           0 :     nscoord bSize = GetProperty(FragStretchBSizeProperty(), &found);
    1725           0 :     if (found) {
    1726           0 :       finalSize.BSize(wm) = std::max(bSize, finalSize.BSize(wm));
    1727             :     }
    1728             :   }
    1729             : 
    1730             :   // Clamp the content size to fit within the margin-box clamp size, if any.
    1731         162 :   if (MOZ_UNLIKELY(aReflowInput.mFlags.mBClampMarginBoxMinSize) &&
    1732           0 :       aState.mReflowStatus.IsComplete()) {
    1733             :     bool found;
    1734           0 :     nscoord cbSize = GetProperty(BClampMarginBoxMinSizeProperty(), &found);
    1735           0 :     if (found) {
    1736           0 :       auto marginBoxBSize = finalSize.BSize(wm) +
    1737           0 :                             aReflowInput.ComputedLogicalMargin().BStartEnd(wm);
    1738           0 :       auto overflow = marginBoxBSize - cbSize;
    1739           0 :       if (overflow > 0) {
    1740           0 :         auto contentBSize = finalSize.BSize(wm) - borderPadding.BStartEnd(wm);
    1741           0 :         auto newContentBSize = std::max(nscoord(0), contentBSize - overflow);
    1742             :         // XXXmats deal with percentages better somehow?
    1743           0 :         finalSize.BSize(wm) -= contentBSize - newContentBSize;
    1744             :       }
    1745             :     }
    1746             :   }
    1747             : 
    1748             :   // Screen out negative block sizes --- can happen due to integer overflows :-(
    1749         162 :   finalSize.BSize(wm) = std::max(0, finalSize.BSize(wm));
    1750         162 :   *aBEndEdgeOfChildren = blockEndEdgeOfChildren;
    1751             : 
    1752         162 :   if (blockEndEdgeOfChildren != finalSize.BSize(wm) - borderPadding.BEnd(wm)) {
    1753          50 :     SetProperty(BlockEndEdgeOfChildrenProperty(), blockEndEdgeOfChildren);
    1754             :   } else {
    1755         112 :     DeleteProperty(BlockEndEdgeOfChildrenProperty());
    1756             :   }
    1757             : 
    1758         162 :   aMetrics.SetSize(wm, finalSize);
    1759             : 
    1760             : #ifdef DEBUG_blocks
    1761             :   if ((CRAZY_SIZE(aMetrics.Width()) || CRAZY_SIZE(aMetrics.Height())) &&
    1762             :       !GetParent()->IsCrazySizeAssertSuppressed()) {
    1763             :     ListTag(stdout);
    1764             :     printf(": WARNING: desired:%d,%d\n", aMetrics.Width(), aMetrics.Height());
    1765             :   }
    1766             : #endif
    1767         162 : }
    1768             : 
    1769             : static void
    1770         162 : ConsiderBlockEndEdgeOfChildren(const WritingMode aWritingMode,
    1771             :                                nscoord aBEndEdgeOfChildren,
    1772             :                                nsOverflowAreas& aOverflowAreas)
    1773             : {
    1774             :   // Factor in the block-end edge of the children.  Child frames will be added
    1775             :   // to the overflow area as we iterate through the lines, but their margins
    1776             :   // won't, so we need to account for block-end margins here.
    1777             :   // REVIEW: For now, we do this for both visual and scrollable area,
    1778             :   // although when we make scrollable overflow area not be a subset of
    1779             :   // visual, we can change this.
    1780             :   // XXX Currently, overflow areas are stored as physical rects, so we have
    1781             :   // to handle writing modes explicitly here. If we change overflow rects
    1782             :   // to be stored logically, this can be simplified again.
    1783         162 :   if (aWritingMode.IsVertical()) {
    1784           0 :     if (aWritingMode.IsVerticalLR()) {
    1785           0 :       NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    1786           0 :         nsRect& o = aOverflowAreas.Overflow(otype);
    1787           0 :         o.width = std::max(o.XMost(), aBEndEdgeOfChildren) - o.x;
    1788             :       }
    1789             :     } else {
    1790           0 :       NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    1791           0 :         nsRect& o = aOverflowAreas.Overflow(otype);
    1792           0 :         nscoord xmost = o.XMost();
    1793           0 :         o.x = std::min(o.x, xmost - aBEndEdgeOfChildren);
    1794           0 :         o.width = xmost - o.x;
    1795             :       }
    1796             :     }
    1797             :   } else {
    1798         486 :     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    1799         324 :       nsRect& o = aOverflowAreas.Overflow(otype);
    1800         324 :       o.height = std::max(o.YMost(), aBEndEdgeOfChildren) - o.y;
    1801             :     }
    1802             :   }
    1803         162 : }
    1804             : 
    1805             : void
    1806         162 : nsBlockFrame::ComputeOverflowAreas(const nsRect&         aBounds,
    1807             :                                    const nsStyleDisplay* aDisplay,
    1808             :                                    nscoord               aBEndEdgeOfChildren,
    1809             :                                    nsOverflowAreas&      aOverflowAreas)
    1810             : {
    1811             :   // Compute the overflow areas of our children
    1812             :   // XXX_perf: This can be done incrementally.  It is currently one of
    1813             :   // the things that makes incremental reflow O(N^2).
    1814         324 :   nsOverflowAreas areas(aBounds, aBounds);
    1815         162 :   if (!ShouldApplyOverflowClipping(this, aDisplay)) {
    1816         313 :     for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    1817             :          line != line_end;
    1818             :          ++line) {
    1819         151 :       areas.UnionWith(line->GetOverflowAreas());
    1820             :     }
    1821             : 
    1822             :     // Factor an outside bullet in; normally the bullet will be factored into
    1823             :     // the line-box's overflow areas. However, if the line is a block
    1824             :     // line then it won't; if there are no lines, it won't. So just
    1825             :     // factor it in anyway (it can't hurt if it was already done).
    1826             :     // XXXldb Can we just fix GetOverflowArea instead?
    1827         162 :     nsIFrame* outsideBullet = GetOutsideBullet();
    1828         162 :     if (outsideBullet) {
    1829           0 :       areas.UnionAllWith(outsideBullet->GetRect());
    1830             :     }
    1831             : 
    1832         162 :     ConsiderBlockEndEdgeOfChildren(GetWritingMode(),
    1833         162 :                                    aBEndEdgeOfChildren, areas);
    1834             :   }
    1835             : 
    1836             : #ifdef NOISY_COMBINED_AREA
    1837             :   ListTag(stdout);
    1838             :   const nsRect& vis = areas.VisualOverflow();
    1839             :   printf(": VisualOverflowArea CA=%d,%d,%d,%d\n", vis.x, vis.y, vis.width, vis.height);
    1840             :   const nsRect& scr = areas.ScrollableOverflow();
    1841             :   printf(": ScrollableOverflowArea CA=%d,%d,%d,%d\n", scr.x, scr.y, scr.width, scr.height);
    1842             : #endif
    1843             : 
    1844         162 :   aOverflowAreas = areas;
    1845         162 : }
    1846             : 
    1847             : void
    1848           0 : nsBlockFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas)
    1849             : {
    1850             :   // We need to update the overflow areas of lines manually, as they
    1851             :   // get cached and re-used otherwise. Lines aren't exposed as normal
    1852             :   // frame children, so calling UnionChildOverflow alone will end up
    1853             :   // using the old cached values.
    1854           0 :   for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    1855             :        line != line_end;
    1856             :        ++line) {
    1857           0 :     nsRect bounds = line->GetPhysicalBounds();
    1858           0 :     nsOverflowAreas lineAreas(bounds, bounds);
    1859             : 
    1860           0 :     int32_t n = line->GetChildCount();
    1861           0 :     for (nsIFrame* lineFrame = line->mFirstChild;
    1862           0 :          n > 0; lineFrame = lineFrame->GetNextSibling(), --n) {
    1863           0 :       ConsiderChildOverflow(lineAreas, lineFrame);
    1864             :     }
    1865             : 
    1866             :     // Consider the overflow areas of the floats attached to the line as well
    1867           0 :     if (line->HasFloats()) {
    1868           0 :       for (nsFloatCache* fc = line->GetFirstFloat(); fc; fc = fc->Next()) {
    1869           0 :         ConsiderChildOverflow(lineAreas, fc->mFloat);
    1870             :       }
    1871             :     }
    1872             : 
    1873           0 :     line->SetOverflowAreas(lineAreas);
    1874           0 :     aOverflowAreas.UnionWith(lineAreas);
    1875             :   }
    1876             : 
    1877             :   // Union with child frames, skipping the principal and float lists
    1878             :   // since we already handled those using the line boxes.
    1879           0 :   nsLayoutUtils::UnionChildOverflow(this, aOverflowAreas,
    1880           0 :                                     kPrincipalList | kFloatList);
    1881           0 : }
    1882             : 
    1883             : bool
    1884           0 : nsBlockFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
    1885             : {
    1886             :   bool found;
    1887             :   nscoord blockEndEdgeOfChildren =
    1888           0 :     GetProperty(BlockEndEdgeOfChildrenProperty(), &found);
    1889           0 :   if (found) {
    1890           0 :     ConsiderBlockEndEdgeOfChildren(GetWritingMode(),
    1891           0 :                                    blockEndEdgeOfChildren, aOverflowAreas);
    1892             :   }
    1893             : 
    1894             :   // Line cursor invariants depend on the overflow areas of the lines, so
    1895             :   // we must clear the line cursor since those areas may have changed.
    1896           0 :   ClearLineCursor();
    1897           0 :   return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
    1898             : }
    1899             : 
    1900             : void
    1901         229 : nsBlockFrame::LazyMarkLinesDirty()
    1902             : {
    1903         229 :   if (GetStateBits() & NS_BLOCK_LOOK_FOR_DIRTY_FRAMES) {
    1904          12 :     for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    1905             :          line != line_end; ++line) {
    1906           6 :       int32_t n = line->GetChildCount();
    1907           6 :       for (nsIFrame* lineFrame = line->mFirstChild;
    1908           6 :            n > 0; lineFrame = lineFrame->GetNextSibling(), --n) {
    1909           6 :         if (NS_SUBTREE_DIRTY(lineFrame)) {
    1910             :           // NOTE:  MarkLineDirty does more than just marking the line dirty.
    1911           6 :           MarkLineDirty(line, &mLines);
    1912           6 :           break;
    1913             :         }
    1914             :       }
    1915             :     }
    1916           6 :     RemoveStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES);
    1917             :   }
    1918         229 : }
    1919             : 
    1920             : void
    1921           6 : nsBlockFrame::MarkLineDirty(LineIterator aLine, const nsLineList* aLineList)
    1922             : {
    1923             :   // Mark aLine dirty
    1924           6 :   aLine->MarkDirty();
    1925           6 :   aLine->SetInvalidateTextRuns(true);
    1926             : #ifdef DEBUG
    1927           6 :   if (gNoisyReflow) {
    1928           0 :     IndentBy(stdout, gNoiseIndent);
    1929           0 :     ListTag(stdout);
    1930           0 :     printf(": mark line %p dirty\n", static_cast<void*>(aLine.get()));
    1931             :   }
    1932             : #endif
    1933             : 
    1934             :   // Mark previous line dirty if it's an inline line so that it can
    1935             :   // maybe pullup something from the line just affected.
    1936             :   // XXX We don't need to do this if aPrevLine ends in a break-after...
    1937          18 :   if (aLine != aLineList->front() && aLine->IsInline() &&
    1938           6 :       aLine.prev()->IsInline()) {
    1939           0 :     aLine.prev()->MarkDirty();
    1940           0 :     aLine.prev()->SetInvalidateTextRuns(true);
    1941             : #ifdef DEBUG
    1942           0 :     if (gNoisyReflow) {
    1943           0 :       IndentBy(stdout, gNoiseIndent);
    1944           0 :       ListTag(stdout);
    1945             :       printf(": mark prev-line %p dirty\n",
    1946           0 :              static_cast<void*>(aLine.prev().get()));
    1947             :     }
    1948             : #endif
    1949             :   }
    1950           6 : }
    1951             : 
    1952             : /**
    1953             :  * Test whether lines are certain to be aligned left so that we can make
    1954             :  * resizing optimizations
    1955             :  */
    1956             : static inline bool
    1957          63 : IsAlignedLeft(uint8_t aAlignment,
    1958             :               uint8_t aDirection,
    1959             :               uint8_t aUnicodeBidi,
    1960             :               nsIFrame* aFrame)
    1961             : {
    1962         126 :   return nsSVGUtils::IsInSVGTextSubtree(aFrame) ||
    1963         189 :          NS_STYLE_TEXT_ALIGN_LEFT == aAlignment ||
    1964          63 :          (((NS_STYLE_TEXT_ALIGN_START == aAlignment &&
    1965           0 :            NS_STYLE_DIRECTION_LTR == aDirection) ||
    1966           0 :           (NS_STYLE_TEXT_ALIGN_END == aAlignment &&
    1967          63 :            NS_STYLE_DIRECTION_RTL == aDirection)) &&
    1968         126 :          !(NS_STYLE_UNICODE_BIDI_PLAINTEXT & aUnicodeBidi));
    1969             : }
    1970             : 
    1971             : void
    1972          27 : nsBlockFrame::PrepareResizeReflow(BlockReflowInput& aState)
    1973             : {
    1974             :   // See if we can try and avoid marking all the lines as dirty
    1975             :   bool tryAndSkipLines =
    1976             :     // The left content-edge must be a constant distance from the left
    1977             :     // border-edge.
    1978          27 :     !StylePadding()->mPadding.GetLeft().HasPercent();
    1979             : 
    1980             : #ifdef DEBUG
    1981          27 :   if (gDisableResizeOpt) {
    1982           0 :     tryAndSkipLines = false;
    1983             :   }
    1984          27 :   if (gNoisyReflow) {
    1985           0 :     if (!tryAndSkipLines) {
    1986           0 :       IndentBy(stdout, gNoiseIndent);
    1987           0 :       ListTag(stdout);
    1988           0 :       printf(": marking all lines dirty: availISize=%d\n",
    1989           0 :              aState.mReflowInput.AvailableISize());
    1990             :     }
    1991             :   }
    1992             : #endif
    1993             : 
    1994          27 :   if (tryAndSkipLines) {
    1995          27 :     WritingMode wm = aState.mReflowInput.GetWritingMode();
    1996             :     nscoord newAvailISize =
    1997          54 :       aState.mReflowInput.ComputedLogicalBorderPadding().IStart(wm) +
    1998          27 :       aState.mReflowInput.ComputedISize();
    1999             : 
    2000             : #ifdef DEBUG
    2001          27 :     if (gNoisyReflow) {
    2002           0 :       IndentBy(stdout, gNoiseIndent);
    2003           0 :       ListTag(stdout);
    2004           0 :       printf(": trying to avoid marking all lines dirty\n");
    2005             :     }
    2006             : #endif
    2007             : 
    2008          52 :     for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    2009             :          line != line_end;
    2010             :          ++line)
    2011             :     {
    2012             :       // We let child blocks make their own decisions the same
    2013             :       // way we are here.
    2014          25 :       bool isLastLine = line == mLines.back() && !GetNextInFlow();
    2015          73 :       if (line->IsBlock() ||
    2016          46 :           line->HasFloats() ||
    2017          23 :           (!isLastLine && !line->HasBreakAfter()) ||
    2018           0 :           ((isLastLine || !line->IsLineWrapped())) ||
    2019           0 :           line->ResizeReflowOptimizationDisabled() ||
    2020          25 :           line->IsImpactedByFloat() ||
    2021           0 :           (line->IEnd() > newAvailISize)) {
    2022          25 :         line->MarkDirty();
    2023             :       }
    2024             : 
    2025             : #ifdef REALLY_NOISY_REFLOW
    2026             :       if (!line->IsBlock()) {
    2027             :         printf("PrepareResizeReflow thinks line %p is %simpacted by floats\n",
    2028             :                line.get(), line->IsImpactedByFloat() ? "" : "not ");
    2029             :       }
    2030             : #endif
    2031             : #ifdef DEBUG
    2032          25 :       if (gNoisyReflow && !line->IsDirty()) {
    2033           0 :         IndentBy(stdout, gNoiseIndent + 1);
    2034           0 :         printf("skipped: line=%p next=%p %s %s%s%s breakTypeBefore/After=%s/%s xmost=%d\n",
    2035           0 :            static_cast<void*>(line.get()),
    2036           0 :            static_cast<void*>((line.next() != LinesEnd() ? line.next().get() : nullptr)),
    2037           0 :            line->IsBlock() ? "block" : "inline",
    2038           0 :            line->HasBreakAfter() ? "has-break-after " : "",
    2039           0 :            line->HasFloats() ? "has-floats " : "",
    2040           0 :            line->IsImpactedByFloat() ? "impacted " : "",
    2041             :            line->BreakTypeToString(line->GetBreakTypeBefore()),
    2042             :            line->BreakTypeToString(line->GetBreakTypeAfter()),
    2043           0 :            line->IEnd());
    2044             :       }
    2045             : #endif
    2046             :     }
    2047             :   }
    2048             :   else {
    2049             :     // Mark everything dirty
    2050           0 :     for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    2051             :          line != line_end;
    2052             :          ++line)
    2053             :     {
    2054           0 :       line->MarkDirty();
    2055             :     }
    2056             :   }
    2057          27 : }
    2058             : 
    2059             : //----------------------------------------
    2060             : 
    2061             : /**
    2062             :  * Propagate reflow "damage" from from earlier lines to the current
    2063             :  * line.  The reflow damage comes from the following sources:
    2064             :  *  1. The regions of float damage remembered during reflow.
    2065             :  *  2. The combination of nonzero |aDeltaBCoord| and any impact by a
    2066             :  *     float, either the previous reflow or now.
    2067             :  *
    2068             :  * When entering this function, |aLine| is still at its old position and
    2069             :  * |aDeltaBCoord| indicates how much it will later be slid (assuming it
    2070             :  * doesn't get marked dirty and reflowed entirely).
    2071             :  */
    2072             : void
    2073          66 : nsBlockFrame::PropagateFloatDamage(BlockReflowInput& aState,
    2074             :                                    nsLineBox* aLine,
    2075             :                                    nscoord aDeltaBCoord)
    2076             : {
    2077          66 :   nsFloatManager* floatManager = aState.FloatManager();
    2078          66 :   NS_ASSERTION((aState.mReflowInput.mParentReflowInput &&
    2079             :                 aState.mReflowInput.mParentReflowInput->mFloatManager == floatManager) ||
    2080             :                 aState.mReflowInput.mBlockDelta == 0, "Bad block delta passed in");
    2081             : 
    2082             :   // Check to see if there are any floats; if there aren't, there can't
    2083             :   // be any float damage
    2084          66 :   if (!floatManager->HasAnyFloats())
    2085          66 :     return;
    2086             : 
    2087             :   // Check the damage region recorded in the float damage.
    2088           0 :   if (floatManager->HasFloatDamage()) {
    2089             :     // Need to check mBounds *and* mCombinedArea to find intersections
    2090             :     // with aLine's floats
    2091           0 :     nscoord lineBCoordBefore = aLine->BStart() + aDeltaBCoord;
    2092           0 :     nscoord lineBCoordAfter = lineBCoordBefore + aLine->BSize();
    2093             :     // Scrollable overflow should be sufficient for things that affect
    2094             :     // layout.
    2095           0 :     WritingMode wm = aState.mReflowInput.GetWritingMode();
    2096           0 :     nsSize containerSize = aState.ContainerSize();
    2097             :     LogicalRect overflow = aLine->GetOverflowArea(eScrollableOverflow, wm,
    2098           0 :                                                   containerSize);
    2099           0 :     nscoord lineBCoordCombinedBefore = overflow.BStart(wm) + aDeltaBCoord;
    2100             :     nscoord lineBCoordCombinedAfter = lineBCoordCombinedBefore +
    2101           0 :                                       overflow.BSize(wm);
    2102             : 
    2103           0 :     bool isDirty = floatManager->IntersectsDamage(lineBCoordBefore,
    2104           0 :                                                   lineBCoordAfter) ||
    2105           0 :                    floatManager->IntersectsDamage(lineBCoordCombinedBefore,
    2106           0 :                                                   lineBCoordCombinedAfter);
    2107           0 :     if (isDirty) {
    2108           0 :       aLine->MarkDirty();
    2109           0 :       return;
    2110             :     }
    2111             :   }
    2112             : 
    2113             :   // Check if the line is moving relative to the float manager
    2114           0 :   if (aDeltaBCoord + aState.mReflowInput.mBlockDelta != 0) {
    2115           0 :     if (aLine->IsBlock()) {
    2116             :       // Unconditionally reflow sliding blocks; we only really need to reflow
    2117             :       // if there's a float impacting this block, but the current float manager
    2118             :       // makes it difficult to check that.  Therefore, we let the child block
    2119             :       // decide what it needs to reflow.
    2120           0 :       aLine->MarkDirty();
    2121             :     } else {
    2122           0 :       bool wasImpactedByFloat = aLine->IsImpactedByFloat();
    2123             :       nsFlowAreaRect floatAvailableSpace =
    2124           0 :         aState.GetFloatAvailableSpaceForBSize(aLine->BStart() + aDeltaBCoord,
    2125             :                                               aLine->BSize(),
    2126           0 :                                               nullptr);
    2127             : 
    2128             : #ifdef REALLY_NOISY_REFLOW
    2129             :     printf("nsBlockFrame::PropagateFloatDamage %p was = %d, is=%d\n",
    2130             :            this, wasImpactedByFloat, floatAvailableSpace.mHasFloats);
    2131             : #endif
    2132             : 
    2133             :       // Mark the line dirty if it was or is affected by a float
    2134             :       // We actually only really need to reflow if the amount of impact
    2135             :       // changes, but that's not straightforward to check
    2136           0 :       if (wasImpactedByFloat || floatAvailableSpace.mHasFloats) {
    2137           0 :         aLine->MarkDirty();
    2138             :       }
    2139             :     }
    2140             :   }
    2141             : }
    2142             : 
    2143         151 : static bool LineHasClear(nsLineBox* aLine) {
    2144         151 :   return aLine->IsBlock()
    2145         171 :     ? (aLine->GetBreakTypeBefore() != StyleClear::None ||
    2146          20 :        (aLine->mFirstChild->GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN) ||
    2147          10 :        !nsBlockFrame::BlockCanIntersectFloats(aLine->mFirstChild))
    2148         151 :     : aLine->HasFloatBreakAfter();
    2149             : }
    2150             : 
    2151             : 
    2152             : /**
    2153             :  * Reparent a whole list of floats from aOldParent to this block.  The
    2154             :  * floats might be taken from aOldParent's overflow list. They will be
    2155             :  * removed from the list. They end up appended to our mFloats list.
    2156             :  */
    2157             : void
    2158           0 : nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
    2159             :                              bool aReparentSiblings) {
    2160           0 :   nsFrameList list;
    2161           0 :   aOldParent->CollectFloats(aFirstFrame, list, aReparentSiblings);
    2162           0 :   if (list.NotEmpty()) {
    2163           0 :     for (nsIFrame* f : list) {
    2164           0 :       MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
    2165             :                  "CollectFloats should've removed that bit");
    2166           0 :       ReparentFrame(f, aOldParent, this);
    2167             :     }
    2168           0 :     mFloats.AppendFrames(nullptr, list);
    2169             :   }
    2170           0 : }
    2171             : 
    2172         302 : static void DumpLine(const BlockReflowInput& aState, nsLineBox* aLine,
    2173             :                      nscoord aDeltaBCoord, int32_t aDeltaIndent) {
    2174             : #ifdef DEBUG
    2175         302 :   if (nsBlockFrame::gNoisyReflow) {
    2176           0 :     nsRect ovis(aLine->GetVisualOverflowArea());
    2177           0 :     nsRect oscr(aLine->GetScrollableOverflowArea());
    2178           0 :     nsBlockFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent + aDeltaIndent);
    2179           0 :     printf("line=%p mBCoord=%d dirty=%s oldBounds={%d,%d,%d,%d} oldoverflow-vis={%d,%d,%d,%d} oldoverflow-scr={%d,%d,%d,%d} deltaBCoord=%d mPrevBEndMargin=%d childCount=%d\n",
    2180           0 :            static_cast<void*>(aLine), aState.mBCoord,
    2181           0 :            aLine->IsDirty() ? "yes" : "no",
    2182             :            aLine->IStart(), aLine->BStart(),
    2183             :            aLine->ISize(), aLine->BSize(),
    2184             :            ovis.x, ovis.y, ovis.width, ovis.height,
    2185             :            oscr.x, oscr.y, oscr.width, oscr.height,
    2186           0 :            aDeltaBCoord, aState.mPrevBEndMargin.get(), aLine->GetChildCount());
    2187             :   }
    2188             : #endif
    2189         302 : }
    2190             : 
    2191             : void
    2192         162 : nsBlockFrame::ReflowDirtyLines(BlockReflowInput& aState)
    2193             : {
    2194         162 :   bool keepGoing = true;
    2195         162 :   bool repositionViews = false; // should we really need this?
    2196         162 :   bool foundAnyClears = aState.mFloatBreakType != StyleClear::None;
    2197         162 :   bool willReflowAgain = false;
    2198             : 
    2199             : #ifdef DEBUG
    2200         162 :   if (gNoisyReflow) {
    2201           0 :     IndentBy(stdout, gNoiseIndent);
    2202           0 :     ListTag(stdout);
    2203           0 :     printf(": reflowing dirty lines");
    2204           0 :     printf(" computedISize=%d\n", aState.mReflowInput.ComputedISize());
    2205             :   }
    2206         324 :   AutoNoisyIndenter indent(gNoisyReflow);
    2207             : #endif
    2208             : 
    2209         350 :   bool selfDirty = (GetStateBits() & NS_FRAME_IS_DIRTY) ||
    2210         139 :                      (aState.mReflowInput.IsBResize() &&
    2211         201 :                       (GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE));
    2212             : 
    2213             :   // Reflow our last line if our availableBSize has increased
    2214             :   // so that we (and our last child) pull up content as necessary
    2215         648 :   if (aState.mReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE
    2216         324 :       && GetNextInFlow() && aState.mReflowInput.AvailableBSize() >
    2217         162 :         GetLogicalSize().BSize(aState.mReflowInput.GetWritingMode())) {
    2218           0 :     LineIterator lastLine = LinesEnd();
    2219           0 :     if (lastLine != LinesBegin()) {
    2220           0 :       --lastLine;
    2221           0 :       lastLine->MarkDirty();
    2222             :     }
    2223             :   }
    2224             :     // the amount by which we will slide the current line if it is not
    2225             :     // dirty
    2226         162 :   nscoord deltaBCoord = 0;
    2227             : 
    2228             :     // whether we did NOT reflow the previous line and thus we need to
    2229             :     // recompute the carried out margin before the line if we want to
    2230             :     // reflow it or if its previous margin is dirty
    2231         162 :   bool needToRecoverState = false;
    2232             :     // Float continuations were reflowed in ReflowPushedFloats
    2233         162 :   bool reflowedFloat = mFloats.NotEmpty() &&
    2234         162 :     (mFloats.FirstChild()->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT);
    2235         162 :   bool lastLineMovedUp = false;
    2236             :   // We save up information about BR-clearance here
    2237         162 :   StyleClear inlineFloatBreakType = aState.mFloatBreakType;
    2238             : 
    2239         162 :   LineIterator line = LinesBegin(), line_end = LinesEnd();
    2240             : 
    2241             :   // Reflow the lines that are already ours
    2242         464 :   for ( ; line != line_end; ++line, aState.AdvanceToNextLine()) {
    2243         151 :     DumpLine(aState, line, deltaBCoord, 0);
    2244             : #ifdef DEBUG
    2245         302 :     AutoNoisyIndenter indent2(gNoisyReflow);
    2246             : #endif
    2247             : 
    2248         151 :     if (selfDirty)
    2249          79 :       line->MarkDirty();
    2250             : 
    2251             :     // This really sucks, but we have to look inside any blocks that have clear
    2252             :     // elements inside them.
    2253             :     // XXX what can we do smarter here?
    2254         151 :     if (!line->IsDirty() && line->IsBlock() &&
    2255           0 :         (line->mFirstChild->GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN)) {
    2256           0 :       line->MarkDirty();
    2257             :     }
    2258             : 
    2259         151 :     nsIFrame *replacedBlock = nullptr;
    2260         161 :     if (line->IsBlock() &&
    2261          10 :         !nsBlockFrame::BlockCanIntersectFloats(line->mFirstChild)) {
    2262           0 :       replacedBlock = line->mFirstChild;
    2263             :     }
    2264             : 
    2265             :     // We have to reflow the line if it's a block whose clearance
    2266             :     // might have changed, so detect that.
    2267         217 :     if (!line->IsDirty() &&
    2268         132 :         (line->GetBreakTypeBefore() != StyleClear::None ||
    2269             :          replacedBlock)) {
    2270           0 :       nscoord curBCoord = aState.mBCoord;
    2271             :       // See where we would be after applying any clearance due to
    2272             :       // BRs.
    2273           0 :       if (inlineFloatBreakType != StyleClear::None) {
    2274           0 :         curBCoord = aState.ClearFloats(curBCoord, inlineFloatBreakType);
    2275             :       }
    2276             : 
    2277             :       nscoord newBCoord =
    2278           0 :         aState.ClearFloats(curBCoord, line->GetBreakTypeBefore(), replacedBlock);
    2279             : 
    2280           0 :       if (line->HasClearance()) {
    2281             :         // Reflow the line if it might not have clearance anymore.
    2282           0 :         if (newBCoord == curBCoord
    2283             :             // aState.mBCoord is the clearance point which should be the
    2284             :             // block-start border-edge of the block frame. If sliding the
    2285             :             // block by deltaBCoord isn't going to put it in the predicted
    2286             :             // position, then we'd better reflow the line.
    2287           0 :             || newBCoord != line->BStart() + deltaBCoord) {
    2288           0 :           line->MarkDirty();
    2289             :         }
    2290             :       } else {
    2291             :         // Reflow the line if the line might have clearance now.
    2292           0 :         if (curBCoord != newBCoord) {
    2293           0 :           line->MarkDirty();
    2294             :         }
    2295             :       }
    2296             :     }
    2297             : 
    2298             :     // We might have to reflow a line that is after a clearing BR.
    2299         151 :     if (inlineFloatBreakType != StyleClear::None) {
    2300           0 :       aState.mBCoord = aState.ClearFloats(aState.mBCoord, inlineFloatBreakType);
    2301           0 :       if (aState.mBCoord != line->BStart() + deltaBCoord) {
    2302             :         // SlideLine is not going to put the line where the clearance
    2303             :         // put it. Reflow the line to be sure.
    2304           0 :         line->MarkDirty();
    2305             :       }
    2306           0 :       inlineFloatBreakType = StyleClear::None;
    2307             :     }
    2308             : 
    2309         151 :     bool previousMarginWasDirty = line->IsPreviousMarginDirty();
    2310         151 :     if (previousMarginWasDirty) {
    2311             :       // If the previous margin is dirty, reflow the current line
    2312           0 :       line->MarkDirty();
    2313           0 :       line->ClearPreviousMarginDirty();
    2314         151 :     } else if (line->BEnd() + deltaBCoord > aState.mBEndEdge) {
    2315             :       // Lines that aren't dirty but get slid past our height constraint must
    2316             :       // be reflowed.
    2317           0 :       line->MarkDirty();
    2318             :     }
    2319             : 
    2320             :     // If we have a constrained height (i.e., breaking columns/pages),
    2321             :     // and the distance to the bottom might have changed, then we need
    2322             :     // to reflow any line that might have floats in it, both because the
    2323             :     // breakpoints within those floats may have changed and because we
    2324             :     // might have to push/pull the floats in their entirety.
    2325             :     // FIXME: What about a deltaBCoord or block-size change that forces us to
    2326             :     // push lines?  Why does that work?
    2327         368 :     if (!line->IsDirty() &&
    2328          66 :         aState.mReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE &&
    2329           0 :         (deltaBCoord != 0 || aState.mReflowInput.IsBResize() ||
    2330         151 :          aState.mReflowInput.mFlags.mMustReflowPlaceholders) &&
    2331           0 :         (line->IsBlock() || line->HasFloats() || line->HadFloatPushed())) {
    2332           0 :       line->MarkDirty();
    2333             :     }
    2334             : 
    2335         151 :     if (!line->IsDirty()) {
    2336             :       // See if there's any reflow damage that requires that we mark the
    2337             :       // line dirty.
    2338          66 :       PropagateFloatDamage(aState, line, deltaBCoord);
    2339             :     }
    2340             : 
    2341             :     // If the container size has changed, reset mContainerSize. If the
    2342             :     // line's writing mode is not ltr, or if the line is not left-aligned, also
    2343             :     // mark the line dirty.
    2344         151 :     if (aState.ContainerSize() != line->mContainerSize) {
    2345          63 :       line->mContainerSize = aState.ContainerSize();
    2346             : 
    2347         126 :       bool isLastLine = line == mLines.back() &&
    2348         126 :                         !GetNextInFlow() &&
    2349         126 :                         NS_STYLE_TEXT_ALIGN_AUTO == StyleText()->mTextAlignLast;
    2350         126 :       uint8_t align = isLastLine ?
    2351         126 :         StyleText()->mTextAlign : StyleText()->mTextAlignLast;
    2352             : 
    2353         189 :       if (line->mWritingMode.IsVertical() ||
    2354         126 :           !line->mWritingMode.IsBidiLTR() ||
    2355         189 :           !IsAlignedLeft(align,
    2356          63 :                          aState.mReflowInput.mStyleVisibility->mDirection,
    2357          63 :                          StyleTextReset()->mUnicodeBidi, this)) {
    2358           0 :         line->MarkDirty();
    2359             :       }
    2360             :     }
    2361             : 
    2362         151 :     if (needToRecoverState && line->IsDirty()) {
    2363             :       // We need to reconstruct the block-end margin only if we didn't
    2364             :       // reflow the previous line and we do need to reflow (or repair
    2365             :       // the block-start position of) the next line.
    2366           0 :       aState.ReconstructMarginBefore(line);
    2367             :     }
    2368             : 
    2369         151 :     bool reflowedPrevLine = !needToRecoverState;
    2370         151 :     if (needToRecoverState) {
    2371           0 :       needToRecoverState = false;
    2372             : 
    2373             :       // Update aState.mPrevChild as if we had reflowed all of the frames in
    2374             :       // this line.
    2375           0 :       if (line->IsDirty()) {
    2376           0 :         NS_ASSERTION(line->mFirstChild->GetPrevSibling() ==
    2377             :                      line.prev()->LastChild(), "unexpected line frames");
    2378           0 :         aState.mPrevChild = line->mFirstChild->GetPrevSibling();
    2379             :       }
    2380             :     }
    2381             : 
    2382             :     // Now repair the line and update |aState.mBCoord| by calling
    2383             :     // |ReflowLine| or |SlideLine|.
    2384             :     // If we're going to reflow everything again, then no need to reflow
    2385             :     // the dirty line ... unless the line has floats, in which case we'd
    2386             :     // better reflow it now to refresh its float cache, which may contain
    2387             :     // dangling frame pointers! Ugh! This reflow of the line may be
    2388             :     // incorrect because we skipped reflowing previous lines (e.g., floats
    2389             :     // may be placed incorrectly), but that's OK because we'll mark the
    2390             :     // line dirty below under "if (aState.mReflowInput.mDiscoveredClearance..."
    2391         151 :     if (line->IsDirty() && (line->HasFloats() || !willReflowAgain)) {
    2392          85 :       lastLineMovedUp = true;
    2393             : 
    2394             :       bool maybeReflowingForFirstTime =
    2395         193 :         line->IStart() == 0 && line->BStart() == 0 &&
    2396         185 :         line->ISize() == 0 && line->BSize() == 0;
    2397             : 
    2398             :       // Compute the dirty lines "before" BEnd, after factoring in
    2399             :       // the running deltaBCoord value - the running value is implicit in
    2400             :       // aState.mBCoord.
    2401          85 :       nscoord oldB = line->BStart();
    2402          85 :       nscoord oldBMost = line->BEnd();
    2403             : 
    2404          85 :       NS_ASSERTION(!willReflowAgain || !line->IsBlock(),
    2405             :                    "Don't reflow blocks while willReflowAgain is true, reflow of block abs-pos children depends on this");
    2406             : 
    2407             :       // Reflow the dirty line. If it's an incremental reflow, then force
    2408             :       // it to invalidate the dirty area if necessary
    2409          85 :       ReflowLine(aState, line, &keepGoing);
    2410             : 
    2411          85 :       if (aState.mReflowInput.WillReflowAgainForClearance()) {
    2412           0 :         line->MarkDirty();
    2413           0 :         willReflowAgain = true;
    2414             :         // Note that once we've entered this state, every line that gets here
    2415             :         // (e.g. because it has floats) gets marked dirty and reflowed again.
    2416             :         // in the next pass. This is important, see above.
    2417             :       }
    2418             : 
    2419          85 :       if (line->HasFloats()) {
    2420           0 :         reflowedFloat = true;
    2421             :       }
    2422             : 
    2423          85 :       if (!keepGoing) {
    2424           0 :         DumpLine(aState, line, deltaBCoord, -1);
    2425           0 :         if (0 == line->GetChildCount()) {
    2426           0 :           DeleteLine(aState, line, line_end);
    2427             :         }
    2428           0 :         break;
    2429             :       }
    2430             : 
    2431             :       // Test to see whether the margin that should be carried out
    2432             :       // to the next line (NL) might have changed. In ReflowBlockFrame
    2433             :       // we call nextLine->MarkPreviousMarginDirty if the block's
    2434             :       // actual carried-out block-end margin changed. So here we only
    2435             :       // need to worry about the following effects:
    2436             :       // 1) the line was just created, and it might now be blocking
    2437             :       // a carried-out block-end margin from previous lines that
    2438             :       // used to reach NL from reaching NL
    2439             :       // 2) the line used to be empty, and is now not empty,
    2440             :       // thus blocking a carried-out block-end margin from previous lines
    2441             :       // that used to reach NL from reaching NL
    2442             :       // 3) the line wasn't empty, but now is, so a carried-out
    2443             :       // block-end margin from previous lines that didn't used to reach NL
    2444             :       // now does
    2445             :       // 4) the line might have changed in a way that affects NL's
    2446             :       // ShouldApplyBStartMargin decision. The three things that matter
    2447             :       // are the line's emptiness, its adjacency to the block-start edge of the
    2448             :       // block, and whether it has clearance (the latter only matters if the
    2449             :       // block was and is adjacent to the block-start and empty).
    2450             :       //
    2451             :       // If the line is empty now, we can't reliably tell if the line was empty
    2452             :       // before, so we just assume it was and do nextLine->MarkPreviousMarginDirty.
    2453             :       // This means the checks in 4) are redundant; if the line is empty now
    2454             :       // we don't need to check 4), but if the line is not empty now and we're sure
    2455             :       // it wasn't empty before, any adjacency and clearance changes are irrelevant
    2456             :       // to the result of nextLine->ShouldApplyBStartMargin.
    2457          85 :       if (line.next() != LinesEnd()) {
    2458           0 :         bool maybeWasEmpty = oldB == line.next()->BStart();
    2459           0 :         bool isEmpty = line->CachedIsEmpty();
    2460           0 :         if (maybeReflowingForFirstTime /*1*/ ||
    2461           0 :             (isEmpty || maybeWasEmpty) /*2/3/4*/) {
    2462           0 :           line.next()->MarkPreviousMarginDirty();
    2463             :           // since it's marked dirty, nobody will care about |deltaBCoord|
    2464             :         }
    2465             :       }
    2466             : 
    2467             :       // If the line was just reflowed for the first time, then its
    2468             :       // old mBounds cannot be trusted so this deltaBCoord computation is
    2469             :       // bogus. But that's OK because we just did
    2470             :       // MarkPreviousMarginDirty on the next line which will force it
    2471             :       // to be reflowed, so this computation of deltaBCoord will not be
    2472             :       // used.
    2473          85 :       deltaBCoord = line->BEnd() - oldBMost;
    2474             : 
    2475             :       // Now do an interrupt check. We want to do this only in the case when we
    2476             :       // actually reflow the line, so that if we get back in here we'll get
    2477             :       // further on the reflow before interrupting.
    2478          85 :       aState.mPresContext->CheckForInterrupt(this);
    2479             :     } else {
    2480          66 :       aState.mOverflowTracker->Skip(line->mFirstChild, aState.mReflowStatus);
    2481             :         // Nop except for blocks (we don't create overflow container
    2482             :         // continuations for any inlines atm), so only checking mFirstChild
    2483             :         // is enough
    2484             : 
    2485          66 :       lastLineMovedUp = deltaBCoord < 0;
    2486             : 
    2487          66 :       if (deltaBCoord != 0)
    2488           0 :         SlideLine(aState, line, deltaBCoord);
    2489             :       else
    2490          66 :         repositionViews = true;
    2491             : 
    2492          66 :       NS_ASSERTION(!line->IsDirty() || !line->HasFloats(),
    2493             :                    "Possibly stale float cache here!");
    2494          66 :       if (willReflowAgain && line->IsBlock()) {
    2495             :         // If we're going to reflow everything again, and this line is a block,
    2496             :         // then there is no need to recover float state. The line may contain
    2497             :         // other lines with floats, but in that case RecoverStateFrom would only
    2498             :         // add floats to the float manager. We don't need to do that because
    2499             :         // everything's going to get reflowed again "for real". Calling
    2500             :         // RecoverStateFrom in this situation could be lethal because the
    2501             :         // block's descendant lines may have float caches containing dangling
    2502             :         // frame pointers. Ugh!
    2503             :         // If this line is inline, then we need to recover its state now
    2504             :         // to make sure that we don't forget to move its floats by deltaBCoord.
    2505             :       } else {
    2506             :         // XXX EVIL O(N^2) EVIL
    2507          66 :         aState.RecoverStateFrom(line, deltaBCoord);
    2508             :       }
    2509             : 
    2510             :       // Keep mBCoord up to date in case we're propagating reflow damage
    2511             :       // and also because our final height may depend on it. If the
    2512             :       // line is inlines, then only update mBCoord if the line is not
    2513             :       // empty, because that's what PlaceLine does. (Empty blocks may
    2514             :       // want to update mBCoord, e.g. if they have clearance.)
    2515          66 :       if (line->IsBlock() || !line->CachedIsEmpty()) {
    2516          61 :         aState.mBCoord = line->BEnd();
    2517             :       }
    2518             : 
    2519          66 :       needToRecoverState = true;
    2520             : 
    2521         132 :       if (reflowedPrevLine && !line->IsBlock() &&
    2522          66 :           aState.mPresContext->HasPendingInterrupt()) {
    2523             :         // Need to make sure to pull overflows from any prev-in-flows
    2524           0 :         for (nsIFrame* inlineKid = line->mFirstChild; inlineKid;
    2525           0 :              inlineKid = inlineKid->PrincipalChildList().FirstChild()) {
    2526           0 :           inlineKid->PullOverflowsFromPrevInFlow();
    2527             :         }
    2528             :       }
    2529             :     }
    2530             : 
    2531             :     // Record if we need to clear floats before reflowing the next
    2532             :     // line. Note that inlineFloatBreakType will be handled and
    2533             :     // cleared before the next line is processed, so there is no
    2534             :     // need to combine break types here.
    2535         151 :     if (line->HasFloatBreakAfter()) {
    2536           0 :       inlineFloatBreakType = line->GetBreakTypeAfter();
    2537             :     }
    2538             : 
    2539         151 :     if (LineHasClear(line.get())) {
    2540           0 :       foundAnyClears = true;
    2541             :     }
    2542             : 
    2543         151 :     DumpLine(aState, line, deltaBCoord, -1);
    2544             : 
    2545         151 :     if (aState.mPresContext->HasPendingInterrupt()) {
    2546           0 :       willReflowAgain = true;
    2547             :       // Another option here might be to leave |line| clean if
    2548             :       // !HasPendingInterrupt() before the CheckForInterrupt() call, since in
    2549             :       // that case the line really did reflow as it should have.  Not sure
    2550             :       // whether that would be safe, so doing this for now instead.  Also not
    2551             :       // sure whether we really want to mark all lines dirty after an
    2552             :       // interrupt, but until we get better at propagating float damage we
    2553             :       // really do need to do it this way; see comments inside MarkLineDirty.
    2554           0 :       MarkLineDirtyForInterrupt(line);
    2555             :     }
    2556             :   }
    2557             : 
    2558             :   // Handle BR-clearance from the last line of the block
    2559         162 :   if (inlineFloatBreakType != StyleClear::None) {
    2560           0 :     aState.mBCoord = aState.ClearFloats(aState.mBCoord, inlineFloatBreakType);
    2561             :   }
    2562             : 
    2563         162 :   if (needToRecoverState) {
    2564             :     // Is this expensive?
    2565          66 :     aState.ReconstructMarginBefore(line);
    2566             : 
    2567             :     // Update aState.mPrevChild as if we had reflowed all of the frames in
    2568             :     // the last line.
    2569          66 :     NS_ASSERTION(line == line_end || line->mFirstChild->GetPrevSibling() ==
    2570             :                  line.prev()->LastChild(), "unexpected line frames");
    2571          66 :     aState.mPrevChild =
    2572          66 :       line == line_end ? mFrames.LastChild() : line->mFirstChild->GetPrevSibling();
    2573             :   }
    2574             : 
    2575             :   // Should we really have to do this?
    2576         162 :   if (repositionViews)
    2577          66 :     nsContainerFrame::PlaceFrameView(this);
    2578             : 
    2579             :   // We can skip trying to pull up the next line if our height is constrained
    2580             :   // (so we can report being incomplete) and there is no next in flow or we
    2581             :   // were told not to or we know it will be futile, i.e.,
    2582             :   // -- the next in flow is not changing
    2583             :   // -- and we cannot have added more space for its first line to be
    2584             :   // pulled up into,
    2585             :   // -- it's an incremental reflow of a descendant
    2586             :   // -- and we didn't reflow any floats (so the available space
    2587             :   // didn't change)
    2588             :   // -- my chain of next-in-flows either has no first line, or its first
    2589             :   // line isn't dirty.
    2590             :   bool heightConstrained =
    2591         162 :     aState.mReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE;
    2592         162 :   bool skipPull = willReflowAgain && heightConstrained;
    2593         162 :   if (!skipPull && heightConstrained && aState.mNextInFlow &&
    2594           0 :       (aState.mReflowInput.mFlags.mNextInFlowUntouched &&
    2595           0 :        !lastLineMovedUp &&
    2596           0 :        !(GetStateBits() & NS_FRAME_IS_DIRTY) &&
    2597           0 :        !reflowedFloat)) {
    2598             :     // We'll place lineIter at the last line of this block, so that
    2599             :     // nsBlockInFlowLineIterator::Next() will take us to the first
    2600             :     // line of my next-in-flow-chain.  (But first, check that I
    2601             :     // have any lines -- if I don't, just bail out of this
    2602             :     // optimization.)
    2603           0 :     LineIterator lineIter = this->LinesEnd();
    2604           0 :     if (lineIter != this->LinesBegin()) {
    2605           0 :       lineIter--; // I have lines; step back from dummy iterator to last line.
    2606           0 :       nsBlockInFlowLineIterator bifLineIter(this, lineIter);
    2607             : 
    2608             :       // Check for next-in-flow-chain's first line.
    2609             :       // (First, see if there is such a line, and second, see if it's clean)
    2610           0 :       if (!bifLineIter.Next() ||
    2611           0 :           !bifLineIter.GetLine()->IsDirty()) {
    2612           0 :         skipPull=true;
    2613             :       }
    2614             :     }
    2615             :   }
    2616             : 
    2617         162 :   if (skipPull && aState.mNextInFlow) {
    2618           0 :     NS_ASSERTION(heightConstrained, "Height should be constrained here\n");
    2619           0 :     if (IS_TRUE_OVERFLOW_CONTAINER(aState.mNextInFlow))
    2620           0 :       aState.mReflowStatus.SetOverflowIncomplete();
    2621             :     else
    2622           0 :       aState.mReflowStatus.SetIncomplete();
    2623             :   }
    2624             : 
    2625         162 :   if (!skipPull && aState.mNextInFlow) {
    2626             :     // Pull data from a next-in-flow if there's still room for more
    2627             :     // content here.
    2628           0 :     while (keepGoing && aState.mNextInFlow) {
    2629             :       // Grab first line from our next-in-flow
    2630           0 :       nsBlockFrame* nextInFlow = aState.mNextInFlow;
    2631             :       nsLineBox* pulledLine;
    2632           0 :       nsFrameList pulledFrames;
    2633           0 :       if (!nextInFlow->mLines.empty()) {
    2634           0 :         RemoveFirstLine(nextInFlow->mLines, nextInFlow->mFrames,
    2635           0 :                         &pulledLine, &pulledFrames);
    2636             :       } else {
    2637             :         // Grab an overflow line if there are any
    2638           0 :         FrameLines* overflowLines = nextInFlow->GetOverflowLines();
    2639           0 :         if (!overflowLines) {
    2640           0 :           aState.mNextInFlow =
    2641           0 :             static_cast<nsBlockFrame*>(nextInFlow->GetNextInFlow());
    2642           0 :           continue;
    2643             :         }
    2644             :         bool last =
    2645           0 :           RemoveFirstLine(overflowLines->mLines, overflowLines->mFrames,
    2646           0 :                           &pulledLine, &pulledFrames);
    2647           0 :         if (last) {
    2648           0 :           nextInFlow->DestroyOverflowLines();
    2649             :         }
    2650             :       }
    2651             : 
    2652           0 :       if (pulledFrames.IsEmpty()) {
    2653             :         // The line is empty. Try the next one.
    2654           0 :         NS_ASSERTION(pulledLine->GetChildCount() == 0 &&
    2655             :                      !pulledLine->mFirstChild, "bad empty line");
    2656           0 :         nextInFlow->FreeLineBox(pulledLine);
    2657           0 :         continue;
    2658             :       }
    2659             : 
    2660           0 :       if (pulledLine == nextInFlow->GetLineCursor()) {
    2661           0 :         nextInFlow->ClearLineCursor();
    2662             :       }
    2663           0 :       ReparentFrames(pulledFrames, nextInFlow, this);
    2664             : 
    2665           0 :       NS_ASSERTION(pulledFrames.LastChild() == pulledLine->LastChild(),
    2666             :                    "Unexpected last frame");
    2667           0 :       NS_ASSERTION(aState.mPrevChild || mLines.empty(), "should have a prevchild here");
    2668           0 :       NS_ASSERTION(aState.mPrevChild == mFrames.LastChild(),
    2669             :                    "Incorrect aState.mPrevChild before inserting line at end");
    2670             : 
    2671             :       // Shift pulledLine's frames into our mFrames list.
    2672           0 :       mFrames.AppendFrames(nullptr, pulledFrames);
    2673             : 
    2674             :       // Add line to our line list, and set its last child as our new prev-child
    2675           0 :       line = mLines.before_insert(LinesEnd(), pulledLine);
    2676           0 :       aState.mPrevChild = mFrames.LastChild();
    2677             : 
    2678             :       // Reparent floats whose placeholders are in the line.
    2679           0 :       ReparentFloats(pulledLine->mFirstChild, nextInFlow, true);
    2680             : 
    2681           0 :       DumpLine(aState, pulledLine, deltaBCoord, 0);
    2682             : #ifdef DEBUG
    2683           0 :       AutoNoisyIndenter indent2(gNoisyReflow);
    2684             : #endif
    2685             : 
    2686           0 :       if (aState.mPresContext->HasPendingInterrupt()) {
    2687           0 :         MarkLineDirtyForInterrupt(line);
    2688             :       } else {
    2689             :         // Now reflow it and any lines that it makes during it's reflow
    2690             :         // (we have to loop here because reflowing the line may cause a new
    2691             :         // line to be created; see SplitLine's callers for examples of
    2692             :         // when this happens).
    2693           0 :         while (line != LinesEnd()) {
    2694           0 :           ReflowLine(aState, line, &keepGoing);
    2695             : 
    2696           0 :           if (aState.mReflowInput.WillReflowAgainForClearance()) {
    2697           0 :             line->MarkDirty();
    2698           0 :             keepGoing = false;
    2699           0 :             aState.mReflowStatus.SetIncomplete();
    2700           0 :             break;
    2701             :           }
    2702             : 
    2703           0 :           DumpLine(aState, line, deltaBCoord, -1);
    2704           0 :           if (!keepGoing) {
    2705           0 :             if (0 == line->GetChildCount()) {
    2706           0 :               DeleteLine(aState, line, line_end);
    2707             :             }
    2708           0 :             break;
    2709             :           }
    2710             : 
    2711           0 :           if (LineHasClear(line.get())) {
    2712           0 :             foundAnyClears = true;
    2713             :           }
    2714             : 
    2715           0 :           if (aState.mPresContext->CheckForInterrupt(this)) {
    2716           0 :             MarkLineDirtyForInterrupt(line);
    2717           0 :             break;
    2718             :           }
    2719             : 
    2720             :           // If this is an inline frame then its time to stop
    2721           0 :           ++line;
    2722           0 :           aState.AdvanceToNextLine();
    2723             :         }
    2724             :       }
    2725             :     }
    2726             : 
    2727           0 :     if (aState.mReflowStatus.IsIncomplete()) {
    2728           0 :       aState.mReflowStatus.SetNextInFlowNeedsReflow();
    2729             :     } //XXXfr shouldn't set this flag when nextinflow has no lines
    2730             :   }
    2731             : 
    2732             :   // Handle an odd-ball case: a list-item with no lines
    2733         162 :   if (HasOutsideBullet() && mLines.empty()) {
    2734           0 :     ReflowOutput metrics(aState.mReflowInput);
    2735           0 :     nsIFrame* bullet = GetOutsideBullet();
    2736           0 :     WritingMode wm = aState.mReflowInput.GetWritingMode();
    2737             :     ReflowBullet(bullet, aState, metrics,
    2738           0 :                  aState.mReflowInput.ComputedPhysicalBorderPadding().top);
    2739           0 :     NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0,
    2740             :                  "empty bullet took up space");
    2741             : 
    2742           0 :     if (!BulletIsEmpty()) {
    2743             :       // There are no lines so we have to fake up some y motion so that
    2744             :       // we end up with *some* height.
    2745             : 
    2746           0 :       if (metrics.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) {
    2747             :         nscoord ascent;
    2748           0 :         WritingMode wm = aState.mReflowInput.GetWritingMode();
    2749           0 :         if (nsLayoutUtils::GetFirstLineBaseline(wm, bullet, &ascent)) {
    2750           0 :           metrics.SetBlockStartAscent(ascent);
    2751             :         } else {
    2752           0 :           metrics.SetBlockStartAscent(metrics.BSize(wm));
    2753             :         }
    2754             :       }
    2755             : 
    2756             :       RefPtr<nsFontMetrics> fm =
    2757           0 :         nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
    2758             : 
    2759             :       nscoord minAscent =
    2760           0 :         nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight,
    2761           0 :                                                wm.IsLineInverted());
    2762           0 :       nscoord minDescent = aState.mMinLineHeight - minAscent;
    2763             : 
    2764           0 :       aState.mBCoord += std::max(minAscent, metrics.BlockStartAscent()) +
    2765           0 :                         std::max(minDescent, metrics.BSize(wm) -
    2766           0 :                                              metrics.BlockStartAscent());
    2767             : 
    2768           0 :       nscoord offset = minAscent - metrics.BlockStartAscent();
    2769           0 :       if (offset > 0) {
    2770           0 :         bullet->SetRect(bullet->GetRect() + nsPoint(0, offset));
    2771             :       }
    2772             :     }
    2773             :   }
    2774             : 
    2775         162 :   if (foundAnyClears) {
    2776           0 :     AddStateBits(NS_BLOCK_HAS_CLEAR_CHILDREN);
    2777             :   } else {
    2778         162 :     RemoveStateBits(NS_BLOCK_HAS_CLEAR_CHILDREN);
    2779             :   }
    2780             : 
    2781             : #ifdef DEBUG
    2782         162 :   VerifyLines(true);
    2783         162 :   VerifyOverflowSituation();
    2784         162 :   if (gNoisyReflow) {
    2785           0 :     IndentBy(stdout, gNoiseIndent - 1);
    2786           0 :     ListTag(stdout);
    2787           0 :     printf(": done reflowing dirty lines (status=%s)\n",
    2788           0 :            ToString(aState.mReflowStatus).c_str());
    2789             :   }
    2790             : #endif
    2791         162 : }
    2792             : 
    2793             : void
    2794           0 : nsBlockFrame::MarkLineDirtyForInterrupt(nsLineBox* aLine)
    2795             : {
    2796           0 :   aLine->MarkDirty();
    2797             : 
    2798             :   // Just checking NS_FRAME_IS_DIRTY is ok, because we've already
    2799             :   // marked the lines that need to be marked dirty based on our
    2800             :   // vertical resize stuff.  So we'll definitely reflow all those kids;
    2801             :   // the only question is how they should behave.
    2802           0 :   if (GetStateBits() & NS_FRAME_IS_DIRTY) {
    2803             :     // Mark all our child frames dirty so we make sure to reflow them
    2804             :     // later.
    2805           0 :     int32_t n = aLine->GetChildCount();
    2806           0 :     for (nsIFrame* f = aLine->mFirstChild; n > 0;
    2807             :          f = f->GetNextSibling(), --n) {
    2808           0 :       f->AddStateBits(NS_FRAME_IS_DIRTY);
    2809             :     }
    2810             :     // And mark all the floats whose reflows we might be skipping dirty too.
    2811           0 :     if (aLine->HasFloats()) {
    2812           0 :       for (nsFloatCache* fc = aLine->GetFirstFloat(); fc; fc = fc->Next()) {
    2813           0 :         fc->mFloat->AddStateBits(NS_FRAME_IS_DIRTY);
    2814             :       }
    2815             :     }
    2816             :   } else {
    2817             :     // Dirty all the descendant lines of block kids to handle float damage,
    2818             :     // since our nsFloatManager will go away by the next time we're reflowing.
    2819             :     // XXXbz Can we do something more like what PropagateFloatDamage does?
    2820             :     // Would need to sort out the exact business with mBlockDelta for that....
    2821             :     // This marks way too much dirty.  If we ever make this better, revisit
    2822             :     // which lines we mark dirty in the interrupt case in ReflowDirtyLines.
    2823           0 :     nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aLine->mFirstChild);
    2824           0 :     if (bf) {
    2825           0 :       MarkAllDescendantLinesDirty(bf);
    2826             :     }
    2827             :   }
    2828           0 : }
    2829             : 
    2830             : void
    2831           0 : nsBlockFrame::DeleteLine(BlockReflowInput& aState,
    2832             :                          nsLineList::iterator aLine,
    2833             :                          nsLineList::iterator aLineEnd)
    2834             : {
    2835           0 :   NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
    2836           0 :   if (0 == aLine->GetChildCount()) {
    2837           0 :     NS_ASSERTION(aState.mCurrentLine == aLine,
    2838             :                  "using function more generally than designed, "
    2839             :                  "but perhaps OK now");
    2840           0 :     nsLineBox* line = aLine;
    2841           0 :     aLine = mLines.erase(aLine);
    2842           0 :     FreeLineBox(line);
    2843             :     // Mark the previous margin of the next line dirty since we need to
    2844             :     // recompute its top position.
    2845           0 :     if (aLine != aLineEnd)
    2846           0 :       aLine->MarkPreviousMarginDirty();
    2847             :   }
    2848           0 : }
    2849             : 
    2850             : /**
    2851             :  * Reflow a line. The line will either contain a single block frame
    2852             :  * or contain 1 or more inline frames. aKeepReflowGoing indicates
    2853             :  * whether or not the caller should continue to reflow more lines.
    2854             :  */
    2855             : void
    2856          85 : nsBlockFrame::ReflowLine(BlockReflowInput& aState,
    2857             :                          LineIterator aLine,
    2858             :                          bool* aKeepReflowGoing)
    2859             : {
    2860          85 :   MOZ_ASSERT(aLine->GetChildCount(), "reflowing empty line");
    2861             : 
    2862             :   // Setup the line-layout for the new line
    2863          85 :   aState.mCurrentLine = aLine;
    2864          85 :   aLine->ClearDirty();
    2865          85 :   aLine->InvalidateCachedIsEmpty();
    2866          85 :   aLine->ClearHadFloatPushed();
    2867             : 
    2868             :   // Now that we know what kind of line we have, reflow it
    2869          85 :   if (aLine->IsBlock()) {
    2870          10 :     ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
    2871             :   } else {
    2872          75 :     aLine->SetLineWrapped(false);
    2873          75 :     ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
    2874             : 
    2875             :     // Store the line's float edges for text-overflow analysis if needed.
    2876          75 :     aLine->ClearFloatEdges();
    2877          75 :     if (aState.mFlags.mCanHaveTextOverflow) {
    2878           0 :       WritingMode wm = aLine->mWritingMode;
    2879             :       nsFlowAreaRect r = aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
    2880             :                                                                aLine->BSize(),
    2881           0 :                                                                nullptr);
    2882           0 :       if (r.mHasFloats) {
    2883             :         LogicalRect so =
    2884           0 :           aLine->GetOverflowArea(eScrollableOverflow, wm, aLine->mContainerSize);
    2885           0 :         nscoord s = r.mRect.IStart(wm);
    2886           0 :         nscoord e = r.mRect.IEnd(wm);
    2887           0 :         if (so.IEnd(wm) > e || so.IStart(wm) < s) {
    2888             :           // This line is overlapping a float - store the edges marking the area
    2889             :           // between the floats for text-overflow analysis.
    2890           0 :           aLine->SetFloatEdges(s, e);
    2891             :         }
    2892             :       }
    2893             :     }
    2894             :   }
    2895          85 : }
    2896             : 
    2897             : nsIFrame*
    2898          66 : nsBlockFrame::PullFrame(BlockReflowInput& aState,
    2899             :                         LineIterator       aLine)
    2900             : {
    2901             :   // First check our remaining lines.
    2902          66 :   if (LinesEnd() != aLine.next()) {
    2903           0 :     return PullFrameFrom(aLine, this, aLine.next());
    2904             :   }
    2905             : 
    2906          66 :   NS_ASSERTION(!GetOverflowLines(),
    2907             :     "Our overflow lines should have been removed at the start of reflow");
    2908             : 
    2909             :   // Try each next-in-flow.
    2910          66 :   nsBlockFrame* nextInFlow = aState.mNextInFlow;
    2911          66 :   while (nextInFlow) {
    2912           0 :     if (nextInFlow->mLines.empty()) {
    2913           0 :       nextInFlow->DrainSelfOverflowList();
    2914             :     }
    2915           0 :     if (!nextInFlow->mLines.empty()) {
    2916           0 :       return PullFrameFrom(aLine, nextInFlow, nextInFlow->mLines.begin());
    2917             :     }
    2918           0 :     nextInFlow = static_cast<nsBlockFrame*>(nextInFlow->GetNextInFlow());
    2919           0 :     aState.mNextInFlow = nextInFlow;
    2920             :   }
    2921             : 
    2922          66 :   return nullptr;
    2923             : }
    2924             : 
    2925             : nsIFrame*
    2926           0 : nsBlockFrame::PullFrameFrom(nsLineBox*           aLine,
    2927             :                             nsBlockFrame*        aFromContainer,
    2928             :                             nsLineList::iterator aFromLine)
    2929             : {
    2930           0 :   nsLineBox* fromLine = aFromLine;
    2931           0 :   MOZ_ASSERT(fromLine, "bad line to pull from");
    2932           0 :   MOZ_ASSERT(fromLine->GetChildCount(), "empty line");
    2933           0 :   MOZ_ASSERT(aLine->GetChildCount(), "empty line");
    2934             : 
    2935           0 :   NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->IsBlockOutside(),
    2936             :                "Disagreement about whether it's a block or not");
    2937             : 
    2938           0 :   if (fromLine->IsBlock()) {
    2939             :     // If our line is not empty and the child in aFromLine is a block
    2940             :     // then we cannot pull up the frame into this line. In this case
    2941             :     // we stop pulling.
    2942           0 :     return nullptr;
    2943             :   }
    2944             :   // Take frame from fromLine
    2945           0 :   nsIFrame* frame = fromLine->mFirstChild;
    2946           0 :   nsIFrame* newFirstChild = frame->GetNextSibling();
    2947             : 
    2948           0 :   if (aFromContainer != this) {
    2949             :     // The frame is being pulled from a next-in-flow; therefore we
    2950             :     // need to add it to our sibling list.
    2951           0 :     MOZ_ASSERT(aLine == mLines.back());
    2952           0 :     MOZ_ASSERT(aFromLine == aFromContainer->mLines.begin(),
    2953             :                "should only pull from first line");
    2954           0 :     aFromContainer->mFrames.RemoveFrame(frame);
    2955             : 
    2956             :     // When pushing and pulling frames we need to check for whether any
    2957             :     // views need to be reparented.
    2958           0 :     ReparentFrame(frame, aFromContainer, this);
    2959           0 :     mFrames.AppendFrame(nullptr, frame);
    2960             : 
    2961             :     // The frame might have (or contain) floats that need to be brought
    2962             :     // over too. (pass 'false' since there are no siblings to check)
    2963           0 :     ReparentFloats(frame, aFromContainer, false);
    2964             :   } else {
    2965           0 :     MOZ_ASSERT(aLine == aFromLine.prev());
    2966             :   }
    2967             : 
    2968           0 :   aLine->NoteFrameAdded(frame);
    2969           0 :   fromLine->NoteFrameRemoved(frame);
    2970             : 
    2971           0 :   if (fromLine->GetChildCount() > 0) {
    2972             :     // Mark line dirty now that we pulled a child
    2973           0 :     fromLine->MarkDirty();
    2974           0 :     fromLine->mFirstChild = newFirstChild;
    2975             :   } else {
    2976             :     // Free up the fromLine now that it's empty.
    2977             :     // Its bounds might need to be redrawn, though.
    2978           0 :     if (aFromLine.next() != aFromContainer->mLines.end()) {
    2979           0 :       aFromLine.next()->MarkPreviousMarginDirty();
    2980             :     }
    2981           0 :     aFromContainer->mLines.erase(aFromLine);
    2982             :     // aFromLine is now invalid
    2983           0 :     aFromContainer->FreeLineBox(fromLine);
    2984             :   }
    2985             : 
    2986             : #ifdef DEBUG
    2987           0 :   VerifyLines(true);
    2988           0 :   VerifyOverflowSituation();
    2989             : #endif
    2990             : 
    2991           0 :   return frame;
    2992             : }
    2993             : 
    2994             : void
    2995           0 : nsBlockFrame::SlideLine(BlockReflowInput& aState,
    2996             :                         nsLineBox* aLine, nscoord aDeltaBCoord)
    2997             : {
    2998           0 :   NS_PRECONDITION(aDeltaBCoord != 0, "why slide a line nowhere?");
    2999             : 
    3000             :   // Adjust line state
    3001           0 :   aLine->SlideBy(aDeltaBCoord, aState.ContainerSize());
    3002             : 
    3003             :   // Adjust the frames in the line
    3004           0 :   MoveChildFramesOfLine(aLine, aDeltaBCoord);
    3005           0 : }
    3006             : 
    3007             : void
    3008           0 : nsBlockFrame::UpdateLineContainerSize(nsLineBox* aLine,
    3009             :                                       const nsSize& aNewContainerSize)
    3010             : {
    3011           0 :   if (aNewContainerSize == aLine->mContainerSize) {
    3012           0 :     return;
    3013             :   }
    3014             : 
    3015             :   // Adjust line state
    3016           0 :   nsSize sizeDelta = aLine->UpdateContainerSize(aNewContainerSize);
    3017             : 
    3018             :   // Changing container width only matters if writing mode is vertical-rl
    3019           0 :   if (GetWritingMode().IsVerticalRL()) {
    3020           0 :     MoveChildFramesOfLine(aLine, sizeDelta.width);
    3021             :   }
    3022             : }
    3023             : 
    3024             : void
    3025           0 : nsBlockFrame::MoveChildFramesOfLine(nsLineBox* aLine, nscoord aDeltaBCoord)
    3026             : {
    3027             :   // Adjust the frames in the line
    3028           0 :   nsIFrame* kid = aLine->mFirstChild;
    3029           0 :   if (!kid) {
    3030           0 :     return;
    3031             :   }
    3032             : 
    3033           0 :   WritingMode wm = GetWritingMode();
    3034           0 :   LogicalPoint translation(wm, 0, aDeltaBCoord);
    3035             : 
    3036           0 :   if (aLine->IsBlock()) {
    3037           0 :     if (aDeltaBCoord) {
    3038           0 :       kid->MovePositionBy(wm, translation);
    3039             :     }
    3040             : 
    3041             :     // Make sure the frame's view and any child views are updated
    3042           0 :     nsContainerFrame::PlaceFrameView(kid);
    3043             :   }
    3044             :   else {
    3045             :     // Adjust the block-dir coordinate of the frames in the line.
    3046             :     // Note: we need to re-position views even if aDeltaBCoord is 0, because
    3047             :     // one of our parent frames may have moved and so the view's position
    3048             :     // relative to its parent may have changed.
    3049           0 :     int32_t n = aLine->GetChildCount();
    3050           0 :     while (--n >= 0) {
    3051           0 :       if (aDeltaBCoord) {
    3052           0 :         kid->MovePositionBy(wm, translation);
    3053             :       }
    3054             :       // Make sure the frame's view and any child views are updated
    3055           0 :       nsContainerFrame::PlaceFrameView(kid);
    3056           0 :       kid = kid->GetNextSibling();
    3057             :     }
    3058             :   }
    3059             : }
    3060             : 
    3061             : nsresult
    3062          20 : nsBlockFrame::AttributeChanged(int32_t         aNameSpaceID,
    3063             :                                nsIAtom*        aAttribute,
    3064             :                                int32_t         aModType)
    3065             : {
    3066          20 :   nsresult rv = nsContainerFrame::AttributeChanged(aNameSpaceID,
    3067          20 :                                                    aAttribute, aModType);
    3068          20 :   if (NS_FAILED(rv)) {
    3069           0 :     return rv;
    3070             :   }
    3071          20 :   if (nsGkAtoms::value == aAttribute) {
    3072           4 :     const nsStyleDisplay* styleDisplay = StyleDisplay();
    3073           4 :     if (mozilla::StyleDisplay::ListItem == styleDisplay->mDisplay) {
    3074             :       // Search for the closest ancestor that's a block frame. We
    3075             :       // make the assumption that all related list items share a
    3076             :       // common block/grid/flex ancestor.
    3077             :       // XXXldb I think that's a bad assumption.
    3078           0 :       nsContainerFrame* ancestor = GetParent();
    3079           0 :       for (; ancestor; ancestor = ancestor->GetParent()) {
    3080           0 :         auto frameType = ancestor->Type();
    3081           0 :         if (frameType == LayoutFrameType::Block ||
    3082           0 :             frameType == LayoutFrameType::FlexContainer ||
    3083             :             frameType == LayoutFrameType::GridContainer) {
    3084             :           break;
    3085             :         }
    3086             :       }
    3087             :       // Tell the ancestor to renumber list items within itself.
    3088           0 :       if (ancestor) {
    3089             :         // XXX Not sure if this is necessary anymore
    3090           0 :         if (ancestor->RenumberList()) {
    3091           0 :           PresContext()->PresShell()->
    3092             :             FrameNeedsReflow(ancestor, nsIPresShell::eStyleChange,
    3093           0 :                              NS_FRAME_HAS_DIRTY_CHILDREN);
    3094             :         }
    3095             :       }
    3096             :     }
    3097             :   }
    3098          20 :   return rv;
    3099             : }
    3100             : 
    3101             : static inline bool
    3102          10 : IsNonAutoNonZeroBSize(const nsStyleCoord& aCoord)
    3103             : {
    3104          10 :   nsStyleUnit unit = aCoord.GetUnit();
    3105          10 :   if (unit == eStyleUnit_Auto ||
    3106             :       // The enumerated values were originally aimed at inline-size
    3107             :       // (or width, as it was before logicalization). For now, let them
    3108             :       // return false here, so we treat them like 'auto' pending a
    3109             :       // real implementation. (See bug 1126420.)
    3110             :       //
    3111             :       // FIXME (bug 567039, bug 527285)
    3112             :       // This isn't correct for the 'fill' value, which should more
    3113             :       // likely (but not necessarily, depending on the available space)
    3114             :       // be returning true.
    3115             :       unit == eStyleUnit_Enumerated) {
    3116          10 :     return false;
    3117             :   }
    3118           0 :   if (aCoord.IsCoordPercentCalcUnit()) {
    3119             :     // If we evaluate the length/percent/calc at a percentage basis of
    3120             :     // both nscoord_MAX and 0, and it's zero both ways, then it's a zero
    3121             :     // length, percent, or combination thereof.  Test > 0 so we clamp
    3122             :     // negative calc() results to 0.
    3123           0 :     return nsRuleNode::ComputeCoordPercentCalc(aCoord, nscoord_MAX) > 0 ||
    3124           0 :            nsRuleNode::ComputeCoordPercentCalc(aCoord, 0) > 0;
    3125             :   }
    3126           0 :   MOZ_ASSERT(false, "unexpected unit for height or min-height");
    3127             :   return true;
    3128             : }
    3129             : 
    3130             : /* virtual */ bool
    3131           5 : nsBlockFrame::IsSelfEmpty()
    3132             : {
    3133             :   // Blocks which are margin-roots (including inline-blocks) cannot be treated
    3134             :   // as empty for margin-collapsing and other purposes. They're more like
    3135             :   // replaced elements.
    3136           5 :   if (GetStateBits() & NS_BLOCK_MARGIN_ROOT) {
    3137           0 :     return false;
    3138             :   }
    3139             : 
    3140           5 :   WritingMode wm = GetWritingMode();
    3141           5 :   const nsStylePosition* position = StylePosition();
    3142             : 
    3143          10 :   if (IsNonAutoNonZeroBSize(position->MinBSize(wm)) ||
    3144           5 :       IsNonAutoNonZeroBSize(position->BSize(wm))) {
    3145           0 :     return false;
    3146             :   }
    3147             : 
    3148           5 :   const nsStyleBorder* border = StyleBorder();
    3149           5 :   const nsStylePadding* padding = StylePadding();
    3150             : 
    3151          20 :   if (border->GetComputedBorderWidth(wm.PhysicalSide(eLogicalSideBStart)) != 0 ||
    3152          15 :       border->GetComputedBorderWidth(wm.PhysicalSide(eLogicalSideBEnd)) != 0 ||
    3153          40 :       !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBStart(wm)) ||
    3154          15 :       !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBEnd(wm))) {
    3155           0 :     return false;
    3156             :   }
    3157             : 
    3158           5 :   if (HasOutsideBullet() && !BulletIsEmpty()) {
    3159           0 :     return false;
    3160             :   }
    3161             : 
    3162           5 :   return true;
    3163             : }
    3164             : 
    3165             : bool
    3166           5 : nsBlockFrame::CachedIsEmpty()
    3167             : {
    3168           5 :   if (!IsSelfEmpty()) {
    3169           0 :     return false;
    3170             :   }
    3171             : 
    3172           5 :   for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    3173             :        line != line_end;
    3174             :        ++line)
    3175             :   {
    3176           0 :     if (!line->CachedIsEmpty())
    3177           0 :       return false;
    3178             :   }
    3179             : 
    3180           5 :   return true;
    3181             : }
    3182             : 
    3183             : bool
    3184           0 : nsBlockFrame::IsEmpty()
    3185             : {
    3186           0 :   if (!IsSelfEmpty()) {
    3187           0 :     return false;
    3188             :   }
    3189             : 
    3190           0 :   for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    3191             :        line != line_end;
    3192             :        ++line)
    3193             :   {
    3194           0 :     if (!line->IsEmpty())
    3195           0 :       return false;
    3196             :   }
    3197             : 
    3198           0 :   return true;
    3199             : }
    3200             : 
    3201             : bool
    3202          85 : nsBlockFrame::ShouldApplyBStartMargin(BlockReflowInput& aState,
    3203             :                                       nsLineBox* aLine,
    3204             :                                       nsIFrame* aChildFrame)
    3205             : {
    3206          85 :   if (aState.mFlags.mShouldApplyBStartMargin) {
    3207             :     // Apply short-circuit check to avoid searching the line list
    3208          84 :     return true;
    3209             :   }
    3210             : 
    3211           2 :   if (!aState.IsAdjacentWithTop() ||
    3212           1 :       aChildFrame->StyleBorder()->mBoxDecorationBreak ==
    3213             :         StyleBoxDecorationBreak::Clone) {
    3214             :     // If we aren't at the start block-coordinate then something of non-zero
    3215             :     // height must have been placed. Therefore the childs block-start margin
    3216             :     // applies.
    3217           0 :     aState.mFlags.mShouldApplyBStartMargin = true;
    3218           0 :     return true;
    3219             :   }
    3220             : 
    3221             :   // Determine if this line is "essentially" the first line
    3222           1 :   LineIterator line = LinesBegin();
    3223           1 :   if (aState.mFlags.mHasLineAdjacentToTop) {
    3224           0 :     line = aState.mLineAdjacentToTop;
    3225             :   }
    3226           1 :   while (line != aLine) {
    3227           0 :     if (!line->CachedIsEmpty() || line->HasClearance()) {
    3228             :       // A line which precedes aLine is non-empty, or has clearance,
    3229             :       // so therefore the block-start margin applies.
    3230           0 :       aState.mFlags.mShouldApplyBStartMargin = true;
    3231           0 :       return true;
    3232             :     }
    3233             :     // No need to apply the block-start margin if the line has floats.  We
    3234             :     // should collapse anyway (bug 44419)
    3235           0 :     ++line;
    3236           0 :     aState.mFlags.mHasLineAdjacentToTop = true;
    3237           0 :     aState.mLineAdjacentToTop = line;
    3238             :   }
    3239             : 
    3240             :   // The line being reflowed is "essentially" the first line in the
    3241             :   // block. Therefore its block-start margin will be collapsed by the
    3242             :   // generational collapsing logic with its parent (us).
    3243           1 :   return false;
    3244             : }
    3245             : 
    3246             : void
    3247          10 : nsBlockFrame::ReflowBlockFrame(BlockReflowInput& aState,
    3248             :                                LineIterator aLine,
    3249             :                                bool* aKeepReflowGoing)
    3250             : {
    3251          10 :   NS_PRECONDITION(*aKeepReflowGoing, "bad caller");
    3252             : 
    3253          10 :   nsIFrame* frame = aLine->mFirstChild;
    3254          10 :   if (!frame) {
    3255           0 :     NS_ASSERTION(false, "program error - unexpected empty line");
    3256           0 :     return;
    3257             :   }
    3258             : 
    3259             :   // Prepare the block reflow engine
    3260          20 :   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowInput);
    3261             : 
    3262             :   StyleClear breakType = frame->StyleDisplay()->
    3263          10 :     PhysicalBreakType(aState.mReflowInput.GetWritingMode());
    3264          10 :   if (StyleClear::None != aState.mFloatBreakType) {
    3265           0 :     breakType = nsLayoutUtils::CombineBreakType(breakType,
    3266           0 :                                                 aState.mFloatBreakType);
    3267           0 :     aState.mFloatBreakType = StyleClear::None;
    3268             :   }
    3269             : 
    3270             :   // Clear past floats before the block if the clear style is not none
    3271          10 :   aLine->SetBreakTypeBefore(breakType);
    3272             : 
    3273             :   // See if we should apply the block-start margin. If the block frame being
    3274             :   // reflowed is a continuation (non-null prev-in-flow) then we don't
    3275             :   // apply its block-start margin because it's not significant unless it has
    3276             :   // 'box-decoration-break:clone'.  Otherwise, dig deeper.
    3277          10 :   bool applyBStartMargin = (frame->StyleBorder()->mBoxDecorationBreak ==
    3278          10 :                               StyleBoxDecorationBreak::Clone ||
    3279          20 :                             !frame->GetPrevInFlow()) &&
    3280          20 :                            ShouldApplyBStartMargin(aState, aLine, frame);
    3281          10 :   if (applyBStartMargin) {
    3282             :     // The HasClearance setting is only valid if ShouldApplyBStartMargin
    3283             :     // returned false (in which case the block-start margin-root set our
    3284             :     // clearance flag). Otherwise clear it now. We'll set it later on
    3285             :     // ourselves if necessary.
    3286          10 :     aLine->ClearHasClearance();
    3287             :   }
    3288          10 :   bool treatWithClearance = aLine->HasClearance();
    3289             : 
    3290          10 :   bool mightClearFloats = breakType != StyleClear::None;
    3291          10 :   nsIFrame *replacedBlock = nullptr;
    3292          10 :   if (!nsBlockFrame::BlockCanIntersectFloats(frame)) {
    3293           0 :     mightClearFloats = true;
    3294           0 :     replacedBlock = frame;
    3295             :   }
    3296             : 
    3297             :   // If our block-start margin was counted as part of some parent's block-start
    3298             :   // margin collapse, and we are being speculatively reflowed assuming this
    3299             :   // frame DID NOT need clearance, then we need to check that
    3300             :   // assumption.
    3301          10 :   if (!treatWithClearance && !applyBStartMargin && mightClearFloats &&
    3302           0 :       aState.mReflowInput.mDiscoveredClearance) {
    3303           0 :     nscoord curBCoord = aState.mBCoord + aState.mPrevBEndMargin.get();
    3304           0 :     nscoord clearBCoord = aState.ClearFloats(curBCoord, breakType, replacedBlock);
    3305           0 :     if (clearBCoord != curBCoord) {
    3306             :       // Only record the first frame that requires clearance
    3307           0 :       if (!*aState.mReflowInput.mDiscoveredClearance) {
    3308           0 :         *aState.mReflowInput.mDiscoveredClearance = frame;
    3309             :       }
    3310           0 :       aState.mPrevChild = frame;
    3311             :       // Exactly what we do now is flexible since we'll definitely be
    3312             :       // reflowed.
    3313           0 :       return;
    3314             :     }
    3315             :   }
    3316          10 :   if (treatWithClearance) {
    3317           0 :     applyBStartMargin = true;
    3318             :   }
    3319             : 
    3320          10 :   nsIFrame* clearanceFrame = nullptr;
    3321          10 :   nscoord startingBCoord = aState.mBCoord;
    3322          10 :   nsCollapsingMargin incomingMargin = aState.mPrevBEndMargin;
    3323             :   nscoord clearance;
    3324             :   // Save the original position of the frame so that we can reposition
    3325             :   // its view as needed.
    3326          10 :   nsPoint originalPosition = frame->GetPosition();
    3327             :   while (true) {
    3328          10 :     clearance = 0;
    3329          10 :     nscoord bStartMargin = 0;
    3330          10 :     bool mayNeedRetry = false;
    3331          10 :     bool clearedFloats = false;
    3332          10 :     if (applyBStartMargin) {
    3333             :       // Precompute the blocks block-start margin value so that we can get the
    3334             :       // correct available space (there might be a float that's
    3335             :       // already been placed below the aState.mPrevBEndMargin
    3336             : 
    3337             :       // Setup a reflowInput to get the style computed block-start margin
    3338             :       // value. We'll use a reason of `resize' so that we don't fudge
    3339             :       // any incremental reflow state.
    3340             : 
    3341             :       // The availSpace here is irrelevant to our needs - all we want
    3342             :       // out if this setup is the block-start margin value which doesn't depend
    3343             :       // on the childs available space.
    3344             :       // XXX building a complete ReflowInput just to get the block-start
    3345             :       // margin seems like a waste. And we do this for almost every block!
    3346          10 :       WritingMode wm = frame->GetWritingMode();
    3347          10 :       LogicalSize availSpace = aState.ContentSize(wm);
    3348             :       ReflowInput reflowInput(aState.mPresContext, aState.mReflowInput,
    3349          10 :                                     frame, availSpace);
    3350             : 
    3351          10 :       if (treatWithClearance) {
    3352           0 :         aState.mBCoord += aState.mPrevBEndMargin.get();
    3353           0 :         aState.mPrevBEndMargin.Zero();
    3354             :       }
    3355             : 
    3356             :       // Now compute the collapsed margin-block-start value into
    3357             :       // aState.mPrevBEndMargin, assuming that all child margins
    3358             :       // collapse down to clearanceFrame.
    3359          10 :       brc.ComputeCollapsedBStartMargin(reflowInput,
    3360             :                                        &aState.mPrevBEndMargin,
    3361             :                                        clearanceFrame,
    3362          20 :                                        &mayNeedRetry);
    3363             : 
    3364             :       // XXX optimization; we could check the collapsing children to see if they are sure
    3365             :       // to require clearance, and so avoid retrying them
    3366             : 
    3367          10 :       if (clearanceFrame) {
    3368             :         // Don't allow retries on the second pass. The clearance decisions for the
    3369             :         // blocks whose block-start margins collapse with ours are now fixed.
    3370           0 :         mayNeedRetry = false;
    3371             :       }
    3372             : 
    3373          10 :       if (!treatWithClearance && !clearanceFrame && mightClearFloats) {
    3374             :         // We don't know if we need clearance and this is the first,
    3375             :         // optimistic pass.  So determine whether *this block* needs
    3376             :         // clearance. Note that we do not allow the decision for whether
    3377             :         // this block has clearance to change on the second pass; that
    3378             :         // decision is only allowed to be made under the optimistic
    3379             :         // first pass.
    3380           0 :         nscoord curBCoord = aState.mBCoord + aState.mPrevBEndMargin.get();
    3381           0 :         nscoord clearBCoord = aState.ClearFloats(curBCoord, breakType, replacedBlock);
    3382           0 :         if (clearBCoord != curBCoord) {
    3383             :           // Looks like we need clearance and we didn't know about it already. So
    3384             :           // recompute collapsed margin
    3385           0 :           treatWithClearance = true;
    3386             :           // Remember this decision, needed for incremental reflow
    3387           0 :           aLine->SetHasClearance();
    3388             : 
    3389             :           // Apply incoming margins
    3390           0 :           aState.mBCoord += aState.mPrevBEndMargin.get();
    3391           0 :           aState.mPrevBEndMargin.Zero();
    3392             : 
    3393             :           // Compute the collapsed margin again, ignoring the incoming margin this time
    3394           0 :           mayNeedRetry = false;
    3395           0 :           brc.ComputeCollapsedBStartMargin(reflowInput,
    3396             :                                            &aState.mPrevBEndMargin,
    3397             :                                            clearanceFrame,
    3398           0 :                                            &mayNeedRetry);
    3399             :         }
    3400             :       }
    3401             : 
    3402             :       // Temporarily advance the running Y value so that the
    3403             :       // GetAvailableSpace method will return the right available
    3404             :       // space. This undone as soon as the horizontal margins are
    3405             :       // computed.
    3406          10 :       bStartMargin = aState.mPrevBEndMargin.get();
    3407             : 
    3408          10 :       if (treatWithClearance) {
    3409           0 :         nscoord currentBCoord = aState.mBCoord;
    3410             :         // advance mBCoord to the clear position.
    3411           0 :         aState.mBCoord = aState.ClearFloats(aState.mBCoord, breakType,
    3412             :                                             replacedBlock);
    3413             : 
    3414           0 :         clearedFloats = aState.mBCoord != currentBCoord;
    3415             : 
    3416             :         // Compute clearance. It's the amount we need to add to the block-start
    3417             :         // border-edge of the frame, after applying collapsed margins
    3418             :         // from the frame and its children, to get it to line up with
    3419             :         // the block-end of the floats. The former is
    3420             :         // currentBCoord + bStartMargin, the latter is the current
    3421             :         // aState.mBCoord.
    3422             :         // Note that negative clearance is possible
    3423           0 :         clearance = aState.mBCoord - (currentBCoord + bStartMargin);
    3424             : 
    3425             :         // Add clearance to our block-start margin while we compute available
    3426             :         // space for the frame
    3427           0 :         bStartMargin += clearance;
    3428             : 
    3429             :         // Note that aState.mBCoord should stay where it is: at the block-start
    3430             :         // border-edge of the frame
    3431             :       } else {
    3432             :         // Advance aState.mBCoord to the block-start border-edge of the frame.
    3433          10 :         aState.mBCoord += bStartMargin;
    3434             :       }
    3435             :     }
    3436             : 
    3437          10 :     aLine->SetLineIsImpactedByFloat(false);
    3438             : 
    3439             :     // Here aState.mBCoord is the block-start border-edge of the block.
    3440             :     // Compute the available space for the block
    3441          10 :     nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
    3442          10 :     WritingMode wm = aState.mReflowInput.GetWritingMode();
    3443          10 :     LogicalRect availSpace(wm);
    3444          10 :     aState.ComputeBlockAvailSpace(frame, floatAvailableSpace,
    3445          10 :                                   replacedBlock != nullptr, availSpace);
    3446             : 
    3447             :     // The check for
    3448             :     //   (!aState.mReflowInput.mFlags.mIsTopOfPage || clearedFloats)
    3449             :     // is to some degree out of paranoia:  if we reliably eat up block-start
    3450             :     // margins at the top of the page as we ought to, it wouldn't be
    3451             :     // needed.
    3452          20 :     if ((!aState.mReflowInput.mFlags.mIsTopOfPage || clearedFloats) &&
    3453          10 :         availSpace.BSize(wm) < 0) {
    3454             :       // We know already that this child block won't fit on this
    3455             :       // page/column due to the block-start margin or the clearance.  So we
    3456             :       // need to get out of here now.  (If we don't, most blocks will handle
    3457             :       // things fine, and report break-before, but zero-height blocks
    3458             :       // won't, and will thus make their parent overly-large and force
    3459             :       // *it* to be pushed in its entirety.)
    3460             :       // Doing this means that we also don't need to worry about the
    3461             :       // |availSpace.BSize(wm) += bStartMargin| below interacting with
    3462             :       // pushed floats (which force nscoord_MAX clearance) to cause a
    3463             :       // constrained block size to turn into an unconstrained one.
    3464           0 :       aState.mBCoord = startingBCoord;
    3465           0 :       aState.mPrevBEndMargin = incomingMargin;
    3466           0 :       *aKeepReflowGoing = false;
    3467           0 :       if (ShouldAvoidBreakInside(aState.mReflowInput)) {
    3468           0 :         aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
    3469             :       } else {
    3470           0 :         PushLines(aState, aLine.prev());
    3471           0 :         aState.mReflowStatus.SetIncomplete();
    3472             :       }
    3473           0 :       return;
    3474             :     }
    3475             : 
    3476             :     // Now put the block-dir coordinate back to the start of the
    3477             :     // block-start-margin + clearance.
    3478          10 :     aState.mBCoord -= bStartMargin;
    3479          10 :     availSpace.BStart(wm) -= bStartMargin;
    3480          10 :     if (NS_UNCONSTRAINEDSIZE != availSpace.BSize(wm)) {
    3481           0 :       availSpace.BSize(wm) += bStartMargin;
    3482             :     }
    3483             : 
    3484             :     // construct the html reflow state for the block. ReflowBlock
    3485             :     // will initialize it.
    3486          10 :     Maybe<ReflowInput> blockHtmlRI;
    3487          10 :     blockHtmlRI.emplace(
    3488             :       aState.mPresContext, aState.mReflowInput, frame,
    3489          20 :       availSpace.Size(wm).ConvertTo(frame->GetWritingMode(), wm));
    3490             : 
    3491          10 :     nsFloatManager::SavedState floatManagerState;
    3492          10 :     nsReflowStatus frameReflowStatus;
    3493             :     do {
    3494          10 :       if (floatAvailableSpace.mHasFloats) {
    3495             :         // Set if floatAvailableSpace.mHasFloats is true for any
    3496             :         // iteration of the loop.
    3497           0 :         aLine->SetLineIsImpactedByFloat(true);
    3498             :       }
    3499             : 
    3500             :       // We might need to store into mDiscoveredClearance later if it's
    3501             :       // currently null; we want to overwrite any writes that
    3502             :       // brc.ReflowBlock() below does, so we need to remember now
    3503             :       // whether it's empty.
    3504             :       const bool shouldStoreClearance =
    3505          10 :         aState.mReflowInput.mDiscoveredClearance &&
    3506          10 :         !*aState.mReflowInput.mDiscoveredClearance;
    3507             : 
    3508             :       // Reflow the block into the available space
    3509          10 :       if (mayNeedRetry || replacedBlock) {
    3510           0 :         aState.FloatManager()->PushState(&floatManagerState);
    3511             :       }
    3512             : 
    3513          10 :       if (mayNeedRetry) {
    3514           0 :         blockHtmlRI->mDiscoveredClearance = &clearanceFrame;
    3515          10 :       } else if (!applyBStartMargin) {
    3516           0 :         blockHtmlRI->mDiscoveredClearance =
    3517           0 :           aState.mReflowInput.mDiscoveredClearance;
    3518             :       }
    3519             : 
    3520          10 :       frameReflowStatus.Reset();
    3521          20 :       brc.ReflowBlock(availSpace, applyBStartMargin, aState.mPrevBEndMargin,
    3522          10 :                       clearance, aState.IsAdjacentWithTop(),
    3523          20 :                       aLine.get(), *blockHtmlRI, frameReflowStatus, aState);
    3524             : 
    3525             :       // Now the block has a height.  Using that height, get the
    3526             :       // available space again and call ComputeBlockAvailSpace again.
    3527             :       // If ComputeBlockAvailSpace gives a different result, we need to
    3528             :       // reflow again.
    3529          10 :       if (!replacedBlock) {
    3530          20 :         break;
    3531             :       }
    3532             : 
    3533           0 :       LogicalRect oldFloatAvailableSpaceRect(floatAvailableSpace.mRect);
    3534           0 :       floatAvailableSpace = aState.GetFloatAvailableSpaceForBSize(
    3535           0 :                               aState.mBCoord + bStartMargin,
    3536           0 :                               brc.GetMetrics().BSize(wm),
    3537           0 :                               &floatManagerState);
    3538           0 :       NS_ASSERTION(floatAvailableSpace.mRect.BStart(wm) ==
    3539             :                      oldFloatAvailableSpaceRect.BStart(wm),
    3540             :                    "yikes");
    3541             :       // Restore the height to the position of the next band.
    3542           0 :       floatAvailableSpace.mRect.BSize(wm) =
    3543           0 :         oldFloatAvailableSpaceRect.BSize(wm);
    3544             :       // Determine whether the available space shrunk on either side,
    3545             :       // because (the first time round) we now know the block's height,
    3546             :       // and it may intersect additional floats, or (on later
    3547             :       // iterations) because narrowing the width relative to the
    3548             :       // previous time may cause the block to become taller.  Note that
    3549             :       // since we're reflowing the block, narrowing the width might also
    3550             :       // make it shorter, so we must pass aCanGrow as true.
    3551           0 :       if (!AvailableSpaceShrunk(wm, oldFloatAvailableSpaceRect,
    3552             :                                 floatAvailableSpace.mRect, true)) {
    3553             :         // The size and position we chose before are fine (i.e., they
    3554             :         // don't cause intersecting with floats that requires a change
    3555             :         // in size or position), so we're done.
    3556           0 :         break;
    3557             :       }
    3558             : 
    3559           0 :       bool advanced = false;
    3560           0 :       if (!aState.ReplacedBlockFitsInAvailSpace(replacedBlock,
    3561             :                                                 floatAvailableSpace)) {
    3562             :         // Advance to the next band.
    3563           0 :         nscoord newBCoord = aState.mBCoord;
    3564           0 :         if (aState.AdvanceToNextBand(floatAvailableSpace.mRect, &newBCoord)) {
    3565           0 :           advanced = true;
    3566             :         }
    3567             :         // ClearFloats might be able to advance us further once we're there.
    3568           0 :         aState.mBCoord =
    3569           0 :           aState.ClearFloats(newBCoord, StyleClear::None, replacedBlock);
    3570             :         // Start over with a new available space rect at the new height.
    3571             :         floatAvailableSpace =
    3572           0 :           aState.GetFloatAvailableSpaceWithState(aState.mBCoord,
    3573             :                                                  ShapeType::ShapeOutside,
    3574           0 :                                                  &floatManagerState);
    3575             :       }
    3576             : 
    3577           0 :       LogicalRect oldAvailSpace(availSpace);
    3578           0 :       aState.ComputeBlockAvailSpace(frame, floatAvailableSpace,
    3579           0 :                                     replacedBlock != nullptr, availSpace);
    3580             : 
    3581           0 :       if (!advanced && availSpace.IsEqualEdges(oldAvailSpace)) {
    3582           0 :         break;
    3583             :       }
    3584             : 
    3585             :       // We need another reflow.
    3586           0 :       aState.FloatManager()->PopState(&floatManagerState);
    3587             : 
    3588           0 :       if (!treatWithClearance && !applyBStartMargin &&
    3589           0 :           aState.mReflowInput.mDiscoveredClearance) {
    3590             :         // We set shouldStoreClearance above to record only the first
    3591             :         // frame that requires clearance.
    3592           0 :         if (shouldStoreClearance) {
    3593           0 :           *aState.mReflowInput.mDiscoveredClearance = frame;
    3594             :         }
    3595           0 :         aState.mPrevChild = frame;
    3596             :         // Exactly what we do now is flexible since we'll definitely be
    3597             :         // reflowed.
    3598           0 :         return;
    3599             :       }
    3600             : 
    3601           0 :       if (advanced) {
    3602             :         // We're pushing down the border-box, so we don't apply margin anymore.
    3603             :         // This should never cause us to move up since the call to
    3604             :         // GetFloatAvailableSpaceForBSize above included the margin.
    3605           0 :         applyBStartMargin = false;
    3606           0 :         bStartMargin = 0;
    3607           0 :         treatWithClearance = true; // avoid hitting test above
    3608           0 :         clearance = 0;
    3609             :       }
    3610             : 
    3611           0 :       blockHtmlRI.reset();
    3612           0 :       blockHtmlRI.emplace(
    3613             :         aState.mPresContext, aState.mReflowInput, frame,
    3614           0 :         availSpace.Size(wm).ConvertTo(frame->GetWritingMode(), wm));
    3615             :     } while (true);
    3616             : 
    3617          10 :     if (mayNeedRetry && clearanceFrame) {
    3618           0 :       aState.FloatManager()->PopState(&floatManagerState);
    3619           0 :       aState.mBCoord = startingBCoord;
    3620           0 :       aState.mPrevBEndMargin = incomingMargin;
    3621           0 :       continue;
    3622             :     }
    3623             : 
    3624          10 :     aState.mPrevChild = frame;
    3625             : 
    3626          10 :     if (blockHtmlRI->WillReflowAgainForClearance()) {
    3627             :       // If an ancestor of ours is going to reflow for clearance, we
    3628             :       // need to avoid calling PlaceBlock, because it unsets dirty bits
    3629             :       // on the child block (both itself, and through its call to
    3630             :       // nsFrame::DidReflow), and those dirty bits imply dirtiness for
    3631             :       // all of the child block, including the lines it didn't reflow.
    3632           0 :       NS_ASSERTION(originalPosition == frame->GetPosition(),
    3633             :                    "we need to call PositionChildViews");
    3634           0 :       return;
    3635             :     }
    3636             : 
    3637             : #if defined(REFLOW_STATUS_COVERAGE)
    3638             :     RecordReflowStatus(true, frameReflowStatus);
    3639             : #endif
    3640             : 
    3641          10 :     if (frameReflowStatus.IsInlineBreakBefore()) {
    3642             :       // None of the child block fits.
    3643           0 :       *aKeepReflowGoing = false;
    3644           0 :       if (ShouldAvoidBreakInside(aState.mReflowInput)) {
    3645           0 :         aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
    3646             :       } else {
    3647           0 :         PushLines(aState, aLine.prev());
    3648           0 :         aState.mReflowStatus.SetIncomplete();
    3649             :       }
    3650             :     }
    3651             :     else {
    3652             :       // Note: line-break-after a block is a nop
    3653             : 
    3654             :       // Try to place the child block.
    3655             :       // Don't force the block to fit if we have positive clearance, because
    3656             :       // pushing it to the next page would give it more room.
    3657             :       // Don't force the block to fit if it's impacted by a float. If it is,
    3658             :       // then pushing it to the next page would give it more room. Note that
    3659             :       // isImpacted doesn't include impact from the block's own floats.
    3660          20 :       bool forceFit = aState.IsAdjacentWithTop() && clearance <= 0 &&
    3661          20 :         !floatAvailableSpace.mHasFloats;
    3662          10 :       nsCollapsingMargin collapsedBEndMargin;
    3663          20 :       nsOverflowAreas overflowAreas;
    3664          10 :       *aKeepReflowGoing = brc.PlaceBlock(*blockHtmlRI, forceFit, aLine.get(),
    3665             :                                          collapsedBEndMargin,
    3666             :                                          overflowAreas,
    3667             :                                          frameReflowStatus);
    3668          10 :       if (!frameReflowStatus.IsFullyComplete() &&
    3669           0 :           ShouldAvoidBreakInside(aState.mReflowInput)) {
    3670           0 :         *aKeepReflowGoing = false;
    3671             :       }
    3672             : 
    3673          10 :       if (aLine->SetCarriedOutBEndMargin(collapsedBEndMargin)) {
    3674           2 :         LineIterator nextLine = aLine;
    3675           2 :         ++nextLine;
    3676           2 :         if (nextLine != LinesEnd()) {
    3677           0 :           nextLine->MarkPreviousMarginDirty();
    3678             :         }
    3679             :       }
    3680             : 
    3681          10 :       aLine->SetOverflowAreas(overflowAreas);
    3682          10 :       if (*aKeepReflowGoing) {
    3683             :         // Some of the child block fit
    3684             : 
    3685             :         // Advance to new Y position
    3686          10 :         nscoord newBCoord = aLine->BEnd();
    3687          10 :         aState.mBCoord = newBCoord;
    3688             : 
    3689             : 
    3690             :         // Continue the block frame now if it didn't completely fit in
    3691             :         // the available space.
    3692          10 :         if (!frameReflowStatus.IsFullyComplete()) {
    3693             :           bool madeContinuation =
    3694           0 :             CreateContinuationFor(aState, nullptr, frame);
    3695             : 
    3696           0 :           nsIFrame* nextFrame = frame->GetNextInFlow();
    3697           0 :           NS_ASSERTION(nextFrame, "We're supposed to have a next-in-flow by now");
    3698             : 
    3699           0 :           if (frameReflowStatus.IsIncomplete()) {
    3700             :             // If nextFrame used to be an overflow container, make it a normal block
    3701           0 :             if (!madeContinuation &&
    3702           0 :                 (NS_FRAME_IS_OVERFLOW_CONTAINER & nextFrame->GetStateBits())) {
    3703           0 :               nsOverflowContinuationTracker::AutoFinish fini(aState.mOverflowTracker, frame);
    3704           0 :               nsContainerFrame* parent = nextFrame->GetParent();
    3705           0 :               nsresult rv = parent->StealFrame(nextFrame);
    3706           0 :               if (NS_FAILED(rv)) {
    3707           0 :                 return;
    3708             :               }
    3709           0 :               if (parent != this)
    3710           0 :                 ReparentFrame(nextFrame, parent, this);
    3711           0 :               mFrames.InsertFrame(nullptr, frame, nextFrame);
    3712           0 :               madeContinuation = true; // needs to be added to mLines
    3713           0 :               nextFrame->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
    3714           0 :               frameReflowStatus.SetNextInFlowNeedsReflow();
    3715             :             }
    3716             : 
    3717             :             // Push continuation to a new line, but only if we actually made one.
    3718           0 :             if (madeContinuation) {
    3719           0 :               nsLineBox* line = NewLineBox(nextFrame, true);
    3720           0 :               mLines.after_insert(aLine, line);
    3721             :             }
    3722             : 
    3723           0 :             PushLines(aState, aLine);
    3724           0 :             aState.mReflowStatus.SetIncomplete();
    3725             : 
    3726             :             // If we need to reflow the continuation of the block child,
    3727             :             // then we'd better reflow our continuation
    3728           0 :             if (frameReflowStatus.NextInFlowNeedsReflow()) {
    3729           0 :               aState.mReflowStatus.SetNextInFlowNeedsReflow();
    3730             :               // We also need to make that continuation's line dirty so
    3731             :               // it gets reflowed when we reflow our next in flow. The
    3732             :               // nif's line must always be either a line of the nif's
    3733             :               // parent block (only if we didn't make a continuation) or
    3734             :               // else one of our own overflow lines. In the latter case
    3735             :               // the line is already marked dirty, so just handle the
    3736             :               // first case.
    3737           0 :               if (!madeContinuation) {
    3738             :                 nsBlockFrame* nifBlock =
    3739           0 :                   nsLayoutUtils::GetAsBlock(nextFrame->GetParent());
    3740           0 :                 NS_ASSERTION(nifBlock,
    3741             :                              "A block's child's next in flow's parent must be a block!");
    3742           0 :                 for (LineIterator line = nifBlock->LinesBegin(),
    3743           0 :                      line_end = nifBlock->LinesEnd(); line != line_end; ++line) {
    3744           0 :                   if (line->Contains(nextFrame)) {
    3745           0 :                     line->MarkDirty();
    3746           0 :                     break;
    3747             :                   }
    3748             :                 }
    3749             :               }
    3750             :             }
    3751           0 :             *aKeepReflowGoing = false;
    3752             : 
    3753             :             // The block-end margin for a block is only applied on the last
    3754             :             // flow block. Since we just continued the child block frame,
    3755             :             // we know that line->mFirstChild is not the last flow block
    3756             :             // therefore zero out the running margin value.
    3757             : #ifdef NOISY_BLOCK_DIR_MARGINS
    3758             :             ListTag(stdout);
    3759             :             printf(": reflow incomplete, frame=");
    3760             :             nsFrame::ListTag(stdout, mFrame);
    3761             :             printf(" prevBEndMargin=%d, setting to zero\n",
    3762             :                    aState.mPrevBEndMargin.get());
    3763             : #endif
    3764           0 :             aState.mPrevBEndMargin.Zero();
    3765             :           }
    3766             :           else { // frame is complete but its overflow is not complete
    3767             :             // Disconnect the next-in-flow and put it in our overflow tracker
    3768           0 :             if (!madeContinuation &&
    3769           0 :                 !(NS_FRAME_IS_OVERFLOW_CONTAINER & nextFrame->GetStateBits())) {
    3770             :               // It already exists, but as a normal next-in-flow, so we need
    3771             :               // to dig it out of the child lists.
    3772           0 :               nsresult rv = nextFrame->GetParent()->StealFrame(nextFrame);
    3773           0 :               if (NS_FAILED(rv)) {
    3774           0 :                 return;
    3775             :               }
    3776             :             }
    3777           0 :             else if (madeContinuation) {
    3778           0 :               mFrames.RemoveFrame(nextFrame);
    3779             :             }
    3780             : 
    3781             :             // Put it in our overflow list
    3782           0 :             aState.mOverflowTracker->Insert(nextFrame, frameReflowStatus);
    3783           0 :             aState.mReflowStatus.MergeCompletionStatusFrom(frameReflowStatus);
    3784             : 
    3785             : #ifdef NOISY_BLOCK_DIR_MARGINS
    3786             :             ListTag(stdout);
    3787             :             printf(": reflow complete but overflow incomplete for ");
    3788             :             nsFrame::ListTag(stdout, mFrame);
    3789             :             printf(" prevBEndMargin=%d collapsedBEndMargin=%d\n",
    3790             :                    aState.mPrevBEndMargin.get(), collapsedBEndMargin.get());
    3791             : #endif
    3792           0 :             aState.mPrevBEndMargin = collapsedBEndMargin;
    3793             :           }
    3794             :         }
    3795             :         else { // frame is fully complete
    3796             : #ifdef NOISY_BLOCK_DIR_MARGINS
    3797             :           ListTag(stdout);
    3798             :           printf(": reflow complete for ");
    3799             :           nsFrame::ListTag(stdout, mFrame);
    3800             :           printf(" prevBEndMargin=%d collapsedBEndMargin=%d\n",
    3801             :                  aState.mPrevBEndMargin.get(), collapsedBEndMargin.get());
    3802             : #endif
    3803          10 :           aState.mPrevBEndMargin = collapsedBEndMargin;
    3804             :         }
    3805             : #ifdef NOISY_BLOCK_DIR_MARGINS
    3806             :         ListTag(stdout);
    3807             :         printf(": frame=");
    3808             :         nsFrame::ListTag(stdout, mFrame);
    3809             :         printf(" carriedOutBEndMargin=%d collapsedBEndMargin=%d => %d\n",
    3810             :                brc.GetCarriedOutBEndMargin().get(), collapsedBEndMargin.get(),
    3811             :                aState.mPrevBEndMargin.get());
    3812             : #endif
    3813             :       } else {
    3814           0 :         if ((aLine == mLines.front() && !GetPrevInFlow()) ||
    3815           0 :             ShouldAvoidBreakInside(aState.mReflowInput)) {
    3816             :           // If it's our very first line *or* we're not at the top of the page
    3817             :           // and we have page-break-inside:avoid, then we need to be pushed to
    3818             :           // our parent's next-in-flow.
    3819           0 :           aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
    3820             :           // When we reflow in the new position, we need to reflow this
    3821             :           // line again.
    3822           0 :           aLine->MarkDirty();
    3823             :         } else {
    3824             :           // Push the line that didn't fit and any lines that follow it
    3825             :           // to our next-in-flow.
    3826           0 :           PushLines(aState, aLine.prev());
    3827           0 :           aState.mReflowStatus.SetIncomplete();
    3828             :         }
    3829             :       }
    3830             :     }
    3831          10 :     break; // out of the reflow retry loop
    3832           0 :   }
    3833             : 
    3834             :   // Now that we've got its final position all figured out, position any child
    3835             :   // views it may have.  Note that the case when frame has a view got handled
    3836             :   // by FinishReflowChild, but that function didn't have the coordinates needed
    3837             :   // to correctly decide whether to reposition child views.
    3838          10 :   if (originalPosition != frame->GetPosition() && !frame->HasView()) {
    3839           2 :     nsContainerFrame::PositionChildViews(frame);
    3840             :   }
    3841             : 
    3842             : #ifdef DEBUG
    3843          10 :   VerifyLines(true);
    3844             : #endif
    3845             : }
    3846             : 
    3847             : void
    3848          75 : nsBlockFrame::ReflowInlineFrames(BlockReflowInput& aState,
    3849             :                                  LineIterator aLine,
    3850             :                                  bool* aKeepReflowGoing)
    3851             : {
    3852          75 :   *aKeepReflowGoing = true;
    3853             : 
    3854          75 :   aLine->SetLineIsImpactedByFloat(false);
    3855             : 
    3856             :   // Setup initial coordinate system for reflowing the inline frames
    3857             :   // into. Apply a previous block frame's block-end margin first.
    3858          75 :   if (ShouldApplyBStartMargin(aState, aLine, aLine->mFirstChild)) {
    3859          74 :     aState.mBCoord += aState.mPrevBEndMargin.get();
    3860             :   }
    3861         150 :   nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
    3862             : 
    3863             :   LineReflowStatus lineReflowStatus;
    3864           0 :   do {
    3865          75 :     nscoord availableSpaceBSize = 0;
    3866          75 :     aState.mLineBSize.reset();
    3867           0 :     do {
    3868          75 :       bool allowPullUp = true;
    3869          75 :       nsIFrame* forceBreakInFrame = nullptr;
    3870          75 :       int32_t forceBreakOffset = -1;
    3871          75 :       gfxBreakPriority forceBreakPriority = gfxBreakPriority::eNoBreak;
    3872           0 :       do {
    3873          75 :         nsFloatManager::SavedState floatManagerState;
    3874          75 :         aState.FloatManager()->PushState(&floatManagerState);
    3875             : 
    3876             :         // Once upon a time we allocated the first 30 nsLineLayout objects
    3877             :         // on the stack, and then we switched to the heap.  At that time
    3878             :         // these objects were large (1100 bytes on a 32 bit system).
    3879             :         // Then the nsLineLayout object was shrunk to 156 bytes by
    3880             :         // removing some internal buffers.  Given that it is so much
    3881             :         // smaller, the complexity of 2 different ways of allocating
    3882             :         // no longer makes sense.  Now we always allocate on the stack.
    3883             :         nsLineLayout lineLayout(aState.mPresContext,
    3884             :                                 aState.FloatManager(),
    3885         150 :                                 &aState.mReflowInput, &aLine, nullptr);
    3886          75 :         lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
    3887          75 :         if (forceBreakInFrame) {
    3888           0 :           lineLayout.ForceBreakAtPosition(forceBreakInFrame, forceBreakOffset);
    3889             :         }
    3890          75 :         DoReflowInlineFrames(aState, lineLayout, aLine,
    3891             :                              floatAvailableSpace, availableSpaceBSize,
    3892             :                              &floatManagerState, aKeepReflowGoing,
    3893          75 :                              &lineReflowStatus, allowPullUp);
    3894          75 :         lineLayout.EndLineReflow();
    3895             : 
    3896         150 :         if (LineReflowStatus::RedoNoPull == lineReflowStatus ||
    3897         150 :             LineReflowStatus::RedoMoreFloats == lineReflowStatus ||
    3898          75 :             LineReflowStatus::RedoNextBand == lineReflowStatus) {
    3899           0 :           if (lineLayout.NeedsBackup()) {
    3900           0 :             NS_ASSERTION(!forceBreakInFrame, "Backing up twice; this should never be necessary");
    3901             :             // If there is no saved break position, then this will set
    3902             :             // set forceBreakInFrame to null and we won't back up, which is
    3903             :             // correct.
    3904             :             forceBreakInFrame =
    3905           0 :               lineLayout.GetLastOptionalBreakPosition(&forceBreakOffset, &forceBreakPriority);
    3906             :           } else {
    3907           0 :             forceBreakInFrame = nullptr;
    3908             :           }
    3909             :           // restore the float manager state
    3910           0 :           aState.FloatManager()->PopState(&floatManagerState);
    3911             :           // Clear out float lists
    3912           0 :           aState.mCurrentLineFloats.DeleteAll();
    3913           0 :           aState.mBelowCurrentLineFloats.DeleteAll();
    3914             :         }
    3915             : 
    3916             :         // Don't allow pullup on a subsequent LineReflowStatus::RedoNoPull pass
    3917          75 :         allowPullUp = false;
    3918          75 :       } while (LineReflowStatus::RedoNoPull == lineReflowStatus);
    3919          75 :     } while (LineReflowStatus::RedoMoreFloats == lineReflowStatus);
    3920          75 :   } while (LineReflowStatus::RedoNextBand == lineReflowStatus);
    3921          75 : }
    3922             : 
    3923             : void
    3924           0 : nsBlockFrame::PushTruncatedLine(BlockReflowInput& aState,
    3925             :                                 LineIterator       aLine,
    3926             :                                 bool*               aKeepReflowGoing)
    3927             : {
    3928           0 :   PushLines(aState, aLine.prev());
    3929           0 :   *aKeepReflowGoing = false;
    3930           0 :   aState.mReflowStatus.SetIncomplete();
    3931           0 : }
    3932             : 
    3933             : void
    3934          75 : nsBlockFrame::DoReflowInlineFrames(BlockReflowInput& aState,
    3935             :                                    nsLineLayout& aLineLayout,
    3936             :                                    LineIterator aLine,
    3937             :                                    nsFlowAreaRect& aFloatAvailableSpace,
    3938             :                                    nscoord& aAvailableSpaceBSize,
    3939             :                                    nsFloatManager::SavedState*
    3940             :                                      aFloatStateBeforeLine,
    3941             :                                    bool* aKeepReflowGoing,
    3942             :                                    LineReflowStatus* aLineReflowStatus,
    3943             :                                    bool aAllowPullUp)
    3944             : {
    3945             :   // Forget all of the floats on the line
    3946          75 :   aLine->FreeFloats(aState.mFloatCacheFreeList);
    3947          75 :   aState.mFloatOverflowAreas.Clear();
    3948             : 
    3949             :   // We need to set this flag on the line if any of our reflow passes
    3950             :   // are impacted by floats.
    3951          75 :   if (aFloatAvailableSpace.mHasFloats)
    3952           0 :     aLine->SetLineIsImpactedByFloat(true);
    3953             : #ifdef REALLY_NOISY_REFLOW
    3954             :   printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
    3955             :          this, aFloatAvailableSpace.mHasFloats);
    3956             : #endif
    3957             : 
    3958          75 :   WritingMode outerWM = aState.mReflowInput.GetWritingMode();
    3959          75 :   WritingMode lineWM = WritingModeForLine(outerWM, aLine->mFirstChild);
    3960             :   LogicalRect lineRect =
    3961             :     aFloatAvailableSpace.mRect.ConvertTo(lineWM, outerWM,
    3962         150 :                                          aState.ContainerSize());
    3963             : 
    3964          75 :   nscoord iStart = lineRect.IStart(lineWM);
    3965          75 :   nscoord availISize = lineRect.ISize(lineWM);
    3966             :   nscoord availBSize;
    3967          75 :   if (aState.mFlags.mHasUnconstrainedBSize) {
    3968          75 :     availBSize = NS_UNCONSTRAINEDSIZE;
    3969             :   }
    3970             :   else {
    3971             :     /* XXX get the height right! */
    3972           0 :     availBSize = lineRect.BSize(lineWM);
    3973             :   }
    3974             : 
    3975             :   // Make sure to enable resize optimization before we call BeginLineReflow
    3976             :   // because it might get disabled there
    3977          75 :   aLine->EnableResizeReflowOptimization();
    3978             : 
    3979         150 :   aLineLayout.BeginLineReflow(iStart, aState.mBCoord,
    3980             :                               availISize, availBSize,
    3981          75 :                               aFloatAvailableSpace.mHasFloats,
    3982             :                               false, /*XXX isTopOfPage*/
    3983          75 :                               lineWM, aState.mContainerSize);
    3984             : 
    3985          75 :   aState.mFlags.mIsLineLayoutEmpty = false;
    3986             : 
    3987             :   // XXX Unfortunately we need to know this before reflowing the first
    3988             :   // inline frame in the line. FIX ME.
    3989         225 :   if ((0 == aLineLayout.GetLineNumber()) &&
    3990          75 :       (NS_BLOCK_HAS_FIRST_LETTER_CHILD & mState) &&
    3991           0 :       (NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
    3992           0 :     aLineLayout.SetFirstLetterStyleOK(true);
    3993             :   }
    3994          75 :   NS_ASSERTION(!((NS_BLOCK_HAS_FIRST_LETTER_CHILD & mState) &&
    3995             :                  GetPrevContinuation()),
    3996             :                "first letter child bit should only be on first continuation");
    3997             : 
    3998             :   // Reflow the frames that are already on the line first
    3999          75 :   LineReflowStatus lineReflowStatus = LineReflowStatus::OK;
    4000             :   int32_t i;
    4001          75 :   nsIFrame* frame = aLine->mFirstChild;
    4002             : 
    4003          75 :   if (aFloatAvailableSpace.mHasFloats) {
    4004             :     // There is a soft break opportunity at the start of the line, because
    4005             :     // we can always move this line down below float(s).
    4006           0 :     if (aLineLayout.NotifyOptionalBreakPosition(
    4007             :             frame, 0, true, gfxBreakPriority::eNormalBreak)) {
    4008           0 :       lineReflowStatus = LineReflowStatus::RedoNextBand;
    4009             :     }
    4010             :   }
    4011             : 
    4012             :   // need to repeatedly call GetChildCount here, because the child
    4013             :   // count can change during the loop!
    4014         150 :   for (i = 0; LineReflowStatus::OK == lineReflowStatus && i < aLine->GetChildCount();
    4015             :        i++, frame = frame->GetNextSibling()) {
    4016          75 :     ReflowInlineFrame(aState, aLineLayout, aLine, frame, &lineReflowStatus);
    4017          75 :     if (LineReflowStatus::OK != lineReflowStatus) {
    4018             :       // It is possible that one or more of next lines are empty
    4019             :       // (because of DeleteNextInFlowChild). If so, delete them now
    4020             :       // in case we are finished.
    4021           9 :       ++aLine;
    4022           9 :       while ((aLine != LinesEnd()) && (0 == aLine->GetChildCount())) {
    4023             :         // XXX Is this still necessary now that DeleteNextInFlowChild
    4024             :         // uses DoRemoveFrame?
    4025           0 :         nsLineBox *toremove = aLine;
    4026           0 :         aLine = mLines.erase(aLine);
    4027           0 :         NS_ASSERTION(nullptr == toremove->mFirstChild, "bad empty line");
    4028           0 :         FreeLineBox(toremove);
    4029             :       }
    4030           9 :       --aLine;
    4031             : 
    4032           9 :       NS_ASSERTION(lineReflowStatus != LineReflowStatus::Truncated,
    4033             :                    "ReflowInlineFrame should never determine that a line "
    4034             :                    "needs to go to the next page/column");
    4035             :     }
    4036             :   }
    4037             : 
    4038             :   // Don't pull up new frames into lines with continuation placeholders
    4039          75 :   if (aAllowPullUp) {
    4040             :     // Pull frames and reflow them until we can't
    4041          75 :     while (LineReflowStatus::OK == lineReflowStatus) {
    4042          66 :       frame = PullFrame(aState, aLine);
    4043          66 :       if (!frame) {
    4044          66 :         break;
    4045             :       }
    4046             : 
    4047           0 :       while (LineReflowStatus::OK == lineReflowStatus) {
    4048           0 :         int32_t oldCount = aLine->GetChildCount();
    4049           0 :         ReflowInlineFrame(aState, aLineLayout, aLine, frame, &lineReflowStatus);
    4050           0 :         if (aLine->GetChildCount() != oldCount) {
    4051             :           // We just created a continuation for aFrame AND its going
    4052             :           // to end up on this line (e.g. :first-letter
    4053             :           // situation). Therefore we have to loop here before trying
    4054             :           // to pull another frame.
    4055           0 :           frame = frame->GetNextSibling();
    4056             :         }
    4057             :         else {
    4058           0 :           break;
    4059             :         }
    4060             :       }
    4061             :     }
    4062             :   }
    4063             : 
    4064          75 :   aState.mFlags.mIsLineLayoutEmpty = aLineLayout.LineIsEmpty();
    4065             : 
    4066             :   // We only need to backup if the line isn't going to be reflowed again anyway
    4067          75 :   bool needsBackup = aLineLayout.NeedsBackup() &&
    4068           0 :     (lineReflowStatus == LineReflowStatus::Stop ||
    4069          75 :      lineReflowStatus == LineReflowStatus::OK);
    4070          75 :   if (needsBackup && aLineLayout.HaveForcedBreakPosition()) {
    4071             :     NS_WARNING("We shouldn't be backing up more than once! "
    4072             :                "Someone must have set a break opportunity beyond the available width, "
    4073           0 :                "even though there were better break opportunities before it");
    4074           0 :     needsBackup = false;
    4075             :   }
    4076          75 :   if (needsBackup) {
    4077             :     // We need to try backing up to before a text run
    4078             :     // XXX It's possible, in fact not unusual, for the break opportunity to already
    4079             :     // be the end of the line. We should detect that and optimize to not
    4080             :     // re-do the line.
    4081           0 :     if (aLineLayout.HasOptionalBreakPosition()) {
    4082             :       // We can back up!
    4083           0 :       lineReflowStatus = LineReflowStatus::RedoNoPull;
    4084             :     }
    4085             :   } else {
    4086             :     // In case we reflow this line again, remember that we don't
    4087             :     // need to force any breaking
    4088          75 :     aLineLayout.ClearOptionalBreakPosition();
    4089             :   }
    4090             : 
    4091          75 :   if (LineReflowStatus::RedoNextBand == lineReflowStatus) {
    4092             :     // This happens only when we have a line that is impacted by
    4093             :     // floats and the first element in the line doesn't fit with
    4094             :     // the floats.
    4095             :     //
    4096             :     // What we do is to advance past the first float we find and
    4097             :     // then reflow the line all over again.
    4098           0 :     NS_ASSERTION(NS_UNCONSTRAINEDSIZE !=
    4099             :                  aFloatAvailableSpace.mRect.BSize(outerWM),
    4100             :                  "unconstrained block size on totally empty line");
    4101             : 
    4102             :     // See the analogous code for blocks in BlockReflowInput::ClearFloats.
    4103           0 :     if (aFloatAvailableSpace.mRect.BSize(outerWM) > 0) {
    4104           0 :       NS_ASSERTION(aFloatAvailableSpace.mHasFloats,
    4105             :                    "redo line on totally empty line with non-empty band...");
    4106             :       // We should never hit this case if we've placed floats on the
    4107             :       // line; if we have, then the GetFloatAvailableSpace call is wrong
    4108             :       // and needs to happen after the caller pops the space manager
    4109             :       // state.
    4110           0 :       aState.FloatManager()->AssertStateMatches(aFloatStateBeforeLine);
    4111           0 :       aState.mBCoord += aFloatAvailableSpace.mRect.BSize(outerWM);
    4112           0 :       aFloatAvailableSpace = aState.GetFloatAvailableSpace();
    4113             :     } else {
    4114           0 :       NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowInput.AvailableBSize(),
    4115             :                    "We shouldn't be running out of height here");
    4116           0 :       if (NS_UNCONSTRAINEDSIZE == aState.mReflowInput.AvailableBSize()) {
    4117             :         // just move it down a bit to try to get out of this mess
    4118           0 :         aState.mBCoord += 1;
    4119             :         // We should never hit this case if we've placed floats on the
    4120             :         // line; if we have, then the GetFloatAvailableSpace call is wrong
    4121             :         // and needs to happen after the caller pops the space manager
    4122             :         // state.
    4123           0 :         aState.FloatManager()->AssertStateMatches(aFloatStateBeforeLine);
    4124           0 :         aFloatAvailableSpace = aState.GetFloatAvailableSpace();
    4125             :       } else {
    4126             :         // There's nowhere to retry placing the line, so we want to push
    4127             :         // it to the next page/column where its contents can fit not
    4128             :         // next to a float.
    4129           0 :         lineReflowStatus = LineReflowStatus::Truncated;
    4130           0 :         PushTruncatedLine(aState, aLine, aKeepReflowGoing);
    4131             :       }
    4132             :     }
    4133             : 
    4134             :     // XXX: a small optimization can be done here when paginating:
    4135             :     // if the new Y coordinate is past the end of the block then
    4136             :     // push the line and return now instead of later on after we are
    4137             :     // past the float.
    4138             :   }
    4139         150 :   else if (LineReflowStatus::Truncated != lineReflowStatus &&
    4140          75 :            LineReflowStatus::RedoNoPull != lineReflowStatus) {
    4141             :     // If we are propagating out a break-before status then there is
    4142             :     // no point in placing the line.
    4143          75 :     if (!aState.mReflowStatus.IsInlineBreakBefore()) {
    4144          75 :       if (!PlaceLine(aState, aLineLayout, aLine, aFloatStateBeforeLine,
    4145             :                      aFloatAvailableSpace.mRect, aAvailableSpaceBSize,
    4146             :                      aKeepReflowGoing)) {
    4147           0 :         lineReflowStatus = LineReflowStatus::RedoMoreFloats;
    4148             :         // PlaceLine already called GetAvailableSpaceForBSize for us.
    4149             :       }
    4150             :     }
    4151             :   }
    4152             : #ifdef DEBUG
    4153          75 :   if (gNoisyReflow) {
    4154           0 :     printf("Line reflow status = %s\n", LineReflowStatusToString(lineReflowStatus));
    4155             :   }
    4156             : #endif
    4157             : 
    4158          75 :   if (aLineLayout.GetDirtyNextLine()) {
    4159             :     // aLine may have been pushed to the overflow lines.
    4160           0 :     FrameLines* overflowLines = GetOverflowLines();
    4161             :     // We can't just compare iterators front() to aLine here, since they may be in
    4162             :     // different lists.
    4163           0 :     bool pushedToOverflowLines = overflowLines &&
    4164           0 :       overflowLines->mLines.front() == aLine.get();
    4165           0 :     if (pushedToOverflowLines) {
    4166             :       // aLine is stale, it's associated with the main line list but it should
    4167             :       // be associated with the overflow line list now
    4168           0 :       aLine = overflowLines->mLines.begin();
    4169             :     }
    4170           0 :     nsBlockInFlowLineIterator iter(this, aLine, pushedToOverflowLines);
    4171           0 :     if (iter.Next() && iter.GetLine()->IsInline()) {
    4172           0 :       iter.GetLine()->MarkDirty();
    4173           0 :       if (iter.GetContainer() != this) {
    4174           0 :         aState.mReflowStatus.SetNextInFlowNeedsReflow();
    4175             :       }
    4176             :     }
    4177             :   }
    4178             : 
    4179          75 :   *aLineReflowStatus = lineReflowStatus;
    4180          75 : }
    4181             : 
    4182             : /**
    4183             :  * Reflow an inline frame. The reflow status is mapped from the frames
    4184             :  * reflow status to the lines reflow status (not to our reflow status).
    4185             :  * The line reflow status is simple: true means keep placing frames
    4186             :  * on the line; false means don't (the line is done). If the line
    4187             :  * has some sort of breaking affect then aLine's break-type will be set
    4188             :  * to something other than StyleClear::None.
    4189             :  */
    4190             : void
    4191          75 : nsBlockFrame::ReflowInlineFrame(BlockReflowInput& aState,
    4192             :                                 nsLineLayout& aLineLayout,
    4193             :                                 LineIterator aLine,
    4194             :                                 nsIFrame* aFrame,
    4195             :                                 LineReflowStatus* aLineReflowStatus)
    4196             : {
    4197          75 :   if (!aFrame) { // XXX change to MOZ_ASSERT(aFrame)
    4198           0 :     NS_ERROR("why call me?");
    4199           0 :     return;
    4200             :   }
    4201             : 
    4202          75 :   *aLineReflowStatus = LineReflowStatus::OK;
    4203             : 
    4204             : #ifdef NOISY_FIRST_LETTER
    4205             :   ListTag(stdout);
    4206             :   printf(": reflowing ");
    4207             :   nsFrame::ListTag(stdout, aFrame);
    4208             :   printf(" reflowingFirstLetter=%s\n",
    4209             :          aLineLayout.GetFirstLetterStyleOK() ? "on" : "off");
    4210             : #endif
    4211             : 
    4212          75 :   if (aFrame->IsPlaceholderFrame()) {
    4213           0 :     auto ph = static_cast<nsPlaceholderFrame*>(aFrame);
    4214           0 :     ph->ForgetLineIsEmptySoFar();
    4215             :   }
    4216             : 
    4217             :   // Reflow the inline frame
    4218          75 :   nsReflowStatus frameReflowStatus;
    4219             :   bool           pushedFrame;
    4220          75 :   aLineLayout.ReflowFrame(aFrame, frameReflowStatus, nullptr, pushedFrame);
    4221             : 
    4222          75 :   if (frameReflowStatus.NextInFlowNeedsReflow()) {
    4223           0 :     aLineLayout.SetDirtyNextLine();
    4224             :   }
    4225             : 
    4226             : #ifdef REALLY_NOISY_REFLOW
    4227             :   nsFrame::ListTag(stdout, aFrame);
    4228             :   printf(": status=%x\n", frameReflowStatus);
    4229             : #endif
    4230             : 
    4231             : #if defined(REFLOW_STATUS_COVERAGE)
    4232             :   RecordReflowStatus(false, frameReflowStatus);
    4233             : #endif
    4234             : 
    4235             :   // Send post-reflow notification
    4236          75 :   aState.mPrevChild = aFrame;
    4237             : 
    4238             :    /* XXX
    4239             :       This is where we need to add logic to handle some odd behavior.
    4240             :       For one thing, we should usually place at least one thing next
    4241             :       to a left float, even when that float takes up all the width on a line.
    4242             :       see bug 22496
    4243             :    */
    4244             : 
    4245             :   // Process the child frames reflow status. There are 5 cases:
    4246             :   // complete, not-complete, break-before, break-after-complete,
    4247             :   // break-after-not-complete. There are two situations: we are a
    4248             :   // block or we are an inline. This makes a total of 10 cases
    4249             :   // (fortunately, there is some overlap).
    4250          75 :   aLine->SetBreakTypeAfter(StyleClear::None);
    4251         141 :   if (frameReflowStatus.IsInlineBreak() ||
    4252          66 :       StyleClear::None != aState.mFloatBreakType) {
    4253             :     // Always abort the line reflow (because a line break is the
    4254             :     // minimal amount of break we do).
    4255           9 :     *aLineReflowStatus = LineReflowStatus::Stop;
    4256             : 
    4257             :     // XXX what should aLine's break-type be set to in all these cases?
    4258           9 :     StyleClear breakType = frameReflowStatus.BreakType();
    4259           9 :     MOZ_ASSERT(StyleClear::None != breakType ||
    4260             :                StyleClear::None != aState.mFloatBreakType, "bad break type");
    4261             : 
    4262           9 :     if (frameReflowStatus.IsInlineBreakBefore()) {
    4263             :       // Break-before cases.
    4264           0 :       if (aFrame == aLine->mFirstChild) {
    4265             :         // If we break before the first frame on the line then we must
    4266             :         // be trying to place content where there's no room (e.g. on a
    4267             :         // line with wide floats). Inform the caller to reflow the
    4268             :         // line after skipping past a float.
    4269           0 :         *aLineReflowStatus = LineReflowStatus::RedoNextBand;
    4270             :       }
    4271             :       else {
    4272             :         // It's not the first child on this line so go ahead and split
    4273             :         // the line. We will see the frame again on the next-line.
    4274           0 :         SplitLine(aState, aLineLayout, aLine, aFrame, aLineReflowStatus);
    4275             : 
    4276             :         // If we're splitting the line because the frame didn't fit and it
    4277             :         // was pushed, then mark the line as having word wrapped. We need to
    4278             :         // know that if we're shrink wrapping our width
    4279           0 :         if (pushedFrame) {
    4280           0 :           aLine->SetLineWrapped(true);
    4281             :         }
    4282             :       }
    4283             :     }
    4284             :     else {
    4285             :       // If a float split and its prev-in-flow was followed by a <BR>, then combine
    4286             :       // the <BR>'s break type with the inline's break type (the inline will be the very
    4287             :       // next frame after the split float).
    4288           9 :       if (StyleClear::None != aState.mFloatBreakType) {
    4289           0 :         breakType = nsLayoutUtils::CombineBreakType(breakType,
    4290           0 :                                                     aState.mFloatBreakType);
    4291           0 :         aState.mFloatBreakType = StyleClear::None;
    4292             :       }
    4293             :       // Break-after cases
    4294           9 :       if (breakType == StyleClear::Line) {
    4295           9 :         if (!aLineLayout.GetLineEndsInBR()) {
    4296           0 :           breakType = StyleClear::None;
    4297             :         }
    4298             :       }
    4299           9 :       aLine->SetBreakTypeAfter(breakType);
    4300           9 :       if (frameReflowStatus.IsComplete()) {
    4301             :         // Split line, but after the frame just reflowed
    4302           9 :         SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling(), aLineReflowStatus);
    4303             : 
    4304          18 :         if (frameReflowStatus.IsInlineBreakAfter() &&
    4305           9 :             !aLineLayout.GetLineEndsInBR()) {
    4306           0 :           aLineLayout.SetDirtyNextLine();
    4307             :         }
    4308             :       }
    4309             :     }
    4310             :   }
    4311             : 
    4312          75 :   if (!frameReflowStatus.IsFullyComplete()) {
    4313             :     // Create a continuation for the incomplete frame. Note that the
    4314             :     // frame may already have a continuation.
    4315           0 :     CreateContinuationFor(aState, aLine, aFrame);
    4316             : 
    4317             :     // Remember that the line has wrapped
    4318           0 :     if (!aLineLayout.GetLineEndsInBR()) {
    4319           0 :       aLine->SetLineWrapped(true);
    4320             :     }
    4321             : 
    4322             :     // If we just ended a first-letter frame or reflowed a placeholder then
    4323             :     // don't split the line and don't stop the line reflow...
    4324             :     // But if we are going to stop anyways we'd better split the line.
    4325           0 :     if ((!frameReflowStatus.FirstLetterComplete() &&
    4326           0 :          !aFrame->IsPlaceholderFrame()) ||
    4327           0 :         *aLineReflowStatus == LineReflowStatus::Stop) {
    4328             :       // Split line after the current frame
    4329           0 :       *aLineReflowStatus = LineReflowStatus::Stop;
    4330           0 :       SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling(), aLineReflowStatus);
    4331             :     }
    4332             :   }
    4333             : }
    4334             : 
    4335             : bool
    4336           0 : nsBlockFrame::CreateContinuationFor(BlockReflowInput& aState,
    4337             :                                     nsLineBox*          aLine,
    4338             :                                     nsIFrame*           aFrame)
    4339             : {
    4340           0 :   nsIFrame* newFrame = nullptr;
    4341             : 
    4342           0 :   if (!aFrame->GetNextInFlow()) {
    4343           0 :     newFrame = aState.mPresContext->PresShell()->FrameConstructor()->
    4344           0 :       CreateContinuingFrame(aState.mPresContext, aFrame, this);
    4345             : 
    4346           0 :     mFrames.InsertFrame(nullptr, aFrame, newFrame);
    4347             : 
    4348           0 :     if (aLine) {
    4349           0 :       aLine->NoteFrameAdded(newFrame);
    4350             :     }
    4351             :   }
    4352             : #ifdef DEBUG
    4353           0 :   VerifyLines(false);
    4354             : #endif
    4355           0 :   return !!newFrame;
    4356             : }
    4357             : 
    4358             : nsresult
    4359           0 : nsBlockFrame::SplitFloat(BlockReflowInput& aState,
    4360             :                          nsIFrame*           aFloat,
    4361             :                          nsReflowStatus      aFloatStatus)
    4362             : {
    4363           0 :   MOZ_ASSERT(!aFloatStatus.IsFullyComplete(),
    4364             :              "why split the frame if it's fully complete?");
    4365           0 :   MOZ_ASSERT(aState.mBlock == this);
    4366             : 
    4367           0 :   nsIFrame* nextInFlow = aFloat->GetNextInFlow();
    4368           0 :   if (nextInFlow) {
    4369           0 :     nsContainerFrame *oldParent = nextInFlow->GetParent();
    4370           0 :     DebugOnly<nsresult> rv = oldParent->StealFrame(nextInFlow);
    4371           0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failed");
    4372           0 :     if (oldParent != this) {
    4373           0 :       ReparentFrame(nextInFlow, oldParent, this);
    4374             :     }
    4375           0 :     if (!aFloatStatus.IsOverflowIncomplete()) {
    4376           0 :       nextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
    4377             :     }
    4378             :   } else {
    4379           0 :     nextInFlow = aState.mPresContext->PresShell()->FrameConstructor()->
    4380           0 :       CreateContinuingFrame(aState.mPresContext, aFloat, this);
    4381             :   }
    4382           0 :   if (aFloatStatus.IsOverflowIncomplete()) {
    4383           0 :     nextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
    4384             :   }
    4385             : 
    4386             :   StyleFloat floatStyle =
    4387           0 :     aFloat->StyleDisplay()->PhysicalFloats(aState.mReflowInput.GetWritingMode());
    4388           0 :   if (floatStyle == StyleFloat::Left) {
    4389           0 :     aState.FloatManager()->SetSplitLeftFloatAcrossBreak();
    4390             :   } else {
    4391           0 :     MOZ_ASSERT(floatStyle == StyleFloat::Right, "Unexpected float side!");
    4392           0 :     aState.FloatManager()->SetSplitRightFloatAcrossBreak();
    4393             :   }
    4394             : 
    4395           0 :   aState.AppendPushedFloatChain(nextInFlow);
    4396           0 :   aState.mReflowStatus.SetOverflowIncomplete();
    4397           0 :   return NS_OK;
    4398             : }
    4399             : 
    4400             : static nsFloatCache*
    4401           0 : GetLastFloat(nsLineBox* aLine)
    4402             : {
    4403           0 :   nsFloatCache* fc = aLine->GetFirstFloat();
    4404           0 :   while (fc && fc->Next()) {
    4405           0 :     fc = fc->Next();
    4406             :   }
    4407           0 :   return fc;
    4408             : }
    4409             : 
    4410             : static bool
    4411           0 : CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine, nsFloatCache* aFC)
    4412             : {
    4413           0 :   if (!aFC)
    4414           0 :     return true;
    4415           0 :   NS_ASSERTION(!aFC->mFloat->GetPrevContinuation(),
    4416             :                "float in a line should never be a continuation");
    4417           0 :   NS_ASSERTION(!(aFC->mFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
    4418             :                "float in a line should never be a pushed float");
    4419           0 :   nsIFrame* ph = aFC->mFloat->FirstInFlow()->GetPlaceholderFrame();
    4420           0 :   for (nsIFrame* f = ph; f; f = f->GetParent()) {
    4421           0 :     if (f->GetParent() == aBlock)
    4422           0 :       return aLine->Contains(f);
    4423             :   }
    4424           0 :   NS_ASSERTION(false, "aBlock is not an ancestor of aFrame!");
    4425           0 :   return true;
    4426             : }
    4427             : 
    4428             : void
    4429           9 : nsBlockFrame::SplitLine(BlockReflowInput& aState,
    4430             :                         nsLineLayout& aLineLayout,
    4431             :                         LineIterator aLine,
    4432             :                         nsIFrame* aFrame,
    4433             :                         LineReflowStatus* aLineReflowStatus)
    4434             : {
    4435           9 :   MOZ_ASSERT(aLine->IsInline(), "illegal SplitLine on block line");
    4436             : 
    4437           9 :   int32_t pushCount = aLine->GetChildCount() - aLineLayout.GetCurrentSpanCount();
    4438           9 :   MOZ_ASSERT(pushCount >= 0, "bad push count");
    4439             : 
    4440             : #ifdef DEBUG
    4441           9 :   if (gNoisyReflow) {
    4442           0 :     nsFrame::IndentBy(stdout, gNoiseIndent);
    4443             :     printf("split line: from line=%p pushCount=%d aFrame=",
    4444           0 :            static_cast<void*>(aLine.get()), pushCount);
    4445           0 :     if (aFrame) {
    4446           0 :       nsFrame::ListTag(stdout, aFrame);
    4447             :     }
    4448             :     else {
    4449           0 :       printf("(null)");
    4450             :     }
    4451           0 :     printf("\n");
    4452           0 :     if (gReallyNoisyReflow) {
    4453           0 :       aLine->List(stdout, gNoiseIndent+1);
    4454             :     }
    4455             :   }
    4456             : #endif
    4457             : 
    4458           9 :   if (0 != pushCount) {
    4459           0 :     MOZ_ASSERT(aLine->GetChildCount() > pushCount, "bad push");
    4460           0 :     MOZ_ASSERT(nullptr != aFrame, "whoops");
    4461             : #ifdef DEBUG
    4462             :     {
    4463           0 :       nsIFrame *f = aFrame;
    4464           0 :       int32_t count = pushCount;
    4465           0 :       while (f && count > 0) {
    4466           0 :         f = f->GetNextSibling();
    4467           0 :         --count;
    4468             :       }
    4469           0 :       NS_ASSERTION(count == 0, "Not enough frames to push");
    4470             :     }
    4471             : #endif
    4472             : 
    4473             :     // Put frames being split out into their own line
    4474           0 :     nsLineBox* newLine = NewLineBox(aLine, aFrame, pushCount);
    4475           0 :     mLines.after_insert(aLine, newLine);
    4476             : #ifdef DEBUG
    4477           0 :     if (gReallyNoisyReflow) {
    4478           0 :       newLine->List(stdout, gNoiseIndent+1);
    4479             :     }
    4480             : #endif
    4481             : 
    4482             :     // Let line layout know that some frames are no longer part of its
    4483             :     // state.
    4484           0 :     aLineLayout.SplitLineTo(aLine->GetChildCount());
    4485             : 
    4486             :     // If floats have been placed whose placeholders have been pushed to the new
    4487             :     // line, we need to reflow the old line again. We don't want to look at the
    4488             :     // frames in the new line, because as a large paragraph is laid out the
    4489             :     // we'd get O(N^2) performance. So instead we just check that the last
    4490             :     // float and the last below-current-line float are still in aLine.
    4491           0 :     if (!CheckPlaceholderInLine(this, aLine, GetLastFloat(aLine)) ||
    4492           0 :         !CheckPlaceholderInLine(this, aLine, aState.mBelowCurrentLineFloats.Tail())) {
    4493           0 :       *aLineReflowStatus = LineReflowStatus::RedoNoPull;
    4494             :     }
    4495             : 
    4496             : #ifdef DEBUG
    4497           0 :     VerifyLines(true);
    4498             : #endif
    4499             :   }
    4500           9 : }
    4501             : 
    4502             : bool
    4503           0 : nsBlockFrame::IsLastLine(BlockReflowInput& aState,
    4504             :                          LineIterator aLine)
    4505             : {
    4506           0 :   while (++aLine != LinesEnd()) {
    4507             :     // There is another line
    4508           0 :     if (0 != aLine->GetChildCount()) {
    4509             :       // If the next line is a block line then this line is the last in a
    4510             :       // group of inline lines.
    4511           0 :       return aLine->IsBlock();
    4512             :     }
    4513             :     // The next line is empty, try the next one
    4514             :   }
    4515             : 
    4516             :   // XXX Not sure about this part
    4517             :   // Try our next-in-flows lines to answer the question
    4518           0 :   nsBlockFrame* nextInFlow = (nsBlockFrame*) GetNextInFlow();
    4519           0 :   while (nullptr != nextInFlow) {
    4520           0 :     for (LineIterator line = nextInFlow->LinesBegin(),
    4521           0 :                    line_end = nextInFlow->LinesEnd();
    4522             :          line != line_end;
    4523             :          ++line)
    4524             :     {
    4525           0 :       if (0 != line->GetChildCount())
    4526           0 :         return line->IsBlock();
    4527             :     }
    4528           0 :     nextInFlow = (nsBlockFrame*) nextInFlow->GetNextInFlow();
    4529             :   }
    4530             : 
    4531             :   // This is the last line - so don't allow justification
    4532           0 :   return true;
    4533             : }
    4534             : 
    4535             : bool
    4536          75 : nsBlockFrame::PlaceLine(BlockReflowInput& aState,
    4537             :                         nsLineLayout& aLineLayout,
    4538             :                         LineIterator aLine,
    4539             :                         nsFloatManager::SavedState *aFloatStateBeforeLine,
    4540             :                         LogicalRect& aFloatAvailableSpace,
    4541             :                         nscoord& aAvailableSpaceBSize,
    4542             :                         bool* aKeepReflowGoing)
    4543             : {
    4544             :   // Trim extra white-space from the line before placing the frames
    4545          75 :   aLineLayout.TrimTrailingWhiteSpace();
    4546             : 
    4547             :   // Vertically align the frames on this line.
    4548             :   //
    4549             :   // According to the CSS2 spec, section 12.6.1, the "marker" box
    4550             :   // participates in the height calculation of the list-item box's
    4551             :   // first line box.
    4552             :   //
    4553             :   // There are exactly two places a bullet can be placed: near the
    4554             :   // first or second line. It's only placed on the second line in a
    4555             :   // rare case: when the first line is empty.
    4556          75 :   WritingMode wm = aState.mReflowInput.GetWritingMode();
    4557          75 :   bool addedBullet = false;
    4558         225 :   if (HasOutsideBullet() &&
    4559           0 :       ((aLine == mLines.front() &&
    4560           0 :         (!aLineLayout.IsZeroBSize() || (aLine == mLines.back()))) ||
    4561           0 :        (mLines.front() != mLines.back() &&
    4562           0 :         0 == mLines.front()->BSize() &&
    4563          75 :         aLine == mLines.begin().next()))) {
    4564           0 :     ReflowOutput metrics(aState.mReflowInput);
    4565           0 :     nsIFrame* bullet = GetOutsideBullet();
    4566           0 :     ReflowBullet(bullet, aState, metrics, aState.mBCoord);
    4567           0 :     NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0,
    4568             :                  "empty bullet took up space");
    4569           0 :     aLineLayout.AddBulletFrame(bullet, metrics);
    4570           0 :     addedBullet = true;
    4571             :   }
    4572          75 :   aLineLayout.VerticalAlignLine();
    4573             : 
    4574             :   // We want to consider the floats in the current line when determining
    4575             :   // whether the float available space is shrunk. If mLineBSize doesn't
    4576             :   // exist, we are in the first pass trying to place the line. Calling
    4577             :   // GetFloatAvailableSpace() like we did in BlockReflowInput::AddFloat()
    4578             :   // for UpdateBand().
    4579             : 
    4580             :   // floatAvailableSpaceWithOldLineBSize is the float available space with
    4581             :   // the old BSize, but including the floats that were added in this line.
    4582             :   LogicalRect floatAvailableSpaceWithOldLineBSize =
    4583          75 :     aState.mLineBSize.isNothing()
    4584         225 :     ? aState.GetFloatAvailableSpace(aLine->BStart()).mRect
    4585          75 :     : aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
    4586             :                                             aState.mLineBSize.value(),
    4587         225 :                                             nullptr).mRect;
    4588             : 
    4589             :   // As we redo for floats, we can't reduce the amount of BSize we're
    4590             :   // checking.
    4591          75 :   aAvailableSpaceBSize = std::max(aAvailableSpaceBSize, aLine->BSize());
    4592             :   LogicalRect floatAvailableSpaceWithLineBSize =
    4593         150 :     aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
    4594             :                                           aAvailableSpaceBSize,
    4595         150 :                                           nullptr).mRect;
    4596             : 
    4597             :   // If the available space between the floats is smaller now that we
    4598             :   // know the BSize, return false (and cause another pass with
    4599             :   // LineReflowStatus::RedoMoreFloats).  We ensure aAvailableSpaceBSize
    4600             :   // never decreases, which means that we can't reduce the set of floats
    4601             :   // we intersect, which means that the available space cannot grow.
    4602          75 :   if (AvailableSpaceShrunk(wm, floatAvailableSpaceWithOldLineBSize,
    4603             :                            floatAvailableSpaceWithLineBSize, false)) {
    4604             :     // Prepare data for redoing the line.
    4605           0 :     aState.mLineBSize = Some(aLine->BSize());
    4606             : 
    4607             :     // Since we want to redo the line, we update aFloatAvailableSpace by
    4608             :     // using the aFloatStateBeforeLine, which is the float manager's state
    4609             :     // before the line is placed.
    4610           0 :     LogicalRect oldFloatAvailableSpace(aFloatAvailableSpace);
    4611           0 :     aFloatAvailableSpace =
    4612           0 :       aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
    4613             :                                             aAvailableSpaceBSize,
    4614             :                                             aFloatStateBeforeLine).mRect;
    4615           0 :     NS_ASSERTION(aFloatAvailableSpace.BStart(wm) ==
    4616             :                  oldFloatAvailableSpace.BStart(wm), "yikes");
    4617             :     // Restore the BSize to the position of the next band.
    4618           0 :     aFloatAvailableSpace.BSize(wm) = oldFloatAvailableSpace.BSize(wm);
    4619             : 
    4620             :     // Enforce both IStart() and IEnd() never move outwards to prevent
    4621             :     // infinite grow-shrink loops.
    4622             :     const nscoord iStartDiff =
    4623           0 :       aFloatAvailableSpace.IStart(wm) - oldFloatAvailableSpace.IStart(wm);
    4624             :     const nscoord iEndDiff =
    4625           0 :       aFloatAvailableSpace.IEnd(wm) - oldFloatAvailableSpace.IEnd(wm);
    4626           0 :     if (iStartDiff < 0) {
    4627           0 :       aFloatAvailableSpace.IStart(wm) -= iStartDiff;
    4628           0 :       aFloatAvailableSpace.ISize(wm) += iStartDiff;
    4629             :     }
    4630           0 :     if (iEndDiff > 0) {
    4631           0 :       aFloatAvailableSpace.ISize(wm) -= iEndDiff;
    4632             :     }
    4633             : 
    4634           0 :     return false;
    4635             :   }
    4636             : 
    4637             : #ifdef DEBUG
    4638          75 :   if (!GetParent()->IsCrazySizeAssertSuppressed()) {
    4639             :     static nscoord lastHeight = 0;
    4640          75 :     if (CRAZY_SIZE(aLine->BStart())) {
    4641           0 :       lastHeight = aLine->BStart();
    4642           0 :       if (abs(aLine->BStart() - lastHeight) > CRAZY_COORD/10) {
    4643           0 :         nsFrame::ListTag(stdout);
    4644           0 :         printf(": line=%p y=%d line.bounds.height=%d\n",
    4645           0 :                static_cast<void*>(aLine.get()),
    4646           0 :                aLine->BStart(), aLine->BSize());
    4647             :       }
    4648             :     }
    4649             :     else {
    4650          75 :       lastHeight = 0;
    4651             :     }
    4652             :   }
    4653             : #endif
    4654             : 
    4655             :   // Only block frames horizontally align their children because
    4656             :   // inline frames "shrink-wrap" around their children (therefore
    4657             :   // there is no extra horizontal space).
    4658          75 :   const nsStyleText* styleText = StyleText();
    4659             : 
    4660             :   /**
    4661             :    * text-align-last defaults to the same value as text-align when
    4662             :    * text-align-last is set to auto (except when text-align is set to justify),
    4663             :    * so in that case we don't need to set isLastLine.
    4664             :    *
    4665             :    * In other words, isLastLine really means isLastLineAndWeCare.
    4666             :    */
    4667             :   bool isLastLine =
    4668         150 :     !nsSVGUtils::IsInSVGTextSubtree(this) &&
    4669         150 :     ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast ||
    4670          75 :       NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) &&
    4671           0 :      (aLineLayout.GetLineEndsInBR() ||
    4672          75 :       IsLastLine(aState, aLine)));
    4673             : 
    4674          75 :   aLineLayout.TextAlignLine(aLine, isLastLine);
    4675             : 
    4676             :   // From here on, pfd->mBounds rectangles are incorrect because bidi
    4677             :   // might have moved frames around!
    4678         150 :   nsOverflowAreas overflowAreas;
    4679          75 :   aLineLayout.RelativePositionFrames(overflowAreas);
    4680          75 :   aLine->SetOverflowAreas(overflowAreas);
    4681          75 :   if (addedBullet) {
    4682           0 :     aLineLayout.RemoveBulletFrame(GetOutsideBullet());
    4683             :   }
    4684             : 
    4685             :   // Inline lines do not have margins themselves; however they are
    4686             :   // impacted by prior block margins. If this line ends up having some
    4687             :   // height then we zero out the previous block-end margin value that was
    4688             :   // already applied to the line's starting Y coordinate. Otherwise we
    4689             :   // leave it be so that the previous blocks block-end margin can be
    4690             :   // collapsed with a block that follows.
    4691             :   nscoord newBCoord;
    4692             : 
    4693          75 :   if (!aLine->CachedIsEmpty()) {
    4694             :     // This line has some height. Therefore the application of the
    4695             :     // previous-bottom-margin should stick.
    4696          59 :     aState.mPrevBEndMargin.Zero();
    4697          59 :     newBCoord = aLine->BEnd();
    4698             :   }
    4699             :   else {
    4700             :     // Don't let the previous-bottom-margin value affect the newBCoord
    4701             :     // coordinate (it was applied in ReflowInlineFrames speculatively)
    4702             :     // since the line is empty.
    4703             :     // We already called |ShouldApplyBStartMargin|, and if we applied it
    4704             :     // then mShouldApplyBStartMargin is set.
    4705          16 :     nscoord dy = aState.mFlags.mShouldApplyBStartMargin
    4706          16 :                    ? -aState.mPrevBEndMargin.get() : 0;
    4707          16 :     newBCoord = aState.mBCoord + dy;
    4708             :   }
    4709             : 
    4710          75 :   if (!aState.mReflowStatus.IsFullyComplete() &&
    4711           0 :       ShouldAvoidBreakInside(aState.mReflowInput)) {
    4712           0 :     aLine->AppendFloats(aState.mCurrentLineFloats);
    4713           0 :     aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
    4714             :     // Reflow the line again when we reflow at our new position.
    4715           0 :     aLine->MarkDirty();
    4716           0 :     *aKeepReflowGoing = false;
    4717           0 :     return true;
    4718             :   }
    4719             : 
    4720             :   // See if the line fit (our first line always does).
    4721         150 :   if (mLines.front() != aLine &&
    4722          75 :       newBCoord > aState.mBEndEdge &&
    4723           0 :       aState.mBEndEdge != NS_UNCONSTRAINEDSIZE) {
    4724           0 :     NS_ASSERTION(aState.mCurrentLine == aLine, "oops");
    4725           0 :     if (ShouldAvoidBreakInside(aState.mReflowInput)) {
    4726             :       // All our content doesn't fit, start on the next page.
    4727           0 :       aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
    4728           0 :       *aKeepReflowGoing = false;
    4729             :     } else {
    4730             :       // Push aLine and all of its children and anything else that
    4731             :       // follows to our next-in-flow.
    4732           0 :       PushTruncatedLine(aState, aLine, aKeepReflowGoing);
    4733             :     }
    4734           0 :     return true;
    4735             :   }
    4736             : 
    4737             :   // Note that any early return before this update of aState.mBCoord
    4738             :   // must either (a) return false or (b) set aKeepReflowGoing to false.
    4739             :   // Otherwise we'll keep reflowing later lines at an incorrect
    4740             :   // position, and we might not come back and clean up the damage later.
    4741          75 :   aState.mBCoord = newBCoord;
    4742             : 
    4743             :   // Add the already placed current-line floats to the line
    4744          75 :   aLine->AppendFloats(aState.mCurrentLineFloats);
    4745             : 
    4746             :   // Any below current line floats to place?
    4747          75 :   if (aState.mBelowCurrentLineFloats.NotEmpty()) {
    4748             :     // Reflow the below-current-line floats, which places on the line's
    4749             :     // float list.
    4750           0 :     aState.PlaceBelowCurrentLineFloats(aState.mBelowCurrentLineFloats, aLine);
    4751           0 :     aLine->AppendFloats(aState.mBelowCurrentLineFloats);
    4752             :   }
    4753             : 
    4754             :   // When a line has floats, factor them into the combined-area
    4755             :   // computations.
    4756          75 :   if (aLine->HasFloats()) {
    4757             :     // Combine the float combined area (stored in aState) and the
    4758             :     // value computed by the line layout code.
    4759           0 :     nsOverflowAreas lineOverflowAreas;
    4760           0 :     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
    4761           0 :       nsRect &o = lineOverflowAreas.Overflow(otype);
    4762           0 :       o = aLine->GetOverflowArea(otype);
    4763             : #ifdef NOISY_COMBINED_AREA
    4764             :       ListTag(stdout);
    4765             :       printf(": overflow %d lineCA=%d,%d,%d,%d floatCA=%d,%d,%d,%d\n",
    4766             :              otype,
    4767             :              o.x, o.y, o.width, o.height,
    4768             :              aState.mFloatOverflowAreas.Overflow(otype).x,
    4769             :              aState.mFloatOverflowAreas.Overflow(otype).y,
    4770             :              aState.mFloatOverflowAreas.Overflow(otype).width,
    4771             :              aState.mFloatOverflowAreas.Overflow(otype).height);
    4772             : #endif
    4773           0 :       o.UnionRect(aState.mFloatOverflowAreas.Overflow(otype), o);
    4774             : 
    4775             : #ifdef NOISY_COMBINED_AREA
    4776             :       printf("  ==> final lineCA=%d,%d,%d,%d\n",
    4777             :              o.x, o.y, o.width, o.height);
    4778             : #endif
    4779             :     }
    4780           0 :     aLine->SetOverflowAreas(lineOverflowAreas);
    4781             :   }
    4782             : 
    4783             :   // Apply break-after clearing if necessary
    4784             :   // This must stay in sync with |ReflowDirtyLines|.
    4785          75 :   if (aLine->HasFloatBreakAfter()) {
    4786           0 :     aState.mBCoord = aState.ClearFloats(aState.mBCoord, aLine->GetBreakTypeAfter());
    4787             :   }
    4788          75 :   return true;
    4789             : }
    4790             : 
    4791             : void
    4792           0 : nsBlockFrame::PushLines(BlockReflowInput&  aState,
    4793             :                         nsLineList::iterator aLineBefore)
    4794             : {
    4795             :   // NOTE: aLineBefore is always a normal line, not an overflow line.
    4796             :   // The following expression will assert otherwise.
    4797           0 :   DebugOnly<bool> check = aLineBefore == mLines.begin();
    4798             : 
    4799           0 :   nsLineList::iterator overBegin(aLineBefore.next());
    4800             : 
    4801             :   // PushTruncatedPlaceholderLine sometimes pushes the first line.  Ugh.
    4802           0 :   bool firstLine = overBegin == LinesBegin();
    4803             : 
    4804           0 :   if (overBegin != LinesEnd()) {
    4805             :     // Remove floats in the lines from mFloats
    4806           0 :     nsFrameList floats;
    4807           0 :     CollectFloats(overBegin->mFirstChild, floats, true);
    4808             : 
    4809           0 :     if (floats.NotEmpty()) {
    4810             : #ifdef DEBUG
    4811           0 :       for (nsIFrame* f : floats) {
    4812           0 :         MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
    4813             :                    "CollectFloats should've removed that bit");
    4814             :       }
    4815             : #endif
    4816             :       // Push the floats onto the front of the overflow out-of-flows list
    4817           0 :       nsAutoOOFFrameList oofs(this);
    4818           0 :       oofs.mList.InsertFrames(nullptr, nullptr, floats);
    4819             :     }
    4820             : 
    4821             :     // overflow lines can already exist in some cases, in particular,
    4822             :     // when shrinkwrapping and we discover that the shrinkwap causes
    4823             :     // the height of some child block to grow which creates additional
    4824             :     // overflowing content. In such cases we must prepend the new
    4825             :     // overflow to the existing overflow.
    4826           0 :     FrameLines* overflowLines = RemoveOverflowLines();
    4827           0 :     if (!overflowLines) {
    4828             :       // XXXldb use presshell arena!
    4829           0 :       overflowLines = new FrameLines();
    4830             :     }
    4831           0 :     if (overflowLines) {
    4832             :       nsIFrame* lineBeforeLastFrame;
    4833           0 :       if (firstLine) {
    4834           0 :         lineBeforeLastFrame = nullptr; // removes all frames
    4835             :       } else {
    4836           0 :         nsIFrame* f = overBegin->mFirstChild;
    4837           0 :         lineBeforeLastFrame = f ? f->GetPrevSibling() : mFrames.LastChild();
    4838           0 :         NS_ASSERTION(!f || lineBeforeLastFrame == aLineBefore->LastChild(),
    4839             :                      "unexpected line frames");
    4840             :       }
    4841           0 :       nsFrameList pushedFrames = mFrames.RemoveFramesAfter(lineBeforeLastFrame);
    4842           0 :       overflowLines->mFrames.InsertFrames(nullptr, nullptr, pushedFrames);
    4843             : 
    4844           0 :       overflowLines->mLines.splice(overflowLines->mLines.begin(), mLines,
    4845           0 :                                     overBegin, LinesEnd());
    4846           0 :       NS_ASSERTION(!overflowLines->mLines.empty(), "should not be empty");
    4847             :       // this takes ownership but it won't delete it immediately so we
    4848             :       // can keep using it.
    4849           0 :       SetOverflowLines(overflowLines);
    4850             : 
    4851             :       // Mark all the overflow lines dirty so that they get reflowed when
    4852             :       // they are pulled up by our next-in-flow.
    4853             : 
    4854             :       // XXXldb Can this get called O(N) times making the whole thing O(N^2)?
    4855           0 :       for (LineIterator line = overflowLines->mLines.begin(),
    4856           0 :              line_end = overflowLines->mLines.end();
    4857             :            line != line_end;
    4858             :            ++line)
    4859             :       {
    4860           0 :         line->MarkDirty();
    4861           0 :         line->MarkPreviousMarginDirty();
    4862           0 :         line->SetBoundsEmpty();
    4863           0 :         if (line->HasFloats()) {
    4864           0 :           line->FreeFloats(aState.mFloatCacheFreeList);
    4865             :         }
    4866             :       }
    4867             :     }
    4868             :   }
    4869             : 
    4870             : #ifdef DEBUG
    4871           0 :   VerifyOverflowSituation();
    4872             : #endif
    4873           0 : }
    4874             : 
    4875             : // The overflowLines property is stored as a pointer to a line list,
    4876             : // which must be deleted.  However, the following functions all maintain
    4877             : // the invariant that the property is never set if the list is empty.
    4878             : 
    4879             : bool
    4880         162 : nsBlockFrame::DrainOverflowLines()
    4881             : {
    4882             : #ifdef DEBUG
    4883         162 :   VerifyOverflowSituation();
    4884             : #endif
    4885             : 
    4886             :   // Steal the prev-in-flow's overflow lines and prepend them.
    4887         162 :   bool didFindOverflow = false;
    4888         162 :   nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
    4889         162 :   if (prevBlock) {
    4890           0 :     prevBlock->ClearLineCursor();
    4891           0 :     FrameLines* overflowLines = prevBlock->RemoveOverflowLines();
    4892           0 :     if (overflowLines) {
    4893             :       // Make all the frames on the overflow line list mine.
    4894           0 :       ReparentFrames(overflowLines->mFrames, prevBlock, this);
    4895             : 
    4896             :       // Make the overflow out-of-flow frames mine too.
    4897           0 :       nsAutoOOFFrameList oofs(prevBlock);
    4898           0 :       if (oofs.mList.NotEmpty()) {
    4899             :         // In case we own a next-in-flow of any of the drained frames, then
    4900             :         // those are now not PUSHED_FLOATs anymore.
    4901           0 :         for (nsFrameList::Enumerator e(oofs.mList); !e.AtEnd(); e.Next()) {
    4902           0 :           nsIFrame* nif = e.get()->GetNextInFlow();
    4903           0 :           for (; nif && nif->GetParent() == this; nif = nif->GetNextInFlow()) {
    4904           0 :             MOZ_ASSERT(mFloats.ContainsFrame(nif));
    4905           0 :             nif->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
    4906             :           }
    4907             :         }
    4908           0 :         ReparentFrames(oofs.mList, prevBlock, this);
    4909           0 :         mFloats.InsertFrames(nullptr, nullptr, oofs.mList);
    4910             :       }
    4911             : 
    4912           0 :       if (!mLines.empty()) {
    4913             :         // Remember to recompute the margins on the first line. This will
    4914             :         // also recompute the correct deltaBCoord if necessary.
    4915           0 :         mLines.front()->MarkPreviousMarginDirty();
    4916             :       }
    4917             :       // The overflow lines have already been marked dirty and their previous
    4918             :       // margins marked dirty also.
    4919             : 
    4920             :       // Prepend the overflow frames/lines to our principal list.
    4921           0 :       mFrames.InsertFrames(nullptr, nullptr, overflowLines->mFrames);
    4922           0 :       mLines.splice(mLines.begin(), overflowLines->mLines);
    4923           0 :       NS_ASSERTION(overflowLines->mLines.empty(), "splice should empty list");
    4924           0 :       delete overflowLines;
    4925           0 :       didFindOverflow = true;
    4926             :     }
    4927             :   }
    4928             : 
    4929             :   // Now append our own overflow lines.
    4930         162 :   return DrainSelfOverflowList() || didFindOverflow;
    4931             : }
    4932             : 
    4933             : bool
    4934         171 : nsBlockFrame::DrainSelfOverflowList()
    4935             : {
    4936         342 :   UniquePtr<FrameLines> ourOverflowLines(RemoveOverflowLines());
    4937         171 :   if (!ourOverflowLines) {
    4938         171 :     return false;
    4939             :   }
    4940             : 
    4941             :   // No need to reparent frames in our own overflow lines/oofs, because they're
    4942             :   // already ours. But we should put overflow floats back in mFloats.
    4943             :   // (explicit scope to remove the OOF list before VerifyOverflowSituation)
    4944             :   {
    4945           0 :     nsAutoOOFFrameList oofs(this);
    4946           0 :     if (oofs.mList.NotEmpty()) {
    4947             : #ifdef DEBUG
    4948           0 :       for (nsIFrame* f : oofs.mList) {
    4949           0 :         MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
    4950             :                    "CollectFloats should've removed that bit");
    4951             :       }
    4952             : #endif
    4953             :       // The overflow floats go after our regular floats.
    4954           0 :       mFloats.AppendFrames(nullptr, oofs.mList);
    4955             :     }
    4956             :   }
    4957           0 :   if (!ourOverflowLines->mLines.empty()) {
    4958           0 :     mFrames.AppendFrames(nullptr, ourOverflowLines->mFrames);
    4959           0 :     mLines.splice(mLines.end(), ourOverflowLines->mLines);
    4960             :   }
    4961             : 
    4962             : #ifdef DEBUG
    4963           0 :   VerifyOverflowSituation();
    4964             : #endif
    4965           0 :   return true;
    4966             : }
    4967             : 
    4968             : /**
    4969             :  * Pushed floats are floats whose placeholders are in a previous
    4970             :  * continuation.  They might themselves be next-continuations of a float
    4971             :  * that partially fit in an earlier continuation, or they might be the
    4972             :  * first continuation of a float that couldn't be placed at all.
    4973             :  *
    4974             :  * Pushed floats live permanently at the beginning of a block's float
    4975             :  * list, where they must live *before* any floats whose placeholders are
    4976             :  * in that block.
    4977             :  *
    4978             :  * Temporarily, during reflow, they also live on the pushed floats list,
    4979             :  * which only holds them between (a) when one continuation pushes them to
    4980             :  * its pushed floats list because they don't fit and (b) when the next
    4981             :  * continuation pulls them onto the beginning of its float list.
    4982             :  *
    4983             :  * DrainPushedFloats sets up pushed floats the way we need them at the
    4984             :  * start of reflow; they are then reflowed by ReflowPushedFloats (which
    4985             :  * might push some of them on).  Floats with placeholders in this block
    4986             :  * are reflowed by (BlockReflowInput/nsLineLayout)::AddFloat, which
    4987             :  * also maintains these invariants.
    4988             :  *
    4989             :  * DrainSelfPushedFloats moves any pushed floats from this block's own
    4990             :  * PushedFloats list back into mFloats.  DrainPushedFloats additionally
    4991             :  * moves frames from its prev-in-flow's PushedFloats list into mFloats.
    4992             :  */
    4993             : void
    4994         162 : nsBlockFrame::DrainSelfPushedFloats()
    4995             : {
    4996             :   // If we're getting reflowed multiple times without our
    4997             :   // next-continuation being reflowed, we might need to pull back floats
    4998             :   // that we just put in the list to be pushed to our next-in-flow.
    4999             :   // We don't want to pull back any next-in-flows of floats on our own
    5000             :   // float list, and we only need to pull back first-in-flows whose
    5001             :   // placeholders were in earlier blocks (since first-in-flows whose
    5002             :   // placeholders are in this block will get pulled appropriately by
    5003             :   // AddFloat, and will then be more likely to be in the correct order).
    5004             :   // FIXME: What if there's a continuation in our pushed floats list
    5005             :   // whose prev-in-flow is in a previous continuation of this block
    5006             :   // rather than this block?  Might we need to pull it back so we don't
    5007             :   // report ourselves complete?
    5008             :   // FIXME: Maybe we should just pull all of them back?
    5009         162 :   nsPresContext* presContext = PresContext();
    5010         162 :   nsFrameList* ourPushedFloats = GetPushedFloats();
    5011         162 :   if (ourPushedFloats) {
    5012             :     // When we pull back floats, we want to put them with the pushed
    5013             :     // floats, which must live at the start of our float list, but we
    5014             :     // want them at the end of those pushed floats.
    5015             :     // FIXME: This isn't quite right!  What if they're all pushed floats?
    5016           0 :     nsIFrame *insertionPrevSibling = nullptr; /* beginning of list */
    5017           0 :     for (nsIFrame* f = mFloats.FirstChild();
    5018           0 :          f && (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT);
    5019             :          f = f->GetNextSibling()) {
    5020           0 :       insertionPrevSibling = f;
    5021             :     }
    5022             : 
    5023           0 :     for (nsIFrame *f = ourPushedFloats->LastChild(), *next; f; f = next) {
    5024           0 :       next = f->GetPrevSibling();
    5025             : 
    5026           0 :       if (f->GetPrevContinuation()) {
    5027             :         // FIXME
    5028             :       } else {
    5029           0 :         nsPlaceholderFrame* placeholder = f->GetPlaceholderFrame();
    5030             :         nsIFrame* floatOriginalParent = presContext->PresShell()->
    5031           0 :           FrameConstructor()->GetFloatContainingBlock(placeholder);
    5032           0 :         if (floatOriginalParent != this) {
    5033             :           // This is a first continuation that was pushed from one of our
    5034             :           // previous continuations.  Take it out of the pushed floats
    5035             :           // list and put it in our floats list, before any of our
    5036             :           // floats, but after other pushed floats.
    5037           0 :           ourPushedFloats->RemoveFrame(f);
    5038           0 :           mFloats.InsertFrame(nullptr, insertionPrevSibling, f);
    5039             :         }
    5040             :       }
    5041             :     }
    5042             : 
    5043           0 :     if (ourPushedFloats->IsEmpty()) {
    5044           0 :       RemovePushedFloats()->Delete(presContext->PresShell());
    5045             :     }
    5046             :   }
    5047         162 : }
    5048             : 
    5049             : void
    5050         162 : nsBlockFrame::DrainPushedFloats()
    5051             : {
    5052         162 :   DrainSelfPushedFloats();
    5053             : 
    5054             :   // After our prev-in-flow has completed reflow, it may have a pushed
    5055             :   // floats list, containing floats that we need to own.  Take these.
    5056         162 :   nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
    5057         162 :   if (prevBlock) {
    5058           0 :     AutoFrameListPtr list(PresContext(), prevBlock->RemovePushedFloats());
    5059           0 :     if (list && list->NotEmpty()) {
    5060           0 :       mFloats.InsertFrames(this, nullptr, *list);
    5061             :     }
    5062             :   }
    5063         162 : }
    5064             : 
    5065             : nsBlockFrame::FrameLines*
    5066         768 : nsBlockFrame::GetOverflowLines() const
    5067             : {
    5068         768 :   if (!HasOverflowLines()) {
    5069         768 :     return nullptr;
    5070             :   }
    5071           0 :   FrameLines* prop = GetProperty(OverflowLinesProperty());
    5072           0 :   NS_ASSERTION(prop && !prop->mLines.empty() &&
    5073             :                prop->mLines.front()->GetChildCount() == 0 ? prop->mFrames.IsEmpty() :
    5074             :                  prop->mLines.front()->mFirstChild == prop->mFrames.FirstChild(),
    5075             :                "value should always be stored and non-empty when state set");
    5076           0 :   return prop;
    5077             : }
    5078             : 
    5079             : nsBlockFrame::FrameLines*
    5080         181 : nsBlockFrame::RemoveOverflowLines()
    5081             : {
    5082         181 :   if (!HasOverflowLines()) {
    5083         181 :     return nullptr;
    5084             :   }
    5085           0 :   FrameLines* prop = RemoveProperty(OverflowLinesProperty());
    5086           0 :   NS_ASSERTION(prop && !prop->mLines.empty() &&
    5087             :                prop->mLines.front()->GetChildCount() == 0 ? prop->mFrames.IsEmpty() :
    5088             :                  prop->mLines.front()->mFirstChild == prop->mFrames.FirstChild(),
    5089             :                "value should always be stored and non-empty when state set");
    5090           0 :   RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
    5091           0 :   return prop;
    5092             : }
    5093             : 
    5094             : void
    5095           0 : nsBlockFrame::DestroyOverflowLines()
    5096             : {
    5097           0 :   NS_ASSERTION(HasOverflowLines(), "huh?");
    5098           0 :   FrameLines* prop = RemoveProperty(OverflowLinesProperty());
    5099           0 :   NS_ASSERTION(prop && prop->mLines.empty(),
    5100             :                "value should always be stored but empty when destroying");
    5101           0 :   RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
    5102           0 :   delete prop;
    5103           0 : }
    5104             : 
    5105             : // This takes ownership of aOverflowLines.
    5106             : // XXX We should allocate overflowLines from presShell arena!
    5107             : void
    5108           0 : nsBlockFrame::SetOverflowLines(FrameLines* aOverflowLines)
    5109             : {
    5110           0 :   NS_ASSERTION(aOverflowLines, "null lines");
    5111           0 :   NS_ASSERTION(!aOverflowLines->mLines.empty(), "empty lines");
    5112           0 :   NS_ASSERTION(aOverflowLines->mLines.front()->mFirstChild ==
    5113             :                aOverflowLines->mFrames.FirstChild(),
    5114             :                "invalid overflow lines / frames");
    5115           0 :   NS_ASSERTION(!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES),
    5116             :                "Overwriting existing overflow lines");
    5117             : 
    5118             :   // Verify that we won't overwrite an existing overflow list
    5119           0 :   NS_ASSERTION(!GetProperty(OverflowLinesProperty()), "existing overflow list");
    5120           0 :   SetProperty(OverflowLinesProperty(), aOverflowLines);
    5121           0 :   AddStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
    5122           0 : }
    5123             : 
    5124             : nsFrameList*
    5125         834 : nsBlockFrame::GetOverflowOutOfFlows() const
    5126             : {
    5127         834 :   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)) {
    5128         834 :     return nullptr;
    5129             :   }
    5130             :   nsFrameList* result =
    5131           0 :     GetPropTableFrames(OverflowOutOfFlowsProperty());
    5132           0 :   NS_ASSERTION(result, "value should always be non-empty when state set");
    5133           0 :   return result;
    5134             : }
    5135             : 
    5136             : // This takes ownership of the frames
    5137             : void
    5138           0 : nsBlockFrame::SetOverflowOutOfFlows(const nsFrameList& aList,
    5139             :                                     nsFrameList* aPropValue)
    5140             : {
    5141           0 :   NS_PRECONDITION(!!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) ==
    5142             :                   !!aPropValue, "state does not match value");
    5143             : 
    5144           0 :   if (aList.IsEmpty()) {
    5145           0 :     if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)) {
    5146           0 :       return;
    5147             :     }
    5148           0 :     nsFrameList* list = RemovePropTableFrames(OverflowOutOfFlowsProperty());
    5149           0 :     NS_ASSERTION(aPropValue == list, "prop value mismatch");
    5150           0 :     list->Clear();
    5151           0 :     list->Delete(PresContext()->PresShell());
    5152           0 :     RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
    5153             :   }
    5154           0 :   else if (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) {
    5155           0 :     NS_ASSERTION(aPropValue == GetPropTableFrames(OverflowOutOfFlowsProperty()),
    5156             :                  "prop value mismatch");
    5157           0 :     *aPropValue = aList;
    5158             :   }
    5159             :   else {
    5160           0 :     SetPropTableFrames(new (PresContext()->PresShell()) nsFrameList(aList),
    5161           0 :                        OverflowOutOfFlowsProperty());
    5162           0 :     AddStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
    5163             :   }
    5164             : }
    5165             : 
    5166             : nsBulletFrame*
    5167           0 : nsBlockFrame::GetInsideBullet() const
    5168             : {
    5169           0 :   if (!HasInsideBullet()) {
    5170           0 :     return nullptr;
    5171             :   }
    5172           0 :   NS_ASSERTION(!HasOutsideBullet(), "invalid bullet state");
    5173           0 :   nsBulletFrame* frame = GetProperty(InsideBulletProperty());
    5174           0 :   NS_ASSERTION(frame && frame->IsBulletFrame(), "bogus inside bullet frame");
    5175           0 :   return frame;
    5176             : }
    5177             : 
    5178             : nsBulletFrame*
    5179         170 : nsBlockFrame::GetOutsideBullet() const
    5180             : {
    5181         170 :   nsFrameList* list = GetOutsideBulletList();
    5182         170 :   return list ? static_cast<nsBulletFrame*>(list->FirstChild())
    5183         170 :               : nullptr;
    5184             : }
    5185             : 
    5186             : nsFrameList*
    5187         512 : nsBlockFrame::GetOutsideBulletList() const
    5188             : {
    5189         512 :   if (!HasOutsideBullet()) {
    5190         512 :     return nullptr;
    5191             :   }
    5192           0 :   NS_ASSERTION(!HasInsideBullet(), "invalid bullet state");
    5193           0 :   nsFrameList* list = GetProperty(OutsideBulletProperty());
    5194           0 :   NS_ASSERTION(list && list->GetLength() == 1 &&
    5195             :                list->FirstChild()->IsBulletFrame(),
    5196             :                "bogus outside bullet list");
    5197           0 :   return list;
    5198             : }
    5199             : 
    5200             : nsFrameList*
    5201        1164 : nsBlockFrame::GetPushedFloats() const
    5202             : {
    5203        1164 :   if (!HasPushedFloats()) {
    5204        1164 :     return nullptr;
    5205             :   }
    5206           0 :   nsFrameList* result = GetProperty(PushedFloatProperty());
    5207           0 :   NS_ASSERTION(result, "value should always be non-empty when state set");
    5208           0 :   return result;
    5209             : }
    5210             : 
    5211             : nsFrameList*
    5212           0 : nsBlockFrame::EnsurePushedFloats()
    5213             : {
    5214           0 :   nsFrameList *result = GetPushedFloats();
    5215           0 :   if (result)
    5216           0 :     return result;
    5217             : 
    5218           0 :   result = new (PresContext()->PresShell()) nsFrameList;
    5219           0 :   SetProperty(PushedFloatProperty(), result);
    5220           0 :   AddStateBits(NS_BLOCK_HAS_PUSHED_FLOATS);
    5221             : 
    5222           0 :   return result;
    5223             : }
    5224             : 
    5225             : nsFrameList*
    5226           0 : nsBlockFrame::RemovePushedFloats()
    5227             : {
    5228           0 :   if (!HasPushedFloats()) {
    5229           0 :     return nullptr;
    5230             :   }
    5231           0 :   nsFrameList *result = RemoveProperty(PushedFloatProperty());
    5232           0 :   RemoveStateBits(NS_BLOCK_HAS_PUSHED_FLOATS);
    5233           0 :   NS_ASSERTION(result, "value should always be non-empty when state set");
    5234           0 :   return result;
    5235             : }
    5236             : 
    5237             : //////////////////////////////////////////////////////////////////////
    5238             : // Frame list manipulation routines
    5239             : 
    5240             : void
    5241           0 : nsBlockFrame::AppendFrames(ChildListID  aListID,
    5242             :                            nsFrameList& aFrameList)
    5243             : {
    5244           0 :   if (aFrameList.IsEmpty()) {
    5245           0 :     return;
    5246             :   }
    5247           0 :   if (aListID != kPrincipalList) {
    5248           0 :     if (kFloatList == aListID) {
    5249           0 :       DrainSelfPushedFloats(); // ensure the last frame is in mFloats
    5250           0 :       mFloats.AppendFrames(nullptr, aFrameList);
    5251           0 :       return;
    5252             :     }
    5253           0 :     MOZ_ASSERT(kNoReflowPrincipalList == aListID, "unexpected child list");
    5254             :   }
    5255             : 
    5256             :   // Find the proper last-child for where the append should go
    5257           0 :   nsIFrame* lastKid = mFrames.LastChild();
    5258           0 :   NS_ASSERTION((mLines.empty() ? nullptr : mLines.back()->LastChild()) ==
    5259             :                lastKid, "out-of-sync mLines / mFrames");
    5260             : 
    5261             : #ifdef NOISY_REFLOW_REASON
    5262             :   ListTag(stdout);
    5263             :   printf(": append ");
    5264             :   nsFrame::ListTag(stdout, aFrameList);
    5265             :   if (lastKid) {
    5266             :     printf(" after ");
    5267             :     nsFrame::ListTag(stdout, lastKid);
    5268             :   }
    5269             :   printf("\n");
    5270             : #endif
    5271             : 
    5272           0 :   AddFrames(aFrameList, lastKid);
    5273           0 :   if (aListID != kNoReflowPrincipalList) {
    5274           0 :     PresContext()->PresShell()->
    5275           0 :       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    5276           0 :                        NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
    5277             :   }
    5278             : }
    5279             : 
    5280             : void
    5281           8 : nsBlockFrame::InsertFrames(ChildListID aListID,
    5282             :                            nsIFrame* aPrevFrame,
    5283             :                            nsFrameList& aFrameList)
    5284             : {
    5285           8 :   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
    5286             :                "inserting after sibling frame with different parent");
    5287             : 
    5288           8 :   if (aListID != kPrincipalList) {
    5289           0 :     if (kFloatList == aListID) {
    5290           0 :       DrainSelfPushedFloats(); // ensure aPrevFrame is in mFloats
    5291           0 :       mFloats.InsertFrames(this, aPrevFrame, aFrameList);
    5292           0 :       return;
    5293             :     }
    5294           0 :     MOZ_ASSERT(kNoReflowPrincipalList == aListID, "unexpected child list");
    5295             :   }
    5296             : 
    5297             : #ifdef NOISY_REFLOW_REASON
    5298             :   ListTag(stdout);
    5299             :   printf(": insert ");
    5300             :   nsFrame::ListTag(stdout, aFrameList);
    5301             :   if (aPrevFrame) {
    5302             :     printf(" after ");
    5303             :     nsFrame::ListTag(stdout, aPrevFrame);
    5304             :   }
    5305             :   printf("\n");
    5306             : #endif
    5307             : 
    5308           8 :   AddFrames(aFrameList, aPrevFrame);
    5309           8 :   if (aListID != kNoReflowPrincipalList) {
    5310           8 :     PresContext()->PresShell()->
    5311           8 :       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    5312          16 :                        NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
    5313             :   }
    5314             : }
    5315             : 
    5316             : void
    5317           6 : nsBlockFrame::RemoveFrame(ChildListID aListID,
    5318             :                           nsIFrame* aOldFrame)
    5319             : {
    5320             : #ifdef NOISY_REFLOW_REASON
    5321             :   ListTag(stdout);
    5322             :   printf(": remove ");
    5323             :   nsFrame::ListTag(stdout, aOldFrame);
    5324             :   printf("\n");
    5325             : #endif
    5326             : 
    5327           6 :   if (aListID == kPrincipalList) {
    5328           6 :     bool hasFloats = BlockHasAnyFloats(aOldFrame);
    5329           6 :     DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
    5330           6 :     if (hasFloats) {
    5331           0 :       MarkSameFloatManagerLinesDirty(this);
    5332             :     }
    5333             :   }
    5334           0 :   else if (kFloatList == aListID) {
    5335             :     // Make sure to mark affected lines dirty for the float frame
    5336             :     // we are removing; this way is a bit messy, but so is the rest of the code.
    5337             :     // See bug 390762.
    5338           0 :     NS_ASSERTION(!aOldFrame->GetPrevContinuation(),
    5339             :                  "RemoveFrame should not be called on pushed floats.");
    5340           0 :     for (nsIFrame* f = aOldFrame;
    5341           0 :          f && !(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
    5342           0 :          f = f->GetNextContinuation()) {
    5343           0 :       MarkSameFloatManagerLinesDirty(static_cast<nsBlockFrame*>(f->GetParent()));
    5344             :     }
    5345           0 :     DoRemoveOutOfFlowFrame(aOldFrame);
    5346             :   }
    5347           0 :   else if (kNoReflowPrincipalList == aListID) {
    5348             :     // Skip the call to |FrameNeedsReflow| below by returning now.
    5349           0 :     DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
    5350           0 :     return;
    5351             :   }
    5352             :   else {
    5353           0 :     MOZ_CRASH("unexpected child list");
    5354             :   }
    5355             : 
    5356           6 :   PresContext()->PresShell()->
    5357           6 :     FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    5358          12 :                      NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
    5359             : }
    5360             : 
    5361             : static bool
    5362           0 : ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
    5363             : {
    5364           0 :   LayoutFrameType type = aLastFrame->Type();
    5365           0 :   if (type == LayoutFrameType::Br) {
    5366           0 :     return true;
    5367             :   }
    5368             :   // XXX the TEXT_OFFSETS_NEED_FIXING check is a wallpaper for bug 822910.
    5369           0 :   if (type == LayoutFrameType::Text &&
    5370           0 :       !(aLastFrame->GetStateBits() & TEXT_OFFSETS_NEED_FIXING)) {
    5371           0 :     return aLastFrame->HasSignificantTerminalNewline();
    5372             :   }
    5373           0 :   return false;
    5374             : }
    5375             : 
    5376             : void
    5377          42 : nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling)
    5378             : {
    5379             :   // Clear our line cursor, since our lines may change.
    5380          42 :   ClearLineCursor();
    5381             : 
    5382          42 :   if (aFrameList.IsEmpty()) {
    5383           9 :     return;
    5384             :   }
    5385             : 
    5386             :   // If we're inserting at the beginning of our list and we have an
    5387             :   // inside bullet, insert after that bullet.
    5388          33 :   if (!aPrevSibling && HasInsideBullet()) {
    5389           0 :     aPrevSibling = GetInsideBullet();
    5390             :   }
    5391             : 
    5392             :   // Attempt to find the line that contains the previous sibling
    5393          33 :   nsLineList* lineList = &mLines;
    5394          33 :   nsFrameList* frames = &mFrames;
    5395          33 :   nsLineList::iterator prevSibLine = lineList->end();
    5396          33 :   int32_t prevSiblingIndex = -1;
    5397          33 :   if (aPrevSibling) {
    5398             :     // XXX_perf This is technically O(N^2) in some cases, but by using
    5399             :     // RFind instead of Find, we make it O(N) in the most common case,
    5400             :     // which is appending content.
    5401             : 
    5402             :     // Find the line that contains the previous sibling
    5403           0 :     if (!nsLineBox::RFindLineContaining(aPrevSibling, lineList->begin(),
    5404             :                                         prevSibLine, mFrames.LastChild(),
    5405             :                                         &prevSiblingIndex)) {
    5406             :       // Not in mLines - try overflow lines.
    5407           0 :       FrameLines* overflowLines = GetOverflowLines();
    5408           0 :       bool found = false;
    5409           0 :       if (overflowLines) {
    5410           0 :         prevSibLine = overflowLines->mLines.end();
    5411           0 :         prevSiblingIndex = -1;
    5412           0 :         found = nsLineBox::RFindLineContaining(aPrevSibling,
    5413           0 :                                                overflowLines->mLines.begin(),
    5414             :                                                prevSibLine,
    5415             :                                                overflowLines->mFrames.LastChild(),
    5416           0 :                                                &prevSiblingIndex);
    5417             :       }
    5418           0 :       if (MOZ_LIKELY(found)) {
    5419           0 :         lineList = &overflowLines->mLines;
    5420           0 :         frames = &overflowLines->mFrames;
    5421             :       } else {
    5422             :         // Note: defensive code! RFindLineContaining must not return
    5423             :         // false in this case, so if it does...
    5424           0 :         MOZ_ASSERT_UNREACHABLE("prev sibling not in line list");
    5425             :         aPrevSibling = nullptr;
    5426             :         prevSibLine = lineList->end();
    5427             :       }
    5428             :     }
    5429             :   }
    5430             : 
    5431             :   // Find the frame following aPrevSibling so that we can join up the
    5432             :   // two lists of frames.
    5433          33 :   if (aPrevSibling) {
    5434             :     // Split line containing aPrevSibling in two if the insertion
    5435             :     // point is somewhere in the middle of the line.
    5436           0 :     int32_t rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
    5437           0 :     if (rem) {
    5438             :       // Split the line in two where the frame(s) are being inserted.
    5439           0 :       nsLineBox* line = NewLineBox(prevSibLine, aPrevSibling->GetNextSibling(), rem);
    5440           0 :       lineList->after_insert(prevSibLine, line);
    5441             :       // Mark prevSibLine dirty and as needing textrun invalidation, since
    5442             :       // we may be breaking up text in the line. Its previous line may also
    5443             :       // need to be invalidated because it may be able to pull some text up.
    5444           0 :       MarkLineDirty(prevSibLine, lineList);
    5445             :       // The new line will also need its textruns recomputed because of the
    5446             :       // frame changes.
    5447           0 :       line->MarkDirty();
    5448           0 :       line->SetInvalidateTextRuns(true);
    5449             :     }
    5450             :   }
    5451          33 :   else if (! lineList->empty()) {
    5452           0 :     lineList->front()->MarkDirty();
    5453           0 :     lineList->front()->SetInvalidateTextRuns(true);
    5454             :   }
    5455             :   const nsFrameList::Slice& newFrames =
    5456          33 :     frames->InsertFrames(nullptr, aPrevSibling, aFrameList);
    5457             : 
    5458             :   // Walk through the new frames being added and update the line data
    5459             :   // structures to fit.
    5460          66 :   for (nsFrameList::Enumerator e(newFrames); !e.AtEnd(); e.Next()) {
    5461          33 :     nsIFrame* newFrame = e.get();
    5462          33 :     NS_ASSERTION(!aPrevSibling || aPrevSibling->GetNextSibling() == newFrame,
    5463             :                  "Unexpected aPrevSibling");
    5464          33 :     NS_ASSERTION(!newFrame->IsPlaceholderFrame() ||
    5465             :                  (!newFrame->IsAbsolutelyPositioned() &&
    5466             :                   !newFrame->IsFloating()),
    5467             :                  "Placeholders should not float or be positioned");
    5468             : 
    5469          33 :     bool isBlock = newFrame->IsBlockOutside();
    5470             : 
    5471             :     // If the frame is a block frame, or if there is no previous line or if the
    5472             :     // previous line is a block line we need to make a new line.  We also make
    5473             :     // a new line, as an optimization, in the two cases we know we'll need it:
    5474             :     // if the previous line ended with a <br>, or if it has significant whitespace
    5475             :     // and ended in a newline.
    5476          66 :     if (isBlock || prevSibLine == lineList->end() || prevSibLine->IsBlock() ||
    5477           0 :         (aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) {
    5478             :       // Create a new line for the frame and add its line to the line
    5479             :       // list.
    5480          33 :       nsLineBox* line = NewLineBox(newFrame, isBlock);
    5481          33 :       if (prevSibLine != lineList->end()) {
    5482             :         // Append new line after prevSibLine
    5483           0 :         lineList->after_insert(prevSibLine, line);
    5484           0 :         ++prevSibLine;
    5485             :       }
    5486             :       else {
    5487             :         // New line is going before the other lines
    5488          33 :         lineList->push_front(line);
    5489          33 :         prevSibLine = lineList->begin();
    5490             :       }
    5491             :     }
    5492             :     else {
    5493           0 :       prevSibLine->NoteFrameAdded(newFrame);
    5494             :       // We're adding inline content to prevSibLine, so we need to mark it
    5495             :       // dirty, ensure its textruns are recomputed, and possibly do the same
    5496             :       // to its previous line since that line may be able to pull content up.
    5497           0 :       MarkLineDirty(prevSibLine, lineList);
    5498             :     }
    5499             : 
    5500          33 :     aPrevSibling = newFrame;
    5501             :   }
    5502             : 
    5503             : #ifdef DEBUG
    5504          33 :   MOZ_ASSERT(aFrameList.IsEmpty());
    5505          33 :   VerifyLines(true);
    5506             : #endif
    5507             : }
    5508             : 
    5509             : void
    5510           0 : nsBlockFrame::RemoveFloatFromFloatCache(nsIFrame* aFloat)
    5511             : {
    5512             :   // Find which line contains the float, so we can update
    5513             :   // the float cache.
    5514           0 :   LineIterator line = LinesBegin(), line_end = LinesEnd();
    5515           0 :   for ( ; line != line_end; ++line) {
    5516           0 :     if (line->IsInline() && line->RemoveFloat(aFloat)) {
    5517           0 :       break;
    5518             :     }
    5519             :   }
    5520           0 : }
    5521             : 
    5522             : void
    5523           0 : nsBlockFrame::RemoveFloat(nsIFrame* aFloat)
    5524             : {
    5525             : #ifdef DEBUG
    5526             :   // Floats live in mFloats, or in the PushedFloat or OverflowOutOfFlows
    5527             :   // frame list properties.
    5528           0 :   if (!mFloats.ContainsFrame(aFloat)) {
    5529           0 :     MOZ_ASSERT((GetOverflowOutOfFlows() &&
    5530             :                 GetOverflowOutOfFlows()->ContainsFrame(aFloat)) ||
    5531             :                (GetPushedFloats() &&
    5532             :                 GetPushedFloats()->ContainsFrame(aFloat)),
    5533             :                "aFloat is not our child or on an unexpected frame list");
    5534             :   }
    5535             : #endif
    5536             : 
    5537           0 :   if (mFloats.StartRemoveFrame(aFloat)) {
    5538           0 :     return;
    5539             :   }
    5540             : 
    5541           0 :   nsFrameList* list = GetPushedFloats();
    5542           0 :   if (list && list->ContinueRemoveFrame(aFloat)) {
    5543             : #if 0
    5544             :     // XXXmats not yet - need to investigate BlockReflowInput::mPushedFloats
    5545             :     // first so we don't leave it pointing to a deleted list.
    5546             :     if (list->IsEmpty()) {
    5547             :       delete RemovePushedFloats();
    5548             :     }
    5549             : #endif
    5550           0 :     return;
    5551             :   }
    5552             : 
    5553             :   {
    5554           0 :     nsAutoOOFFrameList oofs(this);
    5555           0 :     if (oofs.mList.ContinueRemoveFrame(aFloat)) {
    5556           0 :       return;
    5557             :     }
    5558             :   }
    5559             : }
    5560             : 
    5561             : void
    5562           0 : nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
    5563             : {
    5564             :   // The containing block is always the parent of aFrame.
    5565           0 :   nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent();
    5566             : 
    5567             :   // Remove aFrame from the appropriate list.
    5568           0 :   if (aFrame->IsAbsolutelyPositioned()) {
    5569             :     // This also deletes the next-in-flows
    5570           0 :     block->GetAbsoluteContainingBlock()->RemoveFrame(block,
    5571             :                                                      kAbsoluteList,
    5572           0 :                                                      aFrame);
    5573             :   }
    5574             :   else {
    5575             :     // First remove aFrame's next-in-flows.
    5576           0 :     nsIFrame* nif = aFrame->GetNextInFlow();
    5577           0 :     if (nif) {
    5578           0 :       nif->GetParent()->DeleteNextInFlowChild(nif, false);
    5579             :     }
    5580             :     // Now remove aFrame from its child list and Destroy it.
    5581           0 :     block->RemoveFloatFromFloatCache(aFrame);
    5582           0 :     block->RemoveFloat(aFrame);
    5583           0 :     aFrame->Destroy();
    5584             :   }
    5585           0 : }
    5586             : 
    5587             : /**
    5588             :  * This helps us iterate over the list of all normal + overflow lines
    5589             :  */
    5590             : void
    5591           6 : nsBlockFrame::TryAllLines(nsLineList::iterator* aIterator,
    5592             :                           nsLineList::iterator* aStartIterator,
    5593             :                           nsLineList::iterator* aEndIterator,
    5594             :                           bool* aInOverflowLines,
    5595             :                           FrameLines** aOverflowLines)
    5596             : {
    5597           6 :   if (*aIterator == *aEndIterator) {
    5598           0 :     if (!*aInOverflowLines) {
    5599             :       // Try the overflow lines
    5600           0 :       *aInOverflowLines = true;
    5601           0 :       FrameLines* lines = GetOverflowLines();
    5602           0 :       if (lines) {
    5603           0 :         *aStartIterator = lines->mLines.begin();
    5604           0 :         *aIterator = *aStartIterator;
    5605           0 :         *aEndIterator = lines->mLines.end();
    5606           0 :         *aOverflowLines = lines;
    5607             :       }
    5608             :     }
    5609             :   }
    5610           6 : }
    5611             : 
    5612          21 : nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
    5613          21 :     LineIterator aLine)
    5614          21 :   : mFrame(aFrame), mLine(aLine), mLineList(&aFrame->mLines)
    5615             : {
    5616             :   // This will assert if aLine isn't in mLines of aFrame:
    5617          21 :   DebugOnly<bool> check = aLine == mFrame->LinesBegin();
    5618          21 : }
    5619             : 
    5620           0 : nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
    5621           0 :     LineIterator aLine, bool aInOverflow)
    5622             :   : mFrame(aFrame), mLine(aLine),
    5623           0 :     mLineList(aInOverflow ? &aFrame->GetOverflowLines()->mLines
    5624           0 :                           : &aFrame->mLines)
    5625             : {
    5626           0 : }
    5627             : 
    5628          21 : nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
    5629          21 :     bool* aFoundValidLine)
    5630          21 :   : mFrame(aFrame), mLineList(&aFrame->mLines)
    5631             : {
    5632          21 :   mLine = aFrame->LinesBegin();
    5633          21 :   *aFoundValidLine = FindValidLine();
    5634          21 : }
    5635             : 
    5636             : void
    5637           0 : nsBlockFrame::UpdateFirstLetterStyle(ServoRestyleState& aRestyleState)
    5638             : {
    5639           0 :   nsIFrame* letterFrame = GetFirstLetter();
    5640           0 :   if (!letterFrame) {
    5641           0 :     return;
    5642             :   }
    5643             : 
    5644             :   // Figure out what the right style parent is.  This needs to match
    5645             :   // nsCSSFrameConstructor::CreateLetterFrame.
    5646           0 :   nsIFrame* inFlowFrame = letterFrame;
    5647           0 :   if (inFlowFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
    5648           0 :     inFlowFrame = inFlowFrame->GetPlaceholderFrame();
    5649             :   }
    5650             :   nsIFrame* styleParent =
    5651           0 :     CorrectStyleParentFrame(inFlowFrame->GetParent(),
    5652           0 :                             nsCSSPseudoElements::firstLetter);
    5653           0 :   nsStyleContext* parentStyle = styleParent->StyleContext();
    5654             :   RefPtr<nsStyleContext> firstLetterStyle =
    5655           0 :     aRestyleState.StyleSet()
    5656           0 :                  .ResolvePseudoElementStyle(mContent->AsElement(),
    5657             :                                             CSSPseudoElementType::firstLetter,
    5658             :                                             parentStyle,
    5659           0 :                                             nullptr);
    5660             :   // Note that we don't need to worry about changehints for the continuation
    5661             :   // styles: those will be handled by the styleParent already.
    5662             :   RefPtr<nsStyleContext> continuationStyle =
    5663           0 :     aRestyleState.StyleSet().ResolveStyleForFirstLetterContinuation(parentStyle);
    5664           0 :   UpdateStyleOfOwnedChildFrame(letterFrame, firstLetterStyle, aRestyleState,
    5665           0 :                                Some(continuationStyle.get()));
    5666             : 
    5667             :   // We also want to update the style on the textframe inside the first-letter.
    5668             :   // We don't need to compute a changehint for this, though, since any changes
    5669             :   // to it are handled by the first-letter anyway.
    5670           0 :   nsIFrame* textFrame = letterFrame->PrincipalChildList().FirstChild();
    5671             :   RefPtr<nsStyleContext> firstTextStyle =
    5672           0 :     aRestyleState.StyleSet().ResolveStyleForText(textFrame->GetContent(),
    5673           0 :                                                  firstLetterStyle);
    5674           0 :   textFrame->SetStyleContext(firstTextStyle);
    5675             : 
    5676             :   // We don't need to update style for textFrame's continuations: it's already
    5677             :   // set up to inherit from parentStyle, which is what we want.
    5678             : }
    5679             : 
    5680             : static nsIFrame*
    5681           6 : FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
    5682             : {
    5683           6 :   NS_ASSERTION(aFrame, "must have frame");
    5684             :   nsIFrame* child;
    5685             :   while (true) {
    5686           6 :     nsIFrame* block = aFrame;
    5687           0 :     do {
    5688           6 :       child = nsLayoutUtils::FindChildContainingDescendant(block, aFindFrame);
    5689           6 :       if (child)
    5690           6 :         break;
    5691           0 :       block = block->GetNextContinuation();
    5692           0 :     } while (block);
    5693           6 :     if (!child)
    5694           0 :       return nullptr;
    5695           6 :     if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
    5696           6 :       break;
    5697           0 :     aFindFrame = child->GetPlaceholderFrame();
    5698           0 :   }
    5699             : 
    5700           6 :   return child;
    5701             : }
    5702             : 
    5703           6 : nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
    5704           6 :     nsIFrame* aFindFrame, bool* aFoundValidLine)
    5705           6 :   : mFrame(aFrame), mLineList(&aFrame->mLines)
    5706             : {
    5707           6 :   *aFoundValidLine = false;
    5708             : 
    5709           6 :   nsIFrame* child = FindChildContaining(aFrame, aFindFrame);
    5710           6 :   if (!child)
    5711           6 :     return;
    5712             : 
    5713           6 :   LineIterator line_end = aFrame->LinesEnd();
    5714           6 :   mLine = aFrame->LinesBegin();
    5715          12 :   if (mLine != line_end && mLine.next() == line_end &&
    5716           6 :       !aFrame->HasOverflowLines()) {
    5717             :     // The block has a single line - that must be it!
    5718           6 :     *aFoundValidLine = true;
    5719           6 :     return;
    5720             :   }
    5721             : 
    5722             :   // Try to use the cursor if it exists, otherwise fall back to the first line
    5723           0 :   if (nsLineBox* const cursor = aFrame->GetLineCursor()) {
    5724           0 :     mLine = line_end;
    5725             :     // Perform a simultaneous forward and reverse search starting from the
    5726             :     // line cursor.
    5727           0 :     nsBlockFrame::LineIterator line = aFrame->LinesBeginFrom(cursor);
    5728           0 :     nsBlockFrame::ReverseLineIterator rline = aFrame->LinesRBeginFrom(cursor);
    5729           0 :     nsBlockFrame::ReverseLineIterator rline_end = aFrame->LinesREnd();
    5730             :     // rline is positioned on the line containing 'cursor', so it's not
    5731             :     // rline_end. So we can safely increment it (i.e. move it to one line
    5732             :     // earlier) to start searching there.
    5733           0 :     ++rline;
    5734           0 :     while (line != line_end || rline != rline_end) {
    5735           0 :       if (line != line_end) {
    5736           0 :         if (line->Contains(child)) {
    5737           0 :           mLine = line;
    5738           0 :           break;
    5739             :         }
    5740           0 :         ++line;
    5741             :       }
    5742           0 :       if (rline != rline_end) {
    5743           0 :         if (rline->Contains(child)) {
    5744           0 :           mLine = rline;
    5745           0 :           break;
    5746             :         }
    5747           0 :         ++rline;
    5748             :       }
    5749             :     }
    5750           0 :     if (mLine != line_end) {
    5751           0 :       *aFoundValidLine = true;
    5752           0 :       if (mLine != cursor) {
    5753           0 :         aFrame->SetProperty(nsBlockFrame::LineCursorProperty(), mLine);
    5754             :       }
    5755           0 :       return;
    5756             :     }
    5757             :   } else {
    5758           0 :     for (mLine = aFrame->LinesBegin(); mLine != line_end; ++mLine) {
    5759           0 :       if (mLine->Contains(child)) {
    5760           0 :         *aFoundValidLine = true;
    5761           0 :         return;
    5762             :       }
    5763             :     }
    5764             :   }
    5765             :   // Didn't find the line
    5766           0 :   MOZ_ASSERT(mLine == line_end, "mLine should be line_end at this point");
    5767             : 
    5768             :   // If we reach here, it means that we have not been able to find the
    5769             :   // desired frame in our in-flow lines.  So we should start looking at
    5770             :   // our overflow lines. In order to do that, we set mLine to the end
    5771             :   // iterator so that FindValidLine starts to look at overflow lines,
    5772             :   // if any.
    5773             : 
    5774           0 :   if (!FindValidLine())
    5775           0 :     return;
    5776             : 
    5777           0 :   do {
    5778           0 :     if (mLine->Contains(child)) {
    5779           0 :       *aFoundValidLine = true;
    5780           0 :       return;
    5781             :     }
    5782             :   } while (Next());
    5783             : }
    5784             : 
    5785             : nsBlockFrame::LineIterator
    5786           0 : nsBlockInFlowLineIterator::End()
    5787             : {
    5788           0 :   return mLineList->end();
    5789             : }
    5790             : 
    5791             : bool
    5792           0 : nsBlockInFlowLineIterator::IsLastLineInList()
    5793             : {
    5794           0 :   LineIterator end = End();
    5795           0 :   return mLine != end && mLine.next() == end;
    5796             : }
    5797             : 
    5798             : bool
    5799          21 : nsBlockInFlowLineIterator::Next()
    5800             : {
    5801          21 :   ++mLine;
    5802          21 :   return FindValidLine();
    5803             : }
    5804             : 
    5805             : bool
    5806          21 : nsBlockInFlowLineIterator::Prev()
    5807             : {
    5808          21 :   LineIterator begin = mLineList->begin();
    5809          21 :   if (mLine != begin) {
    5810           0 :     --mLine;
    5811           0 :     return true;
    5812             :   }
    5813          21 :   bool currentlyInOverflowLines = GetInOverflow();
    5814             :   while (true) {
    5815          21 :     if (currentlyInOverflowLines) {
    5816           0 :       mLineList = &mFrame->mLines;
    5817           0 :       mLine = mLineList->end();
    5818           0 :       if (mLine != mLineList->begin()) {
    5819           0 :         --mLine;
    5820           0 :         return true;
    5821             :       }
    5822             :     } else {
    5823          21 :       mFrame = static_cast<nsBlockFrame*>(mFrame->GetPrevInFlow());
    5824          21 :       if (!mFrame)
    5825          21 :         return false;
    5826           0 :       nsBlockFrame::FrameLines* overflowLines = mFrame->GetOverflowLines();
    5827           0 :       if (overflowLines) {
    5828           0 :         mLineList = &overflowLines->mLines;
    5829           0 :         mLine = mLineList->end();
    5830           0 :         NS_ASSERTION(mLine != mLineList->begin(), "empty overflow line list?");
    5831           0 :         --mLine;
    5832           0 :         return true;
    5833             :       }
    5834             :     }
    5835           0 :     currentlyInOverflowLines = !currentlyInOverflowLines;
    5836           0 :   }
    5837             : }
    5838             : 
    5839             : bool
    5840          42 : nsBlockInFlowLineIterator::FindValidLine()
    5841             : {
    5842          42 :   LineIterator end = mLineList->end();
    5843          42 :   if (mLine != end)
    5844          21 :     return true;
    5845          21 :   bool currentlyInOverflowLines = GetInOverflow();
    5846             :   while (true) {
    5847          42 :     if (currentlyInOverflowLines) {
    5848          21 :       mFrame = static_cast<nsBlockFrame*>(mFrame->GetNextInFlow());
    5849          21 :       if (!mFrame)
    5850          21 :         return false;
    5851           0 :       mLineList = &mFrame->mLines;
    5852           0 :       mLine = mLineList->begin();
    5853           0 :       if (mLine != mLineList->end())
    5854           0 :         return true;
    5855             :     } else {
    5856          21 :       nsBlockFrame::FrameLines* overflowLines = mFrame->GetOverflowLines();
    5857          21 :       if (overflowLines) {
    5858           0 :         mLineList = &overflowLines->mLines;
    5859           0 :         mLine = mLineList->begin();
    5860           0 :         NS_ASSERTION(mLine != mLineList->end(), "empty overflow line list?");
    5861           0 :         return true;
    5862             :       }
    5863             :     }
    5864          21 :     currentlyInOverflowLines = !currentlyInOverflowLines;
    5865          21 :   }
    5866             : }
    5867             : 
    5868           6 : static void RemoveBlockChild(nsIFrame* aFrame,
    5869             :                              bool      aRemoveOnlyFluidContinuations)
    5870             : {
    5871           6 :   if (!aFrame) {
    5872           6 :     return;
    5873             :   }
    5874           0 :   nsBlockFrame* nextBlock = nsLayoutUtils::GetAsBlock(aFrame->GetParent());
    5875           0 :   NS_ASSERTION(nextBlock,
    5876             :                "Our child's continuation's parent is not a block?");
    5877           0 :   nextBlock->DoRemoveFrame(aFrame,
    5878           0 :       (aRemoveOnlyFluidContinuations ? 0 : nsBlockFrame::REMOVE_FIXED_CONTINUATIONS));
    5879             : }
    5880             : 
    5881             : // This function removes aDeletedFrame and all its continuations.  It
    5882             : // is optimized for deleting a whole series of frames. The easy
    5883             : // implementation would invoke itself recursively on
    5884             : // aDeletedFrame->GetNextContinuation, then locate the line containing
    5885             : // aDeletedFrame and remove aDeletedFrame from that line. But here we
    5886             : // start by locating aDeletedFrame and then scanning from that point
    5887             : // on looking for continuations.
    5888             : void
    5889           6 : nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags)
    5890             : {
    5891             :   // Clear our line cursor, since our lines may change.
    5892           6 :   ClearLineCursor();
    5893             : 
    5894           6 :   if (aDeletedFrame->GetStateBits() &
    5895             :       (NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER)) {
    5896           0 :     if (!aDeletedFrame->GetPrevInFlow()) {
    5897           0 :       NS_ASSERTION(aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
    5898             :                    "Expected out-of-flow frame");
    5899           0 :       DoRemoveOutOfFlowFrame(aDeletedFrame);
    5900             :     }
    5901             :     else {
    5902           0 :       nsContainerFrame::DeleteNextInFlowChild(aDeletedFrame,
    5903           0 :                                               (aFlags & FRAMES_ARE_EMPTY) != 0);
    5904             :     }
    5905           0 :     return;
    5906             :   }
    5907             : 
    5908             :   // Find the line that contains deletedFrame
    5909           6 :   nsLineList::iterator line_start = mLines.begin(),
    5910           6 :                        line_end = mLines.end();
    5911           6 :   nsLineList::iterator line = line_start;
    5912           6 :   FrameLines* overflowLines = nullptr;
    5913           6 :   bool searchingOverflowList = false;
    5914             :   // Make sure we look in the overflow lines even if the normal line
    5915             :   // list is empty
    5916             :   TryAllLines(&line, &line_start, &line_end, &searchingOverflowList,
    5917           6 :               &overflowLines);
    5918           6 :   while (line != line_end) {
    5919           6 :     if (line->Contains(aDeletedFrame)) {
    5920           6 :       break;
    5921             :     }
    5922           0 :     ++line;
    5923             :     TryAllLines(&line, &line_start, &line_end, &searchingOverflowList,
    5924           0 :                 &overflowLines);
    5925             :   }
    5926             : 
    5927           6 :   if (line == line_end) {
    5928           0 :     NS_ERROR("can't find deleted frame in lines");
    5929           0 :     return;
    5930             :   }
    5931             : 
    5932           6 :   if (!(aFlags & FRAMES_ARE_EMPTY)) {
    5933           6 :     if (line != line_start) {
    5934           0 :       line.prev()->MarkDirty();
    5935           0 :       line.prev()->SetInvalidateTextRuns(true);
    5936             :     }
    5937           6 :     else if (searchingOverflowList && !mLines.empty()) {
    5938           0 :       mLines.back()->MarkDirty();
    5939           0 :       mLines.back()->SetInvalidateTextRuns(true);
    5940             :     }
    5941             :   }
    5942             : 
    5943          18 :   while (line != line_end && aDeletedFrame) {
    5944           6 :     NS_ASSERTION(this == aDeletedFrame->GetParent(), "messed up delete code");
    5945           6 :     NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line");
    5946             : 
    5947           6 :     if (!(aFlags & FRAMES_ARE_EMPTY)) {
    5948           6 :       line->MarkDirty();
    5949           6 :       line->SetInvalidateTextRuns(true);
    5950             :     }
    5951             : 
    5952             :     // If the frame being deleted is the last one on the line then
    5953             :     // optimize away the line->Contains(next-in-flow) call below.
    5954           6 :     bool isLastFrameOnLine = 1 == line->GetChildCount();
    5955           6 :     if (!isLastFrameOnLine) {
    5956           0 :       LineIterator next = line.next();
    5957           0 :       nsIFrame* lastFrame = next != line_end ?
    5958           0 :         next->mFirstChild->GetPrevSibling() :
    5959           0 :         (searchingOverflowList ? overflowLines->mFrames.LastChild() :
    5960           0 :                                  mFrames.LastChild());
    5961           0 :       NS_ASSERTION(next == line_end || lastFrame == line->LastChild(),
    5962             :                    "unexpected line frames");
    5963           0 :       isLastFrameOnLine = lastFrame == aDeletedFrame;
    5964             :     }
    5965             : 
    5966             :     // Remove aDeletedFrame from the line
    5967           6 :     if (line->mFirstChild == aDeletedFrame) {
    5968             :       // We should be setting this to null if aDeletedFrame
    5969             :       // is the only frame on the line. HOWEVER in that case
    5970             :       // we will be removing the line anyway, see below.
    5971           6 :       line->mFirstChild = aDeletedFrame->GetNextSibling();
    5972             :     }
    5973             : 
    5974             :     // Hmm, this won't do anything if we're removing a frame in the first
    5975             :     // overflow line... Hopefully doesn't matter
    5976           6 :     --line;
    5977           6 :     if (line != line_end && !line->IsBlock()) {
    5978             :       // Since we just removed a frame that follows some inline
    5979             :       // frames, we need to reflow the previous line.
    5980           0 :       line->MarkDirty();
    5981             :     }
    5982           6 :     ++line;
    5983             : 
    5984             :     // Take aDeletedFrame out of the sibling list. Note that
    5985             :     // prevSibling will only be nullptr when we are deleting the very
    5986             :     // first frame in the main or overflow list.
    5987           6 :     if (searchingOverflowList) {
    5988           0 :       overflowLines->mFrames.RemoveFrame(aDeletedFrame);
    5989             :     } else {
    5990           6 :       mFrames.RemoveFrame(aDeletedFrame);
    5991             :     }
    5992             : 
    5993             :     // Update the child count of the line to be accurate
    5994           6 :     line->NoteFrameRemoved(aDeletedFrame);
    5995             : 
    5996             :     // Destroy frame; capture its next continuation first in case we need
    5997             :     // to destroy that too.
    5998          12 :     nsIFrame* deletedNextContinuation = (aFlags & REMOVE_FIXED_CONTINUATIONS) ?
    5999          12 :         aDeletedFrame->GetNextContinuation() : aDeletedFrame->GetNextInFlow();
    6000             : #ifdef NOISY_REMOVE_FRAME
    6001             :     printf("DoRemoveFrame: %s line=%p frame=",
    6002             :            searchingOverflowList?"overflow":"normal", line.get());
    6003             :     nsFrame::ListTag(stdout, aDeletedFrame);
    6004             :     printf(" prevSibling=%p deletedNextContinuation=%p\n",
    6005             :            aDeletedFrame->GetPrevSibling(), deletedNextContinuation);
    6006             : #endif
    6007             : 
    6008             :     // If next-in-flow is an overflow container, must remove it first.
    6009           6 :     if (deletedNextContinuation &&
    6010           0 :         deletedNextContinuation->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
    6011           0 :       deletedNextContinuation->GetParent()->
    6012           0 :         DeleteNextInFlowChild(deletedNextContinuation, false);
    6013           0 :       deletedNextContinuation = nullptr;
    6014             :     }
    6015             : 
    6016           6 :     aDeletedFrame->Destroy();
    6017           6 :     aDeletedFrame = deletedNextContinuation;
    6018             : 
    6019           6 :     bool haveAdvancedToNextLine = false;
    6020             :     // If line is empty, remove it now.
    6021           6 :     if (0 == line->GetChildCount()) {
    6022             : #ifdef NOISY_REMOVE_FRAME
    6023             :         printf("DoRemoveFrame: %s line=%p became empty so it will be removed\n",
    6024             :                searchingOverflowList?"overflow":"normal", line.get());
    6025             : #endif
    6026           6 :       nsLineBox *cur = line;
    6027           6 :       if (!searchingOverflowList) {
    6028           6 :         line = mLines.erase(line);
    6029             :         // Invalidate the space taken up by the line.
    6030             :         // XXX We need to do this if we're removing a frame as a result of
    6031             :         // a call to RemoveFrame(), but we may not need to do this in all
    6032             :         // cases...
    6033             : #ifdef NOISY_BLOCK_INVALIDATE
    6034             :         nsRect visOverflow(cur->GetVisualOverflowArea());
    6035             :         printf("%p invalidate 10 (%d, %d, %d, %d)\n",
    6036             :                this, visOverflow.x, visOverflow.y,
    6037             :                visOverflow.width, visOverflow.height);
    6038             : #endif
    6039             :       } else {
    6040           0 :         line = overflowLines->mLines.erase(line);
    6041           0 :         if (overflowLines->mLines.empty()) {
    6042           0 :           DestroyOverflowLines();
    6043           0 :           overflowLines = nullptr;
    6044             :           // We just invalidated our iterators.  Since we were in
    6045             :           // the overflow lines list, which is now empty, set them
    6046             :           // so we're at the end of the regular line list.
    6047           0 :           line_start = mLines.begin();
    6048           0 :           line_end = mLines.end();
    6049           0 :           line = line_end;
    6050             :         }
    6051             :       }
    6052           6 :       FreeLineBox(cur);
    6053             : 
    6054             :       // If we're removing a line, ReflowDirtyLines isn't going to
    6055             :       // know that it needs to slide lines unless something is marked
    6056             :       // dirty.  So mark the previous margin of the next line dirty if
    6057             :       // there is one.
    6058           6 :       if (line != line_end) {
    6059           0 :         line->MarkPreviousMarginDirty();
    6060             :       }
    6061           6 :       haveAdvancedToNextLine = true;
    6062             :     } else {
    6063             :       // Make the line that just lost a frame dirty, and advance to
    6064             :       // the next line.
    6065           0 :       if (!deletedNextContinuation || isLastFrameOnLine ||
    6066           0 :           !line->Contains(deletedNextContinuation)) {
    6067           0 :         line->MarkDirty();
    6068           0 :         ++line;
    6069           0 :         haveAdvancedToNextLine = true;
    6070             :       }
    6071             :     }
    6072             : 
    6073           6 :     if (deletedNextContinuation) {
    6074             :       // See if we should keep looking in the current flow's line list.
    6075           0 :       if (deletedNextContinuation->GetParent() != this) {
    6076             :         // The deceased frames continuation is not a child of the
    6077             :         // current block. So break out of the loop so that we advance
    6078             :         // to the next parent.
    6079             :         //
    6080             :         // If we have a continuation in a different block then all bets are
    6081             :         // off regarding whether we are deleting frames without actual content,
    6082             :         // so don't propagate FRAMES_ARE_EMPTY any further.
    6083           0 :         aFlags &= ~FRAMES_ARE_EMPTY;
    6084           0 :         break;
    6085             :       }
    6086             : 
    6087             :       // If we advanced to the next line then check if we should switch to the
    6088             :       // overflow line list.
    6089           0 :       if (haveAdvancedToNextLine) {
    6090           0 :         if (line != line_end && !searchingOverflowList &&
    6091           0 :             !line->Contains(deletedNextContinuation)) {
    6092             :           // We have advanced to the next *normal* line but the next-in-flow
    6093             :           // is not there - force a switch to the overflow line list.
    6094           0 :           line = line_end;
    6095             :         }
    6096             : 
    6097             :         TryAllLines(&line, &line_start, &line_end, &searchingOverflowList,
    6098           0 :                     &overflowLines);
    6099             : #ifdef NOISY_REMOVE_FRAME
    6100             :         printf("DoRemoveFrame: now on %s line=%p\n",
    6101             :                searchingOverflowList?"overflow":"normal", line.get());
    6102             : #endif
    6103             :       }
    6104             :     }
    6105             :   }
    6106             : 
    6107           6 :   if (!(aFlags & FRAMES_ARE_EMPTY) && line.next() != line_end) {
    6108           0 :     line.next()->MarkDirty();
    6109           0 :     line.next()->SetInvalidateTextRuns(true);
    6110             :   }
    6111             : 
    6112             : #ifdef DEBUG
    6113           6 :   VerifyLines(true);
    6114           6 :   VerifyOverflowSituation();
    6115             : #endif
    6116             : 
    6117             :   // Advance to next flow block if the frame has more continuations
    6118           6 :   RemoveBlockChild(aDeletedFrame, !(aFlags & REMOVE_FIXED_CONTINUATIONS));
    6119             : }
    6120             : 
    6121             : static bool
    6122           0 : FindBlockLineFor(nsIFrame*             aChild,
    6123             :                  nsLineList::iterator  aBegin,
    6124             :                  nsLineList::iterator  aEnd,
    6125             :                  nsLineList::iterator* aResult)
    6126             : {
    6127           0 :   MOZ_ASSERT(aChild->IsBlockOutside());
    6128           0 :   for (nsLineList::iterator line = aBegin; line != aEnd; ++line) {
    6129           0 :     MOZ_ASSERT(line->GetChildCount() > 0);
    6130           0 :     if (line->IsBlock() && line->mFirstChild == aChild) {
    6131           0 :       MOZ_ASSERT(line->GetChildCount() == 1);
    6132           0 :       *aResult = line;
    6133           0 :       return true;
    6134             :     }
    6135             :   }
    6136           0 :   return false;
    6137             : }
    6138             : 
    6139             : static bool
    6140           0 : FindInlineLineFor(nsIFrame*             aChild,
    6141             :                   const nsFrameList&    aFrameList,
    6142             :                   nsLineList::iterator  aBegin,
    6143             :                   nsLineList::iterator  aEnd,
    6144             :                   nsLineList::iterator* aResult)
    6145             : {
    6146           0 :   MOZ_ASSERT(!aChild->IsBlockOutside());
    6147           0 :   for (nsLineList::iterator line = aBegin; line != aEnd; ++line) {
    6148           0 :     MOZ_ASSERT(line->GetChildCount() > 0);
    6149           0 :     if (!line->IsBlock()) {
    6150             :       // Optimize by comparing the line's last child first.
    6151           0 :       nsLineList::iterator next = line.next();
    6152           0 :       if (aChild == (next == aEnd ? aFrameList.LastChild()
    6153           0 :                                   : next->mFirstChild->GetPrevSibling()) ||
    6154           0 :           line->Contains(aChild)) {
    6155           0 :         *aResult = line;
    6156           0 :         return true;
    6157             :       }
    6158             :     }
    6159             :   }
    6160           0 :   return false;
    6161             : }
    6162             : 
    6163             : static bool
    6164           0 : FindLineFor(nsIFrame*             aChild,
    6165             :             const nsFrameList&    aFrameList,
    6166             :             nsLineList::iterator  aBegin,
    6167             :             nsLineList::iterator  aEnd,
    6168             :             nsLineList::iterator* aResult)
    6169             : {
    6170           0 :   return aChild->IsBlockOutside() ?
    6171             :     FindBlockLineFor(aChild, aBegin, aEnd, aResult) :
    6172           0 :     FindInlineLineFor(aChild, aFrameList, aBegin, aEnd, aResult);
    6173             : }
    6174             : 
    6175             : nsresult
    6176           0 : nsBlockFrame::StealFrame(nsIFrame* aChild)
    6177             : {
    6178           0 :   MOZ_ASSERT(aChild->GetParent() == this);
    6179             : 
    6180           0 :   if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
    6181           0 :       aChild->IsFloating()) {
    6182           0 :     RemoveFloat(aChild);
    6183           0 :     return NS_OK;
    6184             :   }
    6185             : 
    6186           0 :   if (MaybeStealOverflowContainerFrame(aChild)) {
    6187           0 :     return NS_OK;
    6188             :   }
    6189             : 
    6190           0 :   MOZ_ASSERT(!(aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW));
    6191             : 
    6192           0 :   nsLineList::iterator line;
    6193           0 :   if (FindLineFor(aChild, mFrames, mLines.begin(), mLines.end(), &line)) {
    6194           0 :     RemoveFrameFromLine(aChild, line, mFrames, mLines);
    6195             :   } else {
    6196           0 :     FrameLines* overflowLines = GetOverflowLines();
    6197           0 :     DebugOnly<bool> found;
    6198           0 :     found = FindLineFor(aChild, overflowLines->mFrames,
    6199             :                         overflowLines->mLines.begin(),
    6200           0 :                         overflowLines->mLines.end(), &line);
    6201           0 :     MOZ_ASSERT(found);
    6202           0 :     RemoveFrameFromLine(aChild, line, overflowLines->mFrames,
    6203           0 :                         overflowLines->mLines);
    6204           0 :     if (overflowLines->mLines.empty()) {
    6205           0 :       DestroyOverflowLines();
    6206             :     }
    6207             :   }
    6208             : 
    6209           0 :   return NS_OK;
    6210             : }
    6211             : 
    6212             : void
    6213           0 : nsBlockFrame::RemoveFrameFromLine(nsIFrame* aChild, nsLineList::iterator aLine,
    6214             :                                   nsFrameList& aFrameList, nsLineList& aLineList)
    6215             : {
    6216           0 :   aFrameList.RemoveFrame(aChild);
    6217           0 :   if (aChild == aLine->mFirstChild) {
    6218           0 :     aLine->mFirstChild = aChild->GetNextSibling();
    6219             :   }
    6220           0 :   aLine->NoteFrameRemoved(aChild);
    6221           0 :   if (aLine->GetChildCount() > 0) {
    6222           0 :     aLine->MarkDirty();
    6223             :   } else {
    6224             :     // The line became empty - destroy it.
    6225           0 :     nsLineBox* lineBox = aLine;
    6226           0 :     aLine = aLineList.erase(aLine);
    6227           0 :     if (aLine != aLineList.end()) {
    6228           0 :       aLine->MarkPreviousMarginDirty();
    6229             :     }
    6230           0 :     FreeLineBox(lineBox);
    6231             :   }
    6232           0 : }
    6233             : 
    6234             : void
    6235           0 : nsBlockFrame::DeleteNextInFlowChild(nsIFrame* aNextInFlow,
    6236             :                                     bool      aDeletingEmptyFrames)
    6237             : {
    6238           0 :   NS_PRECONDITION(aNextInFlow->GetPrevInFlow(), "bad next-in-flow");
    6239             : 
    6240           0 :   if (aNextInFlow->GetStateBits() &
    6241             :       (NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER)) {
    6242           0 :     nsContainerFrame::DeleteNextInFlowChild(aNextInFlow, aDeletingEmptyFrames);
    6243             :   }
    6244             :   else {
    6245             : #ifdef DEBUG
    6246           0 :     if (aDeletingEmptyFrames) {
    6247           0 :       nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
    6248             :     }
    6249             : #endif
    6250           0 :     DoRemoveFrame(aNextInFlow,
    6251           0 :         aDeletingEmptyFrames ? FRAMES_ARE_EMPTY : 0);
    6252             :   }
    6253           0 : }
    6254             : 
    6255             : const nsStyleText*
    6256          75 : nsBlockFrame::StyleTextForLineLayout()
    6257             : {
    6258             :   // Return the pointer to an unmodified style text
    6259          75 :   return StyleText();
    6260             : }
    6261             : 
    6262             : ////////////////////////////////////////////////////////////////////////
    6263             : // Float support
    6264             : 
    6265             : LogicalRect
    6266           0 : nsBlockFrame::AdjustFloatAvailableSpace(BlockReflowInput& aState,
    6267             :                                         const LogicalRect& aFloatAvailableSpace,
    6268             :                                         nsIFrame* aFloatFrame)
    6269             : {
    6270             :   // Compute the available inline size. By default, assume the inline
    6271             :   // size of the containing block.
    6272             :   nscoord availISize;
    6273           0 :   const nsStyleDisplay* floatDisplay = aFloatFrame->StyleDisplay();
    6274           0 :   WritingMode wm = aState.mReflowInput.GetWritingMode();
    6275             : 
    6276           0 :   if (mozilla::StyleDisplay::Table != floatDisplay->mDisplay ||
    6277           0 :       eCompatibility_NavQuirks != aState.mPresContext->CompatibilityMode() ) {
    6278           0 :     availISize = aState.ContentISize();
    6279             :   }
    6280             :   else {
    6281             :     // This quirk matches the one in BlockReflowInput::FlowAndPlaceFloat
    6282             :     // give tables only the available space
    6283             :     // if they can shrink we may not be constrained to place
    6284             :     // them in the next line
    6285           0 :     availISize = aFloatAvailableSpace.ISize(wm);
    6286             :   }
    6287             : 
    6288           0 :   nscoord availBSize = NS_UNCONSTRAINEDSIZE == aState.ContentBSize()
    6289           0 :                        ? NS_UNCONSTRAINEDSIZE
    6290           0 :                        : std::max(0, aState.ContentBEnd() - aState.mBCoord);
    6291             : 
    6292           0 :   if (availBSize != NS_UNCONSTRAINEDSIZE &&
    6293           0 :       !aState.mFlags.mFloatFragmentsInsideColumnEnabled &&
    6294           0 :       nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::ColumnSet)) {
    6295             :     // Tell the float it has unrestricted block-size, so it won't break.
    6296             :     // If the float doesn't actually fit in the column it will fail to be
    6297             :     // placed, and either move to the block-start of the next column or just
    6298             :     // overflow.
    6299           0 :     availBSize = NS_UNCONSTRAINEDSIZE;
    6300             :   }
    6301             : 
    6302             :   return LogicalRect(wm, aState.ContentIStart(), aState.ContentBStart(),
    6303           0 :                      availISize, availBSize);
    6304             : }
    6305             : 
    6306             : nscoord
    6307           0 : nsBlockFrame::ComputeFloatISize(BlockReflowInput& aState,
    6308             :                                 const LogicalRect&  aFloatAvailableSpace,
    6309             :                                 nsIFrame*           aFloat)
    6310             : {
    6311           0 :   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
    6312             :                   "aFloat must be an out-of-flow frame");
    6313             :   // Reflow the float.
    6314             :   LogicalRect availSpace = AdjustFloatAvailableSpace(aState,
    6315             :                                                      aFloatAvailableSpace,
    6316           0 :                                                      aFloat);
    6317             : 
    6318           0 :   WritingMode blockWM = aState.mReflowInput.GetWritingMode();
    6319           0 :   WritingMode floatWM = aFloat->GetWritingMode();
    6320             :   ReflowInput
    6321             :     floatRS(aState.mPresContext, aState.mReflowInput, aFloat,
    6322           0 :             availSpace.Size(blockWM).ConvertTo(floatWM, blockWM));
    6323             : 
    6324           0 :   return floatRS.ComputedSizeWithMarginBorderPadding(blockWM).ISize(blockWM);
    6325             : }
    6326             : 
    6327             : void
    6328           0 : nsBlockFrame::ReflowFloat(BlockReflowInput& aState,
    6329             :                           const LogicalRect&  aAdjustedAvailableSpace,
    6330             :                           nsIFrame*           aFloat,
    6331             :                           LogicalMargin&      aFloatMargin,
    6332             :                           LogicalMargin&      aFloatOffsets,
    6333             :                           bool                aFloatPushedDown,
    6334             :                           nsReflowStatus&     aReflowStatus)
    6335             : {
    6336           0 :   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
    6337             :                   "aFloat must be an out-of-flow frame");
    6338             :   // Reflow the float.
    6339           0 :   aReflowStatus.Reset();
    6340             : 
    6341           0 :   WritingMode wm = aState.mReflowInput.GetWritingMode();
    6342             : #ifdef NOISY_FLOAT
    6343             :   printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n",
    6344             :          aFloat, this,
    6345             :          aAdjustedAvailableSpace.IStart(wm), aAdjustedAvailableSpace.BStart(wm),
    6346             :          aAdjustedAvailableSpace.ISize(wm), aAdjustedAvailableSpace.BSize(wm)
    6347             :   );
    6348             : #endif
    6349             : 
    6350             :   ReflowInput
    6351             :     floatRS(aState.mPresContext, aState.mReflowInput, aFloat,
    6352           0 :             aAdjustedAvailableSpace.Size(wm).ConvertTo(aFloat->GetWritingMode(),
    6353           0 :                                                        wm));
    6354             : 
    6355             :   // Normally the mIsTopOfPage state is copied from the parent reflow
    6356             :   // state.  However, when reflowing a float, if we've placed other
    6357             :   // floats that force this float *down* or *narrower*, we should unset
    6358             :   // the mIsTopOfPage state.
    6359             :   // FIXME: This is somewhat redundant with the |isAdjacentWithTop|
    6360             :   // variable below, which has the exact same effect.  Perhaps it should
    6361             :   // be merged into that, except that the test for narrowing here is not
    6362             :   // about adjacency with the top, so it seems misleading.
    6363           0 :   if (floatRS.mFlags.mIsTopOfPage &&
    6364           0 :       (aFloatPushedDown ||
    6365           0 :        aAdjustedAvailableSpace.ISize(wm) != aState.ContentISize())) {
    6366           0 :     floatRS.mFlags.mIsTopOfPage = false;
    6367             :   }
    6368             : 
    6369             :   // Setup a block reflow context to reflow the float.
    6370           0 :   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowInput);
    6371             : 
    6372             :   // Reflow the float
    6373           0 :   bool isAdjacentWithTop = aState.IsAdjacentWithTop();
    6374             : 
    6375           0 :   nsIFrame* clearanceFrame = nullptr;
    6376           0 :   do {
    6377           0 :     nsCollapsingMargin margin;
    6378           0 :     bool mayNeedRetry = false;
    6379           0 :     floatRS.mDiscoveredClearance = nullptr;
    6380             :     // Only first in flow gets a block-start margin.
    6381           0 :     if (!aFloat->GetPrevInFlow()) {
    6382             :       brc.ComputeCollapsedBStartMargin(floatRS, &margin,
    6383             :                                        clearanceFrame,
    6384           0 :                                        &mayNeedRetry);
    6385             : 
    6386           0 :       if (mayNeedRetry && !clearanceFrame) {
    6387           0 :         floatRS.mDiscoveredClearance = &clearanceFrame;
    6388             :         // We don't need to push the float manager state because the the block has its own
    6389             :         // float manager that will be destroyed and recreated
    6390             :       }
    6391             :     }
    6392             : 
    6393           0 :     brc.ReflowBlock(aAdjustedAvailableSpace, true, margin,
    6394             :                     0, isAdjacentWithTop,
    6395             :                     nullptr, floatRS,
    6396           0 :                     aReflowStatus, aState);
    6397           0 :   } while (clearanceFrame);
    6398             : 
    6399           0 :   if (!aReflowStatus.IsFullyComplete() &&
    6400           0 :       ShouldAvoidBreakInside(floatRS)) {
    6401           0 :     aReflowStatus.SetInlineLineBreakBeforeAndReset();
    6402           0 :   } else if (aReflowStatus.IsIncomplete() &&
    6403           0 :              (NS_UNCONSTRAINEDSIZE == aAdjustedAvailableSpace.BSize(wm))) {
    6404             :     // An incomplete reflow status means we should split the float
    6405             :     // if the height is constrained (bug 145305).
    6406           0 :     aReflowStatus.Reset();
    6407             :   }
    6408             : 
    6409           0 :   if (aReflowStatus.NextInFlowNeedsReflow()) {
    6410           0 :     aState.mReflowStatus.SetNextInFlowNeedsReflow();
    6411             :   }
    6412             : 
    6413           0 :   if (aFloat->IsLetterFrame()) {
    6414             :     // We never split floating first letters; an incomplete state for
    6415             :     // such frames simply means that there is more content to be
    6416             :     // reflowed on the line.
    6417           0 :     if (aReflowStatus.IsIncomplete())
    6418           0 :       aReflowStatus.Reset();
    6419             :   }
    6420             : 
    6421             :   // Capture the margin and offsets information for the caller
    6422           0 :   aFloatMargin =
    6423             :     // float margins don't collapse
    6424           0 :     floatRS.ComputedLogicalMargin().ConvertTo(wm, floatRS.GetWritingMode());
    6425           0 :   aFloatOffsets =
    6426           0 :     floatRS.ComputedLogicalOffsets().ConvertTo(wm, floatRS.GetWritingMode());
    6427             : 
    6428           0 :   const ReflowOutput& metrics = brc.GetMetrics();
    6429             : 
    6430             :   // Set the rect, make sure the view is properly sized and positioned,
    6431             :   // and tell the frame we're done reflowing it
    6432             :   // XXXldb This seems like the wrong place to be doing this -- shouldn't
    6433             :   // we be doing this in BlockReflowInput::FlowAndPlaceFloat after
    6434             :   // we've positioned the float, and shouldn't we be doing the equivalent
    6435             :   // of |PlaceFrameView| here?
    6436           0 :   WritingMode metricsWM = metrics.GetWritingMode();
    6437           0 :   aFloat->SetSize(metricsWM, metrics.Size(metricsWM));
    6438           0 :   if (aFloat->HasView()) {
    6439           0 :     nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, aFloat,
    6440             :                                                aFloat->GetView(),
    6441             :                                                metrics.VisualOverflow(),
    6442           0 :                                                NS_FRAME_NO_MOVE_VIEW);
    6443             :   }
    6444             :   // Pass floatRS so the frame hierarchy can be used (redoFloatRS has the same hierarchy)
    6445           0 :   aFloat->DidReflow(aState.mPresContext, &floatRS,
    6446           0 :                     nsDidReflowStatus::FINISHED);
    6447             : 
    6448             : #ifdef NOISY_FLOAT
    6449             :   printf("end ReflowFloat %p, sized to %d,%d\n",
    6450             :          aFloat, metrics.Width(), metrics.Height());
    6451             : #endif
    6452           0 : }
    6453             : 
    6454             : StyleClear
    6455           0 : nsBlockFrame::FindTrailingClear()
    6456             : {
    6457             :   // find the break type of the last line
    6458           0 :   for (nsIFrame* b = this; b; b = b->GetPrevInFlow()) {
    6459           0 :     nsBlockFrame* block = static_cast<nsBlockFrame*>(b);
    6460           0 :     LineIterator endLine = block->LinesEnd();
    6461           0 :     if (endLine != block->LinesBegin()) {
    6462           0 :       --endLine;
    6463           0 :       return endLine->GetBreakTypeAfter();
    6464             :     }
    6465             :   }
    6466           0 :   return StyleClear::None;
    6467             : }
    6468             : 
    6469             : void
    6470         162 : nsBlockFrame::ReflowPushedFloats(BlockReflowInput& aState,
    6471             :                                  nsOverflowAreas&    aOverflowAreas,
    6472             :                                  nsReflowStatus&     aStatus)
    6473             : {
    6474             :   // Pushed floats live at the start of our float list; see comment
    6475             :   // above nsBlockFrame::DrainPushedFloats.
    6476         162 :   nsIFrame* f = mFloats.FirstChild();
    6477         162 :   nsIFrame* prev = nullptr;
    6478         162 :   while (f && (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)) {
    6479           0 :     MOZ_ASSERT(prev == f->GetPrevSibling());
    6480             :     // When we push a first-continuation float in a non-initial reflow,
    6481             :     // it's possible that we end up with two continuations with the same
    6482             :     // parent.  This happens if, on the previous reflow of the block or
    6483             :     // a previous reflow of the line containing the block, the float was
    6484             :     // split between continuations A and B of the parent, but on the
    6485             :     // current reflow, none of the float can fit in A.
    6486             :     //
    6487             :     // When this happens, we might even have the two continuations
    6488             :     // out-of-order due to the management of the pushed floats.  In
    6489             :     // particular, if the float's placeholder was in a pushed line that
    6490             :     // we reflowed before it was pushed, and we split the float during
    6491             :     // that reflow, we might have the continuation of the float before
    6492             :     // the float itself.  (In the general case, however, it's correct
    6493             :     // for floats in the pushed floats list to come before floats
    6494             :     // anchored in pushed lines; however, in this case it's wrong.  We
    6495             :     // should probably find a way to fix it somehow, since it leads to
    6496             :     // incorrect layout in some cases.)
    6497             :     //
    6498             :     // When we have these out-of-order continuations, we might hit the
    6499             :     // next-continuation before the previous-continuation.  When that
    6500             :     // happens, just push it.  When we reflow the next continuation,
    6501             :     // we'll either pull all of its content back and destroy it (by
    6502             :     // calling DeleteNextInFlowChild), or nsBlockFrame::SplitFloat will
    6503             :     // pull it out of its current position and push it again (and
    6504             :     // potentially repeat this cycle for the next continuation, although
    6505             :     // hopefully then they'll be in the right order).
    6506             :     //
    6507             :     // We should also need this code for the in-order case if the first
    6508             :     // continuation of a float gets moved across more than one
    6509             :     // continuation of the containing block.  In this case we'd manage
    6510             :     // to push the second continuation without this check, but not the
    6511             :     // third and later.
    6512           0 :     nsIFrame *prevContinuation = f->GetPrevContinuation();
    6513           0 :     if (prevContinuation && prevContinuation->GetParent() == f->GetParent()) {
    6514           0 :       mFloats.RemoveFrame(f);
    6515           0 :       aState.AppendPushedFloatChain(f);
    6516           0 :       f = !prev ? mFloats.FirstChild() : prev->GetNextSibling();
    6517           0 :       continue;
    6518             :     }
    6519             : 
    6520             :     // Always call FlowAndPlaceFloat; we might need to place this float
    6521             :     // if didn't belong to this block the last time it was reflowed.
    6522           0 :     aState.FlowAndPlaceFloat(f);
    6523           0 :     ConsiderChildOverflow(aOverflowAreas, f);
    6524             : 
    6525           0 :     nsIFrame* next = !prev ? mFloats.FirstChild() : prev->GetNextSibling();
    6526           0 :     if (next == f) {
    6527             :       // We didn't push |f| so its next-sibling is next.
    6528           0 :       next = f->GetNextSibling();
    6529           0 :       prev = f;
    6530             :     } // else: we did push |f| so |prev|'s new next-sibling is next.
    6531           0 :     f = next;
    6532             :   }
    6533             : 
    6534             :   // If there are continued floats, then we may need to continue BR clearance
    6535         162 :   if (0 != aState.ClearFloats(0, StyleClear::Both)) {
    6536           0 :     nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
    6537           0 :     if (prevBlock) {
    6538           0 :       aState.mFloatBreakType = prevBlock->FindTrailingClear();
    6539             :     }
    6540             :   }
    6541         162 : }
    6542             : 
    6543             : void
    6544           0 : nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager, WritingMode aWM,
    6545             :                             const nsSize& aContainerSize)
    6546             : {
    6547             :   // Recover our own floats
    6548           0 :   nsIFrame* stop = nullptr; // Stop before we reach pushed floats that
    6549             :                            // belong to our next-in-flow
    6550           0 :   for (nsIFrame* f = mFloats.FirstChild(); f && f != stop; f = f->GetNextSibling()) {
    6551           0 :     LogicalRect region = nsFloatManager::GetRegionFor(aWM, f, aContainerSize);
    6552           0 :     aFloatManager.AddFloat(f, region, aWM, aContainerSize);
    6553           0 :     if (!stop && f->GetNextInFlow())
    6554           0 :       stop = f->GetNextInFlow();
    6555             :   }
    6556             : 
    6557             :   // Recurse into our overflow container children
    6558           0 :   for (nsIFrame* oc = GetChildList(kOverflowContainersList).FirstChild();
    6559           0 :        oc; oc = oc->GetNextSibling()) {
    6560           0 :     RecoverFloatsFor(oc, aFloatManager, aWM, aContainerSize);
    6561             :   }
    6562             : 
    6563             :   // Recurse into our normal children
    6564           0 :   for (nsBlockFrame::LineIterator line = LinesBegin(); line != LinesEnd(); ++line) {
    6565           0 :     if (line->IsBlock()) {
    6566           0 :       RecoverFloatsFor(line->mFirstChild, aFloatManager, aWM, aContainerSize);
    6567             :     }
    6568             :   }
    6569           0 : }
    6570             : 
    6571             : void
    6572           0 : nsBlockFrame::RecoverFloatsFor(nsIFrame*       aFrame,
    6573             :                                nsFloatManager& aFloatManager,
    6574             :                                WritingMode     aWM,
    6575             :                                const nsSize&   aContainerSize)
    6576             : {
    6577           0 :   NS_PRECONDITION(aFrame, "null frame");
    6578             :   // Only blocks have floats
    6579           0 :   nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
    6580             :   // Don't recover any state inside a block that has its own space manager
    6581             :   // (we don't currently have any blocks like this, though, thanks to our
    6582             :   // use of extra frames for 'overflow')
    6583           0 :   if (block && !nsBlockFrame::BlockNeedsFloatManager(block)) {
    6584             :     // If the element is relatively positioned, then adjust x and y
    6585             :     // accordingly so that we consider relatively positioned frames
    6586             :     // at their original position.
    6587             : 
    6588           0 :     LogicalRect rect(aWM, block->GetNormalRect(), aContainerSize);
    6589           0 :     nscoord lineLeft = rect.LineLeft(aWM, aContainerSize);
    6590           0 :     nscoord blockStart = rect.BStart(aWM);
    6591           0 :     aFloatManager.Translate(lineLeft, blockStart);
    6592           0 :     block->RecoverFloats(aFloatManager, aWM, aContainerSize);
    6593           0 :     aFloatManager.Translate(-lineLeft, -blockStart);
    6594             :   }
    6595           0 : }
    6596             : 
    6597             : //////////////////////////////////////////////////////////////////////
    6598             : // Painting, event handling
    6599             : 
    6600             : #ifdef DEBUG
    6601           0 : static void ComputeVisualOverflowArea(nsLineList& aLines,
    6602             :                                       nscoord aWidth, nscoord aHeight,
    6603             :                                       nsRect& aResult)
    6604             : {
    6605           0 :   nscoord xa = 0, ya = 0, xb = aWidth, yb = aHeight;
    6606           0 :   for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end();
    6607             :        line != line_end;
    6608             :        ++line) {
    6609             :     // Compute min and max x/y values for the reflowed frame's
    6610             :     // combined areas
    6611           0 :     nsRect visOverflow(line->GetVisualOverflowArea());
    6612           0 :     nscoord x = visOverflow.x;
    6613           0 :     nscoord y = visOverflow.y;
    6614           0 :     nscoord xmost = x + visOverflow.width;
    6615           0 :     nscoord ymost = y + visOverflow.height;
    6616           0 :     if (x < xa) {
    6617           0 :       xa = x;
    6618             :     }
    6619           0 :     if (xmost > xb) {
    6620           0 :       xb = xmost;
    6621             :     }
    6622           0 :     if (y < ya) {
    6623           0 :       ya = y;
    6624             :     }
    6625           0 :     if (ymost > yb) {
    6626           0 :       yb = ymost;
    6627             :     }
    6628             :   }
    6629             : 
    6630           0 :   aResult.x = xa;
    6631           0 :   aResult.y = ya;
    6632           0 :   aResult.width = xb - xa;
    6633           0 :   aResult.height = yb - ya;
    6634           0 : }
    6635             : #endif
    6636             : 
    6637             : bool
    6638           0 : nsBlockFrame::IsVisibleInSelection(nsISelection* aSelection)
    6639             : {
    6640           0 :   if (mContent->IsAnyOfHTMLElements(nsGkAtoms::html, nsGkAtoms::body))
    6641           0 :     return true;
    6642             : 
    6643           0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
    6644             :   bool visible;
    6645           0 :   nsresult rv = aSelection->ContainsNode(node, true, &visible);
    6646           0 :   return NS_SUCCEEDED(rv) && visible;
    6647             : }
    6648             : 
    6649             : #ifdef DEBUG
    6650         197 : static void DebugOutputDrawLine(int32_t aDepth, nsLineBox* aLine, bool aDrawn) {
    6651         197 :   if (nsBlockFrame::gNoisyDamageRepair) {
    6652           0 :     nsFrame::IndentBy(stdout, aDepth+1);
    6653           0 :     nsRect lineArea = aLine->GetVisualOverflowArea();
    6654           0 :     printf("%s line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
    6655             :            aDrawn ? "draw" : "skip",
    6656             :            static_cast<void*>(aLine),
    6657             :            aLine->IStart(), aLine->BStart(),
    6658             :            aLine->ISize(), aLine->BSize(),
    6659             :            lineArea.x, lineArea.y,
    6660           0 :            lineArea.width, lineArea.height);
    6661             :   }
    6662         197 : }
    6663             : #endif
    6664             : 
    6665             : static void
    6666         197 : DisplayLine(nsDisplayListBuilder* aBuilder, const nsRect& aLineArea,
    6667             :             const nsRect& aDirtyRect, nsBlockFrame::LineIterator& aLine,
    6668             :             int32_t aDepth, int32_t& aDrawnLines, const nsDisplayListSet& aLists,
    6669             :             nsBlockFrame* aFrame, TextOverflow* aTextOverflow) {
    6670             :   // If the line's combined area (which includes child frames that
    6671             :   // stick outside of the line's bounding box or our bounding box)
    6672             :   // intersects the dirty rect then paint the line.
    6673         197 :   bool intersect = aLineArea.Intersects(aDirtyRect);
    6674             : #ifdef DEBUG
    6675         197 :   if (nsBlockFrame::gLamePaintMetrics) {
    6676           0 :     aDrawnLines++;
    6677             :   }
    6678         197 :   DebugOutputDrawLine(aDepth, aLine.get(), intersect);
    6679             : #endif
    6680             :   // The line might contain a placeholder for a visible out-of-flow, in which
    6681             :   // case we need to descend into it. If there is such a placeholder, we will
    6682             :   // have NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO set.
    6683             :   // In particular, we really want to check ShouldDescendIntoFrame()
    6684             :   // on all the frames on the line, but that might be expensive.  So
    6685             :   // we approximate it by checking it on aFrame; if it's true for any
    6686             :   // frame in the line, it's also true for aFrame.
    6687         197 :   bool lineInline = aLine->IsInline();
    6688         197 :   bool lineMayHaveTextOverflow = aTextOverflow && lineInline;
    6689         270 :   if (!intersect && !aBuilder->ShouldDescendIntoFrame(aFrame) &&
    6690          73 :       !lineMayHaveTextOverflow)
    6691          73 :     return;
    6692             : 
    6693             :   // Collect our line's display items in a temporary nsDisplayListCollection,
    6694             :   // so that we can apply any "text-overflow" clipping to the entire collection
    6695             :   // without affecting previous lines.
    6696         248 :   nsDisplayListCollection collection;
    6697             : 
    6698             :   // Block-level child backgrounds go on the blockBorderBackgrounds list ...
    6699             :   // Inline-level child backgrounds go on the regular child content list.
    6700             :   nsDisplayListSet childLists(collection,
    6701         124 :     lineInline ? collection.Content() : collection.BlockBorderBackgrounds());
    6702             : 
    6703         124 :   uint32_t flags = lineInline ? nsIFrame::DISPLAY_CHILD_INLINE : 0;
    6704             : 
    6705         124 :   nsIFrame* kid = aLine->mFirstChild;
    6706         124 :   int32_t n = aLine->GetChildCount();
    6707         372 :   while (--n >= 0) {
    6708         124 :     aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect,
    6709         124 :                                      childLists, flags);
    6710         124 :     kid = kid->GetNextSibling();
    6711             :   }
    6712             : 
    6713         124 :   if (lineMayHaveTextOverflow) {
    6714           0 :     aTextOverflow->ProcessLine(collection, aLine.get());
    6715             :   }
    6716             : 
    6717         124 :   collection.MoveTo(aLists);
    6718             : }
    6719             : 
    6720             : void
    6721         199 : nsBlockFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    6722             :                                const nsRect&           aDirtyRect,
    6723             :                                const nsDisplayListSet& aLists)
    6724             : {
    6725             :   int32_t drawnLines; // Will only be used if set (gLamePaintMetrics).
    6726         199 :   int32_t depth = 0;
    6727             : #ifdef DEBUG
    6728         199 :   if (gNoisyDamageRepair) {
    6729           0 :       depth = GetDepth();
    6730           0 :       nsRect ca;
    6731           0 :       ::ComputeVisualOverflowArea(mLines, mRect.width, mRect.height, ca);
    6732           0 :       nsFrame::IndentBy(stdout, depth);
    6733           0 :       ListTag(stdout);
    6734           0 :       printf(": bounds=%d,%d,%d,%d dirty(absolute)=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
    6735             :              mRect.x, mRect.y, mRect.width, mRect.height,
    6736           0 :              aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height,
    6737           0 :              ca.x, ca.y, ca.width, ca.height);
    6738             :   }
    6739         199 :   PRTime start = 0; // Initialize these variables to silence the compiler.
    6740         199 :   if (gLamePaintMetrics) {
    6741           0 :     start = PR_Now();
    6742           0 :     drawnLines = 0;
    6743             :   }
    6744             : #endif
    6745             : 
    6746         199 :   DisplayBorderBackgroundOutline(aBuilder, aLists);
    6747             : 
    6748         199 :   if (GetPrevInFlow()) {
    6749           0 :     DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
    6750           0 :     for (nsIFrame* f : mFloats) {
    6751           0 :       if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)
    6752           0 :          BuildDisplayListForChild(aBuilder, f, aDirtyRect, aLists);
    6753             :     }
    6754             :   }
    6755             : 
    6756         199 :   aBuilder->MarkFramesForDisplayList(this, mFloats, aDirtyRect);
    6757             : 
    6758             :   // Prepare for text-overflow processing.
    6759             :   UniquePtr<TextOverflow> textOverflow(
    6760         398 :     TextOverflow::WillProcessLines(aBuilder, this));
    6761             : 
    6762             :   // We'll collect our lines' display items here, & then append this to aLists.
    6763         398 :   nsDisplayListCollection linesDisplayListCollection;
    6764             : 
    6765             :   // Don't use the line cursor if we might have a descendant placeholder ...
    6766             :   // it might skip lines that contain placeholders but don't themselves
    6767             :   // intersect with the dirty area.
    6768             :   // In particular, we really want to check ShouldDescendIntoFrame()
    6769             :   // on all our child frames, but that might be expensive.  So we
    6770             :   // approximate it by checking it on |this|; if it's true for any
    6771             :   // frame in our child list, it's also true for |this|.
    6772         363 :   nsLineBox* cursor = aBuilder->ShouldDescendIntoFrame(this) ?
    6773         363 :     nullptr : GetFirstLineContaining(aDirtyRect.y);
    6774         199 :   LineIterator line_end = LinesEnd();
    6775             : 
    6776         199 :   if (cursor) {
    6777           0 :     for (LineIterator line = mLines.begin(cursor);
    6778             :          line != line_end;
    6779             :          ++line) {
    6780           0 :       nsRect lineArea = line->GetVisualOverflowArea();
    6781           0 :       if (!lineArea.IsEmpty()) {
    6782             :         // Because we have a cursor, the combinedArea.ys are non-decreasing.
    6783             :         // Once we've passed aDirtyRect.YMost(), we can never see it again.
    6784           0 :         if (lineArea.y >= aDirtyRect.YMost()) {
    6785           0 :           break;
    6786             :         }
    6787           0 :         DisplayLine(aBuilder, lineArea, aDirtyRect, line, depth, drawnLines,
    6788           0 :                     linesDisplayListCollection, this, textOverflow.get());
    6789             :       }
    6790             :     }
    6791             :   } else {
    6792         199 :     bool nonDecreasingYs = true;
    6793         199 :     int32_t lineCount = 0;
    6794         199 :     nscoord lastY = INT32_MIN;
    6795         199 :     nscoord lastYMost = INT32_MIN;
    6796         396 :     for (LineIterator line = LinesBegin();
    6797             :          line != line_end;
    6798             :          ++line) {
    6799         394 :       nsRect lineArea = line->GetVisualOverflowArea();
    6800         197 :       DisplayLine(aBuilder, lineArea, aDirtyRect, line, depth, drawnLines,
    6801         197 :                   linesDisplayListCollection, this, textOverflow.get());
    6802         197 :       if (!lineArea.IsEmpty()) {
    6803         248 :         if (lineArea.y < lastY
    6804         124 :             || lineArea.YMost() < lastYMost) {
    6805           0 :           nonDecreasingYs = false;
    6806             :         }
    6807         124 :         lastY = lineArea.y;
    6808         124 :         lastYMost = lineArea.YMost();
    6809             :       }
    6810         197 :       lineCount++;
    6811             :     }
    6812             : 
    6813         199 :     if (nonDecreasingYs && lineCount >= MIN_LINES_NEEDING_CURSOR) {
    6814           0 :       SetupLineCursor();
    6815             :     }
    6816             :   }
    6817             : 
    6818             :   // Pick up the resulting text-overflow markers.  We append them to
    6819             :   // PositionedDescendants just before we append the lines' display items,
    6820             :   // so that our text-overflow markers will appear on top of this block's
    6821             :   // normal content but below any of its its' positioned children.
    6822         199 :   if (textOverflow) {
    6823           0 :     aLists.PositionedDescendants()->AppendToTop(&textOverflow->GetMarkers());
    6824             :   }
    6825         199 :   linesDisplayListCollection.MoveTo(aLists);
    6826             : 
    6827         199 :   if (HasOutsideBullet()) {
    6828             :     // Display outside bullets manually
    6829           0 :     nsIFrame* bullet = GetOutsideBullet();
    6830           0 :     BuildDisplayListForChild(aBuilder, bullet, aDirtyRect, aLists);
    6831             :   }
    6832             : 
    6833             : #ifdef DEBUG
    6834         199 :   if (gLamePaintMetrics) {
    6835           0 :     PRTime end = PR_Now();
    6836             : 
    6837           0 :     int32_t numLines = mLines.size();
    6838           0 :     if (!numLines) numLines = 1;
    6839             :     PRTime lines, deltaPerLine, delta;
    6840           0 :     lines = int64_t(numLines);
    6841           0 :     delta = end - start;
    6842           0 :     deltaPerLine = delta / lines;
    6843             : 
    6844           0 :     ListTag(stdout);
    6845             :     char buf[400];
    6846           0 :     SprintfLiteral(buf,
    6847             :                    ": %" PRId64 " elapsed (%" PRId64 " per line) lines=%d drawn=%d skip=%d",
    6848             :                    delta, deltaPerLine,
    6849           0 :                    numLines, drawnLines, numLines - drawnLines);
    6850           0 :     printf("%s\n", buf);
    6851             :   }
    6852             : #endif
    6853         199 : }
    6854             : 
    6855             : #ifdef ACCESSIBILITY
    6856             : a11y::AccType
    6857           0 : nsBlockFrame::AccessibleType()
    6858             : {
    6859           0 :   if (IsTableCaption()) {
    6860           0 :     return GetRect().IsEmpty() ? a11y::eNoType : a11y::eHTMLCaptionType;
    6861             :   }
    6862             : 
    6863             :   // block frame may be for <hr>
    6864           0 :   if (mContent->IsHTMLElement(nsGkAtoms::hr)) {
    6865           0 :     return a11y::eHTMLHRType;
    6866             :   }
    6867             : 
    6868           0 :   if (!HasBullet() || !PresContext()) {
    6869             :     //XXXsmaug What if we're in the shadow dom?
    6870           0 :     if (!mContent->GetParent()) {
    6871             :       // Don't create accessible objects for the root content node, they are redundant with
    6872             :       // the nsDocAccessible object created with the document node
    6873           0 :       return a11y::eNoType;
    6874             :     }
    6875             : 
    6876             :     nsCOMPtr<nsIDOMHTMLDocument> htmlDoc =
    6877           0 :       do_QueryInterface(mContent->GetComposedDoc());
    6878           0 :     if (htmlDoc) {
    6879           0 :       nsCOMPtr<nsIDOMHTMLElement> body;
    6880           0 :       htmlDoc->GetBody(getter_AddRefs(body));
    6881           0 :       if (SameCOMIdentity(body, mContent)) {
    6882             :         // Don't create accessible objects for the body, they are redundant with
    6883             :         // the nsDocAccessible object created with the document node
    6884           0 :         return a11y::eNoType;
    6885             :       }
    6886             :     }
    6887             : 
    6888             :     // Not a bullet, treat as normal HTML container
    6889           0 :     return a11y::eHyperTextType;
    6890             :   }
    6891             : 
    6892             :   // Create special list bullet accessible
    6893           0 :   return a11y::eHTMLLiType;
    6894             : }
    6895             : #endif
    6896             : 
    6897         220 : void nsBlockFrame::ClearLineCursor()
    6898             : {
    6899         220 :   if (!(GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR)) {
    6900         220 :     return;
    6901             :   }
    6902             : 
    6903           0 :   DeleteProperty(LineCursorProperty());
    6904           0 :   RemoveStateBits(NS_BLOCK_HAS_LINE_CURSOR);
    6905             : }
    6906             : 
    6907           0 : void nsBlockFrame::SetupLineCursor()
    6908             : {
    6909           0 :   if (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR
    6910           0 :       || mLines.empty()) {
    6911           0 :     return;
    6912             :   }
    6913             : 
    6914           0 :   SetProperty(LineCursorProperty(), mLines.front());
    6915           0 :   AddStateBits(NS_BLOCK_HAS_LINE_CURSOR);
    6916             : }
    6917             : 
    6918         164 : nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y)
    6919             : {
    6920         164 :   if (!(GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR)) {
    6921         164 :     return nullptr;
    6922             :   }
    6923             : 
    6924           0 :   nsLineBox* property = GetProperty(LineCursorProperty());
    6925           0 :   LineIterator cursor = mLines.begin(property);
    6926           0 :   nsRect cursorArea = cursor->GetVisualOverflowArea();
    6927             : 
    6928           0 :   while ((cursorArea.IsEmpty() || cursorArea.YMost() > y)
    6929           0 :          && cursor != mLines.front()) {
    6930           0 :     cursor = cursor.prev();
    6931           0 :     cursorArea = cursor->GetVisualOverflowArea();
    6932             :   }
    6933           0 :   while ((cursorArea.IsEmpty() || cursorArea.YMost() <= y)
    6934           0 :          && cursor != mLines.back()) {
    6935           0 :     cursor = cursor.next();
    6936           0 :     cursorArea = cursor->GetVisualOverflowArea();
    6937             :   }
    6938             : 
    6939           0 :   if (cursor.get() != property) {
    6940           0 :     SetProperty(LineCursorProperty(), cursor.get());
    6941             :   }
    6942             : 
    6943           0 :   return cursor.get();
    6944             : }
    6945             : 
    6946             : /* virtual */ void
    6947           8 : nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
    6948             : {
    6949             :   // See if the child is absolutely positioned
    6950           8 :   if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
    6951           0 :       aChild->IsAbsolutelyPositioned()) {
    6952             :     // do nothing
    6953           8 :   } else if (aChild == GetOutsideBullet()) {
    6954             :     // The bullet lives in the first line, unless the first line has
    6955             :     // height 0 and there is a second line, in which case it lives
    6956             :     // in the second line.
    6957           0 :     LineIterator bulletLine = LinesBegin();
    6958           0 :     if (bulletLine != LinesEnd() && bulletLine->BSize() == 0 &&
    6959           0 :         bulletLine != mLines.back()) {
    6960           0 :       bulletLine = bulletLine.next();
    6961             :     }
    6962             : 
    6963           0 :     if (bulletLine != LinesEnd()) {
    6964           0 :       MarkLineDirty(bulletLine, &mLines);
    6965             :     }
    6966             :     // otherwise we have an empty line list, and ReflowDirtyLines
    6967             :     // will handle reflowing the bullet.
    6968             :   } else {
    6969             :     // Note that we should go through our children to mark lines dirty
    6970             :     // before the next reflow.  Doing it now could make things O(N^2)
    6971             :     // since finding the right line is O(N).
    6972             :     // We don't need to worry about marking lines on the overflow list
    6973             :     // as dirty; we're guaranteed to reflow them if we take them off the
    6974             :     // overflow list.
    6975             :     // However, we might have gotten a float, in which case we need to
    6976             :     // reflow the line containing its placeholder.  So find the
    6977             :     // ancestor-or-self of the placeholder that's a child of the block,
    6978             :     // and mark it as NS_FRAME_HAS_DIRTY_CHILDREN too, so that we mark
    6979             :     // its line dirty when we handle NS_BLOCK_LOOK_FOR_DIRTY_FRAMES.
    6980             :     // We need to take some care to handle the case where a float is in
    6981             :     // a different continuation than its placeholder, including marking
    6982             :     // an extra block with NS_BLOCK_LOOK_FOR_DIRTY_FRAMES.
    6983           8 :     if (!(aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    6984           8 :       AddStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES);
    6985             :     } else {
    6986           0 :       NS_ASSERTION(aChild->IsFloating(), "should be a float");
    6987           0 :       nsIFrame* thisFC = FirstContinuation();
    6988           0 :       nsIFrame* placeholderPath = aChild->GetPlaceholderFrame();
    6989             :       // SVG code sometimes sends FrameNeedsReflow notifications during
    6990             :       // frame destruction, leading to null placeholders, but we're safe
    6991             :       // ignoring those.
    6992           0 :       if (placeholderPath) {
    6993             :         for (;;) {
    6994           0 :           nsIFrame *parent = placeholderPath->GetParent();
    6995           0 :           if (parent->GetContent() == mContent &&
    6996           0 :               parent->FirstContinuation() == thisFC) {
    6997           0 :             parent->AddStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES);
    6998           0 :             break;
    6999             :           }
    7000           0 :           placeholderPath = parent;
    7001           0 :         }
    7002           0 :         placeholderPath->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
    7003             :       }
    7004             :     }
    7005             :   }
    7006             : 
    7007           8 :   nsContainerFrame::ChildIsDirty(aChild);
    7008           8 : }
    7009             : 
    7010             : void
    7011          34 : nsBlockFrame::Init(nsIContent*       aContent,
    7012             :                    nsContainerFrame* aParent,
    7013             :                    nsIFrame*         aPrevInFlow)
    7014             : {
    7015          34 :   if (aPrevInFlow) {
    7016             :     // Copy over the inherited block frame bits from the prev-in-flow.
    7017           0 :     RemoveStateBits(NS_BLOCK_FLAGS_MASK);
    7018           0 :     AddStateBits(aPrevInFlow->GetStateBits() &
    7019           0 :                  (NS_BLOCK_FLAGS_MASK & ~NS_BLOCK_FLAGS_NON_INHERITED_MASK));
    7020             :   }
    7021             : 
    7022          34 :   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    7023             : 
    7024          34 :   if (!aPrevInFlow ||
    7025           0 :       aPrevInFlow->GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION) {
    7026          34 :     AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
    7027             :   }
    7028             : 
    7029             :   // A display:flow-root box establishes a block formatting context.
    7030             :   // If a box has a different block flow direction than its containing block:
    7031             :   // ...
    7032             :   //   If the box is a block container, then it establishes a new block
    7033             :   //   formatting context.
    7034             :   // (http://dev.w3.org/csswg/css-writing-modes/#block-flow)
    7035             :   // If the box has contain: paint (or contain: strict), then it should also
    7036             :   // establish a formatting context.
    7037         102 :   if (StyleDisplay()->mDisplay == mozilla::StyleDisplay::FlowRoot ||
    7038         102 :       (GetParent() && StyleVisibility()->mWritingMode !=
    7039         102 :                       GetParent()->StyleVisibility()->mWritingMode) ||
    7040          34 :       StyleDisplay()->IsContainPaint()) {
    7041           0 :     AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
    7042             :   }
    7043             : 
    7044          68 :   if ((GetStateBits() &
    7045             :        (NS_FRAME_FONT_INFLATION_CONTAINER | NS_BLOCK_FLOAT_MGR)) ==
    7046          34 :       (NS_FRAME_FONT_INFLATION_CONTAINER | NS_BLOCK_FLOAT_MGR)) {
    7047           8 :     AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
    7048             :   }
    7049          34 : }
    7050             : 
    7051             : void
    7052          34 : nsBlockFrame::SetInitialChildList(ChildListID     aListID,
    7053             :                                   nsFrameList&    aChildList)
    7054             : {
    7055          34 :   if (kFloatList == aListID) {
    7056           0 :     mFloats.SetFrames(aChildList);
    7057          34 :   } else if (kPrincipalList == aListID) {
    7058          34 :     NS_ASSERTION((GetStateBits() & (NS_BLOCK_FRAME_HAS_INSIDE_BULLET |
    7059             :                                     NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET)) == 0,
    7060             :                  "how can we have a bullet already?");
    7061             : 
    7062             : #ifdef DEBUG
    7063             :     // The only times a block that is an anonymous box is allowed to have a
    7064             :     // first-letter frame are when it's the block inside a non-anonymous cell,
    7065             :     // the block inside a fieldset, button or column set, or a scrolled content
    7066             :     // block, except for <select>.  Note that this means that blocks which are
    7067             :     // the anonymous block in {ib} splits do NOT get first-letter frames.
    7068             :     // Note that NS_BLOCK_HAS_FIRST_LETTER_STYLE gets set on all continuations
    7069             :     // of the block.
    7070          34 :     nsIAtom *pseudo = StyleContext()->GetPseudo();
    7071             :     bool haveFirstLetterStyle =
    7072          20 :       (!pseudo ||
    7073          20 :        (pseudo == nsCSSAnonBoxes::cellContent &&
    7074          20 :         GetParent()->StyleContext()->GetPseudo() == nullptr) ||
    7075          40 :        pseudo == nsCSSAnonBoxes::fieldsetContent ||
    7076          40 :        pseudo == nsCSSAnonBoxes::buttonContent ||
    7077          40 :        pseudo == nsCSSAnonBoxes::columnContent ||
    7078          32 :        (pseudo == nsCSSAnonBoxes::scrolledContent &&
    7079          20 :         !GetParent()->IsListControlFrame()) ||
    7080          34 :        pseudo == nsCSSAnonBoxes::mozSVGText) &&
    7081          52 :       !IsComboboxControlFrame() &&
    7082         112 :       !IsFrameOfType(eMathML) &&
    7083          86 :       RefPtr<nsStyleContext>(GetFirstLetterStyle(PresContext())) != nullptr;
    7084          34 :     NS_ASSERTION(haveFirstLetterStyle ==
    7085             :                  ((mState & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0),
    7086             :                  "NS_BLOCK_HAS_FIRST_LETTER_STYLE state out of sync");
    7087             : #endif
    7088             : 
    7089          34 :     AddFrames(aChildList, nullptr);
    7090             : 
    7091             :     // Create a list bullet if this is a list-item. Note that this is
    7092             :     // done here so that RenumberLists will work (it needs the bullets
    7093             :     // to store the bullet numbers).  Also note that due to various
    7094             :     // wrapper frames (scrollframes, columns) we want to use the
    7095             :     // outermost (primary, ideally, but it's not set yet when we get
    7096             :     // here) frame of our content for the display check.  On the other
    7097             :     // hand, we look at ourselves for the GetPrevInFlow() check, since
    7098             :     // for a columnset we don't want a bullet per column.  Note that
    7099             :     // the outermost frame for the content is the primary frame in
    7100             :     // most cases; the ones when it's not (like tables) can't be
    7101             :     // StyleDisplay::ListItem).
    7102          34 :     nsIFrame* possibleListItem = this;
    7103             :     while (1) {
    7104          57 :       nsIFrame* parent = possibleListItem->GetParent();
    7105          57 :       if (parent->GetContent() != GetContent()) {
    7106          34 :         break;
    7107             :       }
    7108          23 :       possibleListItem = parent;
    7109          23 :     }
    7110          34 :     if (mozilla::StyleDisplay::ListItem ==
    7111          34 :           possibleListItem->StyleDisplay()->mDisplay &&
    7112           0 :         !GetPrevInFlow()) {
    7113             :       // Resolve style for the bullet frame
    7114           0 :       const nsStyleList* styleList = StyleList();
    7115           0 :       CounterStyle* style = styleList->mCounterStyle;
    7116             : 
    7117           0 :       CreateBulletFrameForListItem(
    7118           0 :         style->IsBullet(),
    7119           0 :         styleList->mListStylePosition == NS_STYLE_LIST_STYLE_POSITION_INSIDE);
    7120             :     }
    7121             :   } else {
    7122           0 :     nsContainerFrame::SetInitialChildList(aListID, aChildList);
    7123             :   }
    7124          34 : }
    7125             : 
    7126             : void
    7127           0 : nsBlockFrame::CreateBulletFrameForListItem(bool aCreateBulletList,
    7128             :                                            bool aListStylePositionInside)
    7129             : {
    7130           0 :   nsIPresShell* shell = PresContext()->PresShell();
    7131             : 
    7132           0 :   CSSPseudoElementType pseudoType = aCreateBulletList ?
    7133             :     CSSPseudoElementType::mozListBullet :
    7134           0 :     CSSPseudoElementType::mozListNumber;
    7135             : 
    7136           0 :   RefPtr<nsStyleContext> kidSC = ResolveBulletStyle(pseudoType,
    7137           0 :                                                     shell->StyleSet());
    7138             : 
    7139             :   // Create bullet frame
    7140           0 :   nsBulletFrame* bullet = new (shell) nsBulletFrame(kidSC);
    7141           0 :   bullet->Init(mContent, this, nullptr);
    7142             : 
    7143             :   // If the list bullet frame should be positioned inside then add
    7144             :   // it to the flow now.
    7145           0 :   if (aListStylePositionInside) {
    7146           0 :     nsFrameList bulletList(bullet, bullet);
    7147           0 :     AddFrames(bulletList, nullptr);
    7148           0 :     SetProperty(InsideBulletProperty(), bullet);
    7149           0 :     AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_BULLET);
    7150             :   } else {
    7151           0 :     nsFrameList* bulletList = new (shell) nsFrameList(bullet, bullet);
    7152           0 :     SetProperty(OutsideBulletProperty(), bulletList);
    7153           0 :     AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
    7154             :   }
    7155           0 : }
    7156             : 
    7157             : bool
    7158           0 : nsBlockFrame::BulletIsEmpty() const
    7159             : {
    7160           0 :   NS_ASSERTION(mContent->GetPrimaryFrame()->StyleDisplay()->mDisplay ==
    7161             :                mozilla::StyleDisplay::ListItem && HasOutsideBullet(),
    7162             :                "should only care when we have an outside bullet");
    7163           0 :   const nsStyleList* list = StyleList();
    7164           0 :   return list->mCounterStyle->IsNone() &&
    7165           0 :          !list->GetListStyleImage();
    7166             : }
    7167             : 
    7168             : void
    7169           0 : nsBlockFrame::GetSpokenBulletText(nsAString& aText) const
    7170             : {
    7171           0 :   const nsStyleList* myList = StyleList();
    7172           0 :   if (myList->GetListStyleImage()) {
    7173           0 :     aText.Assign(kDiscCharacter);
    7174           0 :     aText.Append(' ');
    7175             :   } else {
    7176           0 :     nsBulletFrame* bullet = GetBullet();
    7177           0 :     if (bullet) {
    7178           0 :       bullet->GetSpokenText(aText);
    7179             :     } else {
    7180           0 :       aText.Truncate();
    7181             :     }
    7182             :   }
    7183           0 : }
    7184             : 
    7185             : bool
    7186           0 : nsBlockFrame::RenumberChildFrames(int32_t* aOrdinal,
    7187             :                                   int32_t aDepth,
    7188             :                                   int32_t aIncrement,
    7189             :                                   bool aForCounting)
    7190             : {
    7191             :   // Examine each line in the block
    7192             :   bool foundValidLine;
    7193           0 :   nsBlockInFlowLineIterator bifLineIter(this, &foundValidLine);
    7194           0 :   if (!foundValidLine) {
    7195           0 :     return false;
    7196             :   }
    7197             : 
    7198           0 :   bool renumberedABullet = false;
    7199           0 :   do {
    7200           0 :     nsLineList::iterator line = bifLineIter.GetLine();
    7201           0 :     nsIFrame* kid = line->mFirstChild;
    7202           0 :     int32_t n = line->GetChildCount();
    7203           0 :     while (--n >= 0) {
    7204             :       bool kidRenumberedABullet =
    7205           0 :         kid->RenumberFrameAndDescendants(aOrdinal, aDepth, aIncrement, aForCounting);
    7206           0 :       if (!aForCounting && kidRenumberedABullet) {
    7207           0 :         line->MarkDirty();
    7208           0 :         renumberedABullet = true;
    7209             :       }
    7210           0 :       kid = kid->GetNextSibling();
    7211             :     }
    7212             :   } while (bifLineIter.Next());
    7213             : 
    7214             :   // We need to set NS_FRAME_HAS_DIRTY_CHILDREN bits up the tree between
    7215             :   // the bullet and the caller of RenumberLists.  But the caller itself
    7216             :   // has to be responsible for setting the bit itself, since that caller
    7217             :   // might be making a FrameNeedsReflow call, which requires that the
    7218             :   // bit not be set yet.
    7219           0 :   if (renumberedABullet && aDepth != 0) {
    7220           0 :     AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
    7221             :   }
    7222             : 
    7223           0 :   return renumberedABullet;
    7224             : }
    7225             : 
    7226             : void
    7227           0 : nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
    7228             :                            BlockReflowInput& aState,
    7229             :                            ReflowOutput& aMetrics,
    7230             :                            nscoord aLineTop)
    7231             : {
    7232           0 :   const ReflowInput &rs = aState.mReflowInput;
    7233             : 
    7234             :   // Reflow the bullet now
    7235           0 :   WritingMode bulletWM = aBulletFrame->GetWritingMode();
    7236           0 :   LogicalSize availSize(bulletWM);
    7237             :   // Make up an inline-size since it doesn't really matter (XXX).
    7238           0 :   availSize.ISize(bulletWM) = aState.ContentISize();
    7239           0 :   availSize.BSize(bulletWM) = NS_UNCONSTRAINEDSIZE;
    7240             : 
    7241             :   // Get the reason right.
    7242             :   // XXXwaterson Should this look just like the logic in
    7243             :   // nsBlockReflowContext::ReflowBlock and nsLineLayout::ReflowFrame?
    7244             :   ReflowInput reflowInput(aState.mPresContext, rs,
    7245           0 :                                 aBulletFrame, availSize);
    7246           0 :   nsReflowStatus  status;
    7247           0 :   aBulletFrame->Reflow(aState.mPresContext, aMetrics, reflowInput, status);
    7248             : 
    7249             :   // Get the float available space using our saved state from before we
    7250             :   // started reflowing the block, so that we ignore any floats inside
    7251             :   // the block.
    7252             :   // FIXME: aLineTop isn't actually set correctly by some callers, since
    7253             :   // they reposition the line.
    7254             :   LogicalRect floatAvailSpace =
    7255           0 :     aState.GetFloatAvailableSpaceWithState(aLineTop, ShapeType::ShapeOutside,
    7256             :                                            &aState.mFloatManagerStateBefore)
    7257           0 :           .mRect;
    7258             :   // FIXME (bug 25888): need to check the entire region that the first
    7259             :   // line overlaps, not just the top pixel.
    7260             : 
    7261             :   // Place the bullet now.  We want to place the bullet relative to the
    7262             :   // border-box of the associated block (using the right/left margin of
    7263             :   // the bullet frame as separation).  However, if a line box would be
    7264             :   // displaced by floats that are *outside* the associated block, we
    7265             :   // want to displace it by the same amount.  That is, we act as though
    7266             :   // the edge of the floats is the content-edge of the block, and place
    7267             :   // the bullet at a position offset from there by the block's padding,
    7268             :   // the block's border, and the bullet frame's margin.
    7269             : 
    7270             :   // IStart from floatAvailSpace gives us the content/float start edge
    7271             :   // in the current writing mode. Then we subtract out the start
    7272             :   // border/padding and the bullet's width and margin to offset the position.
    7273           0 :   WritingMode wm = rs.GetWritingMode();
    7274             :   // Get the bullet's margin, converted to our writing mode so that we can
    7275             :   // combine it with other logical values here.
    7276             :   LogicalMargin bulletMargin =
    7277           0 :     reflowInput.ComputedLogicalMargin().ConvertTo(wm, bulletWM);
    7278           0 :   nscoord iStart = floatAvailSpace.IStart(wm) -
    7279           0 :                    rs.ComputedLogicalBorderPadding().IStart(wm) -
    7280           0 :                    bulletMargin.IEnd(wm) -
    7281           0 :                    aMetrics.ISize(wm);
    7282             : 
    7283             :   // Approximate the bullets position; vertical alignment will provide
    7284             :   // the final vertical location. We pass our writing-mode here, because
    7285             :   // it may be different from the bullet frame's mode.
    7286           0 :   nscoord bStart = floatAvailSpace.BStart(wm);
    7287           0 :   aBulletFrame->SetRect(wm, LogicalRect(wm, iStart, bStart,
    7288           0 :                                         aMetrics.ISize(wm),
    7289           0 :                                         aMetrics.BSize(wm)),
    7290           0 :                         aState.ContainerSize());
    7291           0 :   aBulletFrame->DidReflow(aState.mPresContext, &aState.mReflowInput,
    7292           0 :                           nsDidReflowStatus::FINISHED);
    7293           0 : }
    7294             : 
    7295             : // This is used to scan frames for any float placeholders, add their
    7296             : // floats to the list represented by aList, and remove the
    7297             : // floats from whatever list they might be in. We don't search descendants
    7298             : // that are float containing blocks.  Floats that or not children of 'this'
    7299             : // are ignored (they are not added to aList).
    7300             : void
    7301           0 : nsBlockFrame::DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList,
    7302             :                               bool aCollectSiblings)
    7303             : {
    7304           0 :   while (aFrame) {
    7305             :     // Don't descend into float containing blocks.
    7306           0 :     if (!aFrame->IsFloatContainingBlock()) {
    7307             :       nsIFrame* outOfFlowFrame =
    7308           0 :         aFrame->IsPlaceholderFrame()
    7309           0 :           ? nsLayoutUtils::GetFloatFromPlaceholder(aFrame)
    7310           0 :           : nullptr;
    7311           0 :       while (outOfFlowFrame && outOfFlowFrame->GetParent() == this) {
    7312           0 :         RemoveFloat(outOfFlowFrame);
    7313             :         // Remove the IS_PUSHED_FLOAT bit, in case |outOfFlowFrame| came from
    7314             :         // the PushedFloats list.
    7315           0 :         outOfFlowFrame->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
    7316           0 :         aList.AppendFrame(nullptr, outOfFlowFrame);
    7317           0 :         outOfFlowFrame = outOfFlowFrame->GetNextInFlow();
    7318             :         // FIXME: By not pulling floats whose parent is one of our
    7319             :         // later siblings, are we risking the pushed floats getting
    7320             :         // out-of-order?
    7321             :         // XXXmats nsInlineFrame's lazy reparenting depends on NOT doing that.
    7322             :       }
    7323             : 
    7324           0 :       DoCollectFloats(aFrame->PrincipalChildList().FirstChild(), aList, true);
    7325           0 :       DoCollectFloats(aFrame->GetChildList(kOverflowList).FirstChild(), aList, true);
    7326             :     }
    7327           0 :     if (!aCollectSiblings)
    7328           0 :       break;
    7329           0 :     aFrame = aFrame->GetNextSibling();
    7330             :   }
    7331           0 : }
    7332             : 
    7333             : void
    7334         162 : nsBlockFrame::CheckFloats(BlockReflowInput& aState)
    7335             : {
    7336             : #ifdef DEBUG
    7337             :   // If any line is still dirty, that must mean we're going to reflow this
    7338             :   // block again soon (e.g. because we bailed out after noticing that
    7339             :   // clearance was imposed), so don't worry if the floats are out of sync.
    7340         162 :   bool anyLineDirty = false;
    7341             : 
    7342             :   // Check that the float list is what we would have built
    7343         324 :   AutoTArray<nsIFrame*, 8> lineFloats;
    7344         313 :   for (LineIterator line = LinesBegin(), line_end = LinesEnd();
    7345             :        line != line_end; ++line) {
    7346         151 :     if (line->HasFloats()) {
    7347           0 :       nsFloatCache* fc = line->GetFirstFloat();
    7348           0 :       while (fc) {
    7349           0 :         lineFloats.AppendElement(fc->mFloat);
    7350           0 :         fc = fc->Next();
    7351             :       }
    7352             :     }
    7353         151 :     if (line->IsDirty()) {
    7354           0 :       anyLineDirty = true;
    7355             :     }
    7356             :   }
    7357             : 
    7358         324 :   AutoTArray<nsIFrame*, 8> storedFloats;
    7359         162 :   bool equal = true;
    7360         162 :   uint32_t i = 0;
    7361         162 :   for (nsIFrame* f : mFloats) {
    7362           0 :     if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)
    7363           0 :       continue;
    7364           0 :     storedFloats.AppendElement(f);
    7365           0 :     if (i < lineFloats.Length() && lineFloats.ElementAt(i) != f) {
    7366           0 :       equal = false;
    7367             :     }
    7368           0 :     ++i;
    7369             :   }
    7370             : 
    7371         162 :   if ((!equal || lineFloats.Length() != storedFloats.Length()) && !anyLineDirty) {
    7372           0 :     NS_WARNING("nsBlockFrame::CheckFloats: Explicit float list is out of sync with float cache");
    7373             : #if defined(DEBUG_roc)
    7374             :     nsFrame::RootFrameList(PresContext(), stdout, 0);
    7375             :     for (i = 0; i < lineFloats.Length(); ++i) {
    7376             :       printf("Line float: %p\n", lineFloats.ElementAt(i));
    7377             :     }
    7378             :     for (i = 0; i < storedFloats.Length(); ++i) {
    7379             :       printf("Stored float: %p\n", storedFloats.ElementAt(i));
    7380             :     }
    7381             : #endif
    7382             :   }
    7383             : #endif
    7384             : 
    7385         162 :   const nsFrameList* oofs = GetOverflowOutOfFlows();
    7386         162 :   if (oofs && oofs->NotEmpty()) {
    7387             :     // Floats that were pushed should be removed from our float
    7388             :     // manager.  Otherwise the float manager's YMost or XMost might
    7389             :     // be larger than necessary, causing this block to get an
    7390             :     // incorrect desired height (or width).  Some of these floats
    7391             :     // may not actually have been added to the float manager because
    7392             :     // they weren't reflowed before being pushed; that's OK,
    7393             :     // RemoveRegions will ignore them. It is safe to do this here
    7394             :     // because we know from here on the float manager will only be
    7395             :     // used for its XMost and YMost, not to place new floats and
    7396             :     // lines.
    7397           0 :     aState.FloatManager()->RemoveTrailingRegions(oofs->FirstChild());
    7398             :   }
    7399         162 : }
    7400             : 
    7401             : void
    7402         172 : nsBlockFrame::IsMarginRoot(bool* aBStartMarginRoot, bool* aBEndMarginRoot)
    7403             : {
    7404         172 :   if (!(GetStateBits() & NS_BLOCK_MARGIN_ROOT)) {
    7405          41 :     nsIFrame* parent = GetParent();
    7406          41 :     if (!parent || parent->IsFloatContainingBlock()) {
    7407          20 :       *aBStartMarginRoot = false;
    7408          20 :       *aBEndMarginRoot = false;
    7409          20 :       return;
    7410             :     }
    7411          21 :     if (parent->IsColumnSetFrame()) {
    7412           0 :       *aBStartMarginRoot = GetPrevInFlow() == nullptr;
    7413           0 :       *aBEndMarginRoot = GetNextInFlow() == nullptr;
    7414           0 :       return;
    7415             :     }
    7416             :   }
    7417             : 
    7418         152 :   *aBStartMarginRoot = true;
    7419         152 :   *aBEndMarginRoot = true;
    7420             : }
    7421             : 
    7422             : /* static */
    7423             : bool
    7424         162 : nsBlockFrame::BlockNeedsFloatManager(nsIFrame* aBlock)
    7425             : {
    7426         162 :   NS_PRECONDITION(aBlock, "Must have a frame");
    7427         162 :   NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlock), "aBlock must be a block");
    7428             : 
    7429         162 :   nsIFrame* parent = aBlock->GetParent();
    7430         314 :   return (aBlock->GetStateBits() & NS_BLOCK_FLOAT_MGR) ||
    7431         193 :     (parent && !parent->IsFloatContainingBlock());
    7432             : }
    7433             : 
    7434             : /* static */
    7435             : bool
    7436          40 : nsBlockFrame::BlockCanIntersectFloats(nsIFrame* aFrame)
    7437             : {
    7438          80 :   return aFrame->IsFrameOfType(nsIFrame::eBlockFrame) &&
    7439          80 :          !aFrame->IsFrameOfType(nsIFrame::eReplaced) &&
    7440          80 :          !(aFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR);
    7441             : }
    7442             : 
    7443             : // Note that this width can vary based on the vertical position.
    7444             : // However, the cases where it varies are the cases where the width fits
    7445             : // in the available space given, which means that variation shouldn't
    7446             : // matter.
    7447             : /* static */
    7448             : nsBlockFrame::ReplacedElementISizeToClear
    7449           0 : nsBlockFrame::ISizeToClearPastFloats(const BlockReflowInput& aState,
    7450             :                                      const LogicalRect& aFloatAvailableSpace,
    7451             :                                      nsIFrame* aFrame)
    7452             : {
    7453             :   nscoord inlineStartOffset, inlineEndOffset;
    7454           0 :   WritingMode wm = aState.mReflowInput.GetWritingMode();
    7455           0 :   SizeComputationInput offsetState(aFrame, aState.mReflowInput.mRenderingContext,
    7456           0 :                                wm, aState.mContentArea.ISize(wm));
    7457             : 
    7458             :   ReplacedElementISizeToClear result;
    7459             :   aState.ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace,
    7460             :                                               inlineStartOffset,
    7461           0 :                                               inlineEndOffset);
    7462           0 :   nscoord availISize = aState.mContentArea.ISize(wm) -
    7463           0 :                        inlineStartOffset - inlineEndOffset;
    7464             : 
    7465             :   // We actually don't want the min width here; see bug 427782; we only
    7466             :   // want to displace if the width won't compute to a value small enough
    7467             :   // to fit.
    7468             :   // All we really need here is the result of ComputeSize, and we
    7469             :   // could *almost* get that from an SizeComputationInput, except for the
    7470             :   // last argument.
    7471           0 :   WritingMode frWM = aFrame->GetWritingMode();
    7472           0 :   LogicalSize availSpace = LogicalSize(wm, availISize, NS_UNCONSTRAINEDSIZE).
    7473           0 :                              ConvertTo(frWM, wm);
    7474           0 :   ReflowInput reflowInput(aState.mPresContext, aState.mReflowInput,
    7475           0 :                                 aFrame, availSpace);
    7476           0 :   result.borderBoxISize =
    7477           0 :     reflowInput.ComputedSizeWithBorderPadding().ConvertTo(wm, frWM).ISize(wm);
    7478             :   // Use the margins from offsetState rather than reflowInput so that
    7479             :   // they aren't reduced by ignoring margins in overconstrained cases.
    7480             :   LogicalMargin computedMargin =
    7481           0 :     offsetState.ComputedLogicalMargin().ConvertTo(wm, frWM);
    7482           0 :   result.marginIStart = computedMargin.IStart(wm);
    7483           0 :   return result;
    7484             : }
    7485             : 
    7486             : /* static */
    7487             : nsBlockFrame*
    7488           0 : nsBlockFrame::GetNearestAncestorBlock(nsIFrame* aCandidate)
    7489             : {
    7490           0 :   nsBlockFrame* block = nullptr;
    7491           0 :   while(aCandidate) {
    7492           0 :     block = nsLayoutUtils::GetAsBlock(aCandidate);
    7493           0 :     if (block) {
    7494             :       // yay, candidate is a block!
    7495           0 :       return block;
    7496             :     }
    7497             :     // Not a block. Check its parent next.
    7498           0 :     aCandidate = aCandidate->GetParent();
    7499             :   }
    7500           0 :   NS_NOTREACHED("Fell off frame tree looking for ancestor block!");
    7501           0 :   return nullptr;
    7502             : }
    7503             : 
    7504             : void
    7505          44 : nsBlockFrame::ComputeFinalBSize(const ReflowInput& aReflowInput,
    7506             :                                 nsReflowStatus*          aStatus,
    7507             :                                 nscoord                  aContentBSize,
    7508             :                                 const LogicalMargin&     aBorderPadding,
    7509             :                                 LogicalSize&             aFinalSize,
    7510             :                                 nscoord                  aConsumed)
    7511             : {
    7512          44 :   WritingMode wm = aReflowInput.GetWritingMode();
    7513             :   // Figure out how much of the computed height should be
    7514             :   // applied to this frame.
    7515          44 :   nscoord computedBSizeLeftOver = GetEffectiveComputedBSize(aReflowInput,
    7516          44 :                                                             aConsumed);
    7517          44 :   NS_ASSERTION(!( IS_TRUE_OVERFLOW_CONTAINER(this)
    7518             :                   && computedBSizeLeftOver ),
    7519             :                "overflow container must not have computedBSizeLeftOver");
    7520             : 
    7521          88 :   aFinalSize.BSize(wm) =
    7522          44 :     NSCoordSaturatingAdd(NSCoordSaturatingAdd(aBorderPadding.BStart(wm),
    7523             :                                               computedBSizeLeftOver),
    7524             :                          aBorderPadding.BEnd(wm));
    7525             : 
    7526          44 :   if (aStatus->IsIncomplete() &&
    7527           0 :       aFinalSize.BSize(wm) < aReflowInput.AvailableBSize()) {
    7528             :     // We fit in the available space - change status to OVERFLOW_INCOMPLETE.
    7529             :     // XXXmats why didn't Reflow report OVERFLOW_INCOMPLETE in the first place?
    7530             :     // XXXmats and why exclude the case when our size == AvailableBSize?
    7531           0 :     aStatus->SetOverflowIncomplete();
    7532             :   }
    7533             : 
    7534          44 :   if (aStatus->IsComplete()) {
    7535          88 :     if (computedBSizeLeftOver > 0 &&
    7536          44 :         NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableBSize() &&
    7537           0 :         aFinalSize.BSize(wm) > aReflowInput.AvailableBSize()) {
    7538           0 :       if (ShouldAvoidBreakInside(aReflowInput)) {
    7539           0 :         aStatus->SetInlineLineBreakBeforeAndReset();
    7540           0 :         return;
    7541             :       }
    7542             :       // We don't fit and we consumed some of the computed height,
    7543             :       // so we should consume all the available height and then
    7544             :       // break.  If our bottom border/padding straddles the break
    7545             :       // point, then this will increase our height and push the
    7546             :       // border/padding to the next page/column.
    7547           0 :       aFinalSize.BSize(wm) = std::max(aReflowInput.AvailableBSize(),
    7548           0 :                                       aContentBSize);
    7549           0 :       aStatus->SetIncomplete();
    7550           0 :       if (!GetNextInFlow())
    7551           0 :         aStatus->SetNextInFlowNeedsReflow();
    7552             :     }
    7553             :   }
    7554             : }
    7555             : 
    7556             : nsresult
    7557         229 : nsBlockFrame::ResolveBidi()
    7558             : {
    7559         229 :   NS_ASSERTION(!GetPrevInFlow(),
    7560             :                "ResolveBidi called on non-first continuation");
    7561             : 
    7562         229 :   nsPresContext* presContext = PresContext();
    7563         229 :   if (!presContext->BidiEnabled()) {
    7564         229 :     return NS_OK;
    7565             :   }
    7566             : 
    7567           0 :   return nsBidiPresUtils::Resolve(this);
    7568             : }
    7569             : 
    7570             : void
    7571           0 : nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState)
    7572             : {
    7573           0 :   if (nsBulletFrame* bullet = GetBullet()) {
    7574           0 :     CSSPseudoElementType type = bullet->StyleContext()->GetPseudoType();
    7575             :     RefPtr<nsStyleContext> newBulletStyle =
    7576           0 :       ResolveBulletStyle(type, &aRestyleState.StyleSet());
    7577           0 :     UpdateStyleOfOwnedChildFrame(bullet, newBulletStyle, aRestyleState);
    7578             :   }
    7579           0 : }
    7580             : 
    7581             : already_AddRefed<nsStyleContext>
    7582           0 : nsBlockFrame::ResolveBulletStyle(CSSPseudoElementType aType,
    7583             :                                  StyleSetHandle aStyleSet)
    7584             : {
    7585             :   nsStyleContext* parentStyle =
    7586             :     CorrectStyleParentFrame(this,
    7587             :                             nsCSSPseudoElements::GetPseudoAtom(aType))->
    7588           0 :     StyleContext();
    7589             : 
    7590           0 :   return aStyleSet->ResolvePseudoElementStyle(mContent->AsElement(), aType,
    7591           0 :                                               parentStyle, nullptr);
    7592             : }
    7593             : 
    7594             : nsIFrame*
    7595           0 : nsBlockFrame::GetFirstLetter() const
    7596             : {
    7597           0 :   if (!(GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE)) {
    7598             :     // Certainly no first-letter frame.
    7599           0 :     return nullptr;
    7600             :   }
    7601             : 
    7602           0 :   return GetProperty(FirstLetterProperty());
    7603             : }
    7604             : 
    7605             : #ifdef DEBUG
    7606             : void
    7607         211 : nsBlockFrame::VerifyLines(bool aFinalCheckOK)
    7608             : {
    7609         211 :   if (!gVerifyLines) {
    7610         422 :     return;
    7611             :   }
    7612           0 :   if (mLines.empty()) {
    7613           0 :     return;
    7614             :   }
    7615             : 
    7616           0 :   nsLineBox* cursor = GetLineCursor();
    7617             : 
    7618             :   // Add up the counts on each line. Also validate that IsFirstLine is
    7619             :   // set properly.
    7620           0 :   int32_t count = 0;
    7621           0 :   LineIterator line, line_end;
    7622           0 :   for (line = LinesBegin(), line_end = LinesEnd();
    7623             :        line != line_end;
    7624             :        ++line) {
    7625           0 :     if (line == cursor) {
    7626           0 :       cursor = nullptr;
    7627             :     }
    7628           0 :     if (aFinalCheckOK) {
    7629           0 :       MOZ_ASSERT(line->GetChildCount(), "empty line");
    7630           0 :       if (line->IsBlock()) {
    7631           0 :         NS_ASSERTION(1 == line->GetChildCount(), "bad first line");
    7632             :       }
    7633             :     }
    7634           0 :     count += line->GetChildCount();
    7635             :   }
    7636             : 
    7637             :   // Then count the frames
    7638           0 :   int32_t frameCount = 0;
    7639           0 :   nsIFrame* frame = mLines.front()->mFirstChild;
    7640           0 :   while (frame) {
    7641           0 :     frameCount++;
    7642           0 :     frame = frame->GetNextSibling();
    7643             :   }
    7644           0 :   NS_ASSERTION(count == frameCount, "bad line list");
    7645             : 
    7646             :   // Next: test that each line has right number of frames on it
    7647           0 :   for (line = LinesBegin(), line_end = LinesEnd();
    7648             :        line != line_end;
    7649             :         ) {
    7650           0 :     count = line->GetChildCount();
    7651           0 :     frame = line->mFirstChild;
    7652           0 :     while (--count >= 0) {
    7653           0 :       frame = frame->GetNextSibling();
    7654             :     }
    7655           0 :     ++line;
    7656           0 :     if ((line != line_end) && (0 != line->GetChildCount())) {
    7657           0 :       NS_ASSERTION(frame == line->mFirstChild, "bad line list");
    7658             :     }
    7659             :   }
    7660             : 
    7661           0 :   if (cursor) {
    7662           0 :     FrameLines* overflowLines = GetOverflowLines();
    7663           0 :     if (overflowLines) {
    7664           0 :       LineIterator line = overflowLines->mLines.begin();
    7665           0 :       LineIterator line_end = overflowLines->mLines.end();
    7666           0 :       for (; line != line_end; ++line) {
    7667           0 :         if (line == cursor) {
    7668           0 :           cursor = nullptr;
    7669           0 :           break;
    7670             :         }
    7671             :       }
    7672             :     }
    7673             :   }
    7674           0 :   NS_ASSERTION(!cursor, "stale LineCursorProperty");
    7675             : }
    7676             : 
    7677             : void
    7678         330 : nsBlockFrame::VerifyOverflowSituation()
    7679             : {
    7680             :   // Overflow out-of-flows must not have a next-in-flow in mFloats or mFrames.
    7681         330 :   nsFrameList* oofs = GetOverflowOutOfFlows() ;
    7682         330 :   if (oofs) {
    7683           0 :     for (nsFrameList::Enumerator e(*oofs); !e.AtEnd(); e.Next()) {
    7684           0 :       nsIFrame* nif = e.get()->GetNextInFlow();
    7685           0 :       MOZ_ASSERT(!nif || (!mFloats.ContainsFrame(nif) && !mFrames.ContainsFrame(nif)));
    7686             :     }
    7687             :   }
    7688             : 
    7689             :   // Pushed floats must not have a next-in-flow in mFloats or mFrames.
    7690         330 :   oofs = GetPushedFloats();
    7691         330 :   if (oofs) {
    7692           0 :     for (nsFrameList::Enumerator e(*oofs); !e.AtEnd(); e.Next()) {
    7693           0 :       nsIFrame* nif = e.get()->GetNextInFlow();
    7694           0 :       MOZ_ASSERT(!nif || (!mFloats.ContainsFrame(nif) && !mFrames.ContainsFrame(nif)));
    7695             :     }
    7696             :   }
    7697             : 
    7698             :   // A child float next-in-flow's parent must be |this| or a next-in-flow of |this|.
    7699             :   // Later next-in-flows must have the same or later parents.
    7700             :   nsIFrame::ChildListID childLists[] = { nsIFrame::kFloatList,
    7701         330 :                                          nsIFrame::kPushedFloatsList };
    7702         990 :   for (size_t i = 0; i < ArrayLength(childLists); ++i) {
    7703         660 :     nsFrameList children(GetChildList(childLists[i]));
    7704         660 :     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
    7705           0 :       nsIFrame* parent = this;
    7706           0 :       nsIFrame* nif = e.get()->GetNextInFlow();
    7707           0 :       for (; nif; nif = nif->GetNextInFlow()) {
    7708           0 :         bool found = false;
    7709           0 :         for (nsIFrame* p = parent; p; p = p->GetNextInFlow()) {
    7710           0 :           if (nif->GetParent() == p) {
    7711           0 :             parent = p;
    7712           0 :             found = true;
    7713           0 :             break;
    7714             :           }
    7715             :         }
    7716           0 :         MOZ_ASSERT(found, "next-in-flow is a child of parent earlier in the frame tree?");
    7717             :       }
    7718             :     }
    7719             :   }
    7720             : 
    7721         330 :   nsBlockFrame* flow = static_cast<nsBlockFrame*>(FirstInFlow());
    7722         990 :   while (flow) {
    7723         330 :     FrameLines* overflowLines = flow->GetOverflowLines();
    7724         330 :     if (overflowLines) {
    7725           0 :       NS_ASSERTION(!overflowLines->mLines.empty(),
    7726             :                    "should not be empty if present");
    7727           0 :       NS_ASSERTION(overflowLines->mLines.front()->mFirstChild,
    7728             :                    "bad overflow lines");
    7729           0 :       NS_ASSERTION(overflowLines->mLines.front()->mFirstChild ==
    7730             :                    overflowLines->mFrames.FirstChild(),
    7731             :                    "bad overflow frames / lines");
    7732             :     }
    7733         330 :     nsLineBox* cursor = flow->GetLineCursor();
    7734         330 :     if (cursor) {
    7735           0 :       LineIterator line = flow->LinesBegin();
    7736           0 :       LineIterator line_end = flow->LinesEnd();
    7737           0 :       for (; line != line_end && line != cursor; ++line)
    7738             :         ;
    7739           0 :       if (line == line_end && overflowLines) {
    7740           0 :         line = overflowLines->mLines.begin();
    7741           0 :         line_end = overflowLines->mLines.end();
    7742           0 :         for (; line != line_end && line != cursor; ++line)
    7743             :           ;
    7744             :         }
    7745           0 :       MOZ_ASSERT(line != line_end, "stale LineCursorProperty");
    7746             :     }
    7747         330 :     flow = static_cast<nsBlockFrame*>(flow->GetNextInFlow());
    7748             :   }
    7749         330 : }
    7750             : 
    7751             : int32_t
    7752           0 : nsBlockFrame::GetDepth() const
    7753             : {
    7754           0 :   int32_t depth = 0;
    7755           0 :   nsIFrame* parent = GetParent();
    7756           0 :   while (parent) {
    7757           0 :     parent = parent->GetParent();
    7758           0 :     depth++;
    7759             :   }
    7760           0 :   return depth;
    7761             : }
    7762             : 
    7763             : already_AddRefed<nsStyleContext>
    7764          26 : nsBlockFrame::GetFirstLetterStyle(nsPresContext* aPresContext)
    7765             : {
    7766          52 :   return aPresContext->StyleSet()->
    7767          26 :     ProbePseudoElementStyle(mContent->AsElement(),
    7768             :                             CSSPseudoElementType::firstLetter,
    7769         104 :                             mStyleContext);
    7770             : }
    7771             : #endif

Generated by: LCOV version 1.13