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

Generated by: LCOV version 1.7