Bumping manifests a=b2g-bump
[gecko.git] / layout / base / nsFrameManager.cpp
blob63eef5e30716f901c7b81113435a99b724529fb5
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:cindent:ts=2:et:sw=2:
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/.
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
12 * Date Modified by Description of modification
13 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
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"
39 #include "nsContainerFrame.h"
41 #ifdef DEBUG
42 //#define DEBUG_UNDISPLAYED_MAP
43 #else
44 #undef DEBUG_UNDISPLAYED_MAP
45 #endif
47 using namespace mozilla;
48 using namespace mozilla::dom;
50 //----------------------------------------------------------------------
52 struct PlaceholderMapEntry : public PLDHashEntryHdr {
53 // key (the out of flow frame) can be obtained through placeholder frame
54 nsPlaceholderFrame *placeholderFrame;
57 static bool
58 PlaceholderMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
59 const void *key)
61 const PlaceholderMapEntry *entry =
62 static_cast<const PlaceholderMapEntry*>(hdr);
63 NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() !=
64 (void*)0xdddddddd,
65 "Dead placeholder in placeholder map");
66 return entry->placeholderFrame->GetOutOfFlowFrame() == key;
69 static const PLDHashTableOps PlaceholderMapOps = {
70 PL_DHashAllocTable,
71 PL_DHashFreeTable,
72 PL_DHashVoidPtrKeyStub,
73 PlaceholderMapMatchEntry,
74 PL_DHashMoveEntryStub,
75 PL_DHashClearEntryStub,
76 PL_DHashFinalizeStub,
77 nullptr
80 //----------------------------------------------------------------------
82 // XXXldb This seems too complicated for what I think it's doing, and it
83 // should also be using pldhash rather than plhash to use less memory.
85 class nsFrameManagerBase::UndisplayedMap {
86 public:
87 explicit UndisplayedMap(uint32_t aNumBuckets = 16);
88 ~UndisplayedMap(void);
90 UndisplayedNode* GetFirstNode(nsIContent* aParentContent);
92 nsresult AddNodeFor(nsIContent* aParentContent,
93 nsIContent* aChild, nsStyleContext* aStyle);
95 void RemoveNodeFor(nsIContent* aParentContent,
96 UndisplayedNode* aNode);
98 void RemoveNodesFor(nsIContent* aParentContent);
100 // Removes all entries from the hash table
101 void Clear(void);
103 protected:
105 * Gets the entry for the provided parent content. If the content
106 * is a <xbl:children> element, |**aParentContent| is set to
107 * the parent of the children element.
109 PLHashEntry** GetEntryFor(nsIContent** aParentContent);
110 void AppendNodeFor(UndisplayedNode* aNode,
111 nsIContent* aParentContent);
113 PLHashTable* mTable;
114 PLHashEntry** mLastLookup;
117 //----------------------------------------------------------------------
119 nsFrameManager::~nsFrameManager()
121 NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
124 void
125 nsFrameManager::Destroy()
127 NS_ASSERTION(mPresShell, "Frame manager already shut down.");
129 // Destroy the frame hierarchy.
130 mPresShell->SetIgnoreFrameDestruction(true);
132 // Unregister all placeholders before tearing down the frame tree
133 nsFrameManager::ClearPlaceholderFrameMap();
135 if (mRootFrame) {
136 mRootFrame->Destroy();
137 mRootFrame = nullptr;
140 delete mUndisplayedMap;
141 mUndisplayedMap = nullptr;
143 mPresShell = nullptr;
146 //----------------------------------------------------------------------
148 // Placeholder frame functions
149 nsPlaceholderFrame*
150 nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame)
152 NS_PRECONDITION(aFrame, "null param unexpected");
154 if (mPlaceholderMap.ops) {
155 PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>
156 (PL_DHashTableOperate(const_cast<PLDHashTable*>(&mPlaceholderMap),
157 aFrame, PL_DHASH_LOOKUP));
158 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
159 return entry->placeholderFrame;
163 return nullptr;
166 nsresult
167 nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
169 NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
170 NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
171 "unexpected frame type");
172 if (!mPlaceholderMap.ops) {
173 PL_DHashTableInit(&mPlaceholderMap, &PlaceholderMapOps, nullptr,
174 sizeof(PlaceholderMapEntry));
176 PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>(PL_DHashTableOperate(&mPlaceholderMap,
177 aPlaceholderFrame->GetOutOfFlowFrame(),
178 PL_DHASH_ADD));
179 if (!entry)
180 return NS_ERROR_OUT_OF_MEMORY;
182 NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
183 entry->placeholderFrame = aPlaceholderFrame;
185 return NS_OK;
188 void
189 nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
191 NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
192 NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
193 "unexpected frame type");
195 if (mPlaceholderMap.ops) {
196 PL_DHashTableOperate(&mPlaceholderMap,
197 aPlaceholderFrame->GetOutOfFlowFrame(),
198 PL_DHASH_REMOVE);
202 static PLDHashOperator
203 UnregisterPlaceholders(PLDHashTable* table, PLDHashEntryHdr* hdr,
204 uint32_t number, void* arg)
206 PlaceholderMapEntry* entry = static_cast<PlaceholderMapEntry*>(hdr);
207 entry->placeholderFrame->SetOutOfFlowFrame(nullptr);
208 return PL_DHASH_NEXT;
211 void
212 nsFrameManager::ClearPlaceholderFrameMap()
214 if (mPlaceholderMap.ops) {
215 PL_DHashTableEnumerate(&mPlaceholderMap, UnregisterPlaceholders, nullptr);
216 PL_DHashTableFinish(&mPlaceholderMap);
217 mPlaceholderMap.ops = nullptr;
221 //----------------------------------------------------------------------
223 nsStyleContext*
224 nsFrameManager::GetUndisplayedContent(nsIContent* aContent)
226 if (!aContent || !mUndisplayedMap)
227 return nullptr;
229 nsIContent* parent = aContent->GetParent();
230 for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(parent);
231 node; node = node->mNext) {
232 if (node->mContent == aContent)
233 return node->mStyle;
236 return nullptr;
239 UndisplayedNode*
240 nsFrameManager::GetAllUndisplayedContentIn(nsIContent* aParentContent)
242 if (!mUndisplayedMap)
243 return nullptr;
245 return mUndisplayedMap->GetFirstNode(aParentContent);
248 void
249 nsFrameManager::SetUndisplayedContent(nsIContent* aContent,
250 nsStyleContext* aStyleContext)
252 NS_PRECONDITION(!aStyleContext->GetPseudo(),
253 "Should only have actual elements here");
255 #ifdef DEBUG_UNDISPLAYED_MAP
256 static int i = 0;
257 printf("SetUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
258 #endif
260 NS_ASSERTION(!GetUndisplayedContent(aContent),
261 "Already have an undisplayed context entry for aContent");
263 if (! mUndisplayedMap) {
264 mUndisplayedMap = new UndisplayedMap;
266 nsIContent* parent = aContent->GetParent();
267 NS_ASSERTION(parent || (mPresShell && mPresShell->GetDocument() &&
268 mPresShell->GetDocument()->GetRootElement() == aContent),
269 "undisplayed content must have a parent, unless it's the root "
270 "element");
271 mUndisplayedMap->AddNodeFor(parent, aContent, aStyleContext);
274 void
275 nsFrameManager::ChangeUndisplayedContent(nsIContent* aContent,
276 nsStyleContext* aStyleContext)
278 NS_ASSERTION(mUndisplayedMap, "no existing undisplayed content");
280 #ifdef DEBUG_UNDISPLAYED_MAP
281 static int i = 0;
282 printf("ChangeUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
283 #endif
285 for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aContent->GetParent());
286 node; node = node->mNext) {
287 if (node->mContent == aContent) {
288 node->mStyle = aStyleContext;
289 return;
293 NS_NOTREACHED("no existing undisplayed content");
296 void
297 nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
298 nsIContent* aParentContent)
300 #ifdef DEBUG_UNDISPLAYED_MAP
301 static int i = 0;
302 printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
303 #endif
305 if (mUndisplayedMap) {
306 UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
307 while (node) {
308 if (node->mContent == aContent) {
309 mUndisplayedMap->RemoveNodeFor(aParentContent, node);
311 #ifdef DEBUG_UNDISPLAYED_MAP
312 printf( "REMOVED!\n");
313 #endif
314 #ifdef DEBUG
315 // make sure that there are no more entries for the same content
316 nsStyleContext *context = GetUndisplayedContent(aContent);
317 NS_ASSERTION(context == nullptr, "Found more undisplayed content data after removal");
318 #endif
319 return;
321 node = node->mNext;
326 void
327 nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent)
329 #ifdef DEBUG_UNDISPLAYED_MAP
330 static int i = 0;
331 printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i++, (void*)aParentContent);
332 #endif
334 if (mUndisplayedMap) {
335 mUndisplayedMap->RemoveNodesFor(aParentContent);
338 // Need to look at aParentContent's content list due to XBL insertions.
339 // Nodes in aParentContent's content list do not have aParentContent as a
340 // parent, but are treated as children of aParentContent. We iterate over
341 // the flattened content list and just ignore any nodes we don't care about.
342 FlattenedChildIterator iter(aParentContent);
343 for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
344 if (child->GetParent() != aParentContent) {
345 ClearUndisplayedContentIn(child, child->GetParent());
350 //----------------------------------------------------------------------
351 void
352 nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
353 ChildListID aListID,
354 nsFrameList& aFrameList)
356 if (aParentFrame->IsAbsoluteContainer() &&
357 aListID == aParentFrame->GetAbsoluteListID()) {
358 aParentFrame->GetAbsoluteContainingBlock()->
359 AppendFrames(aParentFrame, aListID, aFrameList);
360 } else {
361 aParentFrame->AppendFrames(aListID, aFrameList);
365 void
366 nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
367 ChildListID aListID,
368 nsIFrame* aPrevFrame,
369 nsFrameList& aFrameList)
371 NS_PRECONDITION(!aPrevFrame || (!aPrevFrame->GetNextContinuation()
372 || (((aPrevFrame->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))
373 && !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))),
374 "aPrevFrame must be the last continuation in its chain!");
376 if (aParentFrame->IsAbsoluteContainer() &&
377 aListID == aParentFrame->GetAbsoluteListID()) {
378 aParentFrame->GetAbsoluteContainingBlock()->
379 InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
380 } else {
381 aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
385 void
386 nsFrameManager::RemoveFrame(ChildListID aListID,
387 nsIFrame* aOldFrame)
389 bool wasDestroyingFrames = mIsDestroyingFrames;
390 mIsDestroyingFrames = true;
392 // In case the reflow doesn't invalidate anything since it just leaves
393 // a gap where the old frame was, we invalidate it here. (This is
394 // reasonably likely to happen when removing a last child in a way
395 // that doesn't change the size of the parent.)
396 // This has to sure to invalidate the entire overflow rect; this
397 // is important in the presence of absolute positioning
398 aOldFrame->InvalidateFrameForRemoval();
400 NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
401 // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
402 aOldFrame->GetType() == nsGkAtoms::textFrame,
403 "Must remove first continuation.");
404 NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
405 GetPlaceholderFrameFor(aOldFrame)),
406 "Must call RemoveFrame on placeholder for out-of-flows.");
407 nsContainerFrame* parentFrame = aOldFrame->GetParent();
408 if (parentFrame->IsAbsoluteContainer() &&
409 aListID == parentFrame->GetAbsoluteListID()) {
410 parentFrame->GetAbsoluteContainingBlock()->
411 RemoveFrame(parentFrame, aListID, aOldFrame);
412 } else {
413 parentFrame->RemoveFrame(aListID, aOldFrame);
416 mIsDestroyingFrames = wasDestroyingFrames;
419 //----------------------------------------------------------------------
421 void
422 nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
424 nsIContent* content = aFrame->GetContent();
425 if (content && content->GetPrimaryFrame() == aFrame) {
426 ClearAllUndisplayedContentIn(content);
430 // Capture state for a given frame.
431 // Accept a content id here, in some cases we may not have content (scroll position)
432 void
433 nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
434 nsILayoutHistoryState* aState)
436 if (!aFrame || !aState) {
437 NS_WARNING("null frame, or state");
438 return;
441 // Only capture state for stateful frames
442 nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
443 if (!statefulFrame) {
444 return;
447 // Capture the state, exit early if we get null (nothing to save)
448 nsAutoPtr<nsPresState> frameState;
449 nsresult rv = statefulFrame->SaveState(getter_Transfers(frameState));
450 if (!frameState) {
451 return;
454 // Generate the hash key to store the state under
455 // Exit early if we get empty key
456 nsAutoCString stateKey;
457 nsIContent* content = aFrame->GetContent();
458 nsIDocument* doc = content ? content->GetCurrentDoc() : nullptr;
459 rv = nsContentUtils::GenerateStateKey(content, doc, stateKey);
460 if(NS_FAILED(rv) || stateKey.IsEmpty()) {
461 return;
464 // Store the state. aState owns frameState now.
465 aState->AddState(stateKey, frameState.forget());
468 void
469 nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
470 nsILayoutHistoryState* aState)
472 NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
474 CaptureFrameStateFor(aFrame, aState);
476 // Now capture state recursively for the frame hierarchy rooted at aFrame
477 nsIFrame::ChildListIterator lists(aFrame);
478 for (; !lists.IsDone(); lists.Next()) {
479 nsFrameList::Enumerator childFrames(lists.CurrentList());
480 for (; !childFrames.AtEnd(); childFrames.Next()) {
481 nsIFrame* child = childFrames.get();
482 if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
483 // We'll pick it up when we get to its placeholder
484 continue;
486 // Make sure to walk through placeholders as needed, so that we
487 // save state for out-of-flows which may not be our descendants
488 // themselves but whose placeholders are our descendants.
489 CaptureFrameState(nsPlaceholderFrame::GetRealFrameFor(child), aState);
494 // Restore state for a given frame.
495 // Accept a content id here, in some cases we may not have content (scroll position)
496 void
497 nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
498 nsILayoutHistoryState* aState)
500 if (!aFrame || !aState) {
501 NS_WARNING("null frame or state");
502 return;
505 // Only restore state for stateful frames
506 nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
507 if (!statefulFrame) {
508 return;
511 // Generate the hash key the state was stored under
512 // Exit early if we get empty key
513 nsIContent* content = aFrame->GetContent();
514 // If we don't have content, we can't generate a hash
515 // key and there's probably no state information for us.
516 if (!content) {
517 return;
520 nsAutoCString stateKey;
521 nsIDocument* doc = content->GetCurrentDoc();
522 nsresult rv = nsContentUtils::GenerateStateKey(content, doc, stateKey);
523 if (NS_FAILED(rv) || stateKey.IsEmpty()) {
524 return;
527 // Get the state from the hash
528 nsPresState* frameState = aState->GetState(stateKey);
529 if (!frameState) {
530 return;
533 // Restore it
534 rv = statefulFrame->RestoreState(frameState);
535 if (NS_FAILED(rv)) {
536 return;
539 // If we restore ok, remove the state from the state table
540 aState->RemoveState(stateKey);
543 void
544 nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
545 nsILayoutHistoryState* aState)
547 NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
549 RestoreFrameStateFor(aFrame, aState);
551 // Now restore state recursively for the frame hierarchy rooted at aFrame
552 nsIFrame::ChildListIterator lists(aFrame);
553 for (; !lists.IsDone(); lists.Next()) {
554 nsFrameList::Enumerator childFrames(lists.CurrentList());
555 for (; !childFrames.AtEnd(); childFrames.Next()) {
556 RestoreFrameState(childFrames.get(), aState);
561 //----------------------------------------------------------------------
563 static PLHashNumber
564 HashKey(void* key)
566 return NS_PTR_TO_INT32(key);
569 static int
570 CompareKeys(void* key1, void* key2)
572 return key1 == key2;
575 //----------------------------------------------------------------------
577 nsFrameManagerBase::UndisplayedMap::UndisplayedMap(uint32_t aNumBuckets)
579 MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
580 mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey,
581 (PLHashComparator)CompareKeys,
582 (PLHashComparator)nullptr,
583 nullptr, nullptr);
584 mLastLookup = nullptr;
587 nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
589 MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap);
590 Clear();
591 PL_HashTableDestroy(mTable);
594 PLHashEntry**
595 nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent** aParentContent)
597 nsIContent* parentContent = *aParentContent;
599 if (mLastLookup && (parentContent == (*mLastLookup)->key)) {
600 return mLastLookup;
603 // In the case of XBL default content, <xbl:children> elements do not get a
604 // frame causing a mismatch between the content tree and the frame tree.
605 // |GetEntryFor| is sometimes called with the content tree parent (which may
606 // be a <xbl:children> element) but the parent in the frame tree would be the
607 // insertion parent (parent of the <xbl:children> element). Here the children
608 // elements are normalized to the insertion parent to correct for the mismatch.
609 if (parentContent && nsContentUtils::IsContentInsertionPoint(parentContent)) {
610 parentContent = parentContent->GetParent();
611 // Change the caller's pointer for the parent content to be the insertion parent.
612 *aParentContent = parentContent;
615 PLHashNumber hashCode = NS_PTR_TO_INT32(parentContent);
616 PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, parentContent);
617 if (*entry) {
618 mLastLookup = entry;
620 return entry;
623 UndisplayedNode*
624 nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
626 PLHashEntry** entry = GetEntryFor(&aParentContent);
627 if (*entry) {
628 return (UndisplayedNode*)((*entry)->value);
630 return nullptr;
633 void
634 nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
635 nsIContent* aParentContent)
637 PLHashEntry** entry = GetEntryFor(&aParentContent);
638 if (*entry) {
639 UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
640 while (node->mNext) {
641 if (node->mContent == aNode->mContent) {
642 // We actually need to check this in optimized builds because
643 // there are some callers that do this. See bug 118014, bug
644 // 136704, etc.
645 NS_NOTREACHED("node in map twice");
646 delete aNode;
647 return;
649 node = node->mNext;
651 node->mNext = aNode;
653 else {
654 PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
655 PL_HashTableRawAdd(mTable, entry, hashCode, aParentContent, aNode);
656 mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
660 nsresult
661 nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
662 nsIContent* aChild,
663 nsStyleContext* aStyle)
665 UndisplayedNode* node = new UndisplayedNode(aChild, aStyle);
667 AppendNodeFor(node, aParentContent);
668 return NS_OK;
671 void
672 nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
673 UndisplayedNode* aNode)
675 PLHashEntry** entry = GetEntryFor(&aParentContent);
676 NS_ASSERTION(*entry, "content not in map");
677 if (*entry) {
678 if ((UndisplayedNode*)((*entry)->value) == aNode) { // first node
679 if (aNode->mNext) {
680 (*entry)->value = aNode->mNext;
681 aNode->mNext = nullptr;
683 else {
684 PL_HashTableRawRemove(mTable, entry, *entry);
685 mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
688 else {
689 UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
690 while (node->mNext) {
691 if (node->mNext == aNode) {
692 node->mNext = aNode->mNext;
693 aNode->mNext = nullptr;
694 break;
696 node = node->mNext;
700 delete aNode;
703 void
704 nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
706 PLHashEntry** entry = GetEntryFor(&aParentContent);
707 NS_ASSERTION(entry, "content not in map");
708 if (*entry) {
709 UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
710 NS_ASSERTION(node, "null node for non-null entry in UndisplayedMap");
711 delete node;
712 PL_HashTableRawRemove(mTable, entry, *entry);
713 mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
717 static int
718 RemoveUndisplayedEntry(PLHashEntry* he, int i, void* arg)
720 UndisplayedNode* node = (UndisplayedNode*)(he->value);
721 delete node;
722 // Remove and free this entry and continue enumerating
723 return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
726 void
727 nsFrameManagerBase::UndisplayedMap::Clear(void)
729 mLastLookup = nullptr;
730 PL_HashTableEnumerateEntries(mTable, RemoveUndisplayedEntry, 0);
733 uint32_t nsFrameManagerBase::sGlobalGenerationNumber;