layout/generic/nsFrameList.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsFrameList.h"
     7 #include "nsIFrame.h"
     8 #include "nsLayoutUtils.h"
     9 #include "nsPresContext.h"
    10 #include "nsIPresShell.h"
    12 #include "nsGkAtoms.h"
    13 #include "nsILineIterator.h"
    14 #include "nsBidiPresUtils.h"
    16 namespace mozilla {
    17 namespace layout {
    18 namespace detail {
    19 const AlignedFrameListBytes gEmptyFrameListBytes = { 0 };
    20 }
    21 }
    22 }
    24 void*
    25 nsFrameList::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
    26 {
    27   return aPresShell->AllocateByObjectID(nsPresArena::nsFrameList_id, sz);
    28 }
    30 void
    31 nsFrameList::Delete(nsIPresShell* aPresShell)
    32 {
    33   NS_PRECONDITION(this != &EmptyList(), "Shouldn't Delete() this list");
    34   NS_ASSERTION(IsEmpty(), "Shouldn't Delete() a non-empty list");
    36   aPresShell->FreeByObjectID(nsPresArena::nsFrameList_id, this);
    37 }
    39 void
    40 nsFrameList::DestroyFrames()
    41 {
    42   while (nsIFrame* frame = RemoveFirstChild()) {
    43     frame->Destroy();
    44   }
    45   mLastChild = nullptr;
    46 }
    48 void
    49 nsFrameList::DestroyFramesFrom(nsIFrame* aDestructRoot)
    50 {
    51   NS_PRECONDITION(aDestructRoot, "Missing destruct root");
    53   while (nsIFrame* frame = RemoveFirstChild()) {
    54     frame->DestroyFrom(aDestructRoot);
    55   }
    56   mLastChild = nullptr;
    57 }
    59 void
    60 nsFrameList::SetFrames(nsIFrame* aFrameList)
    61 {
    62   NS_PRECONDITION(!mFirstChild, "Losing frames");
    64   mFirstChild = aFrameList;
    65   mLastChild = nsLayoutUtils::GetLastSibling(mFirstChild);
    66 }
    68 void
    69 nsFrameList::RemoveFrame(nsIFrame* aFrame)
    70 {
    71   NS_PRECONDITION(aFrame, "null ptr");
    72 #ifdef DEBUG_FRAME_LIST
    73   // ContainsFrame is O(N)
    74   NS_PRECONDITION(ContainsFrame(aFrame), "wrong list");
    75 #endif
    77   nsIFrame* nextFrame = aFrame->GetNextSibling();
    78   if (aFrame == mFirstChild) {
    79     mFirstChild = nextFrame;
    80     aFrame->SetNextSibling(nullptr);
    81     if (!nextFrame) {
    82       mLastChild = nullptr;
    83     }
    84   }
    85   else {
    86     nsIFrame* prevSibling = aFrame->GetPrevSibling();
    87     NS_ASSERTION(prevSibling && prevSibling->GetNextSibling() == aFrame,
    88                  "Broken frame linkage");
    89     prevSibling->SetNextSibling(nextFrame);
    90     aFrame->SetNextSibling(nullptr);
    91     if (!nextFrame) {
    92       mLastChild = prevSibling;
    93     }
    94   }
    95 }
    97 nsFrameList
    98 nsFrameList::RemoveFramesAfter(nsIFrame* aAfterFrame)
    99 {
   100   if (!aAfterFrame) {
   101     nsFrameList result;
   102     result.InsertFrames(nullptr, nullptr, *this);
   103     return result;
   104   }
   106   NS_PRECONDITION(NotEmpty(), "illegal operation on empty list");
   107 #ifdef DEBUG_FRAME_LIST
   108   NS_PRECONDITION(ContainsFrame(aAfterFrame), "wrong list");
   109 #endif
   111   nsIFrame* tail = aAfterFrame->GetNextSibling();
   112   // if (!tail) return EmptyList();  -- worth optimizing this case?
   113   nsIFrame* oldLastChild = mLastChild;
   114   mLastChild = aAfterFrame;
   115   aAfterFrame->SetNextSibling(nullptr);
   116   return nsFrameList(tail, tail ? oldLastChild : nullptr);
   117 }
   119 nsIFrame*
   120 nsFrameList::RemoveFirstChild()
   121 {
   122   if (mFirstChild) {
   123     nsIFrame* firstChild = mFirstChild;
   124     RemoveFrame(firstChild);
   125     return firstChild;
   126   }
   127   return nullptr;
   128 }
   130 void
   131 nsFrameList::DestroyFrame(nsIFrame* aFrame)
   132 {
   133   NS_PRECONDITION(aFrame, "null ptr");
   134   RemoveFrame(aFrame);
   135   aFrame->Destroy();
   136 }
   138 nsFrameList::Slice
   139 nsFrameList::InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling,
   140                           nsFrameList& aFrameList)
   141 {
   142   NS_PRECONDITION(aFrameList.NotEmpty(), "Unexpected empty list");
   144   if (aParent) {
   145     aFrameList.ApplySetParent(aParent);
   146   }
   148   NS_ASSERTION(IsEmpty() ||
   149                FirstChild()->GetParent() == aFrameList.FirstChild()->GetParent(),
   150                "frame to add has different parent");
   151   NS_ASSERTION(!aPrevSibling ||
   152                aPrevSibling->GetParent() == aFrameList.FirstChild()->GetParent(),
   153                "prev sibling has different parent");
   154 #ifdef DEBUG_FRAME_LIST
   155   // ContainsFrame is O(N)
   156   NS_ASSERTION(!aPrevSibling || ContainsFrame(aPrevSibling),
   157                "prev sibling is not on this list");
   158 #endif
   160   nsIFrame* firstNewFrame = aFrameList.FirstChild();
   161   nsIFrame* nextSibling;
   162   if (aPrevSibling) {
   163     nextSibling = aPrevSibling->GetNextSibling();
   164     aPrevSibling->SetNextSibling(firstNewFrame);
   165   }
   166   else {
   167     nextSibling = mFirstChild;
   168     mFirstChild = firstNewFrame;
   169   }
   171   nsIFrame* lastNewFrame = aFrameList.LastChild();
   172   lastNewFrame->SetNextSibling(nextSibling);
   173   if (!nextSibling) {
   174     mLastChild = lastNewFrame;
   175   }
   177   VerifyList();
   179   aFrameList.Clear();
   180   return Slice(*this, firstNewFrame, nextSibling);
   181 }
   183 nsFrameList
   184 nsFrameList::ExtractHead(FrameLinkEnumerator& aLink)
   185 {
   186   NS_PRECONDITION(&aLink.List() == this, "Unexpected list");
   187   NS_PRECONDITION(!aLink.PrevFrame() ||
   188                   aLink.PrevFrame()->GetNextSibling() ==
   189                     aLink.NextFrame(),
   190                   "Unexpected PrevFrame()");
   191   NS_PRECONDITION(aLink.PrevFrame() ||
   192                   aLink.NextFrame() == FirstChild(),
   193                   "Unexpected NextFrame()");
   194   NS_PRECONDITION(!aLink.PrevFrame() ||
   195                   aLink.NextFrame() != FirstChild(),
   196                   "Unexpected NextFrame()");
   197   NS_PRECONDITION(aLink.mEnd == nullptr,
   198                   "Unexpected mEnd for frame link enumerator");
   200   nsIFrame* prev = aLink.PrevFrame();
   201   nsIFrame* newFirstFrame = nullptr;
   202   if (prev) {
   203     // Truncate the list after |prev| and hand the first part to our new list.
   204     prev->SetNextSibling(nullptr);
   205     newFirstFrame = mFirstChild;
   206     mFirstChild = aLink.NextFrame();
   207     if (!mFirstChild) { // we handed over the whole list
   208       mLastChild = nullptr;
   209     }
   211     // Now make sure aLink doesn't point to a frame we no longer have.
   212     aLink.mPrev = nullptr;
   213   }
   214   // else aLink is pointing to before our first frame.  Nothing to do.
   216   return nsFrameList(newFirstFrame, prev);
   217 }
   219 nsFrameList
   220 nsFrameList::ExtractTail(FrameLinkEnumerator& aLink)
   221 {
   222   NS_PRECONDITION(&aLink.List() == this, "Unexpected list");
   223   NS_PRECONDITION(!aLink.PrevFrame() ||
   224                   aLink.PrevFrame()->GetNextSibling() ==
   225                     aLink.NextFrame(),
   226                   "Unexpected PrevFrame()");
   227   NS_PRECONDITION(aLink.PrevFrame() ||
   228                   aLink.NextFrame() == FirstChild(),
   229                   "Unexpected NextFrame()");
   230   NS_PRECONDITION(!aLink.PrevFrame() ||
   231                   aLink.NextFrame() != FirstChild(),
   232                   "Unexpected NextFrame()");
   233   NS_PRECONDITION(aLink.mEnd == nullptr,
   234                   "Unexpected mEnd for frame link enumerator");
   236   nsIFrame* prev = aLink.PrevFrame();
   237   nsIFrame* newFirstFrame;
   238   nsIFrame* newLastFrame;
   239   if (prev) {
   240     // Truncate the list after |prev| and hand the second part to our new list
   241     prev->SetNextSibling(nullptr);
   242     newFirstFrame = aLink.NextFrame();
   243     newLastFrame = newFirstFrame ? mLastChild : nullptr;
   244     mLastChild = prev;
   245   } else {
   246     // Hand the whole list over to our new list
   247     newFirstFrame = mFirstChild;
   248     newLastFrame = mLastChild;
   249     Clear();
   250   }
   252   // Now make sure aLink doesn't point to a frame we no longer have.
   253   aLink.mFrame = nullptr;
   255   NS_POSTCONDITION(aLink.AtEnd(), "What's going on here?");
   257   return nsFrameList(newFirstFrame, newLastFrame);
   258 }
   260 nsIFrame*
   261 nsFrameList::FrameAt(int32_t aIndex) const
   262 {
   263   NS_PRECONDITION(aIndex >= 0, "invalid arg");
   264   if (aIndex < 0) return nullptr;
   265   nsIFrame* frame = mFirstChild;
   266   while ((aIndex-- > 0) && frame) {
   267     frame = frame->GetNextSibling();
   268   }
   269   return frame;
   270 }
   272 int32_t
   273 nsFrameList::IndexOf(nsIFrame* aFrame) const
   274 {
   275   int32_t count = 0;
   276   for (nsIFrame* f = mFirstChild; f; f = f->GetNextSibling()) {
   277     if (f == aFrame)
   278       return count;
   279     ++count;
   280   }
   281   return -1;
   282 }
   284 bool
   285 nsFrameList::ContainsFrame(const nsIFrame* aFrame) const
   286 {
   287   NS_PRECONDITION(aFrame, "null ptr");
   289   nsIFrame* frame = mFirstChild;
   290   while (frame) {
   291     if (frame == aFrame) {
   292       return true;
   293     }
   294     frame = frame->GetNextSibling();
   295   }
   296   return false;
   297 }
   299 int32_t
   300 nsFrameList::GetLength() const
   301 {
   302   int32_t count = 0;
   303   nsIFrame* frame = mFirstChild;
   304   while (frame) {
   305     count++;
   306     frame = frame->GetNextSibling();
   307   }
   308   return count;
   309 }
   311 void
   312 nsFrameList::ApplySetParent(nsIFrame* aParent) const
   313 {
   314   NS_ASSERTION(aParent, "null ptr");
   316   for (nsIFrame* f = FirstChild(); f; f = f->GetNextSibling()) {
   317     f->SetParent(aParent);
   318   }
   319 }
   321 /* static */ void
   322 nsFrameList::UnhookFrameFromSiblings(nsIFrame* aFrame)
   323 {
   324   MOZ_ASSERT(aFrame->GetPrevSibling() && aFrame->GetNextSibling());
   325   nsIFrame* const nextSibling = aFrame->GetNextSibling();
   326   nsIFrame* const prevSibling = aFrame->GetPrevSibling();
   327   aFrame->SetNextSibling(nullptr);
   328   prevSibling->SetNextSibling(nextSibling);
   329   MOZ_ASSERT(!aFrame->GetPrevSibling() && !aFrame->GetNextSibling());
   330 }
   332 #ifdef DEBUG_FRAME_DUMP
   333 void
   334 nsFrameList::List(FILE* out) const
   335 {
   336   fprintf_stderr(out, "<\n");
   337   for (nsIFrame* frame = mFirstChild; frame;
   338        frame = frame->GetNextSibling()) {
   339     frame->List(out, "  ");
   340   }
   341   fprintf_stderr(out, ">\n");
   342 }
   343 #endif
   345 nsIFrame*
   346 nsFrameList::GetPrevVisualFor(nsIFrame* aFrame) const
   347 {
   348   if (!mFirstChild)
   349     return nullptr;
   351   nsIFrame* parent = mFirstChild->GetParent();
   352   if (!parent)
   353     return aFrame ? aFrame->GetPrevSibling() : LastChild();
   355   nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild);  
   357   nsAutoLineIterator iter = parent->GetLineIterator();
   358   if (!iter) { 
   359     // Parent is not a block Frame
   360     if (parent->GetType() == nsGkAtoms::lineFrame) {
   361       // Line frames are not bidi-splittable, so need to consider bidi reordering
   362       if (baseLevel == NSBIDI_LTR) {
   363         return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1);
   364       } else { // RTL
   365         return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1);
   366       }
   367     } else {
   368       // Just get the next or prev sibling, depending on block and frame direction.
   369       nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild);
   370       if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) {
   371         return aFrame ? aFrame->GetPrevSibling() : LastChild();
   372       } else {
   373         return aFrame ? aFrame->GetNextSibling() : mFirstChild;
   374       }    
   375     }
   376   }
   378   // Parent is a block frame, so use the LineIterator to find the previous visual 
   379   // sibling on this line, or the last one on the previous line.
   381   int32_t thisLine;
   382   if (aFrame) {
   383     thisLine = iter->FindLineContaining(aFrame);
   384     if (thisLine < 0)
   385       return nullptr;
   386   } else {
   387     thisLine = iter->GetNumLines();
   388   }
   390   nsIFrame* frame = nullptr;
   391   nsIFrame* firstFrameOnLine;
   392   int32_t numFramesOnLine;
   393   nsRect lineBounds;
   394   uint32_t lineFlags;
   396   if (aFrame) {
   397     iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
   399     if (baseLevel == NSBIDI_LTR) {
   400       frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine);
   401     } else { // RTL
   402       frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine);
   403     }
   404   }
   406   if (!frame && thisLine > 0) {
   407     // Get the last frame of the previous line
   408     iter->GetLine(thisLine - 1, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
   410     if (baseLevel == NSBIDI_LTR) {
   411       frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine);
   412     } else { // RTL
   413       frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine);
   414     }
   415   }
   416   return frame;
   417 }
   419 nsIFrame*
   420 nsFrameList::GetNextVisualFor(nsIFrame* aFrame) const
   421 {
   422   if (!mFirstChild)
   423     return nullptr;
   425   nsIFrame* parent = mFirstChild->GetParent();
   426   if (!parent)
   427     return aFrame ? aFrame->GetPrevSibling() : mFirstChild;
   429   nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild);
   431   nsAutoLineIterator iter = parent->GetLineIterator();
   432   if (!iter) { 
   433     // Parent is not a block Frame
   434     if (parent->GetType() == nsGkAtoms::lineFrame) {
   435       // Line frames are not bidi-splittable, so need to consider bidi reordering
   436       if (baseLevel == NSBIDI_LTR) {
   437         return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1);
   438       } else { // RTL
   439         return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1);
   440       }
   441     } else {
   442       // Just get the next or prev sibling, depending on block and frame direction.
   443       nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild);
   444       if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) {
   445         return aFrame ? aFrame->GetNextSibling() : mFirstChild;
   446       } else {
   447         return aFrame ? aFrame->GetPrevSibling() : LastChild();
   448       }
   449     }
   450   }
   452   // Parent is a block frame, so use the LineIterator to find the next visual 
   453   // sibling on this line, or the first one on the next line.
   455   int32_t thisLine;
   456   if (aFrame) {
   457     thisLine = iter->FindLineContaining(aFrame);
   458     if (thisLine < 0)
   459       return nullptr;
   460   } else {
   461     thisLine = -1;
   462   }
   464   nsIFrame* frame = nullptr;
   465   nsIFrame* firstFrameOnLine;
   466   int32_t numFramesOnLine;
   467   nsRect lineBounds;
   468   uint32_t lineFlags;
   470   if (aFrame) {
   471     iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
   473     if (baseLevel == NSBIDI_LTR) {
   474       frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine);
   475     } else { // RTL
   476       frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine);
   477     }
   478   }
   480   int32_t numLines = iter->GetNumLines();
   481   if (!frame && thisLine < numLines - 1) {
   482     // Get the first frame of the next line
   483     iter->GetLine(thisLine + 1, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
   485     if (baseLevel == NSBIDI_LTR) {
   486       frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine);
   487     } else { // RTL
   488       frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine);
   489     }
   490   }
   491   return frame;
   492 }
   494 #ifdef DEBUG_FRAME_LIST
   495 void
   496 nsFrameList::VerifyList() const
   497 {
   498   NS_ASSERTION((mFirstChild == nullptr) == (mLastChild == nullptr),
   499                "bad list state");
   501   if (IsEmpty()) {
   502     return;
   503   }
   505   // Simple algorithm to find a loop in a linked list -- advance pointers
   506   // through it at speeds of 1 and 2, and if they ever get to be equal bail
   507   NS_ASSERTION(!mFirstChild->GetPrevSibling(), "bad prev sibling pointer");
   508   nsIFrame *first = mFirstChild, *second = mFirstChild;
   509   for (;;) {
   510     first = first->GetNextSibling();
   511     second = second->GetNextSibling();
   512     if (!second) {
   513       break;
   514     }
   515     NS_ASSERTION(second->GetPrevSibling()->GetNextSibling() == second,
   516                  "bad prev sibling pointer");
   517     second = second->GetNextSibling();
   518     if (first == second) {
   519       // Loop detected!  Since second advances faster, they can't both be null;
   520       // we would have broken out of the loop long ago.
   521       NS_ERROR("loop in frame list.  This will probably hang soon.");
   522       return;
   523     }                           
   524     if (!second) {
   525       break;
   526     }
   527     NS_ASSERTION(second->GetPrevSibling()->GetNextSibling() == second,
   528                  "bad prev sibling pointer");
   529   }
   531   NS_ASSERTION(mLastChild == nsLayoutUtils::GetLastSibling(mFirstChild),
   532                "bogus mLastChild");
   533   // XXX we should also assert that all GetParent() are either null or
   534   // the same non-null value, but nsCSSFrameConstructor::nsFrameItems
   535   // prevents that, e.g. table captions.
   536 }
   537 #endif
   539 namespace mozilla {
   540 namespace layout {
   542 AutoFrameListPtr::~AutoFrameListPtr()
   543 {
   544   if (mFrameList) {
   545     mFrameList->Delete(mPresContext->PresShell());
   546   }
   547 }
   549 }
   550 }

mercurial