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

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-04-21 | 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