Wed, 31 Dec 2014 06:09:35 +0100
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 * 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;