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

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Steve Clark <buster@netscape.com>
      24                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *   L. David Baron <dbaron@dbaron.org>
      26                 :  *   Robert O'Callahan <roc+moz@cs.cmu.edu>
      27                 :  *   IBM Corporation
      28                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      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                 : /* state and methods used while laying out a single line of a block frame */
      45                 : 
      46                 : #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
      47                 : #include "plarena.h"
      48                 : 
      49                 : #include "mozilla/Util.h"
      50                 : #include "nsCOMPtr.h"
      51                 : #include "nsLineLayout.h"
      52                 : #include "nsBlockFrame.h"
      53                 : #include "nsInlineFrame.h"
      54                 : #include "nsStyleConsts.h"
      55                 : #include "nsContainerFrame.h"
      56                 : #include "nsFloatManager.h"
      57                 : #include "nsStyleContext.h"
      58                 : #include "nsPresContext.h"
      59                 : #include "nsRenderingContext.h"
      60                 : #include "nsGkAtoms.h"
      61                 : #include "nsPlaceholderFrame.h"
      62                 : #include "nsIDocument.h"
      63                 : #include "nsIHTMLDocument.h"
      64                 : #include "nsIContent.h"
      65                 : #include "nsTextFragment.h"
      66                 : #include "nsBidiUtils.h"
      67                 : #include "nsLayoutUtils.h"
      68                 : #include "nsTextFrame.h"
      69                 : #include "nsCSSRendering.h"
      70                 : 
      71                 : #ifdef DEBUG
      72                 : #undef  NOISY_HORIZONTAL_ALIGN
      73                 : #undef  NOISY_VERTICAL_ALIGN
      74                 : #undef  REALLY_NOISY_VERTICAL_ALIGN
      75                 : #undef  NOISY_REFLOW
      76                 : #undef  REALLY_NOISY_REFLOW
      77                 : #undef  NOISY_PUSHING
      78                 : #undef  REALLY_NOISY_PUSHING
      79                 : #undef  DEBUG_ADD_TEXT
      80                 : #undef  NOISY_MAX_ELEMENT_SIZE
      81                 : #undef  REALLY_NOISY_MAX_ELEMENT_SIZE
      82                 : #undef  NOISY_CAN_PLACE_FRAME
      83                 : #undef  NOISY_TRIM
      84                 : #undef  REALLY_NOISY_TRIM
      85                 : #endif
      86                 : 
      87                 : using namespace mozilla;
      88                 : 
      89                 : //----------------------------------------------------------------------
      90                 : 
      91                 : #define FIX_BUG_50257
      92                 : 
      93               0 : nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
      94                 :                            nsFloatManager* aFloatManager,
      95                 :                            const nsHTMLReflowState* aOuterReflowState,
      96                 :                            const nsLineList::iterator* aLine)
      97                 :   : mPresContext(aPresContext),
      98                 :     mFloatManager(aFloatManager),
      99                 :     mBlockReflowState(aOuterReflowState),
     100                 :     mLastOptionalBreakContent(nsnull),
     101                 :     mForceBreakContent(nsnull),
     102                 :     mBlockRS(nsnull),/* XXX temporary */
     103                 :     mLastOptionalBreakPriority(eNoBreak),
     104                 :     mLastOptionalBreakContentOffset(-1),
     105                 :     mForceBreakContentOffset(-1),
     106                 :     mMinLineHeight(0),
     107               0 :     mTextIndent(0)
     108                 : {
     109               0 :   NS_ASSERTION(aFloatManager || aOuterReflowState->frame->GetType() ==
     110                 :                                   nsGkAtoms::letterFrame,
     111                 :                "float manager should be present");
     112               0 :   MOZ_COUNT_CTOR(nsLineLayout);
     113                 : 
     114                 :   // Stash away some style data that we need
     115               0 :   mStyleText = aOuterReflowState->frame->GetStyleText();
     116               0 :   mLineNumber = 0;
     117               0 :   mFlags = 0; // default all flags to false except those that follow here...
     118               0 :   mTotalPlacedFrames = 0;
     119               0 :   mTopEdge = 0;
     120               0 :   mTrimmableWidth = 0;
     121                 : 
     122                 :   mInflationMinFontSize =
     123                 :     nsLayoutUtils::InflationMinFontSizeFor(aOuterReflowState->frame,
     124               0 :                                            nsLayoutUtils::eInReflow);
     125                 : 
     126                 :   // Instead of always pre-initializing the free-lists for frames and
     127                 :   // spans, we do it on demand so that situations that only use a few
     128                 :   // frames and spans won't waste a lot of time in unneeded
     129                 :   // initialization.
     130               0 :   PL_INIT_ARENA_POOL(&mArena, "nsLineLayout", 1024);
     131               0 :   mFrameFreeList = nsnull;
     132               0 :   mSpanFreeList = nsnull;
     133                 : 
     134               0 :   mCurrentSpan = mRootSpan = nsnull;
     135               0 :   mSpanDepth = 0;
     136                 : 
     137               0 :   if (aLine) {
     138               0 :     SetFlag(LL_GOTLINEBOX, true);
     139               0 :     mLineBox = *aLine;
     140                 :   }
     141               0 : }
     142                 : 
     143               0 : nsLineLayout::~nsLineLayout()
     144                 : {
     145               0 :   MOZ_COUNT_DTOR(nsLineLayout);
     146                 : 
     147               0 :   NS_ASSERTION(nsnull == mRootSpan, "bad line-layout user");
     148                 : 
     149                 :   // PL_FreeArenaPool takes our memory and puts in on a global free list so
     150                 :   // that the next time an arena makes an allocation it will not have to go
     151                 :   // all the way down to malloc.  This is desirable as this class is created
     152                 :   // and destroyed in a tight loop.
     153                 :   //
     154                 :   // I looked at the code.  It is not technically necessary to call
     155                 :   // PL_FinishArenaPool() after PL_FreeArenaPool(), but from an API
     156                 :   // standpoint, I think we are susposed to.  It will be very fast anyway,
     157                 :   // since PL_FreeArenaPool() has done all the work.
     158               0 :   PL_FreeArenaPool(&mArena);
     159               0 :   PL_FinishArenaPool(&mArena);
     160               0 : }
     161                 : 
     162                 : // Find out if the frame has a non-null prev-in-flow, i.e., whether it
     163                 : // is a continuation.
     164                 : inline bool
     165               0 : HasPrevInFlow(nsIFrame *aFrame)
     166                 : {
     167               0 :   nsIFrame *prevInFlow = aFrame->GetPrevInFlow();
     168               0 :   return prevInFlow != nsnull;
     169                 : }
     170                 : 
     171                 : void
     172               0 : nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
     173                 :                               nscoord aWidth, nscoord aHeight,
     174                 :                               bool aImpactedByFloats,
     175                 :                               bool aIsTopOfPage,
     176                 :                               PRUint8 aDirection)
     177                 : {
     178               0 :   NS_ASSERTION(nsnull == mRootSpan, "bad linelayout user");
     179               0 :   NS_WARN_IF_FALSE(aWidth != NS_UNCONSTRAINEDSIZE,
     180                 :                    "have unconstrained width; this should only result from "
     181                 :                    "very large sizes, not attempts at intrinsic width "
     182                 :                    "calculation");
     183                 : #ifdef DEBUG
     184               0 :   if ((aWidth != NS_UNCONSTRAINEDSIZE) && CRAZY_WIDTH(aWidth)) {
     185               0 :     nsFrame::ListTag(stdout, mBlockReflowState->frame);
     186                 :     printf(": Init: bad caller: width WAS %d(0x%x)\n",
     187               0 :            aWidth, aWidth);
     188                 :   }
     189               0 :   if ((aHeight != NS_UNCONSTRAINEDSIZE) && CRAZY_HEIGHT(aHeight)) {
     190               0 :     nsFrame::ListTag(stdout, mBlockReflowState->frame);
     191                 :     printf(": Init: bad caller: height WAS %d(0x%x)\n",
     192               0 :            aHeight, aHeight);
     193                 :   }
     194                 : #endif
     195                 : #ifdef NOISY_REFLOW
     196                 :   nsFrame::ListTag(stdout, mBlockReflowState->frame);
     197                 :   printf(": BeginLineReflow: %d,%d,%d,%d impacted=%s %s\n",
     198                 :          aX, aY, aWidth, aHeight,
     199                 :          aImpactedByFloats?"true":"false",
     200                 :          aIsTopOfPage ? "top-of-page" : "");
     201                 : #endif
     202                 : #ifdef DEBUG
     203               0 :   mSpansAllocated = mSpansFreed = mFramesAllocated = mFramesFreed = 0;
     204                 : #endif
     205                 : 
     206               0 :   SetFlag(LL_FIRSTLETTERSTYLEOK, false);
     207               0 :   SetFlag(LL_ISTOPOFPAGE, aIsTopOfPage);
     208               0 :   SetFlag(LL_IMPACTEDBYFLOATS, aImpactedByFloats);
     209               0 :   mTotalPlacedFrames = 0;
     210               0 :   SetFlag(LL_LINEISEMPTY, true);
     211               0 :   SetFlag(LL_LINEATSTART, true);
     212               0 :   SetFlag(LL_LINEENDSINBR, false);
     213               0 :   mSpanDepth = 0;
     214               0 :   mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
     215                 : 
     216               0 :   if (GetFlag(LL_GOTLINEBOX)) {
     217               0 :     mLineBox->ClearHasBullet();
     218                 :   }
     219                 : 
     220                 :   PerSpanData* psd;
     221               0 :   NewPerSpanData(&psd);
     222               0 :   mCurrentSpan = mRootSpan = psd;
     223               0 :   psd->mReflowState = mBlockReflowState;
     224               0 :   psd->mLeftEdge = aX;
     225               0 :   psd->mX = aX;
     226               0 :   psd->mRightEdge = aX + aWidth;
     227                 : 
     228               0 :   mTopEdge = aY;
     229                 : 
     230               0 :   psd->mNoWrap = !mStyleText->WhiteSpaceCanWrap();
     231               0 :   psd->mDirection = aDirection;
     232               0 :   psd->mChangedFrameDirection = false;
     233                 : 
     234                 :   // If this is the first line of a block then see if the text-indent
     235                 :   // property amounts to anything.
     236                 : 
     237               0 :   if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowState->frame)) {
     238               0 :     const nsStyleCoord &textIndent = mStyleText->mTextIndent;
     239               0 :     nscoord pctBasis = 0;
     240               0 :     if (textIndent.HasPercent()) {
     241                 :       pctBasis =
     242               0 :         nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState);
     243                 : 
     244               0 :       if (GetFlag(LL_GOTLINEBOX)) {
     245               0 :         mLineBox->DisableResizeReflowOptimization();
     246                 :       }
     247                 :     }
     248               0 :     nscoord indent = nsRuleNode::ComputeCoordPercentCalc(textIndent, pctBasis);
     249                 : 
     250               0 :     mTextIndent = indent;
     251                 : 
     252               0 :     if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
     253               0 :       psd->mRightEdge -= indent;
     254                 :     }
     255                 :     else {
     256               0 :       psd->mX += indent;
     257                 :     }
     258                 :   }
     259               0 : }
     260                 : 
     261                 : void
     262               0 : nsLineLayout::EndLineReflow()
     263                 : {
     264                 : #ifdef NOISY_REFLOW
     265                 :   nsFrame::ListTag(stdout, mBlockReflowState->frame);
     266                 :   printf(": EndLineReflow: width=%d\n", mRootSpan->mX - mRootSpan->mLeftEdge);
     267                 : #endif
     268                 : 
     269               0 :   FreeSpan(mRootSpan);
     270               0 :   mCurrentSpan = mRootSpan = nsnull;
     271                 : 
     272               0 :   NS_ASSERTION(mSpansAllocated == mSpansFreed, "leak");
     273               0 :   NS_ASSERTION(mFramesAllocated == mFramesFreed, "leak");
     274                 : 
     275                 : #if 0
     276                 :   static PRInt32 maxSpansAllocated = NS_LINELAYOUT_NUM_SPANS;
     277                 :   static PRInt32 maxFramesAllocated = NS_LINELAYOUT_NUM_FRAMES;
     278                 :   if (mSpansAllocated > maxSpansAllocated) {
     279                 :     printf("XXX: saw a line with %d spans\n", mSpansAllocated);
     280                 :     maxSpansAllocated = mSpansAllocated;
     281                 :   }
     282                 :   if (mFramesAllocated > maxFramesAllocated) {
     283                 :     printf("XXX: saw a line with %d frames\n", mFramesAllocated);
     284                 :     maxFramesAllocated = mFramesAllocated;
     285                 :   }
     286                 : #endif
     287               0 : }
     288                 : 
     289                 : // XXX swtich to a single mAvailLineWidth that we adjust as each frame
     290                 : // on the line is placed. Each span can still have a per-span mX that
     291                 : // tracks where a child frame is going in its span; they don't need a
     292                 : // per-span mLeftEdge?
     293                 : 
     294                 : void
     295               0 : nsLineLayout::UpdateBand(const nsRect& aNewAvailSpace,
     296                 :                          nsIFrame* aFloatFrame)
     297                 : {
     298                 : #ifdef REALLY_NOISY_REFLOW
     299                 :   printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p\n  will set mImpacted to true\n",
     300                 :          aNewAvailSpace.x, aNewAvailSpace.y,
     301                 :          aNewAvailSpace.width, aNewAvailSpace.height,
     302                 :          aFloatFrame);
     303                 : #endif
     304                 : #ifdef DEBUG
     305               0 :   if ((aNewAvailSpace.width != NS_UNCONSTRAINEDSIZE) && CRAZY_WIDTH(aNewAvailSpace.width)) {
     306               0 :     nsFrame::ListTag(stdout, mBlockReflowState->frame);
     307                 :     printf(": UpdateBand: bad caller: width WAS %d(0x%x)\n",
     308               0 :            aNewAvailSpace.width, aNewAvailSpace.width);
     309                 :   }
     310               0 :   if ((aNewAvailSpace.height != NS_UNCONSTRAINEDSIZE) && CRAZY_HEIGHT(aNewAvailSpace.height)) {
     311               0 :     nsFrame::ListTag(stdout, mBlockReflowState->frame);
     312                 :     printf(": UpdateBand: bad caller: height WAS %d(0x%x)\n",
     313               0 :            aNewAvailSpace.height, aNewAvailSpace.height);
     314                 :   }
     315                 : #endif
     316                 : 
     317                 :   // Compute the difference between last times width and the new width
     318               0 :   NS_WARN_IF_FALSE(mRootSpan->mRightEdge != NS_UNCONSTRAINEDSIZE &&
     319                 :                    aNewAvailSpace.width != NS_UNCONSTRAINEDSIZE,
     320                 :                    "have unconstrained width; this should only result from "
     321                 :                    "very large sizes, not attempts at intrinsic width "
     322                 :                    "calculation");
     323                 :   // The root span's mLeftEdge moves to aX
     324               0 :   nscoord deltaX = aNewAvailSpace.x - mRootSpan->mLeftEdge;
     325                 :   // The width of all spans changes by this much (the root span's
     326                 :   // mRightEdge moves to aX + aWidth, its new width is aWidth)
     327               0 :   nscoord deltaWidth = aNewAvailSpace.width - (mRootSpan->mRightEdge - mRootSpan->mLeftEdge);
     328                 : #ifdef NOISY_REFLOW
     329                 :   nsFrame::ListTag(stdout, mBlockReflowState->frame);
     330                 :   printf(": UpdateBand: %d,%d,%d,%d deltaWidth=%d deltaX=%d\n",
     331                 :          aNewAvailSpace.x, aNewAvailSpace.y,
     332                 :          aNewAvailSpace.width, aNewAvailSpace.height, deltaWidth, deltaX);
     333                 : #endif
     334                 : 
     335                 :   // Update the root span position
     336               0 :   mRootSpan->mLeftEdge += deltaX;
     337               0 :   mRootSpan->mRightEdge += deltaX;
     338               0 :   mRootSpan->mX += deltaX;
     339                 : 
     340                 :   // Now update the right edges of the open spans to account for any
     341                 :   // change in available space width
     342               0 :   for (PerSpanData* psd = mCurrentSpan; psd; psd = psd->mParent) {
     343               0 :     psd->mRightEdge += deltaWidth;
     344               0 :     psd->mContainsFloat = true;
     345               0 :     NS_ASSERTION(psd->mX - mTrimmableWidth <= psd->mRightEdge,
     346                 :                  "We placed a float where there was no room!");
     347                 : #ifdef NOISY_REFLOW
     348                 :     printf("  span %p: oldRightEdge=%d newRightEdge=%d\n",
     349                 :            psd, psd->mRightEdge - deltaRightEdge, psd->mRightEdge);
     350                 : #endif
     351                 :   }
     352               0 :   NS_ASSERTION(mRootSpan->mContainsFloat &&
     353                 :                mRootSpan->mLeftEdge == aNewAvailSpace.x &&
     354                 :                mRootSpan->mRightEdge == aNewAvailSpace.XMost(),
     355                 :                "root span was updated incorrectly?");
     356                 : 
     357                 :   // Update frame bounds
     358                 :   // Note: Only adjust the outermost frames (the ones that are direct
     359                 :   // children of the block), not the ones in the child spans. The reason
     360                 :   // is simple: the frames in the spans have coordinates local to their
     361                 :   // parent therefore they are moved when their parent span is moved.
     362               0 :   if (deltaX != 0) {
     363               0 :     for (PerFrameData* pfd = mRootSpan->mFirstFrame; pfd; pfd = pfd->mNext) {
     364               0 :       pfd->mBounds.x += deltaX;
     365                 :     }
     366                 :   }
     367                 : 
     368               0 :   mTopEdge = aNewAvailSpace.y;
     369               0 :   SetFlag(LL_IMPACTEDBYFLOATS, true);
     370                 : 
     371                 :   SetFlag(LL_LASTFLOATWASLETTERFRAME,
     372               0 :           nsGkAtoms::letterFrame == aFloatFrame->GetType());
     373               0 : }
     374                 : 
     375                 : nsresult
     376               0 : nsLineLayout::NewPerSpanData(PerSpanData** aResult)
     377                 : {
     378               0 :   PerSpanData* psd = mSpanFreeList;
     379               0 :   if (nsnull == psd) {
     380                 :     void *mem;
     381               0 :     PL_ARENA_ALLOCATE(mem, &mArena, sizeof(PerSpanData));
     382               0 :     if (nsnull == mem) {
     383               0 :       return NS_ERROR_OUT_OF_MEMORY;
     384                 :     }
     385               0 :     psd = reinterpret_cast<PerSpanData*>(mem);
     386                 :   }
     387                 :   else {
     388               0 :     mSpanFreeList = psd->mNextFreeSpan;
     389                 :   }
     390               0 :   psd->mParent = nsnull;
     391               0 :   psd->mFrame = nsnull;
     392               0 :   psd->mFirstFrame = nsnull;
     393               0 :   psd->mLastFrame = nsnull;
     394               0 :   psd->mContainsFloat = false;
     395               0 :   psd->mZeroEffectiveSpanBox = false;
     396               0 :   psd->mHasNonemptyContent = false;
     397                 : 
     398                 : #ifdef DEBUG
     399               0 :   mSpansAllocated++;
     400                 : #endif
     401               0 :   *aResult = psd;
     402               0 :   return NS_OK;
     403                 : }
     404                 : 
     405                 : nsresult
     406               0 : nsLineLayout::BeginSpan(nsIFrame* aFrame,
     407                 :                         const nsHTMLReflowState* aSpanReflowState,
     408                 :                         nscoord aLeftEdge,
     409                 :                         nscoord aRightEdge,
     410                 :                         nscoord* aBaseline)
     411                 : {
     412               0 :   NS_ASSERTION(aRightEdge != NS_UNCONSTRAINEDSIZE,
     413                 :                "should no longer be using unconstrained sizes");
     414                 : #ifdef NOISY_REFLOW
     415                 :   nsFrame::IndentBy(stdout, mSpanDepth+1);
     416                 :   nsFrame::ListTag(stdout, aFrame);
     417                 :   printf(": BeginSpan leftEdge=%d rightEdge=%d\n", aLeftEdge, aRightEdge);
     418                 : #endif
     419                 : 
     420                 :   PerSpanData* psd;
     421               0 :   nsresult rv = NewPerSpanData(&psd);
     422               0 :   if (NS_SUCCEEDED(rv)) {
     423                 :     // Link up span frame's pfd to point to its child span data
     424               0 :     PerFrameData* pfd = mCurrentSpan->mLastFrame;
     425               0 :     NS_ASSERTION(pfd->mFrame == aFrame, "huh?");
     426               0 :     pfd->mSpan = psd;
     427                 : 
     428                 :     // Init new span
     429               0 :     psd->mFrame = pfd;
     430               0 :     psd->mParent = mCurrentSpan;
     431               0 :     psd->mReflowState = aSpanReflowState;
     432               0 :     psd->mLeftEdge = aLeftEdge;
     433               0 :     psd->mX = aLeftEdge;
     434               0 :     psd->mRightEdge = aRightEdge;
     435               0 :     psd->mBaseline = aBaseline;
     436                 : 
     437                 :     psd->mNoWrap =
     438               0 :       !aSpanReflowState->frame->GetStyleText()->WhiteSpaceCanWrap();
     439               0 :     psd->mDirection = aSpanReflowState->mStyleVisibility->mDirection;
     440               0 :     psd->mChangedFrameDirection = false;
     441                 : 
     442                 :     // Switch to new span
     443               0 :     mCurrentSpan = psd;
     444               0 :     mSpanDepth++;
     445                 :   }
     446               0 :   return rv;
     447                 : }
     448                 : 
     449                 : nscoord
     450               0 : nsLineLayout::EndSpan(nsIFrame* aFrame)
     451                 : {
     452               0 :   NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span");
     453                 : #ifdef NOISY_REFLOW
     454                 :   nsFrame::IndentBy(stdout, mSpanDepth);
     455                 :   nsFrame::ListTag(stdout, aFrame);
     456                 :   printf(": EndSpan width=%d\n", mCurrentSpan->mX - mCurrentSpan->mLeftEdge);
     457                 : #endif
     458               0 :   PerSpanData* psd = mCurrentSpan;
     459               0 :   nscoord widthResult = psd->mLastFrame ? (psd->mX - psd->mLeftEdge) : 0;
     460                 : 
     461               0 :   mSpanDepth--;
     462               0 :   mCurrentSpan->mReflowState = nsnull;  // no longer valid so null it out!
     463               0 :   mCurrentSpan = mCurrentSpan->mParent;
     464               0 :   return widthResult;
     465                 : }
     466                 : 
     467                 : PRInt32
     468               0 : nsLineLayout::GetCurrentSpanCount() const
     469                 : {
     470               0 :   NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
     471               0 :   PRInt32 count = 0;
     472               0 :   PerFrameData* pfd = mRootSpan->mFirstFrame;
     473               0 :   while (nsnull != pfd) {
     474               0 :     count++;
     475               0 :     pfd = pfd->mNext;
     476                 :   }
     477               0 :   return count;
     478                 : }
     479                 : 
     480                 : void
     481               0 : nsLineLayout::SplitLineTo(PRInt32 aNewCount)
     482                 : {
     483               0 :   NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
     484                 : 
     485                 : #ifdef REALLY_NOISY_PUSHING
     486                 :   printf("SplitLineTo %d (current count=%d); before:\n", aNewCount,
     487                 :          GetCurrentSpanCount());
     488                 :   DumpPerSpanData(mRootSpan, 1);
     489                 : #endif
     490               0 :   PerSpanData* psd = mRootSpan;
     491               0 :   PerFrameData* pfd = psd->mFirstFrame;
     492               0 :   while (nsnull != pfd) {
     493               0 :     if (--aNewCount == 0) {
     494                 :       // Truncate list at pfd (we keep pfd, but anything following is freed)
     495               0 :       PerFrameData* next = pfd->mNext;
     496               0 :       pfd->mNext = nsnull;
     497               0 :       psd->mLastFrame = pfd;
     498                 : 
     499                 :       // Now release all of the frames following pfd
     500               0 :       pfd = next;
     501               0 :       while (nsnull != pfd) {
     502               0 :         next = pfd->mNext;
     503               0 :         pfd->mNext = mFrameFreeList;
     504               0 :         mFrameFreeList = pfd;
     505                 : #ifdef DEBUG
     506               0 :         mFramesFreed++;
     507                 : #endif
     508               0 :         if (nsnull != pfd->mSpan) {
     509               0 :           FreeSpan(pfd->mSpan);
     510                 :         }
     511               0 :         pfd = next;
     512                 :       }
     513               0 :       break;
     514                 :     }
     515               0 :     pfd = pfd->mNext;
     516                 :   }
     517                 : #ifdef NOISY_PUSHING
     518                 :   printf("SplitLineTo %d (current count=%d); after:\n", aNewCount,
     519                 :          GetCurrentSpanCount());
     520                 :   DumpPerSpanData(mRootSpan, 1);
     521                 : #endif
     522               0 : }
     523                 : 
     524                 : void
     525               0 : nsLineLayout::PushFrame(nsIFrame* aFrame)
     526                 : {
     527               0 :   PerSpanData* psd = mCurrentSpan;
     528               0 :   NS_ASSERTION(psd->mLastFrame->mFrame == aFrame, "pushing non-last frame");
     529                 : 
     530                 : #ifdef REALLY_NOISY_PUSHING
     531                 :   nsFrame::IndentBy(stdout, mSpanDepth);
     532                 :   printf("PushFrame %p, before:\n", psd);
     533                 :   DumpPerSpanData(psd, 1);
     534                 : #endif
     535                 : 
     536                 :   // Take the last frame off of the span's frame list
     537               0 :   PerFrameData* pfd = psd->mLastFrame;
     538               0 :   if (pfd == psd->mFirstFrame) {
     539                 :     // We are pushing away the only frame...empty the list
     540               0 :     psd->mFirstFrame = nsnull;
     541               0 :     psd->mLastFrame = nsnull;
     542                 :   }
     543                 :   else {
     544               0 :     PerFrameData* prevFrame = pfd->mPrev;
     545               0 :     prevFrame->mNext = nsnull;
     546               0 :     psd->mLastFrame = prevFrame;
     547                 :   }
     548                 : 
     549                 :   // Now free it, and if it has a span, free that too
     550               0 :   pfd->mNext = mFrameFreeList;
     551               0 :   mFrameFreeList = pfd;
     552                 : #ifdef DEBUG
     553               0 :   mFramesFreed++;
     554                 : #endif
     555               0 :   if (nsnull != pfd->mSpan) {
     556               0 :     FreeSpan(pfd->mSpan);
     557                 :   }
     558                 : #ifdef NOISY_PUSHING
     559                 :   nsFrame::IndentBy(stdout, mSpanDepth);
     560                 :   printf("PushFrame: %p after:\n", psd);
     561                 :   DumpPerSpanData(psd, 1);
     562                 : #endif
     563               0 : }
     564                 : 
     565                 : void
     566               0 : nsLineLayout::FreeSpan(PerSpanData* psd)
     567                 : {
     568                 :   // Free its frames
     569               0 :   PerFrameData* pfd = psd->mFirstFrame;
     570               0 :   while (nsnull != pfd) {
     571               0 :     if (nsnull != pfd->mSpan) {
     572               0 :       FreeSpan(pfd->mSpan);
     573                 :     }
     574               0 :     PerFrameData* next = pfd->mNext;
     575               0 :     pfd->mNext = mFrameFreeList;
     576               0 :     mFrameFreeList = pfd;
     577                 : #ifdef DEBUG
     578               0 :     mFramesFreed++;
     579                 : #endif
     580               0 :     pfd = next;
     581                 :   }
     582                 : 
     583                 :   // Now put the span on the free list since it's free too
     584               0 :   psd->mNextFreeSpan = mSpanFreeList;
     585               0 :   mSpanFreeList = psd;
     586                 : #ifdef DEBUG
     587               0 :   mSpansFreed++;
     588                 : #endif
     589               0 : }
     590                 : 
     591                 : bool
     592               0 : nsLineLayout::IsZeroHeight()
     593                 : {
     594               0 :   PerSpanData* psd = mCurrentSpan;
     595               0 :   PerFrameData* pfd = psd->mFirstFrame;
     596               0 :   while (nsnull != pfd) {
     597               0 :     if (0 != pfd->mBounds.height) {
     598               0 :       return false;
     599                 :     }
     600               0 :     pfd = pfd->mNext;
     601                 :   }
     602               0 :   return true;
     603                 : }
     604                 : 
     605                 : nsresult
     606               0 : nsLineLayout::NewPerFrameData(PerFrameData** aResult)
     607                 : {
     608               0 :   PerFrameData* pfd = mFrameFreeList;
     609               0 :   if (nsnull == pfd) {
     610                 :     void *mem;
     611               0 :     PL_ARENA_ALLOCATE(mem, &mArena, sizeof(PerFrameData));
     612               0 :     if (nsnull == mem) {
     613               0 :       return NS_ERROR_OUT_OF_MEMORY;
     614                 :     }
     615               0 :     pfd = reinterpret_cast<PerFrameData*>(mem);
     616                 :   }
     617                 :   else {
     618               0 :     mFrameFreeList = pfd->mNext;
     619                 :   }
     620               0 :   pfd->mSpan = nsnull;
     621               0 :   pfd->mNext = nsnull;
     622               0 :   pfd->mPrev = nsnull;
     623               0 :   pfd->mFrame = nsnull;
     624               0 :   pfd->mFlags = 0;  // all flags default to false
     625                 : 
     626                 : #ifdef DEBUG
     627               0 :   pfd->mVerticalAlign = 0xFF;
     628               0 :   mFramesAllocated++;
     629                 : #endif
     630               0 :   *aResult = pfd;
     631               0 :   return NS_OK;
     632                 : }
     633                 : 
     634                 : bool
     635               0 : nsLineLayout::LineIsBreakable() const
     636                 : {
     637                 :   // XXX mTotalPlacedFrames should go away and we should just use
     638                 :   // LL_LINEISEMPTY here instead
     639               0 :   if ((0 != mTotalPlacedFrames) || GetFlag(LL_IMPACTEDBYFLOATS)) {
     640               0 :     return true;
     641                 :   }
     642               0 :   return false;
     643                 : }
     644                 : 
     645                 : // Checks all four sides for percentage units.  This means it should
     646                 : // only be used for things (margin, padding) where percentages on top
     647                 : // and bottom depend on the *width* just like percentages on left and
     648                 : // right.
     649                 : static bool
     650               0 : HasPercentageUnitSide(const nsStyleSides& aSides)
     651                 : {
     652               0 :   NS_FOR_CSS_SIDES(side) {
     653               0 :     if (aSides.Get(side).HasPercent())
     654               0 :       return true;
     655                 :   }
     656               0 :   return false;
     657                 : }
     658                 : 
     659                 : static bool
     660               0 : IsPercentageAware(const nsIFrame* aFrame)
     661                 : {
     662               0 :   NS_ASSERTION(aFrame, "null frame is not allowed");
     663                 : 
     664               0 :   nsIAtom *fType = aFrame->GetType();
     665               0 :   if (fType == nsGkAtoms::textFrame) {
     666                 :     // None of these things can ever be true for text frames.
     667               0 :     return false;
     668                 :   }
     669                 : 
     670                 :   // Some of these things don't apply to non-replaced inline frames
     671                 :   // (that is, fType == nsGkAtoms::inlineFrame), but we won't bother making
     672                 :   // things unnecessarily complicated, since they'll probably be set
     673                 :   // quite rarely.
     674                 : 
     675               0 :   const nsStyleMargin* margin = aFrame->GetStyleMargin();
     676               0 :   if (HasPercentageUnitSide(margin->mMargin)) {
     677               0 :     return true;
     678                 :   }
     679                 : 
     680               0 :   const nsStylePadding* padding = aFrame->GetStylePadding();
     681               0 :   if (HasPercentageUnitSide(padding->mPadding)) {
     682               0 :     return true;
     683                 :   }
     684                 : 
     685                 :   // Note that borders can't be aware of percentages
     686                 : 
     687               0 :   const nsStylePosition* pos = aFrame->GetStylePosition();
     688                 : 
     689               0 :   if ((pos->WidthDependsOnContainer() &&
     690               0 :        pos->mWidth.GetUnit() != eStyleUnit_Auto) ||
     691               0 :       pos->MaxWidthDependsOnContainer() ||
     692               0 :       pos->MinWidthDependsOnContainer() ||
     693               0 :       pos->OffsetHasPercent(NS_SIDE_RIGHT) ||
     694               0 :       pos->OffsetHasPercent(NS_SIDE_LEFT)) {
     695               0 :     return true;
     696                 :   }
     697                 : 
     698               0 :   if (eStyleUnit_Auto == pos->mWidth.GetUnit()) {
     699                 :     // We need to check for frames that shrink-wrap when they're auto
     700                 :     // width.
     701               0 :     const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
     702               0 :     if (disp->mDisplay == NS_STYLE_DISPLAY_INLINE_BLOCK ||
     703                 :         disp->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE ||
     704                 :         fType == nsGkAtoms::HTMLButtonControlFrame ||
     705                 :         fType == nsGkAtoms::gfxButtonControlFrame ||
     706                 :         fType == nsGkAtoms::fieldSetFrame ||
     707                 :         fType == nsGkAtoms::comboboxDisplayFrame) {
     708               0 :       return true;
     709                 :     }
     710                 : 
     711                 :     // Per CSS 2.1, section 10.3.2:
     712                 :     //   If 'height' and 'width' both have computed values of 'auto' and
     713                 :     //   the element has an intrinsic ratio but no intrinsic height or
     714                 :     //   width and the containing block's width does not itself depend
     715                 :     //   on the replaced element's width, then the used value of 'width'
     716                 :     //   is calculated from the constraint equation used for
     717                 :     //   block-level, non-replaced elements in normal flow. 
     718               0 :     nsIFrame *f = const_cast<nsIFrame*>(aFrame);
     719               0 :     if (f->GetIntrinsicRatio() != nsSize(0, 0) &&
     720                 :         // Some percents are treated like 'auto', so check != coord
     721               0 :         pos->mHeight.GetUnit() != eStyleUnit_Coord) {
     722               0 :       const nsIFrame::IntrinsicSize &intrinsicSize = f->GetIntrinsicSize();
     723               0 :       if (intrinsicSize.width.GetUnit() == eStyleUnit_None &&
     724               0 :           intrinsicSize.height.GetUnit() == eStyleUnit_None) {
     725               0 :         return true;
     726                 :       }
     727                 :     }
     728                 :   }
     729                 : 
     730               0 :   return false;
     731                 : }
     732                 : 
     733                 : nsresult
     734               0 : nsLineLayout::ReflowFrame(nsIFrame* aFrame,
     735                 :                           nsReflowStatus& aReflowStatus,
     736                 :                           nsHTMLReflowMetrics* aMetrics,
     737                 :                           bool& aPushedFrame)
     738                 : {
     739                 :   // Initialize OUT parameter
     740               0 :   aPushedFrame = false;
     741                 : 
     742                 :   PerFrameData* pfd;
     743               0 :   nsresult rv = NewPerFrameData(&pfd);
     744               0 :   if (NS_FAILED(rv)) {
     745               0 :     return rv;
     746                 :   }
     747               0 :   PerSpanData* psd = mCurrentSpan;
     748               0 :   psd->AppendFrame(pfd);
     749                 : 
     750                 : #ifdef REALLY_NOISY_REFLOW
     751                 :   nsFrame::IndentBy(stdout, mSpanDepth);
     752                 :   printf("%p: Begin ReflowFrame pfd=%p ", psd, pfd);
     753                 :   nsFrame::ListTag(stdout, aFrame);
     754                 :   printf("\n");
     755                 : #endif
     756                 : 
     757               0 :   mTextJustificationNumSpaces = 0;
     758               0 :   mTextJustificationNumLetters = 0;
     759                 : 
     760                 :   // Stash copies of some of the computed state away for later
     761                 :   // (vertical alignment, for example)
     762               0 :   pfd->mFrame = aFrame;
     763                 : 
     764                 :   // NOTE: While the x coordinate remains relative to the parent span,
     765                 :   // the y coordinate is fixed at the top edge for the line. During
     766                 :   // VerticalAlignFrames we will repair this so that the y coordinate
     767                 :   // is properly set and relative to the appropriate span.
     768               0 :   pfd->mBounds.x = psd->mX;
     769               0 :   pfd->mBounds.y = mTopEdge;
     770                 : 
     771                 :   // We want to guarantee that we always make progress when
     772                 :   // formatting. Therefore, if the object being placed on the line is
     773                 :   // too big for the line, but it is the only thing on the line and is not
     774                 :   // impacted by a float, then we go ahead and place it anyway. (If the line
     775                 :   // is impacted by one or more floats, then it is safe to break because
     776                 :   // we can move the line down below float(s).)
     777                 :   //
     778                 :   // Capture this state *before* we reflow the frame in case it clears
     779                 :   // the state out. We need to know how to treat the current frame
     780                 :   // when breaking.
     781               0 :   bool notSafeToBreak = LineIsEmpty() && !GetFlag(LL_IMPACTEDBYFLOATS);
     782                 : 
     783                 :   // Figure out whether we're talking about a textframe here
     784               0 :   nsIAtom* frameType = aFrame->GetType();
     785               0 :   bool isText = frameType == nsGkAtoms::textFrame;
     786                 :   
     787                 :   // Compute the available size for the frame. This available width
     788                 :   // includes room for the side margins.
     789                 :   // For now, set the available height to unconstrained always.
     790               0 :   nsSize availSize(mBlockReflowState->ComputedWidth(), NS_UNCONSTRAINEDSIZE);
     791                 : 
     792                 :   // Inline-ish and text-ish things don't compute their width;
     793                 :   // everything else does.  We need to give them an available width that
     794                 :   // reflects the space left on the line.
     795               0 :   NS_WARN_IF_FALSE(psd->mRightEdge != NS_UNCONSTRAINEDSIZE,
     796                 :                    "have unconstrained width; this should only result from "
     797                 :                    "very large sizes, not attempts at intrinsic width "
     798                 :                    "calculation");
     799               0 :   nscoord availableSpaceOnLine = psd->mRightEdge - psd->mX;
     800                 : 
     801                 :   // Setup reflow state for reflowing the frame
     802               0 :   Maybe<nsHTMLReflowState> reflowStateHolder;
     803               0 :   if (!isText) {
     804                 :     reflowStateHolder.construct(mPresContext, *psd->mReflowState,
     805               0 :                                 aFrame, availSize);
     806               0 :     nsHTMLReflowState& reflowState = reflowStateHolder.ref();
     807               0 :     reflowState.mLineLayout = this;
     808               0 :     reflowState.mFlags.mIsTopOfPage = GetFlag(LL_ISTOPOFPAGE);
     809               0 :     if (reflowState.ComputedWidth() == NS_UNCONSTRAINEDSIZE)
     810               0 :       reflowState.availableWidth = availableSpaceOnLine;
     811               0 :     pfd->mMargin = reflowState.mComputedMargin;
     812               0 :     pfd->mBorderPadding = reflowState.mComputedBorderPadding;
     813                 :     pfd->SetFlag(PFD_RELATIVEPOS,
     814               0 :                  (reflowState.mStyleDisplay->mPosition == NS_STYLE_POSITION_RELATIVE));
     815               0 :     if (pfd->GetFlag(PFD_RELATIVEPOS)) {
     816               0 :       pfd->mOffsets = reflowState.mComputedOffsets;
     817                 :     }
     818                 : 
     819                 :     // Apply start margins (as appropriate) to the frame computing the
     820                 :     // new starting x,y coordinates for the frame.
     821               0 :     ApplyStartMargin(pfd, reflowState);
     822                 :   } else {
     823               0 :     pfd->mMargin.SizeTo(0, 0, 0, 0);
     824               0 :     pfd->mBorderPadding.SizeTo(0, 0, 0, 0);
     825               0 :     pfd->mOffsets.SizeTo(0, 0, 0, 0);
     826                 :     // Text reflow doesn't look at the dirty bits on the frame being reflowed,
     827                 :     // so no need to propagate NS_FRAME_IS_DIRTY from the parent.
     828                 :   }
     829                 : 
     830                 :   // See if this frame depends on the width of its containing block.  If
     831                 :   // so, disable resize reflow optimizations for the line.  (Note that,
     832                 :   // to be conservative, we do this if we *try* to fit a frame on a
     833                 :   // line, even if we don't succeed.)  (Note also that we can only make
     834                 :   // this IsPercentageAware check *after* we've constructed our
     835                 :   // nsHTMLReflowState, because that construction may be what forces aFrame
     836                 :   // to lazily initialize its (possibly-percent-valued) intrinsic size.)
     837               0 :   if (GetFlag(LL_GOTLINEBOX) && IsPercentageAware(aFrame)) {
     838               0 :     mLineBox->DisableResizeReflowOptimization();
     839                 :   }
     840                 : 
     841                 :   // Let frame know that are reflowing it. Note that we don't bother
     842                 :   // positioning the frame yet, because we're probably going to end up
     843                 :   // moving it when we do the vertical alignment
     844               0 :   aFrame->WillReflow(mPresContext);
     845                 : 
     846                 :   // Adjust spacemanager coordinate system for the frame.
     847               0 :   nsHTMLReflowMetrics metrics;
     848                 : #ifdef DEBUG
     849               0 :   metrics.width = nscoord(0xdeadbeef);
     850               0 :   metrics.height = nscoord(0xdeadbeef);
     851                 : #endif
     852               0 :   nscoord tx = pfd->mBounds.x;
     853               0 :   nscoord ty = pfd->mBounds.y;
     854               0 :   mFloatManager->Translate(tx, ty);
     855                 : 
     856                 :   PRInt32 savedOptionalBreakOffset;
     857                 :   gfxBreakPriority savedOptionalBreakPriority;
     858                 :   nsIContent* savedOptionalBreakContent =
     859                 :     GetLastOptionalBreakPosition(&savedOptionalBreakOffset,
     860               0 :                                  &savedOptionalBreakPriority);
     861                 : 
     862               0 :   if (!isText) {
     863               0 :     rv = aFrame->Reflow(mPresContext, metrics, reflowStateHolder.ref(),
     864               0 :                         aReflowStatus);
     865               0 :     if (NS_FAILED(rv)) {
     866               0 :       NS_WARNING( "Reflow of frame failed in nsLineLayout" );
     867               0 :       return rv;
     868                 :     }
     869                 :   } else {
     870                 :     static_cast<nsTextFrame*>(aFrame)->
     871                 :       ReflowText(*this, availableSpaceOnLine, psd->mReflowState->rendContext,
     872               0 :                  psd->mReflowState->mFlags.mBlinks, metrics, aReflowStatus);
     873                 :   }
     874                 :   
     875               0 :   pfd->mJustificationNumSpaces = mTextJustificationNumSpaces;
     876               0 :   pfd->mJustificationNumLetters = mTextJustificationNumLetters;
     877                 : 
     878                 :   // See if the frame is a placeholderFrame and if it is process
     879                 :   // the float. At the same time, check if the frame has any non-collapsed-away
     880                 :   // content.
     881               0 :   bool placedFloat = false;
     882                 :   bool isEmpty;
     883               0 :   if (!frameType) {
     884               0 :     isEmpty = pfd->mFrame->IsEmpty();
     885                 :   } else {
     886               0 :     if (nsGkAtoms::placeholderFrame == frameType) {
     887               0 :       isEmpty = true;
     888               0 :       pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, true);
     889               0 :       nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
     890               0 :       if (outOfFlowFrame) {
     891                 :         // Add mTrimmableWidth to the available width since if the line ends
     892                 :         // here, the width of the inline content will be reduced by
     893                 :         // mTrimmableWidth.
     894               0 :         nscoord availableWidth = psd->mRightEdge - (psd->mX - mTrimmableWidth);
     895               0 :         if (psd->mNoWrap) {
     896                 :           // If we place floats after inline content where there's
     897                 :           // no break opportunity, we don't know how much additional
     898                 :           // width is required for the non-breaking content after the float,
     899                 :           // so we can't know whether the float plus that content will fit
     900                 :           // on the line. So for now, don't place floats after inline
     901                 :           // content where there's no break opportunity. This is incorrect
     902                 :           // but hopefully rare. Fixing it will require significant
     903                 :           // restructuring of line layout.
     904                 :           // We might as well allow zero-width floats to be placed, though.
     905               0 :           availableWidth = 0;
     906                 :         }
     907               0 :         placedFloat = AddFloat(outOfFlowFrame, availableWidth);
     908               0 :         NS_ASSERTION(!(outOfFlowFrame->GetType() == nsGkAtoms::letterFrame &&
     909                 :                        GetFirstLetterStyleOK()),
     910                 :                     "FirstLetterStyle set on line with floating first letter");
     911                 :       }
     912                 :     }
     913               0 :     else if (isText) {
     914                 :       // Note non-empty text-frames for inline frame compatibility hackery
     915               0 :       pfd->SetFlag(PFD_ISTEXTFRAME, true);
     916               0 :       nsTextFrame* textFrame = static_cast<nsTextFrame*>(pfd->mFrame);
     917               0 :       isEmpty = !textFrame->HasNoncollapsedCharacters();
     918               0 :       if (!isEmpty) {
     919               0 :         pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, true);
     920               0 :         nsIContent* content = textFrame->GetContent();
     921                 : 
     922               0 :         const nsTextFragment* frag = content->GetText();
     923               0 :         if (frag) {
     924                 :           pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME,
     925               0 :                        !content->TextIsOnlyWhitespace());
     926                 :         }
     927                 :       }
     928                 :     }
     929               0 :     else if (nsGkAtoms::brFrame == frameType) {
     930               0 :       pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, true);
     931               0 :       isEmpty = false;
     932                 :     } else {
     933               0 :       if (nsGkAtoms::letterFrame==frameType) {
     934               0 :         pfd->SetFlag(PFD_ISLETTERFRAME, true);
     935                 :       }
     936               0 :       if (pfd->mSpan) {
     937               0 :         isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
     938                 :       } else {
     939               0 :         isEmpty = pfd->mFrame->IsEmpty();
     940                 :       }
     941                 :     }
     942                 :   }
     943                 : 
     944               0 :   mFloatManager->Translate(-tx, -ty);
     945                 : 
     946               0 :   NS_ASSERTION(metrics.width>=0, "bad width");
     947               0 :   NS_ASSERTION(metrics.height>=0,"bad height");
     948               0 :   if (metrics.width<0) metrics.width=0;
     949               0 :   if (metrics.height<0) metrics.height=0;
     950                 : 
     951                 : #ifdef DEBUG
     952                 :   // Note: break-before means ignore the reflow metrics since the
     953                 :   // frame will be reflowed another time.
     954               0 :   if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
     955               0 :     if (CRAZY_WIDTH(metrics.width) || CRAZY_HEIGHT(metrics.height)) {
     956               0 :       printf("nsLineLayout: ");
     957               0 :       nsFrame::ListTag(stdout, aFrame);
     958               0 :       printf(" metrics=%d,%d!\n", metrics.width, metrics.height);
     959                 :     }
     960               0 :     if ((metrics.width == nscoord(0xdeadbeef)) ||
     961                 :         (metrics.height == nscoord(0xdeadbeef))) {
     962               0 :       printf("nsLineLayout: ");
     963               0 :       nsFrame::ListTag(stdout, aFrame);
     964               0 :       printf(" didn't set w/h %d,%d!\n", metrics.width, metrics.height);
     965                 :     }
     966                 :   }
     967                 : #endif
     968                 : 
     969                 :   // Unlike with non-inline reflow, the overflow area here does *not*
     970                 :   // include the accumulation of the frame's bounds and its inline
     971                 :   // descendants' bounds. Nor does it include the outline area; it's
     972                 :   // just the union of the bounds of any absolute children. That is
     973                 :   // added in later by nsLineLayout::ReflowInlineFrames.
     974               0 :   pfd->mOverflowAreas = metrics.mOverflowAreas;
     975                 : 
     976               0 :   pfd->mBounds.width = metrics.width;
     977               0 :   pfd->mBounds.height = metrics.height;
     978                 : 
     979                 :   // Size the frame, but |RelativePositionFrames| will size the view.
     980               0 :   aFrame->SetSize(nsSize(metrics.width, metrics.height));
     981                 : 
     982                 :   // Tell the frame that we're done reflowing it
     983                 :   aFrame->DidReflow(mPresContext,
     984                 :                     isText ? nsnull : reflowStateHolder.addr(),
     985               0 :                     NS_FRAME_REFLOW_FINISHED);
     986                 : 
     987               0 :   if (aMetrics) {
     988               0 :     *aMetrics = metrics;
     989                 :   }
     990                 : 
     991               0 :   if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
     992                 :     // If frame is complete and has a next-in-flow, we need to delete
     993                 :     // them now. Do not do this when a break-before is signaled because
     994                 :     // the frame is going to get reflowed again (and may end up wanting
     995                 :     // a next-in-flow where it ends up).
     996               0 :     if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
     997               0 :       nsIFrame* kidNextInFlow = aFrame->GetNextInFlow();
     998               0 :       if (nsnull != kidNextInFlow) {
     999                 :         // Remove all of the childs next-in-flows. Make sure that we ask
    1000                 :         // the right parent to do the removal (it's possible that the
    1001                 :         // parent is not this because we are executing pullup code)
    1002                 :         nsContainerFrame* parent = static_cast<nsContainerFrame*>
    1003               0 :                                                   (kidNextInFlow->GetParent());
    1004               0 :         parent->DeleteNextInFlowChild(mPresContext, kidNextInFlow, true);
    1005                 :       }
    1006                 :     }
    1007                 : 
    1008                 :     // Check whether this frame breaks up text runs. All frames break up text
    1009                 :     // runs (hence return false here) except for text frames and inline containers.
    1010               0 :     bool continuingTextRun = aFrame->CanContinueTextRun();
    1011                 :     
    1012                 :     // Clear any residual mTrimmableWidth if this isn't a text frame
    1013               0 :     if (!continuingTextRun && !pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) {
    1014               0 :       mTrimmableWidth = 0;
    1015                 :     }
    1016                 : 
    1017                 :     // See if we can place the frame. If we can't fit it, then we
    1018                 :     // return now.
    1019                 :     bool optionalBreakAfterFits;
    1020               0 :     NS_ASSERTION(isText ||
    1021                 :                  reflowStateHolder.ref().mStyleDisplay->mFloats ==
    1022                 :                    NS_STYLE_FLOAT_NONE,
    1023                 :                  "How'd we get a floated inline frame? "
    1024                 :                  "The frame ctor should've dealt with this.");
    1025                 :     // Direction is inherited, so using the psd direction is fine.
    1026                 :     // Get it off the reflow state instead of the frame to save style
    1027                 :     // data computation (especially for the text).
    1028                 :     PRUint8 direction =
    1029                 :       isText ? psd->mReflowState->mStyleVisibility->mDirection :
    1030               0 :                reflowStateHolder.ref().mStyleVisibility->mDirection;
    1031               0 :     if (CanPlaceFrame(pfd, direction, notSafeToBreak, continuingTextRun,
    1032                 :                       savedOptionalBreakContent != nsnull, metrics,
    1033               0 :                       aReflowStatus, &optionalBreakAfterFits)) {
    1034               0 :       if (!isEmpty) {
    1035               0 :         psd->mHasNonemptyContent = true;
    1036               0 :         SetFlag(LL_LINEISEMPTY, false);
    1037               0 :         if (!pfd->mSpan) {
    1038                 :           // nonempty leaf content has been placed
    1039               0 :           SetFlag(LL_LINEATSTART, false);
    1040                 :         }
    1041                 :       }
    1042                 : 
    1043                 :       // Place the frame, updating aBounds with the final size and
    1044                 :       // location.  Then apply the bottom+right margins (as
    1045                 :       // appropriate) to the frame.
    1046               0 :       PlaceFrame(pfd, metrics);
    1047               0 :       PerSpanData* span = pfd->mSpan;
    1048               0 :       if (span) {
    1049                 :         // The frame we just finished reflowing is an inline
    1050                 :         // container.  It needs its child frames vertically aligned,
    1051                 :         // so do most of it now.
    1052               0 :         VerticalAlignFrames(span);
    1053                 :       }
    1054                 :       
    1055               0 :       if (!continuingTextRun) {
    1056               0 :         if (!psd->mNoWrap && (!LineIsEmpty() || placedFloat)) {
    1057                 :           // record soft break opportunity after this content that can't be
    1058                 :           // part of a text run. This is not a text frame so we know
    1059                 :           // that offset PR_INT32_MAX means "after the content".
    1060               0 :           if (NotifyOptionalBreakPosition(aFrame->GetContent(), PR_INT32_MAX, optionalBreakAfterFits, eNormalBreak)) {
    1061                 :             // If this returns true then we are being told to actually break here.
    1062               0 :             aReflowStatus = NS_INLINE_LINE_BREAK_AFTER(aReflowStatus);
    1063                 :           }
    1064                 :         }
    1065                 :       }
    1066                 :     }
    1067                 :     else {
    1068               0 :       PushFrame(aFrame);
    1069               0 :       aPushedFrame = true;
    1070                 :       // Undo any saved break positions that the frame might have told us about,
    1071                 :       // since we didn't end up placing it
    1072                 :       RestoreSavedBreakPosition(savedOptionalBreakContent,
    1073                 :                                 savedOptionalBreakOffset,
    1074               0 :                                 savedOptionalBreakPriority);
    1075                 :     }
    1076                 :   }
    1077                 :   else {
    1078               0 :     PushFrame(aFrame);
    1079                 :   }
    1080                 :   
    1081                 : #ifdef REALLY_NOISY_REFLOW
    1082                 :   nsFrame::IndentBy(stdout, mSpanDepth);
    1083                 :   printf("End ReflowFrame ");
    1084                 :   nsFrame::ListTag(stdout, aFrame);
    1085                 :   printf(" status=%x\n", aReflowStatus);
    1086                 : #endif
    1087                 : 
    1088               0 :   return rv;
    1089                 : }
    1090                 : 
    1091                 : void
    1092               0 : nsLineLayout::ApplyStartMargin(PerFrameData* pfd,
    1093                 :                                nsHTMLReflowState& aReflowState)
    1094                 : {
    1095               0 :   NS_ASSERTION(aReflowState.mStyleDisplay->mFloats == NS_STYLE_FLOAT_NONE,
    1096                 :                "How'd we get a floated inline frame? "
    1097                 :                "The frame ctor should've dealt with this.");
    1098                 : 
    1099                 :   // XXXwaterson probably not the right way to get this; e.g., embeddings, etc.
    1100               0 :   bool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
    1101                 : 
    1102                 :   // Only apply start-margin on the first-in flow for inline frames,
    1103                 :   // and make sure to not apply it to any inline other than the first
    1104                 :   // in an ib split.  Note that the ib special sibling annotations
    1105                 :   // only live on the first continuation, but we don't want to apply
    1106                 :   // the start margin for later continuations anyway.
    1107               0 :   if (pfd->mFrame->GetPrevContinuation() ||
    1108               0 :       nsLayoutUtils::FrameIsNonFirstInIBSplit(pfd->mFrame)) {
    1109                 :     // Zero this out so that when we compute the max-element-width of
    1110                 :     // the frame we will properly avoid adding in the starting margin.
    1111               0 :     if (ltr)
    1112               0 :       pfd->mMargin.left = 0;
    1113                 :     else
    1114               0 :       pfd->mMargin.right = 0;
    1115                 :   }
    1116                 :   else {
    1117               0 :     pfd->mBounds.x += ltr ? pfd->mMargin.left : pfd->mMargin.right;
    1118                 : 
    1119               0 :     NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth,
    1120                 :                      "have unconstrained width; this should only result from "
    1121                 :                      "very large sizes, not attempts at intrinsic width "
    1122                 :                      "calculation");
    1123               0 :     if (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedWidth()) {
    1124                 :       // For inline-ish and text-ish things (which don't compute widths
    1125                 :       // in the reflow state), adjust available width to account for the
    1126                 :       // left margin. The right margin will be accounted for when we
    1127                 :       // finish flowing the frame.
    1128               0 :       aReflowState.availableWidth -= ltr ? pfd->mMargin.left : pfd->mMargin.right;
    1129                 :     }
    1130                 :   }
    1131               0 : }
    1132                 : 
    1133                 : nscoord
    1134               0 : nsLineLayout::GetCurrentFrameXDistanceFromBlock()
    1135                 : {
    1136                 :   PerSpanData* psd;
    1137               0 :   nscoord x = 0;
    1138               0 :   for (psd = mCurrentSpan; psd; psd = psd->mParent) {
    1139               0 :     x += psd->mX;
    1140                 :   }
    1141               0 :   return x;
    1142                 : }
    1143                 : 
    1144                 : /**
    1145                 :  * See if the frame can be placed now that we know it's desired size.
    1146                 :  * We can always place the frame if the line is empty. Note that we
    1147                 :  * know that the reflow-status is not a break-before because if it was
    1148                 :  * ReflowFrame above would have returned false, preventing this method
    1149                 :  * from being called. The logic in this method assumes that.
    1150                 :  *
    1151                 :  * Note that there is no check against the Y coordinate because we
    1152                 :  * assume that the caller will take care of that.
    1153                 :  */
    1154                 : bool
    1155               0 : nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
    1156                 :                             PRUint8 aFrameDirection,
    1157                 :                             bool aNotSafeToBreak,
    1158                 :                             bool aFrameCanContinueTextRun,
    1159                 :                             bool aCanRollBackBeforeFrame,
    1160                 :                             nsHTMLReflowMetrics& aMetrics,
    1161                 :                             nsReflowStatus& aStatus,
    1162                 :                             bool* aOptionalBreakAfterFits)
    1163                 : {
    1164               0 :   NS_PRECONDITION(pfd && pfd->mFrame, "bad args, null pointers for frame data");
    1165                 :   
    1166               0 :   *aOptionalBreakAfterFits = true;
    1167                 :   // Compute right margin to use
    1168               0 :   if (0 != pfd->mBounds.width) {
    1169                 :     // XXXwaterson this is probably not exactly right; e.g., embeddings, etc.
    1170               0 :     bool ltr = (NS_STYLE_DIRECTION_LTR == aFrameDirection);
    1171                 : 
    1172                 :     /*
    1173                 :      * We want to only apply the end margin if we're the last continuation and
    1174                 :      * either not in an {ib} split or the last inline in it.  In all other
    1175                 :      * cases we want to zero it out.  That means zeroing it out if any of these
    1176                 :      * conditions hold:
    1177                 :      * 1) The frame is not complete (in this case it will get a next-in-flow)
    1178                 :      * 2) The frame is complete but has a non-fluid continuation on its
    1179                 :      *    continuation chain.  Note that if it has a fluid continuation, that
    1180                 :      *    continuation will get destroyed later, so we don't want to drop the
    1181                 :      *    end-margin in that case.
    1182                 :      * 3) The frame is in an {ib} split and is not the last part.
    1183                 :      *
    1184                 :      * However, none of that applies if this is a letter frame (XXXbz why?)
    1185                 :      */
    1186               0 :     if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) ||
    1187               0 :          pfd->mFrame->GetLastInFlow()->GetNextContinuation() ||
    1188               0 :          nsLayoutUtils::FrameIsNonLastInIBSplit(pfd->mFrame))
    1189               0 :         && !pfd->GetFlag(PFD_ISLETTERFRAME)) {
    1190               0 :       if (ltr)
    1191               0 :         pfd->mMargin.right = 0;
    1192                 :       else
    1193               0 :         pfd->mMargin.left = 0;
    1194                 :     }
    1195                 :   }
    1196                 :   else {
    1197                 :     // Don't apply margin to empty frames.
    1198               0 :     pfd->mMargin.left = pfd->mMargin.right = 0;
    1199                 :   }
    1200                 : 
    1201               0 :   PerSpanData* psd = mCurrentSpan;
    1202               0 :   if (psd->mNoWrap) {
    1203                 :     // When wrapping is off, everything fits.
    1204               0 :     return true;
    1205                 :   }
    1206                 : 
    1207               0 :   bool ltr = NS_STYLE_DIRECTION_LTR == aFrameDirection;
    1208               0 :   nscoord endMargin = ltr ? pfd->mMargin.right : pfd->mMargin.left;
    1209                 : 
    1210                 : #ifdef NOISY_CAN_PLACE_FRAME
    1211                 :   if (nsnull != psd->mFrame) {
    1212                 :     nsFrame::ListTag(stdout, psd->mFrame->mFrame);
    1213                 :   }
    1214                 :   else {
    1215                 :     nsFrame::ListTag(stdout, mBlockReflowState->frame);
    1216                 :   } 
    1217                 :   printf(": aNotSafeToBreak=%s frame=", aNotSafeToBreak ? "true" : "false");
    1218                 :   nsFrame::ListTag(stdout, pfd->mFrame);
    1219                 :   printf(" frameWidth=%d\n", pfd->mBounds.XMost() + endMargin - psd->mX);
    1220                 : #endif
    1221                 : 
    1222                 :   // Set outside to true if the result of the reflow leads to the
    1223                 :   // frame sticking outside of our available area.
    1224               0 :   bool outside = pfd->mBounds.XMost() - mTrimmableWidth + endMargin > psd->mRightEdge;
    1225               0 :   if (!outside) {
    1226                 :     // If it fits, it fits
    1227                 : #ifdef NOISY_CAN_PLACE_FRAME
    1228                 :     printf("   ==> inside\n");
    1229                 : #endif
    1230               0 :     return true;
    1231                 :   }
    1232               0 :   *aOptionalBreakAfterFits = false;
    1233                 : 
    1234                 :   // When it doesn't fit, check for a few special conditions where we
    1235                 :   // allow it to fit anyway.
    1236               0 :   if (0 == pfd->mMargin.left + pfd->mBounds.width + pfd->mMargin.right) {
    1237                 :     // Empty frames always fit right where they are
    1238                 : #ifdef NOISY_CAN_PLACE_FRAME
    1239                 :     printf("   ==> empty frame fits\n");
    1240                 : #endif
    1241               0 :     return true;
    1242                 :   }
    1243                 : 
    1244                 : #ifdef FIX_BUG_50257
    1245                 :   // another special case:  always place a BR
    1246               0 :   if (nsGkAtoms::brFrame == pfd->mFrame->GetType()) {
    1247                 : #ifdef NOISY_CAN_PLACE_FRAME
    1248                 :     printf("   ==> BR frame fits\n");
    1249                 : #endif
    1250               0 :     return true;
    1251                 :   }
    1252                 : #endif
    1253                 : 
    1254               0 :   if (aNotSafeToBreak) {
    1255                 :     // There are no frames on the line that take up width and the line is
    1256                 :     // not impacted by floats, so we must allow the current frame to be
    1257                 :     // placed on the line
    1258                 : #ifdef NOISY_CAN_PLACE_FRAME
    1259                 :     printf("   ==> not-safe and not-impacted fits: ");
    1260                 :     while (nsnull != psd) {
    1261                 :       printf("<psd=%p x=%d left=%d> ", psd, psd->mX, psd->mLeftEdge);
    1262                 :       psd = psd->mParent;
    1263                 :     }
    1264                 :     printf("\n");
    1265                 : #endif
    1266               0 :     return true;
    1267                 :   }
    1268                 :  
    1269                 :   // Special check for span frames
    1270               0 :   if (pfd->mSpan && pfd->mSpan->mContainsFloat) {
    1271                 :     // If the span either directly or indirectly contains a float then
    1272                 :     // it fits. Why? It's kind of complicated, but here goes:
    1273                 :     //
    1274                 :     // 1. CanPlaceFrame is used for all frame placements on a line,
    1275                 :     // and in a span. This includes recursively placement of frames
    1276                 :     // inside of spans, and the span itself. Because the logic always
    1277                 :     // checks for room before proceeding (the code above here), the
    1278                 :     // only things on a line will be those things that "fit".
    1279                 :     //
    1280                 :     // 2. Before a float is placed on a line, the line has to be empty
    1281                 :     // (otherwise it's a "below current line" float and will be placed
    1282                 :     // after the line).
    1283                 :     //
    1284                 :     // Therefore, if the span directly or indirectly has a float
    1285                 :     // then it means that at the time of the placement of the float
    1286                 :     // the line was empty. Because of #1, only the frames that fit can
    1287                 :     // be added after that point, therefore we can assume that the
    1288                 :     // current span being placed has fit.
    1289                 :     //
    1290                 :     // So how do we get here and have a span that should already fit
    1291                 :     // and yet doesn't: Simple: span's that have the no-wrap attribute
    1292                 :     // set on them and contain a float and are placed where they
    1293                 :     // don't naturally fit.
    1294               0 :     return true;
    1295                 :  }
    1296                 : 
    1297               0 :   if (aFrameCanContinueTextRun) {
    1298                 :     // Let it fit, but we reserve the right to roll back.
    1299                 :     // Note that we usually won't get here because a text frame will break
    1300                 :     // itself to avoid exceeding the available width.
    1301                 :     // We'll only get here for text frames that couldn't break early enough.
    1302                 : #ifdef NOISY_CAN_PLACE_FRAME
    1303                 :     printf("   ==> placing overflowing textrun, requesting backup\n");
    1304                 : #endif
    1305                 : 
    1306                 :     // We will want to try backup.
    1307               0 :     SetFlag(LL_NEEDBACKUP, true);
    1308               0 :     return true;
    1309                 :   }
    1310                 : 
    1311                 : #ifdef NOISY_CAN_PLACE_FRAME
    1312                 :   printf("   ==> didn't fit\n");
    1313                 : #endif
    1314               0 :   aStatus = NS_INLINE_LINE_BREAK_BEFORE();
    1315               0 :   return false;
    1316                 : }
    1317                 : 
    1318                 : /**
    1319                 :  * Place the frame. Update running counters.
    1320                 :  */
    1321                 : void
    1322               0 : nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
    1323                 : {
    1324                 :   // If frame is zero width then do not apply its left and right margins.
    1325               0 :   PerSpanData* psd = mCurrentSpan;
    1326               0 :   bool emptyFrame = false;
    1327               0 :   if ((0 == pfd->mBounds.width) && (0 == pfd->mBounds.height)) {
    1328               0 :     pfd->mBounds.x = psd->mX;
    1329               0 :     pfd->mBounds.y = mTopEdge;
    1330               0 :     emptyFrame = true;
    1331                 :   }
    1332                 : 
    1333                 :   // Record ascent and update max-ascent and max-descent values
    1334               0 :   if (aMetrics.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE)
    1335               0 :     pfd->mAscent = pfd->mFrame->GetBaseline();
    1336                 :   else
    1337               0 :     pfd->mAscent = aMetrics.ascent;
    1338                 : 
    1339               0 :   bool ltr = (NS_STYLE_DIRECTION_LTR == pfd->mFrame->GetStyleVisibility()->mDirection);
    1340                 :   // Advance to next X coordinate
    1341               0 :   psd->mX = pfd->mBounds.XMost() + (ltr ? pfd->mMargin.right : pfd->mMargin.left);
    1342                 : 
    1343                 :   // Count the number of non-empty frames on the line...
    1344               0 :   if (!emptyFrame) {
    1345               0 :     mTotalPlacedFrames++;
    1346                 :   }
    1347               0 : }
    1348                 : 
    1349                 : nsresult
    1350               0 : nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
    1351                 :                              const nsHTMLReflowMetrics& aMetrics)
    1352                 : {
    1353               0 :   NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
    1354               0 :   NS_ASSERTION(GetFlag(LL_GOTLINEBOX), "must have line box");
    1355                 : 
    1356                 : 
    1357               0 :   nsIFrame *blockFrame = mBlockReflowState->frame;
    1358               0 :   NS_ASSERTION(blockFrame->IsFrameOfType(nsIFrame::eBlockFrame),
    1359                 :                "must be for block");
    1360               0 :   if (!static_cast<nsBlockFrame*>(blockFrame)->BulletIsEmpty()) {
    1361               0 :     SetFlag(LL_HASBULLET, true);
    1362               0 :     mLineBox->SetHasBullet();
    1363                 :   }
    1364                 : 
    1365                 :   PerFrameData* pfd;
    1366               0 :   nsresult rv = NewPerFrameData(&pfd);
    1367               0 :   if (NS_SUCCEEDED(rv)) {
    1368               0 :     mRootSpan->AppendFrame(pfd);
    1369               0 :     pfd->mFrame = aFrame;
    1370               0 :     pfd->mMargin.SizeTo(0, 0, 0, 0);
    1371               0 :     pfd->mBorderPadding.SizeTo(0, 0, 0, 0);
    1372               0 :     pfd->mFlags = 0;  // all flags default to false
    1373               0 :     pfd->SetFlag(PFD_ISBULLET, true);
    1374               0 :     if (aMetrics.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE)
    1375               0 :       pfd->mAscent = aFrame->GetBaseline();
    1376                 :     else
    1377               0 :       pfd->mAscent = aMetrics.ascent;
    1378                 : 
    1379                 :     // Note: y value will be updated during vertical alignment
    1380               0 :     pfd->mBounds = aFrame->GetRect();
    1381               0 :     pfd->mOverflowAreas = aMetrics.mOverflowAreas;
    1382                 :   }
    1383               0 :   return rv;
    1384                 : }
    1385                 : 
    1386                 : #ifdef DEBUG
    1387                 : void
    1388               0 : nsLineLayout::DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent)
    1389                 : {
    1390               0 :   nsFrame::IndentBy(stdout, aIndent);
    1391                 :   printf("%p: left=%d x=%d right=%d\n", static_cast<void*>(psd),
    1392               0 :          psd->mLeftEdge, psd->mX, psd->mRightEdge);
    1393               0 :   PerFrameData* pfd = psd->mFirstFrame;
    1394               0 :   while (nsnull != pfd) {
    1395               0 :     nsFrame::IndentBy(stdout, aIndent+1);
    1396               0 :     nsFrame::ListTag(stdout, pfd->mFrame);
    1397                 :     printf(" %d,%d,%d,%d\n", pfd->mBounds.x, pfd->mBounds.y,
    1398               0 :            pfd->mBounds.width, pfd->mBounds.height);
    1399               0 :     if (pfd->mSpan) {
    1400               0 :       DumpPerSpanData(pfd->mSpan, aIndent + 1);
    1401                 :     }
    1402               0 :     pfd = pfd->mNext;
    1403                 :   }
    1404               0 : }
    1405                 : #endif
    1406                 : 
    1407                 : #define VALIGN_OTHER  0
    1408                 : #define VALIGN_TOP    1
    1409                 : #define VALIGN_BOTTOM 2
    1410                 : 
    1411                 : void
    1412               0 : nsLineLayout::VerticalAlignLine()
    1413                 : {
    1414                 :   // Synthesize a PerFrameData for the block frame
    1415               0 :   PerFrameData rootPFD;
    1416               0 :   rootPFD.mFrame = mBlockReflowState->frame;
    1417               0 :   rootPFD.mAscent = 0;
    1418               0 :   mRootSpan->mFrame = &rootPFD;
    1419                 : 
    1420                 :   // Partially place the children of the block frame. The baseline for
    1421                 :   // this operation is set to zero so that the y coordinates for all
    1422                 :   // of the placed children will be relative to there.
    1423               0 :   PerSpanData* psd = mRootSpan;
    1424               0 :   VerticalAlignFrames(psd);
    1425                 : 
    1426                 :   // Compute the line-height. The line-height will be the larger of:
    1427                 :   //
    1428                 :   // [1] maxY - minY (the distance between the highest childs top edge
    1429                 :   // and the lowest childs bottom edge)
    1430                 :   //
    1431                 :   // [2] the maximum logical box height (since not every frame may have
    1432                 :   // participated in #1; for example: top/bottom aligned frames)
    1433                 :   //
    1434                 :   // [3] the minimum line height (line-height property set on the
    1435                 :   // block frame)
    1436               0 :   nscoord lineHeight = psd->mMaxY - psd->mMinY;
    1437                 : 
    1438                 :   // Now that the line-height is computed, we need to know where the
    1439                 :   // baseline is in the line. Position baseline so that mMinY is just
    1440                 :   // inside the top of the line box.
    1441                 :   nscoord baselineY;
    1442               0 :   if (psd->mMinY < 0) {
    1443               0 :     baselineY = mTopEdge - psd->mMinY;
    1444                 :   }
    1445                 :   else {
    1446               0 :     baselineY = mTopEdge;
    1447                 :   }
    1448                 : 
    1449                 :   // It's also possible that the line-height isn't tall enough because
    1450                 :   // of top/bottom aligned elements that were not accounted for in
    1451                 :   // min/max Y.
    1452                 :   //
    1453                 :   // The CSS2 spec doesn't really say what happens when to the
    1454                 :   // baseline in this situations. What we do is if the largest top
    1455                 :   // aligned box height is greater than the line-height then we leave
    1456                 :   // the baseline alone. If the largest bottom aligned box is greater
    1457                 :   // than the line-height then we slide the baseline down by the extra
    1458                 :   // amount.
    1459                 :   //
    1460                 :   // Navigator 4 gives precedence to the first top/bottom aligned
    1461                 :   // object.  We just let bottom aligned objects win.
    1462               0 :   if (lineHeight < mMaxBottomBoxHeight) {
    1463                 :     // When the line is shorter than the maximum top aligned box
    1464               0 :     nscoord extra = mMaxBottomBoxHeight - lineHeight;
    1465               0 :     baselineY += extra;
    1466               0 :     lineHeight = mMaxBottomBoxHeight;
    1467                 :   }
    1468               0 :   if (lineHeight < mMaxTopBoxHeight) {
    1469               0 :     lineHeight = mMaxTopBoxHeight;
    1470                 :   }
    1471                 : #ifdef NOISY_VERTICAL_ALIGN
    1472                 :   printf("  [line]==> lineHeight=%d baselineY=%d\n", lineHeight, baselineY);
    1473                 : #endif
    1474                 : 
    1475                 :   // Now position all of the frames in the root span. We will also
    1476                 :   // recurse over the child spans and place any top/bottom aligned
    1477                 :   // frames we find.
    1478                 :   // XXX PERFORMANCE: set a bit per-span to avoid the extra work
    1479                 :   // (propagate it upward too)
    1480               0 :   for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
    1481               0 :     if (pfd->mVerticalAlign == VALIGN_OTHER) {
    1482               0 :       pfd->mBounds.y += baselineY;
    1483               0 :       pfd->mFrame->SetRect(pfd->mBounds);
    1484                 :     }
    1485                 :   }
    1486               0 :   PlaceTopBottomFrames(psd, -mTopEdge, lineHeight);
    1487                 : 
    1488                 :   // If the frame being reflowed has text decorations, we simulate the
    1489                 :   // propagation of those decorations to a line-level element by storing the
    1490                 :   // offset in a frame property on any child frames that are vertically-aligned
    1491                 :   // somewhere other than the baseline. This property is then used by
    1492                 :   // nsTextFrame::GetTextDecorations when the same conditions are met.
    1493               0 :   if (rootPFD.mFrame->GetStyleContext()->HasTextDecorationLines()) {
    1494               0 :     for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
    1495               0 :       const nsIFrame *const f = pfd->mFrame;
    1496                 :       const nsStyleCoord& vAlign =
    1497               0 :           f->GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
    1498                 : 
    1499               0 :       if (vAlign.GetUnit() != eStyleUnit_Enumerated ||
    1500               0 :           vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
    1501               0 :         const nscoord offset = baselineY - pfd->mBounds.y;
    1502                 :         f->Properties().Set(nsIFrame::LineBaselineOffset(),
    1503               0 :                             NS_INT32_TO_PTR(offset));
    1504                 :       }
    1505                 :     }
    1506                 :   }
    1507                 : 
    1508                 :   // Fill in returned line-box and max-element-width data
    1509               0 :   mLineBox->mBounds.x = psd->mLeftEdge;
    1510               0 :   mLineBox->mBounds.y = mTopEdge;
    1511               0 :   mLineBox->mBounds.width = psd->mX - psd->mLeftEdge;
    1512               0 :   mLineBox->mBounds.height = lineHeight;
    1513               0 :   mFinalLineHeight = lineHeight;
    1514               0 :   mLineBox->SetAscent(baselineY - mTopEdge);
    1515                 : #ifdef NOISY_VERTICAL_ALIGN
    1516                 :   printf(
    1517                 :     "  [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d\n",
    1518                 :     mLineBox->mBounds.x, mLineBox->mBounds.y,
    1519                 :     mLineBox->mBounds.width, mLineBox->mBounds.height,
    1520                 :     mFinalLineHeight, mLineBox->GetAscent());
    1521                 : #endif
    1522                 : 
    1523                 :   // Undo root-span mFrame pointer to prevent brane damage later on...
    1524               0 :   mRootSpan->mFrame = nsnull;
    1525               0 : }
    1526                 : 
    1527                 : void
    1528               0 : nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
    1529                 :                                    nscoord aDistanceFromTop,
    1530                 :                                    nscoord aLineHeight)
    1531                 : {
    1532               0 :   for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
    1533               0 :     PerSpanData* span = pfd->mSpan;
    1534                 : #ifdef DEBUG
    1535               0 :     NS_ASSERTION(0xFF != pfd->mVerticalAlign, "umr");
    1536                 : #endif
    1537               0 :     switch (pfd->mVerticalAlign) {
    1538                 :       case VALIGN_TOP:
    1539               0 :         if (span) {
    1540               0 :           pfd->mBounds.y = -aDistanceFromTop - span->mMinY;
    1541                 :         }
    1542                 :         else {
    1543               0 :           pfd->mBounds.y = -aDistanceFromTop + pfd->mMargin.top;
    1544                 :         }
    1545               0 :         pfd->mFrame->SetRect(pfd->mBounds);
    1546                 : #ifdef NOISY_VERTICAL_ALIGN
    1547                 :         printf("    ");
    1548                 :         nsFrame::ListTag(stdout, pfd->mFrame);
    1549                 :         printf(": y=%d dTop=%d [bp.top=%d topLeading=%d]\n",
    1550                 :                pfd->mBounds.y, aDistanceFromTop,
    1551                 :                span ? pfd->mBorderPadding.top : 0,
    1552                 :                span ? span->mTopLeading : 0);
    1553                 : #endif
    1554               0 :         break;
    1555                 :       case VALIGN_BOTTOM:
    1556               0 :         if (span) {
    1557                 :           // Compute bottom leading
    1558               0 :           pfd->mBounds.y = -aDistanceFromTop + aLineHeight - span->mMaxY;
    1559                 :         }
    1560                 :         else {
    1561                 :           pfd->mBounds.y = -aDistanceFromTop + aLineHeight -
    1562               0 :             pfd->mMargin.bottom - pfd->mBounds.height;
    1563                 :         }
    1564               0 :         pfd->mFrame->SetRect(pfd->mBounds);
    1565                 : #ifdef NOISY_VERTICAL_ALIGN
    1566                 :         printf("    ");
    1567                 :         nsFrame::ListTag(stdout, pfd->mFrame);
    1568                 :         printf(": y=%d\n", pfd->mBounds.y);
    1569                 : #endif
    1570               0 :         break;
    1571                 :     }
    1572               0 :     if (span) {
    1573               0 :       nscoord distanceFromTop = aDistanceFromTop + pfd->mBounds.y;
    1574               0 :       PlaceTopBottomFrames(span, distanceFromTop, aLineHeight);
    1575                 :     }
    1576                 :   }
    1577               0 : }
    1578                 : 
    1579                 : #define VERTICAL_ALIGN_FRAMES_NO_MINIMUM nscoord_MAX
    1580                 : #define VERTICAL_ALIGN_FRAMES_NO_MAXIMUM nscoord_MIN
    1581                 : 
    1582                 : // Vertically place frames within a given span. Note: this doesn't
    1583                 : // place top/bottom aligned frames as those have to wait until the
    1584                 : // entire line box height is known. This is called after the span
    1585                 : // frame has finished being reflowed so that we know its height.
    1586                 : void
    1587               0 : nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
    1588                 : {
    1589                 :   // Get parent frame info
    1590               0 :   PerFrameData* spanFramePFD = psd->mFrame;
    1591               0 :   nsIFrame* spanFrame = spanFramePFD->mFrame;
    1592                 : 
    1593                 :   // Get the parent frame's font for all of the frames in this span
    1594               0 :   nsRefPtr<nsFontMetrics> fm;
    1595                 :   float inflation =
    1596               0 :     nsLayoutUtils::FontSizeInflationInner(spanFrame, mInflationMinFontSize);
    1597                 :   nsLayoutUtils::GetFontMetricsForFrame(spanFrame, getter_AddRefs(fm),
    1598               0 :                                         inflation);
    1599               0 :   mBlockReflowState->rendContext->SetFont(fm);
    1600                 : 
    1601               0 :   bool preMode = mStyleText->WhiteSpaceIsSignificant();
    1602                 : 
    1603                 :   // See if the span is an empty continuation. It's an empty continuation iff:
    1604                 :   // - it has a prev-in-flow
    1605                 :   // - it has no next in flow
    1606                 :   // - it's zero sized
    1607                 :   bool emptyContinuation = psd != mRootSpan &&
    1608               0 :     spanFrame->GetPrevInFlow() && !spanFrame->GetNextInFlow() &&
    1609               0 :     (0 == spanFramePFD->mBounds.width) && (0 == spanFramePFD->mBounds.height);
    1610                 : 
    1611                 : #ifdef NOISY_VERTICAL_ALIGN
    1612                 :   printf("[%sSpan]", (psd == mRootSpan)?"Root":"");
    1613                 :   nsFrame::ListTag(stdout, spanFrame);
    1614                 :   printf(": preMode=%s strictMode=%s w/h=%d,%d emptyContinuation=%s",
    1615                 :          preMode ? "yes" : "no",
    1616                 :          mPresContext->CompatibilityMode() != eCompatibility_NavQuirks ? "yes" : "no",
    1617                 :          spanFramePFD->mBounds.width, spanFramePFD->mBounds.height,
    1618                 :          emptyContinuation ? "yes" : "no");
    1619                 :   if (psd != mRootSpan) {
    1620                 :     printf(" bp=%d,%d,%d,%d margin=%d,%d,%d,%d",
    1621                 :            spanFramePFD->mBorderPadding.top,
    1622                 :            spanFramePFD->mBorderPadding.right,
    1623                 :            spanFramePFD->mBorderPadding.bottom,
    1624                 :            spanFramePFD->mBorderPadding.left,
    1625                 :            spanFramePFD->mMargin.top,
    1626                 :            spanFramePFD->mMargin.right,
    1627                 :            spanFramePFD->mMargin.bottom,
    1628                 :            spanFramePFD->mMargin.left);
    1629                 :   }
    1630                 :   printf("\n");
    1631                 : #endif
    1632                 : 
    1633                 :   // Compute the span's mZeroEffectiveSpanBox flag. What we are trying
    1634                 :   // to determine is how we should treat the span: should it act
    1635                 :   // "normally" according to css2 or should it effectively
    1636                 :   // "disappear".
    1637                 :   //
    1638                 :   // In general, if the document being processed is in full standards
    1639                 :   // mode then it should act normally (with one exception). The
    1640                 :   // exception case is when a span is continued and yet the span is
    1641                 :   // empty (e.g. compressed whitespace). For this kind of span we treat
    1642                 :   // it as if it were not there so that it doesn't impact the
    1643                 :   // line-height.
    1644                 :   //
    1645                 :   // In almost standards mode or quirks mode, we should sometimes make
    1646                 :   // it disappear. The cases that matter are those where the span
    1647                 :   // contains no real text elements that would provide an ascent and
    1648                 :   // descent and height. However, if css style elements have been
    1649                 :   // applied to the span (border/padding/margin) so that it's clear the
    1650                 :   // document author is intending css2 behavior then we act as if strict
    1651                 :   // mode is set.
    1652                 :   //
    1653                 :   // This code works correctly for preMode, because a blank line
    1654                 :   // in PRE mode is encoded as a text node with a LF in it, since
    1655                 :   // text nodes with only whitespace are considered in preMode.
    1656                 :   //
    1657                 :   // Much of this logic is shared with the various implementations of
    1658                 :   // nsIFrame::IsEmpty since they need to duplicate the way it makes
    1659                 :   // some lines empty.  However, nsIFrame::IsEmpty can't be reused here
    1660                 :   // since this code sets zeroEffectiveSpanBox even when there are
    1661                 :   // non-empty children.
    1662               0 :   bool zeroEffectiveSpanBox = false;
    1663                 :   // XXXldb If we really have empty continuations, then all these other
    1664                 :   // checks don't make sense for them.
    1665                 :   // XXXldb This should probably just use nsIFrame::IsSelfEmpty, assuming that
    1666                 :   // it agrees with this code.  (If it doesn't agree, it probably should.)
    1667               0 :   if ((emptyContinuation ||
    1668               0 :        mPresContext->CompatibilityMode() != eCompatibility_FullStandards) &&
    1669                 :       ((psd == mRootSpan) ||
    1670                 :        ((0 == spanFramePFD->mBorderPadding.top) &&
    1671                 :         (0 == spanFramePFD->mBorderPadding.right) &&
    1672                 :         (0 == spanFramePFD->mBorderPadding.bottom) &&
    1673                 :         (0 == spanFramePFD->mBorderPadding.left) &&
    1674                 :         (0 == spanFramePFD->mMargin.top) &&
    1675                 :         (0 == spanFramePFD->mMargin.right) &&
    1676                 :         (0 == spanFramePFD->mMargin.bottom) &&
    1677                 :         (0 == spanFramePFD->mMargin.left)))) {
    1678                 :     // This code handles an issue with compatibility with non-css
    1679                 :     // conformant browsers. In particular, there are some cases
    1680                 :     // where the font-size and line-height for a span must be
    1681                 :     // ignored and instead the span must *act* as if it were zero
    1682                 :     // sized. In general, if the span contains any non-compressed
    1683                 :     // text then we don't use this logic.
    1684                 :     // However, this is not propagated outwards, since (in compatibility
    1685                 :     // mode) we don't want big line heights for things like
    1686                 :     // <p><font size="-1">Text</font></p>
    1687                 : 
    1688                 :     // We shouldn't include any whitespace that collapses, unless we're
    1689                 :     // preformatted (in which case it shouldn't, but the width=0 test is
    1690                 :     // perhaps incorrect).  This includes whitespace at the beginning of
    1691                 :     // a line and whitespace preceded (?) by other whitespace.
    1692                 :     // See bug 134580 and bug 155333.
    1693               0 :     zeroEffectiveSpanBox = true;
    1694               0 :     for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
    1695               0 :       if (pfd->GetFlag(PFD_ISTEXTFRAME) &&
    1696               0 :           (pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME) || preMode ||
    1697                 :            pfd->mBounds.width != 0)) {
    1698               0 :         zeroEffectiveSpanBox = false;
    1699               0 :         break;
    1700                 :       }
    1701                 :     }
    1702                 :   }
    1703               0 :   psd->mZeroEffectiveSpanBox = zeroEffectiveSpanBox;
    1704                 : 
    1705                 :   // Setup baselineY, minY, and maxY
    1706                 :   nscoord baselineY, minY, maxY;
    1707               0 :   if (psd == mRootSpan) {
    1708                 :     // Use a zero baselineY since we don't yet know where the baseline
    1709                 :     // will be (until we know how tall the line is; then we will
    1710                 :     // know). In addition, use extreme values for the minY and maxY
    1711                 :     // values so that only the child frames will impact their values
    1712                 :     // (since these are children of the block, there is no span box to
    1713                 :     // provide initial values).
    1714               0 :     baselineY = 0;
    1715               0 :     minY = VERTICAL_ALIGN_FRAMES_NO_MINIMUM;
    1716               0 :     maxY = VERTICAL_ALIGN_FRAMES_NO_MAXIMUM;
    1717                 : #ifdef NOISY_VERTICAL_ALIGN
    1718                 :     printf("[RootSpan]");
    1719                 :     nsFrame::ListTag(stdout, spanFrame);
    1720                 :     printf(": pass1 valign frames: topEdge=%d minLineHeight=%d zeroEffectiveSpanBox=%s\n",
    1721                 :            mTopEdge, mMinLineHeight,
    1722                 :            zeroEffectiveSpanBox ? "yes" : "no");
    1723                 : #endif
    1724                 :   }
    1725                 :   else {
    1726                 :     // Compute the logical height for this span. The logical height
    1727                 :     // is based on the line-height value, not the font-size. Also
    1728                 :     // compute the top leading.
    1729                 :     float inflation =
    1730               0 :       nsLayoutUtils::FontSizeInflationInner(spanFrame, mInflationMinFontSize);
    1731                 :     nscoord logicalHeight = nsHTMLReflowState::
    1732                 :       CalcLineHeight(spanFrame->GetStyleContext(),
    1733                 :                      mBlockReflowState->ComputedHeight(),
    1734               0 :                      inflation);
    1735                 :     nscoord contentHeight = spanFramePFD->mBounds.height -
    1736               0 :       spanFramePFD->mBorderPadding.top - spanFramePFD->mBorderPadding.bottom;
    1737                 : 
    1738                 :     // Special-case for a ::first-letter frame, set the line height to
    1739                 :     // the frame height if the user has left line-height == normal 
    1740               0 :     if (spanFramePFD->GetFlag(PFD_ISLETTERFRAME) &&
    1741               0 :         !spanFrame->GetPrevInFlow() &&
    1742               0 :         spanFrame->GetStyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal) {
    1743               0 :       logicalHeight = spanFramePFD->mBounds.height;
    1744                 :     }
    1745                 : 
    1746               0 :     nscoord leading = logicalHeight - contentHeight;
    1747               0 :     psd->mTopLeading = leading / 2;
    1748               0 :     psd->mBottomLeading = leading - psd->mTopLeading;
    1749               0 :     psd->mLogicalHeight = logicalHeight;
    1750                 : 
    1751               0 :     if (zeroEffectiveSpanBox) {
    1752                 :       // When the span-box is to be ignored, zero out the initial
    1753                 :       // values so that the span doesn't impact the final line
    1754                 :       // height. The contents of the span can impact the final line
    1755                 :       // height.
    1756                 : 
    1757                 :       // Note that things are readjusted for this span after its children
    1758                 :       // are reflowed
    1759               0 :       minY = VERTICAL_ALIGN_FRAMES_NO_MINIMUM;
    1760               0 :       maxY = VERTICAL_ALIGN_FRAMES_NO_MAXIMUM;
    1761                 :     }
    1762                 :     else {
    1763                 : 
    1764                 :       // The initial values for the min and max Y values are in the spans
    1765                 :       // coordinate space, and cover the logical height of the span. If
    1766                 :       // there are child frames in this span that stick out of this area
    1767                 :       // then the minY and maxY are updated by the amount of logical
    1768                 :       // height that is outside this range.
    1769               0 :       minY = spanFramePFD->mBorderPadding.top - psd->mTopLeading;
    1770               0 :       maxY = minY + psd->mLogicalHeight;
    1771                 :     }
    1772                 : 
    1773                 :     // This is the distance from the top edge of the parents visual
    1774                 :     // box to the baseline. The span already computed this for us,
    1775                 :     // so just use it.
    1776               0 :     *psd->mBaseline = baselineY = spanFramePFD->mAscent;
    1777                 : 
    1778                 : 
    1779                 : #ifdef NOISY_VERTICAL_ALIGN
    1780                 :     printf("[%sSpan]", (psd == mRootSpan)?"Root":"");
    1781                 :     nsFrame::ListTag(stdout, spanFrame);
    1782                 :     printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d zeroEffectiveSpanBox=%s\n",
    1783                 :            baselineY, psd->mLogicalHeight, psd->mTopLeading,
    1784                 :            spanFramePFD->mBounds.height,
    1785                 :            spanFramePFD->mBorderPadding.top, spanFramePFD->mBorderPadding.bottom,
    1786                 :            zeroEffectiveSpanBox ? "yes" : "no");
    1787                 : #endif
    1788                 :   }
    1789                 : 
    1790               0 :   nscoord maxTopBoxHeight = 0;
    1791               0 :   nscoord maxBottomBoxHeight = 0;
    1792               0 :   PerFrameData* pfd = psd->mFirstFrame;
    1793               0 :   while (nsnull != pfd) {
    1794               0 :     nsIFrame* frame = pfd->mFrame;
    1795                 : 
    1796                 :     // sanity check (see bug 105168, non-reproducible crashes from null frame)
    1797               0 :     NS_ASSERTION(frame, "null frame in PerFrameData - something is very very bad");
    1798               0 :     if (!frame) {
    1799                 :       return;
    1800                 :     }
    1801                 : 
    1802                 :     // Compute the logical height of the frame
    1803                 :     nscoord logicalHeight;
    1804               0 :     PerSpanData* frameSpan = pfd->mSpan;
    1805               0 :     if (frameSpan) {
    1806                 :       // For span frames the logical-height and top-leading was
    1807                 :       // pre-computed when the span was reflowed.
    1808               0 :       logicalHeight = frameSpan->mLogicalHeight;
    1809                 :     }
    1810                 :     else {
    1811                 :       // For other elements the logical height is the same as the
    1812                 :       // frames height plus its margins.
    1813                 :       logicalHeight = pfd->mBounds.height + pfd->mMargin.top +
    1814               0 :         pfd->mMargin.bottom;
    1815                 :     }
    1816                 : 
    1817                 :     // Get vertical-align property
    1818                 :     const nsStyleCoord& verticalAlign =
    1819               0 :       frame->GetStyleTextReset()->mVerticalAlign;
    1820                 : #ifdef NOISY_VERTICAL_ALIGN
    1821                 :     printf("  [frame]");
    1822                 :     nsFrame::ListTag(stdout, frame);
    1823                 :     printf(": verticalAlignUnit=%d (enum == %d)\n",
    1824                 :            verticalAlign.GetUnit(),
    1825                 :            ((eStyleUnit_Enumerated == verticalAlign.GetUnit())
    1826                 :             ? verticalAlign.GetIntValue()
    1827                 :             : -1));
    1828                 : #endif
    1829                 : 
    1830               0 :     if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
    1831               0 :       switch (verticalAlign.GetIntValue()) {
    1832                 :         default:
    1833                 :         case NS_STYLE_VERTICAL_ALIGN_BASELINE:
    1834                 :         {
    1835                 :           // The element's baseline is aligned with the baseline of
    1836                 :           // the parent.
    1837               0 :           pfd->mBounds.y = baselineY - pfd->mAscent;
    1838               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1839               0 :           break;
    1840                 :         }
    1841                 : 
    1842                 :         case NS_STYLE_VERTICAL_ALIGN_SUB:
    1843                 :         {
    1844                 :           // Lower the baseline of the box to the subscript offset
    1845                 :           // of the parent's box. This is identical to the baseline
    1846                 :           // alignment except for the addition of the subscript
    1847                 :           // offset to the baseline Y.
    1848               0 :           nscoord parentSubscript = fm->SubscriptOffset();
    1849               0 :           nscoord revisedBaselineY = baselineY + parentSubscript;
    1850               0 :           pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
    1851               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1852               0 :           break;
    1853                 :         }
    1854                 : 
    1855                 :         case NS_STYLE_VERTICAL_ALIGN_SUPER:
    1856                 :         {
    1857                 :           // Raise the baseline of the box to the superscript offset
    1858                 :           // of the parent's box. This is identical to the baseline
    1859                 :           // alignment except for the subtraction of the superscript
    1860                 :           // offset to the baseline Y.
    1861               0 :           nscoord parentSuperscript = fm->SuperscriptOffset();
    1862               0 :           nscoord revisedBaselineY = baselineY - parentSuperscript;
    1863               0 :           pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
    1864               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1865               0 :           break;
    1866                 :         }
    1867                 : 
    1868                 :         case NS_STYLE_VERTICAL_ALIGN_TOP:
    1869                 :         {
    1870               0 :           pfd->mVerticalAlign = VALIGN_TOP;
    1871               0 :           nscoord subtreeHeight = logicalHeight;
    1872               0 :           if (frameSpan) {
    1873               0 :             subtreeHeight = frameSpan->mMaxY - frameSpan->mMinY;
    1874               0 :             NS_ASSERTION(subtreeHeight >= logicalHeight,
    1875                 :                          "unexpected subtree height");
    1876                 :           }
    1877               0 :           if (subtreeHeight > maxTopBoxHeight) {
    1878               0 :             maxTopBoxHeight = subtreeHeight;
    1879                 :           }
    1880               0 :           break;
    1881                 :         }
    1882                 : 
    1883                 :         case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
    1884                 :         {
    1885               0 :           pfd->mVerticalAlign = VALIGN_BOTTOM;
    1886               0 :           nscoord subtreeHeight = logicalHeight;
    1887               0 :           if (frameSpan) {
    1888               0 :             subtreeHeight = frameSpan->mMaxY - frameSpan->mMinY;
    1889               0 :             NS_ASSERTION(subtreeHeight >= logicalHeight,
    1890                 :                          "unexpected subtree height");
    1891                 :           }
    1892               0 :           if (subtreeHeight > maxBottomBoxHeight) {
    1893               0 :             maxBottomBoxHeight = subtreeHeight;
    1894                 :           }
    1895               0 :           break;
    1896                 :         }
    1897                 : 
    1898                 :         case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
    1899                 :         {
    1900                 :           // Align the midpoint of the frame with 1/2 the parents
    1901                 :           // x-height above the baseline.
    1902               0 :           nscoord parentXHeight = fm->XHeight();
    1903               0 :           if (frameSpan) {
    1904                 :             pfd->mBounds.y = baselineY -
    1905               0 :               (parentXHeight + pfd->mBounds.height)/2;
    1906                 :           }
    1907                 :           else {
    1908                 :             pfd->mBounds.y = baselineY - (parentXHeight + logicalHeight)/2 +
    1909               0 :               pfd->mMargin.top;
    1910                 :           }
    1911               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1912               0 :           break;
    1913                 :         }
    1914                 : 
    1915                 :         case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
    1916                 :         {
    1917                 :           // The top of the logical box is aligned with the top of
    1918                 :           // the parent element's text.
    1919               0 :           nscoord parentAscent = fm->MaxAscent();
    1920               0 :           if (frameSpan) {
    1921                 :             pfd->mBounds.y = baselineY - parentAscent -
    1922               0 :               pfd->mBorderPadding.top + frameSpan->mTopLeading;
    1923                 :           }
    1924                 :           else {
    1925               0 :             pfd->mBounds.y = baselineY - parentAscent + pfd->mMargin.top;
    1926                 :           }
    1927               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1928               0 :           break;
    1929                 :         }
    1930                 : 
    1931                 :         case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
    1932                 :         {
    1933                 :           // The bottom of the logical box is aligned with the
    1934                 :           // bottom of the parent elements text.
    1935               0 :           nscoord parentDescent = fm->MaxDescent();
    1936               0 :           if (frameSpan) {
    1937                 :             pfd->mBounds.y = baselineY + parentDescent -
    1938                 :               pfd->mBounds.height + pfd->mBorderPadding.bottom -
    1939               0 :               frameSpan->mBottomLeading;
    1940                 :           }
    1941                 :           else {
    1942                 :             pfd->mBounds.y = baselineY + parentDescent -
    1943               0 :               pfd->mBounds.height - pfd->mMargin.bottom;
    1944                 :           }
    1945               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1946               0 :           break;
    1947                 :         }
    1948                 : 
    1949                 :         case NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE:
    1950                 :         {
    1951                 :           // Align the midpoint of the frame with the baseline of the parent.
    1952               0 :           if (frameSpan) {
    1953               0 :             pfd->mBounds.y = baselineY - pfd->mBounds.height/2;
    1954                 :           }
    1955                 :           else {
    1956               0 :             pfd->mBounds.y = baselineY - logicalHeight/2 + pfd->mMargin.top;
    1957                 :           }
    1958               0 :           pfd->mVerticalAlign = VALIGN_OTHER;
    1959               0 :           break;
    1960                 :         }
    1961                 :       }
    1962                 :     } else {
    1963                 :       // We have either a coord, a percent, or a calc().
    1964               0 :       nscoord pctBasis = 0;
    1965               0 :       if (verticalAlign.HasPercent()) {
    1966                 :         // Percentages are like lengths, except treated as a percentage
    1967                 :         // of the elements line-height value.
    1968                 :         float inflation =
    1969               0 :           nsLayoutUtils::FontSizeInflationInner(frame, mInflationMinFontSize);
    1970                 :         pctBasis = nsHTMLReflowState::CalcLineHeight(
    1971                 :           frame->GetStyleContext(), mBlockReflowState->ComputedHeight(),
    1972               0 :           inflation);
    1973                 :       }
    1974                 :       nscoord offset =
    1975               0 :         nsRuleNode::ComputeCoordPercentCalc(verticalAlign, pctBasis);
    1976                 :       // According to the CSS2 spec (10.8.1), a positive value
    1977                 :       // "raises" the box by the given distance while a negative value
    1978                 :       // "lowers" the box by the given distance (with zero being the
    1979                 :       // baseline). Since Y coordinates increase towards the bottom of
    1980                 :       // the screen we reverse the sign.
    1981               0 :       nscoord revisedBaselineY = baselineY - offset;
    1982               0 :       pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
    1983               0 :       pfd->mVerticalAlign = VALIGN_OTHER;
    1984                 :     }
    1985                 : 
    1986                 :     // Update minY/maxY for frames that we just placed. Do not factor
    1987                 :     // text into the equation.
    1988               0 :     if (pfd->mVerticalAlign == VALIGN_OTHER) {
    1989                 :       // Text frames do not contribute to the min/max Y values for the
    1990                 :       // line (instead their parent frame's font-size contributes).
    1991                 :       // XXXrbs -- relax this restriction because it causes text frames
    1992                 :       //           to jam together when 'font-size-adjust' is enabled
    1993                 :       //           and layout is using dynamic font heights (bug 20394)
    1994                 :       //        -- Note #1: With this code enabled and with the fact that we are not
    1995                 :       //           using Em[Ascent|Descent] as nsDimensions for text metrics in
    1996                 :       //           GFX mean that the discussion in bug 13072 cannot hold.
    1997                 :       //        -- Note #2: We still don't want empty-text frames to interfere.
    1998                 :       //           For example in quirks mode, avoiding empty text frames prevents
    1999                 :       //           "tall" lines around elements like <hr> since the rules of <hr>
    2000                 :       //           in quirks.css have pseudo text contents with LF in them.
    2001                 : #if 0
    2002                 :       if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
    2003                 : #else
    2004                 :       // Only consider non empty text frames when line-height=normal
    2005               0 :       bool canUpdate = !pfd->GetFlag(PFD_ISTEXTFRAME);
    2006               0 :       if (!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
    2007                 :         canUpdate =
    2008               0 :           frame->GetStyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal;
    2009                 :       }
    2010               0 :       if (canUpdate) {
    2011                 : #endif
    2012                 :         nscoord yTop, yBottom;
    2013               0 :         if (frameSpan) {
    2014                 :           // For spans that were are now placing, use their position
    2015                 :           // plus their already computed min-Y and max-Y values for
    2016                 :           // computing yTop and yBottom.
    2017               0 :           yTop = pfd->mBounds.y + frameSpan->mMinY;
    2018               0 :           yBottom = pfd->mBounds.y + frameSpan->mMaxY;
    2019                 :         }
    2020                 :         else {
    2021               0 :           yTop = pfd->mBounds.y - pfd->mMargin.top;
    2022               0 :           yBottom = yTop + logicalHeight;
    2023                 :         }
    2024               0 :         if (!preMode &&
    2025               0 :             mPresContext->CompatibilityMode() != eCompatibility_FullStandards &&
    2026                 :             !logicalHeight) {
    2027                 :           // Check if it's a BR frame that is not alone on its line (it
    2028                 :           // is given a height of zero to indicate this), and if so reset
    2029                 :           // yTop and yBottom so that BR frames don't influence the line.
    2030               0 :           if (nsGkAtoms::brFrame == frame->GetType()) {
    2031               0 :             yTop = VERTICAL_ALIGN_FRAMES_NO_MINIMUM;
    2032               0 :             yBottom = VERTICAL_ALIGN_FRAMES_NO_MAXIMUM;
    2033                 :           }
    2034                 :         }
    2035               0 :         if (yTop < minY) minY = yTop;
    2036               0 :         if (yBottom > maxY) maxY = yBottom;
    2037                 : #ifdef NOISY_VERTICAL_ALIGN
    2038                 :         printf("     [frame]raw: a=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
    2039                 :                pfd->mAscent, pfd->mBounds.height,
    2040                 :                pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
    2041                 :                logicalHeight,
    2042                 :                frameSpan ? frameSpan->mTopLeading : 0,
    2043                 :                pfd->mBounds.y, minY, maxY);
    2044                 : #endif
    2045                 :       }
    2046               0 :       if (psd != mRootSpan) {
    2047               0 :         frame->SetRect(pfd->mBounds);
    2048                 :       }
    2049                 :     }
    2050               0 :     pfd = pfd->mNext;
    2051                 :   }
    2052                 : 
    2053                 :   // Factor in the minimum line-height when handling the root-span for
    2054                 :   // the block.
    2055               0 :   if (psd == mRootSpan) {
    2056                 :     // We should factor in the block element's minimum line-height (as
    2057                 :     // defined in section 10.8.1 of the css2 spec) assuming that
    2058                 :     // mZeroEffectiveSpanBox is not set on the root span.  This only happens
    2059                 :     // in some cases in quirks mode:
    2060                 :     //  (1) if the root span contains non-whitespace text directly (this
    2061                 :     //      is handled by mZeroEffectiveSpanBox
    2062                 :     //  (2) if this line has a bullet
    2063                 :     //  (3) if this is the last line of an LI, DT, or DD element
    2064                 :     //      (The last line before a block also counts, but not before a
    2065                 :     //      BR) (NN4/IE5 quirk)
    2066                 : 
    2067                 :     // (1) and (2) above
    2068               0 :     bool applyMinLH = !psd->mZeroEffectiveSpanBox || GetFlag(LL_HASBULLET);
    2069               0 :     bool isLastLine = (!mLineBox->IsLineWrapped() && !GetFlag(LL_LINEENDSINBR));
    2070               0 :     if (!applyMinLH && isLastLine) {
    2071               0 :       nsIContent* blockContent = mRootSpan->mFrame->mFrame->GetContent();
    2072               0 :       if (blockContent) {
    2073               0 :         nsIAtom *blockTagAtom = blockContent->Tag();
    2074                 :         // (3) above, if the last line of LI, DT, or DD
    2075               0 :         if (blockTagAtom == nsGkAtoms::li ||
    2076                 :             blockTagAtom == nsGkAtoms::dt ||
    2077                 :             blockTagAtom == nsGkAtoms::dd) {
    2078               0 :           applyMinLH = true;
    2079                 :         }
    2080                 :       }
    2081                 :     }
    2082               0 :     if (applyMinLH) {
    2083               0 :       if (psd->mHasNonemptyContent || preMode || GetFlag(LL_HASBULLET)) {
    2084                 : #ifdef NOISY_VERTICAL_ALIGN
    2085                 :         printf("  [span]==> adjusting min/maxY: currentValues: %d,%d", minY, maxY);
    2086                 : #endif
    2087               0 :         nscoord minimumLineHeight = mMinLineHeight;
    2088                 :         nscoord yTop =
    2089               0 :           -nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineHeight);
    2090               0 :         nscoord yBottom = yTop + minimumLineHeight;
    2091                 : 
    2092               0 :         if (yTop < minY) minY = yTop;
    2093               0 :         if (yBottom > maxY) maxY = yBottom;
    2094                 : 
    2095                 : #ifdef NOISY_VERTICAL_ALIGN
    2096                 :         printf(" new values: %d,%d\n", minY, maxY);
    2097                 : #endif
    2098                 : #ifdef NOISY_VERTICAL_ALIGN
    2099                 :         printf("            Used mMinLineHeight: %d, yTop: %d, yBottom: %d\n", mMinLineHeight, yTop, yBottom);
    2100                 : #endif
    2101                 :       }
    2102                 :       else {
    2103                 :         // XXX issues:
    2104                 :         // [1] BR's on empty lines stop working
    2105                 :         // [2] May not honor css2's notion of handling empty elements
    2106                 :         // [3] blank lines in a pre-section ("\n") (handled with preMode)
    2107                 : 
    2108                 :         // XXX Are there other problems with this?
    2109                 : #ifdef NOISY_VERTICAL_ALIGN
    2110                 :         printf("  [span]==> zapping min/maxY: currentValues: %d,%d newValues: 0,0\n",
    2111                 :                minY, maxY);
    2112                 : #endif
    2113               0 :         minY = maxY = 0;
    2114                 :       }
    2115                 :     }
    2116                 :   }
    2117                 : 
    2118               0 :   if ((minY == VERTICAL_ALIGN_FRAMES_NO_MINIMUM) ||
    2119                 :       (maxY == VERTICAL_ALIGN_FRAMES_NO_MAXIMUM)) {
    2120               0 :     minY = maxY = baselineY;
    2121                 :   }
    2122                 : 
    2123               0 :   if ((psd != mRootSpan) && (psd->mZeroEffectiveSpanBox)) {
    2124                 : #ifdef NOISY_VERTICAL_ALIGN
    2125                 :     printf("   [span]adjusting for zeroEffectiveSpanBox\n");
    2126                 :     printf("     Original: minY=%d, maxY=%d, height=%d, ascent=%d, logicalHeight=%d, topLeading=%d, bottomLeading=%d\n",
    2127                 :            minY, maxY, spanFramePFD->mBounds.height,
    2128                 :            spanFramePFD->mAscent,
    2129                 :            psd->mLogicalHeight, psd->mTopLeading, psd->mBottomLeading);
    2130                 : #endif
    2131               0 :     nscoord goodMinY = spanFramePFD->mBorderPadding.top - psd->mTopLeading;
    2132               0 :     nscoord goodMaxY = goodMinY + psd->mLogicalHeight;
    2133                 : 
    2134                 :     // For cases like the one in bug 714519 (text-decoration placement
    2135                 :     // or making nsLineLayout::IsZeroHeight() handle
    2136                 :     // vertical-align:top/bottom on a descendant of the line that's not
    2137                 :     // a child of it), we want to treat elements that are
    2138                 :     // vertical-align: top or bottom somewhat like children for the
    2139                 :     // purposes of this quirk.  To some extent, this is guessing, since
    2140                 :     // they might end up being aligned anywhere.  However, we'll guess
    2141                 :     // that they'll be placed aligned with the top or bottom of this
    2142                 :     // frame (as though this frame is the only thing in the line).
    2143                 :     // (Guessing isn't crazy, since all we're doing is reducing the
    2144                 :     // scope of a quirk and making the behavior more standards-like.)
    2145               0 :     if (maxTopBoxHeight > maxY - minY) {
    2146                 :       // Distribute maxTopBoxHeight to ascent (baselineY - minY), and
    2147                 :       // then to descent (maxY - baselineY) by adjusting minY or maxY,
    2148                 :       // but not to exceed goodMinY and goodMaxY.
    2149               0 :       nscoord distribute = maxTopBoxHeight - (maxY - minY);
    2150               0 :       nscoord ascentSpace = NS_MAX(minY - goodMinY, 0);
    2151               0 :       if (distribute > ascentSpace) {
    2152               0 :         distribute -= ascentSpace;
    2153               0 :         minY -= ascentSpace;
    2154               0 :         nscoord descentSpace = NS_MAX(goodMaxY - maxY, 0);
    2155               0 :         if (distribute > descentSpace) {
    2156               0 :           maxY += descentSpace;
    2157                 :         } else {
    2158               0 :           maxY += distribute;
    2159                 :         }
    2160                 :       } else {
    2161               0 :         minY -= distribute;
    2162                 :       }
    2163                 :     }
    2164               0 :     if (maxBottomBoxHeight > maxY - minY) {
    2165                 :       // Likewise, but preferring descent to ascent.
    2166               0 :       nscoord distribute = maxBottomBoxHeight - (maxY - minY);
    2167               0 :       nscoord descentSpace = NS_MAX(goodMaxY - maxY, 0);
    2168               0 :       if (distribute > descentSpace) {
    2169               0 :         distribute -= descentSpace;
    2170               0 :         maxY += descentSpace;
    2171               0 :         nscoord ascentSpace = NS_MAX(minY - goodMinY, 0);
    2172               0 :         if (distribute > ascentSpace) {
    2173               0 :           minY -= ascentSpace;
    2174                 :         } else {
    2175               0 :           minY -= distribute;
    2176                 :         }
    2177                 :       } else {
    2178               0 :         maxY += distribute;
    2179                 :       }
    2180                 :     }
    2181                 : 
    2182               0 :     if (minY > goodMinY) {
    2183               0 :       nscoord adjust = minY - goodMinY; // positive
    2184                 : 
    2185                 :       // shrink the logical extents
    2186               0 :       psd->mLogicalHeight -= adjust;
    2187               0 :       psd->mTopLeading -= adjust;
    2188                 :     }
    2189               0 :     if (maxY < goodMaxY) {
    2190               0 :       nscoord adjust = goodMaxY - maxY;
    2191               0 :       psd->mLogicalHeight -= adjust;
    2192               0 :       psd->mBottomLeading -= adjust;
    2193                 :     }
    2194               0 :     if (minY > 0) {
    2195                 : 
    2196                 :       // shrink the content by moving its top down.  This is tricky, since
    2197                 :       // the top is the 0 for many coordinates, so what we do is
    2198                 :       // move everything else up.
    2199               0 :       spanFramePFD->mAscent -= minY; // move the baseline up
    2200               0 :       spanFramePFD->mBounds.height -= minY; // move the bottom up
    2201               0 :       psd->mTopLeading += minY;
    2202               0 :       *psd->mBaseline -= minY;
    2203                 : 
    2204               0 :       pfd = psd->mFirstFrame;
    2205               0 :       while (nsnull != pfd) {
    2206               0 :         pfd->mBounds.y -= minY; // move all the children back up
    2207               0 :         pfd->mFrame->SetRect(pfd->mBounds);
    2208               0 :         pfd = pfd->mNext;
    2209                 :       }
    2210               0 :       maxY -= minY; // since minY is in the frame's own coordinate system
    2211               0 :       minY = 0;
    2212                 :     }
    2213               0 :     if (maxY < spanFramePFD->mBounds.height) {
    2214               0 :       nscoord adjust = spanFramePFD->mBounds.height - maxY;
    2215               0 :       spanFramePFD->mBounds.height -= adjust; // move the bottom up
    2216               0 :       psd->mBottomLeading += adjust;
    2217                 :     }
    2218                 : #ifdef NOISY_VERTICAL_ALIGN
    2219                 :     printf("     New: minY=%d, maxY=%d, height=%d, ascent=%d, logicalHeight=%d, topLeading=%d, bottomLeading=%d\n",
    2220                 :            minY, maxY, spanFramePFD->mBounds.height,
    2221                 :            spanFramePFD->mAscent,
    2222                 :            psd->mLogicalHeight, psd->mTopLeading, psd->mBottomLeading);
    2223                 : #endif
    2224                 :   }
    2225                 : 
    2226               0 :   psd->mMinY = minY;
    2227               0 :   psd->mMaxY = maxY;
    2228                 : #ifdef NOISY_VERTICAL_ALIGN
    2229                 :   printf("  [span]==> minY=%d maxY=%d delta=%d maxTopBoxHeight=%d maxBottomBoxHeight=%d\n",
    2230                 :          minY, maxY, maxY - minY, maxTopBoxHeight, maxBottomBoxHeight);
    2231                 : #endif
    2232               0 :   if (maxTopBoxHeight > mMaxTopBoxHeight) {
    2233               0 :     mMaxTopBoxHeight = maxTopBoxHeight;
    2234                 :   }
    2235               0 :   if (maxBottomBoxHeight > mMaxBottomBoxHeight) {
    2236               0 :     mMaxBottomBoxHeight = maxBottomBoxHeight;
    2237                 :   }
    2238                 : }
    2239                 : 
    2240               0 : static void SlideSpanFrameRect(nsIFrame* aFrame, nscoord aDeltaWidth)
    2241                 : {
    2242               0 :   nsRect r = aFrame->GetRect();
    2243               0 :   r.x -= aDeltaWidth;
    2244               0 :   aFrame->SetRect(r);
    2245               0 : }
    2246                 : 
    2247                 : bool
    2248               0 : nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
    2249                 :                                        nscoord* aDeltaWidth)
    2250                 : {
    2251                 : #ifndef IBMBIDI
    2252                 : // XXX what about NS_STYLE_DIRECTION_RTL?
    2253                 :   if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
    2254                 :     *aDeltaWidth = 0;
    2255                 :     return true;
    2256                 :   }
    2257                 : #endif
    2258                 : 
    2259               0 :   PerFrameData* pfd = psd->mFirstFrame;
    2260               0 :   if (!pfd) {
    2261               0 :     *aDeltaWidth = 0;
    2262               0 :     return false;
    2263                 :   }
    2264               0 :   pfd = pfd->Last();
    2265               0 :   while (nsnull != pfd) {
    2266                 : #ifdef REALLY_NOISY_TRIM
    2267                 :     nsFrame::ListTag(stdout, (psd == mRootSpan
    2268                 :                               ? mBlockReflowState->frame
    2269                 :                               : psd->mFrame->mFrame));
    2270                 :     printf(": attempting trim of ");
    2271                 :     nsFrame::ListTag(stdout, pfd->mFrame);
    2272                 :     printf("\n");
    2273                 : #endif
    2274               0 :     PerSpanData* childSpan = pfd->mSpan;
    2275               0 :     if (childSpan) {
    2276                 :       // Maybe the child span has the trailing white-space in it?
    2277               0 :       if (TrimTrailingWhiteSpaceIn(childSpan, aDeltaWidth)) {
    2278               0 :         nscoord deltaWidth = *aDeltaWidth;
    2279               0 :         if (deltaWidth) {
    2280                 :           // Adjust the child spans frame size
    2281               0 :           pfd->mBounds.width -= deltaWidth;
    2282               0 :           if (psd != mRootSpan) {
    2283                 :             // When the child span is not a direct child of the block
    2284                 :             // we need to update the child spans frame rectangle
    2285                 :             // because it most likely will not be done again. Spans
    2286                 :             // that are direct children of the block will be updated
    2287                 :             // later, however, because the VerticalAlignFrames method
    2288                 :             // will be run after this method.
    2289               0 :             nsIFrame* f = pfd->mFrame;
    2290               0 :             nsRect r = f->GetRect();
    2291               0 :             r.width -= deltaWidth;
    2292               0 :             f->SetRect(r);
    2293                 :           }
    2294                 : 
    2295                 :           // Adjust the right edge of the span that contains the child span
    2296               0 :           psd->mX -= deltaWidth;
    2297                 : 
    2298                 :           // Slide any frames that follow the child span over by the
    2299                 :           // right amount. The only thing that can follow the child
    2300                 :           // span is empty stuff, so we are just making things
    2301                 :           // sensible (keeping the combined area honest).
    2302               0 :           while (pfd->mNext) {
    2303               0 :             pfd = pfd->mNext;
    2304               0 :             pfd->mBounds.x -= deltaWidth;
    2305               0 :             if (psd != mRootSpan) {
    2306                 :               // When the child span is not a direct child of the block
    2307                 :               // we need to update the child spans frame rectangle
    2308                 :               // because it most likely will not be done again. Spans
    2309                 :               // that are direct children of the block will be updated
    2310                 :               // later, however, because the VerticalAlignFrames method
    2311                 :               // will be run after this method.
    2312               0 :               SlideSpanFrameRect(pfd->mFrame, deltaWidth);
    2313                 :             }
    2314                 :           }
    2315                 :         }
    2316               0 :         return true;
    2317                 :       }
    2318                 :     }
    2319               0 :     else if (!pfd->GetFlag(PFD_ISTEXTFRAME) &&
    2320               0 :              !pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) {
    2321                 :       // If we hit a frame on the end that's not text and not a placeholder,
    2322                 :       // then there is no trailing whitespace to trim. Stop the search.
    2323               0 :       *aDeltaWidth = 0;
    2324               0 :       return true;
    2325                 :     }
    2326               0 :     else if (pfd->GetFlag(PFD_ISTEXTFRAME)) {
    2327                 :       // Call TrimTrailingWhiteSpace even on empty textframes because they
    2328                 :       // might have a soft hyphen which should now appear, changing the frame's
    2329                 :       // width
    2330                 :       nsTextFrame::TrimOutput trimOutput = static_cast<nsTextFrame*>(pfd->mFrame)->
    2331               0 :           TrimTrailingWhiteSpace(mBlockReflowState->rendContext);
    2332                 : #ifdef NOISY_TRIM
    2333                 :       nsFrame::ListTag(stdout, (psd == mRootSpan
    2334                 :                                 ? mBlockReflowState->frame
    2335                 :                                 : psd->mFrame->mFrame));
    2336                 :       printf(": trim of ");
    2337                 :       nsFrame::ListTag(stdout, pfd->mFrame);
    2338                 :       printf(" returned %d\n", trimOutput.mDeltaWidth);
    2339                 : #endif
    2340               0 :       if (trimOutput.mLastCharIsJustifiable && pfd->mJustificationNumSpaces > 0) {
    2341               0 :         pfd->mJustificationNumSpaces--;
    2342                 :       }
    2343                 :       
    2344               0 :       if (trimOutput.mChanged) {
    2345               0 :         pfd->SetFlag(PFD_RECOMPUTEOVERFLOW, true);
    2346                 :       }
    2347                 : 
    2348               0 :       if (trimOutput.mDeltaWidth) {
    2349               0 :         pfd->mBounds.width -= trimOutput.mDeltaWidth;
    2350                 : 
    2351                 :         // See if the text frame has already been placed in its parent
    2352               0 :         if (psd != mRootSpan) {
    2353                 :           // The frame was already placed during psd's
    2354                 :           // reflow. Update the frames rectangle now.
    2355               0 :           pfd->mFrame->SetRect(pfd->mBounds);
    2356                 :         }
    2357                 : 
    2358                 :         // Adjust containing span's right edge
    2359               0 :         psd->mX -= trimOutput.mDeltaWidth;
    2360                 : 
    2361                 :         // Slide any frames that follow the text frame over by the
    2362                 :         // right amount. The only thing that can follow the text
    2363                 :         // frame is empty stuff, so we are just making things
    2364                 :         // sensible (keeping the combined area honest).
    2365               0 :         while (pfd->mNext) {
    2366               0 :           pfd = pfd->mNext;
    2367               0 :           pfd->mBounds.x -= trimOutput.mDeltaWidth;
    2368               0 :           if (psd != mRootSpan) {
    2369                 :             // When the child span is not a direct child of the block
    2370                 :             // we need to update the child spans frame rectangle
    2371                 :             // because it most likely will not be done again. Spans
    2372                 :             // that are direct children of the block will be updated
    2373                 :             // later, however, because the VerticalAlignFrames method
    2374                 :             // will be run after this method.
    2375               0 :             SlideSpanFrameRect(pfd->mFrame, trimOutput.mDeltaWidth);
    2376                 :           }
    2377                 :         }
    2378                 :       }
    2379                 : 
    2380               0 :       if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME) || trimOutput.mChanged) {
    2381                 :         // Pass up to caller so they can shrink their span
    2382               0 :         *aDeltaWidth = trimOutput.mDeltaWidth;
    2383               0 :         return true;
    2384                 :       }
    2385                 :     }
    2386               0 :     pfd = pfd->mPrev;
    2387                 :   }
    2388                 : 
    2389               0 :   *aDeltaWidth = 0;
    2390               0 :   return false;
    2391                 : }
    2392                 : 
    2393                 : bool
    2394               0 : nsLineLayout::TrimTrailingWhiteSpace()
    2395                 : {
    2396               0 :   PerSpanData* psd = mRootSpan;
    2397                 :   nscoord deltaWidth;
    2398               0 :   TrimTrailingWhiteSpaceIn(psd, &deltaWidth);
    2399               0 :   return 0 != deltaWidth;
    2400                 : }
    2401                 : 
    2402                 : void
    2403               0 : nsLineLayout::ComputeJustificationWeights(PerSpanData* aPSD,
    2404                 :                                           PRInt32* aNumSpaces,
    2405                 :                                           PRInt32* aNumLetters)
    2406                 : {
    2407               0 :   NS_ASSERTION(aPSD, "null arg");
    2408               0 :   NS_ASSERTION(aNumSpaces, "null arg");
    2409               0 :   NS_ASSERTION(aNumLetters, "null arg");
    2410               0 :   PRInt32 numSpaces = 0;
    2411               0 :   PRInt32 numLetters = 0;
    2412                 : 
    2413               0 :   for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
    2414                 : 
    2415               0 :     if (true == pfd->GetFlag(PFD_ISTEXTFRAME)) {
    2416               0 :       numSpaces += pfd->mJustificationNumSpaces;
    2417               0 :       numLetters += pfd->mJustificationNumLetters;
    2418                 :     }
    2419               0 :     else if (pfd->mSpan != nsnull) {
    2420                 :       PRInt32 spanSpaces;
    2421                 :       PRInt32 spanLetters;
    2422                 : 
    2423               0 :       ComputeJustificationWeights(pfd->mSpan, &spanSpaces, &spanLetters);
    2424                 : 
    2425               0 :       numSpaces += spanSpaces;
    2426               0 :       numLetters += spanLetters;
    2427                 :     }
    2428                 :   }
    2429                 : 
    2430               0 :   *aNumSpaces = numSpaces;
    2431               0 :   *aNumLetters = numLetters;
    2432               0 : }
    2433                 : 
    2434                 : nscoord 
    2435               0 : nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState)
    2436                 : {
    2437               0 :   NS_ASSERTION(aPSD, "null arg");
    2438               0 :   NS_ASSERTION(aState, "null arg");
    2439                 : 
    2440               0 :   nscoord deltaX = 0;
    2441               0 :   for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
    2442                 :     // Don't reposition bullets (and other frames that occur out of X-order?)
    2443               0 :     if (!pfd->GetFlag(PFD_ISBULLET)) {
    2444               0 :       nscoord dw = 0;
    2445                 :       
    2446               0 :       pfd->mBounds.x += deltaX;
    2447                 :       
    2448               0 :       if (true == pfd->GetFlag(PFD_ISTEXTFRAME)) {
    2449               0 :         if (aState->mTotalWidthForSpaces > 0 &&
    2450                 :             aState->mTotalNumSpaces > 0) {
    2451               0 :           aState->mNumSpacesProcessed += pfd->mJustificationNumSpaces;
    2452                 : 
    2453                 :           nscoord newAllocatedWidthForSpaces =
    2454                 :             (aState->mTotalWidthForSpaces*aState->mNumSpacesProcessed)
    2455               0 :               /aState->mTotalNumSpaces;
    2456                 :           
    2457               0 :           dw += newAllocatedWidthForSpaces - aState->mWidthForSpacesProcessed;
    2458                 : 
    2459               0 :           aState->mWidthForSpacesProcessed = newAllocatedWidthForSpaces;
    2460                 :         }
    2461                 : 
    2462               0 :         if (aState->mTotalWidthForLetters > 0 &&
    2463                 :             aState->mTotalNumLetters > 0) {
    2464               0 :           aState->mNumLettersProcessed += pfd->mJustificationNumLetters;
    2465                 : 
    2466                 :           nscoord newAllocatedWidthForLetters =
    2467                 :             (aState->mTotalWidthForLetters*aState->mNumLettersProcessed)
    2468               0 :               /aState->mTotalNumLetters;
    2469                 :           
    2470               0 :           dw += newAllocatedWidthForLetters - aState->mWidthForLettersProcessed;
    2471                 : 
    2472               0 :           aState->mWidthForLettersProcessed = newAllocatedWidthForLetters;
    2473                 :         }
    2474                 :         
    2475               0 :         if (dw) {
    2476               0 :           pfd->SetFlag(PFD_RECOMPUTEOVERFLOW, true);
    2477                 :         }
    2478                 :       }
    2479                 :       else {
    2480               0 :         if (nsnull != pfd->mSpan) {
    2481               0 :           dw += ApplyFrameJustification(pfd->mSpan, aState);
    2482                 :         }
    2483                 :       }
    2484                 :       
    2485               0 :       pfd->mBounds.width += dw;
    2486                 : 
    2487               0 :       deltaX += dw;
    2488               0 :       pfd->mFrame->SetRect(pfd->mBounds);
    2489                 :     }
    2490                 :   }
    2491               0 :   return deltaX;
    2492                 : }
    2493                 : 
    2494                 : void
    2495               0 : nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
    2496                 :                                     bool aIsLastLine)
    2497                 : {
    2498                 :   /**
    2499                 :    * NOTE: aIsLastLine ain't necessarily so: it is correctly set by caller
    2500                 :    * only in cases where the last line needs special handling.
    2501                 :    */
    2502               0 :   PerSpanData* psd = mRootSpan;
    2503               0 :   NS_WARN_IF_FALSE(psd->mRightEdge != NS_UNCONSTRAINEDSIZE,
    2504                 :                    "have unconstrained width; this should only result from "
    2505                 :                    "very large sizes, not attempts at intrinsic width "
    2506                 :                    "calculation");
    2507               0 :   nscoord availWidth = psd->mRightEdge - psd->mLeftEdge;
    2508               0 :   nscoord remainingWidth = availWidth - aLineBounds.width;
    2509                 : #ifdef NOISY_HORIZONTAL_ALIGN
    2510                 :     nsFrame::ListTag(stdout, mBlockReflowState->frame);
    2511                 :     printf(": availWidth=%d lineWidth=%d delta=%d\n",
    2512                 :            availWidth, aLineBounds.width, remainingWidth);
    2513                 : #endif
    2514               0 :   nscoord dx = 0;
    2515                 : 
    2516               0 :   if (remainingWidth > 0) {
    2517               0 :     PRUint8 textAlign = mStyleText->mTextAlign;
    2518                 : 
    2519                 :     /* 
    2520                 :      * 'text-align-last: auto' is equivalent to the value of the 'text-align'
    2521                 :      * property except when 'text-align' is set to 'justify', in which case it
    2522                 :      * is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise.
    2523                 :      *
    2524                 :      * XXX: the code below will have to change when we implement text-justify
    2525                 :      */
    2526               0 :     if (aIsLastLine) {
    2527               0 :       if (mStyleText->mTextAlignLast == NS_STYLE_TEXT_ALIGN_AUTO) {
    2528               0 :         if (textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
    2529               0 :           textAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
    2530                 :         }
    2531                 :       } else {
    2532               0 :         textAlign = mStyleText->mTextAlignLast;
    2533                 :       }
    2534                 :     }
    2535                 : 
    2536               0 :     switch (textAlign) {
    2537                 :       case NS_STYLE_TEXT_ALIGN_JUSTIFY:
    2538                 :         PRInt32 numSpaces;
    2539                 :         PRInt32 numLetters;
    2540                 :             
    2541               0 :         ComputeJustificationWeights(psd, &numSpaces, &numLetters);
    2542                 : 
    2543               0 :         if (numSpaces > 0) {
    2544                 :           FrameJustificationState state =
    2545               0 :             { numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 };
    2546                 : 
    2547                 :           // Apply the justification, and make sure to update our linebox
    2548                 :           // width to account for it.
    2549               0 :           aLineBounds.width += ApplyFrameJustification(psd, &state);
    2550               0 :           remainingWidth = availWidth - aLineBounds.width;
    2551               0 :           break;
    2552                 :         }
    2553                 :         // Fall through to the default case if we could not justify to fill
    2554                 :         // the space.
    2555                 : 
    2556                 :       case NS_STYLE_TEXT_ALIGN_DEFAULT:
    2557               0 :         if (NS_STYLE_DIRECTION_LTR == psd->mDirection) {
    2558                 :           // default alignment for left-to-right is left so do nothing
    2559               0 :           break;
    2560                 :         }
    2561                 :         // Fall through to align right case for default alignment
    2562                 :         // used when the direction is right-to-left.
    2563                 : 
    2564                 :       case NS_STYLE_TEXT_ALIGN_RIGHT:
    2565                 :       case NS_STYLE_TEXT_ALIGN_MOZ_RIGHT:
    2566               0 :         dx = remainingWidth;
    2567               0 :         break;
    2568                 : 
    2569                 :       case NS_STYLE_TEXT_ALIGN_END:
    2570               0 :         if (NS_STYLE_DIRECTION_LTR == psd->mDirection) {
    2571                 :           // Do what we do for ALIGN_RIGHT
    2572               0 :           dx = remainingWidth;
    2573               0 :           break;
    2574                 :         }
    2575                 :         // Fall through to align left case for end alignment
    2576                 :         // used when the direction is right-to-left.
    2577                 : 
    2578                 :       case NS_STYLE_TEXT_ALIGN_LEFT:
    2579                 :       case NS_STYLE_TEXT_ALIGN_MOZ_LEFT:
    2580               0 :         break;
    2581                 : 
    2582                 :       case NS_STYLE_TEXT_ALIGN_CENTER:
    2583                 :       case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
    2584               0 :         dx = remainingWidth / 2;
    2585               0 :         break;
    2586                 :     }
    2587                 :   }
    2588               0 :   else if (remainingWidth < 0) {
    2589               0 :     if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
    2590               0 :       dx = remainingWidth;
    2591               0 :       psd->mX += dx;
    2592               0 :       psd->mLeftEdge += dx;
    2593                 :     }
    2594                 :   }
    2595                 : 
    2596               0 :   if (NS_STYLE_DIRECTION_RTL == psd->mDirection &&
    2597               0 :       !psd->mChangedFrameDirection) {
    2598               0 :     if (psd->mLastFrame->GetFlag(PFD_ISBULLET) ) {
    2599               0 :       PerFrameData* bulletPfd = psd->mLastFrame;
    2600               0 :       bulletPfd->mBounds.x -= remainingWidth;
    2601               0 :       bulletPfd->mFrame->SetRect(bulletPfd->mBounds);
    2602                 :     }
    2603               0 :     psd->mChangedFrameDirection = true;
    2604                 :   }
    2605                 : 
    2606               0 :   if (dx) {
    2607               0 :     for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
    2608               0 :       pfd->mBounds.x += dx;
    2609               0 :       pfd->mFrame->SetRect(pfd->mBounds);
    2610                 :     }
    2611               0 :     aLineBounds.x += dx;
    2612                 :   }
    2613               0 : }
    2614                 : 
    2615                 : void
    2616               0 : nsLineLayout::RelativePositionFrames(nsOverflowAreas& aOverflowAreas)
    2617                 : {
    2618               0 :   RelativePositionFrames(mRootSpan, aOverflowAreas);
    2619               0 : }
    2620                 : 
    2621                 : void
    2622               0 : nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflowAreas)
    2623                 : {
    2624               0 :   nsOverflowAreas overflowAreas;
    2625               0 :   if (nsnull != psd->mFrame) {
    2626                 :     // The span's overflow areas come in three parts:
    2627                 :     // -- this frame's width and height
    2628                 :     // -- pfd->mOverflowAreas, which is the area of a bullet or the union
    2629                 :     // of a relatively positioned frame's absolute children
    2630                 :     // -- the bounds of all inline descendants
    2631                 :     // The former two parts are computed right here, we gather the descendants
    2632                 :     // below.
    2633                 :     // At this point psd->mFrame->mBounds might be out of date since
    2634                 :     // bidi reordering can move and resize the frames. So use the frame's
    2635                 :     // rect instead of mBounds.
    2636               0 :     nsRect adjustedBounds(nsPoint(0, 0), psd->mFrame->mFrame->GetSize());
    2637                 : 
    2638               0 :     overflowAreas.ScrollableOverflow().UnionRect(
    2639               0 :       psd->mFrame->mOverflowAreas.ScrollableOverflow(), adjustedBounds);
    2640               0 :     overflowAreas.VisualOverflow().UnionRect(
    2641               0 :       psd->mFrame->mOverflowAreas.VisualOverflow(), adjustedBounds);
    2642                 :   }
    2643                 :   else {
    2644                 :     // The minimum combined area for the frames that are direct
    2645                 :     // children of the block starts at the upper left corner of the
    2646                 :     // line and is sized to match the size of the line's bounding box
    2647                 :     // (the same size as the values returned from VerticalAlignFrames)
    2648               0 :     overflowAreas.VisualOverflow().x = psd->mLeftEdge;
    2649                 :     // If this turns out to be negative, the rect will be treated as empty.
    2650                 :     // Which is just fine.
    2651               0 :     overflowAreas.VisualOverflow().width =
    2652               0 :       psd->mX - overflowAreas.VisualOverflow().x;
    2653               0 :     overflowAreas.VisualOverflow().y = mTopEdge;
    2654               0 :     overflowAreas.VisualOverflow().height = mFinalLineHeight;
    2655                 : 
    2656               0 :     overflowAreas.ScrollableOverflow() = overflowAreas.VisualOverflow();
    2657                 :   }
    2658                 : 
    2659               0 :   for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
    2660               0 :     nsIFrame* frame = pfd->mFrame;
    2661               0 :     nsPoint origin = frame->GetPosition();
    2662                 : 
    2663                 :     // Adjust the origin of the frame
    2664               0 :     if (pfd->GetFlag(PFD_RELATIVEPOS)) {
    2665                 :       // right and bottom are handled by
    2666                 :       // nsHTMLReflowState::ComputeRelativeOffsets
    2667               0 :       nsPoint change(pfd->mOffsets.left, pfd->mOffsets.top);
    2668               0 :       origin += change;
    2669               0 :       frame->SetPosition(origin);
    2670                 :     }
    2671                 : 
    2672                 :     // We must position the view correctly before positioning its
    2673                 :     // descendants so that widgets are positioned properly (since only
    2674                 :     // some views have widgets).
    2675               0 :     if (frame->HasView())
    2676                 :       nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
    2677               0 :         frame->GetView(), pfd->mOverflowAreas.VisualOverflow(),
    2678               0 :         NS_FRAME_NO_SIZE_VIEW);
    2679                 : 
    2680                 :     // Note: the combined area of a child is in its coordinate
    2681                 :     // system. We adjust the childs combined area into our coordinate
    2682                 :     // system before computing the aggregated value by adding in
    2683                 :     // <b>x</b> and <b>y</b> which were computed above.
    2684               0 :     nsOverflowAreas r;
    2685               0 :     if (pfd->mSpan) {
    2686                 :       // Compute a new combined area for the child span before
    2687                 :       // aggregating it into our combined area.
    2688               0 :       RelativePositionFrames(pfd->mSpan, r);
    2689                 :     } else {
    2690               0 :       r = pfd->mOverflowAreas;
    2691               0 :       if (pfd->GetFlag(PFD_ISTEXTFRAME)) {
    2692                 :         // We need to recompute overflow areas in two cases:
    2693                 :         // (1) When PFD_RECOMPUTEOVERFLOW is set due to trimming
    2694                 :         // (2) When there are text decorations, since we can't recompute the
    2695                 :         //     overflow area until Reflow and VerticalAlignLine have finished
    2696               0 :         if (pfd->GetFlag(PFD_RECOMPUTEOVERFLOW) ||
    2697               0 :             frame->GetStyleContext()->HasTextDecorationLines()) {
    2698               0 :           nsTextFrame* f = static_cast<nsTextFrame*>(frame);
    2699               0 :           r = f->RecomputeOverflow(*mBlockReflowState);
    2700                 :         }
    2701               0 :         frame->FinishAndStoreOverflow(r, frame->GetSize());
    2702                 :       }
    2703                 : 
    2704                 :       // If we have something that's not an inline but with a complex frame
    2705                 :       // hierarchy inside that contains views, they need to be
    2706                 :       // positioned.
    2707                 :       // All descendant views must be repositioned even if this frame
    2708                 :       // does have a view in case this frame's view does not have a
    2709                 :       // widget and some of the descendant views do have widgets --
    2710                 :       // otherwise the widgets won't be repositioned.
    2711               0 :       nsContainerFrame::PositionChildViews(frame);
    2712                 :     }
    2713                 : 
    2714                 :     // Do this here (rather than along with setting the overflow rect
    2715                 :     // below) so we get leaf frames as well.  No need to worry
    2716                 :     // about the root span, since it doesn't have a frame.
    2717               0 :     if (frame->HasView())
    2718                 :       nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
    2719                 :                                                  frame->GetView(),
    2720               0 :                                                  r.VisualOverflow(),
    2721               0 :                                                  NS_FRAME_NO_MOVE_VIEW);
    2722                 : 
    2723               0 :     overflowAreas.UnionWith(r + origin);
    2724                 :   }
    2725                 : 
    2726                 :   // If we just computed a spans combined area, we need to update its
    2727                 :   // overflow rect...
    2728               0 :   if (psd->mFrame) {
    2729               0 :     PerFrameData* spanPFD = psd->mFrame;
    2730               0 :     nsIFrame* frame = spanPFD->mFrame;
    2731               0 :     frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
    2732                 :   }
    2733               0 :   aOverflowAreas = overflowAreas;
    2734               0 : }

Generated by: LCOV version 1.7