LCOV - code coverage report
Current view: directory - layout/generic - nsBlockFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2973 0 0.0 %
Date: 2012-06-02 Functions: 154 0 0.0 %

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

Generated by: LCOV version 1.7