LCOV - code coverage report
Current view: top level - layout/generic - nsLineBox.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 180 547 32.9 %
Date: 2017-07-14 16:53:18 Functions: 26 58 44.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13