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

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim:cindent:ts=2:et:sw=2:
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   L. David Baron <dbaron@dbaron.org>
      25                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /* representation of one line within a block frame, a CSS line box */
      42                 : 
      43                 : #include "nsLineBox.h"
      44                 : #include "nsLineLayout.h"
      45                 : #include "prprf.h"
      46                 : #include "nsBlockFrame.h"
      47                 : #include "nsGkAtoms.h"
      48                 : #include "nsFrameManager.h"
      49                 : #ifdef IBMBIDI
      50                 : #include "nsBidiPresUtils.h"
      51                 : #endif
      52                 : 
      53                 : #ifdef DEBUG
      54                 : static PRInt32 ctorCount;
      55               0 : PRInt32 nsLineBox::GetCtorCount() { return ctorCount; }
      56                 : #endif
      57                 : 
      58                 : #ifndef _MSC_VER
      59                 : // static nsLineBox constant; initialized in the header file.
      60                 : const PRUint32 nsLineBox::kMinChildCountForHashtable;
      61                 : #endif
      62                 : 
      63               0 : nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock)
      64                 :   : mFirstChild(aFrame),
      65                 :     mBounds(0, 0, 0, 0),
      66                 :     mAscent(0),
      67               0 :     mData(nsnull)
      68                 : {
      69               0 :   MOZ_COUNT_CTOR(nsLineBox);
      70                 : #ifdef DEBUG
      71               0 :   ++ctorCount;
      72               0 :   NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child");
      73               0 :   nsIFrame* f = aFrame;
      74               0 :   for (PRInt32 n = aCount; n > 0; f = f->GetNextSibling(), --n) {
      75               0 :     NS_ASSERTION(aIsBlock == f->GetStyleDisplay()->IsBlockOutside(),
      76                 :                  "wrong kind of child frame");
      77                 :   }
      78                 : #endif
      79                 : 
      80               0 :   mAllFlags = 0;
      81                 : #if NS_STYLE_CLEAR_NONE > 0
      82                 :   mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
      83                 : #endif
      84               0 :   mChildCount = aCount;
      85               0 :   MarkDirty();
      86               0 :   mFlags.mBlock = aIsBlock;
      87               0 : }
      88                 : 
      89               0 : nsLineBox::~nsLineBox()
      90                 : {
      91               0 :   MOZ_COUNT_DTOR(nsLineBox);
      92               0 :   if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
      93               0 :     delete mFrames;
      94                 :   }  
      95               0 :   Cleanup();
      96               0 : }
      97                 : 
      98                 : nsLineBox*
      99               0 : NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, bool aIsBlock)
     100                 : {
     101               0 :   return new (aPresShell) nsLineBox(aFrame, 1, aIsBlock);
     102                 : }
     103                 : 
     104                 : nsLineBox*
     105               0 : NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
     106                 :               nsIFrame* aFrame, PRInt32 aCount)
     107                 : {
     108               0 :   nsLineBox* newLine = new (aPresShell) nsLineBox(aFrame, aCount, false);
     109               0 :   if (newLine) {
     110               0 :     newLine->NoteFramesMovedFrom(aFromLine);
     111                 :   }
     112               0 :   return newLine;
     113                 : }
     114                 : 
     115                 : void
     116               0 : nsLineBox::StealHashTableFrom(nsLineBox* aFromLine, PRUint32 aFromLineNewCount)
     117                 : {
     118               0 :   MOZ_ASSERT(!mFlags.mHasHashedFrames);
     119               0 :   MOZ_ASSERT(GetChildCount() >= PRInt32(aFromLineNewCount));
     120               0 :   mFrames = aFromLine->mFrames;
     121               0 :   mFlags.mHasHashedFrames = 1;
     122               0 :   aFromLine->mFlags.mHasHashedFrames = 0;
     123               0 :   aFromLine->mChildCount = aFromLineNewCount;
     124                 :   // remove aFromLine's frames that aren't on this line
     125               0 :   nsIFrame* f = aFromLine->mFirstChild;
     126               0 :   for (PRUint32 i = 0; i < aFromLineNewCount; f = f->GetNextSibling(), ++i) {
     127               0 :     mFrames->RemoveEntry(f);
     128                 :   }
     129               0 : }
     130                 : 
     131                 : void
     132               0 : nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine)
     133                 : {
     134               0 :   PRUint32 fromCount = aFromLine->GetChildCount();
     135               0 :   PRUint32 toCount = GetChildCount();
     136               0 :   MOZ_ASSERT(toCount <= fromCount, "moved more frames than aFromLine has");
     137               0 :   PRUint32 fromNewCount = fromCount - toCount;
     138               0 :   if (NS_LIKELY(!aFromLine->mFlags.mHasHashedFrames)) {
     139               0 :     aFromLine->mChildCount = fromNewCount;
     140               0 :     MOZ_ASSERT(toCount < kMinChildCountForHashtable);
     141               0 :   } else if (fromNewCount < kMinChildCountForHashtable) {
     142                 :     // aFromLine has a hash table but will not have it after moving the frames
     143                 :     // so this line can steal the hash table if it needs it.
     144               0 :     if (toCount >= kMinChildCountForHashtable) {
     145               0 :       StealHashTableFrom(aFromLine, fromNewCount);
     146                 :     } else {
     147               0 :       delete aFromLine->mFrames;
     148               0 :       aFromLine->mFlags.mHasHashedFrames = 0;
     149               0 :       aFromLine->mChildCount = fromNewCount;
     150                 :     }
     151                 :   } else {
     152                 :     // aFromLine still needs a hash table.
     153               0 :     if (toCount < kMinChildCountForHashtable) {
     154                 :       // remove the moved frames from it
     155               0 :       nsIFrame* f = mFirstChild;
     156               0 :       for (PRUint32 i = 0; i < toCount; f = f->GetNextSibling(), ++i) {
     157               0 :         aFromLine->mFrames->RemoveEntry(f);
     158                 :       }
     159               0 :     } else if (toCount <= fromNewCount) {
     160                 :       // This line needs a hash table, allocate a hash table for it since that
     161                 :       // means fewer hash ops.
     162               0 :       nsIFrame* f = mFirstChild;
     163               0 :       for (PRUint32 i = 0; i < toCount; f = f->GetNextSibling(), ++i) {
     164               0 :         aFromLine->mFrames->RemoveEntry(f); // toCount RemoveEntry
     165                 :       }
     166               0 :       SwitchToHashtable(); // toCount PutEntry
     167                 :     } else {
     168                 :       // This line needs a hash table, but it's fewer hash ops to steal
     169                 :       // aFromLine's hash table and allocate a new hash table for that line.
     170               0 :       StealHashTableFrom(aFromLine, fromNewCount); // fromNewCount RemoveEntry
     171               0 :       aFromLine->SwitchToHashtable(); // fromNewCount PutEntry
     172                 :     }
     173                 :   }
     174               0 : }
     175                 : 
     176                 : // Overloaded new operator. Uses an arena (which comes from the presShell)
     177                 : // to perform the allocation.
     178                 : void*
     179               0 : nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
     180                 : {
     181               0 :   return aPresShell->AllocateMisc(sz);
     182                 : }
     183                 : 
     184                 : void
     185               0 : nsLineBox::Destroy(nsIPresShell* aPresShell)
     186                 : {
     187               0 :   this->nsLineBox::~nsLineBox();
     188               0 :   aPresShell->FreeMisc(sizeof(*this), this);
     189               0 : }
     190                 : 
     191                 : void
     192               0 : nsLineBox::Cleanup()
     193                 : {
     194               0 :   if (mData) {
     195               0 :     if (IsBlock()) {
     196               0 :       delete mBlockData;
     197                 :     }
     198                 :     else {
     199               0 :       delete mInlineData;
     200                 :     }
     201               0 :     mData = nsnull;
     202                 :   }
     203               0 : }
     204                 : 
     205                 : #ifdef DEBUG
     206                 : static void
     207               0 : ListFloats(FILE* out, PRInt32 aIndent, const nsFloatCacheList& aFloats)
     208                 : {
     209               0 :   nsFloatCache* fc = aFloats.Head();
     210               0 :   while (fc) {
     211               0 :     nsFrame::IndentBy(out, aIndent);
     212               0 :     nsIFrame* frame = fc->mFloat;
     213               0 :     fprintf(out, "floatframe@%p ", static_cast<void*>(frame));
     214               0 :     if (frame) {
     215               0 :       nsAutoString frameName;
     216               0 :       frame->GetFrameName(frameName);
     217               0 :       fputs(NS_LossyConvertUTF16toASCII(frameName).get(), out);
     218                 :     }
     219                 :     else {
     220               0 :       fputs("\n###!!! NULL out-of-flow frame", out);
     221                 :     }
     222               0 :     fprintf(out, "\n");
     223               0 :     fc = fc->Next();
     224                 :   }
     225               0 : }
     226                 : #endif
     227                 : 
     228                 : #ifdef DEBUG
     229                 : const char *
     230               0 : BreakTypeToString(PRUint8 aBreakType)
     231                 : {
     232               0 :   switch (aBreakType) {
     233               0 :   case NS_STYLE_CLEAR_NONE: return "nobr";
     234               0 :   case NS_STYLE_CLEAR_LEFT: return "leftbr";
     235               0 :   case NS_STYLE_CLEAR_RIGHT: return "rightbr";
     236               0 :   case NS_STYLE_CLEAR_LEFT_AND_RIGHT: return "leftbr+rightbr";
     237               0 :   case NS_STYLE_CLEAR_LINE: return "linebr";
     238               0 :   case NS_STYLE_CLEAR_BLOCK: return "blockbr";
     239               0 :   case NS_STYLE_CLEAR_COLUMN: return "columnbr";
     240               0 :   case NS_STYLE_CLEAR_PAGE: return "pagebr";
     241                 :   default:
     242                 :     break;
     243                 :   }
     244               0 :   return "unknown";
     245                 : }
     246                 : 
     247                 : char*
     248               0 : nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
     249                 : {
     250                 :   PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]",
     251               0 :               IsBlock() ? "block" : "inline",
     252               0 :               IsDirty() ? "dirty" : "clean",
     253               0 :               IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean",
     254               0 :               IsImpactedByFloat() ? "impacted" : "not impacted",
     255               0 :               IsLineWrapped() ? "wrapped" : "not wrapped",
     256               0 :               BreakTypeToString(GetBreakTypeBefore()),
     257               0 :               BreakTypeToString(GetBreakTypeAfter()),
     258               0 :               mAllFlags);
     259               0 :   return aBuf;
     260                 : }
     261                 : 
     262                 : void
     263               0 : nsLineBox::List(FILE* out, PRInt32 aIndent) const
     264                 : {
     265                 :   PRInt32 i;
     266                 : 
     267               0 :   for (i = aIndent; --i >= 0; ) fputs("  ", out);
     268                 :   char cbuf[100];
     269                 :   fprintf(out, "line %p: count=%d state=%s ",
     270                 :           static_cast<const void*>(this), GetChildCount(),
     271               0 :           StateToString(cbuf, sizeof(cbuf)));
     272               0 :   if (IsBlock() && !GetCarriedOutBottomMargin().IsZero()) {
     273               0 :     fprintf(out, "bm=%d ", GetCarriedOutBottomMargin().get());
     274                 :   }
     275                 :   fprintf(out, "{%d,%d,%d,%d} ",
     276               0 :           mBounds.x, mBounds.y, mBounds.width, mBounds.height);
     277               0 :   if (mData) {
     278                 :     fprintf(out, "vis-overflow={%d,%d,%d,%d} scr-overflow={%d,%d,%d,%d} ",
     279               0 :             mData->mOverflowAreas.VisualOverflow().x,
     280               0 :             mData->mOverflowAreas.VisualOverflow().y,
     281               0 :             mData->mOverflowAreas.VisualOverflow().width,
     282               0 :             mData->mOverflowAreas.VisualOverflow().height,
     283               0 :             mData->mOverflowAreas.ScrollableOverflow().x,
     284               0 :             mData->mOverflowAreas.ScrollableOverflow().y,
     285               0 :             mData->mOverflowAreas.ScrollableOverflow().width,
     286               0 :             mData->mOverflowAreas.ScrollableOverflow().height);
     287                 :   }
     288               0 :   fprintf(out, "<\n");
     289                 : 
     290               0 :   nsIFrame* frame = mFirstChild;
     291               0 :   PRInt32 n = GetChildCount();
     292               0 :   while (--n >= 0) {
     293               0 :     frame->List(out, aIndent + 1);
     294               0 :     frame = frame->GetNextSibling();
     295                 :   }
     296                 : 
     297               0 :   for (i = aIndent; --i >= 0; ) fputs("  ", out);
     298               0 :   if (HasFloats()) {
     299               0 :     fputs("> floats <\n", out);
     300               0 :     ListFloats(out, aIndent + 1, mInlineData->mFloats);
     301               0 :     for (i = aIndent; --i >= 0; ) fputs("  ", out);
     302                 :   }
     303               0 :   fputs(">\n", out);
     304               0 : }
     305                 : #endif
     306                 : 
     307                 : #ifdef DEBUG
     308                 : nsIFrame*
     309               0 : nsLineBox::LastChild() const
     310                 : {
     311               0 :   nsIFrame* frame = mFirstChild;
     312               0 :   PRInt32 n = GetChildCount() - 1;
     313               0 :   while (--n >= 0) {
     314               0 :     frame = frame->GetNextSibling();
     315                 :   }
     316               0 :   return frame;
     317                 : }
     318                 : #endif
     319                 : 
     320                 : PRInt32
     321               0 : nsLineBox::IndexOf(nsIFrame* aFrame) const
     322                 : {
     323               0 :   PRInt32 i, n = GetChildCount();
     324               0 :   nsIFrame* frame = mFirstChild;
     325               0 :   for (i = 0; i < n; i++) {
     326               0 :     if (frame == aFrame) {
     327               0 :       return i;
     328                 :     }
     329               0 :     frame = frame->GetNextSibling();
     330                 :   }
     331               0 :   return -1;
     332                 : }
     333                 : 
     334                 : bool
     335               0 : nsLineBox::IsEmpty() const
     336                 : {
     337               0 :   if (IsBlock())
     338               0 :     return mFirstChild->IsEmpty();
     339                 : 
     340                 :   PRInt32 n;
     341                 :   nsIFrame *kid;
     342               0 :   for (n = GetChildCount(), kid = mFirstChild;
     343                 :        n > 0;
     344                 :        --n, kid = kid->GetNextSibling())
     345                 :   {
     346               0 :     if (!kid->IsEmpty())
     347               0 :       return false;
     348                 :   }
     349               0 :   if (HasBullet()) {
     350               0 :     return false;
     351                 :   }
     352               0 :   return true;
     353                 : }
     354                 : 
     355                 : bool
     356               0 : nsLineBox::CachedIsEmpty()
     357                 : {
     358               0 :   if (mFlags.mDirty) {
     359               0 :     return IsEmpty();
     360                 :   }
     361                 :   
     362               0 :   if (mFlags.mEmptyCacheValid) {
     363               0 :     return mFlags.mEmptyCacheState;
     364                 :   }
     365                 : 
     366                 :   bool result;
     367               0 :   if (IsBlock()) {
     368               0 :     result = mFirstChild->CachedIsEmpty();
     369                 :   } else {
     370                 :     PRInt32 n;
     371                 :     nsIFrame *kid;
     372               0 :     result = true;
     373               0 :     for (n = GetChildCount(), kid = mFirstChild;
     374                 :          n > 0;
     375                 :          --n, kid = kid->GetNextSibling())
     376                 :       {
     377               0 :         if (!kid->CachedIsEmpty()) {
     378               0 :           result = false;
     379               0 :           break;
     380                 :         }
     381                 :       }
     382               0 :     if (HasBullet()) {
     383               0 :       result = false;
     384                 :     }
     385                 :   }
     386                 : 
     387               0 :   mFlags.mEmptyCacheValid = true;
     388               0 :   mFlags.mEmptyCacheState = result;
     389               0 :   return result;
     390                 : }
     391                 : 
     392                 : void
     393               0 : nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
     394                 :                           nsIFrame* aDestructRoot)
     395                 : {
     396               0 :   if (! aLines.empty()) {
     397                 :     // Delete our child frames before doing anything else. In particular
     398                 :     // we do all of this before our base class releases it's hold on the
     399                 :     // view.
     400                 : #ifdef DEBUG
     401               0 :     PRInt32 numFrames = 0;
     402                 : #endif
     403               0 :     for (nsIFrame* child = aLines.front()->mFirstChild; child; ) {
     404               0 :       nsIFrame* nextChild = child->GetNextSibling();
     405               0 :       child->SetNextSibling(nsnull);
     406               0 :       child->DestroyFrom((aDestructRoot) ? aDestructRoot : child);
     407               0 :       child = nextChild;
     408                 : #ifdef DEBUG
     409               0 :       numFrames++;
     410                 : #endif
     411                 :     }
     412                 : 
     413               0 :     nsIPresShell *shell = aPresContext->PresShell();
     414                 : 
     415               0 :     do {
     416               0 :       nsLineBox* line = aLines.front();
     417                 : #ifdef DEBUG
     418               0 :       numFrames -= line->GetChildCount();
     419                 : #endif
     420               0 :       aLines.pop_front();
     421               0 :       line->Destroy(shell);
     422               0 :     } while (! aLines.empty());
     423                 : #ifdef DEBUG
     424               0 :     NS_ASSERTION(numFrames == 0, "number of frames deleted does not match");
     425                 : #endif
     426                 :   }
     427               0 : }
     428                 : 
     429                 : bool
     430               0 : nsLineBox::RFindLineContaining(nsIFrame* aFrame,
     431                 :                                const nsLineList::iterator& aBegin,
     432                 :                                nsLineList::iterator& aEnd,
     433                 :                                nsIFrame* aLastFrameBeforeEnd,
     434                 :                                PRInt32* aFrameIndexInLine)
     435                 : {
     436               0 :   NS_PRECONDITION(aFrame, "null ptr");
     437                 : 
     438               0 :   nsIFrame* curFrame = aLastFrameBeforeEnd;
     439               0 :   while (aBegin != aEnd) {
     440               0 :     --aEnd;
     441               0 :     NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame");
     442               0 :     if (NS_UNLIKELY(aEnd->mFlags.mHasHashedFrames) &&
     443               0 :         !aEnd->Contains(aFrame)) {
     444               0 :       if (aEnd->mFirstChild) {
     445               0 :         curFrame = aEnd->mFirstChild->GetPrevSibling();
     446                 :       }
     447               0 :       continue;
     448                 :     }
     449                 :     // i is the index of curFrame in aEnd
     450               0 :     PRInt32 i = aEnd->GetChildCount() - 1;
     451               0 :     while (i >= 0) {
     452               0 :       if (curFrame == aFrame) {
     453               0 :         *aFrameIndexInLine = i;
     454               0 :         return true;
     455                 :       }
     456               0 :       --i;
     457               0 :       curFrame = curFrame->GetPrevSibling();
     458                 :     }
     459               0 :     MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!");
     460                 :   }
     461               0 :   *aFrameIndexInLine = -1;
     462               0 :   return false;
     463                 : }
     464                 : 
     465                 : nsCollapsingMargin
     466               0 : nsLineBox::GetCarriedOutBottomMargin() const
     467                 : {
     468               0 :   NS_ASSERTION(IsBlock(),
     469                 :                "GetCarriedOutBottomMargin called on non-block line.");
     470               0 :   return (IsBlock() && mBlockData)
     471                 :     ? mBlockData->mCarriedOutBottomMargin
     472               0 :     : nsCollapsingMargin();
     473                 : }
     474                 : 
     475                 : bool
     476               0 : nsLineBox::SetCarriedOutBottomMargin(nsCollapsingMargin aValue)
     477                 : {
     478               0 :   bool changed = false;
     479               0 :   if (IsBlock()) {
     480               0 :     if (!aValue.IsZero()) {
     481               0 :       if (!mBlockData) {
     482               0 :         mBlockData = new ExtraBlockData(mBounds);
     483                 :       }
     484               0 :       changed = aValue != mBlockData->mCarriedOutBottomMargin;
     485               0 :       mBlockData->mCarriedOutBottomMargin = aValue;
     486                 :     }
     487               0 :     else if (mBlockData) {
     488               0 :       changed = aValue != mBlockData->mCarriedOutBottomMargin;
     489               0 :       mBlockData->mCarriedOutBottomMargin = aValue;
     490               0 :       MaybeFreeData();
     491                 :     }
     492                 :   }
     493               0 :   return changed;
     494                 : }
     495                 : 
     496                 : void
     497               0 : nsLineBox::MaybeFreeData()
     498                 : {
     499               0 :   if (mData && mData->mOverflowAreas == nsOverflowAreas(mBounds, mBounds)) {
     500               0 :     if (IsInline()) {
     501               0 :       if (mInlineData->mFloats.IsEmpty()) {
     502               0 :         delete mInlineData;
     503               0 :         mInlineData = nsnull;
     504                 :       }
     505                 :     }
     506               0 :     else if (mBlockData->mCarriedOutBottomMargin.IsZero()) {
     507               0 :       delete mBlockData;
     508               0 :       mBlockData = nsnull;
     509                 :     }
     510                 :   }
     511               0 : }
     512                 : 
     513                 : // XXX get rid of this???
     514                 : nsFloatCache*
     515               0 : nsLineBox::GetFirstFloat()
     516                 : {
     517               0 :   NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats");
     518               0 :   return mInlineData ? mInlineData->mFloats.Head() : nsnull;
     519                 : }
     520                 : 
     521                 : // XXX this might be too eager to free memory
     522                 : void
     523               0 : nsLineBox::FreeFloats(nsFloatCacheFreeList& aFreeList)
     524                 : {
     525               0 :   NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats");
     526               0 :   if (IsInline() && mInlineData) {
     527               0 :     if (mInlineData->mFloats.NotEmpty()) {
     528               0 :       aFreeList.Append(mInlineData->mFloats);
     529                 :     }
     530               0 :     MaybeFreeData();
     531                 :   }
     532               0 : }
     533                 : 
     534                 : void
     535               0 : nsLineBox::AppendFloats(nsFloatCacheFreeList& aFreeList)
     536                 : { 
     537               0 :   NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats");
     538               0 :   if (IsInline()) {
     539               0 :     if (aFreeList.NotEmpty()) {
     540               0 :       if (!mInlineData) {
     541               0 :         mInlineData = new ExtraInlineData(mBounds);
     542                 :       }
     543               0 :       mInlineData->mFloats.Append(aFreeList);
     544                 :     }
     545                 :   }
     546               0 : }
     547                 : 
     548                 : bool
     549               0 : nsLineBox::RemoveFloat(nsIFrame* aFrame)
     550                 : {
     551               0 :   NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats");
     552               0 :   if (IsInline() && mInlineData) {
     553               0 :     nsFloatCache* fc = mInlineData->mFloats.Find(aFrame);
     554               0 :     if (fc) {
     555                 :       // Note: the placeholder is part of the line's child list
     556                 :       // and will be removed later.
     557               0 :       mInlineData->mFloats.Remove(fc);
     558               0 :       delete fc;
     559               0 :       MaybeFreeData();
     560               0 :       return true;
     561                 :     }
     562                 :   }
     563               0 :   return false;
     564                 : }
     565                 : 
     566                 : void
     567               0 : nsLineBox::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
     568                 : {
     569               0 :   NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
     570               0 :     NS_ASSERTION(aOverflowAreas.Overflow(otype).width >= 0,
     571                 :                  "illegal width for combined area");
     572               0 :     NS_ASSERTION(aOverflowAreas.Overflow(otype).height >= 0,
     573                 :                  "illegal height for combined area");
     574                 :   }
     575               0 :   if (!aOverflowAreas.VisualOverflow().IsEqualInterior(mBounds) ||
     576               0 :       !aOverflowAreas.ScrollableOverflow().IsEqualEdges(mBounds)) {
     577               0 :     if (!mData) {
     578               0 :       if (IsInline()) {
     579               0 :         mInlineData = new ExtraInlineData(mBounds);
     580                 :       }
     581                 :       else {
     582               0 :         mBlockData = new ExtraBlockData(mBounds);
     583                 :       }
     584                 :     }
     585               0 :     mData->mOverflowAreas = aOverflowAreas;
     586                 :   }
     587               0 :   else if (mData) {
     588                 :     // Store away new value so that MaybeFreeData compares against
     589                 :     // the right value.
     590               0 :     mData->mOverflowAreas = aOverflowAreas;
     591               0 :     MaybeFreeData();
     592                 :   }
     593               0 : }
     594                 : 
     595                 : //----------------------------------------------------------------------
     596                 : 
     597                 : 
     598                 : static nsLineBox* gDummyLines[1];
     599                 : 
     600               0 : nsLineIterator::nsLineIterator()
     601                 : {
     602               0 :   mLines = gDummyLines;
     603               0 :   mNumLines = 0;
     604               0 :   mIndex = 0;
     605               0 :   mRightToLeft = false;
     606               0 : }
     607                 : 
     608               0 : nsLineIterator::~nsLineIterator()
     609                 : {
     610               0 :   if (mLines != gDummyLines) {
     611               0 :     delete [] mLines;
     612                 :   }
     613               0 : }
     614                 : 
     615                 : /* virtual */ void
     616               0 : nsLineIterator::DisposeLineIterator()
     617                 : {
     618               0 :   delete this;
     619               0 : }
     620                 : 
     621                 : nsresult
     622               0 : nsLineIterator::Init(nsLineList& aLines, bool aRightToLeft)
     623                 : {
     624               0 :   mRightToLeft = aRightToLeft;
     625                 : 
     626                 :   // Count the lines
     627               0 :   PRInt32 numLines = aLines.size();
     628               0 :   if (0 == numLines) {
     629                 :     // Use gDummyLines so that we don't need null pointer checks in
     630                 :     // the accessor methods
     631               0 :     mLines = gDummyLines;
     632               0 :     return NS_OK;
     633                 :   }
     634                 : 
     635                 :   // Make a linear array of the lines
     636               0 :   mLines = new nsLineBox*[numLines];
     637               0 :   if (!mLines) {
     638                 :     // Use gDummyLines so that we don't need null pointer checks in
     639                 :     // the accessor methods
     640               0 :     mLines = gDummyLines;
     641               0 :     return NS_ERROR_OUT_OF_MEMORY;
     642                 :   }
     643               0 :   nsLineBox** lp = mLines;
     644               0 :   for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end() ;
     645                 :        line != line_end;
     646                 :        ++line)
     647                 :   {
     648               0 :     *lp++ = line;
     649                 :   }
     650               0 :   mNumLines = numLines;
     651               0 :   return NS_OK;
     652                 : }
     653                 : 
     654                 : PRInt32
     655               0 : nsLineIterator::GetNumLines()
     656                 : {
     657               0 :   return mNumLines;
     658                 : }
     659                 : 
     660                 : bool
     661               0 : nsLineIterator::GetDirection()
     662                 : {
     663               0 :   return mRightToLeft;
     664                 : }
     665                 : 
     666                 : NS_IMETHODIMP
     667               0 : nsLineIterator::GetLine(PRInt32 aLineNumber,
     668                 :                         nsIFrame** aFirstFrameOnLine,
     669                 :                         PRInt32* aNumFramesOnLine,
     670                 :                         nsRect& aLineBounds,
     671                 :                         PRUint32* aLineFlags)
     672                 : {
     673               0 :   NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
     674               0 :   NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
     675               0 :   NS_ENSURE_ARG_POINTER(aLineFlags);
     676                 : 
     677               0 :   if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
     678               0 :     *aFirstFrameOnLine = nsnull;
     679               0 :     *aNumFramesOnLine = 0;
     680               0 :     aLineBounds.SetRect(0, 0, 0, 0);
     681               0 :     return NS_OK;
     682                 :   }
     683               0 :   nsLineBox* line = mLines[aLineNumber];
     684               0 :   *aFirstFrameOnLine = line->mFirstChild;
     685               0 :   *aNumFramesOnLine = line->GetChildCount();
     686               0 :   aLineBounds = line->mBounds;
     687                 : 
     688               0 :   PRUint32 flags = 0;
     689               0 :   if (line->IsBlock()) {
     690               0 :     flags |= NS_LINE_FLAG_IS_BLOCK;
     691                 :   }
     692                 :   else {
     693               0 :     if (line->HasBreakAfter())
     694               0 :       flags |= NS_LINE_FLAG_ENDS_IN_BREAK;
     695                 :   }
     696               0 :   *aLineFlags = flags;
     697                 : 
     698               0 :   return NS_OK;
     699                 : }
     700                 : 
     701                 : PRInt32
     702               0 : nsLineIterator::FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine)
     703                 : {
     704               0 :   NS_PRECONDITION(aStartLine <= mNumLines, "Bogus line numbers");
     705               0 :   PRInt32 lineNumber = aStartLine;
     706               0 :   while (lineNumber != mNumLines) {
     707               0 :     nsLineBox* line = mLines[lineNumber];
     708               0 :     if (line->Contains(aFrame)) {
     709               0 :       return lineNumber;
     710                 :     }
     711               0 :     ++lineNumber;
     712                 :   }
     713               0 :   return -1;
     714                 : }
     715                 : 
     716                 : #ifdef IBMBIDI
     717                 : NS_IMETHODIMP
     718               0 : nsLineIterator::CheckLineOrder(PRInt32                  aLine,
     719                 :                                bool                     *aIsReordered,
     720                 :                                nsIFrame                 **aFirstVisual,
     721                 :                                nsIFrame                 **aLastVisual)
     722                 : {
     723               0 :   NS_ASSERTION (aLine >= 0 && aLine < mNumLines, "aLine out of range!");
     724               0 :   nsLineBox* line = mLines[aLine];
     725                 : 
     726               0 :   if (!line->mFirstChild) { // empty line
     727               0 :     *aIsReordered = false;
     728               0 :     *aFirstVisual = nsnull;
     729               0 :     *aLastVisual = nsnull;
     730               0 :     return NS_OK;
     731                 :   }
     732                 : 
     733                 :   nsIFrame* leftmostFrame;
     734                 :   nsIFrame* rightmostFrame;
     735               0 :   *aIsReordered = nsBidiPresUtils::CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame);
     736                 : 
     737                 :   // map leftmost/rightmost to first/last according to paragraph direction
     738               0 :   *aFirstVisual = mRightToLeft ? rightmostFrame : leftmostFrame;
     739               0 :   *aLastVisual = mRightToLeft ? leftmostFrame : rightmostFrame;
     740                 : 
     741               0 :   return NS_OK;
     742                 : }
     743                 : #endif // IBMBIDI
     744                 : 
     745                 : NS_IMETHODIMP
     746               0 : nsLineIterator::FindFrameAt(PRInt32 aLineNumber,
     747                 :                             nscoord aX,
     748                 :                             nsIFrame** aFrameFound,
     749                 :                             bool* aXIsBeforeFirstFrame,
     750                 :                             bool* aXIsAfterLastFrame)
     751                 : {
     752               0 :   NS_PRECONDITION(aFrameFound && aXIsBeforeFirstFrame && aXIsAfterLastFrame,
     753                 :                   "null OUT ptr");
     754               0 :   if (!aFrameFound || !aXIsBeforeFirstFrame || !aXIsAfterLastFrame) {
     755               0 :     return NS_ERROR_NULL_POINTER;
     756                 :   }
     757               0 :   if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
     758               0 :     return NS_ERROR_INVALID_ARG;
     759                 :   }
     760                 : 
     761               0 :   nsLineBox* line = mLines[aLineNumber];
     762               0 :   if (!line) {
     763               0 :     *aFrameFound = nsnull;
     764               0 :     *aXIsBeforeFirstFrame = true;
     765               0 :     *aXIsAfterLastFrame = false;
     766               0 :     return NS_OK;
     767                 :   }
     768                 : 
     769               0 :   if (line->mBounds.width == 0 && line->mBounds.height == 0)
     770               0 :     return NS_ERROR_FAILURE;
     771                 : 
     772               0 :   nsIFrame* frame = line->mFirstChild;
     773               0 :   nsIFrame* closestFromLeft = nsnull;
     774               0 :   nsIFrame* closestFromRight = nsnull;
     775               0 :   PRInt32 n = line->GetChildCount();
     776               0 :   while (n--) {
     777               0 :     nsRect rect = frame->GetRect();
     778               0 :     if (rect.width > 0) {
     779                 :       // If aX is inside this frame - this is it
     780               0 :       if (rect.x <= aX && rect.XMost() > aX) {
     781               0 :         closestFromLeft = closestFromRight = frame;
     782                 :         break;
     783                 :       }
     784               0 :       if (rect.x < aX) {
     785               0 :         if (!closestFromLeft || 
     786               0 :             rect.XMost() > closestFromLeft->GetRect().XMost())
     787               0 :           closestFromLeft = frame;
     788                 :       }
     789                 :       else {
     790               0 :         if (!closestFromRight ||
     791               0 :             rect.x < closestFromRight->GetRect().x)
     792               0 :           closestFromRight = frame;
     793                 :       }
     794                 :     }
     795               0 :     frame = frame->GetNextSibling();
     796                 :   }
     797               0 :   if (!closestFromLeft && !closestFromRight) {
     798                 :     // All frames were zero-width. Just take the first one.
     799               0 :     closestFromLeft = closestFromRight = line->mFirstChild;
     800                 :   }
     801               0 :   *aXIsBeforeFirstFrame = mRightToLeft ? !closestFromRight : !closestFromLeft;
     802               0 :   *aXIsAfterLastFrame = mRightToLeft ? !closestFromLeft : !closestFromRight;
     803               0 :   if (closestFromLeft == closestFromRight) {
     804               0 :     *aFrameFound = closestFromLeft;
     805                 :   }
     806               0 :   else if (!closestFromLeft) {
     807               0 :     *aFrameFound = closestFromRight;
     808                 :   }
     809               0 :   else if (!closestFromRight) {
     810               0 :     *aFrameFound = closestFromLeft;
     811                 :   }
     812                 :   else { // we're between two frames
     813               0 :     nscoord delta = closestFromRight->GetRect().x - closestFromLeft->GetRect().XMost();
     814               0 :     if (aX < closestFromLeft->GetRect().XMost() + delta/2)
     815               0 :       *aFrameFound = closestFromLeft;
     816                 :     else
     817               0 :       *aFrameFound = closestFromRight;
     818                 :   }
     819               0 :   return NS_OK;
     820                 : }
     821                 : 
     822                 : NS_IMETHODIMP
     823               0 : nsLineIterator::GetNextSiblingOnLine(nsIFrame*& aFrame, PRInt32 aLineNumber)
     824                 : {
     825               0 :   aFrame = aFrame->GetNextSibling();
     826               0 :   return NS_OK;
     827                 : }
     828                 : 
     829                 : //----------------------------------------------------------------------
     830                 : 
     831                 : #ifdef NS_BUILD_REFCNT_LOGGING
     832               0 : nsFloatCacheList::nsFloatCacheList() :
     833               0 :   mHead(nsnull)
     834                 : {
     835               0 :   MOZ_COUNT_CTOR(nsFloatCacheList);
     836               0 : }
     837                 : #endif
     838                 : 
     839               0 : nsFloatCacheList::~nsFloatCacheList()
     840                 : {
     841               0 :   DeleteAll();
     842               0 :   MOZ_COUNT_DTOR(nsFloatCacheList);
     843               0 : }
     844                 : 
     845                 : void
     846               0 : nsFloatCacheList::DeleteAll()
     847                 : {
     848               0 :   nsFloatCache* c = mHead;
     849               0 :   while (c) {
     850               0 :     nsFloatCache* next = c->Next();
     851               0 :     delete c;
     852               0 :     c = next;
     853                 :   }
     854               0 :   mHead = nsnull;
     855               0 : }
     856                 : 
     857                 : nsFloatCache*
     858               0 : nsFloatCacheList::Tail() const
     859                 : {
     860               0 :   nsFloatCache* fc = mHead;
     861               0 :   while (fc) {
     862               0 :     if (!fc->mNext) {
     863               0 :       break;
     864                 :     }
     865               0 :     fc = fc->mNext;
     866                 :   }
     867               0 :   return fc;
     868                 : }
     869                 : 
     870                 : void
     871               0 : nsFloatCacheList::Append(nsFloatCacheFreeList& aList)
     872                 : {
     873               0 :   NS_PRECONDITION(aList.NotEmpty(), "Appending empty list will fail");
     874                 :   
     875               0 :   nsFloatCache* tail = Tail();
     876               0 :   if (tail) {
     877               0 :     NS_ASSERTION(!tail->mNext, "Bogus!");
     878               0 :     tail->mNext = aList.mHead;
     879                 :   }
     880                 :   else {
     881               0 :     NS_ASSERTION(!mHead, "Bogus!");
     882               0 :     mHead = aList.mHead;
     883                 :   }
     884               0 :   aList.mHead = nsnull;
     885               0 :   aList.mTail = nsnull;
     886               0 : }
     887                 : 
     888                 : nsFloatCache*
     889               0 : nsFloatCacheList::Find(nsIFrame* aOutOfFlowFrame)
     890                 : {
     891               0 :   nsFloatCache* fc = mHead;
     892               0 :   while (fc) {
     893               0 :     if (fc->mFloat == aOutOfFlowFrame) {
     894               0 :       break;
     895                 :     }
     896               0 :     fc = fc->Next();
     897                 :   }
     898               0 :   return fc;
     899                 : }
     900                 : 
     901                 : nsFloatCache*
     902               0 : nsFloatCacheList::RemoveAndReturnPrev(nsFloatCache* aElement)
     903                 : {
     904               0 :   nsFloatCache* fc = mHead;
     905               0 :   nsFloatCache* prev = nsnull;
     906               0 :   while (fc) {
     907               0 :     if (fc == aElement) {
     908               0 :       if (prev) {
     909               0 :         prev->mNext = fc->mNext;
     910                 :       } else {
     911               0 :         mHead = fc->mNext;
     912                 :       }
     913               0 :       return prev;
     914                 :     }
     915               0 :     prev = fc;
     916               0 :     fc = fc->mNext;
     917                 :   }
     918               0 :   return nsnull;
     919                 : }
     920                 : 
     921                 : //----------------------------------------------------------------------
     922                 : 
     923                 : #ifdef NS_BUILD_REFCNT_LOGGING
     924               0 : nsFloatCacheFreeList::nsFloatCacheFreeList() :
     925               0 :   mTail(nsnull)
     926                 : {
     927               0 :   MOZ_COUNT_CTOR(nsFloatCacheFreeList);
     928               0 : }
     929                 : 
     930               0 : nsFloatCacheFreeList::~nsFloatCacheFreeList()
     931                 : {
     932               0 :   MOZ_COUNT_DTOR(nsFloatCacheFreeList);
     933               0 : }
     934                 : #endif
     935                 :   
     936                 : void
     937               0 : nsFloatCacheFreeList::Append(nsFloatCacheList& aList)
     938                 : {
     939               0 :   NS_PRECONDITION(aList.NotEmpty(), "Appending empty list will fail");
     940                 :   
     941               0 :   if (mTail) {
     942               0 :     NS_ASSERTION(!mTail->mNext, "Bogus");
     943               0 :     mTail->mNext = aList.mHead;
     944                 :   }
     945                 :   else {
     946               0 :     NS_ASSERTION(!mHead, "Bogus");
     947               0 :     mHead = aList.mHead;
     948                 :   }
     949               0 :   mTail = aList.Tail();
     950               0 :   aList.mHead = nsnull;
     951               0 : }
     952                 : 
     953                 : void
     954               0 : nsFloatCacheFreeList::Remove(nsFloatCache* aElement)
     955                 : {
     956               0 :   nsFloatCache* prev = nsFloatCacheList::RemoveAndReturnPrev(aElement);
     957               0 :   if (mTail == aElement) {
     958               0 :     mTail = prev;
     959                 :   }
     960               0 : }
     961                 : 
     962                 : void
     963               0 : nsFloatCacheFreeList::DeleteAll()
     964                 : {
     965               0 :   nsFloatCacheList::DeleteAll();
     966               0 :   mTail = nsnull;
     967               0 : }
     968                 : 
     969                 : nsFloatCache*
     970               0 : nsFloatCacheFreeList::Alloc(nsIFrame* aFloat)
     971                 : {
     972               0 :   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
     973                 :                   "This is a float cache, why isn't the frame out-of-flow?");
     974               0 :   nsFloatCache* fc = mHead;
     975               0 :   if (mHead) {
     976               0 :     if (mHead == mTail) {
     977               0 :       mHead = mTail = nsnull;
     978                 :     }
     979                 :     else {
     980               0 :       mHead = fc->mNext;
     981                 :     }
     982               0 :     fc->mNext = nsnull;
     983                 :   }
     984                 :   else {
     985               0 :     fc = new nsFloatCache();
     986                 :   }
     987               0 :   fc->mFloat = aFloat;
     988               0 :   return fc;
     989                 : }
     990                 : 
     991                 : void
     992               0 : nsFloatCacheFreeList::Append(nsFloatCache* aFloat)
     993                 : {
     994               0 :   NS_ASSERTION(!aFloat->mNext, "Bogus!");
     995               0 :   aFloat->mNext = nsnull;
     996               0 :   if (mTail) {
     997               0 :     NS_ASSERTION(!mTail->mNext, "Bogus!");
     998               0 :     mTail->mNext = aFloat;
     999               0 :     mTail = aFloat;
    1000                 :   }
    1001                 :   else {
    1002               0 :     NS_ASSERTION(!mHead, "Bogus!");
    1003               0 :     mHead = mTail = aFloat;
    1004                 :   }
    1005               0 : }
    1006                 : 
    1007                 : //----------------------------------------------------------------------
    1008                 : 
    1009               0 : nsFloatCache::nsFloatCache()
    1010                 :   : mFloat(nsnull),
    1011               0 :     mNext(nsnull)
    1012                 : {
    1013               0 :   MOZ_COUNT_CTOR(nsFloatCache);
    1014               0 : }
    1015                 : 
    1016                 : #ifdef NS_BUILD_REFCNT_LOGGING
    1017               0 : nsFloatCache::~nsFloatCache()
    1018                 : {
    1019               0 :   MOZ_COUNT_DTOR(nsFloatCache);
    1020               0 : }
    1021                 : #endif

Generated by: LCOV version 1.7