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 */
19 #include "nsIPresShell.h"
20 #include "nsStyleContext.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"
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"
42 //#define DEBUG_UNDISPLAYED_MAP
43 //#define DEBUG_DISPLAY_CONTENTS_MAP
45 #undef DEBUG_UNDISPLAYED_MAP
46 #undef DEBUG_DISPLAY_CONTENTS_MAP
49 using namespace mozilla
;
50 using namespace mozilla::dom
;
52 //----------------------------------------------------------------------
54 struct PlaceholderMapEntry
: public PLDHashEntryHdr
{
55 // key (the out of flow frame) can be obtained through placeholder frame
56 nsPlaceholderFrame
*placeholderFrame
;
60 PlaceholderMapMatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
63 const PlaceholderMapEntry
*entry
=
64 static_cast<const PlaceholderMapEntry
*>(hdr
);
65 NS_ASSERTION(entry
->placeholderFrame
->GetOutOfFlowFrame() !=
67 "Dead placeholder in placeholder map");
68 return entry
->placeholderFrame
->GetOutOfFlowFrame() == key
;
71 static const PLDHashTableOps PlaceholderMapOps
= {
74 PL_DHashVoidPtrKeyStub
,
75 PlaceholderMapMatchEntry
,
76 PL_DHashMoveEntryStub
,
77 PL_DHashClearEntryStub
,
82 //----------------------------------------------------------------------
84 // XXXldb This seems too complicated for what I think it's doing, and it
85 // should also be using pldhash rather than plhash to use less memory.
87 class nsFrameManagerBase::UndisplayedMap
{
89 explicit UndisplayedMap(uint32_t aNumBuckets
= 16);
90 ~UndisplayedMap(void);
92 UndisplayedNode
* GetFirstNode(nsIContent
* aParentContent
);
94 nsresult
AddNodeFor(nsIContent
* aParentContent
,
95 nsIContent
* aChild
, nsStyleContext
* aStyle
);
97 void RemoveNodeFor(nsIContent
* aParentContent
,
98 UndisplayedNode
* aNode
);
100 void RemoveNodesFor(nsIContent
* aParentContent
);
101 UndisplayedNode
* UnlinkNodesFor(nsIContent
* aParentContent
);
103 // Removes all entries from the hash table
108 * Gets the entry for the provided parent content. If the content
109 * is a <xbl:children> element, |**aParentContent| is set to
110 * the parent of the children element.
112 PLHashEntry
** GetEntryFor(nsIContent
** aParentContent
);
113 void AppendNodeFor(UndisplayedNode
* aNode
,
114 nsIContent
* aParentContent
);
117 PLHashEntry
** mLastLookup
;
120 //----------------------------------------------------------------------
122 nsFrameManager::~nsFrameManager()
124 NS_ASSERTION(!mPresShell
, "nsFrameManager::Destroy never called");
128 nsFrameManager::Destroy()
130 NS_ASSERTION(mPresShell
, "Frame manager already shut down.");
132 // Destroy the frame hierarchy.
133 mPresShell
->SetIgnoreFrameDestruction(true);
135 // Unregister all placeholders before tearing down the frame tree
136 nsFrameManager::ClearPlaceholderFrameMap();
139 mRootFrame
->Destroy();
140 mRootFrame
= nullptr;
143 delete mUndisplayedMap
;
144 mUndisplayedMap
= nullptr;
145 delete mDisplayContentsMap
;
146 mDisplayContentsMap
= nullptr;
148 mPresShell
= nullptr;
151 //----------------------------------------------------------------------
153 // Placeholder frame functions
155 nsFrameManager::GetPlaceholderFrameFor(const nsIFrame
* aFrame
)
157 NS_PRECONDITION(aFrame
, "null param unexpected");
159 if (mPlaceholderMap
.ops
) {
160 PlaceholderMapEntry
*entry
= static_cast<PlaceholderMapEntry
*>
161 (PL_DHashTableLookup(const_cast<PLDHashTable
*>(&mPlaceholderMap
),
163 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
164 return entry
->placeholderFrame
;
172 nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame
* aPlaceholderFrame
)
174 NS_PRECONDITION(aPlaceholderFrame
, "null param unexpected");
175 NS_PRECONDITION(nsGkAtoms::placeholderFrame
== aPlaceholderFrame
->GetType(),
176 "unexpected frame type");
177 if (!mPlaceholderMap
.ops
) {
178 PL_DHashTableInit(&mPlaceholderMap
, &PlaceholderMapOps
, nullptr,
179 sizeof(PlaceholderMapEntry
));
181 PlaceholderMapEntry
*entry
= static_cast<PlaceholderMapEntry
*>(PL_DHashTableAdd(&mPlaceholderMap
,
182 aPlaceholderFrame
->GetOutOfFlowFrame()));
184 return NS_ERROR_OUT_OF_MEMORY
;
186 NS_ASSERTION(!entry
->placeholderFrame
, "Registering a placeholder for a frame that already has a placeholder!");
187 entry
->placeholderFrame
= aPlaceholderFrame
;
193 nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame
* aPlaceholderFrame
)
195 NS_PRECONDITION(aPlaceholderFrame
, "null param unexpected");
196 NS_PRECONDITION(nsGkAtoms::placeholderFrame
== aPlaceholderFrame
->GetType(),
197 "unexpected frame type");
199 if (mPlaceholderMap
.ops
) {
200 PL_DHashTableRemove(&mPlaceholderMap
,
201 aPlaceholderFrame
->GetOutOfFlowFrame());
205 static PLDHashOperator
206 UnregisterPlaceholders(PLDHashTable
* table
, PLDHashEntryHdr
* hdr
,
207 uint32_t number
, void* arg
)
209 PlaceholderMapEntry
* entry
= static_cast<PlaceholderMapEntry
*>(hdr
);
210 entry
->placeholderFrame
->SetOutOfFlowFrame(nullptr);
211 return PL_DHASH_NEXT
;
215 nsFrameManager::ClearPlaceholderFrameMap()
217 if (mPlaceholderMap
.ops
) {
218 PL_DHashTableEnumerate(&mPlaceholderMap
, UnregisterPlaceholders
, nullptr);
219 PL_DHashTableFinish(&mPlaceholderMap
);
220 mPlaceholderMap
.ops
= nullptr;
224 //----------------------------------------------------------------------
226 /* static */ nsStyleContext
*
227 nsFrameManager::GetStyleContextInMap(UndisplayedMap
* aMap
, nsIContent
* aContent
)
232 nsIContent
* parent
= aContent
->GetParent();
233 for (UndisplayedNode
* node
= aMap
->GetFirstNode(parent
);
234 node
; node
= node
->mNext
) {
235 if (node
->mContent
== aContent
)
242 /* static */ UndisplayedNode
*
243 nsFrameManager::GetAllUndisplayedNodesInMapFor(UndisplayedMap
* aMap
,
244 nsIContent
* aParentContent
)
246 return aMap
? aMap
->GetFirstNode(aParentContent
) : nullptr;
250 nsFrameManager::GetAllUndisplayedContentIn(nsIContent
* aParentContent
)
252 return GetAllUndisplayedNodesInMapFor(mUndisplayedMap
, aParentContent
);
256 nsFrameManager::SetStyleContextInMap(UndisplayedMap
* aMap
,
257 nsIContent
* aContent
,
258 nsStyleContext
* aStyleContext
)
260 NS_PRECONDITION(!aStyleContext
->GetPseudo(),
261 "Should only have actual elements here");
263 #if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
265 printf("SetStyleContextInMap(%d): p=%p \n", i
++, (void *)aContent
);
268 NS_ASSERTION(!GetStyleContextInMap(aMap
, aContent
),
269 "Already have an entry for aContent");
271 nsIContent
* parent
= aContent
->GetParent();
273 nsIPresShell
* shell
= aStyleContext
->PresContext()->PresShell();
274 NS_ASSERTION(parent
|| (shell
&& shell
->GetDocument() &&
275 shell
->GetDocument()->GetRootElement() == aContent
),
276 "undisplayed content must have a parent, unless it's the root "
279 aMap
->AddNodeFor(parent
, aContent
, aStyleContext
);
283 nsFrameManager::SetUndisplayedContent(nsIContent
* aContent
,
284 nsStyleContext
* aStyleContext
)
286 if (!mUndisplayedMap
) {
287 mUndisplayedMap
= new UndisplayedMap
;
289 SetStyleContextInMap(mUndisplayedMap
, aContent
, aStyleContext
);
293 nsFrameManager::ChangeStyleContextInMap(UndisplayedMap
* aMap
,
294 nsIContent
* aContent
,
295 nsStyleContext
* aStyleContext
)
297 MOZ_ASSERT(aMap
, "expecting a map");
299 #if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
301 printf("ChangeStyleContextInMap(%d): p=%p \n", i
++, (void *)aContent
);
304 for (UndisplayedNode
* node
= aMap
->GetFirstNode(aContent
->GetParent());
305 node
; node
= node
->mNext
) {
306 if (node
->mContent
== aContent
) {
307 node
->mStyle
= aStyleContext
;
312 MOZ_CRASH("couldn't find the entry to change");
316 nsFrameManager::ClearUndisplayedContentIn(nsIContent
* aContent
,
317 nsIContent
* aParentContent
)
319 #ifdef DEBUG_UNDISPLAYED_MAP
321 printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i
++, (void *)aContent
, (void*)aParentContent
);
324 if (mUndisplayedMap
) {
325 UndisplayedNode
* node
= mUndisplayedMap
->GetFirstNode(aParentContent
);
327 if (node
->mContent
== aContent
) {
328 mUndisplayedMap
->RemoveNodeFor(aParentContent
, node
);
330 #ifdef DEBUG_UNDISPLAYED_MAP
331 printf( "REMOVED!\n");
334 // make sure that there are no more entries for the same content
335 nsStyleContext
*context
= GetUndisplayedContent(aContent
);
336 NS_ASSERTION(context
== nullptr, "Found more undisplayed content data after removal");
343 #ifdef DEBUG_UNDISPLAYED_MAP
344 printf( "not found.\n");
349 nsFrameManager::ClearAllUndisplayedContentIn(nsIContent
* aParentContent
)
351 #ifdef DEBUG_UNDISPLAYED_MAP
353 printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i
++, (void*)aParentContent
);
356 if (mUndisplayedMap
) {
357 mUndisplayedMap
->RemoveNodesFor(aParentContent
);
360 // Need to look at aParentContent's content list due to XBL insertions.
361 // Nodes in aParentContent's content list do not have aParentContent as a
362 // parent, but are treated as children of aParentContent. We iterate over
363 // the flattened content list and just ignore any nodes we don't care about.
364 FlattenedChildIterator
iter(aParentContent
);
365 for (nsIContent
* child
= iter
.GetNextChild(); child
; child
= iter
.GetNextChild()) {
366 if (child
->GetParent() != aParentContent
) {
367 ClearUndisplayedContentIn(child
, child
->GetParent());
372 //----------------------------------------------------------------------
375 nsFrameManager::SetDisplayContents(nsIContent
* aContent
,
376 nsStyleContext
* aStyleContext
)
378 if (!mDisplayContentsMap
) {
379 mDisplayContentsMap
= new UndisplayedMap
;
381 SetStyleContextInMap(mDisplayContentsMap
, aContent
, aStyleContext
);
385 nsFrameManager::GetAllDisplayContentsIn(nsIContent
* aParentContent
)
387 return GetAllUndisplayedNodesInMapFor(mDisplayContentsMap
, aParentContent
);
391 nsFrameManager::ClearDisplayContentsIn(nsIContent
* aContent
,
392 nsIContent
* aParentContent
)
394 #ifdef DEBUG_DISPLAY_CONTENTS_MAP
396 printf("ClearDisplayContents(%d): content=%p parent=%p --> ", i
++, (void *)aContent
, (void*)aParentContent
);
399 if (mDisplayContentsMap
) {
400 UndisplayedNode
* node
= mDisplayContentsMap
->GetFirstNode(aParentContent
);
402 if (node
->mContent
== aContent
) {
403 mDisplayContentsMap
->RemoveNodeFor(aParentContent
, node
);
405 #ifdef DEBUG_DISPLAY_CONTENTS_MAP
406 printf( "REMOVED!\n");
409 // make sure that there are no more entries for the same content
410 nsStyleContext
* context
= GetDisplayContentsStyleFor(aContent
);
411 NS_ASSERTION(context
== nullptr, "Found more entries for aContent after removal");
413 ClearAllDisplayContentsIn(aContent
);
414 ClearAllUndisplayedContentIn(aContent
);
420 #ifdef DEBUG_DISPLAY_CONTENTS_MAP
421 printf( "not found.\n");
426 nsFrameManager::ClearAllDisplayContentsIn(nsIContent
* aParentContent
)
428 #ifdef DEBUG_DISPLAY_CONTENTS_MAP
430 printf("ClearAllDisplayContentsIn(%d): parent=%p \n", i
++, (void*)aParentContent
);
433 if (mDisplayContentsMap
) {
434 UndisplayedNode
* cur
= mDisplayContentsMap
->UnlinkNodesFor(aParentContent
);
436 UndisplayedNode
* next
= cur
->mNext
;
437 cur
->mNext
= nullptr;
438 ClearAllDisplayContentsIn(cur
->mContent
);
439 ClearAllUndisplayedContentIn(cur
->mContent
);
445 // Need to look at aParentContent's content list due to XBL insertions.
446 // Nodes in aParentContent's content list do not have aParentContent as a
447 // parent, but are treated as children of aParentContent. We iterate over
448 // the flattened content list and just ignore any nodes we don't care about.
449 FlattenedChildIterator
iter(aParentContent
);
450 for (nsIContent
* child
= iter
.GetNextChild(); child
; child
= iter
.GetNextChild()) {
451 if (child
->GetParent() != aParentContent
) {
452 ClearDisplayContentsIn(child
, child
->GetParent());
453 ClearUndisplayedContentIn(child
, child
->GetParent());
458 //----------------------------------------------------------------------
460 nsFrameManager::AppendFrames(nsContainerFrame
* aParentFrame
,
462 nsFrameList
& aFrameList
)
464 if (aParentFrame
->IsAbsoluteContainer() &&
465 aListID
== aParentFrame
->GetAbsoluteListID()) {
466 aParentFrame
->GetAbsoluteContainingBlock()->
467 AppendFrames(aParentFrame
, aListID
, aFrameList
);
469 aParentFrame
->AppendFrames(aListID
, aFrameList
);
474 nsFrameManager::InsertFrames(nsContainerFrame
* aParentFrame
,
476 nsIFrame
* aPrevFrame
,
477 nsFrameList
& aFrameList
)
479 NS_PRECONDITION(!aPrevFrame
|| (!aPrevFrame
->GetNextContinuation()
480 || (((aPrevFrame
->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
))
481 && !(aPrevFrame
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
))),
482 "aPrevFrame must be the last continuation in its chain!");
484 if (aParentFrame
->IsAbsoluteContainer() &&
485 aListID
== aParentFrame
->GetAbsoluteListID()) {
486 aParentFrame
->GetAbsoluteContainingBlock()->
487 InsertFrames(aParentFrame
, aListID
, aPrevFrame
, aFrameList
);
489 aParentFrame
->InsertFrames(aListID
, aPrevFrame
, aFrameList
);
494 nsFrameManager::RemoveFrame(ChildListID aListID
,
497 bool wasDestroyingFrames
= mIsDestroyingFrames
;
498 mIsDestroyingFrames
= true;
500 // In case the reflow doesn't invalidate anything since it just leaves
501 // a gap where the old frame was, we invalidate it here. (This is
502 // reasonably likely to happen when removing a last child in a way
503 // that doesn't change the size of the parent.)
504 // This has to sure to invalidate the entire overflow rect; this
505 // is important in the presence of absolute positioning
506 aOldFrame
->InvalidateFrameForRemoval();
508 NS_ASSERTION(!aOldFrame
->GetPrevContinuation() ||
509 // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
510 aOldFrame
->GetType() == nsGkAtoms::textFrame
,
511 "Must remove first continuation.");
512 NS_ASSERTION(!(aOldFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
&&
513 GetPlaceholderFrameFor(aOldFrame
)),
514 "Must call RemoveFrame on placeholder for out-of-flows.");
515 nsContainerFrame
* parentFrame
= aOldFrame
->GetParent();
516 if (parentFrame
->IsAbsoluteContainer() &&
517 aListID
== parentFrame
->GetAbsoluteListID()) {
518 parentFrame
->GetAbsoluteContainingBlock()->
519 RemoveFrame(parentFrame
, aListID
, aOldFrame
);
521 parentFrame
->RemoveFrame(aListID
, aOldFrame
);
524 mIsDestroyingFrames
= wasDestroyingFrames
;
527 //----------------------------------------------------------------------
530 nsFrameManager::NotifyDestroyingFrame(nsIFrame
* aFrame
)
532 nsIContent
* content
= aFrame
->GetContent();
533 if (content
&& content
->GetPrimaryFrame() == aFrame
) {
534 ClearAllUndisplayedContentIn(content
);
535 ClearAllDisplayContentsIn(content
);
539 // Capture state for a given frame.
540 // Accept a content id here, in some cases we may not have content (scroll position)
542 nsFrameManager::CaptureFrameStateFor(nsIFrame
* aFrame
,
543 nsILayoutHistoryState
* aState
)
545 if (!aFrame
|| !aState
) {
546 NS_WARNING("null frame, or state");
550 // Only capture state for stateful frames
551 nsIStatefulFrame
* statefulFrame
= do_QueryFrame(aFrame
);
552 if (!statefulFrame
) {
556 // Capture the state, exit early if we get null (nothing to save)
557 nsAutoPtr
<nsPresState
> frameState
;
558 nsresult rv
= statefulFrame
->SaveState(getter_Transfers(frameState
));
563 // Generate the hash key to store the state under
564 // Exit early if we get empty key
565 nsAutoCString stateKey
;
566 nsIContent
* content
= aFrame
->GetContent();
567 nsIDocument
* doc
= content
? content
->GetCurrentDoc() : nullptr;
568 rv
= nsContentUtils::GenerateStateKey(content
, doc
, stateKey
);
569 if(NS_FAILED(rv
) || stateKey
.IsEmpty()) {
573 // Store the state. aState owns frameState now.
574 aState
->AddState(stateKey
, frameState
.forget());
578 nsFrameManager::CaptureFrameState(nsIFrame
* aFrame
,
579 nsILayoutHistoryState
* aState
)
581 NS_PRECONDITION(nullptr != aFrame
&& nullptr != aState
, "null parameters passed in");
583 CaptureFrameStateFor(aFrame
, aState
);
585 // Now capture state recursively for the frame hierarchy rooted at aFrame
586 nsIFrame::ChildListIterator
lists(aFrame
);
587 for (; !lists
.IsDone(); lists
.Next()) {
588 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
589 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
590 nsIFrame
* child
= childFrames
.get();
591 if (child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
592 // We'll pick it up when we get to its placeholder
595 // Make sure to walk through placeholders as needed, so that we
596 // save state for out-of-flows which may not be our descendants
597 // themselves but whose placeholders are our descendants.
598 CaptureFrameState(nsPlaceholderFrame::GetRealFrameFor(child
), aState
);
603 // Restore state for a given frame.
604 // Accept a content id here, in some cases we may not have content (scroll position)
606 nsFrameManager::RestoreFrameStateFor(nsIFrame
* aFrame
,
607 nsILayoutHistoryState
* aState
)
609 if (!aFrame
|| !aState
) {
610 NS_WARNING("null frame or state");
614 // Only restore state for stateful frames
615 nsIStatefulFrame
* statefulFrame
= do_QueryFrame(aFrame
);
616 if (!statefulFrame
) {
620 // Generate the hash key the state was stored under
621 // Exit early if we get empty key
622 nsIContent
* content
= aFrame
->GetContent();
623 // If we don't have content, we can't generate a hash
624 // key and there's probably no state information for us.
629 nsAutoCString stateKey
;
630 nsIDocument
* doc
= content
->GetCurrentDoc();
631 nsresult rv
= nsContentUtils::GenerateStateKey(content
, doc
, stateKey
);
632 if (NS_FAILED(rv
) || stateKey
.IsEmpty()) {
636 // Get the state from the hash
637 nsPresState
* frameState
= aState
->GetState(stateKey
);
643 rv
= statefulFrame
->RestoreState(frameState
);
648 // If we restore ok, remove the state from the state table
649 aState
->RemoveState(stateKey
);
653 nsFrameManager::RestoreFrameState(nsIFrame
* aFrame
,
654 nsILayoutHistoryState
* aState
)
656 NS_PRECONDITION(nullptr != aFrame
&& nullptr != aState
, "null parameters passed in");
658 RestoreFrameStateFor(aFrame
, aState
);
660 // Now restore state recursively for the frame hierarchy rooted at aFrame
661 nsIFrame::ChildListIterator
lists(aFrame
);
662 for (; !lists
.IsDone(); lists
.Next()) {
663 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
664 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
665 RestoreFrameState(childFrames
.get(), aState
);
670 //----------------------------------------------------------------------
675 return NS_PTR_TO_INT32(key
);
679 CompareKeys(void* key1
, void* key2
)
684 //----------------------------------------------------------------------
686 nsFrameManagerBase::UndisplayedMap::UndisplayedMap(uint32_t aNumBuckets
)
688 MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap
);
689 mTable
= PL_NewHashTable(aNumBuckets
, (PLHashFunction
)HashKey
,
690 (PLHashComparator
)CompareKeys
,
691 (PLHashComparator
)nullptr,
693 mLastLookup
= nullptr;
696 nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
698 MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap
);
700 PL_HashTableDestroy(mTable
);
704 nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent
** aParentContent
)
706 nsIContent
* parentContent
= *aParentContent
;
708 if (mLastLookup
&& (parentContent
== (*mLastLookup
)->key
)) {
712 // In the case of XBL default content, <xbl:children> elements do not get a
713 // frame causing a mismatch between the content tree and the frame tree.
714 // |GetEntryFor| is sometimes called with the content tree parent (which may
715 // be a <xbl:children> element) but the parent in the frame tree would be the
716 // insertion parent (parent of the <xbl:children> element). Here the children
717 // elements are normalized to the insertion parent to correct for the mismatch.
718 if (parentContent
&& nsContentUtils::IsContentInsertionPoint(parentContent
)) {
719 parentContent
= parentContent
->GetParent();
720 // Change the caller's pointer for the parent content to be the insertion parent.
721 *aParentContent
= parentContent
;
724 PLHashNumber hashCode
= NS_PTR_TO_INT32(parentContent
);
725 PLHashEntry
** entry
= PL_HashTableRawLookup(mTable
, hashCode
, parentContent
);
733 nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent
* aParentContent
)
735 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
737 return (UndisplayedNode
*)((*entry
)->value
);
743 nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode
* aNode
,
744 nsIContent
* aParentContent
)
746 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
748 UndisplayedNode
* node
= (UndisplayedNode
*)((*entry
)->value
);
749 while (node
->mNext
) {
750 if (node
->mContent
== aNode
->mContent
) {
751 // We actually need to check this in optimized builds because
752 // there are some callers that do this. See bug 118014, bug
754 NS_NOTREACHED("node in map twice");
763 PLHashNumber hashCode
= NS_PTR_TO_INT32(aParentContent
);
764 PL_HashTableRawAdd(mTable
, entry
, hashCode
, aParentContent
, aNode
);
765 mLastLookup
= nullptr; // hashtable may have shifted bucket out from under us
770 nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent
* aParentContent
,
772 nsStyleContext
* aStyle
)
774 UndisplayedNode
* node
= new UndisplayedNode(aChild
, aStyle
);
776 AppendNodeFor(node
, aParentContent
);
781 nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent
* aParentContent
,
782 UndisplayedNode
* aNode
)
784 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
785 NS_ASSERTION(*entry
, "content not in map");
787 if ((UndisplayedNode
*)((*entry
)->value
) == aNode
) { // first node
789 (*entry
)->value
= aNode
->mNext
;
790 aNode
->mNext
= nullptr;
793 PL_HashTableRawRemove(mTable
, entry
, *entry
);
794 mLastLookup
= nullptr; // hashtable may have shifted bucket out from under us
798 UndisplayedNode
* node
= (UndisplayedNode
*)((*entry
)->value
);
799 while (node
->mNext
) {
800 if (node
->mNext
== aNode
) {
801 node
->mNext
= aNode
->mNext
;
802 aNode
->mNext
= nullptr;
814 nsFrameManagerBase::UndisplayedMap::UnlinkNodesFor(nsIContent
* aParentContent
)
816 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
817 NS_ASSERTION(entry
, "content not in map");
819 UndisplayedNode
* node
= (UndisplayedNode
*)((*entry
)->value
);
820 NS_ASSERTION(node
, "null node for non-null entry in UndisplayedMap");
821 PL_HashTableRawRemove(mTable
, entry
, *entry
);
822 mLastLookup
= nullptr; // hashtable may have shifted bucket out from under us
829 nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent
* aParentContent
)
831 delete UnlinkNodesFor(aParentContent
);
835 RemoveUndisplayedEntry(PLHashEntry
* he
, int i
, void* arg
)
837 UndisplayedNode
* node
= (UndisplayedNode
*)(he
->value
);
839 // Remove and free this entry and continue enumerating
840 return HT_ENUMERATE_REMOVE
| HT_ENUMERATE_NEXT
;
844 nsFrameManagerBase::UndisplayedMap::Clear(void)
846 mLastLookup
= nullptr;
847 PL_HashTableEnumerateEntries(mTable
, RemoveUndisplayedEntry
, 0);
850 uint32_t nsFrameManagerBase::sGlobalGenerationNumber
;