LCOV - code coverage report
Current view: directory - layout/base - nsFrameManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 730 0 0.0 %
Date: 2012-06-02 Functions: 48 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  * vim:cindent:ts=2:et:sw=2:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is mozilla.org code.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Mats Palmgren <matspal@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK *****
      40                 :  *
      41                 :  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
      42                 :  * described herein are Copyright (c) International Business Machines Corporation, 2000.
      43                 :  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
      44                 :  *
      45                 :  * Date             Modified by     Description of modification
      46                 :  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
      47                 :  */
      48                 : 
      49                 : /* storage of the frame tree and information about it */
      50                 : 
      51                 : #include "nscore.h"
      52                 : #include "nsPresContext.h"
      53                 : #include "nsIPresShell.h"
      54                 : #include "nsStyleSet.h"
      55                 : #include "nsCSSFrameConstructor.h"
      56                 : #include "nsStyleContext.h"
      57                 : #include "nsStyleChangeList.h"
      58                 : #include "nsIServiceManager.h"
      59                 : #include "nsCOMPtr.h"
      60                 : #include "prthread.h"
      61                 : #include "plhash.h"
      62                 : #include "nsPlaceholderFrame.h"
      63                 : #include "nsContainerFrame.h"
      64                 : #include "nsBlockFrame.h"
      65                 : #include "nsGkAtoms.h"
      66                 : #include "nsCSSAnonBoxes.h"
      67                 : #include "nsCSSPseudoElements.h"
      68                 : #ifdef NS_DEBUG
      69                 : #include "nsIStyleRule.h"
      70                 : #endif
      71                 : #include "nsILayoutHistoryState.h"
      72                 : #include "nsPresState.h"
      73                 : #include "nsIContent.h"
      74                 : #include "nsINameSpaceManager.h"
      75                 : #include "nsIDocument.h"
      76                 : #include "nsIScrollableFrame.h"
      77                 : 
      78                 : #include "nsIHTMLDocument.h"
      79                 : #include "nsIDOMHTMLDocument.h"
      80                 : #include "nsIDOMNodeList.h"
      81                 : #include "nsIDOMHTMLCollection.h"
      82                 : #include "nsIFormControl.h"
      83                 : #include "nsIDOMElement.h"
      84                 : #include "nsIDOMHTMLFormElement.h"
      85                 : #include "nsIForm.h"
      86                 : #include "nsContentUtils.h"
      87                 : #include "nsReadableUtils.h"
      88                 : #include "nsUnicharUtils.h"
      89                 : #include "nsLayoutErrors.h"
      90                 : #include "nsLayoutUtils.h"
      91                 : #include "nsAutoPtr.h"
      92                 : #include "imgIRequest.h"
      93                 : #include "nsTransitionManager.h"
      94                 : #include "RestyleTracker.h"
      95                 : #include "nsAbsoluteContainingBlock.h"
      96                 : 
      97                 : #include "nsFrameManager.h"
      98                 : #include "nsRuleProcessorData.h"
      99                 : 
     100                 : #ifdef ACCESSIBILITY
     101                 : #include "nsAccessibilityService.h"
     102                 : #endif
     103                 : 
     104                 :   #ifdef DEBUG
     105                 :     //#define NOISY_DEBUG
     106                 :     //#define DEBUG_UNDISPLAYED_MAP
     107                 :   #else
     108                 :     #undef NOISY_DEBUG
     109                 :     #undef DEBUG_UNDISPLAYED_MAP
     110                 :   #endif
     111                 : 
     112                 :   #ifdef NOISY_DEBUG
     113                 :     #define NOISY_TRACE(_msg) \
     114                 :       printf("%s",_msg);
     115                 :     #define NOISY_TRACE_FRAME(_msg,_frame) \
     116                 :       printf("%s ",_msg); nsFrame::ListTag(stdout,_frame); printf("\n");
     117                 :   #else
     118                 :     #define NOISY_TRACE(_msg);
     119                 :     #define NOISY_TRACE_FRAME(_msg,_frame);
     120                 :   #endif
     121                 : 
     122                 : using namespace mozilla;
     123                 : using namespace mozilla::dom;
     124                 : 
     125                 : //----------------------------------------------------------------------
     126                 : 
     127                 : struct PlaceholderMapEntry : public PLDHashEntryHdr {
     128                 :   // key (the out of flow frame) can be obtained through placeholder frame
     129                 :   nsPlaceholderFrame *placeholderFrame;
     130                 : };
     131                 : 
     132                 : static bool
     133               0 : PlaceholderMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
     134                 :                          const void *key)
     135                 : {
     136                 :   const PlaceholderMapEntry *entry =
     137               0 :     static_cast<const PlaceholderMapEntry*>(hdr);
     138               0 :   NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() !=
     139                 :                (void*)0xdddddddd,
     140                 :                "Dead placeholder in placeholder map");
     141               0 :   return entry->placeholderFrame->GetOutOfFlowFrame() == key;
     142                 : }
     143                 : 
     144                 : static PLDHashTableOps PlaceholderMapOps = {
     145                 :   PL_DHashAllocTable,
     146                 :   PL_DHashFreeTable,
     147                 :   PL_DHashVoidPtrKeyStub,
     148                 :   PlaceholderMapMatchEntry,
     149                 :   PL_DHashMoveEntryStub,
     150                 :   PL_DHashClearEntryStub,
     151                 :   PL_DHashFinalizeStub,
     152                 :   NULL
     153                 : };
     154                 : 
     155                 : //----------------------------------------------------------------------
     156                 : 
     157                 : // XXXldb This seems too complicated for what I think it's doing, and it
     158                 : // should also be using pldhash rather than plhash to use less memory.
     159                 : 
     160                 : class UndisplayedNode {
     161                 : public:
     162               0 :   UndisplayedNode(nsIContent* aContent, nsStyleContext* aStyle)
     163                 :     : mContent(aContent),
     164                 :       mStyle(aStyle),
     165               0 :       mNext(nsnull)
     166                 :   {
     167               0 :     MOZ_COUNT_CTOR(UndisplayedNode);
     168               0 :   }
     169                 : 
     170               0 :   NS_HIDDEN ~UndisplayedNode()
     171               0 :   {
     172               0 :     MOZ_COUNT_DTOR(UndisplayedNode);
     173                 : 
     174                 :     // Delete mNext iteratively to avoid blowing up the stack (bug 460461).
     175               0 :     UndisplayedNode *cur = mNext;
     176               0 :     while (cur) {
     177               0 :       UndisplayedNode *next = cur->mNext;
     178               0 :       cur->mNext = nsnull;
     179               0 :       delete cur;
     180               0 :       cur = next;
     181                 :     }
     182               0 :   }
     183                 : 
     184                 :   nsCOMPtr<nsIContent>      mContent;
     185                 :   nsRefPtr<nsStyleContext>  mStyle;
     186                 :   UndisplayedNode*          mNext;
     187                 : };
     188                 : 
     189                 : class nsFrameManagerBase::UndisplayedMap {
     190                 : public:
     191                 :   UndisplayedMap(PRUint32 aNumBuckets = 16) NS_HIDDEN;
     192                 :   ~UndisplayedMap(void) NS_HIDDEN;
     193                 : 
     194                 :   NS_HIDDEN_(UndisplayedNode*) GetFirstNode(nsIContent* aParentContent);
     195                 : 
     196                 :   NS_HIDDEN_(nsresult) AddNodeFor(nsIContent* aParentContent,
     197                 :                                   nsIContent* aChild, nsStyleContext* aStyle);
     198                 : 
     199                 :   NS_HIDDEN_(void) RemoveNodeFor(nsIContent* aParentContent,
     200                 :                                  UndisplayedNode* aNode);
     201                 : 
     202                 :   NS_HIDDEN_(void) RemoveNodesFor(nsIContent* aParentContent);
     203                 : 
     204                 :   // Removes all entries from the hash table
     205                 :   NS_HIDDEN_(void)  Clear(void);
     206                 : 
     207                 : protected:
     208                 :   NS_HIDDEN_(PLHashEntry**) GetEntryFor(nsIContent* aParentContent);
     209                 :   NS_HIDDEN_(void)          AppendNodeFor(UndisplayedNode* aNode,
     210                 :                                           nsIContent* aParentContent);
     211                 : 
     212                 :   PLHashTable*  mTable;
     213                 :   PLHashEntry** mLastLookup;
     214                 : };
     215                 : 
     216                 : //----------------------------------------------------------------------
     217                 : 
     218               0 : nsFrameManager::~nsFrameManager()
     219                 : {
     220               0 :   NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
     221               0 : }
     222                 : 
     223                 : nsresult
     224               0 : nsFrameManager::Init(nsStyleSet* aStyleSet)
     225                 : {
     226               0 :   if (!mPresShell) {
     227               0 :     NS_ERROR("null pres shell");
     228               0 :     return NS_ERROR_FAILURE;
     229                 :   }
     230                 : 
     231               0 :   if (!aStyleSet) {
     232               0 :     NS_ERROR("null style set");
     233               0 :     return NS_ERROR_FAILURE;
     234                 :   }
     235                 : 
     236               0 :   mStyleSet = aStyleSet;
     237               0 :   return NS_OK;
     238                 : }
     239                 : 
     240                 : void
     241               0 : nsFrameManager::Destroy()
     242                 : {
     243               0 :   NS_ASSERTION(mPresShell, "Frame manager already shut down.");
     244                 : 
     245                 :   // Destroy the frame hierarchy.
     246               0 :   mPresShell->SetIgnoreFrameDestruction(true);
     247                 : 
     248                 :   // Unregister all placeholders before tearing down the frame tree
     249               0 :   nsFrameManager::ClearPlaceholderFrameMap();
     250                 : 
     251               0 :   if (mRootFrame) {
     252               0 :     mRootFrame->Destroy();
     253               0 :     mRootFrame = nsnull;
     254                 :   }
     255                 :   
     256               0 :   delete mUndisplayedMap;
     257               0 :   mUndisplayedMap = nsnull;
     258                 : 
     259               0 :   mPresShell = nsnull;
     260               0 : }
     261                 : 
     262                 : //----------------------------------------------------------------------
     263                 : 
     264                 : // Placeholder frame functions
     265                 : nsPlaceholderFrame*
     266               0 : nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame)
     267                 : {
     268               0 :   NS_PRECONDITION(aFrame, "null param unexpected");
     269                 : 
     270               0 :   if (mPlaceholderMap.ops) {
     271                 :     PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>
     272                 :                                             (PL_DHashTableOperate(const_cast<PLDHashTable*>(&mPlaceholderMap),
     273               0 :                                 aFrame, PL_DHASH_LOOKUP));
     274               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     275               0 :       return entry->placeholderFrame;
     276                 :     }
     277                 :   }
     278                 : 
     279               0 :   return nsnull;
     280                 : }
     281                 : 
     282                 : nsresult
     283               0 : nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
     284                 : {
     285               0 :   NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
     286               0 :   NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
     287                 :                   "unexpected frame type");
     288               0 :   if (!mPlaceholderMap.ops) {
     289               0 :     if (!PL_DHashTableInit(&mPlaceholderMap, &PlaceholderMapOps, nsnull,
     290               0 :                            sizeof(PlaceholderMapEntry), 16)) {
     291               0 :       mPlaceholderMap.ops = nsnull;
     292               0 :       return NS_ERROR_OUT_OF_MEMORY;
     293                 :     }
     294                 :   }
     295                 :   PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>(PL_DHashTableOperate(&mPlaceholderMap,
     296               0 :                               aPlaceholderFrame->GetOutOfFlowFrame(),
     297               0 :                               PL_DHASH_ADD));
     298               0 :   if (!entry)
     299               0 :     return NS_ERROR_OUT_OF_MEMORY;
     300                 : 
     301               0 :   NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
     302               0 :   entry->placeholderFrame = aPlaceholderFrame;
     303                 : 
     304               0 :   return NS_OK;
     305                 : }
     306                 : 
     307                 : void
     308               0 : nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
     309                 : {
     310               0 :   NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
     311               0 :   NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
     312                 :                   "unexpected frame type");
     313                 : 
     314               0 :   if (mPlaceholderMap.ops) {
     315                 :     PL_DHashTableOperate(&mPlaceholderMap,
     316               0 :                          aPlaceholderFrame->GetOutOfFlowFrame(),
     317               0 :                          PL_DHASH_REMOVE);
     318                 :   }
     319               0 : }
     320                 : 
     321                 : static PLDHashOperator
     322               0 : UnregisterPlaceholders(PLDHashTable* table, PLDHashEntryHdr* hdr,
     323                 :                        PRUint32 number, void* arg)
     324                 : {
     325               0 :   PlaceholderMapEntry* entry = static_cast<PlaceholderMapEntry*>(hdr);
     326               0 :   entry->placeholderFrame->SetOutOfFlowFrame(nsnull);
     327               0 :   return PL_DHASH_NEXT;
     328                 : }
     329                 : 
     330                 : void
     331               0 : nsFrameManager::ClearPlaceholderFrameMap()
     332                 : {
     333               0 :   if (mPlaceholderMap.ops) {
     334               0 :     PL_DHashTableEnumerate(&mPlaceholderMap, UnregisterPlaceholders, nsnull);
     335               0 :     PL_DHashTableFinish(&mPlaceholderMap);
     336               0 :     mPlaceholderMap.ops = nsnull;
     337                 :   }
     338               0 : }
     339                 : 
     340                 : //----------------------------------------------------------------------
     341                 : 
     342                 : nsStyleContext*
     343               0 : nsFrameManager::GetUndisplayedContent(nsIContent* aContent)
     344                 : {
     345               0 :   if (!aContent || !mUndisplayedMap)
     346               0 :     return nsnull;
     347                 : 
     348               0 :   nsIContent* parent = aContent->GetParent();
     349               0 :   for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(parent);
     350                 :          node; node = node->mNext) {
     351               0 :     if (node->mContent == aContent)
     352               0 :       return node->mStyle;
     353                 :   }
     354                 : 
     355               0 :   return nsnull;
     356                 : }
     357                 :   
     358                 : void
     359               0 : nsFrameManager::SetUndisplayedContent(nsIContent* aContent, 
     360                 :                                       nsStyleContext* aStyleContext)
     361                 : {
     362               0 :   NS_PRECONDITION(!aStyleContext->GetPseudo(),
     363                 :                   "Should only have actual elements here");
     364                 : 
     365                 : #ifdef DEBUG_UNDISPLAYED_MAP
     366                 :   static int i = 0;
     367                 :   printf("SetUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
     368                 : #endif
     369                 : 
     370               0 :   NS_ASSERTION(!GetUndisplayedContent(aContent),
     371                 :                "Already have an undisplayed context entry for aContent");
     372                 : 
     373               0 :   if (! mUndisplayedMap) {
     374               0 :     mUndisplayedMap = new UndisplayedMap;
     375                 :   }
     376               0 :   nsIContent* parent = aContent->GetParent();
     377               0 :   NS_ASSERTION(parent || (mPresShell && mPresShell->GetDocument() &&
     378                 :                mPresShell->GetDocument()->GetRootElement() == aContent),
     379                 :                "undisplayed content must have a parent, unless it's the root "
     380                 :                "element");
     381               0 :   mUndisplayedMap->AddNodeFor(parent, aContent, aStyleContext);
     382               0 : }
     383                 : 
     384                 : void
     385               0 : nsFrameManager::ChangeUndisplayedContent(nsIContent* aContent, 
     386                 :                                          nsStyleContext* aStyleContext)
     387                 : {
     388               0 :   NS_ASSERTION(mUndisplayedMap, "no existing undisplayed content");
     389                 :   
     390                 : #ifdef DEBUG_UNDISPLAYED_MAP
     391                 :    static int i = 0;
     392                 :    printf("ChangeUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
     393                 : #endif
     394                 : 
     395               0 :   for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aContent->GetParent());
     396                 :          node; node = node->mNext) {
     397               0 :     if (node->mContent == aContent) {
     398               0 :       node->mStyle = aStyleContext;
     399               0 :       return;
     400                 :     }
     401                 :   }
     402                 : 
     403               0 :   NS_NOTREACHED("no existing undisplayed content");
     404                 : }
     405                 : 
     406                 : void
     407               0 : nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
     408                 :                                           nsIContent* aParentContent)
     409                 : {
     410                 : #ifdef DEBUG_UNDISPLAYED_MAP
     411                 :   static int i = 0;
     412                 :   printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
     413                 : #endif
     414                 :   
     415               0 :   if (mUndisplayedMap) {
     416               0 :     UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
     417               0 :     while (node) {
     418               0 :       if (node->mContent == aContent) {
     419               0 :         mUndisplayedMap->RemoveNodeFor(aParentContent, node);
     420                 : 
     421                 : #ifdef DEBUG_UNDISPLAYED_MAP
     422                 :         printf( "REMOVED!\n");
     423                 : #endif
     424                 : #ifdef DEBUG
     425                 :         // make sure that there are no more entries for the same content
     426               0 :         nsStyleContext *context = GetUndisplayedContent(aContent);
     427               0 :         NS_ASSERTION(context == nsnull, "Found more undisplayed content data after removal");
     428                 : #endif
     429               0 :         return;
     430                 :       }
     431               0 :       node = node->mNext;
     432                 :     }
     433                 :   }
     434                 : }
     435                 : 
     436                 : void
     437               0 : nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent)
     438                 : {
     439                 : #ifdef DEBUG_UNDISPLAYED_MAP
     440                 :   static int i = 0;
     441                 :   printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i++, (void*)aParentContent);
     442                 : #endif
     443                 : 
     444               0 :   if (mUndisplayedMap) {
     445               0 :     mUndisplayedMap->RemoveNodesFor(aParentContent);
     446                 :   }
     447                 : 
     448                 :   // Need to look at aParentContent's content list due to XBL insertions.
     449                 :   // Nodes in aParentContent's content list do not have aParentContent as a
     450                 :   // parent, but are treated as children of aParentContent. We get access to
     451                 :   // the content list via GetXBLChildNodesFor and just ignore any nodes we
     452                 :   // don't care about.
     453                 :   nsINodeList* list =
     454               0 :     aParentContent->OwnerDoc()->BindingManager()->GetXBLChildNodesFor(aParentContent);
     455               0 :   if (list) {
     456                 :     PRUint32 length;
     457               0 :     list->GetLength(&length);
     458               0 :     for (PRUint32 i = 0; i < length; ++i) {
     459               0 :       nsIContent* child = list->GetNodeAt(i);
     460               0 :       if (child->GetParent() != aParentContent) {
     461               0 :         ClearUndisplayedContentIn(child, child->GetParent());
     462                 :       }
     463                 :     }
     464                 :   }
     465               0 : }
     466                 : 
     467                 : //----------------------------------------------------------------------
     468                 : nsresult
     469               0 : nsFrameManager::AppendFrames(nsIFrame*       aParentFrame,
     470                 :                              ChildListID     aListID,
     471                 :                              nsFrameList&    aFrameList)
     472                 : {
     473               0 :   if (aParentFrame->IsAbsoluteContainer() &&
     474               0 :       aListID == aParentFrame->GetAbsoluteListID()) {
     475                 :     return aParentFrame->GetAbsoluteContainingBlock()->
     476               0 :            AppendFrames(aParentFrame, aListID, aFrameList);
     477                 :   } else {
     478               0 :     return aParentFrame->AppendFrames(aListID, aFrameList);
     479                 :   }
     480                 : }
     481                 : 
     482                 : nsresult
     483               0 : nsFrameManager::InsertFrames(nsIFrame*       aParentFrame,
     484                 :                              ChildListID     aListID,
     485                 :                              nsIFrame*       aPrevFrame,
     486                 :                              nsFrameList&    aFrameList)
     487                 : {
     488               0 :   NS_PRECONDITION(!aPrevFrame || (!aPrevFrame->GetNextContinuation()
     489                 :                   || (aPrevFrame->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))
     490                 :                   && !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
     491                 :                   "aPrevFrame must be the last continuation in its chain!");
     492                 : 
     493               0 :   if (aParentFrame->IsAbsoluteContainer() &&
     494               0 :       aListID == aParentFrame->GetAbsoluteListID()) {
     495                 :     return aParentFrame->GetAbsoluteContainingBlock()->
     496               0 :            InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
     497                 :   } else {
     498               0 :     return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
     499                 :   }
     500                 : }
     501                 : 
     502                 : nsresult
     503               0 : nsFrameManager::RemoveFrame(ChildListID     aListID,
     504                 :                             nsIFrame*       aOldFrame)
     505                 : {
     506               0 :   bool wasDestroyingFrames = mIsDestroyingFrames;
     507               0 :   mIsDestroyingFrames = true;
     508                 : 
     509                 :   // In case the reflow doesn't invalidate anything since it just leaves
     510                 :   // a gap where the old frame was, we invalidate it here.  (This is
     511                 :   // reasonably likely to happen when removing a last child in a way
     512                 :   // that doesn't change the size of the parent.)
     513                 :   // This has to sure to invalidate the entire overflow rect; this
     514                 :   // is important in the presence of absolute positioning
     515               0 :   aOldFrame->InvalidateFrameSubtree();
     516                 : 
     517               0 :   NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
     518                 :                // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
     519                 :                aOldFrame->GetType() == nsGkAtoms::textFrame,
     520                 :                "Must remove first continuation.");
     521               0 :   NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
     522                 :                  GetPlaceholderFrameFor(aOldFrame)),
     523                 :                "Must call RemoveFrame on placeholder for out-of-flows.");
     524               0 :   nsresult rv = NS_OK;
     525               0 :   nsIFrame* parentFrame = aOldFrame->GetParent();
     526               0 :   if (parentFrame->IsAbsoluteContainer() &&
     527               0 :       aListID == parentFrame->GetAbsoluteListID()) {
     528                 :     parentFrame->GetAbsoluteContainingBlock()->
     529               0 :       RemoveFrame(parentFrame, aListID, aOldFrame);
     530                 :   } else {
     531               0 :     rv = parentFrame->RemoveFrame(aListID, aOldFrame);
     532                 :   }
     533                 : 
     534               0 :   mIsDestroyingFrames = wasDestroyingFrames;
     535                 : 
     536               0 :   return rv;
     537                 : }
     538                 : 
     539                 : //----------------------------------------------------------------------
     540                 : 
     541                 : void
     542               0 : nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
     543                 : {
     544               0 :   nsIContent* content = aFrame->GetContent();
     545               0 :   if (content && content->GetPrimaryFrame() == aFrame) {
     546               0 :     ClearAllUndisplayedContentIn(content);
     547                 :   }
     548               0 : }
     549                 : 
     550                 : #ifdef NS_DEBUG
     551                 : static void
     552               0 : DumpContext(nsIFrame* aFrame, nsStyleContext* aContext)
     553                 : {
     554               0 :   if (aFrame) {
     555               0 :     fputs("frame: ", stdout);
     556               0 :     nsAutoString  name;
     557               0 :     aFrame->GetFrameName(name);
     558               0 :     fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
     559               0 :     fprintf(stdout, " (%p)", static_cast<void*>(aFrame));
     560                 :   }
     561               0 :   if (aContext) {
     562               0 :     fprintf(stdout, " style: %p ", static_cast<void*>(aContext));
     563                 : 
     564               0 :     nsIAtom* pseudoTag = aContext->GetPseudo();
     565               0 :     if (pseudoTag) {
     566               0 :       nsAutoString  buffer;
     567               0 :       pseudoTag->ToString(buffer);
     568               0 :       fputs(NS_LossyConvertUTF16toASCII(buffer).get(), stdout);
     569               0 :       fputs(" ", stdout);
     570                 :     }
     571               0 :     fputs("{}\n", stdout);
     572                 :   }
     573               0 : }
     574                 : 
     575                 : static void
     576               0 : VerifySameTree(nsStyleContext* aContext1, nsStyleContext* aContext2)
     577                 : {
     578               0 :   nsStyleContext* top1 = aContext1;
     579               0 :   nsStyleContext* top2 = aContext2;
     580                 :   nsStyleContext* parent;
     581               0 :   for (;;) {
     582               0 :     parent = top1->GetParent();
     583               0 :     if (!parent)
     584               0 :       break;
     585               0 :     top1 = parent;
     586                 :   }
     587               0 :   for (;;) {
     588               0 :     parent = top2->GetParent();
     589               0 :     if (!parent)
     590                 :       break;
     591               0 :     top2 = parent;
     592                 :   }
     593               0 :   NS_ASSERTION(top1 == top2,
     594                 :                "Style contexts are not in the same style context tree");
     595               0 : }
     596                 : 
     597                 : static void
     598               0 : VerifyContextParent(nsPresContext* aPresContext, nsIFrame* aFrame, 
     599                 :                     nsStyleContext* aContext, nsStyleContext* aParentContext)
     600                 : {
     601                 :   // get the contexts not provided
     602               0 :   if (!aContext) {
     603               0 :     aContext = aFrame->GetStyleContext();
     604                 :   }
     605                 : 
     606               0 :   if (!aParentContext) {
     607                 :     // Get the correct parent context from the frame
     608                 :     //  - if the frame is a placeholder, we get the out of flow frame's context 
     609                 :     //    as the parent context instead of asking the frame
     610                 : 
     611                 :     // get the parent context from the frame (indirectly)
     612               0 :     nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame();
     613               0 :     if (providerFrame)
     614               0 :       aParentContext = providerFrame->GetStyleContext();
     615                 :     // aParentContext could still be null
     616                 :   }
     617                 : 
     618               0 :   NS_ASSERTION(aContext, "Failure to get required contexts");
     619               0 :   nsStyleContext* actualParentContext = aContext->GetParent();
     620                 : 
     621               0 :   if (aParentContext) {
     622               0 :     if (aParentContext != actualParentContext) {
     623               0 :       DumpContext(aFrame, aContext);
     624               0 :       if (aContext == aParentContext) {
     625               0 :         NS_ERROR("Using parent's style context");
     626                 :       }
     627                 :       else {
     628               0 :         NS_ERROR("Wrong parent style context");
     629               0 :         fputs("Wrong parent style context: ", stdout);
     630               0 :         DumpContext(nsnull, actualParentContext);
     631               0 :         fputs("should be using: ", stdout);
     632               0 :         DumpContext(nsnull, aParentContext);
     633               0 :         VerifySameTree(actualParentContext, aParentContext);
     634               0 :         fputs("\n", stdout);
     635                 :       }
     636                 :     }
     637                 : 
     638                 :   }
     639                 :   else {
     640               0 :     if (actualParentContext) {
     641               0 :       NS_ERROR("Have parent context and shouldn't");
     642               0 :       DumpContext(aFrame, aContext);
     643               0 :       fputs("Has parent context: ", stdout);
     644               0 :       DumpContext(nsnull, actualParentContext);
     645               0 :       fputs("Should be null\n\n", stdout);
     646                 :     }
     647                 :   }
     648                 : 
     649               0 :   nsStyleContext* childStyleIfVisited = aContext->GetStyleIfVisited();
     650                 :   // Either childStyleIfVisited has aContext->GetParent()->GetStyleIfVisited()
     651                 :   // as the parent or it has a different rulenode from aContext _and_ has
     652                 :   // aContext->GetParent() as the parent.
     653               0 :   if (childStyleIfVisited &&
     654               0 :       !((childStyleIfVisited->GetRuleNode() != aContext->GetRuleNode() &&
     655               0 :          childStyleIfVisited->GetParent() == aContext->GetParent()) ||
     656               0 :         childStyleIfVisited->GetParent() ==
     657               0 :           aContext->GetParent()->GetStyleIfVisited())) {
     658               0 :     NS_ERROR("Visited style has wrong parent");
     659               0 :     DumpContext(aFrame, aContext);
     660               0 :     fputs("\n", stdout);
     661                 :   }
     662               0 : }
     663                 : 
     664                 : static void
     665               0 : VerifyStyleTree(nsPresContext* aPresContext, nsIFrame* aFrame,
     666                 :                 nsStyleContext* aParentContext)
     667                 : {
     668               0 :   nsStyleContext*  context = aFrame->GetStyleContext();
     669               0 :   VerifyContextParent(aPresContext, aFrame, context, nsnull);
     670                 : 
     671               0 :   nsIFrame::ChildListIterator lists(aFrame);
     672               0 :   for (; !lists.IsDone(); lists.Next()) {
     673               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
     674               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
     675               0 :       nsIFrame* child = childFrames.get();
     676               0 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
     677                 :         // only do frames that are in flow
     678               0 :         if (nsGkAtoms::placeholderFrame == child->GetType()) { 
     679                 :           // placeholder: first recurse and verify the out of flow frame,
     680                 :           // then verify the placeholder's context
     681                 :           nsIFrame* outOfFlowFrame =
     682               0 :             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
     683                 : 
     684                 :           // recurse to out of flow frame, letting the parent context get resolved
     685               0 :           do {
     686               0 :             VerifyStyleTree(aPresContext, outOfFlowFrame, nsnull);
     687               0 :           } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
     688                 : 
     689                 :           // verify placeholder using the parent frame's context as
     690                 :           // parent context
     691               0 :           VerifyContextParent(aPresContext, child, nsnull, nsnull);
     692                 :         }
     693                 :         else { // regular frame
     694               0 :           VerifyStyleTree(aPresContext, child, nsnull);
     695                 :         }
     696                 :       }
     697                 :     }
     698                 :   }
     699                 :   
     700                 :   // do additional contexts 
     701               0 :   PRInt32 contextIndex = -1;
     702               0 :   while (1) {
     703               0 :     nsStyleContext* extraContext = aFrame->GetAdditionalStyleContext(++contextIndex);
     704               0 :     if (extraContext) {
     705               0 :       VerifyContextParent(aPresContext, aFrame, extraContext, context);
     706                 :     }
     707                 :     else {
     708                 :       break;
     709                 :     }
     710                 :   }
     711               0 : }
     712                 : 
     713                 : void
     714               0 : nsFrameManager::DebugVerifyStyleTree(nsIFrame* aFrame)
     715                 : {
     716               0 :   if (aFrame) {
     717               0 :     nsStyleContext* context = aFrame->GetStyleContext();
     718               0 :     nsStyleContext* parentContext = context->GetParent();
     719               0 :     VerifyStyleTree(GetPresContext(), aFrame, parentContext);
     720                 :   }
     721               0 : }
     722                 : 
     723                 : #endif // DEBUG
     724                 : 
     725                 : // aContent must be the content for the frame in question, which may be
     726                 : // :before/:after content
     727                 : static void
     728               0 : TryStartingTransition(nsPresContext *aPresContext, nsIContent *aContent,
     729                 :                       nsStyleContext *aOldStyleContext,
     730                 :                       nsRefPtr<nsStyleContext> *aNewStyleContext /* inout */)
     731                 : {
     732               0 :   if (!aContent || !aContent->IsElement()) {
     733               0 :     return;
     734                 :   }
     735                 : 
     736                 :   // Notify the transition manager, and if it starts a transition,
     737                 :   // it will give us back a transition-covering style rule which
     738                 :   // we'll use to get *another* style context.  We want to ignore
     739                 :   // any already-running transitions, but cover up any that we're
     740                 :   // currently starting with their start value so we don't start
     741                 :   // them again for descendants that inherit that value.
     742                 :   nsCOMPtr<nsIStyleRule> coverRule = 
     743                 :     aPresContext->TransitionManager()->StyleContextChanged(
     744               0 :       aContent->AsElement(), aOldStyleContext, *aNewStyleContext);
     745               0 :   if (coverRule) {
     746               0 :     nsCOMArray<nsIStyleRule> rules;
     747               0 :     rules.AppendObject(coverRule);
     748                 :     *aNewStyleContext = aPresContext->StyleSet()->
     749               0 :                           ResolveStyleByAddingRules(*aNewStyleContext, rules);
     750                 :   }
     751                 : }
     752                 : 
     753                 : static inline Element*
     754               0 : ElementForStyleContext(nsIContent* aParentContent,
     755                 :                        nsIFrame* aFrame,
     756                 :                        nsCSSPseudoElements::Type aPseudoType)
     757                 : {
     758                 :   // We don't expect XUL tree stuff here.
     759               0 :   NS_PRECONDITION(aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
     760                 :                   aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox ||
     761                 :                   aPseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
     762                 :                   "Unexpected pseudo");
     763                 :   // XXX see the comments about the various element confusion in
     764                 :   // ReResolveStyleContext.
     765               0 :   if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
     766               0 :     return aFrame->GetContent()->AsElement();
     767                 :   }
     768                 : 
     769               0 :   if (aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
     770               0 :     return nsnull;
     771                 :   }
     772                 : 
     773               0 :   if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter) {
     774               0 :     NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame,
     775                 :                  "firstLetter pseudoTag without a nsFirstLetterFrame");
     776               0 :     nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame);
     777               0 :     return block->GetContent()->AsElement();
     778                 :   }
     779                 : 
     780               0 :   nsIContent* content = aParentContent ? aParentContent : aFrame->GetContent();
     781               0 :   return content->AsElement();
     782                 : }
     783                 : 
     784                 : static nsIFrame*
     785               0 : GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame)
     786                 : {
     787                 :   // Account for {ib} splits when looking for "prevContinuation".  In
     788                 :   // particular, for the first-continuation of a part of an {ib} split we
     789                 :   // want to use the special prevsibling of the special prevsibling of
     790                 :   // aFrame, which should have the same style context as aFrame itself.
     791                 :   // In particular, if aFrame is the first continuation of an inline part
     792                 :   // of an {ib} split then its special prevsibling is a block, and the
     793                 :   // special prevsibling of _that_ is an inline, just like aFrame.
     794                 :   // Similarly, if aFrame is the first continuation of a block part of an
     795                 :   // {ib} split (an {ib} wrapper block), then its special prevsibling is
     796                 :   // an inline and the special prevsibling of that is either another {ib}
     797                 :   // wrapper block block or null.
     798               0 :   nsIFrame *prevContinuation = aFrame->GetPrevContinuation();
     799               0 :   if (!prevContinuation && (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
     800                 :     // We're the first continuation, so we can just get the frame
     801                 :     // property directly
     802                 :     prevContinuation = static_cast<nsIFrame*>(
     803               0 :       aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
     804               0 :     if (prevContinuation) {
     805                 :       prevContinuation = static_cast<nsIFrame*>(
     806               0 :         prevContinuation->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
     807                 :     }
     808                 :   }
     809               0 :   return prevContinuation;
     810                 : }
     811                 : 
     812                 : nsresult
     813               0 : nsFrameManager::ReparentStyleContext(nsIFrame* aFrame)
     814                 : {
     815               0 :   if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
     816                 :     // Also reparent the out-of-flow and all its continuations.
     817                 :     nsIFrame* outOfFlow =
     818               0 :       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
     819               0 :     NS_ASSERTION(outOfFlow, "no out-of-flow frame");
     820               0 :     do {
     821               0 :       ReparentStyleContext(outOfFlow);
     822               0 :     } while ((outOfFlow = outOfFlow->GetNextContinuation()));
     823                 :   }
     824                 : 
     825                 :   // DO NOT verify the style tree before reparenting.  The frame
     826                 :   // tree has already been changed, so this check would just fail.
     827               0 :   nsStyleContext* oldContext = aFrame->GetStyleContext();
     828                 :   // XXXbz can oldContext really ever be null?
     829               0 :   if (oldContext) {
     830               0 :     nsRefPtr<nsStyleContext> newContext;
     831               0 :     nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame();
     832               0 :     bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
     833               0 :     nsStyleContext* newParentContext = nsnull;
     834               0 :     nsIFrame* providerChild = nsnull;
     835               0 :     if (isChild) {
     836               0 :       ReparentStyleContext(providerFrame);
     837               0 :       newParentContext = providerFrame->GetStyleContext();
     838               0 :       providerChild = providerFrame;
     839               0 :     } else if (providerFrame) {
     840               0 :       newParentContext = providerFrame->GetStyleContext();
     841                 :     } else {
     842                 :       NS_NOTREACHED("Reparenting something that has no usable parent? "
     843               0 :                     "Shouldn't happen!");
     844                 :     }
     845                 :     // XXX need to do something here to produce the correct style context for
     846                 :     // an IB split whose first inline part is inside a first-line frame.
     847                 :     // Currently the first IB anonymous block's style context takes the first
     848                 :     // part's style context as parent, which is wrong since first-line style
     849                 :     // should not apply to the anonymous block.
     850                 : 
     851                 : #ifdef DEBUG
     852                 :     {
     853                 :       // Check that our assumption that continuations of the same
     854                 :       // pseudo-type and with the same style context parent have the
     855                 :       // same style context is valid before the reresolution.  (We need
     856                 :       // to check the pseudo-type and style context parent because of
     857                 :       // :first-letter and :first-line, where we create styled and
     858                 :       // unstyled letter/line frames distinguished by pseudo-type, and
     859                 :       // then need to distinguish their descendants based on having
     860                 :       // different parents.)
     861               0 :       nsIFrame *nextContinuation = aFrame->GetNextContinuation();
     862               0 :       if (nextContinuation) {
     863                 :         nsStyleContext *nextContinuationContext =
     864               0 :           nextContinuation->GetStyleContext();
     865               0 :         NS_ASSERTION(oldContext == nextContinuationContext ||
     866                 :                      oldContext->GetPseudo() !=
     867                 :                        nextContinuationContext->GetPseudo() ||
     868                 :                      oldContext->GetParent() !=
     869                 :                        nextContinuationContext->GetParent(),
     870                 :                      "continuations should have the same style context");
     871                 :       }
     872                 :     }
     873                 : #endif
     874                 : 
     875                 :     nsIFrame *prevContinuation =
     876               0 :       GetPrevContinuationWithPossiblySameStyle(aFrame);
     877                 :     nsStyleContext *prevContinuationContext;
     878                 :     bool copyFromContinuation =
     879                 :       prevContinuation &&
     880                 :       (prevContinuationContext = prevContinuation->GetStyleContext())
     881               0 :         ->GetPseudo() == oldContext->GetPseudo() &&
     882               0 :        prevContinuationContext->GetParent() == newParentContext;
     883               0 :     if (copyFromContinuation) {
     884                 :       // Just use the style context from the frame's previous
     885                 :       // continuation (see assertion about aFrame->GetNextContinuation()
     886                 :       // above, which we would have previously hit for aFrame's previous
     887                 :       // continuation).
     888               0 :       newContext = prevContinuationContext;
     889                 :     } else {
     890               0 :       nsIFrame* parentFrame = aFrame->GetParent();
     891                 :       Element* element =
     892                 :         ElementForStyleContext(parentFrame ? parentFrame->GetContent() : nsnull,
     893                 :                                aFrame,
     894               0 :                                oldContext->GetPseudoType());
     895                 :       newContext = mStyleSet->ReparentStyleContext(oldContext,
     896                 :                                                    newParentContext,
     897               0 :                                                    element);
     898                 :     }
     899                 : 
     900               0 :     if (newContext) {
     901               0 :       if (newContext != oldContext) {
     902                 :         // We probably don't want to initiate transitions from
     903                 :         // ReparentStyleContext, since we call it during frame
     904                 :         // construction rather than in response to dynamic changes.
     905                 :         // Also see the comment at the start of
     906                 :         // nsTransitionManager::ConsiderStartingTransition.
     907                 : #if 0
     908                 :         if (!copyFromContinuation) {
     909                 :           TryStartingTransition(GetPresContext(), aFrame->GetContent(),
     910                 :                                 oldContext, &newContext);
     911                 :         }
     912                 : #endif
     913                 : 
     914                 :         // Make sure to call CalcStyleDifference so that the new context ends
     915                 :         // up resolving all the structs the old context resolved.
     916               0 :         nsChangeHint styleChange = oldContext->CalcStyleDifference(newContext);
     917                 :         // The style change is always 0 because we have the same rulenode and
     918                 :         // CalcStyleDifference optimizes us away.  That's OK, though:
     919                 :         // reparenting should never trigger a frame reconstruct, and whenever
     920                 :         // it's happening we already plan to reflow and repaint the frames.
     921               0 :         NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
     922                 :                      "Our frame tree is likely to be bogus!");
     923                 :         
     924               0 :         aFrame->SetStyleContext(newContext);
     925                 : 
     926               0 :         nsIFrame::ChildListIterator lists(aFrame);
     927               0 :         for (; !lists.IsDone(); lists.Next()) {
     928               0 :           nsFrameList::Enumerator childFrames(lists.CurrentList());
     929               0 :           for (; !childFrames.AtEnd(); childFrames.Next()) {
     930               0 :             nsIFrame* child = childFrames.get();
     931                 :             // only do frames that are in flow
     932               0 :             if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
     933                 :                 child != providerChild) {
     934                 : #ifdef DEBUG
     935               0 :               if (nsGkAtoms::placeholderFrame == child->GetType()) {
     936                 :                 nsIFrame* outOfFlowFrame =
     937               0 :                   nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
     938               0 :                 NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
     939                 : 
     940               0 :                 NS_ASSERTION(outOfFlowFrame != providerChild,
     941                 :                              "Out of flow provider?");
     942                 :               }
     943                 : #endif
     944               0 :               ReparentStyleContext(child);
     945                 :             }
     946                 :           }
     947                 :         }
     948                 : 
     949                 :         // If this frame is part of an IB split, then the style context of
     950                 :         // the next part of the split might be a child of our style context.
     951                 :         // Reparent its style context just in case one of our ancestors
     952                 :         // (split or not) hasn't done so already). It's not a problem to
     953                 :         // reparent the same frame twice because the "if (newContext !=
     954                 :         // oldContext)" check will prevent us from redoing work.
     955               0 :         if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
     956               0 :             !aFrame->GetPrevContinuation()) {
     957                 :           nsIFrame* sib = static_cast<nsIFrame*>
     958               0 :             (aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
     959               0 :           if (sib) {
     960               0 :             ReparentStyleContext(sib);
     961                 :           }
     962                 :         }
     963                 : 
     964                 :         // do additional contexts 
     965               0 :         PRInt32 contextIndex = -1;
     966               0 :         while (1) {
     967                 :           nsStyleContext* oldExtraContext =
     968               0 :             aFrame->GetAdditionalStyleContext(++contextIndex);
     969               0 :           if (oldExtraContext) {
     970               0 :             nsRefPtr<nsStyleContext> newExtraContext;
     971                 :             newExtraContext = mStyleSet->ReparentStyleContext(oldExtraContext,
     972                 :                                                               newContext,
     973               0 :                                                               nsnull);
     974               0 :             if (newExtraContext) {
     975               0 :               if (newExtraContext != oldExtraContext) {
     976                 :                 // Make sure to call CalcStyleDifference so that the new
     977                 :                 // context ends up resolving all the structs the old context
     978                 :                 // resolved.
     979                 :                 styleChange =
     980               0 :                   oldExtraContext->CalcStyleDifference(newExtraContext);
     981                 :                 // The style change is always 0 because we have the same
     982                 :                 // rulenode and CalcStyleDifference optimizes us away.  That's
     983                 :                 // OK, though: reparenting should never trigger a frame
     984                 :                 // reconstruct, and whenever it's happening we already plan to
     985                 :                 // reflow and repaint the frames.
     986               0 :                 NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
     987                 :                              "Our frame tree is likely to be bogus!");
     988                 :               }
     989                 :               
     990               0 :               aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
     991                 :             }
     992                 :           }
     993                 :           else {
     994                 :             break;
     995                 :           }
     996                 :         }
     997                 : #ifdef DEBUG
     998               0 :         VerifyStyleTree(GetPresContext(), aFrame, newParentContext);
     999                 : #endif
    1000                 :       }
    1001                 :     }
    1002                 :   }
    1003               0 :   return NS_OK;
    1004                 : }
    1005                 : 
    1006                 : static nsChangeHint
    1007               0 : CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext,
    1008                 :               nsIFrame* aFrame, nsIContent* aContent,
    1009                 :               nsStyleChangeList* aChangeList, nsChangeHint aMinChange,
    1010                 :               nsChangeHint aChangeToAssume)
    1011                 : {
    1012               0 :   nsChangeHint ourChange = aOldContext->CalcStyleDifference(aNewContext);
    1013               0 :   NS_ASSERTION(!(ourChange & nsChangeHint_ReflowFrame) ||
    1014                 :                (ourChange & nsChangeHint_NeedReflow),
    1015                 :                "Reflow hint bits set without actually asking for a reflow");
    1016                 : 
    1017               0 :   NS_UpdateHint(ourChange, aChangeToAssume);
    1018               0 :   if (NS_UpdateHint(aMinChange, ourChange)) {
    1019               0 :     if (!(ourChange & nsChangeHint_ReconstructFrame) || aContent) {
    1020               0 :       aChangeList->AppendChange(aFrame, aContent, ourChange);
    1021                 :     }
    1022                 :   }
    1023               0 :   return aMinChange;
    1024                 : }
    1025                 : 
    1026                 : /**
    1027                 :  * Recompute style for aFrame and accumulate changes into aChangeList
    1028                 :  * given that aMinChange is already accumulated for an ancestor.
    1029                 :  * aParentContent is the content node used to resolve the parent style
    1030                 :  * context.  This means that, for pseudo-elements, it is the content
    1031                 :  * that should be used for selector matching (rather than the fake
    1032                 :  * content node attached to the frame).
    1033                 :  */
    1034                 : nsChangeHint
    1035               0 : nsFrameManager::ReResolveStyleContext(nsPresContext     *aPresContext,
    1036                 :                                       nsIFrame          *aFrame,
    1037                 :                                       nsIContent        *aParentContent,
    1038                 :                                       nsStyleChangeList *aChangeList, 
    1039                 :                                       nsChangeHint       aMinChange,
    1040                 :                                       nsRestyleHint      aRestyleHint,
    1041                 :                                       RestyleTracker&    aRestyleTracker,
    1042                 :                                       DesiredA11yNotifications aDesiredA11yNotifications,
    1043                 :                                       nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement,
    1044                 :                                       TreeMatchContext &aTreeMatchContext)
    1045                 : {
    1046               0 :   if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aMinChange)) {
    1047                 :     // If aMinChange doesn't include nsChangeHint_NeedDirtyReflow, clear out
    1048                 :     // all the reflow change bits from it, so that we'll make sure to append a
    1049                 :     // change to the list for ourselves if we need a reflow.  We need this
    1050                 :     // because the parent may or may not actually end up reflowing us
    1051                 :     // otherwise.
    1052               0 :     aMinChange = NS_SubtractHint(aMinChange, nsChangeHint_ReflowFrame);
    1053               0 :   } else if (!NS_IsHintSubset(nsChangeHint_ClearDescendantIntrinsics,
    1054               0 :                               aMinChange)) {
    1055                 :     // If aMinChange doesn't include nsChangeHint_ClearDescendantIntrinsics,
    1056                 :     // clear out the nsChangeHint_ClearAncestorIntrinsics flag, since it's
    1057                 :     // possible that we had some random ancestor that cleared ancestor
    1058                 :     // intrinsic widths, but we still need to clear intrinsic widths on frames
    1059                 :     // that are our ancestors but its descendants.
    1060                 :     aMinChange =
    1061               0 :       NS_SubtractHint(aMinChange, nsChangeHint_ClearAncestorIntrinsics);
    1062                 :   }
    1063                 : 
    1064                 :   // We need to generate a new change list entry for every frame whose style
    1065                 :   // comparision returns one of these hints. These hints don't automatically
    1066                 :   // update all their descendant frames.
    1067               0 :   aMinChange = NS_SubtractHint(aMinChange, nsChangeHint_UpdateTransformLayer);
    1068               0 :   aMinChange = NS_SubtractHint(aMinChange, nsChangeHint_UpdateOpacityLayer);
    1069               0 :   aMinChange = NS_SubtractHint(aMinChange, nsChangeHint_UpdateOverflow);
    1070                 : 
    1071                 :   // It would be nice if we could make stronger assertions here; they
    1072                 :   // would let us simplify the ?: expressions below setting |content|
    1073                 :   // and |pseudoContent| in sensible ways as well as making what
    1074                 :   // |localContent|, |content|, and |pseudoContent| mean make more
    1075                 :   // sense.  However, we can't, because of frame trees like the one in
    1076                 :   // https://bugzilla.mozilla.org/show_bug.cgi?id=472353#c14 .  Once we
    1077                 :   // fix bug 242277 we should be able to make this make more sense.
    1078               0 :   NS_ASSERTION(aFrame->GetContent() || !aParentContent ||
    1079                 :                !aParentContent->GetParent(),
    1080                 :                "frame must have content (unless at the top of the tree)");
    1081                 :   // XXXldb get new context from prev-in-flow if possible, to avoid
    1082                 :   // duplication.  (Or should we just let |GetContext| handle that?)
    1083                 :   // Getting the hint would be nice too, but that's harder.
    1084                 : 
    1085                 :   // XXXbryner we may be able to avoid some of the refcounting goop here.
    1086                 :   // We do need a reference to oldContext for the lifetime of this function, and it's possible
    1087                 :   // that the frame has the last reference to it, so AddRef it here.
    1088                 : 
    1089               0 :   nsChangeHint assumeDifferenceHint = NS_STYLE_HINT_NONE;
    1090                 :   // XXXbz oldContext should just be an nsRefPtr
    1091               0 :   nsStyleContext* oldContext = aFrame->GetStyleContext();
    1092               0 :   nsStyleSet* styleSet = aPresContext->StyleSet();
    1093                 : 
    1094                 :   // XXXbz the nsIFrame constructor takes an nsStyleContext, so how
    1095                 :   // could oldContext be null?
    1096               0 :   if (oldContext) {
    1097               0 :     oldContext->AddRef();
    1098                 : 
    1099                 : #ifdef ACCESSIBILITY
    1100               0 :     bool wasFrameVisible = nsIPresShell::IsAccessibilityActive() ?
    1101               0 :       oldContext->GetStyleVisibility()->IsVisible() : false;
    1102                 : #endif
    1103                 : 
    1104               0 :     nsIAtom* const pseudoTag = oldContext->GetPseudo();
    1105               0 :     const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType();
    1106               0 :     nsIContent* localContent = aFrame->GetContent();
    1107                 :     // |content| is the node that we used for rule matching of
    1108                 :     // normal elements (not pseudo-elements) and for which we generate
    1109                 :     // framechange hints if we need them.
    1110                 :     // XXXldb Why does it make sense to use aParentContent?  (See
    1111                 :     // comment above assertion at start of function.)
    1112               0 :     nsIContent* content = localContent ? localContent : aParentContent;
    1113                 : 
    1114               0 :     if (content && content->IsElement()) {
    1115               0 :       content->OwnerDoc()->FlushPendingLinkUpdates();
    1116                 :       RestyleTracker::RestyleData restyleData;
    1117               0 :       if (aRestyleTracker.GetRestyleData(content->AsElement(), &restyleData)) {
    1118               0 :         if (NS_UpdateHint(aMinChange, restyleData.mChangeHint)) {
    1119               0 :           aChangeList->AppendChange(aFrame, content, restyleData.mChangeHint);
    1120                 :         }
    1121               0 :         aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint);
    1122                 :       }
    1123                 :     }
    1124                 : 
    1125               0 :     nsRestyleHint childRestyleHint = aRestyleHint;
    1126                 : 
    1127               0 :     if (childRestyleHint == eRestyle_Self) {
    1128               0 :       childRestyleHint = nsRestyleHint(0);
    1129                 :     }
    1130                 : 
    1131                 :     nsStyleContext* parentContext;
    1132               0 :     nsIFrame* resolvedChild = nsnull;
    1133                 :     // Get the frame providing the parent style context.  If it is a
    1134                 :     // child, then resolve the provider first.
    1135               0 :     nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame();
    1136               0 :     bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
    1137               0 :     if (!isChild) {
    1138               0 :       if (providerFrame)
    1139               0 :         parentContext = providerFrame->GetStyleContext();
    1140                 :       else
    1141               0 :         parentContext = nsnull;
    1142                 :     }
    1143                 :     else {
    1144               0 :       MOZ_ASSERT(providerFrame->GetContent() == aFrame->GetContent(),
    1145                 :                  "Postcondition for GetParentStyleContextFrame() violated. "
    1146                 :                  "That means we need to add the current element to the "
    1147               0 :                  "ancestor filter.");
    1148                 : 
    1149                 :       // resolve the provider here (before aFrame below).
    1150                 : 
    1151                 :       // assumeDifferenceHint forces the parent's change to be also
    1152                 :       // applied to this frame, no matter what
    1153                 :       // nsStyleContext::CalcStyleDifference says. CalcStyleDifference
    1154                 :       // can't be trusted because it assumes any changes to the parent
    1155                 :       // style context provider will be automatically propagated to
    1156                 :       // the frame(s) with child style contexts.
    1157                 : 
    1158                 :       assumeDifferenceHint = ReResolveStyleContext(aPresContext, providerFrame,
    1159                 :                                                    aParentContent, aChangeList,
    1160                 :                                                    aMinChange, aRestyleHint,
    1161                 :                                                    aRestyleTracker,
    1162                 :                                                    aDesiredA11yNotifications,
    1163                 :                                                    aVisibleKidsOfHiddenElement,
    1164               0 :                                                    aTreeMatchContext);
    1165                 : 
    1166                 :       // The provider's new context becomes the parent context of
    1167                 :       // aFrame's context.
    1168               0 :       parentContext = providerFrame->GetStyleContext();
    1169                 :       // Set |resolvedChild| so we don't bother resolving the
    1170                 :       // provider again.
    1171               0 :       resolvedChild = providerFrame;
    1172                 :     }
    1173                 : 
    1174                 : #ifdef DEBUG
    1175                 :     {
    1176                 :       // Check that our assumption that continuations of the same
    1177                 :       // pseudo-type and with the same style context parent have the
    1178                 :       // same style context is valid before the reresolution.  (We need
    1179                 :       // to check the pseudo-type and style context parent because of
    1180                 :       // :first-letter and :first-line, where we create styled and
    1181                 :       // unstyled letter/line frames distinguished by pseudo-type, and
    1182                 :       // then need to distinguish their descendants based on having
    1183                 :       // different parents.)
    1184               0 :       nsIFrame *nextContinuation = aFrame->GetNextContinuation();
    1185               0 :       if (nextContinuation) {
    1186                 :         nsStyleContext *nextContinuationContext =
    1187               0 :           nextContinuation->GetStyleContext();
    1188               0 :         NS_ASSERTION(oldContext == nextContinuationContext ||
    1189                 :                      oldContext->GetPseudo() !=
    1190                 :                        nextContinuationContext->GetPseudo() ||
    1191                 :                      oldContext->GetParent() !=
    1192                 :                        nextContinuationContext->GetParent(),
    1193                 :                      "continuations should have the same style context");
    1194                 :       }
    1195                 :       // And assert the same thing for {ib} splits.  See the comments in
    1196                 :       // GetPrevContinuationWithPossiblySameStyle for an explanation of
    1197                 :       // why we step two forward in the special sibling chain.
    1198               0 :       if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
    1199               0 :           !aFrame->GetPrevContinuation()) {
    1200                 :         nsIFrame *nextIBSibling = static_cast<nsIFrame*>(
    1201               0 :           aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
    1202               0 :         if (nextIBSibling) {
    1203                 :           nextIBSibling = static_cast<nsIFrame*>(
    1204               0 :             nextIBSibling->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
    1205                 :         }
    1206               0 :         if (nextIBSibling) {
    1207                 :           nsStyleContext *nextIBSiblingContext =
    1208               0 :             nextIBSibling->GetStyleContext();
    1209               0 :           NS_ASSERTION(oldContext == nextIBSiblingContext ||
    1210                 :                        oldContext->GetPseudo() !=
    1211                 :                          nextIBSiblingContext->GetPseudo() ||
    1212                 :                        oldContext->GetParent() !=
    1213                 :                          nextIBSiblingContext->GetParent(),
    1214                 :                        "continuations should have the same style context");
    1215                 :         }
    1216                 :       }
    1217                 :     }
    1218                 : #endif
    1219                 : 
    1220                 :     // do primary context
    1221               0 :     nsRefPtr<nsStyleContext> newContext;
    1222                 :     nsIFrame *prevContinuation =
    1223               0 :       GetPrevContinuationWithPossiblySameStyle(aFrame);
    1224                 :     nsStyleContext *prevContinuationContext;
    1225                 :     bool copyFromContinuation =
    1226                 :       prevContinuation &&
    1227                 :       (prevContinuationContext = prevContinuation->GetStyleContext())
    1228               0 :         ->GetPseudo() == oldContext->GetPseudo() &&
    1229               0 :        prevContinuationContext->GetParent() == parentContext;
    1230               0 :     if (copyFromContinuation) {
    1231                 :       // Just use the style context from the frame's previous
    1232                 :       // continuation (see assertion about aFrame->GetNextContinuation()
    1233                 :       // above, which we would have previously hit for aFrame's previous
    1234                 :       // continuation).
    1235               0 :       newContext = prevContinuationContext;
    1236                 :     }
    1237               0 :     else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
    1238               0 :       NS_ASSERTION(localContent,
    1239                 :                    "non pseudo-element frame without content node");
    1240               0 :       newContext = styleSet->ResolveStyleForNonElement(parentContext);
    1241                 :     }
    1242               0 :     else if (!aRestyleHint && !prevContinuation) {
    1243                 :       // Unfortunately, if prevContinuation is non-null then we may have
    1244                 :       // already stolen the restyle tracker entry for this element while
    1245                 :       // processing prevContinuation.  So we don't know whether aRestyleHint
    1246                 :       // should really be 0 here or whether it should be eRestyle_Self.  Be
    1247                 :       // pessimistic and force an actual reresolve in that situation.  The good
    1248                 :       // news is that in the common case when prevContinuation is non-null we
    1249                 :       // just used prevContinuationContext anyway and aren't reaching this code
    1250                 :       // to start with.
    1251                 :       newContext =
    1252                 :         styleSet->ReparentStyleContext(oldContext, parentContext,
    1253                 :                                        ElementForStyleContext(aParentContent,
    1254                 :                                                               aFrame,
    1255               0 :                                                               pseudoType));
    1256               0 :     } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
    1257                 :       newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag,
    1258               0 :                                                       parentContext);
    1259                 :     }
    1260                 :     else {
    1261                 :       Element* element = ElementForStyleContext(aParentContent,
    1262                 :                                                 aFrame,
    1263               0 :                                                 pseudoType);
    1264               0 :       if (pseudoTag) {
    1265               0 :         if (pseudoTag == nsCSSPseudoElements::before ||
    1266                 :             pseudoTag == nsCSSPseudoElements::after) {
    1267                 :           // XXX what other pseudos do we need to treat like this?
    1268                 :           newContext = styleSet->ProbePseudoElementStyle(element,
    1269                 :                                                          pseudoType,
    1270                 :                                                          parentContext,
    1271               0 :                                                          aTreeMatchContext);
    1272               0 :           if (!newContext) {
    1273                 :             // This pseudo should no longer exist; gotta reframe
    1274               0 :             NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
    1275                 :             aChangeList->AppendChange(aFrame, element,
    1276               0 :                                       nsChangeHint_ReconstructFrame);
    1277                 :             // We're reframing anyway; just keep the same context
    1278               0 :             newContext = oldContext;
    1279                 :           }
    1280                 :         } else {
    1281                 :           // Don't expect XUL tree stuff here, since it needs a comparator and
    1282                 :           // all.
    1283               0 :           NS_ASSERTION(pseudoType <
    1284                 :                          nsCSSPseudoElements::ePseudo_PseudoElementCount,
    1285                 :                        "Unexpected pseudo type");
    1286                 :           newContext = styleSet->ResolvePseudoElementStyle(element,
    1287                 :                                                            pseudoType,
    1288               0 :                                                            parentContext);
    1289                 :         }
    1290                 :       }
    1291                 :       else {
    1292               0 :         NS_ASSERTION(localContent,
    1293                 :                      "non pseudo-element frame without content node");
    1294                 :         newContext = styleSet->ResolveStyleFor(element, parentContext,
    1295               0 :                                                aTreeMatchContext);
    1296                 :       }
    1297                 :     }
    1298                 : 
    1299               0 :     NS_ASSERTION(newContext, "failed to get new style context");
    1300               0 :     if (newContext) {
    1301               0 :       if (!parentContext) {
    1302               0 :         if (oldContext->GetRuleNode() == newContext->GetRuleNode() &&
    1303               0 :             oldContext->IsLinkContext() == newContext->IsLinkContext() &&
    1304               0 :             oldContext->RelevantLinkVisited() ==
    1305               0 :               newContext->RelevantLinkVisited()) {
    1306                 :           // We're the root of the style context tree and the new style
    1307                 :           // context returned has the same rule node.  This means that
    1308                 :           // we can use FindChildWithRules to keep a lot of the old
    1309                 :           // style contexts around.  However, we need to start from the
    1310                 :           // same root.
    1311               0 :           newContext = oldContext;
    1312                 :         }
    1313                 :       }
    1314                 : 
    1315               0 :       if (newContext != oldContext) {
    1316               0 :         if (!copyFromContinuation) {
    1317                 :           TryStartingTransition(aPresContext, aFrame->GetContent(),
    1318               0 :                                 oldContext, &newContext);
    1319                 :         }
    1320                 : 
    1321                 :         aMinChange = CaptureChange(oldContext, newContext, aFrame,
    1322                 :                                    content, aChangeList, aMinChange,
    1323               0 :                                    assumeDifferenceHint);
    1324               0 :         if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
    1325                 :           // if frame gets regenerated, let it keep old context
    1326               0 :           aFrame->SetStyleContext(newContext);
    1327                 :         }
    1328                 :       }
    1329               0 :       oldContext->Release();
    1330                 :     }
    1331                 :     else {
    1332               0 :       NS_ERROR("resolve style context failed");
    1333               0 :       newContext = oldContext;  // new context failed, recover...
    1334                 :     }
    1335                 : 
    1336                 :     // do additional contexts
    1337                 :     // XXXbz might be able to avoid selector matching here in some
    1338                 :     // cases; won't worry about it for now.
    1339               0 :     PRInt32 contextIndex = -1;
    1340               0 :     while (1 == 1) {
    1341               0 :       nsStyleContext* oldExtraContext = nsnull;
    1342               0 :       oldExtraContext = aFrame->GetAdditionalStyleContext(++contextIndex);
    1343               0 :       if (oldExtraContext) {
    1344               0 :         nsRefPtr<nsStyleContext> newExtraContext;
    1345               0 :         nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
    1346                 :         const nsCSSPseudoElements::Type extraPseudoType =
    1347               0 :           oldExtraContext->GetPseudoType();
    1348               0 :         NS_ASSERTION(extraPseudoTag &&
    1349                 :                      extraPseudoTag != nsCSSAnonBoxes::mozNonElement,
    1350                 :                      "extra style context is not pseudo element");
    1351               0 :         if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
    1352                 :           newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag,
    1353               0 :                                                                newContext);
    1354                 :         }
    1355                 :         else {
    1356                 :           // Don't expect XUL tree stuff here, since it needs a comparator and
    1357                 :           // all.
    1358               0 :           NS_ASSERTION(extraPseudoType <
    1359                 :                          nsCSSPseudoElements::ePseudo_PseudoElementCount,
    1360                 :                        "Unexpected type");
    1361                 :           newExtraContext = styleSet->ResolvePseudoElementStyle(content->AsElement(),
    1362                 :                                                                 extraPseudoType,
    1363               0 :                                                                 newContext);
    1364                 :         }
    1365               0 :         if (newExtraContext) {
    1366               0 :           if (oldExtraContext != newExtraContext) {
    1367                 :             aMinChange = CaptureChange(oldExtraContext, newExtraContext,
    1368                 :                                        aFrame, content, aChangeList,
    1369               0 :                                        aMinChange, assumeDifferenceHint);
    1370               0 :             if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
    1371               0 :               aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
    1372                 :             }
    1373                 :           }
    1374                 :         }
    1375                 :       }
    1376                 :       else {
    1377                 :         break;
    1378                 :       }
    1379                 :     }
    1380                 : 
    1381                 :     // now look for undisplayed child content and pseudos
    1382                 : 
    1383                 :     // When the root element is display:none, we still construct *some*
    1384                 :     // frames that have the root element as their mContent, down to the
    1385                 :     // DocElementContainingBlock.
    1386                 :     bool checkUndisplayed;
    1387                 :     nsIContent *undisplayedParent;
    1388               0 :     if (pseudoTag) {
    1389                 :       checkUndisplayed = aFrame == mPresShell->FrameConstructor()->
    1390               0 :                                      GetDocElementContainingBlock();
    1391               0 :       undisplayedParent = nsnull;
    1392                 :     } else {
    1393               0 :       checkUndisplayed = !!localContent;
    1394               0 :       undisplayedParent = localContent;
    1395                 :     }
    1396               0 :     if (checkUndisplayed && mUndisplayedMap) {
    1397                 :       UndisplayedNode* undisplayed =
    1398               0 :         mUndisplayedMap->GetFirstNode(undisplayedParent);
    1399               0 :       for (AncestorFilter::AutoAncestorPusher
    1400                 :              pushAncestor(undisplayed, aTreeMatchContext.mAncestorFilter,
    1401               0 :                           undisplayedParent ? undisplayedParent->AsElement()
    1402               0 :                                             : nsnull);
    1403                 :            undisplayed; undisplayed = undisplayed->mNext) {
    1404               0 :         NS_ASSERTION(undisplayedParent ||
    1405                 :                      undisplayed->mContent ==
    1406                 :                        mPresShell->GetDocument()->GetRootElement(),
    1407                 :                      "undisplayed node child of null must be root");
    1408               0 :         NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
    1409                 :                      "Shouldn't have random pseudo style contexts in the "
    1410                 :                      "undisplayed map");
    1411               0 :         nsRestyleHint thisChildHint = childRestyleHint;
    1412                 :         RestyleTracker::RestyleData undisplayedRestyleData;
    1413               0 :         if (aRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
    1414               0 :                                            &undisplayedRestyleData)) {
    1415                 :           thisChildHint =
    1416               0 :             nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
    1417                 :         }
    1418               0 :         nsRefPtr<nsStyleContext> undisplayedContext;
    1419               0 :         if (thisChildHint) {
    1420                 :           undisplayedContext =
    1421               0 :             styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
    1422                 :                                       newContext,
    1423               0 :                                       aTreeMatchContext);
    1424                 :         } else {
    1425                 :           undisplayedContext =
    1426                 :             styleSet->ReparentStyleContext(undisplayed->mStyle, newContext,
    1427               0 :                                            undisplayed->mContent->AsElement());
    1428                 :         }
    1429               0 :         if (undisplayedContext) {
    1430               0 :           const nsStyleDisplay* display = undisplayedContext->GetStyleDisplay();
    1431               0 :           if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
    1432               0 :             NS_ASSERTION(undisplayed->mContent,
    1433                 :                          "Must have undisplayed content");
    1434                 :             aChangeList->AppendChange(nsnull, undisplayed->mContent, 
    1435               0 :                                       NS_STYLE_HINT_FRAMECHANGE);
    1436                 :             // The node should be removed from the undisplayed map when
    1437                 :             // we reframe it.
    1438                 :           } else {
    1439                 :             // update the undisplayed node with the new context
    1440               0 :             undisplayed->mStyle = undisplayedContext;
    1441                 :           }
    1442                 :         }
    1443                 :       }
    1444                 :     }
    1445                 : 
    1446                 :     // Check whether we might need to create a new ::before frame.
    1447                 :     // There's no need to do this if we're planning to reframe already
    1448                 :     // or if we're not forcing restyles on kids.
    1449               0 :     if (!(aMinChange & nsChangeHint_ReconstructFrame) &&
    1450                 :         childRestyleHint) {
    1451                 :       // Make sure not to do this for pseudo-frames -- those can't have :before
    1452                 :       // or :after content.  Neither can non-elements or leaf frames.
    1453               0 :       if (!pseudoTag && localContent && localContent->IsElement() &&
    1454               0 :           !aFrame->IsLeaf()) {
    1455                 :         // Check for a new :before pseudo and an existing :before
    1456                 :         // frame, but only if the frame is the first continuation.
    1457               0 :         nsIFrame* prevContinuation = aFrame->GetPrevContinuation();
    1458               0 :         if (!prevContinuation) {
    1459                 :           // Checking for a :before frame is cheaper than getting the
    1460                 :           // :before style context.
    1461               0 :           if (!nsLayoutUtils::GetBeforeFrame(aFrame) &&
    1462                 :               nsLayoutUtils::HasPseudoStyle(localContent, newContext,
    1463                 :                                             nsCSSPseudoElements::ePseudo_before,
    1464               0 :                                             aPresContext)) {
    1465                 :             // Have to create the new :before frame
    1466               0 :             NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
    1467                 :             aChangeList->AppendChange(aFrame, content,
    1468               0 :                                       nsChangeHint_ReconstructFrame);
    1469                 :           }
    1470                 :         }
    1471                 :       }
    1472                 :     }
    1473                 : 
    1474                 :     // Check whether we might need to create a new ::after frame.
    1475                 :     // There's no need to do this if we're planning to reframe already
    1476                 :     // or if we're not forcing restyles on kids.
    1477               0 :     if (!(aMinChange & nsChangeHint_ReconstructFrame) &&
    1478                 :         childRestyleHint) {
    1479                 :       // Make sure not to do this for pseudo-frames -- those can't have :before
    1480                 :       // or :after content.  Neither can non-elements or leaf frames.
    1481               0 :       if (!pseudoTag && localContent && localContent->IsElement() &&
    1482               0 :           !aFrame->IsLeaf()) {
    1483                 :         // Check for new :after content, but only if the frame is the
    1484                 :         // last continuation.
    1485               0 :         nsIFrame* nextContinuation = aFrame->GetNextContinuation();
    1486                 : 
    1487               0 :         if (!nextContinuation) {
    1488                 :           // Getting the :after frame is more expensive than getting the pseudo
    1489                 :           // context, so get the pseudo context first.
    1490               0 :           if (nsLayoutUtils::HasPseudoStyle(localContent, newContext,
    1491                 :                                             nsCSSPseudoElements::ePseudo_after,
    1492               0 :                                             aPresContext) &&
    1493               0 :               !nsLayoutUtils::GetAfterFrame(aFrame)) {
    1494                 :             // have to create the new :after frame
    1495               0 :             NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
    1496                 :             aChangeList->AppendChange(aFrame, content,
    1497               0 :                                       nsChangeHint_ReconstructFrame);
    1498                 :           }
    1499                 :         }      
    1500                 :       }
    1501                 :     }
    1502                 : 
    1503               0 :     if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
    1504                 :       DesiredA11yNotifications kidsDesiredA11yNotification =
    1505               0 :         aDesiredA11yNotifications;
    1506                 : #ifdef ACCESSIBILITY
    1507               0 :       A11yNotificationType ourA11yNotification = eDontNotify;
    1508                 :       // Notify a11y for primary frame only if it's a root frame of visibility
    1509                 :       // changes or its parent frame was hidden while it stays visible and
    1510                 :       // it is not inside a {ib} split or is the first frame of {ib} split.
    1511               0 :       if (nsIPresShell::IsAccessibilityActive() &&
    1512               0 :           !aFrame->GetPrevContinuation() &&
    1513               0 :           !nsLayoutUtils::FrameIsNonFirstInIBSplit(aFrame)) {
    1514               0 :         if (aDesiredA11yNotifications == eSendAllNotifications) {
    1515               0 :           bool isFrameVisible = newContext->GetStyleVisibility()->IsVisible();
    1516               0 :           if (isFrameVisible != wasFrameVisible) {
    1517               0 :             if (isFrameVisible) {
    1518                 :               // Notify a11y the element (perhaps with its children) was shown.
    1519                 :               // We don't fall into this case if this element gets or stays shown
    1520                 :               // while its parent becomes hidden.
    1521               0 :               kidsDesiredA11yNotification = eSkipNotifications;
    1522               0 :               ourA11yNotification = eNotifyShown;
    1523                 :             } else {
    1524                 :               // The element is being hidden; its children may stay visible, or
    1525                 :               // become visible after being hidden previously. If we'll find
    1526                 :               // visible children then we should notify a11y about that as if
    1527                 :               // they were inserted into tree. Notify a11y this element was
    1528                 :               // hidden.
    1529               0 :               kidsDesiredA11yNotification = eNotifyIfShown;
    1530               0 :               ourA11yNotification = eNotifyHidden;
    1531                 :             }
    1532                 :           }
    1533               0 :         } else if (aDesiredA11yNotifications == eNotifyIfShown &&
    1534               0 :                    newContext->GetStyleVisibility()->IsVisible()) {
    1535                 :           // Notify a11y that element stayed visible while its parent was
    1536                 :           // hidden.
    1537               0 :           aVisibleKidsOfHiddenElement.AppendElement(aFrame->GetContent());
    1538               0 :           kidsDesiredA11yNotification = eSkipNotifications;
    1539                 :         }
    1540                 :       }
    1541                 : #endif
    1542                 : 
    1543                 :       // There is no need to waste time crawling into a frame's children on a frame change.
    1544                 :       // The act of reconstructing frames will force new style contexts to be resolved on all
    1545                 :       // of this frame's descendants anyway, so we want to avoid wasting time processing
    1546                 :       // style contexts that we're just going to throw away anyway. - dwh
    1547                 : 
    1548                 :       // now do children
    1549               0 :       nsIFrame::ChildListIterator lists(aFrame);
    1550               0 :       for (AncestorFilter::AutoAncestorPusher
    1551               0 :              pushAncestor(!lists.IsDone(),
    1552                 :                           aTreeMatchContext.mAncestorFilter,
    1553               0 :                           content && content->IsElement() ? content->AsElement()
    1554               0 :                                                           : nsnull);
    1555               0 :            !lists.IsDone(); lists.Next()) {
    1556               0 :         nsFrameList::Enumerator childFrames(lists.CurrentList());
    1557               0 :         for (; !childFrames.AtEnd(); childFrames.Next()) {
    1558               0 :           nsIFrame* child = childFrames.get();
    1559               0 :           if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    1560                 :             // only do frames that are in flow
    1561               0 :             if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
    1562                 :               // get out of flow frame and recur there
    1563                 :               nsIFrame* outOfFlowFrame =
    1564               0 :                 nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
    1565               0 :               NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
    1566               0 :               NS_ASSERTION(outOfFlowFrame != resolvedChild,
    1567                 :                            "out-of-flow frame not a true descendant");
    1568                 : 
    1569                 :               // Note that the out-of-flow may not be a geometric descendant of
    1570                 :               // the frame where we started the reresolve.  Therefore, even if
    1571                 :               // aMinChange already includes nsChangeHint_ReflowFrame we don't
    1572                 :               // want to pass that on to the out-of-flow reresolve, since that
    1573                 :               // can lead to the out-of-flow not getting reflowed when it should
    1574                 :               // be (eg a reresolve starting at <body> that involves reflowing
    1575                 :               // the <body> would miss reflowing fixed-pos nodes that also need
    1576                 :               // reflow).  In the cases when the out-of-flow _is_ a geometric
    1577                 :               // descendant of a frame we already have a reflow hint for,
    1578                 :               // reflow coalescing should keep us from doing the work twice.
    1579                 : 
    1580                 :               // |nsFrame::GetParentStyleContextFrame| checks being out
    1581                 :               // of flow so that this works correctly.
    1582               0 :               do {
    1583                 :                 ReResolveStyleContext(aPresContext, outOfFlowFrame,
    1584                 :                                       content, aChangeList,
    1585                 :                                       NS_SubtractHint(aMinChange,
    1586                 :                                                       nsChangeHint_ReflowFrame),
    1587                 :                                       childRestyleHint,
    1588                 :                                       aRestyleTracker,
    1589                 :                                       kidsDesiredA11yNotification,
    1590                 :                                       aVisibleKidsOfHiddenElement,
    1591               0 :                                       aTreeMatchContext);
    1592               0 :               } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
    1593                 : 
    1594                 :               // reresolve placeholder's context under the same parent
    1595                 :               // as the out-of-flow frame
    1596                 :               ReResolveStyleContext(aPresContext, child, content,
    1597                 :                                     aChangeList, aMinChange,
    1598                 :                                     childRestyleHint,
    1599                 :                                     aRestyleTracker,
    1600                 :                                     kidsDesiredA11yNotification,
    1601                 :                                     aVisibleKidsOfHiddenElement,
    1602               0 :                                     aTreeMatchContext);
    1603                 :             }
    1604                 :             else {  // regular child frame
    1605               0 :               if (child != resolvedChild) {
    1606                 :                 ReResolveStyleContext(aPresContext, child, content,
    1607                 :                                       aChangeList, aMinChange,
    1608                 :                                       childRestyleHint,
    1609                 :                                       aRestyleTracker,
    1610                 :                                       kidsDesiredA11yNotification,
    1611                 :                                       aVisibleKidsOfHiddenElement,
    1612               0 :                                       aTreeMatchContext);
    1613                 :               } else {
    1614                 :                 NOISY_TRACE_FRAME("child frame already resolved as descendant, skipping",aFrame);
    1615                 :               }
    1616                 :             }
    1617                 :           }
    1618                 :         }
    1619                 :       }
    1620                 :       // XXX need to do overflow frames???
    1621                 : 
    1622                 : #ifdef ACCESSIBILITY
    1623                 :       // Send notifications about visibility changes.
    1624               0 :       if (ourA11yNotification == eNotifyShown) {
    1625               0 :         nsAccessibilityService* accService = nsIPresShell::AccService();
    1626               0 :         if (accService) {
    1627               0 :           nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
    1628               0 :           nsIContent* content = aFrame->GetContent();
    1629                 : 
    1630                 :           accService->ContentRangeInserted(presShell, content->GetParent(),
    1631                 :                                            content,
    1632               0 :                                            content->GetNextSibling());
    1633                 :         }
    1634               0 :       } else if (ourA11yNotification == eNotifyHidden) {
    1635               0 :         nsAccessibilityService* accService = nsIPresShell::AccService();
    1636               0 :         if (accService) {
    1637               0 :           nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
    1638               0 :           nsIContent* content = aFrame->GetContent();
    1639               0 :           accService->ContentRemoved(presShell, content->GetParent(), content);
    1640                 : 
    1641                 :           // Process children staying shown.
    1642               0 :           PRUint32 visibleContentCount = aVisibleKidsOfHiddenElement.Length();
    1643               0 :           for (PRUint32 idx = 0; idx < visibleContentCount; idx++) {
    1644               0 :             nsIContent* content = aVisibleKidsOfHiddenElement[idx];
    1645                 :             accService->ContentRangeInserted(presShell, content->GetParent(),
    1646               0 :                                              content, content->GetNextSibling());
    1647                 :           }
    1648               0 :           aVisibleKidsOfHiddenElement.Clear();
    1649                 :         }
    1650                 :       }
    1651                 : #endif
    1652                 :     }
    1653                 :   }
    1654                 : 
    1655               0 :   return aMinChange;
    1656                 : }
    1657                 : 
    1658                 : void
    1659               0 : nsFrameManager::ComputeStyleChangeFor(nsIFrame          *aFrame, 
    1660                 :                                       nsStyleChangeList *aChangeList,
    1661                 :                                       nsChangeHint       aMinChange,
    1662                 :                                       RestyleTracker&    aRestyleTracker,
    1663                 :                                       bool               aRestyleDescendants)
    1664                 : {
    1665               0 :   nsIContent *content = aFrame->GetContent();
    1666               0 :   if (aMinChange) {
    1667               0 :     aChangeList->AppendChange(aFrame, content, aMinChange);
    1668                 :   }
    1669                 : 
    1670               0 :   nsChangeHint topLevelChange = aMinChange;
    1671                 : 
    1672               0 :   nsIFrame* frame = aFrame;
    1673               0 :   nsIFrame* frame2 = aFrame;
    1674                 : 
    1675               0 :   NS_ASSERTION(!frame->GetPrevContinuation(), "must start with the first in flow");
    1676                 : 
    1677                 :   // We want to start with this frame and walk all its next-in-flows,
    1678                 :   // as well as all its special siblings and their next-in-flows,
    1679                 :   // reresolving style on all the frames we encounter in this walk.
    1680                 : 
    1681               0 :   FramePropertyTable *propTable = GetPresContext()->PropertyTable();
    1682                 : 
    1683                 :   TreeMatchContext treeMatchContext(true,
    1684                 :                                     nsRuleWalker::eRelevantLinkUnvisited,
    1685               0 :                                     mPresShell->GetDocument());
    1686               0 :   nsIContent *parent = content ? content->GetParent() : nsnull;
    1687                 :   Element *parentElement =
    1688               0 :     parent && parent->IsElement() ? parent->AsElement() : nsnull;
    1689               0 :   treeMatchContext.mAncestorFilter.Init(parentElement);
    1690               0 :   nsTArray<nsIContent*> visibleKidsOfHiddenElement;
    1691               0 :   do {
    1692                 :     // Outer loop over special siblings
    1693               0 :     do {
    1694                 :       // Inner loop over next-in-flows of the current frame
    1695                 :       nsChangeHint frameChange =
    1696                 :         ReResolveStyleContext(GetPresContext(), frame, nsnull,
    1697                 :                               aChangeList, topLevelChange,
    1698                 :                               aRestyleDescendants ?
    1699                 :                                 eRestyle_Subtree : eRestyle_Self,
    1700                 :                               aRestyleTracker,
    1701                 :                               eSendAllNotifications,
    1702                 :                               visibleKidsOfHiddenElement,
    1703               0 :                               treeMatchContext);
    1704               0 :       NS_UpdateHint(topLevelChange, frameChange);
    1705                 : 
    1706               0 :       if (topLevelChange & nsChangeHint_ReconstructFrame) {
    1707                 :         // If it's going to cause a framechange, then don't bother
    1708                 :         // with the continuations or special siblings since they'll be
    1709                 :         // clobbered by the frame reconstruct anyway.
    1710               0 :         NS_ASSERTION(!frame->GetPrevContinuation(),
    1711                 :                      "continuing frame had more severe impact than first-in-flow");
    1712                 :         return;
    1713                 :       }
    1714                 : 
    1715               0 :       frame = frame->GetNextContinuation();
    1716                 :     } while (frame);
    1717                 : 
    1718                 :     // Might we have special siblings?
    1719               0 :     if (!(frame2->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
    1720                 :       // nothing more to do here
    1721                 :       return;
    1722                 :     }
    1723                 :     
    1724                 :     frame2 = static_cast<nsIFrame*>
    1725               0 :       (propTable->Get(frame2, nsIFrame::IBSplitSpecialSibling()));
    1726               0 :     frame = frame2;
    1727                 :   } while (frame2);
    1728                 : }
    1729                 : 
    1730                 : // Capture state for a given frame.
    1731                 : // Accept a content id here, in some cases we may not have content (scroll position)
    1732                 : void
    1733               0 : nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
    1734                 :                                      nsILayoutHistoryState* aState,
    1735                 :                                      nsIStatefulFrame::SpecialStateID aID)
    1736                 : {
    1737               0 :   if (!aFrame || !aState) {
    1738               0 :     NS_WARNING("null frame, or state");
    1739               0 :     return;
    1740                 :   }
    1741                 : 
    1742                 :   // Only capture state for stateful frames
    1743               0 :   nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
    1744               0 :   if (!statefulFrame) {
    1745               0 :     return;
    1746                 :   }
    1747                 : 
    1748                 :   // Capture the state, exit early if we get null (nothing to save)
    1749               0 :   nsAutoPtr<nsPresState> frameState;
    1750               0 :   nsresult rv = statefulFrame->SaveState(aID, getter_Transfers(frameState));
    1751               0 :   if (!frameState) {
    1752                 :     return;
    1753                 :   }
    1754                 : 
    1755                 :   // Generate the hash key to store the state under
    1756                 :   // Exit early if we get empty key
    1757               0 :   nsCAutoString stateKey;
    1758               0 :   nsIContent* content = aFrame->GetContent();
    1759               0 :   nsIDocument* doc = content ? content->GetCurrentDoc() : nsnull;
    1760               0 :   rv = nsContentUtils::GenerateStateKey(content, doc, aID, stateKey);
    1761               0 :   if(NS_FAILED(rv) || stateKey.IsEmpty()) {
    1762                 :     return;
    1763                 :   }
    1764                 : 
    1765                 :   // Store the state
    1766               0 :   rv = aState->AddState(stateKey, frameState);
    1767               0 :   if (NS_SUCCEEDED(rv)) {
    1768                 :     // aState owns frameState now.
    1769               0 :     frameState.forget();
    1770                 :   }
    1771                 : }
    1772                 : 
    1773                 : void
    1774               0 : nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
    1775                 :                                   nsILayoutHistoryState* aState)
    1776                 : {
    1777               0 :   NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
    1778                 : 
    1779               0 :   CaptureFrameStateFor(aFrame, aState);
    1780                 : 
    1781                 :   // Now capture state recursively for the frame hierarchy rooted at aFrame
    1782               0 :   nsIFrame::ChildListIterator lists(aFrame);
    1783               0 :   for (; !lists.IsDone(); lists.Next()) {
    1784               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    1785               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    1786               0 :       CaptureFrameState(childFrames.get(), aState);
    1787                 :     }
    1788                 :   }
    1789               0 : }
    1790                 : 
    1791                 : // Restore state for a given frame.
    1792                 : // Accept a content id here, in some cases we may not have content (scroll position)
    1793                 : void
    1794               0 : nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
    1795                 :                                      nsILayoutHistoryState* aState,
    1796                 :                                      nsIStatefulFrame::SpecialStateID aID)
    1797                 : {
    1798               0 :   if (!aFrame || !aState) {
    1799               0 :     NS_WARNING("null frame or state");
    1800               0 :     return;
    1801                 :   }
    1802                 : 
    1803                 :   // Only restore state for stateful frames
    1804               0 :   nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
    1805               0 :   if (!statefulFrame) {
    1806               0 :     return;
    1807                 :   }
    1808                 : 
    1809                 :   // Generate the hash key the state was stored under
    1810                 :   // Exit early if we get empty key
    1811               0 :   nsIContent* content = aFrame->GetContent();
    1812                 :   // If we don't have content, we can't generate a hash
    1813                 :   // key and there's probably no state information for us.
    1814               0 :   if (!content) {
    1815               0 :     return;
    1816                 :   }
    1817                 : 
    1818               0 :   nsCAutoString stateKey;
    1819               0 :   nsIDocument* doc = content->GetCurrentDoc();
    1820               0 :   nsresult rv = nsContentUtils::GenerateStateKey(content, doc, aID, stateKey);
    1821               0 :   if (NS_FAILED(rv) || stateKey.IsEmpty()) {
    1822                 :     return;
    1823                 :   }
    1824                 : 
    1825                 :   // Get the state from the hash
    1826                 :   nsPresState *frameState;
    1827               0 :   rv = aState->GetState(stateKey, &frameState);
    1828               0 :   if (!frameState) {
    1829                 :     return;
    1830                 :   }
    1831                 : 
    1832                 :   // Restore it
    1833               0 :   rv = statefulFrame->RestoreState(frameState);
    1834               0 :   if (NS_FAILED(rv)) {
    1835                 :     return;
    1836                 :   }
    1837                 : 
    1838                 :   // If we restore ok, remove the state from the state table
    1839               0 :   aState->RemoveState(stateKey);
    1840                 : }
    1841                 : 
    1842                 : void
    1843               0 : nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
    1844                 :                                   nsILayoutHistoryState* aState)
    1845                 : {
    1846               0 :   NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
    1847                 :   
    1848               0 :   RestoreFrameStateFor(aFrame, aState);
    1849                 : 
    1850                 :   // Now restore state recursively for the frame hierarchy rooted at aFrame
    1851               0 :   nsIFrame::ChildListIterator lists(aFrame);
    1852               0 :   for (; !lists.IsDone(); lists.Next()) {
    1853               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    1854               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    1855               0 :       RestoreFrameState(childFrames.get(), aState);
    1856                 :     }
    1857                 :   }
    1858               0 : }
    1859                 : 
    1860                 : //----------------------------------------------------------------------
    1861                 : 
    1862                 : static PLHashNumber
    1863               0 : HashKey(void* key)
    1864                 : {
    1865               0 :   return NS_PTR_TO_INT32(key);
    1866                 : }
    1867                 : 
    1868                 : static PRIntn
    1869               0 : CompareKeys(void* key1, void* key2)
    1870                 : {
    1871               0 :   return key1 == key2;
    1872                 : }
    1873                 : 
    1874                 : //----------------------------------------------------------------------
    1875                 : 
    1876               0 : nsFrameManagerBase::UndisplayedMap::UndisplayedMap(PRUint32 aNumBuckets)
    1877                 : {
    1878               0 :   MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
    1879                 :   mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey,
    1880                 :                            (PLHashComparator)CompareKeys,
    1881                 :                            (PLHashComparator)nsnull,
    1882               0 :                            nsnull, nsnull);
    1883               0 :   mLastLookup = nsnull;
    1884               0 : }
    1885                 : 
    1886               0 : nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
    1887                 : {
    1888               0 :   MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap);
    1889               0 :   Clear();
    1890               0 :   PL_HashTableDestroy(mTable);
    1891               0 : }
    1892                 : 
    1893                 : PLHashEntry**  
    1894               0 : nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent* aParentContent)
    1895                 : {
    1896               0 :   if (mLastLookup && (aParentContent == (*mLastLookup)->key)) {
    1897               0 :     return mLastLookup;
    1898                 :   }
    1899               0 :   PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
    1900               0 :   PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, aParentContent);
    1901               0 :   if (*entry) {
    1902               0 :     mLastLookup = entry;
    1903                 :   }
    1904               0 :   return entry;
    1905                 : }
    1906                 : 
    1907                 : UndisplayedNode* 
    1908               0 : nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
    1909                 : {
    1910               0 :   PLHashEntry** entry = GetEntryFor(aParentContent);
    1911               0 :   if (*entry) {
    1912               0 :     return (UndisplayedNode*)((*entry)->value);
    1913                 :   }
    1914               0 :   return nsnull;
    1915                 : }
    1916                 : 
    1917                 : void
    1918               0 : nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
    1919                 :                                                   nsIContent* aParentContent)
    1920                 : {
    1921               0 :   PLHashEntry** entry = GetEntryFor(aParentContent);
    1922               0 :   if (*entry) {
    1923               0 :     UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
    1924               0 :     while (node->mNext) {
    1925               0 :       if (node->mContent == aNode->mContent) {
    1926                 :         // We actually need to check this in optimized builds because
    1927                 :         // there are some callers that do this.  See bug 118014, bug
    1928                 :         // 136704, etc.
    1929               0 :         NS_NOTREACHED("node in map twice");
    1930               0 :         delete aNode;
    1931               0 :         return;
    1932                 :       }
    1933               0 :       node = node->mNext;
    1934                 :     }
    1935               0 :     node->mNext = aNode;
    1936                 :   }
    1937                 :   else {
    1938               0 :     PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
    1939               0 :     PL_HashTableRawAdd(mTable, entry, hashCode, aParentContent, aNode);
    1940               0 :     mLastLookup = nsnull; // hashtable may have shifted bucket out from under us
    1941                 :   }
    1942                 : }
    1943                 : 
    1944                 : nsresult 
    1945               0 : nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
    1946                 :                                                nsIContent* aChild, 
    1947                 :                                                nsStyleContext* aStyle)
    1948                 : {
    1949               0 :   UndisplayedNode*  node = new UndisplayedNode(aChild, aStyle);
    1950                 : 
    1951               0 :   AppendNodeFor(node, aParentContent);
    1952               0 :   return NS_OK;
    1953                 : }
    1954                 : 
    1955                 : void
    1956               0 : nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
    1957                 :                                                   UndisplayedNode* aNode)
    1958                 : {
    1959               0 :   PLHashEntry** entry = GetEntryFor(aParentContent);
    1960               0 :   NS_ASSERTION(*entry, "content not in map");
    1961               0 :   if (*entry) {
    1962               0 :     if ((UndisplayedNode*)((*entry)->value) == aNode) {  // first node
    1963               0 :       if (aNode->mNext) {
    1964               0 :         (*entry)->value = aNode->mNext;
    1965               0 :         aNode->mNext = nsnull;
    1966                 :       }
    1967                 :       else {
    1968               0 :         PL_HashTableRawRemove(mTable, entry, *entry);
    1969               0 :         mLastLookup = nsnull; // hashtable may have shifted bucket out from under us
    1970                 :       }
    1971                 :     }
    1972                 :     else {
    1973               0 :       UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
    1974               0 :       while (node->mNext) {
    1975               0 :         if (node->mNext == aNode) {
    1976               0 :           node->mNext = aNode->mNext;
    1977               0 :           aNode->mNext = nsnull;
    1978               0 :           break;
    1979                 :         }
    1980               0 :         node = node->mNext;
    1981                 :       }
    1982                 :     }
    1983                 :   }
    1984               0 :   delete aNode;
    1985               0 : }
    1986                 : 
    1987                 : void
    1988               0 : nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
    1989                 : {
    1990               0 :   PLHashEntry** entry = GetEntryFor(aParentContent);
    1991               0 :   NS_ASSERTION(entry, "content not in map");
    1992               0 :   if (*entry) {
    1993               0 :     UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
    1994               0 :     NS_ASSERTION(node, "null node for non-null entry in UndisplayedMap");
    1995               0 :     delete node;
    1996               0 :     PL_HashTableRawRemove(mTable, entry, *entry);
    1997               0 :     mLastLookup = nsnull; // hashtable may have shifted bucket out from under us
    1998                 :   }
    1999               0 : }
    2000                 : 
    2001                 : static PRIntn
    2002               0 : RemoveUndisplayedEntry(PLHashEntry* he, PRIntn i, void* arg)
    2003                 : {
    2004               0 :   UndisplayedNode*  node = (UndisplayedNode*)(he->value);
    2005               0 :   delete node;
    2006                 :   // Remove and free this entry and continue enumerating
    2007               0 :   return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
    2008                 : }
    2009                 : 
    2010                 : void
    2011               0 : nsFrameManagerBase::UndisplayedMap::Clear(void)
    2012                 : {
    2013               0 :   mLastLookup = nsnull;
    2014               0 :   PL_HashTableEnumerateEntries(mTable, RemoveUndisplayedEntry, 0);
    2015               0 : }

Generated by: LCOV version 1.7