Line data Source code
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 : */
15 :
16 : /* storage of the frame tree and information about it */
17 :
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"
29 :
30 : #include "nsContentUtils.h"
31 : #include "nsError.h"
32 : #include "nsAutoPtr.h"
33 : #include "nsAbsoluteContainingBlock.h"
34 : #include "ChildIterator.h"
35 :
36 : #include "nsFrameManager.h"
37 : #include "GeckoProfiler.h"
38 : #include "nsIStatefulFrame.h"
39 : #include "nsContainerFrame.h"
40 :
41 : // #define DEBUG_UNDISPLAYED_MAP
42 : // #define DEBUG_DISPLAY_CONTENTS_MAP
43 :
44 : using namespace mozilla;
45 : using namespace mozilla::dom;
46 :
47 : //----------------------------------------------------------------------
48 :
49 28 : nsFrameManagerBase::nsFrameManagerBase()
50 : : mPresShell(nullptr)
51 : , mRootFrame(nullptr)
52 : , mUndisplayedMap(nullptr)
53 : , mDisplayContentsMap(nullptr)
54 28 : , mIsDestroyingFrames(false)
55 : {
56 28 : }
57 :
58 : //----------------------------------------------------------------------
59 :
60 : /**
61 : * The undisplayed map is a class that maps a parent content node to the
62 : * undisplayed content children, and their style contexts.
63 : *
64 : * The linked list of nodes holds strong references to the style contexts and
65 : * the content.
66 : */
67 : class nsFrameManagerBase::UndisplayedMap :
68 : private nsClassHashtable<nsPtrHashKey<nsIContent>,
69 : LinkedList<UndisplayedNode>>
70 : {
71 : typedef nsClassHashtable<nsPtrHashKey<nsIContent>, LinkedList<UndisplayedNode>> base_type;
72 :
73 : public:
74 : UndisplayedMap();
75 : ~UndisplayedMap();
76 :
77 : UndisplayedNode* GetFirstNode(nsIContent* aParentContent);
78 :
79 : void AddNodeFor(nsIContent* aParentContent,
80 : nsIContent* aChild,
81 : nsStyleContext* aStyle);
82 :
83 : void RemoveNodeFor(nsIContent* aParentContent, UndisplayedNode* aNode);
84 :
85 : void RemoveNodesFor(nsIContent* aParentContent);
86 :
87 : nsAutoPtr<LinkedList<UndisplayedNode>>
88 : UnlinkNodesFor(nsIContent* aParentContent);
89 :
90 : // Removes all entries from the hash table
91 : void Clear();
92 :
93 : protected:
94 : LinkedList<UndisplayedNode>* GetListFor(nsIContent* aParentContent);
95 : LinkedList<UndisplayedNode>* GetOrCreateListFor(nsIContent* aParentContent);
96 : void AppendNodeFor(UndisplayedNode* aNode, nsIContent* aParentContent);
97 : /**
98 : * Get the applicable parent for the map lookup. This is almost always the
99 : * provided argument, except if it's a <xbl:children> element, in which case
100 : * it's the parent of the children element.
101 : */
102 : nsIContent* GetApplicableParent(nsIContent* aParent);
103 : };
104 :
105 : //----------------------------------------------------------------------
106 :
107 8 : nsFrameManager::~nsFrameManager()
108 : {
109 4 : NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
110 4 : }
111 :
112 : void
113 4 : nsFrameManager::Destroy()
114 : {
115 4 : NS_ASSERTION(mPresShell, "Frame manager already shut down.");
116 :
117 : // Destroy the frame hierarchy.
118 4 : mPresShell->SetIgnoreFrameDestruction(true);
119 :
120 4 : if (mRootFrame) {
121 0 : mRootFrame->Destroy();
122 0 : mRootFrame = nullptr;
123 : }
124 :
125 4 : delete mUndisplayedMap;
126 4 : mUndisplayedMap = nullptr;
127 4 : delete mDisplayContentsMap;
128 4 : mDisplayContentsMap = nullptr;
129 :
130 4 : mPresShell = nullptr;
131 4 : }
132 :
133 : //----------------------------------------------------------------------
134 :
135 : static nsIContent*
136 649 : ParentForUndisplayedMap(const nsIContent* aContent)
137 : {
138 649 : MOZ_ASSERT(aContent);
139 :
140 649 : nsIContent* parent = aContent->GetParentElementCrossingShadowRoot();
141 649 : MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
142 :
143 649 : return parent;
144 : }
145 :
146 : /* static */ nsStyleContext*
147 355 : nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap,
148 : const nsIContent* aContent)
149 : {
150 355 : UndisplayedNode* node = GetUndisplayedNodeInMapFor(aMap, aContent);
151 355 : return node ? node->mStyle.get() : nullptr;
152 : }
153 :
154 : /* static */ UndisplayedNode*
155 355 : nsFrameManager::GetUndisplayedNodeInMapFor(UndisplayedMap* aMap,
156 : const nsIContent* aContent)
157 : {
158 355 : if (!aContent) {
159 0 : return nullptr;
160 : }
161 355 : nsIContent* parent = ParentForUndisplayedMap(aContent);
162 2285 : for (UndisplayedNode* node = aMap->GetFirstNode(parent);
163 4215 : node; node = node->getNext()) {
164 1938 : if (node->mContent == aContent)
165 8 : return node;
166 : }
167 :
168 347 : return nullptr;
169 : }
170 :
171 :
172 : /* static */ UndisplayedNode*
173 2110 : nsFrameManager::GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
174 : nsIContent* aParentContent)
175 : {
176 2110 : return aMap ? aMap->GetFirstNode(aParentContent) : nullptr;
177 : }
178 :
179 : UndisplayedNode*
180 1055 : nsFrameManager::GetAllUndisplayedContentIn(nsIContent* aParentContent)
181 : {
182 1055 : return GetAllUndisplayedNodesInMapFor(mUndisplayedMap, aParentContent);
183 : }
184 :
185 : /* static */ void
186 294 : nsFrameManager::SetStyleContextInMap(UndisplayedMap* aMap,
187 : nsIContent* aContent,
188 : nsStyleContext* aStyleContext)
189 : {
190 294 : MOZ_ASSERT(!aStyleContext->GetPseudo(),
191 : "Should only have actual elements here");
192 :
193 : #if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
194 : static int i = 0;
195 : printf("SetStyleContextInMap(%d): p=%p \n", i++, (void *)aContent);
196 : #endif
197 :
198 294 : MOZ_ASSERT(!GetStyleContextInMap(aMap, aContent),
199 : "Already have an entry for aContent");
200 :
201 294 : nsIContent* parent = ParentForUndisplayedMap(aContent);
202 : #ifdef DEBUG
203 294 : nsIPresShell* shell = aStyleContext->PresContext()->PresShell();
204 294 : NS_ASSERTION(parent || (shell && shell->GetDocument() &&
205 : shell->GetDocument()->GetRootElement() == aContent),
206 : "undisplayed content must have a parent, unless it's the root "
207 : "element");
208 : #endif
209 294 : aMap->AddNodeFor(parent, aContent, aStyleContext);
210 294 : }
211 :
212 : void
213 294 : nsFrameManager::SetUndisplayedContent(nsIContent* aContent,
214 : nsStyleContext* aStyleContext)
215 : {
216 294 : if (!mUndisplayedMap) {
217 24 : mUndisplayedMap = new UndisplayedMap;
218 : }
219 294 : SetStyleContextInMap(mUndisplayedMap, aContent, aStyleContext);
220 294 : }
221 :
222 : /* static */ void
223 8 : nsFrameManager::ChangeStyleContextInMap(UndisplayedMap* aMap,
224 : nsIContent* aContent,
225 : nsStyleContext* aStyleContext)
226 : {
227 8 : MOZ_ASSERT(aMap, "expecting a map");
228 :
229 : #if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
230 : static int i = 0;
231 : printf("ChangeStyleContextInMap(%d): p=%p \n", i++, (void *)aContent);
232 : #endif
233 :
234 12 : for (UndisplayedNode* node = aMap->GetFirstNode(aContent->GetParent());
235 16 : node; node = node->getNext()) {
236 12 : if (node->mContent == aContent) {
237 8 : node->mStyle = aStyleContext;
238 8 : return;
239 : }
240 : }
241 :
242 0 : MOZ_CRASH("couldn't find the entry to change");
243 : }
244 :
245 : void
246 16 : nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
247 : nsIContent* aParentContent)
248 : {
249 : #ifdef DEBUG_UNDISPLAYED_MAP
250 : static int i = 0;
251 : printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
252 : #endif
253 :
254 16 : if (!mUndisplayedMap) {
255 0 : return;
256 : }
257 :
258 68 : for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
259 120 : node; node = node->getNext()) {
260 58 : if (node->mContent == aContent) {
261 6 : mUndisplayedMap->RemoveNodeFor(aParentContent, node);
262 :
263 : #ifdef DEBUG_UNDISPLAYED_MAP
264 : printf( "REMOVED!\n");
265 : #endif
266 : // make sure that there are no more entries for the same content
267 6 : MOZ_ASSERT(!GetUndisplayedContent(aContent),
268 : "Found more undisplayed content data after removal");
269 6 : return;
270 : }
271 : }
272 :
273 : #ifdef DEBUG_UNDISPLAYED_MAP
274 : printf( "not found.\n");
275 : #endif
276 : }
277 :
278 : void
279 111 : nsFrameManager::ClearAllMapsFor(nsIContent* aParentContent)
280 : {
281 : #if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_CONTENTS_MAP)
282 : static int i = 0;
283 : printf("ClearAllMapsFor(%d): parent=%p \n", i++, aParentContent);
284 : #endif
285 :
286 111 : if (mUndisplayedMap) {
287 111 : mUndisplayedMap->RemoveNodesFor(aParentContent);
288 : }
289 111 : if (mDisplayContentsMap) {
290 : nsAutoPtr<LinkedList<UndisplayedNode>> list =
291 0 : mDisplayContentsMap->UnlinkNodesFor(aParentContent);
292 0 : if (list) {
293 0 : while (UndisplayedNode* node = list->popFirst()) {
294 0 : ClearAllMapsFor(node->mContent);
295 0 : delete node;
296 0 : }
297 : }
298 : }
299 :
300 : // Need to look at aParentContent's content list due to XBL insertions.
301 : // Nodes in aParentContent's content list do not have aParentContent as a
302 : // parent, but are treated as children of aParentContent. We iterate over
303 : // the flattened content list and just ignore any nodes we don't care about.
304 222 : FlattenedChildIterator iter(aParentContent);
305 279 : for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
306 168 : auto parent = child->GetParent();
307 168 : if (parent != aParentContent) {
308 7 : ClearUndisplayedContentIn(child, parent);
309 7 : ClearDisplayContentsIn(child, parent);
310 : }
311 : }
312 111 : }
313 :
314 : //----------------------------------------------------------------------
315 :
316 : void
317 0 : nsFrameManager::SetDisplayContents(nsIContent* aContent,
318 : nsStyleContext* aStyleContext)
319 : {
320 0 : if (!mDisplayContentsMap) {
321 0 : mDisplayContentsMap = new UndisplayedMap;
322 : }
323 0 : SetStyleContextInMap(mDisplayContentsMap, aContent, aStyleContext);
324 0 : }
325 :
326 : UndisplayedNode*
327 1055 : nsFrameManager::GetAllDisplayContentsIn(nsIContent* aParentContent)
328 : {
329 1055 : return GetAllUndisplayedNodesInMapFor(mDisplayContentsMap, aParentContent);
330 : }
331 :
332 : void
333 7 : nsFrameManager::ClearDisplayContentsIn(nsIContent* aContent,
334 : nsIContent* aParentContent)
335 : {
336 : #ifdef DEBUG_DISPLAY_CONTENTS_MAP
337 : static int i = 0;
338 : printf("ClearDisplayContents(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
339 : #endif
340 :
341 7 : if (!mDisplayContentsMap) {
342 7 : return;
343 : }
344 :
345 0 : for (UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent);
346 0 : node; node = node->getNext()) {
347 0 : if (node->mContent == aContent) {
348 0 : mDisplayContentsMap->RemoveNodeFor(aParentContent, node);
349 :
350 : #ifdef DEBUG_DISPLAY_CONTENTS_MAP
351 : printf( "REMOVED!\n");
352 : #endif
353 : // make sure that there are no more entries for the same content
354 0 : MOZ_ASSERT(!GetDisplayContentsStyleFor(aContent),
355 : "Found more entries for aContent after removal");
356 0 : ClearAllMapsFor(aContent);
357 0 : return;
358 : }
359 : }
360 : #ifdef DEBUG_DISPLAY_CONTENTS_MAP
361 : printf( "not found.\n");
362 : #endif
363 : }
364 :
365 : //----------------------------------------------------------------------
366 : void
367 8 : nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
368 : ChildListID aListID,
369 : nsFrameList& aFrameList)
370 : {
371 10 : if (aParentFrame->IsAbsoluteContainer() &&
372 2 : aListID == aParentFrame->GetAbsoluteListID()) {
373 : aParentFrame->GetAbsoluteContainingBlock()->
374 2 : AppendFrames(aParentFrame, aListID, aFrameList);
375 : } else {
376 6 : aParentFrame->AppendFrames(aListID, aFrameList);
377 : }
378 8 : }
379 :
380 : void
381 43 : nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
382 : ChildListID aListID,
383 : nsIFrame* aPrevFrame,
384 : nsFrameList& aFrameList)
385 : {
386 43 : NS_PRECONDITION(!aPrevFrame || (!aPrevFrame->GetNextContinuation()
387 : || (((aPrevFrame->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))
388 : && !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))),
389 : "aPrevFrame must be the last continuation in its chain!");
390 :
391 45 : if (aParentFrame->IsAbsoluteContainer() &&
392 2 : aListID == aParentFrame->GetAbsoluteListID()) {
393 : aParentFrame->GetAbsoluteContainingBlock()->
394 0 : InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
395 : } else {
396 43 : aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
397 : }
398 43 : }
399 :
400 : void
401 27 : nsFrameManager::RemoveFrame(ChildListID aListID,
402 : nsIFrame* aOldFrame)
403 : {
404 27 : bool wasDestroyingFrames = mIsDestroyingFrames;
405 27 : mIsDestroyingFrames = true;
406 :
407 : // In case the reflow doesn't invalidate anything since it just leaves
408 : // a gap where the old frame was, we invalidate it here. (This is
409 : // reasonably likely to happen when removing a last child in a way
410 : // that doesn't change the size of the parent.)
411 : // This has to sure to invalidate the entire overflow rect; this
412 : // is important in the presence of absolute positioning
413 27 : aOldFrame->InvalidateFrameForRemoval();
414 :
415 27 : NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
416 : // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
417 : aOldFrame->IsTextFrame(),
418 : "Must remove first continuation.");
419 27 : NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
420 : aOldFrame->GetPlaceholderFrame()),
421 : "Must call RemoveFrame on placeholder for out-of-flows.");
422 27 : nsContainerFrame* parentFrame = aOldFrame->GetParent();
423 31 : if (parentFrame->IsAbsoluteContainer() &&
424 4 : aListID == parentFrame->GetAbsoluteListID()) {
425 : parentFrame->GetAbsoluteContainingBlock()->
426 2 : RemoveFrame(parentFrame, aListID, aOldFrame);
427 : } else {
428 25 : parentFrame->RemoveFrame(aListID, aOldFrame);
429 : }
430 :
431 27 : mIsDestroyingFrames = wasDestroyingFrames;
432 27 : }
433 :
434 : //----------------------------------------------------------------------
435 :
436 : void
437 126 : nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
438 : {
439 126 : nsIContent* content = aFrame->GetContent();
440 126 : if (content && content->GetPrimaryFrame() == aFrame) {
441 111 : ClearAllMapsFor(content);
442 : }
443 126 : }
444 :
445 : // Capture state for a given frame.
446 : // Accept a content id here, in some cases we may not have content (scroll position)
447 : void
448 135 : nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
449 : nsILayoutHistoryState* aState)
450 : {
451 135 : if (!aFrame || !aState) {
452 0 : NS_WARNING("null frame, or state");
453 0 : return;
454 : }
455 :
456 : // Only capture state for stateful frames
457 135 : nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
458 135 : if (!statefulFrame) {
459 124 : return;
460 : }
461 :
462 : // Capture the state, exit early if we get null (nothing to save)
463 11 : nsAutoPtr<nsPresState> frameState;
464 11 : nsresult rv = statefulFrame->SaveState(getter_Transfers(frameState));
465 11 : if (!frameState) {
466 11 : return;
467 : }
468 :
469 : // Generate the hash key to store the state under
470 : // Exit early if we get empty key
471 0 : nsAutoCString stateKey;
472 0 : nsIContent* content = aFrame->GetContent();
473 0 : nsIDocument* doc = content ? content->GetUncomposedDoc() : nullptr;
474 0 : rv = statefulFrame->GenerateStateKey(content, doc, stateKey);
475 0 : if(NS_FAILED(rv) || stateKey.IsEmpty()) {
476 0 : return;
477 : }
478 :
479 : // Store the state. aState owns frameState now.
480 0 : aState->AddState(stateKey, frameState.forget());
481 : }
482 :
483 : void
484 135 : nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
485 : nsILayoutHistoryState* aState)
486 : {
487 135 : NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
488 :
489 135 : CaptureFrameStateFor(aFrame, aState);
490 :
491 : // Now capture state recursively for the frame hierarchy rooted at aFrame
492 270 : nsIFrame::ChildListIterator lists(aFrame);
493 279 : for (; !lists.IsDone(); lists.Next()) {
494 72 : nsFrameList::Enumerator childFrames(lists.CurrentList());
495 308 : for (; !childFrames.AtEnd(); childFrames.Next()) {
496 118 : nsIFrame* child = childFrames.get();
497 118 : if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
498 : // We'll pick it up when we get to its placeholder
499 0 : continue;
500 : }
501 : // Make sure to walk through placeholders as needed, so that we
502 : // save state for out-of-flows which may not be our descendants
503 : // themselves but whose placeholders are our descendants.
504 118 : CaptureFrameState(nsPlaceholderFrame::GetRealFrameFor(child), aState);
505 : }
506 : }
507 135 : }
508 :
509 : // Restore state for a given frame.
510 : // Accept a content id here, in some cases we may not have content (scroll position)
511 : void
512 120 : nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
513 : nsILayoutHistoryState* aState)
514 : {
515 120 : if (!aFrame || !aState) {
516 0 : NS_WARNING("null frame or state");
517 0 : return;
518 : }
519 :
520 : // Only restore state for stateful frames
521 120 : nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
522 120 : if (!statefulFrame) {
523 110 : return;
524 : }
525 :
526 : // Generate the hash key the state was stored under
527 : // Exit early if we get empty key
528 10 : nsIContent* content = aFrame->GetContent();
529 : // If we don't have content, we can't generate a hash
530 : // key and there's probably no state information for us.
531 10 : if (!content) {
532 0 : return;
533 : }
534 :
535 10 : nsAutoCString stateKey;
536 10 : nsIDocument* doc = content->GetUncomposedDoc();
537 10 : nsresult rv = statefulFrame->GenerateStateKey(content, doc, stateKey);
538 10 : if (NS_FAILED(rv) || stateKey.IsEmpty()) {
539 6 : return;
540 : }
541 :
542 : // Get the state from the hash
543 4 : nsPresState* frameState = aState->GetState(stateKey);
544 4 : if (!frameState) {
545 4 : return;
546 : }
547 :
548 : // Restore it
549 0 : rv = statefulFrame->RestoreState(frameState);
550 0 : if (NS_FAILED(rv)) {
551 0 : return;
552 : }
553 :
554 : // If we restore ok, remove the state from the state table
555 0 : aState->RemoveState(stateKey);
556 : }
557 :
558 : void
559 0 : nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
560 : nsILayoutHistoryState* aState)
561 : {
562 0 : NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
563 :
564 0 : RestoreFrameStateFor(aFrame, aState);
565 :
566 : // Now restore state recursively for the frame hierarchy rooted at aFrame
567 0 : nsIFrame::ChildListIterator lists(aFrame);
568 0 : for (; !lists.IsDone(); lists.Next()) {
569 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
570 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
571 0 : RestoreFrameState(childFrames.get(), aState);
572 : }
573 : }
574 0 : }
575 :
576 : //----------------------------------------------------------------------
577 :
578 24 : nsFrameManagerBase::UndisplayedMap::UndisplayedMap()
579 : {
580 24 : MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
581 24 : }
582 :
583 0 : nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
584 : {
585 0 : MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap);
586 0 : Clear();
587 0 : }
588 :
589 : void
590 0 : nsFrameManagerBase::UndisplayedMap::Clear()
591 : {
592 0 : for (auto iter = Iter(); !iter.Done(); iter.Next()) {
593 0 : auto* list = iter.UserData();
594 0 : while (auto* node = list->popFirst()) {
595 0 : delete node;
596 0 : }
597 0 : iter.Remove();
598 : }
599 0 : }
600 :
601 :
602 : nsIContent*
603 1845 : nsFrameManagerBase::UndisplayedMap::GetApplicableParent(nsIContent* aParent)
604 : {
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 1845 : if (aParent && nsContentUtils::IsContentInsertionPoint(aParent)) {
612 0 : return aParent->GetParent();
613 : }
614 :
615 1845 : return aParent;
616 : }
617 :
618 : LinkedList<UndisplayedNode>*
619 1440 : nsFrameManagerBase::UndisplayedMap::GetListFor(nsIContent* aParent)
620 : {
621 1440 : aParent = GetApplicableParent(aParent);
622 :
623 : LinkedList<UndisplayedNode>* list;
624 1440 : if (Get(aParent, &list)) {
625 400 : return list;
626 : }
627 :
628 1040 : return nullptr;
629 : }
630 :
631 : LinkedList<UndisplayedNode>*
632 294 : nsFrameManagerBase::UndisplayedMap::GetOrCreateListFor(nsIContent* aParent)
633 : {
634 294 : aParent = GetApplicableParent(aParent);
635 294 : return LookupOrAdd(aParent);
636 : }
637 :
638 :
639 : UndisplayedNode*
640 1434 : nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
641 : {
642 1434 : auto* list = GetListFor(aParentContent);
643 1434 : return list ? list->getFirst() : nullptr;
644 : }
645 :
646 :
647 : void
648 294 : nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
649 : nsIContent* aParentContent)
650 : {
651 294 : LinkedList<UndisplayedNode>* list = GetOrCreateListFor(aParentContent);
652 :
653 : #ifdef DEBUG
654 2158 : for (UndisplayedNode* node = list->getFirst(); node; node = node->getNext()) {
655 : // NOTE: In the original code there was a work around for this case, I want
656 : // to check it still happens before hacking around it the same way.
657 1864 : MOZ_ASSERT(node->mContent != aNode->mContent,
658 : "Duplicated content in undisplayed list!");
659 : }
660 : #endif
661 :
662 294 : list->insertBack(aNode);
663 294 : }
664 :
665 : void
666 294 : nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
667 : nsIContent* aChild,
668 : nsStyleContext* aStyle)
669 : {
670 294 : UndisplayedNode* node = new UndisplayedNode(aChild, aStyle);
671 294 : AppendNodeFor(node, aParentContent);
672 294 : }
673 :
674 : void
675 6 : nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
676 : UndisplayedNode* aNode)
677 : {
678 : #ifdef DEBUG
679 6 : auto list = GetListFor(aParentContent);
680 6 : MOZ_ASSERT(list, "content not in map");
681 6 : aNode->removeFrom(*list);
682 : #else
683 : aNode->remove();
684 : #endif
685 6 : delete aNode;
686 6 : }
687 :
688 :
689 : nsAutoPtr<LinkedList<UndisplayedNode>>
690 111 : nsFrameManagerBase::UndisplayedMap::UnlinkNodesFor(nsIContent* aParentContent)
691 : {
692 111 : nsAutoPtr<LinkedList<UndisplayedNode>> list;
693 111 : Remove(GetApplicableParent(aParentContent), &list);
694 111 : return list;
695 : }
696 :
697 : void
698 111 : nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
699 : {
700 222 : nsAutoPtr<LinkedList<UndisplayedNode>> list = UnlinkNodesFor(aParentContent);
701 111 : if (list) {
702 92 : while (auto* node = list->popFirst()) {
703 67 : delete node;
704 67 : }
705 : }
706 111 : }
|