LCOV - code coverage report
Current view: top level - layout/base - nsFrameManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 189 252 75.0 %
Date: 2017-07-14 16:53:18 Functions: 32 36 88.9 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13