Back to index

lightning-sunbird  0.9+nobinonly
nsDTDUtils.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038        
00039   
00040 #include "nsIAtom.h"
00041 #include "nsDTDUtils.h" 
00042 #include "CNavDTD.h" 
00043 #include "nsIParserNode.h"
00044 #include "nsParserNode.h" 
00045 #include "nsIChannel.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsUnicharUtils.h"
00048 
00049 MOZ_DECL_CTOR_COUNTER(nsEntryStack)
00050 MOZ_DECL_CTOR_COUNTER(nsDTDContext)
00051 MOZ_DECL_CTOR_COUNTER(nsTokenAllocator)
00052 MOZ_DECL_CTOR_COUNTER(CNodeRecycler)
00053  
00054 /**************************************************************************************
00055   A few notes about how residual style handling is performed:
00056    
00057     1. The style stack contains nsTagEntry elements. 
00058     2. Every tag on the containment stack can have it's own residual style stack.
00059     3. When a style leaks, it's mParent member is set to the level on the stack where 
00060        it originated. A node with an mParent of 0 is not opened on tag stack, 
00061        but is open on stylestack.
00062     4. An easy way to tell that a container on the element stack is a residual style tag
00063        is that it's use count is >1.
00064 
00065  **************************************************************************************/
00066 
00067 
00073 nsEntryStack::nsEntryStack()  {
00074 
00075   MOZ_COUNT_CTOR(nsEntryStack);
00076   
00077   mCapacity=0;
00078   mCount=0;
00079   mEntries=0;
00080 }
00081 
00087 nsEntryStack::~nsEntryStack() {
00088 
00089   MOZ_COUNT_DTOR(nsEntryStack);
00090 
00091   if(mEntries) {
00092     //add code here to recycle the node if you have one...  
00093     delete [] mEntries;
00094     mEntries=0;
00095   }
00096 
00097   mCount=mCapacity=0;
00098 }
00099 
00103 void 
00104 nsEntryStack::ReleaseAll(nsNodeAllocator* aNodeAllocator)
00105 {
00106   NS_WARN_IF_FALSE(aNodeAllocator,"no allocator? - potential leak!");
00107 
00108   if(aNodeAllocator) {
00109     NS_WARN_IF_FALSE(mCount >= 0,"count should not be negative");
00110     while(mCount > 0) {
00111       nsCParserNode* node=this->Pop();
00112       IF_FREE(node,aNodeAllocator);
00113     }
00114   }
00115 }
00116 
00121 void nsEntryStack::Empty(void) {
00122   mCount=0;
00123 }
00124 
00125 
00130 void nsEntryStack::EnsureCapacityFor(PRInt32 aNewMax,PRInt32 aShiftOffset) {
00131   if(mCapacity<aNewMax){ 
00132 
00133     const int kDelta=16;
00134 
00135     PRInt32 theSize = kDelta * ((aNewMax / kDelta) + 1);
00136     nsTagEntry* temp=new nsTagEntry[theSize]; 
00137     mCapacity=theSize;
00138 
00139     if(temp){ 
00140       PRInt32 index=0; 
00141       for(index=0;index<mCount;++index) {
00142         temp[aShiftOffset+index]=mEntries[index];
00143       }
00144       if(mEntries) delete [] mEntries;
00145       mEntries=temp;
00146     }
00147     else{
00148       //XXX HACK! This is very bad! We failed to get memory.
00149     }
00150   } //if
00151 }
00152 
00157 void nsEntryStack::Push(nsCParserNode* aNode,
00158                         nsEntryStack* aStyleStack, 
00159                         PRBool aRefCntNode) 
00160 {
00161   if(aNode) {
00162     EnsureCapacityFor(mCount+1);
00163     mEntries[mCount].mTag = (eHTMLTags)aNode->GetNodeType();
00164     if (aRefCntNode) {
00165       aNode->mUseCount++;
00166       mEntries[mCount].mNode = NS_CONST_CAST(nsCParserNode*,aNode);
00167       IF_HOLD(mEntries[mCount].mNode);
00168     }
00169     mEntries[mCount].mParent=aStyleStack;
00170     mEntries[mCount++].mStyles=0;
00171   }
00172 }
00173 
00174 
00180 void nsEntryStack::PushFront(nsCParserNode* aNode,
00181                              nsEntryStack* aStyleStack, 
00182                              PRBool aRefCntNode) 
00183 {
00184   if(aNode) {
00185     if(mCount<mCapacity) {
00186       PRInt32 index=0; 
00187       for(index=mCount;index>0;index--) {
00188         mEntries[index]=mEntries[index-1];
00189       }
00190     }
00191     else {
00192       EnsureCapacityFor(mCount+1,1);
00193     }
00194     mEntries[0].mTag = (eHTMLTags)aNode->GetNodeType();
00195     if (aRefCntNode) {
00196       aNode->mUseCount++;
00197       mEntries[0].mNode = NS_CONST_CAST(nsCParserNode*,aNode);
00198       IF_HOLD(mEntries[0].mNode);
00199     }
00200     mEntries[0].mParent=aStyleStack;
00201     mEntries[0].mStyles=0;
00202     ++mCount;
00203   }
00204 }
00205 
00210 void nsEntryStack::Append(nsEntryStack *aStack) {
00211   if(aStack) {
00212 
00213     PRInt32 theCount=aStack->mCount;
00214 
00215     EnsureCapacityFor(mCount+aStack->mCount,0);
00216 
00217     PRInt32 theIndex=0;
00218     for(theIndex=0;theIndex<theCount;++theIndex){
00219       mEntries[mCount]=aStack->mEntries[theIndex];
00220       mEntries[mCount++].mParent=0;
00221     }
00222   }
00223 } 
00224  
00238 nsCParserNode* nsEntryStack::Remove(PRInt32 anIndex,
00239                                     eHTMLTags aTag) 
00240 {
00241   nsCParserNode* result = 0;
00242   if (0 < mCount && anIndex < mCount){
00243     result = mEntries[anIndex].mNode;
00244     if (result)
00245       result->mUseCount--;
00246     PRInt32 theIndex = 0;
00247     mCount -= 1;
00248     for( theIndex = anIndex; theIndex < mCount; ++theIndex){
00249       mEntries[theIndex] = mEntries[theIndex+1];
00250     }
00251     mEntries[mCount].mNode = 0;
00252     mEntries[mCount].mStyles = 0;
00253     nsEntryStack* theStyleStack = mEntries[anIndex].mParent;
00254     if (theStyleStack) {
00255       //now we have to tell the residual style stack where this tag
00256       //originated that it's no longer in use.
00257       PRUint32 scount = theStyleStack->mCount;
00258       PRUint32 sindex = 0;
00259       nsTagEntry *theStyleEntry=theStyleStack->mEntries;
00260       for (sindex=scount-1;sindex>0;--sindex){            
00261         if (theStyleEntry->mTag==aTag) {
00262           theStyleEntry->mParent=0;  //this tells us that the style is not open at any level
00263           break;
00264         }
00265         ++theStyleEntry;
00266       } //for
00267     }
00268   }
00269   return result;
00270 }
00271 
00277 nsCParserNode* nsEntryStack::Pop(void)
00278 {
00279   nsCParserNode* result = 0;
00280   if (0 < mCount) {
00281     result = mEntries[--mCount].mNode;
00282     if (result)
00283       result->mUseCount--;
00284     mEntries[mCount].mNode = 0;
00285     mEntries[mCount].mStyles = 0;
00286     nsEntryStack* theStyleStack=mEntries[mCount].mParent;
00287     if (theStyleStack) {
00288       //now we have to tell the residual style stack where this tag
00289       //originated that it's no longer in use.
00290       PRUint32 scount = theStyleStack->mCount;
00291 
00292       // XXX If this NS_ENSURE_TRUE fails, it means that the style stack was
00293       //     empty before we were removed.
00294       NS_ENSURE_TRUE(scount != 0, result);
00295 
00296       PRUint32 sindex = 0;
00297       nsTagEntry *theStyleEntry=theStyleStack->mEntries;
00298 
00299       for (sindex=scount-1;sindex>0;--sindex){            
00300         if (theStyleEntry->mTag==mEntries[mCount].mTag) {
00301           theStyleEntry->mParent=0;  //this tells us that the style is not open at any level
00302           break;
00303         }
00304         ++theStyleEntry;
00305       } //for
00306     }
00307   }
00308   return result;
00309 } 
00310 
00316 eHTMLTags nsEntryStack::First() const 
00317 {
00318   eHTMLTags result=eHTMLTag_unknown;
00319   if(0<mCount){
00320     result=mEntries[0].mTag;
00321   }
00322   return result;
00323 }
00324 
00330 nsCParserNode* nsEntryStack::NodeAt(PRInt32 anIndex) const 
00331 {
00332   nsCParserNode* result=0;
00333   if((0<mCount) && (anIndex<mCount)) {
00334     result=mEntries[anIndex].mNode;
00335   }
00336   return result;
00337 }
00338 
00344 eHTMLTags nsEntryStack::TagAt(PRInt32 anIndex) const 
00345 {
00346   eHTMLTags result=eHTMLTag_unknown;
00347   if((0<mCount) && (anIndex<mCount)) {
00348     result=mEntries[anIndex].mTag;
00349   }
00350   return result;
00351 }
00352 
00357 nsTagEntry* nsEntryStack::EntryAt(PRInt32 anIndex) const 
00358 {
00359   nsTagEntry *result=0;
00360   if((0<mCount) && (anIndex<mCount)) {
00361     result=&mEntries[anIndex];
00362   }
00363   return result;
00364 }
00365 
00366 
00372 eHTMLTags nsEntryStack::operator[](PRInt32 anIndex) const 
00373 {
00374   eHTMLTags result=eHTMLTag_unknown;
00375   if((0<mCount) && (anIndex<mCount)) {
00376     result=mEntries[anIndex].mTag;
00377   }
00378   return result;
00379 }
00380 
00381 
00387 eHTMLTags nsEntryStack::Last(void) const 
00388 {
00389   eHTMLTags result=eHTMLTag_unknown;
00390   if(0<mCount) {
00391     result=mEntries[mCount-1].mTag;
00392   }
00393   return result;
00394 }
00395 
00396 nsTagEntry*
00397 nsEntryStack::PopEntry() 
00398 {
00399   nsTagEntry* entry = EntryAt(mCount-1);
00400   this->Pop();
00401   return entry;
00402 }
00403 
00404 void nsEntryStack::PushEntry(nsTagEntry* aEntry, 
00405                              PRBool aRefCntNode) 
00406 {
00407   if (aEntry) {
00408     EnsureCapacityFor(mCount+1);
00409     mEntries[mCount].mNode   = aEntry->mNode;
00410     mEntries[mCount].mTag    = aEntry->mTag;
00411     mEntries[mCount].mParent = aEntry->mParent;
00412     mEntries[mCount].mStyles = aEntry->mStyles;
00413     if (aRefCntNode && mEntries[mCount].mNode) {
00414       mEntries[mCount].mNode->mUseCount++;
00415       IF_HOLD(mEntries[mCount].mNode);
00416     }
00417     mCount++;
00418   }
00419 }
00420 
00421 /***************************************************************
00422   Now define the dtdcontext class
00423  ***************************************************************/
00424 
00425 
00430 nsDTDContext::nsDTDContext() : mStack(), mEntities(0){
00431 
00432   MOZ_COUNT_CTOR(nsDTDContext);
00433   mResidualStyleCount=0;
00434   mContextTopIndex=-1;
00435   mTableStates=0;
00436   mTokenAllocator=0;
00437   mNodeAllocator=0;
00438   mAllBits=0;
00439 
00440 #ifdef DEBUG
00441   memset(mXTags,0,sizeof(mXTags));
00442 #endif
00443 } 
00444  
00449 nsDTDContext::~nsDTDContext() {
00450   MOZ_COUNT_DTOR(nsDTDContext);
00451 
00452   while(mTableStates) {
00453     //pop the current state and restore it's predecessor, if any...
00454     CTableState *theState=mTableStates;      
00455     mTableStates=theState->mPrevious;
00456     delete theState;
00457   }
00458 }
00459 
00460 
00465 PRBool nsDTDContext::HasOpenContainer(eHTMLTags aTag) const {
00466   PRInt32 theIndex=mStack.LastOf(aTag);
00467   return PRBool(-1<theIndex);
00468 }
00469 
00474 void nsDTDContext::Push(nsCParserNode* aNode,
00475                         nsEntryStack* aStyleStack, 
00476                         PRBool aRefCntNode) {
00477   if(aNode) {
00478 #ifdef  NS_DEBUG
00479     eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
00480     int size = mStack.mCount;
00481     if (size < eMaxTags)
00482       mXTags[size] = theTag;
00483 #endif
00484     mStack.Push(aNode, aStyleStack, aRefCntNode);
00485   }
00486 }
00487 
00488 nsTagEntry*
00489 nsDTDContext::PopEntry()
00490 {
00491   PRInt32 theSize = mStack.mCount;
00492   if(0<theSize) {
00493 #ifdef  NS_DEBUG
00494     if (theSize <= eMaxTags)
00495       mXTags[theSize-1]=eHTMLTag_unknown;
00496 #endif
00497     return mStack.PopEntry();
00498   }
00499   return 0;
00500 }
00501 
00502 void nsDTDContext::PushEntry(nsTagEntry* aEntry, 
00503                              PRBool aRefCntNode)
00504 {
00505 #ifdef  NS_DEBUG
00506     int size=mStack.mCount;
00507     if(size< eMaxTags && aEntry)
00508       mXTags[size]=aEntry->mTag;
00509 #endif
00510     mStack.PushEntry(aEntry, aRefCntNode);
00511 }
00512 
00513 /* This method will move the top entires, in the entry-stack, into dest context.
00514  * @param aDest  - Destination context for the entries.
00515  * @param aCount - Number of entries, on top of the entry-stack, to be moved.
00516  */
00517 void 
00518 nsDTDContext::MoveEntries(nsDTDContext& aDest,
00519                           PRInt32 aCount)
00520 {
00521   NS_ASSERTION(aCount > 0 && mStack.mCount >= aCount, "cannot move entries");
00522   if (aCount > 0 && mStack.mCount >= aCount) {
00523     while (aCount) {
00524       aDest.PushEntry(&mStack.mEntries[--mStack.mCount], PR_FALSE);
00525 #ifdef  NS_DEBUG
00526       mXTags[mStack.mCount] = eHTMLTag_unknown;
00527 #endif
00528       --aCount;
00529     }
00530   }
00531 }
00532 
00537 nsCParserNode* nsDTDContext::Pop(nsEntryStack *&aChildStyleStack) {
00538 
00539   PRInt32         theSize=mStack.mCount;
00540   nsCParserNode*  result=0;
00541 
00542   if(0<theSize) {
00543 
00544 #ifdef  NS_DEBUG
00545     if ((theSize>0) && (theSize <= eMaxTags))
00546       mXTags[theSize-1]=eHTMLTag_unknown;
00547 #endif
00548 
00549 
00550     nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
00551     if(theEntry) {
00552       aChildStyleStack=theEntry->mStyles;
00553     }
00554 
00555     result=mStack.Pop();
00556     theEntry->mParent=0;
00557   }
00558 
00559   return result;
00560 }
00561  
00567 nsCParserNode* nsDTDContext::Pop() {
00568   nsEntryStack   *theTempStyleStack=0; // This has no use here...
00569   return Pop(theTempStyleStack);
00570 }
00571 
00576 eHTMLTags nsDTDContext::First(void) const {
00577   return mStack.First();
00578 }
00579 
00584 eHTMLTags nsDTDContext::TagAt(PRInt32 anIndex) const {
00585   return mStack.TagAt(anIndex);
00586 }
00587 
00592 nsTagEntry* nsDTDContext::LastEntry(void) const {
00593   return mStack.EntryAt(mStack.mCount-1);
00594 }
00595 
00600 eHTMLTags nsDTDContext::Last() const {
00601   return mStack.Last();
00602 }
00603 
00604 
00609 nsEntryStack* nsDTDContext::GetStylesAt(PRInt32 anIndex) const {
00610   nsEntryStack* result=0;
00611 
00612   if(anIndex<mStack.mCount){
00613     nsTagEntry* theEntry=mStack.EntryAt(anIndex);
00614     if(theEntry) {
00615       result=theEntry->mStyles;
00616     }
00617   }
00618   return result;
00619 }
00620 
00621 
00626 void nsDTDContext::PushStyle(nsCParserNode* aNode){
00627 
00628   nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
00629   if(theEntry ) {
00630     nsEntryStack* theStack=theEntry->mStyles;
00631     if(!theStack) {
00632       theStack=theEntry->mStyles=new nsEntryStack();
00633     }
00634     if(theStack) {
00635       theStack->Push(aNode);
00636       ++mResidualStyleCount;
00637     }
00638   } //if
00639 }
00640 
00641 
00648 void nsDTDContext::PushStyles(nsEntryStack *aStyles){
00649 
00650   if(aStyles) {
00651     nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
00652     if(theEntry ) {
00653       nsEntryStack* theStyles=theEntry->mStyles;
00654       if(!theStyles) {
00655         theEntry->mStyles=aStyles;
00656 
00657         PRUint32 scount=aStyles->mCount;
00658         PRUint32 sindex=0;
00659 
00660         theEntry=aStyles->mEntries;
00661         for(sindex=0;sindex<scount;++sindex){            
00662           theEntry->mParent=0;  //this tells us that the style is not open at any level
00663           ++theEntry;
00664           ++mResidualStyleCount;
00665         } //for
00666 
00667       }
00668       else {
00669         theStyles->Append(aStyles);
00670         //  Delete aStyles since it has been copied to theStyles...
00671         delete aStyles;
00672         aStyles=0;
00673       }
00674     } //if(theEntry )
00675     else if(mStack.mCount==0) {
00676       // If you're here it means that we have hit the rock bottom
00677       // ,of the stack, and there's no need to handle anymore styles.
00678       // Fix for bug 29048
00679       IF_DELETE(aStyles,mNodeAllocator);
00680     }
00681   }//if(aStyles)
00682 }
00683 
00684 
00689 nsCParserNode* nsDTDContext::PopStyle(void){
00690   nsCParserNode *result=0;
00691 
00692   nsTagEntry *theEntry=mStack.EntryAt(mStack.mCount-1);
00693   if(theEntry && (theEntry->mNode)) {
00694     nsEntryStack* theStyleStack=theEntry->mParent;
00695     if(theStyleStack){
00696       result=theStyleStack->Pop();
00697       mResidualStyleCount--;
00698     }
00699   } //if
00700   return result;
00701 }
00702 
00707 nsCParserNode* nsDTDContext::PopStyle(eHTMLTags aTag){
00708 
00709   PRInt32 theLevel=0;
00710   nsCParserNode* result=0;
00711 
00712   for(theLevel=mStack.mCount-1;theLevel>0;theLevel--) {
00713     nsEntryStack *theStack=mStack.mEntries[theLevel].mStyles;
00714     if(theStack) {
00715       if(aTag==theStack->Last()) {
00716         result=theStack->Pop();
00717         mResidualStyleCount--;
00718         break; // Fix bug 50710 - Stop after finding a style.
00719       } else {
00720         // NS_ERROR("bad residual style entry");
00721       }
00722     } 
00723   }
00724 
00725   return result;
00726 }
00727 
00736 void nsDTDContext::RemoveStyle(eHTMLTags aTag){
00737   
00738   PRInt32 theLevel=mStack.mCount;
00739   
00740   while (theLevel) {
00741     nsEntryStack *theStack=GetStylesAt(--theLevel);
00742     if (theStack) {
00743       PRInt32 index=theStack->mCount;
00744       while (index){
00745         nsTagEntry *theEntry=theStack->EntryAt(--index);
00746         if (aTag==(eHTMLTags)theEntry->mNode->GetNodeType()) {
00747           mResidualStyleCount--;
00748           nsCParserNode* result=theStack->Remove(index,aTag);
00749           IF_FREE(result, mNodeAllocator);  
00750           return;
00751         } 
00752       }
00753     } 
00754   }
00755 }
00756 
00762 void nsDTDContext::ReleaseGlobalObjects(void){
00763 }
00764 
00765 
00766 /**************************************************************
00767   Now define the nsTokenAllocator class...
00768  **************************************************************/
00769 
00770 static const size_t  kTokenBuckets[]       ={sizeof(CStartToken),sizeof(CAttributeToken),sizeof(CCommentToken),sizeof(CEndToken)};
00771 static const PRInt32 kNumTokenBuckets      = sizeof(kTokenBuckets) / sizeof(size_t);
00772 static const PRInt32 kInitialTokenPoolSize = NS_SIZE_IN_HEAP(sizeof(CToken)) * 200;
00773 
00779 nsTokenAllocator::nsTokenAllocator() {
00780 
00781   MOZ_COUNT_CTOR(nsTokenAllocator);
00782 
00783   mArenaPool.Init("TokenPool", kTokenBuckets, kNumTokenBuckets, kInitialTokenPoolSize);
00784 
00785 #ifdef NS_DEBUG
00786   int i=0;
00787   for(i=0;i<eToken_last-1;++i) {
00788     mTotals[i]=0;
00789   }
00790 #endif
00791 
00792 }
00793 
00798 nsTokenAllocator::~nsTokenAllocator() {
00799 
00800   MOZ_COUNT_DTOR(nsTokenAllocator);
00801 
00802 }
00803 
00804 class CTokenFinder: public nsDequeFunctor{
00805 public:
00806   CTokenFinder(CToken* aToken) {mToken=aToken;}
00807   virtual void* operator()(void* anObject) {
00808     if(anObject==mToken) {
00809       return anObject;
00810     }
00811     return 0;
00812   }
00813   CToken* mToken;
00814 };
00815 
00826 CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsAString& aString) {
00827 
00828   CToken* result=0;
00829 
00830 #ifdef  NS_DEBUG
00831     mTotals[aType-1]++;
00832 #endif
00833   switch(aType){
00834     case eToken_start:            result=new(mArenaPool) CStartToken(aString, aTag); break;
00835     case eToken_end:              result=new(mArenaPool) CEndToken(aString, aTag); break;
00836     case eToken_comment:          result=new(mArenaPool) CCommentToken(aString); break;
00837     case eToken_entity:           result=new(mArenaPool) CEntityToken(aString); break;
00838     case eToken_whitespace:       result=new(mArenaPool) CWhitespaceToken(aString); break;
00839     case eToken_newline:          result=new(mArenaPool) CNewlineToken(); break;
00840     case eToken_text:             result=new(mArenaPool) CTextToken(aString); break;
00841     case eToken_attribute:        result=new(mArenaPool) CAttributeToken(aString); break;
00842     case eToken_instruction:      result=new(mArenaPool) CInstructionToken(aString); break;
00843     case eToken_cdatasection:     result=new(mArenaPool) CCDATASectionToken(aString); break;
00844     case eToken_doctypeDecl:      result=new(mArenaPool) CDoctypeDeclToken(aString); break;
00845     case eToken_markupDecl:       result=new(mArenaPool) CMarkupDeclToken(aString); break;
00846       default:
00847         NS_ASSERTION(PR_FALSE, "nsDTDUtils::CreateTokenOfType: illegal token type"); 
00848         break;
00849   }
00850 
00851   return result;
00852 }
00853 
00863 CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag) {
00864 
00865   CToken* result=0;
00866 
00867 #ifdef  NS_DEBUG
00868     mTotals[aType-1]++;
00869 #endif
00870   switch(aType){
00871     case eToken_start:            result=new(mArenaPool) CStartToken(aTag); break;
00872     case eToken_end:              result=new(mArenaPool) CEndToken(aTag); break;
00873     case eToken_comment:          result=new(mArenaPool) CCommentToken(); break;
00874     case eToken_attribute:        result=new(mArenaPool) CAttributeToken(); break;
00875     case eToken_entity:           result=new(mArenaPool) CEntityToken(); break;
00876     case eToken_whitespace:       result=new(mArenaPool) CWhitespaceToken(); break;
00877     case eToken_newline:          result=new(mArenaPool) CNewlineToken(); break;
00878     case eToken_text:             result=new(mArenaPool) CTextToken(); break;
00879     case eToken_instruction:      result=new(mArenaPool) CInstructionToken(); break;
00880     case eToken_cdatasection:     result=new(mArenaPool) CCDATASectionToken(aTag); break;
00881     case eToken_doctypeDecl:      result=new(mArenaPool) CDoctypeDeclToken(aTag); break;
00882     case eToken_markupDecl:       result=new(mArenaPool) CMarkupDeclToken(); break;
00883     default:
00884       NS_ASSERTION(PR_FALSE, "nsDTDUtils::CreateTokenOfType: illegal token type"); 
00885       break;
00886    }
00887 
00888   return result;
00889 }
00890 
00891 #ifdef DEBUG_TRACK_NODES 
00892 
00893 static nsCParserNode* gAllNodes[100];
00894 static int gAllNodeCount=0;
00895 
00896 int FindNode(nsCParserNode *aNode) {
00897   int theIndex=0;
00898   for(theIndex=0;theIndex<gAllNodeCount;++theIndex) {
00899     if(gAllNodes[theIndex]==aNode) {
00900       return theIndex;
00901     }
00902   }
00903   return -1;
00904 }
00905 
00906 void AddNode(nsCParserNode *aNode) {
00907   if(-1==FindNode(aNode)) {
00908     gAllNodes[gAllNodeCount++]=aNode;
00909   }
00910   else {
00911     //you tried to recycle a node twice!
00912   }
00913 }
00914 
00915 void RemoveNode(nsCParserNode *aNode) {
00916   int theIndex=FindNode(aNode);
00917   if(-1<theIndex) {
00918     gAllNodes[theIndex]=gAllNodes[--gAllNodeCount];
00919   }
00920 }
00921 
00922 #endif 
00923 
00924 
00925 #ifdef HEAP_ALLOCATED_NODES
00926 nsNodeAllocator::nsNodeAllocator():mSharedNodes(0){
00927 #ifdef DEBUG_TRACK_NODES
00928   mCount=0;
00929 #endif
00930 #else 
00931   static const size_t  kNodeBuckets[]       = { sizeof(nsCParserNode), sizeof(nsCParserStartNode) };
00932   static const PRInt32 kNumNodeBuckets      = sizeof(kNodeBuckets) / sizeof(size_t);
00933   static const PRInt32 kInitialNodePoolSize = NS_SIZE_IN_HEAP(sizeof(nsCParserNode)) * 35; // optimal size based on space-trace data
00934 nsNodeAllocator::nsNodeAllocator() {
00935   mNodePool.Init("NodePool", kNodeBuckets, kNumNodeBuckets, kInitialNodePoolSize);
00936 #endif
00937   MOZ_COUNT_CTOR(nsNodeAllocator);
00938 }
00939   
00940 nsNodeAllocator::~nsNodeAllocator() {
00941   MOZ_COUNT_DTOR(nsNodeAllocator);
00942 
00943 #ifdef HEAP_ALLOCATED_NODES
00944   nsCParserNode* theNode = 0;
00945 
00946   while((theNode=(nsCParserNode*)mSharedNodes.Pop())){
00947 #ifdef DEBUG_TRACK_NODES
00948     RemoveNode(theNode);
00949 #endif
00950     ::operator delete(theNode); 
00951     theNode=nsnull;
00952   }
00953 #ifdef DEBUG_TRACK_NODES
00954   if(mCount) {
00955     printf("**************************\n");
00956     printf("%i out of %i nodes leaked!\n",gAllNodeCount,mCount);
00957     printf("**************************\n");
00958   }
00959 #endif
00960 #endif
00961 }
00962   
00963 nsCParserNode* nsNodeAllocator::CreateNode(CToken* aToken,  
00964                                            nsTokenAllocator* aTokenAllocator) 
00965 {
00966   nsCParserNode* result = 0;
00967 #ifdef HEAP_ALLOCATED_NODES
00968 #if 0
00969   if(gAllNodeCount!=mSharedNodes.GetSize()) {
00970     int x=10; //this is very BAD!
00971   }
00972 #endif
00973   result = NS_STATIC_CAST(nsCParserNode*,mSharedNodes.Pop());
00974   if (result) {
00975     result->Init(aToken, aTokenAllocator,this);
00976   }
00977   else{
00978     result = nsCParserNode::Create(aToken, aTokenAllocator,this);
00979 #ifdef DEBUG_TRACK_NODES
00980     ++mCount;
00981     AddNode(NS_STATIC_CAST(nsCParserNode*,result));
00982 #endif
00983     IF_HOLD(result);
00984   }
00985 #else
00986   eHTMLTokenTypes type = aToken ? eHTMLTokenTypes(aToken->GetTokenType()) : eToken_unknown;
00987   switch (type) {
00988     case eToken_start:
00989       result = nsCParserStartNode::Create(aToken, aTokenAllocator,this); 
00990       break;
00991     default :
00992       result = nsCParserNode::Create(aToken, aTokenAllocator,this); 
00993       break;
00994   }
00995   IF_HOLD(result);
00996 #endif
00997   return result;
00998 }
00999 
01000 #ifdef DEBUG
01001 void DebugDumpContainmentRules(nsIDTD& theDTD,const char* aFilename,const char* aTitle) {
01002 }
01003 #endif
01004 
01005 /**************************************************************
01006   This defines the topic object used by the observer service.
01007   The observerService uses a list of these, 1 per topic when
01008   registering tags.
01009  **************************************************************/
01010 NS_IMPL_ISUPPORTS1(nsObserverEntry, nsIObserverEntry)
01011 
01012 nsObserverEntry::nsObserverEntry(const nsAString& aTopic) : mTopic(aTopic) 
01013 {
01014   memset(mObservers, 0, sizeof(mObservers));
01015 }
01016 
01017 nsObserverEntry::~nsObserverEntry() {
01018   for (PRInt32 i = 0; i <= NS_HTML_TAG_MAX; ++i){
01019     if (mObservers[i]) {
01020       PRInt32 count = mObservers[i]->Count();
01021       for (PRInt32 j = 0; j < count; ++j) {
01022         nsISupports* obs = (nsISupports*)mObservers[i]->ElementAt(j);
01023         NS_IF_RELEASE(obs);
01024       }
01025       delete mObservers[i];
01026     }
01027   }
01028 }
01029 
01030 NS_IMETHODIMP
01031 nsObserverEntry::Notify(nsIParserNode* aNode,
01032                         nsIParser* aParser,
01033                         nsISupports* aWebShell,
01034                         const PRUint32 aFlags) 
01035 {
01036   NS_ENSURE_ARG_POINTER(aNode);
01037   NS_ENSURE_ARG_POINTER(aParser);
01038 
01039   nsresult result = NS_OK;
01040   eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
01041  
01042   if (theTag <= NS_HTML_TAG_MAX) {
01043     nsVoidArray*  theObservers = mObservers[theTag];
01044     if (theObservers) {
01045       PRInt32   theCharsetSource;
01046       nsCAutoString      charset;
01047       aParser->GetDocumentCharset(charset,theCharsetSource);
01048       NS_ConvertASCIItoUCS2 theCharsetValue(charset);
01049 
01050       PRInt32 theAttrCount = aNode->GetAttributeCount(); 
01051       PRInt32 theObserversCount = theObservers->Count(); 
01052       if (0 < theObserversCount){
01053         nsStringArray keys(theAttrCount+4), values(theAttrCount+4);
01054 
01055         // XXX this and the following code may be a performance issue.
01056         // Every key and value is copied and added to an voidarray (causing at
01057         // least 2 allocations for mImpl, usually more, plus at least 1 per
01058         // string (total = 2*(keys+3) + 2(or more) array allocations )).
01059         PRInt32 index;
01060         for (index = 0; index < theAttrCount; ++index) {
01061           keys.AppendString(aNode->GetKeyAt(index));
01062           values.AppendString(aNode->GetValueAt(index));
01063         } 
01064 
01065         nsAutoString intValue;
01066 
01067         keys.AppendString(NS_LITERAL_STRING("charset")); 
01068         values.AppendString(theCharsetValue);       
01069       
01070         keys.AppendString(NS_LITERAL_STRING("charsetSource")); 
01071         intValue.AppendInt(PRInt32(theCharsetSource),10);
01072         values.AppendString(intValue); 
01073 
01074         keys.AppendString(NS_LITERAL_STRING("X_COMMAND"));
01075         values.AppendString(NS_LITERAL_STRING("text/html")); 
01076 
01077         nsCOMPtr<nsIChannel> channel;
01078         aParser->GetChannel(getter_AddRefs(channel));
01079 
01080         for (index=0;index<theObserversCount;++index) {
01081           nsIElementObserver* observer = NS_STATIC_CAST(nsIElementObserver*,theObservers->ElementAt(index));
01082           if (observer) {
01083             result = observer->Notify(aWebShell, channel,
01084                                       nsHTMLTags::GetStringValue(theTag),
01085                                       &keys, &values, aFlags);
01086             if (NS_FAILED(result)) {
01087               break;
01088             }
01089 
01090             if (result == NS_HTMLPARSER_VALID_META_CHARSET) {
01091               // Inform the parser that this meta tag contained a valid
01092               // charset. See bug 272815
01093               aParser->SetDocumentCharset(charset, kCharsetFromMetaTag);
01094               result = NS_OK;
01095             }
01096           }
01097         } 
01098       } 
01099     }
01100   }
01101   return result;
01102 }
01103 
01104 PRBool 
01105 nsObserverEntry::Matches(const nsAString& aString) {
01106   PRBool result = aString.Equals(mTopic);
01107   return result;
01108 }
01109 
01110 nsresult
01111 nsObserverEntry::AddObserver(nsIElementObserver *aObserver,
01112                              eHTMLTags aTag) 
01113 {
01114   if (aObserver) {
01115     if (!mObservers[aTag]) {
01116       mObservers[aTag] = new nsAutoVoidArray();
01117       if (!mObservers[aTag]) {
01118         return NS_ERROR_OUT_OF_MEMORY;
01119       }
01120     }
01121     NS_ADDREF(aObserver);
01122     mObservers[aTag]->AppendElement(aObserver);
01123   }
01124   return NS_OK;
01125 }
01126 
01127 void 
01128 nsObserverEntry::RemoveObserver(nsIElementObserver *aObserver)
01129 {
01130   for (PRInt32 i=0; i <= NS_HTML_TAG_MAX; ++i){
01131     if (mObservers[i]) {
01132       nsISupports* obs = aObserver;
01133       PRBool removed = mObservers[i]->RemoveElement(obs);
01134       if (removed) {
01135         NS_RELEASE(obs);
01136       }
01137     }
01138   }
01139 }