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
44 #undef DEBUG_UNDISPLAYED_MAP
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
;
58 PlaceholderMapMatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
61 const PlaceholderMapEntry
*entry
=
62 static_cast<const PlaceholderMapEntry
*>(hdr
);
63 NS_ASSERTION(entry
->placeholderFrame
->GetOutOfFlowFrame() !=
65 "Dead placeholder in placeholder map");
66 return entry
->placeholderFrame
->GetOutOfFlowFrame() == key
;
69 static const PLDHashTableOps PlaceholderMapOps
= {
72 PL_DHashVoidPtrKeyStub
,
73 PlaceholderMapMatchEntry
,
74 PL_DHashMoveEntryStub
,
75 PL_DHashClearEntryStub
,
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
{
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
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
);
114 PLHashEntry
** mLastLookup
;
117 //----------------------------------------------------------------------
119 nsFrameManager::~nsFrameManager()
121 NS_ASSERTION(!mPresShell
, "nsFrameManager::Destroy never called");
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();
136 mRootFrame
->Destroy();
137 mRootFrame
= nullptr;
140 delete mUndisplayedMap
;
141 mUndisplayedMap
= nullptr;
143 mPresShell
= nullptr;
146 //----------------------------------------------------------------------
148 // Placeholder frame functions
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
;
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(),
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
;
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(),
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
;
212 nsFrameManager::ClearPlaceholderFrameMap()
214 if (mPlaceholderMap
.ops
) {
215 PL_DHashTableEnumerate(&mPlaceholderMap
, UnregisterPlaceholders
, nullptr);
216 PL_DHashTableFinish(&mPlaceholderMap
);
217 mPlaceholderMap
.ops
= nullptr;
221 //----------------------------------------------------------------------
224 nsFrameManager::GetUndisplayedContent(nsIContent
* aContent
)
226 if (!aContent
|| !mUndisplayedMap
)
229 nsIContent
* parent
= aContent
->GetParent();
230 for (UndisplayedNode
* node
= mUndisplayedMap
->GetFirstNode(parent
);
231 node
; node
= node
->mNext
) {
232 if (node
->mContent
== aContent
)
240 nsFrameManager::GetAllUndisplayedContentIn(nsIContent
* aParentContent
)
242 if (!mUndisplayedMap
)
245 return mUndisplayedMap
->GetFirstNode(aParentContent
);
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
257 printf("SetUndisplayedContent(%d): p=%p \n", i
++, (void *)aContent
);
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 "
271 mUndisplayedMap
->AddNodeFor(parent
, aContent
, aStyleContext
);
275 nsFrameManager::ChangeUndisplayedContent(nsIContent
* aContent
,
276 nsStyleContext
* aStyleContext
)
278 NS_ASSERTION(mUndisplayedMap
, "no existing undisplayed content");
280 #ifdef DEBUG_UNDISPLAYED_MAP
282 printf("ChangeUndisplayedContent(%d): p=%p \n", i
++, (void *)aContent
);
285 for (UndisplayedNode
* node
= mUndisplayedMap
->GetFirstNode(aContent
->GetParent());
286 node
; node
= node
->mNext
) {
287 if (node
->mContent
== aContent
) {
288 node
->mStyle
= aStyleContext
;
293 NS_NOTREACHED("no existing undisplayed content");
297 nsFrameManager::ClearUndisplayedContentIn(nsIContent
* aContent
,
298 nsIContent
* aParentContent
)
300 #ifdef DEBUG_UNDISPLAYED_MAP
302 printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i
++, (void *)aContent
, (void*)aParentContent
);
305 if (mUndisplayedMap
) {
306 UndisplayedNode
* node
= mUndisplayedMap
->GetFirstNode(aParentContent
);
308 if (node
->mContent
== aContent
) {
309 mUndisplayedMap
->RemoveNodeFor(aParentContent
, node
);
311 #ifdef DEBUG_UNDISPLAYED_MAP
312 printf( "REMOVED!\n");
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");
327 nsFrameManager::ClearAllUndisplayedContentIn(nsIContent
* aParentContent
)
329 #ifdef DEBUG_UNDISPLAYED_MAP
331 printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i
++, (void*)aParentContent
);
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 //----------------------------------------------------------------------
352 nsFrameManager::AppendFrames(nsContainerFrame
* aParentFrame
,
354 nsFrameList
& aFrameList
)
356 if (aParentFrame
->IsAbsoluteContainer() &&
357 aListID
== aParentFrame
->GetAbsoluteListID()) {
358 aParentFrame
->GetAbsoluteContainingBlock()->
359 AppendFrames(aParentFrame
, aListID
, aFrameList
);
361 aParentFrame
->AppendFrames(aListID
, aFrameList
);
366 nsFrameManager::InsertFrames(nsContainerFrame
* aParentFrame
,
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
);
381 aParentFrame
->InsertFrames(aListID
, aPrevFrame
, aFrameList
);
386 nsFrameManager::RemoveFrame(ChildListID aListID
,
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
);
413 parentFrame
->RemoveFrame(aListID
, aOldFrame
);
416 mIsDestroyingFrames
= wasDestroyingFrames
;
419 //----------------------------------------------------------------------
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)
433 nsFrameManager::CaptureFrameStateFor(nsIFrame
* aFrame
,
434 nsILayoutHistoryState
* aState
)
436 if (!aFrame
|| !aState
) {
437 NS_WARNING("null frame, or state");
441 // Only capture state for stateful frames
442 nsIStatefulFrame
* statefulFrame
= do_QueryFrame(aFrame
);
443 if (!statefulFrame
) {
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
));
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()) {
464 // Store the state. aState owns frameState now.
465 aState
->AddState(stateKey
, frameState
.forget());
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
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)
497 nsFrameManager::RestoreFrameStateFor(nsIFrame
* aFrame
,
498 nsILayoutHistoryState
* aState
)
500 if (!aFrame
|| !aState
) {
501 NS_WARNING("null frame or state");
505 // Only restore state for stateful frames
506 nsIStatefulFrame
* statefulFrame
= do_QueryFrame(aFrame
);
507 if (!statefulFrame
) {
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.
520 nsAutoCString stateKey
;
521 nsIDocument
* doc
= content
->GetCurrentDoc();
522 nsresult rv
= nsContentUtils::GenerateStateKey(content
, doc
, stateKey
);
523 if (NS_FAILED(rv
) || stateKey
.IsEmpty()) {
527 // Get the state from the hash
528 nsPresState
* frameState
= aState
->GetState(stateKey
);
534 rv
= statefulFrame
->RestoreState(frameState
);
539 // If we restore ok, remove the state from the state table
540 aState
->RemoveState(stateKey
);
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 //----------------------------------------------------------------------
566 return NS_PTR_TO_INT32(key
);
570 CompareKeys(void* key1
, void* 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,
584 mLastLookup
= nullptr;
587 nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
589 MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap
);
591 PL_HashTableDestroy(mTable
);
595 nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent
** aParentContent
)
597 nsIContent
* parentContent
= *aParentContent
;
599 if (mLastLookup
&& (parentContent
== (*mLastLookup
)->key
)) {
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
);
624 nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent
* aParentContent
)
626 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
628 return (UndisplayedNode
*)((*entry
)->value
);
634 nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode
* aNode
,
635 nsIContent
* aParentContent
)
637 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
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
645 NS_NOTREACHED("node in map twice");
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
661 nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent
* aParentContent
,
663 nsStyleContext
* aStyle
)
665 UndisplayedNode
* node
= new UndisplayedNode(aChild
, aStyle
);
667 AppendNodeFor(node
, aParentContent
);
672 nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent
* aParentContent
,
673 UndisplayedNode
* aNode
)
675 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
676 NS_ASSERTION(*entry
, "content not in map");
678 if ((UndisplayedNode
*)((*entry
)->value
) == aNode
) { // first node
680 (*entry
)->value
= aNode
->mNext
;
681 aNode
->mNext
= nullptr;
684 PL_HashTableRawRemove(mTable
, entry
, *entry
);
685 mLastLookup
= nullptr; // hashtable may have shifted bucket out from under us
689 UndisplayedNode
* node
= (UndisplayedNode
*)((*entry
)->value
);
690 while (node
->mNext
) {
691 if (node
->mNext
== aNode
) {
692 node
->mNext
= aNode
->mNext
;
693 aNode
->mNext
= nullptr;
704 nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent
* aParentContent
)
706 PLHashEntry
** entry
= GetEntryFor(&aParentContent
);
707 NS_ASSERTION(entry
, "content not in map");
709 UndisplayedNode
* node
= (UndisplayedNode
*)((*entry
)->value
);
710 NS_ASSERTION(node
, "null node for non-null entry in UndisplayedMap");
712 PL_HashTableRawRemove(mTable
, entry
, *entry
);
713 mLastLookup
= nullptr; // hashtable may have shifted bucket out from under us
718 RemoveUndisplayedEntry(PLHashEntry
* he
, int i
, void* arg
)
720 UndisplayedNode
* node
= (UndisplayedNode
*)(he
->value
);
722 // Remove and free this entry and continue enumerating
723 return HT_ENUMERATE_REMOVE
| HT_ENUMERATE_NEXT
;
727 nsFrameManagerBase::UndisplayedMap::Clear(void)
729 mLastLookup
= nullptr;
730 PL_HashTableEnumerateEntries(mTable
, RemoveUndisplayedEntry
, 0);
733 uint32_t nsFrameManagerBase::sGlobalGenerationNumber
;