PageRenderTime 87ms CodeModel.GetById 10ms app.highlight 70ms RepoModel.GetById 1ms app.codeStats 1ms

/parser/htmlparser/src/nsDTDUtils.cpp

http://github.com/zpao/v8monkey
C++ | 1028 lines | 644 code | 124 blank | 260 comment | 98 complexity | 73184584e2cc87ecb819faaf71208895 MD5 | raw file
   1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   2/* vim: set ts=2 sw=2 et tw=80: */
   3/* ***** BEGIN LICENSE BLOCK *****
   4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   5 *
   6 * The contents of this file are subject to the Mozilla Public License Version
   7 * 1.1 (the "License"); you may not use this file except in compliance with
   8 * the License. You may obtain a copy of the License at
   9 * http://www.mozilla.org/MPL/
  10 *
  11 * Software distributed under the License is distributed on an "AS IS" basis,
  12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13 * for the specific language governing rights and limitations under the
  14 * License.
  15 *
  16 * The Original Code is mozilla.org code.
  17 *
  18 * The Initial Developer of the Original Code is
  19 * Netscape Communications Corporation.
  20 * Portions created by the Initial Developer are Copyright (C) 1998
  21 * the Initial Developer. All Rights Reserved.
  22 *
  23 * Contributor(s):
  24 *   Pierre Phaneuf <pp@ludusdesign.com>
  25 *
  26 * Alternatively, the contents of this file may be used under the terms of
  27 * either of the GNU General Public License Version 2 or later (the "GPL"),
  28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29 * in which case the provisions of the GPL or the LGPL are applicable instead
  30 * of those above. If you wish to allow use of your version of this file only
  31 * under the terms of either the GPL or the LGPL, and not to allow others to
  32 * use your version of this file under the terms of the MPL, indicate your
  33 * decision by deleting the provisions above and replace them with the notice
  34 * and other provisions required by the GPL or the LGPL. If you do not delete
  35 * the provisions above, a recipient may use your version of this file under
  36 * the terms of any one of the MPL, the GPL or the LGPL.
  37 *
  38 * ***** END LICENSE BLOCK ***** */
  39       
  40  
  41#include "nsIAtom.h"
  42#include "nsDTDUtils.h" 
  43#include "CNavDTD.h" 
  44#include "nsIParserNode.h"
  45#include "nsParserNode.h" 
  46#include "nsIChannel.h"
  47#include "nsIServiceManager.h"
  48#include "nsUnicharUtils.h"
  49
  50/**************************************************************************************
  51  A few notes about how residual style handling is performed:
  52   
  53    1. The style stack contains nsTagEntry elements. 
  54    2. Every tag on the containment stack can have it's own residual style stack.
  55    3. When a style leaks, it's mParent member is set to the level on the stack where 
  56       it originated. A node with an mParent of 0 is not opened on tag stack, 
  57       but is open on stylestack.
  58    4. An easy way to tell that a container on the element stack is a residual style tag
  59       is that it's use count is >1.
  60
  61 **************************************************************************************/
  62
  63
  64/**
  65 * Default constructor
  66 * @update	harishd 04/04/99
  67 * @update  gess 04/22/99
  68 */
  69nsEntryStack::nsEntryStack()  {
  70
  71  MOZ_COUNT_CTOR(nsEntryStack);
  72  
  73  mCapacity=0;
  74  mCount=0;
  75  mEntries=0;
  76}
  77
  78/**
  79 * Default destructor
  80 * @update  harishd 04/04/99
  81 * @update  gess 04/22/99
  82 */
  83nsEntryStack::~nsEntryStack() {
  84
  85  MOZ_COUNT_DTOR(nsEntryStack);
  86
  87  if(mEntries) {
  88    //add code here to recycle the node if you have one...  
  89    delete [] mEntries;
  90    mEntries=0;
  91  }
  92
  93  mCount=mCapacity=0;
  94}
  95
  96/**
  97 * Release all objects in the entry stack
  98 */
  99void 
 100nsEntryStack::ReleaseAll(nsNodeAllocator* aNodeAllocator)
 101{
 102  NS_ASSERTION(aNodeAllocator,"no allocator? - potential leak!");
 103
 104  if(aNodeAllocator) {
 105    NS_ASSERTION(mCount >= 0,"count should not be negative");
 106    while(mCount > 0) {
 107      nsCParserNode* node=this->Pop();
 108      IF_FREE(node,aNodeAllocator);
 109    }
 110  }
 111}
 112
 113/**
 114 * Resets state of stack to be empty.
 115 * @update harishd 04/04/99
 116 */
 117void nsEntryStack::Empty(void) {
 118  mCount=0;
 119}
 120
 121
 122/**
 123 * 
 124 * @update  gess 04/22/99
 125 */
 126void nsEntryStack::EnsureCapacityFor(PRInt32 aNewMax,PRInt32 aShiftOffset) {
 127  if(mCapacity<aNewMax){ 
 128
 129    const int kDelta=16;
 130
 131    PRInt32 theSize = kDelta * ((aNewMax / kDelta) + 1);
 132    nsTagEntry* temp=new nsTagEntry[theSize]; 
 133    mCapacity=theSize;
 134
 135    if(temp){ 
 136      PRInt32 index=0; 
 137      for(index=0;index<mCount;++index) {
 138        temp[aShiftOffset+index]=mEntries[index];
 139      }
 140      if(mEntries) delete [] mEntries;
 141      mEntries=temp;
 142    }
 143    else{
 144      //XXX HACK! This is very bad! We failed to get memory.
 145    }
 146  } //if
 147}
 148
 149/**
 150 * 
 151 * @update  gess 04/22/99
 152 */
 153void nsEntryStack::Push(nsCParserNode* aNode,
 154                        nsEntryStack* aStyleStack, 
 155                        bool aRefCntNode) 
 156{
 157  if(aNode) {
 158    EnsureCapacityFor(mCount+1);
 159    mEntries[mCount].mTag = (eHTMLTags)aNode->GetNodeType();
 160    if (aRefCntNode) {
 161      aNode->mUseCount++;
 162      mEntries[mCount].mNode = const_cast<nsCParserNode*>(aNode);
 163      IF_HOLD(mEntries[mCount].mNode);
 164    }
 165    mEntries[mCount].mParent=aStyleStack;
 166    mEntries[mCount++].mStyles=0;
 167  }
 168}
 169
 170void nsEntryStack::PushTag(eHTMLTags aTag)
 171{
 172  EnsureCapacityFor(mCount + 1);
 173  mEntries[mCount].mTag = aTag;
 174  mEntries[mCount].mParent = nsnull;
 175  mEntries[mCount].mStyles = nsnull;
 176  ++mCount;
 177}
 178
 179
 180/**
 181 * This method inserts the given node onto the front of this stack
 182 *
 183 * @update  gess 11/10/99
 184 */
 185void nsEntryStack::PushFront(nsCParserNode* aNode,
 186                             nsEntryStack* aStyleStack, 
 187                             bool aRefCntNode) 
 188{
 189  if(aNode) {
 190    if(mCount<mCapacity) {
 191      PRInt32 index=0; 
 192      for(index=mCount;index>0;index--) {
 193        mEntries[index]=mEntries[index-1];
 194      }
 195    }
 196    else {
 197      EnsureCapacityFor(mCount+1,1);
 198    }
 199    mEntries[0].mTag = (eHTMLTags)aNode->GetNodeType();
 200    if (aRefCntNode) {
 201      aNode->mUseCount++;
 202      mEntries[0].mNode = const_cast<nsCParserNode*>(aNode);
 203      IF_HOLD(mEntries[0].mNode);
 204    }
 205    mEntries[0].mParent=aStyleStack;
 206    mEntries[0].mStyles=0;
 207    ++mCount;
 208  }
 209}
 210
 211/**
 212 * 
 213 * @update  gess 11/10/99
 214 */
 215void nsEntryStack::Append(nsEntryStack *aStack) {
 216  if(aStack) {
 217
 218    PRInt32 theCount=aStack->mCount;
 219
 220    EnsureCapacityFor(mCount+aStack->mCount,0);
 221
 222    PRInt32 theIndex=0;
 223    for(theIndex=0;theIndex<theCount;++theIndex){
 224      mEntries[mCount]=aStack->mEntries[theIndex];
 225      mEntries[mCount++].mParent=0;
 226    }
 227  }
 228} 
 229 
 230/**
 231 * This method removes the node for the given tag
 232 * from anywhere within this entry stack, and shifts
 233 * other entries down.
 234 * 
 235 * NOTE: It's odd to be removing an element from the middle
 236 *       of a stack, but it's necessary because of how MALFORMED
 237 *       html can be. 
 238 * 
 239 * anIndex: the index within the stack of the tag to be removed
 240 * aTag: the id of the tag to be removed
 241 * @update  gess 02/25/00
 242 */
 243nsCParserNode* nsEntryStack::Remove(PRInt32 anIndex,
 244                                    eHTMLTags aTag) 
 245{
 246  nsCParserNode* result = 0;
 247  if (0 < mCount && anIndex < mCount){
 248    result = mEntries[anIndex].mNode;
 249    if (result)
 250      result->mUseCount--;
 251    PRInt32 theIndex = 0;
 252    mCount -= 1;
 253    for( theIndex = anIndex; theIndex < mCount; ++theIndex){
 254      mEntries[theIndex] = mEntries[theIndex+1];
 255    }
 256    mEntries[mCount].mNode = 0;
 257    mEntries[mCount].mStyles = 0;
 258    nsEntryStack* theStyleStack = mEntries[anIndex].mParent;
 259    if (theStyleStack) {
 260      //now we have to tell the residual style stack where this tag
 261      //originated that it's no longer in use.
 262      PRUint32 scount = theStyleStack->mCount;
 263#ifdef DEBUG_mrbkap
 264      NS_ASSERTION(scount != 0, "RemoveStyles has a bad style stack");
 265#endif
 266      nsTagEntry *theStyleEntry = theStyleStack->mEntries;
 267      for (PRUint32 sindex = scount-1;; --sindex) {            
 268        if (theStyleEntry->mTag == aTag) {
 269          // This tells us that the style is not open at any level.
 270          theStyleEntry->mParent = nsnull;
 271          break;
 272        }
 273        if (sindex == 0) {
 274#ifdef DEBUG_mrbkap
 275          NS_ERROR("Couldn't find the removed style on its parent stack");
 276#endif
 277          break;
 278        }
 279        ++theStyleEntry;
 280      }
 281    }
 282  }
 283  return result;
 284}
 285
 286/**
 287 * Pops an entry from this style stack. If the entry has a parent stack, it
 288 * updates the entry so that we know not to try to remove it from the parent
 289 * stack since it's no longer open.
 290 */
 291nsCParserNode* nsEntryStack::Pop(void)
 292{
 293  nsCParserNode* result = 0;
 294  if (0 < mCount) {
 295    result = mEntries[--mCount].mNode;
 296    if (result)
 297      result->mUseCount--;
 298    mEntries[mCount].mNode = 0;
 299    mEntries[mCount].mStyles = 0;
 300    nsEntryStack* theStyleStack = mEntries[mCount].mParent;
 301    if (theStyleStack) {
 302      //now we have to tell the residual style stack where this tag
 303      //originated that it's no longer in use.
 304      PRUint32 scount = theStyleStack->mCount;
 305
 306      // XXX If this NS_ENSURE_TRUE fails, it means that the style stack was
 307      //     empty before we were removed.
 308#ifdef DEBUG_mrbkap
 309      NS_ASSERTION(scount != 0, "preventing a potential crash.");
 310#endif
 311      NS_ENSURE_TRUE(scount != 0, result);
 312
 313      nsTagEntry *theStyleEntry = theStyleStack->mEntries;
 314      for (PRUint32 sindex = scount - 1;; --sindex) {
 315        if (theStyleEntry->mTag == mEntries[mCount].mTag) {
 316          // This tells us that the style is not open at any level
 317          theStyleEntry->mParent = nsnull;
 318          break;
 319        }
 320        if (sindex == 0) {
 321#ifdef DEBUG_mrbkap
 322          NS_ERROR("Couldn't find the removed style on its parent stack");
 323#endif
 324          break;
 325        }
 326        ++theStyleEntry;
 327      }
 328    }
 329  }
 330  return result;
 331} 
 332
 333/**
 334 * 
 335 * @update  harishd 04/04/99
 336 * @update  gess 04/21/99
 337 */
 338eHTMLTags nsEntryStack::First() const 
 339{
 340  eHTMLTags result=eHTMLTag_unknown;
 341  if(0<mCount){
 342    result=mEntries[0].mTag;
 343  }
 344  return result;
 345}
 346
 347/**
 348 * 
 349 * @update  harishd 04/04/99
 350 * @update  gess 04/21/99
 351 */
 352nsCParserNode* nsEntryStack::NodeAt(PRInt32 anIndex) const 
 353{
 354  nsCParserNode* result=0;
 355  if((0<mCount) && (anIndex<mCount)) {
 356    result=mEntries[anIndex].mNode;
 357  }
 358  return result;
 359}
 360
 361/**
 362 * 
 363 * @update  harishd 04/04/99
 364 * @update  gess 04/21/99
 365 */
 366eHTMLTags nsEntryStack::TagAt(PRInt32 anIndex) const 
 367{
 368  eHTMLTags result=eHTMLTag_unknown;
 369  if((0<mCount) && (anIndex<mCount)) {
 370    result=mEntries[anIndex].mTag;
 371  }
 372  return result;
 373}
 374
 375/**
 376 * 
 377 * @update  gess 04/21/99
 378 */
 379nsTagEntry* nsEntryStack::EntryAt(PRInt32 anIndex) const 
 380{
 381  nsTagEntry *result=0;
 382  if((0<mCount) && (anIndex<mCount)) {
 383    result=&mEntries[anIndex];
 384  }
 385  return result;
 386}
 387
 388
 389/**
 390 * 
 391 * @update  harishd 04/04/99
 392 * @update  gess 04/21/99
 393 */
 394eHTMLTags nsEntryStack::operator[](PRInt32 anIndex) const 
 395{
 396  eHTMLTags result=eHTMLTag_unknown;
 397  if((0<mCount) && (anIndex<mCount)) {
 398    result=mEntries[anIndex].mTag;
 399  }
 400  return result;
 401}
 402
 403
 404/**
 405 * 
 406 * @update  harishd 04/04/99
 407 * @update  gess 04/21/99
 408 */
 409eHTMLTags nsEntryStack::Last(void) const 
 410{
 411  eHTMLTags result=eHTMLTag_unknown;
 412  if(0<mCount) {
 413    result=mEntries[mCount-1].mTag;
 414  }
 415  return result;
 416}
 417
 418nsTagEntry*
 419nsEntryStack::PopEntry() 
 420{
 421  nsTagEntry* entry = EntryAt(mCount-1);
 422  this->Pop();
 423  return entry;
 424}
 425
 426void nsEntryStack::PushEntry(nsTagEntry* aEntry, 
 427                             bool aRefCntNode) 
 428{
 429  if (aEntry) {
 430    EnsureCapacityFor(mCount+1);
 431    mEntries[mCount].mNode   = aEntry->mNode;
 432    mEntries[mCount].mTag    = aEntry->mTag;
 433    mEntries[mCount].mParent = aEntry->mParent;
 434    mEntries[mCount].mStyles = aEntry->mStyles;
 435    if (aRefCntNode && mEntries[mCount].mNode) {
 436      mEntries[mCount].mNode->mUseCount++;
 437      IF_HOLD(mEntries[mCount].mNode);
 438    }
 439    mCount++;
 440  }
 441}
 442
 443/***************************************************************
 444  Now define the dtdcontext class
 445 ***************************************************************/
 446
 447
 448/**
 449 * 
 450 * @update	gess 04.21.2000
 451 */
 452nsDTDContext::nsDTDContext() : mStack()
 453{
 454  MOZ_COUNT_CTOR(nsDTDContext);
 455  mResidualStyleCount=0;
 456  mContextTopIndex=-1;
 457  mTokenAllocator=0;
 458  mNodeAllocator=0;
 459
 460#ifdef DEBUG
 461  memset(mXTags,0,sizeof(mXTags));
 462#endif
 463} 
 464 
 465/**
 466 * 
 467 * @update	gess9/10/98
 468 */
 469nsDTDContext::~nsDTDContext()
 470{
 471  MOZ_COUNT_DTOR(nsDTDContext);
 472}
 473
 474
 475/**
 476 * 
 477 * @update  gess7/9/98
 478 */
 479bool nsDTDContext::HasOpenContainer(eHTMLTags aTag) const {
 480  PRInt32 theIndex=mStack.LastOf(aTag);
 481  return bool(-1<theIndex);
 482}
 483
 484/**
 485 * 
 486 * @update  gess7/9/98
 487 */
 488void nsDTDContext::Push(nsCParserNode* aNode,
 489                        nsEntryStack* aStyleStack, 
 490                        bool aRefCntNode) {
 491  if(aNode) {
 492#ifdef  NS_DEBUG
 493    eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
 494    int size = mStack.mCount;
 495    if (size < eMaxTags)
 496      mXTags[size] = theTag;
 497#endif
 498    mStack.Push(aNode, aStyleStack, aRefCntNode);
 499  }
 500}
 501
 502void nsDTDContext::PushTag(eHTMLTags aTag)
 503{
 504#ifdef NS_DEBUG
 505  if (mStack.mCount < eMaxTags) {
 506    mXTags[mStack.mCount] = aTag;
 507  }
 508#endif
 509
 510  mStack.PushTag(aTag);
 511}
 512
 513nsTagEntry*
 514nsDTDContext::PopEntry()
 515{
 516  PRInt32 theSize = mStack.mCount;
 517  if(0<theSize) {
 518#ifdef  NS_DEBUG
 519    if (theSize <= eMaxTags)
 520      mXTags[theSize-1]=eHTMLTag_unknown;
 521#endif
 522    return mStack.PopEntry();
 523  }
 524  return 0;
 525}
 526
 527void nsDTDContext::PushEntry(nsTagEntry* aEntry, 
 528                             bool aRefCntNode)
 529{
 530#ifdef  NS_DEBUG
 531    int size=mStack.mCount;
 532    if(size< eMaxTags && aEntry)
 533      mXTags[size]=aEntry->mTag;
 534#endif
 535    mStack.PushEntry(aEntry, aRefCntNode);
 536}
 537
 538/* This method will move the top entries, in the entry-stack, into dest context.
 539 * @param aDest  - Destination context for the entries.
 540 * @param aCount - Number of entries, on top of the entry-stack, to be moved.
 541 */
 542void 
 543nsDTDContext::MoveEntries(nsDTDContext& aDest,
 544                          PRInt32 aCount)
 545{
 546  NS_ASSERTION(aCount > 0 && mStack.mCount >= aCount, "cannot move entries");
 547  if (aCount > 0 && mStack.mCount >= aCount) {
 548    while (aCount) {
 549      aDest.PushEntry(&mStack.mEntries[--mStack.mCount], false);
 550#ifdef  NS_DEBUG
 551      if (mStack.mCount < eMaxTags) {
 552        mXTags[mStack.mCount] = eHTMLTag_unknown;
 553      }
 554#endif
 555      --aCount;
 556    }
 557  }
 558}
 559
 560/** 
 561 * @update  gess 11/11/99, 
 562 *          harishd 04/04/99
 563 */
 564nsCParserNode* nsDTDContext::Pop(nsEntryStack *&aChildStyleStack) {
 565
 566  PRInt32         theSize=mStack.mCount;
 567  nsCParserNode*  result=0;
 568
 569  if(0<theSize) {
 570
 571#ifdef  NS_DEBUG
 572    if ((theSize>0) && (theSize <= eMaxTags))
 573      mXTags[theSize-1]=eHTMLTag_unknown;
 574#endif
 575
 576
 577    nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
 578    aChildStyleStack=theEntry->mStyles;
 579
 580    result=mStack.Pop();
 581    theEntry->mParent=0;
 582  }
 583
 584  return result;
 585}
 586 
 587/**
 588 * 
 589 * @update  harishd 04/07/00
 590 */
 591
 592nsCParserNode* nsDTDContext::Pop() {
 593  nsEntryStack   *theTempStyleStack=0; // This has no use here...
 594  return Pop(theTempStyleStack);
 595}
 596
 597/**
 598 * 
 599 * @update  gess7/9/98
 600 */
 601eHTMLTags nsDTDContext::First(void) const {
 602  return mStack.First();
 603}
 604
 605/**
 606 * 
 607 * @update  gess7/9/98
 608 */
 609eHTMLTags nsDTDContext::TagAt(PRInt32 anIndex) const {
 610  return mStack.TagAt(anIndex);
 611}
 612
 613/**
 614 * 
 615 * @update  gess7/9/98
 616 */
 617nsTagEntry* nsDTDContext::LastEntry(void) const {
 618  return mStack.EntryAt(mStack.mCount-1);
 619}
 620
 621/**
 622 *  
 623 * @update  gess7/9/98
 624 */
 625eHTMLTags nsDTDContext::Last() const {
 626  return mStack.Last();
 627}
 628
 629
 630/**
 631 * 
 632 * @update  gess7/9/98
 633 */
 634nsEntryStack* nsDTDContext::GetStylesAt(PRInt32 anIndex) const {
 635  nsEntryStack* result=0;
 636
 637  if(anIndex<mStack.mCount){
 638    nsTagEntry* theEntry=mStack.EntryAt(anIndex);
 639    if(theEntry) {
 640      result=theEntry->mStyles;
 641    }
 642  }
 643  return result;
 644}
 645
 646
 647/**
 648 * 
 649 * @update  gess 04/28/99
 650 */
 651void nsDTDContext::PushStyle(nsCParserNode* aNode){
 652
 653  nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
 654  if(theEntry ) {
 655    nsEntryStack* theStack=theEntry->mStyles;
 656    if(!theStack) {
 657      theStack=theEntry->mStyles=new nsEntryStack();
 658    }
 659    if(theStack) {
 660      theStack->Push(aNode);
 661      ++mResidualStyleCount;
 662    }
 663  } //if
 664}
 665
 666
 667/**
 668 * Call this when you have an EntryStack full of styles
 669 * that you want to push at this level.
 670 * 
 671 * @update  gess 04/28/99
 672 */
 673void nsDTDContext::PushStyles(nsEntryStack *aStyles){
 674
 675  if(aStyles) {
 676    nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
 677    if(theEntry ) {
 678      nsEntryStack* theStyles=theEntry->mStyles;
 679      if(!theStyles) {
 680        theEntry->mStyles=aStyles;
 681
 682        PRUint32 scount=aStyles->mCount;
 683        PRUint32 sindex=0;
 684
 685        theEntry=aStyles->mEntries;
 686        for(sindex=0;sindex<scount;++sindex){            
 687          theEntry->mParent=0;  //this tells us that the style is not open at any level
 688          ++theEntry;
 689          ++mResidualStyleCount;
 690        } //for
 691
 692      }
 693      else {
 694        theStyles->Append(aStyles);
 695        //  Delete aStyles since it has been copied to theStyles...
 696        delete aStyles;
 697        aStyles=0;
 698      }
 699    } //if(theEntry )
 700    else if(mStack.mCount==0) {
 701      // If you're here it means that we have hit the rock bottom
 702      // ,of the stack, and there's no need to handle anymore styles.
 703      // Fix for bug 29048
 704      IF_DELETE(aStyles,mNodeAllocator);
 705    }
 706  }//if(aStyles)
 707}
 708
 709
 710/** 
 711 * 
 712 * @update  gess 04/28/99
 713 */
 714nsCParserNode* nsDTDContext::PopStyle(void){
 715  nsCParserNode *result=0;
 716
 717  nsTagEntry *theEntry=mStack.EntryAt(mStack.mCount-1);
 718  if(theEntry && (theEntry->mNode)) {
 719    nsEntryStack* theStyleStack=theEntry->mParent;
 720    if(theStyleStack){
 721      result=theStyleStack->Pop();
 722      mResidualStyleCount--;
 723    }
 724  } //if
 725  return result;
 726}
 727
 728/** 
 729 * 
 730 * @update  gess 04/28/99
 731 */
 732nsCParserNode* nsDTDContext::PopStyle(eHTMLTags aTag){
 733
 734  PRInt32 theLevel=0;
 735  nsCParserNode* result=0;
 736
 737  for(theLevel=mStack.mCount-1;theLevel>0;theLevel--) {
 738    nsEntryStack *theStack=mStack.mEntries[theLevel].mStyles;
 739    if(theStack) {
 740      if(aTag==theStack->Last()) {
 741        result=theStack->Pop();
 742        mResidualStyleCount--;
 743        break; // Fix bug 50710 - Stop after finding a style.
 744      } else {
 745        // NS_ERROR("bad residual style entry");
 746      }
 747    } 
 748  }
 749
 750  return result;
 751}
 752
 753/** 
 754 * 
 755 * This is similar to popstyle, except that it removes the
 756 * style tag given from anywhere in the style stack, and
 757 * not just at the top.
 758 *
 759 * @update  gess 01/26/00
 760 */
 761void nsDTDContext::RemoveStyle(eHTMLTags aTag){
 762  
 763  PRInt32 theLevel=mStack.mCount;
 764  
 765  while (theLevel) {
 766    nsEntryStack *theStack=GetStylesAt(--theLevel);
 767    if (theStack) {
 768      PRInt32 index=theStack->mCount;
 769      while (index){
 770        nsTagEntry *theEntry=theStack->EntryAt(--index);
 771        if (aTag==(eHTMLTags)theEntry->mNode->GetNodeType()) {
 772          mResidualStyleCount--;
 773          nsCParserNode* result=theStack->Remove(index,aTag);
 774          IF_FREE(result, mNodeAllocator);  
 775          return;
 776        } 
 777      }
 778    } 
 779  }
 780}
 781
 782/**
 783 * This gets called when the parser module is getting unloaded
 784 * 
 785 * @return  nada
 786 */
 787void nsDTDContext::ReleaseGlobalObjects(void){
 788}
 789
 790
 791/**************************************************************
 792  Now define the nsTokenAllocator class...
 793 **************************************************************/
 794
 795static const size_t  kTokenBuckets[]       ={sizeof(CStartToken),sizeof(CAttributeToken),sizeof(CCommentToken),sizeof(CEndToken)};
 796static const PRInt32 kNumTokenBuckets      = sizeof(kTokenBuckets) / sizeof(size_t);
 797static const PRInt32 kInitialTokenPoolSize = NS_SIZE_IN_HEAP(sizeof(CToken)) * 200;
 798
 799/**
 800 * 
 801 * @update  gess7/25/98
 802 * @param 
 803 */
 804nsTokenAllocator::nsTokenAllocator() {
 805
 806  MOZ_COUNT_CTOR(nsTokenAllocator);
 807
 808  mArenaPool.Init("TokenPool", kTokenBuckets, kNumTokenBuckets, kInitialTokenPoolSize);
 809
 810#ifdef NS_DEBUG
 811  int i=0;
 812  for(i=0;i<eToken_last-1;++i) {
 813    mTotals[i]=0;
 814  }
 815#endif
 816
 817}
 818
 819/**
 820 * Destructor for the token factory
 821 * @update  gess7/25/98
 822 */
 823nsTokenAllocator::~nsTokenAllocator() {
 824
 825  MOZ_COUNT_DTOR(nsTokenAllocator);
 826
 827}
 828
 829class CTokenFinder: public nsDequeFunctor{
 830public:
 831  CTokenFinder(CToken* aToken) {mToken=aToken;}
 832  virtual void* operator()(void* anObject) {
 833    if(anObject==mToken) {
 834      return anObject;
 835    }
 836    return 0;
 837  }
 838  CToken* mToken;
 839};
 840
 841/**
 842 * Let's get this code ready to be reused by all the contexts.
 843 * 
 844 * @update	rickg 12June2000
 845 * @param   aType -- tells you the type of token to create
 846 * @param   aTag  -- tells you the type of tag to init with this token
 847 * @param   aString -- gives a default string value for the token
 848 *
 849 * @return  ptr to new token (or 0).
 850 */
 851CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsAString& aString) {
 852
 853  CToken* result=0;
 854
 855#ifdef  NS_DEBUG
 856    mTotals[aType-1]++;
 857#endif
 858  switch(aType){
 859    case eToken_start:            result=new(mArenaPool) CStartToken(aString, aTag); break;
 860    case eToken_end:              result=new(mArenaPool) CEndToken(aString, aTag); break;
 861    case eToken_comment:          result=new(mArenaPool) CCommentToken(aString); break;
 862    case eToken_entity:           result=new(mArenaPool) CEntityToken(aString); break;
 863    case eToken_whitespace:       result=new(mArenaPool) CWhitespaceToken(aString); break;
 864    case eToken_newline:          result=new(mArenaPool) CNewlineToken(); break;
 865    case eToken_text:             result=new(mArenaPool) CTextToken(aString); break;
 866    case eToken_attribute:        result=new(mArenaPool) CAttributeToken(aString); break;
 867    case eToken_instruction:      result=new(mArenaPool) CInstructionToken(aString); break;
 868    case eToken_cdatasection:     result=new(mArenaPool) CCDATASectionToken(aString); break;
 869    case eToken_doctypeDecl:      result=new(mArenaPool) CDoctypeDeclToken(aString); break;
 870    case eToken_markupDecl:       result=new(mArenaPool) CMarkupDeclToken(aString); break;
 871      default:
 872        NS_ASSERTION(false, "nsDTDUtils::CreateTokenOfType: illegal token type"); 
 873        break;
 874  }
 875
 876  return result;
 877}
 878
 879/**
 880 * Let's get this code ready to be reused by all the contexts.
 881 * 
 882 * @update	rickg 12June2000
 883 * @param   aType -- tells you the type of token to create
 884 * @param   aTag  -- tells you the type of tag to init with this token
 885 *
 886 * @return  ptr to new token (or 0).
 887 */
 888CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag) {
 889
 890  CToken* result=0;
 891
 892#ifdef  NS_DEBUG
 893    mTotals[aType-1]++;
 894#endif
 895  switch(aType){
 896    case eToken_start:            result=new(mArenaPool) CStartToken(aTag); break;
 897    case eToken_end:              result=new(mArenaPool) CEndToken(aTag); break;
 898    case eToken_comment:          result=new(mArenaPool) CCommentToken(); break;
 899    case eToken_attribute:        result=new(mArenaPool) CAttributeToken(); break;
 900    case eToken_entity:           result=new(mArenaPool) CEntityToken(); break;
 901    case eToken_whitespace:       result=new(mArenaPool) CWhitespaceToken(); break;
 902    case eToken_newline:          result=new(mArenaPool) CNewlineToken(); break;
 903    case eToken_text:             result=new(mArenaPool) CTextToken(); break;
 904    case eToken_instruction:      result=new(mArenaPool) CInstructionToken(); break;
 905    case eToken_cdatasection:     result=new(mArenaPool) CCDATASectionToken(aTag); break;
 906    case eToken_doctypeDecl:      result=new(mArenaPool) CDoctypeDeclToken(aTag); break;
 907    case eToken_markupDecl:       result=new(mArenaPool) CMarkupDeclToken(); break;
 908    default:
 909      NS_ASSERTION(false, "nsDTDUtils::CreateTokenOfType: illegal token type"); 
 910      break;
 911   }
 912
 913  return result;
 914}
 915
 916#ifdef DEBUG_TRACK_NODES 
 917
 918static nsCParserNode* gAllNodes[100];
 919static int gAllNodeCount=0;
 920
 921int FindNode(nsCParserNode *aNode) {
 922  int theIndex=0;
 923  for(theIndex=0;theIndex<gAllNodeCount;++theIndex) {
 924    if(gAllNodes[theIndex]==aNode) {
 925      return theIndex;
 926    }
 927  }
 928  return -1;
 929}
 930
 931void AddNode(nsCParserNode *aNode) {
 932  if(-1==FindNode(aNode)) {
 933    gAllNodes[gAllNodeCount++]=aNode;
 934  }
 935  else {
 936    //you tried to recycle a node twice!
 937  }
 938}
 939
 940void RemoveNode(nsCParserNode *aNode) {
 941  int theIndex=FindNode(aNode);
 942  if(-1<theIndex) {
 943    gAllNodes[theIndex]=gAllNodes[--gAllNodeCount];
 944  }
 945}
 946
 947#endif 
 948
 949
 950#ifdef HEAP_ALLOCATED_NODES
 951nsNodeAllocator::nsNodeAllocator():mSharedNodes(0){
 952#ifdef DEBUG_TRACK_NODES
 953  mCount=0;
 954#endif
 955#else 
 956  static const size_t  kNodeBuckets[]       = { sizeof(nsCParserNode), sizeof(nsCParserStartNode) };
 957  static const PRInt32 kNumNodeBuckets      = sizeof(kNodeBuckets) / sizeof(size_t);
 958  static const PRInt32 kInitialNodePoolSize = NS_SIZE_IN_HEAP(sizeof(nsCParserNode)) * 35; // optimal size based on space-trace data
 959nsNodeAllocator::nsNodeAllocator() {
 960  mNodePool.Init("NodePool", kNodeBuckets, kNumNodeBuckets, kInitialNodePoolSize);
 961#endif
 962  MOZ_COUNT_CTOR(nsNodeAllocator);
 963}
 964  
 965nsNodeAllocator::~nsNodeAllocator() {
 966  MOZ_COUNT_DTOR(nsNodeAllocator);
 967
 968#ifdef HEAP_ALLOCATED_NODES
 969  nsCParserNode* theNode = 0;
 970
 971  while((theNode=(nsCParserNode*)mSharedNodes.Pop())){
 972#ifdef DEBUG_TRACK_NODES
 973    RemoveNode(theNode);
 974#endif
 975    ::operator delete(theNode); 
 976    theNode=nsnull;
 977  }
 978#ifdef DEBUG_TRACK_NODES
 979  if(mCount) {
 980    printf("**************************\n");
 981    printf("%i out of %i nodes leaked!\n",gAllNodeCount,mCount);
 982    printf("**************************\n");
 983  }
 984#endif
 985#endif
 986}
 987  
 988nsCParserNode* nsNodeAllocator::CreateNode(CToken* aToken,  
 989                                           nsTokenAllocator* aTokenAllocator) 
 990{
 991  nsCParserNode* result = 0;
 992#ifdef HEAP_ALLOCATED_NODES
 993#if 0
 994  if(gAllNodeCount!=mSharedNodes.GetSize()) {
 995    int x=10; //this is very BAD!
 996  }
 997#endif
 998  result = static_cast<nsCParserNode*>(mSharedNodes.Pop());
 999  if (result) {
1000    result->Init(aToken, aTokenAllocator,this);
1001  }
1002  else{
1003    result = nsCParserNode::Create(aToken, aTokenAllocator,this);
1004#ifdef DEBUG_TRACK_NODES
1005    ++mCount;
1006    AddNode(static_cast<nsCParserNode*>(result));
1007#endif
1008    IF_HOLD(result);
1009  }
1010#else
1011  eHTMLTokenTypes type = aToken ? eHTMLTokenTypes(aToken->GetTokenType()) : eToken_unknown;
1012  switch (type) {
1013    case eToken_start:
1014      result = nsCParserStartNode::Create(aToken, aTokenAllocator,this); 
1015      break;
1016    default :
1017      result = nsCParserNode::Create(aToken, aTokenAllocator,this); 
1018      break;
1019  }
1020  IF_HOLD(result);
1021#endif
1022  return result;
1023}
1024
1025#ifdef DEBUG
1026void DebugDumpContainmentRules(nsIDTD& theDTD,const char* aFilename,const char* aTitle) {
1027}
1028#endif