layout/base/nsFrameManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * vim:cindent:ts=2:et:sw=2:
     3  *
     4  * This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     7  *
     8  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
     9  * described herein are Copyright (c) International Business Machines Corporation, 2000.
    10  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
    11  *
    12  * Date             Modified by     Description of modification
    13  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
    14  */
    16 /* storage of the frame tree and information about it */
    18 #include "nscore.h"
    19 #include "nsIPresShell.h"
    20 #include "nsStyleContext.h"
    21 #include "nsCOMPtr.h"
    22 #include "plhash.h"
    23 #include "nsPlaceholderFrame.h"
    24 #include "nsGkAtoms.h"
    25 #include "nsILayoutHistoryState.h"
    26 #include "nsPresState.h"
    27 #include "mozilla/dom/Element.h"
    28 #include "nsIDocument.h"
    30 #include "nsContentUtils.h"
    31 #include "nsError.h"
    32 #include "nsAutoPtr.h"
    33 #include "nsAbsoluteContainingBlock.h"
    34 #include "ChildIterator.h"
    36 #include "nsFrameManager.h"
    37 #include "GeckoProfiler.h"
    38 #include "nsIStatefulFrame.h"
    40   #ifdef DEBUG
    41     //#define DEBUG_UNDISPLAYED_MAP
    42   #else
    43     #undef DEBUG_UNDISPLAYED_MAP
    44   #endif
    46 using namespace mozilla;
    47 using namespace mozilla::dom;
    49 //----------------------------------------------------------------------
    51 struct PlaceholderMapEntry : public PLDHashEntryHdr {
    52   // key (the out of flow frame) can be obtained through placeholder frame
    53   nsPlaceholderFrame *placeholderFrame;
    54 };
    56 static bool
    57 PlaceholderMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
    58                          const void *key)
    59 {
    60   const PlaceholderMapEntry *entry =
    61     static_cast<const PlaceholderMapEntry*>(hdr);
    62   NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() !=
    63                (void*)0xdddddddd,
    64                "Dead placeholder in placeholder map");
    65   return entry->placeholderFrame->GetOutOfFlowFrame() == key;
    66 }
    68 static const PLDHashTableOps PlaceholderMapOps = {
    69   PL_DHashAllocTable,
    70   PL_DHashFreeTable,
    71   PL_DHashVoidPtrKeyStub,
    72   PlaceholderMapMatchEntry,
    73   PL_DHashMoveEntryStub,
    74   PL_DHashClearEntryStub,
    75   PL_DHashFinalizeStub,
    76   nullptr
    77 };
    79 //----------------------------------------------------------------------
    81 // XXXldb This seems too complicated for what I think it's doing, and it
    82 // should also be using pldhash rather than plhash to use less memory.
    84 class nsFrameManagerBase::UndisplayedMap {
    85 public:
    86   UndisplayedMap(uint32_t aNumBuckets = 16) NS_HIDDEN;
    87   ~UndisplayedMap(void) NS_HIDDEN;
    89   NS_HIDDEN_(UndisplayedNode*) GetFirstNode(nsIContent* aParentContent);
    91   NS_HIDDEN_(nsresult) AddNodeFor(nsIContent* aParentContent,
    92                                   nsIContent* aChild, nsStyleContext* aStyle);
    94   NS_HIDDEN_(void) RemoveNodeFor(nsIContent* aParentContent,
    95                                  UndisplayedNode* aNode);
    97   NS_HIDDEN_(void) RemoveNodesFor(nsIContent* aParentContent);
    99   // Removes all entries from the hash table
   100   NS_HIDDEN_(void)  Clear(void);
   102 protected:
   103   /**
   104    * Gets the entry for the provided parent content. If the content
   105    * is a <xbl:children> element, |**aParentContent| is set to
   106    * the parent of the children element.
   107    */
   108   NS_HIDDEN_(PLHashEntry**) GetEntryFor(nsIContent** aParentContent);
   109   NS_HIDDEN_(void)          AppendNodeFor(UndisplayedNode* aNode,
   110                                           nsIContent* aParentContent);
   112   PLHashTable*  mTable;
   113   PLHashEntry** mLastLookup;
   114 };
   116 //----------------------------------------------------------------------
   118 nsFrameManager::~nsFrameManager()
   119 {
   120   NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
   121 }
   123 void
   124 nsFrameManager::Destroy()
   125 {
   126   NS_ASSERTION(mPresShell, "Frame manager already shut down.");
   128   // Destroy the frame hierarchy.
   129   mPresShell->SetIgnoreFrameDestruction(true);
   131   // Unregister all placeholders before tearing down the frame tree
   132   nsFrameManager::ClearPlaceholderFrameMap();
   134   if (mRootFrame) {
   135     mRootFrame->Destroy();
   136     mRootFrame = nullptr;
   137   }
   139   delete mUndisplayedMap;
   140   mUndisplayedMap = nullptr;
   142   mPresShell = nullptr;
   143 }
   145 //----------------------------------------------------------------------
   147 // Placeholder frame functions
   148 nsPlaceholderFrame*
   149 nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame)
   150 {
   151   NS_PRECONDITION(aFrame, "null param unexpected");
   153   if (mPlaceholderMap.ops) {
   154     PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>
   155                                             (PL_DHashTableOperate(const_cast<PLDHashTable*>(&mPlaceholderMap),
   156                                 aFrame, PL_DHASH_LOOKUP));
   157     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
   158       return entry->placeholderFrame;
   159     }
   160   }
   162   return nullptr;
   163 }
   165 nsresult
   166 nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
   167 {
   168   NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
   169   NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
   170                   "unexpected frame type");
   171   if (!mPlaceholderMap.ops) {
   172     PL_DHashTableInit(&mPlaceholderMap, &PlaceholderMapOps, nullptr,
   173                       sizeof(PlaceholderMapEntry), 16);
   174   }
   175   PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>(PL_DHashTableOperate(&mPlaceholderMap,
   176                               aPlaceholderFrame->GetOutOfFlowFrame(),
   177                               PL_DHASH_ADD));
   178   if (!entry)
   179     return NS_ERROR_OUT_OF_MEMORY;
   181   NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
   182   entry->placeholderFrame = aPlaceholderFrame;
   184   return NS_OK;
   185 }
   187 void
   188 nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
   189 {
   190   NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
   191   NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
   192                   "unexpected frame type");
   194   if (mPlaceholderMap.ops) {
   195     PL_DHashTableOperate(&mPlaceholderMap,
   196                          aPlaceholderFrame->GetOutOfFlowFrame(),
   197                          PL_DHASH_REMOVE);
   198   }
   199 }
   201 static PLDHashOperator
   202 UnregisterPlaceholders(PLDHashTable* table, PLDHashEntryHdr* hdr,
   203                        uint32_t number, void* arg)
   204 {
   205   PlaceholderMapEntry* entry = static_cast<PlaceholderMapEntry*>(hdr);
   206   entry->placeholderFrame->SetOutOfFlowFrame(nullptr);
   207   return PL_DHASH_NEXT;
   208 }
   210 void
   211 nsFrameManager::ClearPlaceholderFrameMap()
   212 {
   213   if (mPlaceholderMap.ops) {
   214     PL_DHashTableEnumerate(&mPlaceholderMap, UnregisterPlaceholders, nullptr);
   215     PL_DHashTableFinish(&mPlaceholderMap);
   216     mPlaceholderMap.ops = nullptr;
   217   }
   218 }
   220 //----------------------------------------------------------------------
   222 nsStyleContext*
   223 nsFrameManager::GetUndisplayedContent(nsIContent* aContent)
   224 {
   225   if (!aContent || !mUndisplayedMap)
   226     return nullptr;
   228   nsIContent* parent = aContent->GetParent();
   229   for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(parent);
   230          node; node = node->mNext) {
   231     if (node->mContent == aContent)
   232       return node->mStyle;
   233   }
   235   return nullptr;
   236 }
   238 UndisplayedNode*
   239 nsFrameManager::GetAllUndisplayedContentIn(nsIContent* aParentContent)
   240 {
   241   if (!mUndisplayedMap)
   242     return nullptr;
   244   return mUndisplayedMap->GetFirstNode(aParentContent);
   245 }
   247 void
   248 nsFrameManager::SetUndisplayedContent(nsIContent* aContent, 
   249                                       nsStyleContext* aStyleContext)
   250 {
   251   NS_PRECONDITION(!aStyleContext->GetPseudo(),
   252                   "Should only have actual elements here");
   254 #ifdef DEBUG_UNDISPLAYED_MAP
   255   static int i = 0;
   256   printf("SetUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
   257 #endif
   259   NS_ASSERTION(!GetUndisplayedContent(aContent),
   260                "Already have an undisplayed context entry for aContent");
   262   if (! mUndisplayedMap) {
   263     mUndisplayedMap = new UndisplayedMap;
   264   }
   265   nsIContent* parent = aContent->GetParent();
   266   NS_ASSERTION(parent || (mPresShell && mPresShell->GetDocument() &&
   267                mPresShell->GetDocument()->GetRootElement() == aContent),
   268                "undisplayed content must have a parent, unless it's the root "
   269                "element");
   270   mUndisplayedMap->AddNodeFor(parent, aContent, aStyleContext);
   271 }
   273 void
   274 nsFrameManager::ChangeUndisplayedContent(nsIContent* aContent, 
   275                                          nsStyleContext* aStyleContext)
   276 {
   277   NS_ASSERTION(mUndisplayedMap, "no existing undisplayed content");
   279 #ifdef DEBUG_UNDISPLAYED_MAP
   280    static int i = 0;
   281    printf("ChangeUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
   282 #endif
   284   for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aContent->GetParent());
   285          node; node = node->mNext) {
   286     if (node->mContent == aContent) {
   287       node->mStyle = aStyleContext;
   288       return;
   289     }
   290   }
   292   NS_NOTREACHED("no existing undisplayed content");
   293 }
   295 void
   296 nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
   297                                           nsIContent* aParentContent)
   298 {
   299 #ifdef DEBUG_UNDISPLAYED_MAP
   300   static int i = 0;
   301   printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
   302 #endif
   304   if (mUndisplayedMap) {
   305     UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
   306     while (node) {
   307       if (node->mContent == aContent) {
   308         mUndisplayedMap->RemoveNodeFor(aParentContent, node);
   310 #ifdef DEBUG_UNDISPLAYED_MAP
   311         printf( "REMOVED!\n");
   312 #endif
   313 #ifdef DEBUG
   314         // make sure that there are no more entries for the same content
   315         nsStyleContext *context = GetUndisplayedContent(aContent);
   316         NS_ASSERTION(context == nullptr, "Found more undisplayed content data after removal");
   317 #endif
   318         return;
   319       }
   320       node = node->mNext;
   321     }
   322   }
   323 }
   325 void
   326 nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent)
   327 {
   328 #ifdef DEBUG_UNDISPLAYED_MAP
   329   static int i = 0;
   330   printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i++, (void*)aParentContent);
   331 #endif
   333   if (mUndisplayedMap) {
   334     mUndisplayedMap->RemoveNodesFor(aParentContent);
   335   }
   337   // Need to look at aParentContent's content list due to XBL insertions.
   338   // Nodes in aParentContent's content list do not have aParentContent as a
   339   // parent, but are treated as children of aParentContent. We iterate over
   340   // the flattened content list and just ignore any nodes we don't care about.
   341   FlattenedChildIterator iter(aParentContent);
   342   for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
   343     if (child->GetParent() != aParentContent) {
   344       ClearUndisplayedContentIn(child, child->GetParent());
   345     }
   346   }
   347 }
   349 //----------------------------------------------------------------------
   350 nsresult
   351 nsFrameManager::AppendFrames(nsIFrame*       aParentFrame,
   352                              ChildListID     aListID,
   353                              nsFrameList&    aFrameList)
   354 {
   355   if (aParentFrame->IsAbsoluteContainer() &&
   356       aListID == aParentFrame->GetAbsoluteListID()) {
   357     return aParentFrame->GetAbsoluteContainingBlock()->
   358            AppendFrames(aParentFrame, aListID, aFrameList);
   359   } else {
   360     return aParentFrame->AppendFrames(aListID, aFrameList);
   361   }
   362 }
   364 nsresult
   365 nsFrameManager::InsertFrames(nsIFrame*       aParentFrame,
   366                              ChildListID     aListID,
   367                              nsIFrame*       aPrevFrame,
   368                              nsFrameList&    aFrameList)
   369 {
   370   NS_PRECONDITION(!aPrevFrame || (!aPrevFrame->GetNextContinuation()
   371                   || (((aPrevFrame->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))
   372                   && !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))),
   373                   "aPrevFrame must be the last continuation in its chain!");
   375   if (aParentFrame->IsAbsoluteContainer() &&
   376       aListID == aParentFrame->GetAbsoluteListID()) {
   377     return aParentFrame->GetAbsoluteContainingBlock()->
   378            InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
   379   } else {
   380     return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
   381   }
   382 }
   384 nsresult
   385 nsFrameManager::RemoveFrame(ChildListID     aListID,
   386                             nsIFrame*       aOldFrame)
   387 {
   388   bool wasDestroyingFrames = mIsDestroyingFrames;
   389   mIsDestroyingFrames = true;
   391   // In case the reflow doesn't invalidate anything since it just leaves
   392   // a gap where the old frame was, we invalidate it here.  (This is
   393   // reasonably likely to happen when removing a last child in a way
   394   // that doesn't change the size of the parent.)
   395   // This has to sure to invalidate the entire overflow rect; this
   396   // is important in the presence of absolute positioning
   397   aOldFrame->InvalidateFrameForRemoval();
   399   NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
   400                // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
   401                aOldFrame->GetType() == nsGkAtoms::textFrame,
   402                "Must remove first continuation.");
   403   NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
   404                  GetPlaceholderFrameFor(aOldFrame)),
   405                "Must call RemoveFrame on placeholder for out-of-flows.");
   406   nsresult rv = NS_OK;
   407   nsIFrame* parentFrame = aOldFrame->GetParent();
   408   if (parentFrame->IsAbsoluteContainer() &&
   409       aListID == parentFrame->GetAbsoluteListID()) {
   410     parentFrame->GetAbsoluteContainingBlock()->
   411       RemoveFrame(parentFrame, aListID, aOldFrame);
   412   } else {
   413     rv = parentFrame->RemoveFrame(aListID, aOldFrame);
   414   }
   416   mIsDestroyingFrames = wasDestroyingFrames;
   418   return rv;
   419 }
   421 //----------------------------------------------------------------------
   423 void
   424 nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
   425 {
   426   nsIContent* content = aFrame->GetContent();
   427   if (content && content->GetPrimaryFrame() == aFrame) {
   428     ClearAllUndisplayedContentIn(content);
   429   }
   430 }
   432 // Capture state for a given frame.
   433 // Accept a content id here, in some cases we may not have content (scroll position)
   434 void
   435 nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
   436                                      nsILayoutHistoryState* aState)
   437 {
   438   if (!aFrame || !aState) {
   439     NS_WARNING("null frame, or state");
   440     return;
   441   }
   443   // Only capture state for stateful frames
   444   nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
   445   if (!statefulFrame) {
   446     return;
   447   }
   449   // Capture the state, exit early if we get null (nothing to save)
   450   nsAutoPtr<nsPresState> frameState;
   451   nsresult rv = statefulFrame->SaveState(getter_Transfers(frameState));
   452   if (!frameState) {
   453     return;
   454   }
   456   // Generate the hash key to store the state under
   457   // Exit early if we get empty key
   458   nsAutoCString stateKey;
   459   nsIContent* content = aFrame->GetContent();
   460   nsIDocument* doc = content ? content->GetCurrentDoc() : nullptr;
   461   rv = nsContentUtils::GenerateStateKey(content, doc, stateKey);
   462   if(NS_FAILED(rv) || stateKey.IsEmpty()) {
   463     return;
   464   }
   466   // Store the state. aState owns frameState now.
   467   aState->AddState(stateKey, frameState.forget());
   468 }
   470 void
   471 nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
   472                                   nsILayoutHistoryState* aState)
   473 {
   474   NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
   476   CaptureFrameStateFor(aFrame, aState);
   478   // Now capture state recursively for the frame hierarchy rooted at aFrame
   479   nsIFrame::ChildListIterator lists(aFrame);
   480   for (; !lists.IsDone(); lists.Next()) {
   481     nsFrameList::Enumerator childFrames(lists.CurrentList());
   482     for (; !childFrames.AtEnd(); childFrames.Next()) {
   483       nsIFrame* child = childFrames.get();
   484       if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
   485         // We'll pick it up when we get to its placeholder
   486         continue;
   487       }
   488       // Make sure to walk through placeholders as needed, so that we
   489       // save state for out-of-flows which may not be our descendants
   490       // themselves but whose placeholders are our descendants.
   491       CaptureFrameState(nsPlaceholderFrame::GetRealFrameFor(child), aState);
   492     }
   493   }
   494 }
   496 // Restore state for a given frame.
   497 // Accept a content id here, in some cases we may not have content (scroll position)
   498 void
   499 nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
   500                                      nsILayoutHistoryState* aState)
   501 {
   502   if (!aFrame || !aState) {
   503     NS_WARNING("null frame or state");
   504     return;
   505   }
   507   // Only restore state for stateful frames
   508   nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
   509   if (!statefulFrame) {
   510     return;
   511   }
   513   // Generate the hash key the state was stored under
   514   // Exit early if we get empty key
   515   nsIContent* content = aFrame->GetContent();
   516   // If we don't have content, we can't generate a hash
   517   // key and there's probably no state information for us.
   518   if (!content) {
   519     return;
   520   }
   522   nsAutoCString stateKey;
   523   nsIDocument* doc = content->GetCurrentDoc();
   524   nsresult rv = nsContentUtils::GenerateStateKey(content, doc, stateKey);
   525   if (NS_FAILED(rv) || stateKey.IsEmpty()) {
   526     return;
   527   }
   529   // Get the state from the hash
   530   nsPresState* frameState = aState->GetState(stateKey);
   531   if (!frameState) {
   532     return;
   533   }
   535   // Restore it
   536   rv = statefulFrame->RestoreState(frameState);
   537   if (NS_FAILED(rv)) {
   538     return;
   539   }
   541   // If we restore ok, remove the state from the state table
   542   aState->RemoveState(stateKey);
   543 }
   545 void
   546 nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
   547                                   nsILayoutHistoryState* aState)
   548 {
   549   NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
   551   RestoreFrameStateFor(aFrame, aState);
   553   // Now restore state recursively for the frame hierarchy rooted at aFrame
   554   nsIFrame::ChildListIterator lists(aFrame);
   555   for (; !lists.IsDone(); lists.Next()) {
   556     nsFrameList::Enumerator childFrames(lists.CurrentList());
   557     for (; !childFrames.AtEnd(); childFrames.Next()) {
   558       RestoreFrameState(childFrames.get(), aState);
   559     }
   560   }
   561 }
   563 //----------------------------------------------------------------------
   565 static PLHashNumber
   566 HashKey(void* key)
   567 {
   568   return NS_PTR_TO_INT32(key);
   569 }
   571 static int
   572 CompareKeys(void* key1, void* key2)
   573 {
   574   return key1 == key2;
   575 }
   577 //----------------------------------------------------------------------
   579 nsFrameManagerBase::UndisplayedMap::UndisplayedMap(uint32_t aNumBuckets)
   580 {
   581   MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
   582   mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey,
   583                            (PLHashComparator)CompareKeys,
   584                            (PLHashComparator)nullptr,
   585                            nullptr, nullptr);
   586   mLastLookup = nullptr;
   587 }
   589 nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
   590 {
   591   MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap);
   592   Clear();
   593   PL_HashTableDestroy(mTable);
   594 }
   596 PLHashEntry**  
   597 nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent** aParentContent)
   598 {
   599   nsIContent* parentContent = *aParentContent;
   601   if (mLastLookup && (parentContent == (*mLastLookup)->key)) {
   602     return mLastLookup;
   603   }
   605   // In the case of XBL default content, <xbl:children> elements do not get a
   606   // frame causing a mismatch between the content tree and the frame tree.
   607   // |GetEntryFor| is sometimes called with the content tree parent (which may
   608   // be a <xbl:children> element) but the parent in the frame tree would be the
   609   // insertion parent (parent of the <xbl:children> element). Here the children
   610   // elements are normalized to the insertion parent to correct for the mismatch.
   611   if (parentContent && nsContentUtils::IsContentInsertionPoint(parentContent)) {
   612     parentContent = parentContent->GetParent();
   613     // Change the caller's pointer for the parent content to be the insertion parent.
   614     *aParentContent = parentContent;
   615   }
   617   PLHashNumber hashCode = NS_PTR_TO_INT32(parentContent);
   618   PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, parentContent);
   619   if (*entry) {
   620     mLastLookup = entry;
   621   }
   622   return entry;
   623 }
   625 UndisplayedNode* 
   626 nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
   627 {
   628   PLHashEntry** entry = GetEntryFor(&aParentContent);
   629   if (*entry) {
   630     return (UndisplayedNode*)((*entry)->value);
   631   }
   632   return nullptr;
   633 }
   635 void
   636 nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
   637                                                   nsIContent* aParentContent)
   638 {
   639   PLHashEntry** entry = GetEntryFor(&aParentContent);
   640   if (*entry) {
   641     UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
   642     while (node->mNext) {
   643       if (node->mContent == aNode->mContent) {
   644         // We actually need to check this in optimized builds because
   645         // there are some callers that do this.  See bug 118014, bug
   646         // 136704, etc.
   647         NS_NOTREACHED("node in map twice");
   648         delete aNode;
   649         return;
   650       }
   651       node = node->mNext;
   652     }
   653     node->mNext = aNode;
   654   }
   655   else {
   656     PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
   657     PL_HashTableRawAdd(mTable, entry, hashCode, aParentContent, aNode);
   658     mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
   659   }
   660 }
   662 nsresult 
   663 nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
   664                                                nsIContent* aChild, 
   665                                                nsStyleContext* aStyle)
   666 {
   667   UndisplayedNode*  node = new UndisplayedNode(aChild, aStyle);
   669   AppendNodeFor(node, aParentContent);
   670   return NS_OK;
   671 }
   673 void
   674 nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
   675                                                   UndisplayedNode* aNode)
   676 {
   677   PLHashEntry** entry = GetEntryFor(&aParentContent);
   678   NS_ASSERTION(*entry, "content not in map");
   679   if (*entry) {
   680     if ((UndisplayedNode*)((*entry)->value) == aNode) {  // first node
   681       if (aNode->mNext) {
   682         (*entry)->value = aNode->mNext;
   683         aNode->mNext = nullptr;
   684       }
   685       else {
   686         PL_HashTableRawRemove(mTable, entry, *entry);
   687         mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
   688       }
   689     }
   690     else {
   691       UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
   692       while (node->mNext) {
   693         if (node->mNext == aNode) {
   694           node->mNext = aNode->mNext;
   695           aNode->mNext = nullptr;
   696           break;
   697         }
   698         node = node->mNext;
   699       }
   700     }
   701   }
   702   delete aNode;
   703 }
   705 void
   706 nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
   707 {
   708   PLHashEntry** entry = GetEntryFor(&aParentContent);
   709   NS_ASSERTION(entry, "content not in map");
   710   if (*entry) {
   711     UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
   712     NS_ASSERTION(node, "null node for non-null entry in UndisplayedMap");
   713     delete node;
   714     PL_HashTableRawRemove(mTable, entry, *entry);
   715     mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
   716   }
   717 }
   719 static int
   720 RemoveUndisplayedEntry(PLHashEntry* he, int i, void* arg)
   721 {
   722   UndisplayedNode*  node = (UndisplayedNode*)(he->value);
   723   delete node;
   724   // Remove and free this entry and continue enumerating
   725   return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
   726 }
   728 void
   729 nsFrameManagerBase::UndisplayedMap::Clear(void)
   730 {
   731   mLastLookup = nullptr;
   732   PL_HashTableEnumerateEntries(mTable, RemoveUndisplayedEntry, 0);
   733 }
   735 uint32_t nsFrameManagerBase::sGlobalGenerationNumber;

mercurial