/parser/htmlparser/src/nsDTDUtils.cpp

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