LCOV - app.info - layout/generic/nsBlockFrame.cpp

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