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
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/
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
16 * The Original Code is mozilla.org code.
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.
24 * Pierre Phaneuf <pp@ludusdesign.com>
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.
38 * ***** END LICENSE BLOCK ***** */
42 #include "nsDTDUtils.h"
44 #include "nsIParserNode.h"
45 #include "nsParserNode.h"
46 #include "nsIChannel.h"
47 #include "nsIServiceManager.h"
48 #include "nsUnicharUtils.h"
50 /**************************************************************************************
51 A few notes about how residual style handling is performed:
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.
61 **************************************************************************************/
66 * @update harishd 04/04/99
67 * @update gess 04/22/99
69 nsEntryStack::nsEntryStack() {
71 MOZ_COUNT_CTOR(nsEntryStack
);
80 * @update harishd 04/04/99
81 * @update gess 04/22/99
83 nsEntryStack::~nsEntryStack() {
85 MOZ_COUNT_DTOR(nsEntryStack
);
88 //add code here to recycle the node if you have one...
97 * Release all objects in the entry stack
100 nsEntryStack::ReleaseAll(nsNodeAllocator
* aNodeAllocator
)
102 NS_ASSERTION(aNodeAllocator
,"no allocator? - potential leak!");
105 NS_ASSERTION(mCount
>= 0,"count should not be negative");
107 nsCParserNode
* node
=this->Pop();
108 IF_FREE(node
,aNodeAllocator
);
114 * Resets state of stack to be empty.
115 * @update harishd 04/04/99
117 void nsEntryStack::Empty(void) {
124 * @update gess 04/22/99
126 void nsEntryStack::EnsureCapacityFor(PRInt32 aNewMax
,PRInt32 aShiftOffset
) {
127 if(mCapacity
<aNewMax
){
131 PRInt32 theSize
= kDelta
* ((aNewMax
/ kDelta
) + 1);
132 nsTagEntry
* temp
=new nsTagEntry
[theSize
];
137 for(index
=0;index
<mCount
;++index
) {
138 temp
[aShiftOffset
+index
]=mEntries
[index
];
140 if(mEntries
) delete [] mEntries
;
144 //XXX HACK! This is very bad! We failed to get memory.
151 * @update gess 04/22/99
153 void nsEntryStack::Push(nsCParserNode
* aNode
,
154 nsEntryStack
* aStyleStack
,
158 EnsureCapacityFor(mCount
+1);
159 mEntries
[mCount
].mTag
= (eHTMLTags
)aNode
->GetNodeType();
162 mEntries
[mCount
].mNode
= const_cast<nsCParserNode
*>(aNode
);
163 IF_HOLD(mEntries
[mCount
].mNode
);
165 mEntries
[mCount
].mParent
=aStyleStack
;
166 mEntries
[mCount
++].mStyles
=0;
170 void nsEntryStack::PushTag(eHTMLTags aTag
)
172 EnsureCapacityFor(mCount
+ 1);
173 mEntries
[mCount
].mTag
= aTag
;
174 mEntries
[mCount
].mParent
= nsnull
;
175 mEntries
[mCount
].mStyles
= nsnull
;
181 * This method inserts the given node onto the front of this stack
183 * @update gess 11/10/99
185 void nsEntryStack::PushFront(nsCParserNode
* aNode
,
186 nsEntryStack
* aStyleStack
,
190 if(mCount
<mCapacity
) {
192 for(index
=mCount
;index
>0;index
--) {
193 mEntries
[index
]=mEntries
[index
-1];
197 EnsureCapacityFor(mCount
+1,1);
199 mEntries
[0].mTag
= (eHTMLTags
)aNode
->GetNodeType();
202 mEntries
[0].mNode
= const_cast<nsCParserNode
*>(aNode
);
203 IF_HOLD(mEntries
[0].mNode
);
205 mEntries
[0].mParent
=aStyleStack
;
206 mEntries
[0].mStyles
=0;
213 * @update gess 11/10/99
215 void nsEntryStack::Append(nsEntryStack
*aStack
) {
218 PRInt32 theCount
=aStack
->mCount
;
220 EnsureCapacityFor(mCount
+aStack
->mCount
,0);
223 for(theIndex
=0;theIndex
<theCount
;++theIndex
){
224 mEntries
[mCount
]=aStack
->mEntries
[theIndex
];
225 mEntries
[mCount
++].mParent
=0;
231 * This method removes the node for the given tag
232 * from anywhere within this entry stack, and shifts
233 * other entries down.
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
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
243 nsCParserNode
* nsEntryStack::Remove(PRInt32 anIndex
,
246 nsCParserNode
* result
= 0;
247 if (0 < mCount
&& anIndex
< mCount
){
248 result
= mEntries
[anIndex
].mNode
;
251 PRInt32 theIndex
= 0;
253 for( theIndex
= anIndex
; theIndex
< mCount
; ++theIndex
){
254 mEntries
[theIndex
] = mEntries
[theIndex
+1];
256 mEntries
[mCount
].mNode
= 0;
257 mEntries
[mCount
].mStyles
= 0;
258 nsEntryStack
* theStyleStack
= mEntries
[anIndex
].mParent
;
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
;
264 NS_ASSERTION(scount
!= 0, "RemoveStyles has a bad style stack");
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
;
275 NS_ERROR("Couldn't find the removed style on its parent stack");
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.
291 nsCParserNode
* nsEntryStack::Pop(void)
293 nsCParserNode
* result
= 0;
295 result
= mEntries
[--mCount
].mNode
;
298 mEntries
[mCount
].mNode
= 0;
299 mEntries
[mCount
].mStyles
= 0;
300 nsEntryStack
* theStyleStack
= mEntries
[mCount
].mParent
;
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
;
306 // XXX If this NS_ENSURE_TRUE fails, it means that the style stack was
307 // empty before we were removed.
309 NS_ASSERTION(scount
!= 0, "preventing a potential crash.");
311 NS_ENSURE_TRUE(scount
!= 0, result
);
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
;
322 NS_ERROR("Couldn't find the removed style on its parent stack");
335 * @update harishd 04/04/99
336 * @update gess 04/21/99
338 eHTMLTags
nsEntryStack::First() const
340 eHTMLTags result
=eHTMLTag_unknown
;
342 result
=mEntries
[0].mTag
;
349 * @update harishd 04/04/99
350 * @update gess 04/21/99
352 nsCParserNode
* nsEntryStack::NodeAt(PRInt32 anIndex
) const
354 nsCParserNode
* result
=0;
355 if((0<mCount
) && (anIndex
<mCount
)) {
356 result
=mEntries
[anIndex
].mNode
;
363 * @update harishd 04/04/99
364 * @update gess 04/21/99
366 eHTMLTags
nsEntryStack::TagAt(PRInt32 anIndex
) const
368 eHTMLTags result
=eHTMLTag_unknown
;
369 if((0<mCount
) && (anIndex
<mCount
)) {
370 result
=mEntries
[anIndex
].mTag
;
377 * @update gess 04/21/99
379 nsTagEntry
* nsEntryStack::EntryAt(PRInt32 anIndex
) const
381 nsTagEntry
*result
=0;
382 if((0<mCount
) && (anIndex
<mCount
)) {
383 result
=&mEntries
[anIndex
];
391 * @update harishd 04/04/99
392 * @update gess 04/21/99
394 eHTMLTags
nsEntryStack::operator[](PRInt32 anIndex
) const
396 eHTMLTags result
=eHTMLTag_unknown
;
397 if((0<mCount
) && (anIndex
<mCount
)) {
398 result
=mEntries
[anIndex
].mTag
;
406 * @update harishd 04/04/99
407 * @update gess 04/21/99
409 eHTMLTags
nsEntryStack::Last(void) const
411 eHTMLTags result
=eHTMLTag_unknown
;
413 result
=mEntries
[mCount
-1].mTag
;
419 nsEntryStack::PopEntry()
421 nsTagEntry
* entry
= EntryAt(mCount
-1);
426 void nsEntryStack::PushEntry(nsTagEntry
* 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
);
443 /***************************************************************
444 Now define the dtdcontext class
445 ***************************************************************/
450 * @update gess 04.21.2000
452 nsDTDContext::nsDTDContext() : mStack()
454 MOZ_COUNT_CTOR(nsDTDContext
);
455 mResidualStyleCount
=0;
461 memset(mXTags
,0,sizeof(mXTags
));
467 * @update gess9/10/98
469 nsDTDContext::~nsDTDContext()
471 MOZ_COUNT_DTOR(nsDTDContext
);
479 PRBool
nsDTDContext::HasOpenContainer(eHTMLTags aTag
) const {
480 PRInt32 theIndex
=mStack
.LastOf(aTag
);
481 return PRBool(-1<theIndex
);
488 void nsDTDContext::Push(nsCParserNode
* aNode
,
489 nsEntryStack
* aStyleStack
,
490 PRBool aRefCntNode
) {
493 eHTMLTags theTag
= (eHTMLTags
)aNode
->GetNodeType();
494 int size
= mStack
.mCount
;
496 mXTags
[size
] = theTag
;
498 mStack
.Push(aNode
, aStyleStack
, aRefCntNode
);
502 void nsDTDContext::PushTag(eHTMLTags aTag
)
505 if (mStack
.mCount
< eMaxTags
) {
506 mXTags
[mStack
.mCount
] = aTag
;
510 mStack
.PushTag(aTag
);
514 nsDTDContext::PopEntry()
516 PRInt32 theSize
= mStack
.mCount
;
519 if (theSize
<= eMaxTags
)
520 mXTags
[theSize
-1]=eHTMLTag_unknown
;
522 return mStack
.PopEntry();
527 void nsDTDContext::PushEntry(nsTagEntry
* aEntry
,
531 int size
=mStack
.mCount
;
532 if(size
< eMaxTags
&& aEntry
)
533 mXTags
[size
]=aEntry
->mTag
;
535 mStack
.PushEntry(aEntry
, aRefCntNode
);
538 /* This method will move the top entires, 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.
543 nsDTDContext::MoveEntries(nsDTDContext
& aDest
,
546 NS_ASSERTION(aCount
> 0 && mStack
.mCount
>= aCount
, "cannot move entries");
547 if (aCount
> 0 && mStack
.mCount
>= aCount
) {
549 aDest
.PushEntry(&mStack
.mEntries
[--mStack
.mCount
], PR_FALSE
);
551 if (mStack
.mCount
< eMaxTags
) {
552 mXTags
[mStack
.mCount
] = eHTMLTag_unknown
;
561 * @update gess 11/11/99,
564 nsCParserNode
* nsDTDContext::Pop(nsEntryStack
*&aChildStyleStack
) {
566 PRInt32 theSize
=mStack
.mCount
;
567 nsCParserNode
* result
=0;
572 if ((theSize
>0) && (theSize
<= eMaxTags
))
573 mXTags
[theSize
-1]=eHTMLTag_unknown
;
577 nsTagEntry
* theEntry
=mStack
.EntryAt(mStack
.mCount
-1);
578 aChildStyleStack
=theEntry
->mStyles
;
589 * @update harishd 04/07/00
592 nsCParserNode
* nsDTDContext::Pop() {
593 nsEntryStack
*theTempStyleStack
=0; // This has no use here...
594 return Pop(theTempStyleStack
);
601 eHTMLTags
nsDTDContext::First(void) const {
602 return mStack
.First();
609 eHTMLTags
nsDTDContext::TagAt(PRInt32 anIndex
) const {
610 return mStack
.TagAt(anIndex
);
617 nsTagEntry
* nsDTDContext::LastEntry(void) const {
618 return mStack
.EntryAt(mStack
.mCount
-1);
625 eHTMLTags
nsDTDContext::Last() const {
626 return mStack
.Last();
634 nsEntryStack
* nsDTDContext::GetStylesAt(PRInt32 anIndex
) const {
635 nsEntryStack
* result
=0;
637 if(anIndex
<mStack
.mCount
){
638 nsTagEntry
* theEntry
=mStack
.EntryAt(anIndex
);
640 result
=theEntry
->mStyles
;
649 * @update gess 04/28/99
651 void nsDTDContext::PushStyle(nsCParserNode
* aNode
){
653 nsTagEntry
* theEntry
=mStack
.EntryAt(mStack
.mCount
-1);
655 nsEntryStack
* theStack
=theEntry
->mStyles
;
657 theStack
=theEntry
->mStyles
=new nsEntryStack();
660 theStack
->Push(aNode
);
661 ++mResidualStyleCount
;
668 * Call this when you have an EntryStack full of styles
669 * that you want to push at this level.
671 * @update gess 04/28/99
673 void nsDTDContext::PushStyles(nsEntryStack
*aStyles
){
676 nsTagEntry
* theEntry
=mStack
.EntryAt(mStack
.mCount
-1);
678 nsEntryStack
* theStyles
=theEntry
->mStyles
;
680 theEntry
->mStyles
=aStyles
;
682 PRUint32 scount
=aStyles
->mCount
;
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
689 ++mResidualStyleCount
;
694 theStyles
->Append(aStyles
);
695 // Delete aStyles since it has been copied to theStyles...
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.
704 IF_DELETE(aStyles
,mNodeAllocator
);
712 * @update gess 04/28/99
714 nsCParserNode
* nsDTDContext::PopStyle(void){
715 nsCParserNode
*result
=0;
717 nsTagEntry
*theEntry
=mStack
.EntryAt(mStack
.mCount
-1);
718 if(theEntry
&& (theEntry
->mNode
)) {
719 nsEntryStack
* theStyleStack
=theEntry
->mParent
;
721 result
=theStyleStack
->Pop();
722 mResidualStyleCount
--;
730 * @update gess 04/28/99
732 nsCParserNode
* nsDTDContext::PopStyle(eHTMLTags aTag
){
735 nsCParserNode
* result
=0;
737 for(theLevel
=mStack
.mCount
-1;theLevel
>0;theLevel
--) {
738 nsEntryStack
*theStack
=mStack
.mEntries
[theLevel
].mStyles
;
740 if(aTag
==theStack
->Last()) {
741 result
=theStack
->Pop();
742 mResidualStyleCount
--;
743 break; // Fix bug 50710 - Stop after finding a style.
745 // NS_ERROR("bad residual style entry");
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.
759 * @update gess 01/26/00
761 void nsDTDContext::RemoveStyle(eHTMLTags aTag
){
763 PRInt32 theLevel
=mStack
.mCount
;
766 nsEntryStack
*theStack
=GetStylesAt(--theLevel
);
768 PRInt32 index
=theStack
->mCount
;
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
);
783 * This gets called when the parser module is getting unloaded
787 void nsDTDContext::ReleaseGlobalObjects(void){
791 /**************************************************************
792 Now define the nsTokenAllocator class...
793 **************************************************************/
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;
801 * @update gess7/25/98
804 nsTokenAllocator::nsTokenAllocator() {
806 MOZ_COUNT_CTOR(nsTokenAllocator
);
808 mArenaPool
.Init("TokenPool", kTokenBuckets
, kNumTokenBuckets
, kInitialTokenPoolSize
);
812 for(i
=0;i
<eToken_last
-1;++i
) {
820 * Destructor for the token factory
821 * @update gess7/25/98
823 nsTokenAllocator::~nsTokenAllocator() {
825 MOZ_COUNT_DTOR(nsTokenAllocator
);
829 class CTokenFinder
: public nsDequeFunctor
{
831 CTokenFinder(CToken
* aToken
) {mToken
=aToken
;}
832 virtual void* operator()(void* anObject
) {
833 if(anObject
==mToken
) {
842 * Let's get this code ready to be reused by all the contexts.
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
849 * @return ptr to new token (or 0).
851 CToken
* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType
,eHTMLTags aTag
, const nsAString
& aString
) {
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;
872 NS_ASSERTION(PR_FALSE
, "nsDTDUtils::CreateTokenOfType: illegal token type");
880 * Let's get this code ready to be reused by all the contexts.
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
886 * @return ptr to new token (or 0).
888 CToken
* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType
,eHTMLTags aTag
) {
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;
909 NS_ASSERTION(PR_FALSE
, "nsDTDUtils::CreateTokenOfType: illegal token type");
916 #ifdef DEBUG_TRACK_NODES
918 static nsCParserNode
* gAllNodes
[100];
919 static int gAllNodeCount
=0;
921 int FindNode(nsCParserNode
*aNode
) {
923 for(theIndex
=0;theIndex
<gAllNodeCount
;++theIndex
) {
924 if(gAllNodes
[theIndex
]==aNode
) {
931 void AddNode(nsCParserNode
*aNode
) {
932 if(-1==FindNode(aNode
)) {
933 gAllNodes
[gAllNodeCount
++]=aNode
;
936 //you tried to recycle a node twice!
940 void RemoveNode(nsCParserNode
*aNode
) {
941 int theIndex
=FindNode(aNode
);
943 gAllNodes
[theIndex
]=gAllNodes
[--gAllNodeCount
];
950 #ifdef HEAP_ALLOCATED_NODES
951 nsNodeAllocator::nsNodeAllocator():mSharedNodes(0){
952 #ifdef DEBUG_TRACK_NODES
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 nsNodeAllocator::nsNodeAllocator() {
960 mNodePool
.Init("NodePool", kNodeBuckets
, kNumNodeBuckets
, kInitialNodePoolSize
);
962 MOZ_COUNT_CTOR(nsNodeAllocator
);
965 nsNodeAllocator::~nsNodeAllocator() {
966 MOZ_COUNT_DTOR(nsNodeAllocator
);
968 #ifdef HEAP_ALLOCATED_NODES
969 nsCParserNode
* theNode
= 0;
971 while((theNode
=(nsCParserNode
*)mSharedNodes
.Pop())){
972 #ifdef DEBUG_TRACK_NODES
975 ::operator delete(theNode
);
978 #ifdef DEBUG_TRACK_NODES
980 printf("**************************\n");
981 printf("%i out of %i nodes leaked!\n",gAllNodeCount
,mCount
);
982 printf("**************************\n");
988 nsCParserNode
* nsNodeAllocator::CreateNode(CToken
* aToken
,
989 nsTokenAllocator
* aTokenAllocator
)
991 nsCParserNode
* result
= 0;
992 #ifdef HEAP_ALLOCATED_NODES
994 if(gAllNodeCount
!=mSharedNodes
.GetSize()) {
995 int x
=10; //this is very BAD!
998 result
= static_cast<nsCParserNode
*>(mSharedNodes
.Pop());
1000 result
->Init(aToken
, aTokenAllocator
,this);
1003 result
= nsCParserNode::Create(aToken
, aTokenAllocator
,this);
1004 #ifdef DEBUG_TRACK_NODES
1006 AddNode(static_cast<nsCParserNode
*>(result
));
1011 eHTMLTokenTypes type
= aToken
? eHTMLTokenTypes(aToken
->GetTokenType()) : eToken_unknown
;
1014 result
= nsCParserStartNode::Create(aToken
, aTokenAllocator
,this);
1017 result
= nsCParserNode::Create(aToken
, aTokenAllocator
,this);
1026 void DebugDumpContainmentRules(nsIDTD
& theDTD
,const char* aFilename
,const char* aTitle
) {
1030 /**************************************************************
1031 This defines the topic object used by the observer service.
1032 The observerService uses a list of these, 1 per topic when
1034 **************************************************************/
1035 NS_IMPL_ISUPPORTS1(nsObserverEntry
, nsIObserverEntry
)
1037 nsObserverEntry::nsObserverEntry(const nsAString
& aTopic
) : mTopic(aTopic
)
1039 memset(mObservers
, 0, sizeof(mObservers
));
1042 nsObserverEntry::~nsObserverEntry() {
1043 for (PRInt32 i
= 0; i
<= NS_HTML_TAG_MAX
; ++i
){
1044 if (mObservers
[i
]) {
1045 PRInt32 count
= mObservers
[i
]->Count();
1046 for (PRInt32 j
= 0; j
< count
; ++j
) {
1047 nsISupports
* obs
= (nsISupports
*)mObservers
[i
]->ElementAt(j
);
1050 delete mObservers
[i
];
1056 nsObserverEntry::Notify(nsIParserNode
* aNode
,
1058 nsISupports
* aWebShell
,
1059 const PRUint32 aFlags
)
1061 NS_ENSURE_ARG_POINTER(aNode
);
1062 NS_ENSURE_ARG_POINTER(aParser
);
1064 nsresult result
= NS_OK
;
1065 eHTMLTags theTag
= (eHTMLTags
)aNode
->GetNodeType();
1067 if (theTag
<= NS_HTML_TAG_MAX
) {
1068 nsVoidArray
* theObservers
= mObservers
[theTag
];
1070 PRInt32 theCharsetSource
;
1071 nsCAutoString charset
;
1072 aParser
->GetDocumentCharset(charset
,theCharsetSource
);
1073 NS_ConvertASCIItoUTF16
theCharsetValue(charset
);
1075 PRInt32 theAttrCount
= aNode
->GetAttributeCount();
1076 PRInt32 theObserversCount
= theObservers
->Count();
1077 if (0 < theObserversCount
){
1078 nsStringArray
keys(theAttrCount
+4), values(theAttrCount
+4);
1080 // XXX this and the following code may be a performance issue.
1081 // Every key and value is copied and added to an voidarray (causing at
1082 // least 2 allocations for mImpl, usually more, plus at least 1 per
1083 // string (total = 2*(keys+3) + 2(or more) array allocations )).
1085 for (index
= 0; index
< theAttrCount
; ++index
) {
1086 keys
.AppendString(aNode
->GetKeyAt(index
));
1087 values
.AppendString(aNode
->GetValueAt(index
));
1090 nsAutoString intValue
;
1092 keys
.AppendString(NS_LITERAL_STRING("charset"));
1093 values
.AppendString(theCharsetValue
);
1095 keys
.AppendString(NS_LITERAL_STRING("charsetSource"));
1096 intValue
.AppendInt(PRInt32(theCharsetSource
),10);
1097 values
.AppendString(intValue
);
1099 keys
.AppendString(NS_LITERAL_STRING("X_COMMAND"));
1100 values
.AppendString(NS_LITERAL_STRING("text/html"));
1102 nsCOMPtr
<nsIChannel
> channel
;
1103 aParser
->GetChannel(getter_AddRefs(channel
));
1105 for (index
=0;index
<theObserversCount
;++index
) {
1106 nsIElementObserver
* observer
= static_cast<nsIElementObserver
*>(theObservers
->ElementAt(index
));
1108 result
= observer
->Notify(aWebShell
, channel
,
1109 nsHTMLTags::GetStringValue(theTag
),
1110 &keys
, &values
, aFlags
);
1111 if (NS_FAILED(result
)) {
1115 if (result
== NS_HTMLPARSER_VALID_META_CHARSET
) {
1116 // Inform the parser that this meta tag contained a valid
1117 // charset. See bug 272815
1118 aParser
->SetDocumentCharset(charset
, kCharsetFromMetaTag
);
1130 nsObserverEntry::Matches(const nsAString
& aString
) {
1131 PRBool result
= aString
.Equals(mTopic
);
1136 nsObserverEntry::AddObserver(nsIElementObserver
*aObserver
,
1140 if (!mObservers
[aTag
]) {
1141 mObservers
[aTag
] = new nsAutoVoidArray();
1142 if (!mObservers
[aTag
]) {
1143 return NS_ERROR_OUT_OF_MEMORY
;
1146 NS_ADDREF(aObserver
);
1147 mObservers
[aTag
]->AppendElement(aObserver
);
1153 nsObserverEntry::RemoveObserver(nsIElementObserver
*aObserver
)
1155 for (PRInt32 i
=0; i
<= NS_HTML_TAG_MAX
; ++i
){
1156 if (mObservers
[i
]) {
1157 nsISupports
* obs
= aObserver
;
1158 PRBool removed
= mObservers
[i
]->RemoveElement(obs
);