LCOV - code coverage report
Current view: top level - layout/generic - nsLineBox.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 52 524 9.9 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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           0 : 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           0 :   , 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           0 :   MOZ_COUNT_CTOR(nsLineBox);
      54             : #ifdef DEBUG
      55           0 :   ++ctorCount;
      56           0 :   NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child");
      57             :   nsIFrame* f = aFrame;
      58           0 :   for (int32_t n = aCount; n > 0; f = f->GetNextSibling(), --n) {
      59           0 :     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           0 :   mChildCount = aCount;
      67           0 :   MarkDirty();
      68           0 :   mFlags.mBlock = aIsBlock;
      69           0 : }
      70             : 
      71           0 : nsLineBox::~nsLineBox()
      72             : {
      73           0 :   MOZ_COUNT_DTOR(nsLineBox);
      74           0 :   if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) {
      75           0 :     delete mFrames;
      76             :   }
      77           0 :   Cleanup();
      78           0 : }
      79             : 
      80             : nsLineBox*
      81           0 : NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, bool aIsBlock)
      82             : {
      83           0 :   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           0 : nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell)
     159             : {
     160           0 :   return aPresShell->AllocateByObjectID(eArenaObjectID_nsLineBox, sz);
     161             : }
     162             : 
     163             : void
     164           0 : nsLineBox::Destroy(nsIPresShell* aPresShell)
     165             : {
     166           0 :   this->nsLineBox::~nsLineBox();
     167           0 :   aPresShell->FreeByObjectID(eArenaObjectID_nsLineBox, this);
     168           0 : }
     169             : 
     170             : void
     171           0 : nsLineBox::Cleanup()
     172             : {
     173           0 :   if (mData) {
     174           0 :     if (IsBlock()) {
     175           0 :       delete mBlockData;
     176             :     }
     177             :     else {
     178           0 :       delete mInlineData;
     179             :     }
     180           0 :     mData = nullptr;
     181             :   }
     182           0 : }
     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             : /* static */ const char*
     207           0 : nsLineBox::BreakTypeToString(StyleClear aBreakType)
     208             : {
     209           0 :   switch (aBreakType) {
     210             :     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           0 : nsLineBox::IndexOf(nsIFrame* aFrame) const
     312             : {
     313           0 :   int32_t i, n = GetChildCount();
     314           0 :   nsIFrame* frame = mFirstChild;
     315           0 :   for (i = 0; i < n; i++) {
     316           0 :     if (frame == aFrame) {
     317             :       return i;
     318             :     }
     319           0 :     frame = frame->GetNextSibling();
     320             :   }
     321             :   return -1;
     322             : }
     323             : 
     324             : bool
     325           0 : nsLineBox::IsEmpty() const
     326             : {
     327           0 :   if (IsBlock())
     328           0 :     return mFirstChild->IsEmpty();
     329             : 
     330             :   int32_t n;
     331             :   nsIFrame *kid;
     332           0 :   for (n = GetChildCount(), kid = mFirstChild;
     333           0 :        n > 0;
     334             :        --n, kid = kid->GetNextSibling())
     335             :   {
     336           0 :     if (!kid->IsEmpty())
     337             :       return false;
     338             :   }
     339           0 :   if (HasBullet()) {
     340             :     return false;
     341             :   }
     342           0 :   return true;
     343             : }
     344             : 
     345             : bool
     346           0 : nsLineBox::CachedIsEmpty()
     347             : {
     348           0 :   if (mFlags.mDirty) {
     349           0 :     return IsEmpty();
     350             :   }
     351             : 
     352           0 :   if (mFlags.mEmptyCacheValid) {
     353           0 :     return mFlags.mEmptyCacheState;
     354             :   }
     355             : 
     356             :   bool result;
     357           0 :   if (IsBlock()) {
     358           0 :     result = mFirstChild->CachedIsEmpty();
     359             :   } else {
     360             :     int32_t n;
     361             :     nsIFrame *kid;
     362           0 :     result = true;
     363           0 :     for (n = GetChildCount(), kid = mFirstChild;
     364           0 :          n > 0;
     365             :          --n, kid = kid->GetNextSibling())
     366             :       {
     367           0 :         if (!kid->CachedIsEmpty()) {
     368             :           result = false;
     369             :           break;
     370             :         }
     371             :       }
     372           0 :     if (HasBullet()) {
     373           0 :       result = false;
     374             :     }
     375             :   }
     376             : 
     377           0 :   mFlags.mEmptyCacheValid = true;
     378           0 :   mFlags.mEmptyCacheState = result;
     379           0 :   return result;
     380             : }
     381             : 
     382             : void
     383           0 : nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
     384             :                           nsIFrame* aDestructRoot, nsFrameList* aFrames,
     385             :                           PostDestroyData& aPostDestroyData)
     386             : {
     387           0 :   nsIPresShell* shell = aPresContext->PresShell();
     388             : 
     389             :   // Keep our line list and frame list up to date as we
     390             :   // remove frames, in case something wants to traverse the
     391             :   // frame tree while we're destroying.
     392           0 :   while (!aLines.empty()) {
     393           0 :     nsLineBox* line = aLines.front();
     394           0 :     if (MOZ_UNLIKELY(line->mFlags.mHasHashedFrames)) {
     395           0 :       line->SwitchToCounter();  // Avoid expensive has table removals.
     396             :     }
     397           0 :     while (line->GetChildCount() > 0) {
     398           0 :       nsIFrame* child = aFrames->RemoveFirstChild();
     399           0 :       MOZ_DIAGNOSTIC_ASSERT(child->PresContext() == aPresContext);
     400           0 :       MOZ_DIAGNOSTIC_ASSERT(child == line->mFirstChild, "Lines out of sync");
     401           0 :       line->mFirstChild = aFrames->FirstChild();
     402           0 :       line->NoteFrameRemoved(child);
     403           3 :       child->DestroyFrom(aDestructRoot, aPostDestroyData);
     404             :     }
     405           0 :     MOZ_DIAGNOSTIC_ASSERT(line == aLines.front(),
     406             :                           "destroying child frames messed up our lines!");
     407           3 :     aLines.pop_front();
     408           0 :     line->Destroy(shell);
     409             :   }
     410           4 : }
     411             : 
     412             : bool
     413           0 : nsLineBox::RFindLineContaining(nsIFrame* aFrame,
     414             :                                const nsLineList::iterator& aBegin,
     415             :                                nsLineList::iterator& aEnd,
     416             :                                nsIFrame* aLastFrameBeforeEnd,
     417             :                                int32_t* aFrameIndexInLine)
     418             : {
     419           0 :   MOZ_ASSERT(aFrame, "null ptr");
     420             : 
     421             :   nsIFrame* curFrame = aLastFrameBeforeEnd;
     422           0 :   while (aBegin != aEnd) {
     423           0 :     --aEnd;
     424           0 :     NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame");
     425           0 :     if (MOZ_UNLIKELY(aEnd->mFlags.mHasHashedFrames) &&
     426           0 :         !aEnd->Contains(aFrame)) {
     427           0 :       if (aEnd->mFirstChild) {
     428           0 :         curFrame = aEnd->mFirstChild->GetPrevSibling();
     429             :       }
     430             :       continue;
     431             :     }
     432             :     // i is the index of curFrame in aEnd
     433           0 :     int32_t i = aEnd->GetChildCount() - 1;
     434           0 :     while (i >= 0) {
     435           0 :       if (curFrame == aFrame) {
     436           0 :         *aFrameIndexInLine = i;
     437           0 :         return true;
     438             :       }
     439           0 :       --i;
     440           0 :       curFrame = curFrame->GetPrevSibling();
     441             :     }
     442           0 :     MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!");
     443             :   }
     444           0 :   *aFrameIndexInLine = -1;
     445           0 :   return false;
     446             : }
     447             : 
     448             : nsCollapsingMargin
     449           0 : nsLineBox::GetCarriedOutBEndMargin() const
     450             : {
     451           0 :   NS_ASSERTION(IsBlock(),
     452             :                "GetCarriedOutBEndMargin called on non-block line.");
     453           0 :   return (IsBlock() && mBlockData)
     454           2 :     ? mBlockData->mCarriedOutBEndMargin
     455           4 :     : nsCollapsingMargin();
     456             : }
     457             : 
     458             : bool
     459           0 : nsLineBox::SetCarriedOutBEndMargin(nsCollapsingMargin aValue)
     460             : {
     461           0 :   bool changed = false;
     462           0 :   if (IsBlock()) {
     463           0 :     if (!aValue.IsZero()) {
     464           5 :       if (!mBlockData) {
     465           0 :         mBlockData = new ExtraBlockData(GetPhysicalBounds());
     466             :       }
     467           5 :       changed = aValue != mBlockData->mCarriedOutBEndMargin;
     468           0 :       mBlockData->mCarriedOutBEndMargin = aValue;
     469             :     }
     470           0 :     else if (mBlockData) {
     471           0 :       changed = aValue != mBlockData->mCarriedOutBEndMargin;
     472           0 :       mBlockData->mCarriedOutBEndMargin = aValue;
     473           0 :       MaybeFreeData();
     474             :     }
     475             :   }
     476           5 :   return changed;
     477             : }
     478             : 
     479             : void
     480           0 : nsLineBox::MaybeFreeData()
     481             : {
     482           0 :   nsRect bounds = GetPhysicalBounds();
     483           0 :   if (mData && mData->mOverflowAreas == nsOverflowAreas(bounds, bounds)) {
     484           0 :     if (IsInline()) {
     485           0 :       if (mInlineData->mFloats.IsEmpty()) {
     486           0 :         delete mInlineData;
     487           0 :         mInlineData = nullptr;
     488             :       }
     489             :     }
     490           0 :     else if (mBlockData->mCarriedOutBEndMargin.IsZero()) {
     491           0 :       delete mBlockData;
     492           0 :       mBlockData = nullptr;
     493             :     }
     494             :   }
     495           4 : }
     496             : 
     497             : // XXX get rid of this???
     498             : nsFloatCache*
     499           0 : nsLineBox::GetFirstFloat()
     500             : {
     501           0 :   MOZ_ASSERT(IsInline(), "block line can't have floats");
     502           0 :   return mInlineData ? mInlineData->mFloats.Head() : nullptr;
     503             : }
     504             : 
     505             : // XXX this might be too eager to free memory
     506             : void
     507           0 : nsLineBox::FreeFloats(nsFloatCacheFreeList& aFreeList)
     508             : {
     509           0 :   MOZ_ASSERT(IsInline(), "block line can't have floats");
     510           0 :   if (IsInline() && mInlineData) {
     511           8 :     if (mInlineData->mFloats.NotEmpty()) {
     512           0 :       aFreeList.Append(mInlineData->mFloats);
     513             :     }
     514           0 :     MaybeFreeData();
     515             :   }
     516          23 : }
     517             : 
     518             : void
     519           0 : nsLineBox::AppendFloats(nsFloatCacheFreeList& aFreeList)
     520             : {
     521           0 :   MOZ_ASSERT(IsInline(), "block line can't have floats");
     522           0 :   if (IsInline()) {
     523           0 :     if (aFreeList.NotEmpty()) {
     524           0 :       if (!mInlineData) {
     525           0 :         mInlineData = new ExtraInlineData(GetPhysicalBounds());
     526             :       }
     527           0 :       mInlineData->mFloats.Append(aFreeList);
     528             :     }
     529             :   }
     530          23 : }
     531             : 
     532             : bool
     533           0 : nsLineBox::RemoveFloat(nsIFrame* aFrame)
     534             : {
     535           0 :   MOZ_ASSERT(IsInline(), "block line can't have floats");
     536           0 :   if (IsInline() && mInlineData) {
     537           0 :     nsFloatCache* fc = mInlineData->mFloats.Find(aFrame);
     538           0 :     if (fc) {
     539             :       // Note: the placeholder is part of the line's child list
     540             :       // and will be removed later.
     541           0 :       mInlineData->mFloats.Remove(fc);
     542           0 :       delete fc;
     543           0 :       MaybeFreeData();
     544           0 :       return true;
     545             :     }
     546             :   }
     547             :   return false;
     548             : }
     549             : 
     550             : void
     551           0 : nsLineBox::SetFloatEdges(nscoord aStart, nscoord aEnd)
     552             : {
     553           0 :   MOZ_ASSERT(IsInline(), "block line can't have float edges");
     554           0 :   if (!mInlineData) {
     555           0 :     mInlineData = new ExtraInlineData(GetPhysicalBounds());
     556             :   }
     557           0 :   mInlineData->mFloatEdgeIStart = aStart;
     558           0 :   mInlineData->mFloatEdgeIEnd = aEnd;
     559           0 : }
     560             : 
     561             : void
     562           0 : nsLineBox::ClearFloatEdges()
     563             : {
     564           0 :   MOZ_ASSERT(IsInline(), "block line can't have float edges");
     565           0 :   if (mInlineData) {
     566           8 :     mInlineData->mFloatEdgeIStart = nscoord_MIN;
     567           0 :     mInlineData->mFloatEdgeIEnd = nscoord_MIN;
     568             :   }
     569          23 : }
     570             : 
     571             : void
     572           0 : nsLineBox::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
     573             : {
     574          84 :   NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
     575           0 :     NS_ASSERTION(aOverflowAreas.Overflow(otype).width >= 0,
     576             :                  "illegal width for combined area");
     577          56 :     NS_ASSERTION(aOverflowAreas.Overflow(otype).height >= 0,
     578             :                  "illegal height for combined area");
     579             :   }
     580           0 :   nsRect bounds = GetPhysicalBounds();
     581           0 :   if (!aOverflowAreas.VisualOverflow().IsEqualInterior(bounds) ||
     582           0 :       !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
     583           0 :     if (!mData) {
     584           4 :       if (IsInline()) {
     585           4 :         mInlineData = new ExtraInlineData(bounds);
     586             :       }
     587             :       else {
     588           0 :         mBlockData = new ExtraBlockData(bounds);
     589             :       }
     590             :     }
     591           0 :     mData->mOverflowAreas = aOverflowAreas;
     592             :   }
     593          15 :   else if (mData) {
     594             :     // Store away new value so that MaybeFreeData compares against
     595             :     // the right value.
     596           0 :     mData->mOverflowAreas = aOverflowAreas;
     597           0 :     MaybeFreeData();
     598             :   }
     599          28 : }
     600             : 
     601             : //----------------------------------------------------------------------
     602             : 
     603             : 
     604             : static nsLineBox* gDummyLines[1];
     605             : 
     606           0 : nsLineIterator::nsLineIterator()
     607             : {
     608           0 :   mLines = gDummyLines;
     609           0 :   mNumLines = 0;
     610           0 :   mIndex = 0;
     611           4 :   mRightToLeft = false;
     612           0 : }
     613             : 
     614           0 : nsLineIterator::~nsLineIterator()
     615             : {
     616           4 :   if (mLines != gDummyLines) {
     617           0 :     delete [] mLines;
     618             :   }
     619           4 : }
     620             : 
     621             : /* virtual */ void
     622           0 : nsLineIterator::DisposeLineIterator()
     623             : {
     624           4 :   delete this;
     625           4 : }
     626             : 
     627             : nsresult
     628           0 : nsLineIterator::Init(nsLineList& aLines, bool aRightToLeft)
     629             : {
     630           4 :   mRightToLeft = aRightToLeft;
     631             : 
     632             :   // Count the lines
     633           4 :   int32_t numLines = aLines.size();
     634           4 :   if (0 == numLines) {
     635             :     // Use gDummyLines so that we don't need null pointer checks in
     636             :     // the accessor methods
     637           1 :     mLines = gDummyLines;
     638           1 :     return NS_OK;
     639             :   }
     640             : 
     641             :   // Make a linear array of the lines
     642           6 :   mLines = new nsLineBox*[numLines];
     643           3 :   if (!mLines) {
     644             :     // Use gDummyLines so that we don't need null pointer checks in
     645             :     // the accessor methods
     646           0 :     mLines = gDummyLines;
     647           0 :     return NS_ERROR_OUT_OF_MEMORY;
     648             :   }
     649           3 :   nsLineBox** lp = mLines;
     650           3 :   for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end() ;
     651             :        line != line_end;
     652             :        ++line)
     653             :   {
     654           0 :     *lp++ = line;
     655             :   }
     656           3 :   mNumLines = numLines;
     657           3 :   return NS_OK;
     658             : }
     659             : 
     660             : int32_t
     661           0 : nsLineIterator::GetNumLines()
     662             : {
     663           0 :   return mNumLines;
     664             : }
     665             : 
     666             : bool
     667           0 : nsLineIterator::GetDirection()
     668             : {
     669           0 :   return mRightToLeft;
     670             : }
     671             : 
     672             : NS_IMETHODIMP
     673           7 : nsLineIterator::GetLine(int32_t aLineNumber,
     674             :                         nsIFrame** aFirstFrameOnLine,
     675             :                         int32_t* aNumFramesOnLine,
     676             :                         nsRect& aLineBounds)
     677             : {
     678           7 :   NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
     679           0 :   NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
     680             : 
     681           0 :   if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
     682           0 :     *aFirstFrameOnLine = nullptr;
     683           0 :     *aNumFramesOnLine = 0;
     684           8 :     aLineBounds.SetRect(0, 0, 0, 0);
     685           0 :     return NS_OK;
     686             :   }
     687           0 :   nsLineBox* line = mLines[aLineNumber];
     688           0 :   *aFirstFrameOnLine = line->mFirstChild;
     689           3 :   *aNumFramesOnLine = line->GetChildCount();
     690           0 :   aLineBounds = line->GetPhysicalBounds();
     691             : 
     692           3 :   return NS_OK;
     693             : }
     694             : 
     695             : int32_t
     696           0 : nsLineIterator::FindLineContaining(nsIFrame* aFrame, int32_t aStartLine)
     697             : {
     698           0 :   MOZ_ASSERT(aStartLine <= mNumLines, "Bogus line numbers");
     699             :   int32_t lineNumber = aStartLine;
     700           0 :   while (lineNumber != mNumLines) {
     701           0 :     nsLineBox* line = mLines[lineNumber];
     702           0 :     if (line->Contains(aFrame)) {
     703             :       return lineNumber;
     704             :     }
     705           0 :     ++lineNumber;
     706             :   }
     707             :   return -1;
     708             : }
     709             : 
     710             : NS_IMETHODIMP
     711           0 : nsLineIterator::CheckLineOrder(int32_t                  aLine,
     712             :                                bool                     *aIsReordered,
     713             :                                nsIFrame                 **aFirstVisual,
     714             :                                nsIFrame                 **aLastVisual)
     715             : {
     716           0 :   NS_ASSERTION (aLine >= 0 && aLine < mNumLines, "aLine out of range!");
     717           0 :   nsLineBox* line = mLines[aLine];
     718             : 
     719           0 :   if (!line->mFirstChild) { // empty line
     720           0 :     *aIsReordered = false;
     721           0 :     *aFirstVisual = nullptr;
     722           0 :     *aLastVisual = nullptr;
     723           0 :     return NS_OK;
     724             :   }
     725             : 
     726             :   nsIFrame* leftmostFrame;
     727             :   nsIFrame* rightmostFrame;
     728           0 :   *aIsReordered = nsBidiPresUtils::CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame);
     729             : 
     730             :   // map leftmost/rightmost to first/last according to paragraph direction
     731           0 :   *aFirstVisual = mRightToLeft ? rightmostFrame : leftmostFrame;
     732           0 :   *aLastVisual = mRightToLeft ? leftmostFrame : rightmostFrame;
     733             : 
     734           0 :   return NS_OK;
     735             : }
     736             : 
     737             : NS_IMETHODIMP
     738           0 : nsLineIterator::FindFrameAt(int32_t aLineNumber,
     739             :                             nsPoint aPos,
     740             :                             nsIFrame** aFrameFound,
     741             :                             bool* aPosIsBeforeFirstFrame,
     742             :                             bool* aPosIsAfterLastFrame)
     743             : {
     744           0 :   MOZ_ASSERT(aFrameFound && aPosIsBeforeFirstFrame && aPosIsAfterLastFrame,
     745             :              "null OUT ptr");
     746             : 
     747           0 :   if (!aFrameFound || !aPosIsBeforeFirstFrame || !aPosIsAfterLastFrame) {
     748             :     return NS_ERROR_NULL_POINTER;
     749             :   }
     750           0 :   if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
     751             :     return NS_ERROR_INVALID_ARG;
     752             :   }
     753             : 
     754           0 :   nsLineBox* line = mLines[aLineNumber];
     755           0 :   if (!line) {
     756           0 :     *aFrameFound = nullptr;
     757           0 :     *aPosIsBeforeFirstFrame = true;
     758           0 :     *aPosIsAfterLastFrame = false;
     759           0 :     return NS_OK;
     760             :   }
     761             : 
     762           0 :   if (line->ISize() == 0 && line->BSize() == 0)
     763             :     return NS_ERROR_FAILURE;
     764             : 
     765           0 :   nsIFrame* frame = line->mFirstChild;
     766           0 :   nsIFrame* closestFromStart = nullptr;
     767           0 :   nsIFrame* closestFromEnd = nullptr;
     768             : 
     769           0 :   WritingMode wm = line->mWritingMode;
     770           0 :   nsSize containerSize = line->mContainerSize;
     771             : 
     772           0 :   LogicalPoint pos(wm, aPos, containerSize);
     773             : 
     774           0 :   int32_t n = line->GetChildCount();
     775           0 :   while (n--) {
     776           0 :     LogicalRect rect = frame->GetLogicalRect(wm, containerSize);
     777           0 :     if (rect.ISize(wm) > 0) {
     778             :       // If pos.I() is inside this frame - this is it
     779           0 :       if (rect.IStart(wm) <= pos.I(wm) && rect.IEnd(wm) > pos.I(wm)) {
     780           0 :         closestFromStart = closestFromEnd = frame;
     781           0 :         break;
     782             :       }
     783           0 :       if (rect.IStart(wm) < pos.I(wm)) {
     784           0 :         if (!closestFromStart ||
     785           0 :             rect.IEnd(wm) > closestFromStart->
     786           0 :                               GetLogicalRect(wm, containerSize).IEnd(wm))
     787           0 :           closestFromStart = frame;
     788             :       }
     789             :       else {
     790           0 :         if (!closestFromEnd ||
     791           0 :             rect.IStart(wm) < closestFromEnd->
     792           0 :                                 GetLogicalRect(wm, containerSize).IStart(wm))
     793           0 :           closestFromEnd = frame;
     794             :       }
     795             :     }
     796           0 :     frame = frame->GetNextSibling();
     797             :   }
     798           0 :   if (!closestFromStart && !closestFromEnd) {
     799             :     // All frames were zero-width. Just take the first one.
     800           0 :     closestFromStart = closestFromEnd = line->mFirstChild;
     801             :   }
     802           0 :   *aPosIsBeforeFirstFrame = mRightToLeft ? !closestFromEnd : !closestFromStart;
     803           0 :   *aPosIsAfterLastFrame = mRightToLeft ? !closestFromStart : !closestFromEnd;
     804           0 :   if (closestFromStart == closestFromEnd) {
     805           0 :     *aFrameFound = closestFromStart;
     806             :   }
     807           0 :   else if (!closestFromStart) {
     808           0 :     *aFrameFound = closestFromEnd;
     809             :   }
     810           0 :   else if (!closestFromEnd) {
     811           0 :     *aFrameFound = closestFromStart;
     812             :   }
     813             :   else { // we're between two frames
     814             :     nscoord delta =
     815           0 :       closestFromEnd->GetLogicalRect(wm, containerSize).IStart(wm) -
     816           0 :       closestFromStart->GetLogicalRect(wm, containerSize).IEnd(wm);
     817           0 :     if (pos.I(wm) < closestFromStart->
     818           0 :                       GetLogicalRect(wm, containerSize).IEnd(wm) + delta/2) {
     819           0 :       *aFrameFound = closestFromStart;
     820             :     } else {
     821           0 :       *aFrameFound = closestFromEnd;
     822             :     }
     823             :   }
     824             :   return NS_OK;
     825             : }
     826             : 
     827             : NS_IMETHODIMP
     828           0 : nsLineIterator::GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber)
     829             : {
     830           0 :   aFrame = aFrame->GetNextSibling();
     831           0 :   return NS_OK;
     832             : }
     833             : 
     834             : //----------------------------------------------------------------------
     835             : 
     836             : #ifdef NS_BUILD_REFCNT_LOGGING
     837         142 : nsFloatCacheList::nsFloatCacheList() :
     838           0 :   mHead(nullptr)
     839             : {
     840         142 :   MOZ_COUNT_CTOR(nsFloatCacheList);
     841         142 : }
     842             : #endif
     843             : 
     844           0 : nsFloatCacheList::~nsFloatCacheList()
     845             : {
     846           0 :   DeleteAll();
     847         138 :   MOZ_COUNT_DTOR(nsFloatCacheList);
     848         138 : }
     849             : 
     850             : void
     851           0 : nsFloatCacheList::DeleteAll()
     852             : {
     853           0 :   nsFloatCache* c = mHead;
     854           0 :   while (c) {
     855           0 :     nsFloatCache* next = c->Next();
     856           0 :     delete c;
     857           0 :     c = next;
     858             :   }
     859         138 :   mHead = nullptr;
     860         138 : }
     861             : 
     862             : nsFloatCache*
     863           0 : nsFloatCacheList::Tail() const
     864             : {
     865           0 :   nsFloatCache* fc = mHead;
     866           0 :   while (fc) {
     867           0 :     if (!fc->mNext) {
     868             :       break;
     869             :     }
     870             :     fc = fc->mNext;
     871             :   }
     872           0 :   return fc;
     873             : }
     874             : 
     875             : void
     876           0 : nsFloatCacheList::Append(nsFloatCacheFreeList& aList)
     877             : {
     878           0 :   MOZ_ASSERT(aList.NotEmpty(), "Appending empty list will fail");
     879             : 
     880           0 :   nsFloatCache* tail = Tail();
     881           0 :   if (tail) {
     882           0 :     NS_ASSERTION(!tail->mNext, "Bogus!");
     883           0 :     tail->mNext = aList.mHead;
     884             :   }
     885             :   else {
     886           0 :     NS_ASSERTION(!mHead, "Bogus!");
     887           0 :     mHead = aList.mHead;
     888             :   }
     889           0 :   aList.mHead = nullptr;
     890           0 :   aList.mTail = nullptr;
     891           0 : }
     892             : 
     893             : nsFloatCache*
     894           0 : nsFloatCacheList::Find(nsIFrame* aOutOfFlowFrame)
     895             : {
     896           0 :   nsFloatCache* fc = mHead;
     897           0 :   while (fc) {
     898           0 :     if (fc->mFloat == aOutOfFlowFrame) {
     899             :       break;
     900             :     }
     901           0 :     fc = fc->Next();
     902             :   }
     903           0 :   return fc;
     904             : }
     905             : 
     906             : nsFloatCache*
     907           0 : nsFloatCacheList::RemoveAndReturnPrev(nsFloatCache* aElement)
     908             : {
     909           0 :   nsFloatCache* fc = mHead;
     910           0 :   nsFloatCache* prev = nullptr;
     911           0 :   while (fc) {
     912           0 :     if (fc == aElement) {
     913           0 :       if (prev) {
     914           0 :         prev->mNext = fc->mNext;
     915             :       } else {
     916           0 :         mHead = fc->mNext;
     917             :       }
     918             :       return prev;
     919             :     }
     920           0 :     prev = fc;
     921           0 :     fc = fc->mNext;
     922             :   }
     923             :   return nullptr;
     924             : }
     925             : 
     926             : //----------------------------------------------------------------------
     927             : 
     928             : #ifdef NS_BUILD_REFCNT_LOGGING
     929         138 : nsFloatCacheFreeList::nsFloatCacheFreeList() :
     930           0 :   mTail(nullptr)
     931             : {
     932         138 :   MOZ_COUNT_CTOR(nsFloatCacheFreeList);
     933           0 : }
     934             : 
     935           0 : nsFloatCacheFreeList::~nsFloatCacheFreeList()
     936             : {
     937         138 :   MOZ_COUNT_DTOR(nsFloatCacheFreeList);
     938         138 : }
     939             : #endif
     940             : 
     941             : void
     942           0 : nsFloatCacheFreeList::Append(nsFloatCacheList& aList)
     943             : {
     944           0 :   MOZ_ASSERT(aList.NotEmpty(), "Appending empty list will fail");
     945             : 
     946           0 :   if (mTail) {
     947           0 :     NS_ASSERTION(!mTail->mNext, "Bogus");
     948           0 :     mTail->mNext = aList.mHead;
     949             :   }
     950             :   else {
     951           0 :     NS_ASSERTION(!mHead, "Bogus");
     952           0 :     mHead = aList.mHead;
     953             :   }
     954           0 :   mTail = aList.Tail();
     955           0 :   aList.mHead = nullptr;
     956           0 : }
     957             : 
     958             : void
     959           0 : nsFloatCacheFreeList::Remove(nsFloatCache* aElement)
     960             : {
     961           0 :   nsFloatCache* prev = nsFloatCacheList::RemoveAndReturnPrev(aElement);
     962           0 :   if (mTail == aElement) {
     963           0 :     mTail = prev;
     964             :   }
     965           0 : }
     966             : 
     967             : void
     968           0 : nsFloatCacheFreeList::DeleteAll()
     969             : {
     970           0 :   nsFloatCacheList::DeleteAll();
     971           0 :   mTail = nullptr;
     972           0 : }
     973             : 
     974             : nsFloatCache*
     975           0 : nsFloatCacheFreeList::Alloc(nsIFrame* aFloat)
     976             : {
     977           0 :   MOZ_ASSERT(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
     978             :              "This is a float cache, why isn't the frame out-of-flow?");
     979             : 
     980           0 :   nsFloatCache* fc = mHead;
     981           0 :   if (mHead) {
     982           0 :     if (mHead == mTail) {
     983           0 :       mHead = mTail = nullptr;
     984             :     }
     985             :     else {
     986           0 :       mHead = fc->mNext;
     987             :     }
     988           0 :     fc->mNext = nullptr;
     989             :   }
     990             :   else {
     991           0 :     fc = new nsFloatCache();
     992             :   }
     993           0 :   fc->mFloat = aFloat;
     994           0 :   return fc;
     995             : }
     996             : 
     997             : void
     998           0 : nsFloatCacheFreeList::Append(nsFloatCache* aFloat)
     999             : {
    1000           0 :   NS_ASSERTION(!aFloat->mNext, "Bogus!");
    1001           0 :   aFloat->mNext = nullptr;
    1002           0 :   if (mTail) {
    1003           0 :     NS_ASSERTION(!mTail->mNext, "Bogus!");
    1004           0 :     mTail->mNext = aFloat;
    1005           0 :     mTail = aFloat;
    1006             :   }
    1007             :   else {
    1008           0 :     NS_ASSERTION(!mHead, "Bogus!");
    1009           0 :     mHead = mTail = aFloat;
    1010             :   }
    1011           0 : }
    1012             : 
    1013             : //----------------------------------------------------------------------
    1014             : 
    1015           0 : nsFloatCache::nsFloatCache()
    1016             :   : mFloat(nullptr),
    1017           0 :     mNext(nullptr)
    1018             : {
    1019           0 :   MOZ_COUNT_CTOR(nsFloatCache);
    1020           0 : }
    1021             : 
    1022             : #ifdef NS_BUILD_REFCNT_LOGGING
    1023           0 : nsFloatCache::~nsFloatCache()
    1024             : {
    1025             :   MOZ_COUNT_DTOR(nsFloatCache);
    1026             : }
    1027             : #endif

Generated by: LCOV version 1.13-14-ga5dd952