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 : */
69 28 : nsEntryStack::nsEntryStack() {
70 :
71 28 : MOZ_COUNT_CTOR(nsEntryStack);
72 :
73 28 : mCapacity=0;
74 28 : mCount=0;
75 28 : mEntries=0;
76 28 : }
77 :
78 : /**
79 : * Default destructor
80 : * @update harishd 04/04/99
81 : * @update gess 04/22/99
82 : */
83 28 : nsEntryStack::~nsEntryStack() {
84 :
85 28 : MOZ_COUNT_DTOR(nsEntryStack);
86 :
87 28 : if(mEntries) {
88 : //add code here to recycle the node if you have one...
89 28 : delete [] mEntries;
90 28 : mEntries=0;
91 : }
92 :
93 28 : mCount=mCapacity=0;
94 28 : }
95 :
96 : /**
97 : * Release all objects in the entry stack
98 : */
99 : void
100 0 : nsEntryStack::ReleaseAll(nsNodeAllocator* aNodeAllocator)
101 : {
102 0 : NS_ASSERTION(aNodeAllocator,"no allocator? - potential leak!");
103 :
104 0 : if(aNodeAllocator) {
105 0 : NS_ASSERTION(mCount >= 0,"count should not be negative");
106 0 : while(mCount > 0) {
107 0 : nsCParserNode* node=this->Pop();
108 0 : IF_FREE(node,aNodeAllocator);
109 : }
110 : }
111 0 : }
112 :
113 : /**
114 : * Resets state of stack to be empty.
115 : * @update harishd 04/04/99
116 : */
117 0 : void nsEntryStack::Empty(void) {
118 0 : mCount=0;
119 0 : }
120 :
121 :
122 : /**
123 : *
124 : * @update gess 04/22/99
125 : */
126 850 : void nsEntryStack::EnsureCapacityFor(PRInt32 aNewMax,PRInt32 aShiftOffset) {
127 850 : if(mCapacity<aNewMax){
128 :
129 28 : const int kDelta=16;
130 :
131 28 : PRInt32 theSize = kDelta * ((aNewMax / kDelta) + 1);
132 56 : nsTagEntry* temp=new nsTagEntry[theSize];
133 28 : mCapacity=theSize;
134 :
135 28 : if(temp){
136 28 : PRInt32 index=0;
137 28 : for(index=0;index<mCount;++index) {
138 0 : temp[aShiftOffset+index]=mEntries[index];
139 : }
140 28 : if(mEntries) delete [] mEntries;
141 28 : mEntries=temp;
142 : }
143 : else{
144 : //XXX HACK! This is very bad! We failed to get memory.
145 : }
146 : } //if
147 850 : }
148 :
149 : /**
150 : *
151 : * @update gess 04/22/99
152 : */
153 825 : void nsEntryStack::Push(nsCParserNode* aNode,
154 : nsEntryStack* aStyleStack,
155 : bool aRefCntNode)
156 : {
157 825 : if(aNode) {
158 825 : EnsureCapacityFor(mCount+1);
159 825 : mEntries[mCount].mTag = (eHTMLTags)aNode->GetNodeType();
160 825 : if (aRefCntNode) {
161 147 : aNode->mUseCount++;
162 147 : mEntries[mCount].mNode = const_cast<nsCParserNode*>(aNode);
163 147 : IF_HOLD(mEntries[mCount].mNode);
164 : }
165 825 : mEntries[mCount].mParent=aStyleStack;
166 825 : mEntries[mCount++].mStyles=0;
167 : }
168 825 : }
169 :
170 25 : void nsEntryStack::PushTag(eHTMLTags aTag)
171 : {
172 25 : EnsureCapacityFor(mCount + 1);
173 25 : mEntries[mCount].mTag = aTag;
174 25 : mEntries[mCount].mParent = nsnull;
175 25 : mEntries[mCount].mStyles = nsnull;
176 25 : ++mCount;
177 25 : }
178 :
179 :
180 : /**
181 : * This method inserts the given node onto the front of this stack
182 : *
183 : * @update gess 11/10/99
184 : */
185 0 : void nsEntryStack::PushFront(nsCParserNode* aNode,
186 : nsEntryStack* aStyleStack,
187 : bool aRefCntNode)
188 : {
189 0 : if(aNode) {
190 0 : if(mCount<mCapacity) {
191 0 : PRInt32 index=0;
192 0 : for(index=mCount;index>0;index--) {
193 0 : mEntries[index]=mEntries[index-1];
194 : }
195 : }
196 : else {
197 0 : EnsureCapacityFor(mCount+1,1);
198 : }
199 0 : mEntries[0].mTag = (eHTMLTags)aNode->GetNodeType();
200 0 : if (aRefCntNode) {
201 0 : aNode->mUseCount++;
202 0 : mEntries[0].mNode = const_cast<nsCParserNode*>(aNode);
203 0 : IF_HOLD(mEntries[0].mNode);
204 : }
205 0 : mEntries[0].mParent=aStyleStack;
206 0 : mEntries[0].mStyles=0;
207 0 : ++mCount;
208 : }
209 0 : }
210 :
211 : /**
212 : *
213 : * @update gess 11/10/99
214 : */
215 0 : void nsEntryStack::Append(nsEntryStack *aStack) {
216 0 : if(aStack) {
217 :
218 0 : PRInt32 theCount=aStack->mCount;
219 :
220 0 : EnsureCapacityFor(mCount+aStack->mCount,0);
221 :
222 0 : PRInt32 theIndex=0;
223 0 : for(theIndex=0;theIndex<theCount;++theIndex){
224 0 : mEntries[mCount]=aStack->mEntries[theIndex];
225 0 : mEntries[mCount++].mParent=0;
226 : }
227 : }
228 0 : }
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 : */
243 0 : nsCParserNode* nsEntryStack::Remove(PRInt32 anIndex,
244 : eHTMLTags aTag)
245 : {
246 0 : nsCParserNode* result = 0;
247 0 : if (0 < mCount && anIndex < mCount){
248 0 : result = mEntries[anIndex].mNode;
249 0 : if (result)
250 0 : result->mUseCount--;
251 0 : PRInt32 theIndex = 0;
252 0 : mCount -= 1;
253 0 : for( theIndex = anIndex; theIndex < mCount; ++theIndex){
254 0 : mEntries[theIndex] = mEntries[theIndex+1];
255 : }
256 0 : mEntries[mCount].mNode = 0;
257 0 : mEntries[mCount].mStyles = 0;
258 0 : nsEntryStack* theStyleStack = mEntries[anIndex].mParent;
259 0 : 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 0 : PRUint32 scount = theStyleStack->mCount;
263 : #ifdef DEBUG_mrbkap
264 : NS_ASSERTION(scount != 0, "RemoveStyles has a bad style stack");
265 : #endif
266 0 : nsTagEntry *theStyleEntry = theStyleStack->mEntries;
267 0 : for (PRUint32 sindex = scount-1;; --sindex) {
268 0 : if (theStyleEntry->mTag == aTag) {
269 : // This tells us that the style is not open at any level.
270 0 : theStyleEntry->mParent = nsnull;
271 0 : break;
272 : }
273 0 : if (sindex == 0) {
274 : #ifdef DEBUG_mrbkap
275 : NS_ERROR("Couldn't find the removed style on its parent stack");
276 : #endif
277 0 : break;
278 : }
279 0 : ++theStyleEntry;
280 : }
281 : }
282 : }
283 0 : 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 : */
291 850 : nsCParserNode* nsEntryStack::Pop(void)
292 : {
293 850 : nsCParserNode* result = 0;
294 850 : if (0 < mCount) {
295 850 : result = mEntries[--mCount].mNode;
296 850 : if (result)
297 147 : result->mUseCount--;
298 850 : mEntries[mCount].mNode = 0;
299 850 : mEntries[mCount].mStyles = 0;
300 850 : nsEntryStack* theStyleStack = mEntries[mCount].mParent;
301 850 : 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 0 : 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 0 : NS_ENSURE_TRUE(scount != 0, result);
312 :
313 0 : nsTagEntry *theStyleEntry = theStyleStack->mEntries;
314 0 : for (PRUint32 sindex = scount - 1;; --sindex) {
315 0 : if (theStyleEntry->mTag == mEntries[mCount].mTag) {
316 : // This tells us that the style is not open at any level
317 0 : theStyleEntry->mParent = nsnull;
318 0 : break;
319 : }
320 0 : if (sindex == 0) {
321 : #ifdef DEBUG_mrbkap
322 : NS_ERROR("Couldn't find the removed style on its parent stack");
323 : #endif
324 0 : break;
325 : }
326 0 : ++theStyleEntry;
327 : }
328 : }
329 : }
330 850 : return result;
331 : }
332 :
333 : /**
334 : *
335 : * @update harishd 04/04/99
336 : * @update gess 04/21/99
337 : */
338 0 : eHTMLTags nsEntryStack::First() const
339 : {
340 0 : eHTMLTags result=eHTMLTag_unknown;
341 0 : if(0<mCount){
342 0 : result=mEntries[0].mTag;
343 : }
344 0 : return result;
345 : }
346 :
347 : /**
348 : *
349 : * @update harishd 04/04/99
350 : * @update gess 04/21/99
351 : */
352 61 : nsCParserNode* nsEntryStack::NodeAt(PRInt32 anIndex) const
353 : {
354 61 : nsCParserNode* result=0;
355 61 : if((0<mCount) && (anIndex<mCount)) {
356 61 : result=mEntries[anIndex].mNode;
357 : }
358 61 : return result;
359 : }
360 :
361 : /**
362 : *
363 : * @update harishd 04/04/99
364 : * @update gess 04/21/99
365 : */
366 8141 : eHTMLTags nsEntryStack::TagAt(PRInt32 anIndex) const
367 : {
368 8141 : eHTMLTags result=eHTMLTag_unknown;
369 8141 : if((0<mCount) && (anIndex<mCount)) {
370 8113 : result=mEntries[anIndex].mTag;
371 : }
372 8141 : return result;
373 : }
374 :
375 : /**
376 : *
377 : * @update gess 04/21/99
378 : */
379 4463 : nsTagEntry* nsEntryStack::EntryAt(PRInt32 anIndex) const
380 : {
381 4463 : nsTagEntry *result=0;
382 4463 : if((0<mCount) && (anIndex<mCount)) {
383 4463 : result=&mEntries[anIndex];
384 : }
385 4463 : return result;
386 : }
387 :
388 :
389 : /**
390 : *
391 : * @update harishd 04/04/99
392 : * @update gess 04/21/99
393 : */
394 0 : eHTMLTags nsEntryStack::operator[](PRInt32 anIndex) const
395 : {
396 0 : eHTMLTags result=eHTMLTag_unknown;
397 0 : if((0<mCount) && (anIndex<mCount)) {
398 0 : result=mEntries[anIndex].mTag;
399 : }
400 0 : return result;
401 : }
402 :
403 :
404 : /**
405 : *
406 : * @update harishd 04/04/99
407 : * @update gess 04/21/99
408 : */
409 3718 : eHTMLTags nsEntryStack::Last(void) const
410 : {
411 3718 : eHTMLTags result=eHTMLTag_unknown;
412 3718 : if(0<mCount) {
413 3690 : result=mEntries[mCount-1].mTag;
414 : }
415 3718 : return result;
416 : }
417 :
418 : nsTagEntry*
419 0 : nsEntryStack::PopEntry()
420 : {
421 0 : nsTagEntry* entry = EntryAt(mCount-1);
422 0 : this->Pop();
423 0 : return entry;
424 : }
425 :
426 0 : void nsEntryStack::PushEntry(nsTagEntry* aEntry,
427 : bool aRefCntNode)
428 : {
429 0 : if (aEntry) {
430 0 : EnsureCapacityFor(mCount+1);
431 0 : mEntries[mCount].mNode = aEntry->mNode;
432 0 : mEntries[mCount].mTag = aEntry->mTag;
433 0 : mEntries[mCount].mParent = aEntry->mParent;
434 0 : mEntries[mCount].mStyles = aEntry->mStyles;
435 0 : if (aRefCntNode && mEntries[mCount].mNode) {
436 0 : mEntries[mCount].mNode->mUseCount++;
437 0 : IF_HOLD(mEntries[mCount].mNode);
438 : }
439 0 : mCount++;
440 : }
441 0 : }
442 :
443 : /***************************************************************
444 : Now define the dtdcontext class
445 : ***************************************************************/
446 :
447 :
448 : /**
449 : *
450 : * @update gess 04.21.2000
451 : */
452 28 : nsDTDContext::nsDTDContext() : mStack()
453 : {
454 28 : MOZ_COUNT_CTOR(nsDTDContext);
455 28 : mResidualStyleCount=0;
456 28 : mContextTopIndex=-1;
457 28 : mTokenAllocator=0;
458 28 : mNodeAllocator=0;
459 :
460 : #ifdef DEBUG
461 28 : memset(mXTags,0,sizeof(mXTags));
462 : #endif
463 28 : }
464 :
465 : /**
466 : *
467 : * @update gess9/10/98
468 : */
469 56 : nsDTDContext::~nsDTDContext()
470 : {
471 28 : MOZ_COUNT_DTOR(nsDTDContext);
472 28 : }
473 :
474 :
475 : /**
476 : *
477 : * @update gess7/9/98
478 : */
479 109 : bool nsDTDContext::HasOpenContainer(eHTMLTags aTag) const {
480 109 : PRInt32 theIndex=mStack.LastOf(aTag);
481 109 : return bool(-1<theIndex);
482 : }
483 :
484 : /**
485 : *
486 : * @update gess7/9/98
487 : */
488 825 : void nsDTDContext::Push(nsCParserNode* aNode,
489 : nsEntryStack* aStyleStack,
490 : bool aRefCntNode) {
491 825 : if(aNode) {
492 : #ifdef NS_DEBUG
493 825 : eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
494 825 : int size = mStack.mCount;
495 825 : if (size < eMaxTags)
496 825 : mXTags[size] = theTag;
497 : #endif
498 825 : mStack.Push(aNode, aStyleStack, aRefCntNode);
499 : }
500 825 : }
501 :
502 25 : void nsDTDContext::PushTag(eHTMLTags aTag)
503 : {
504 : #ifdef NS_DEBUG
505 25 : if (mStack.mCount < eMaxTags) {
506 25 : mXTags[mStack.mCount] = aTag;
507 : }
508 : #endif
509 :
510 25 : mStack.PushTag(aTag);
511 25 : }
512 :
513 : nsTagEntry*
514 0 : nsDTDContext::PopEntry()
515 : {
516 0 : PRInt32 theSize = mStack.mCount;
517 0 : if(0<theSize) {
518 : #ifdef NS_DEBUG
519 0 : if (theSize <= eMaxTags)
520 0 : mXTags[theSize-1]=eHTMLTag_unknown;
521 : #endif
522 0 : return mStack.PopEntry();
523 : }
524 0 : return 0;
525 : }
526 :
527 0 : void nsDTDContext::PushEntry(nsTagEntry* aEntry,
528 : bool aRefCntNode)
529 : {
530 : #ifdef NS_DEBUG
531 0 : int size=mStack.mCount;
532 0 : if(size< eMaxTags && aEntry)
533 0 : mXTags[size]=aEntry->mTag;
534 : #endif
535 0 : mStack.PushEntry(aEntry, aRefCntNode);
536 0 : }
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 : */
542 : void
543 0 : nsDTDContext::MoveEntries(nsDTDContext& aDest,
544 : PRInt32 aCount)
545 : {
546 0 : NS_ASSERTION(aCount > 0 && mStack.mCount >= aCount, "cannot move entries");
547 0 : if (aCount > 0 && mStack.mCount >= aCount) {
548 0 : while (aCount) {
549 0 : aDest.PushEntry(&mStack.mEntries[--mStack.mCount], false);
550 : #ifdef NS_DEBUG
551 0 : if (mStack.mCount < eMaxTags) {
552 0 : mXTags[mStack.mCount] = eHTMLTag_unknown;
553 : }
554 : #endif
555 0 : --aCount;
556 : }
557 : }
558 0 : }
559 :
560 : /**
561 : * @update gess 11/11/99,
562 : * harishd 04/04/99
563 : */
564 850 : nsCParserNode* nsDTDContext::Pop(nsEntryStack *&aChildStyleStack) {
565 :
566 850 : PRInt32 theSize=mStack.mCount;
567 850 : nsCParserNode* result=0;
568 :
569 850 : if(0<theSize) {
570 :
571 : #ifdef NS_DEBUG
572 850 : if ((theSize>0) && (theSize <= eMaxTags))
573 850 : mXTags[theSize-1]=eHTMLTag_unknown;
574 : #endif
575 :
576 :
577 850 : nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
578 850 : aChildStyleStack=theEntry->mStyles;
579 :
580 850 : result=mStack.Pop();
581 850 : theEntry->mParent=0;
582 : }
583 :
584 850 : return result;
585 : }
586 :
587 : /**
588 : *
589 : * @update harishd 04/07/00
590 : */
591 :
592 0 : nsCParserNode* nsDTDContext::Pop() {
593 0 : nsEntryStack *theTempStyleStack=0; // This has no use here...
594 0 : return Pop(theTempStyleStack);
595 : }
596 :
597 : /**
598 : *
599 : * @update gess7/9/98
600 : */
601 0 : eHTMLTags nsDTDContext::First(void) const {
602 0 : return mStack.First();
603 : }
604 :
605 : /**
606 : *
607 : * @update gess7/9/98
608 : */
609 8141 : eHTMLTags nsDTDContext::TagAt(PRInt32 anIndex) const {
610 8141 : return mStack.TagAt(anIndex);
611 : }
612 :
613 : /**
614 : *
615 : * @update gess7/9/98
616 : */
617 0 : nsTagEntry* nsDTDContext::LastEntry(void) const {
618 0 : return mStack.EntryAt(mStack.mCount-1);
619 : }
620 :
621 : /**
622 : *
623 : * @update gess7/9/98
624 : */
625 3718 : eHTMLTags nsDTDContext::Last() const {
626 3718 : return mStack.Last();
627 : }
628 :
629 :
630 : /**
631 : *
632 : * @update gess7/9/98
633 : */
634 3613 : nsEntryStack* nsDTDContext::GetStylesAt(PRInt32 anIndex) const {
635 3613 : nsEntryStack* result=0;
636 :
637 3613 : if(anIndex<mStack.mCount){
638 3613 : nsTagEntry* theEntry=mStack.EntryAt(anIndex);
639 3613 : if(theEntry) {
640 3613 : result=theEntry->mStyles;
641 : }
642 : }
643 3613 : return result;
644 : }
645 :
646 :
647 : /**
648 : *
649 : * @update gess 04/28/99
650 : */
651 0 : void nsDTDContext::PushStyle(nsCParserNode* aNode){
652 :
653 0 : nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
654 0 : if(theEntry ) {
655 0 : nsEntryStack* theStack=theEntry->mStyles;
656 0 : if(!theStack) {
657 0 : theStack=theEntry->mStyles=new nsEntryStack();
658 : }
659 0 : if(theStack) {
660 0 : theStack->Push(aNode);
661 0 : ++mResidualStyleCount;
662 : }
663 : } //if
664 0 : }
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 : */
673 0 : void nsDTDContext::PushStyles(nsEntryStack *aStyles){
674 :
675 0 : if(aStyles) {
676 0 : nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1);
677 0 : if(theEntry ) {
678 0 : nsEntryStack* theStyles=theEntry->mStyles;
679 0 : if(!theStyles) {
680 0 : theEntry->mStyles=aStyles;
681 :
682 0 : PRUint32 scount=aStyles->mCount;
683 0 : PRUint32 sindex=0;
684 :
685 0 : theEntry=aStyles->mEntries;
686 0 : for(sindex=0;sindex<scount;++sindex){
687 0 : theEntry->mParent=0; //this tells us that the style is not open at any level
688 0 : ++theEntry;
689 0 : ++mResidualStyleCount;
690 : } //for
691 :
692 : }
693 : else {
694 0 : theStyles->Append(aStyles);
695 : // Delete aStyles since it has been copied to theStyles...
696 0 : delete aStyles;
697 0 : aStyles=0;
698 : }
699 : } //if(theEntry )
700 0 : 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 0 : IF_DELETE(aStyles,mNodeAllocator);
705 : }
706 : }//if(aStyles)
707 0 : }
708 :
709 :
710 : /**
711 : *
712 : * @update gess 04/28/99
713 : */
714 0 : nsCParserNode* nsDTDContext::PopStyle(void){
715 0 : nsCParserNode *result=0;
716 :
717 0 : nsTagEntry *theEntry=mStack.EntryAt(mStack.mCount-1);
718 0 : if(theEntry && (theEntry->mNode)) {
719 0 : nsEntryStack* theStyleStack=theEntry->mParent;
720 0 : if(theStyleStack){
721 0 : result=theStyleStack->Pop();
722 0 : mResidualStyleCount--;
723 : }
724 : } //if
725 0 : return result;
726 : }
727 :
728 : /**
729 : *
730 : * @update gess 04/28/99
731 : */
732 0 : nsCParserNode* nsDTDContext::PopStyle(eHTMLTags aTag){
733 :
734 0 : PRInt32 theLevel=0;
735 0 : nsCParserNode* result=0;
736 :
737 0 : for(theLevel=mStack.mCount-1;theLevel>0;theLevel--) {
738 0 : nsEntryStack *theStack=mStack.mEntries[theLevel].mStyles;
739 0 : if(theStack) {
740 0 : if(aTag==theStack->Last()) {
741 0 : result=theStack->Pop();
742 0 : mResidualStyleCount--;
743 0 : break; // Fix bug 50710 - Stop after finding a style.
744 : } else {
745 : // NS_ERROR("bad residual style entry");
746 : }
747 : }
748 : }
749 :
750 0 : 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 : */
761 0 : void nsDTDContext::RemoveStyle(eHTMLTags aTag){
762 :
763 0 : PRInt32 theLevel=mStack.mCount;
764 :
765 0 : while (theLevel) {
766 0 : nsEntryStack *theStack=GetStylesAt(--theLevel);
767 0 : if (theStack) {
768 0 : PRInt32 index=theStack->mCount;
769 0 : while (index){
770 0 : nsTagEntry *theEntry=theStack->EntryAt(--index);
771 0 : if (aTag==(eHTMLTags)theEntry->mNode->GetNodeType()) {
772 0 : mResidualStyleCount--;
773 0 : nsCParserNode* result=theStack->Remove(index,aTag);
774 0 : IF_FREE(result, mNodeAllocator);
775 0 : return;
776 : }
777 : }
778 : }
779 : }
780 : }
781 :
782 : /**
783 : * This gets called when the parser module is getting unloaded
784 : *
785 : * @return nada
786 : */
787 263 : void nsDTDContext::ReleaseGlobalObjects(void){
788 263 : }
789 :
790 :
791 : /**************************************************************
792 : Now define the nsTokenAllocator class...
793 : **************************************************************/
794 :
795 : static const size_t kTokenBuckets[] ={sizeof(CStartToken),sizeof(CAttributeToken),sizeof(CCommentToken),sizeof(CEndToken)};
796 : static const PRInt32 kNumTokenBuckets = sizeof(kTokenBuckets) / sizeof(size_t);
797 : static const PRInt32 kInitialTokenPoolSize = NS_SIZE_IN_HEAP(sizeof(CToken)) * 200;
798 :
799 : /**
800 : *
801 : * @update gess7/25/98
802 : * @param
803 : */
804 3345 : nsTokenAllocator::nsTokenAllocator() {
805 :
806 3345 : MOZ_COUNT_CTOR(nsTokenAllocator);
807 :
808 3345 : mArenaPool.Init("TokenPool", kTokenBuckets, kNumTokenBuckets, kInitialTokenPoolSize);
809 :
810 : #ifdef NS_DEBUG
811 3345 : int i=0;
812 43485 : for(i=0;i<eToken_last-1;++i) {
813 40140 : mTotals[i]=0;
814 : }
815 : #endif
816 :
817 3345 : }
818 :
819 : /**
820 : * Destructor for the token factory
821 : * @update gess7/25/98
822 : */
823 6690 : nsTokenAllocator::~nsTokenAllocator() {
824 :
825 3345 : MOZ_COUNT_DTOR(nsTokenAllocator);
826 :
827 3345 : }
828 :
829 : class CTokenFinder: public nsDequeFunctor{
830 : public:
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 : */
851 53 : CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsAString& aString) {
852 :
853 53 : CToken* result=0;
854 :
855 : #ifdef NS_DEBUG
856 53 : mTotals[aType-1]++;
857 : #endif
858 53 : switch(aType){
859 53 : case eToken_start: result=new(mArenaPool) CStartToken(aString, aTag); break;
860 0 : case eToken_end: result=new(mArenaPool) CEndToken(aString, aTag); break;
861 0 : case eToken_comment: result=new(mArenaPool) CCommentToken(aString); break;
862 0 : case eToken_entity: result=new(mArenaPool) CEntityToken(aString); break;
863 0 : case eToken_whitespace: result=new(mArenaPool) CWhitespaceToken(aString); break;
864 0 : case eToken_newline: result=new(mArenaPool) CNewlineToken(); break;
865 0 : case eToken_text: result=new(mArenaPool) CTextToken(aString); break;
866 0 : case eToken_attribute: result=new(mArenaPool) CAttributeToken(aString); break;
867 0 : case eToken_instruction: result=new(mArenaPool) CInstructionToken(aString); break;
868 0 : case eToken_cdatasection: result=new(mArenaPool) CCDATASectionToken(aString); break;
869 0 : case eToken_doctypeDecl: result=new(mArenaPool) CDoctypeDeclToken(aString); break;
870 0 : case eToken_markupDecl: result=new(mArenaPool) CMarkupDeclToken(aString); break;
871 : default:
872 0 : NS_ASSERTION(false, "nsDTDUtils::CreateTokenOfType: illegal token type");
873 0 : break;
874 : }
875 :
876 53 : 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 : */
888 3040 : CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag) {
889 :
890 3040 : CToken* result=0;
891 :
892 : #ifdef NS_DEBUG
893 3040 : mTotals[aType-1]++;
894 : #endif
895 3040 : switch(aType){
896 797 : case eToken_start: result=new(mArenaPool) CStartToken(aTag); break;
897 344 : case eToken_end: result=new(mArenaPool) CEndToken(aTag); break;
898 25 : case eToken_comment: result=new(mArenaPool) CCommentToken(); break;
899 732 : case eToken_attribute: result=new(mArenaPool) CAttributeToken(); break;
900 0 : case eToken_entity: result=new(mArenaPool) CEntityToken(); break;
901 281 : case eToken_whitespace: result=new(mArenaPool) CWhitespaceToken(); break;
902 530 : case eToken_newline: result=new(mArenaPool) CNewlineToken(); break;
903 306 : case eToken_text: result=new(mArenaPool) CTextToken(); break;
904 0 : case eToken_instruction: result=new(mArenaPool) CInstructionToken(); break;
905 0 : case eToken_cdatasection: result=new(mArenaPool) CCDATASectionToken(aTag); break;
906 25 : case eToken_doctypeDecl: result=new(mArenaPool) CDoctypeDeclToken(aTag); break;
907 0 : case eToken_markupDecl: result=new(mArenaPool) CMarkupDeclToken(); break;
908 : default:
909 0 : NS_ASSERTION(false, "nsDTDUtils::CreateTokenOfType: illegal token type");
910 0 : break;
911 : }
912 :
913 3040 : return result;
914 : }
915 :
916 : #ifdef DEBUG_TRACK_NODES
917 :
918 : static nsCParserNode* gAllNodes[100];
919 : static int gAllNodeCount=0;
920 :
921 : int 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 :
931 : void 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 :
940 : void 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
951 : nsNodeAllocator::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
959 28 : nsNodeAllocator::nsNodeAllocator() {
960 28 : mNodePool.Init("NodePool", kNodeBuckets, kNumNodeBuckets, kInitialNodePoolSize);
961 : #endif
962 28 : MOZ_COUNT_CTOR(nsNodeAllocator);
963 28 : }
964 :
965 56 : nsNodeAllocator::~nsNodeAllocator() {
966 28 : 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 28 : }
987 :
988 1967 : nsCParserNode* nsNodeAllocator::CreateNode(CToken* aToken,
989 : nsTokenAllocator* aTokenAllocator)
990 : {
991 1967 : 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 1967 : eHTMLTokenTypes type = aToken ? eHTMLTokenTypes(aToken->GetTokenType()) : eToken_unknown;
1012 1967 : switch (type) {
1013 : case eToken_start:
1014 850 : result = nsCParserStartNode::Create(aToken, aTokenAllocator,this);
1015 850 : break;
1016 : default :
1017 1117 : result = nsCParserNode::Create(aToken, aTokenAllocator,this);
1018 1117 : break;
1019 : }
1020 1967 : IF_HOLD(result);
1021 : #endif
1022 1967 : return result;
1023 : }
1024 :
1025 : #ifdef DEBUG
1026 0 : void DebugDumpContainmentRules(nsIDTD& theDTD,const char* aFilename,const char* aTitle) {
1027 0 : }
1028 : #endif
|