зеркало из https://github.com/mozilla/pjs.git
Too many bugs to mention; tables, skipped content; perf; memory
This commit is contained in:
Родитель
c1d7662228
Коммит
d69ea1fb89
|
@ -217,6 +217,20 @@ eHTMLTags CTagStack::Last() const {
|
|||
return eHTMLTag_unknown;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Now define the token deallocator class...
|
||||
**************************************************************/
|
||||
class CNavTokenDeallocator: public nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject) {
|
||||
CToken* aToken = (CToken*)anObject;
|
||||
delete aToken;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
static CNavTokenDeallocator gTokenKiller;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Now define the tokenrecycler class...
|
||||
**************************************************************/
|
||||
|
@ -230,7 +244,7 @@ eHTMLTags CTagStack::Last() const {
|
|||
class nsCTokenRecycler : public nsITokenRecycler {
|
||||
public:
|
||||
|
||||
enum {eCacheMaxSize=100};
|
||||
// enum {eCacheMaxSize=100};
|
||||
|
||||
nsCTokenRecycler();
|
||||
virtual ~nsCTokenRecycler();
|
||||
|
@ -238,9 +252,8 @@ public:
|
|||
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString);
|
||||
|
||||
protected:
|
||||
CToken* mTokenCache[eToken_last-1][eCacheMaxSize];
|
||||
PRInt32 mCount[eToken_last-1];
|
||||
PRInt32 mTotals[eToken_last-1];
|
||||
nsDeque* mTokenCache[eToken_last-1];
|
||||
// PRInt32 mTotals[eToken_last-1];
|
||||
};
|
||||
|
||||
|
||||
|
@ -250,9 +263,11 @@ protected:
|
|||
* @param
|
||||
*/
|
||||
nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
|
||||
nsCRT::zero(mTokenCache,sizeof(mTokenCache));
|
||||
nsCRT::zero(mCount,sizeof(mCount));
|
||||
nsCRT::zero(mTotals,sizeof(mTotals));
|
||||
int i=0;
|
||||
for(i=0;i<eToken_last-1;i++) {
|
||||
mTokenCache[i]=new nsDeque(gTokenKiller);
|
||||
// mTotals[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -260,13 +275,11 @@ nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
|
|||
* @update gess7/25/98
|
||||
*/
|
||||
nsCTokenRecycler::~nsCTokenRecycler() {
|
||||
//begin by deleting all the known (recycled tokens)...
|
||||
int index1,index2;
|
||||
for(index1=0;index1<eToken_last-1;index1++){
|
||||
for(index2=0;index2<mCount[index1];index2++){
|
||||
if(mTokenCache[index1][index2])
|
||||
delete mTokenCache[index1][index2];
|
||||
}
|
||||
//begin by deleting all the known (recycled) tokens...
|
||||
//We're also deleting the cache-deques themselves.
|
||||
int i;
|
||||
for(i=0;i<eToken_last-1;i++) {
|
||||
delete mTokenCache[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,15 +293,7 @@ nsCTokenRecycler::~nsCTokenRecycler() {
|
|||
void nsCTokenRecycler::RecycleToken(CToken* aToken) {
|
||||
if(aToken) {
|
||||
PRInt32 theType=aToken->GetTokenType();
|
||||
if(mCount[theType-1]<eCacheMaxSize) {
|
||||
mTokenCache[theType-1][mCount[theType-1]]=aToken;
|
||||
mCount[theType-1]++;
|
||||
} else {
|
||||
//this is an overflow condition. More tokens of a given
|
||||
//type have been created than we can store in our recycler.
|
||||
//In this case, just destroy the extra token.
|
||||
delete aToken;
|
||||
}
|
||||
mTokenCache[theType-1]->Push(aToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,17 +306,13 @@ void nsCTokenRecycler::RecycleToken(CToken* aToken) {
|
|||
*/
|
||||
CToken* nsCTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString) {
|
||||
|
||||
CToken* result;
|
||||
CToken* result=(CToken*)mTokenCache[aType-1]->Pop();
|
||||
|
||||
if(0<mCount[aType-1]) {
|
||||
int cnt=CToken::GetTokenCount();
|
||||
result=mTokenCache[aType-1][mCount[aType-1]-1];
|
||||
if(result) {
|
||||
result->Reinitialize(aTag,aString);
|
||||
mTokenCache[aType-1][mCount[aType-1]-1]=0;
|
||||
mCount[aType-1]--;
|
||||
}
|
||||
else {
|
||||
mTotals[aType-1]++;
|
||||
// mTotals[aType-1]++;
|
||||
switch(aType){
|
||||
case eToken_start: result=new CStartToken(aTag); break;
|
||||
case eToken_end: result=new CEndToken(aTag); break;
|
||||
|
@ -465,17 +466,6 @@ void CNavDTD::InitializeDefaultTokenHandlers() {
|
|||
}
|
||||
|
||||
|
||||
class CNavTokenDeallocator: public nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject) {
|
||||
CToken* aToken = (CToken*)anObject;
|
||||
delete aToken;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static CNavTokenDeallocator gTokenKiller;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
|
@ -530,7 +520,7 @@ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
|
|||
* @return
|
||||
*/
|
||||
nsITokenRecycler* CNavDTD::GetTokenRecycler(void){
|
||||
return 0;
|
||||
// return 0;
|
||||
return &gTokenRecycler;
|
||||
}
|
||||
|
||||
|
@ -704,12 +694,14 @@ nsresult CNavDTD::HandleToken(CToken* aToken){
|
|||
nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode) {
|
||||
NS_PRECONDITION(0!=aToken,kNullToken);
|
||||
|
||||
eHTMLTags parentTag=GetTopNode();
|
||||
nsresult result=NS_OK;
|
||||
PRBool contains=CanContain(parentTag,aChildTag);
|
||||
eHTMLTags theParentTag=GetTopNode();
|
||||
nsresult result=NS_OK;
|
||||
PRBool contains=CanContain(theParentTag,aChildTag);
|
||||
|
||||
if(PR_FALSE==contains){
|
||||
result=CreateContextStackFor(aChildTag);
|
||||
if(CanPropagate(theParentTag,aChildTag))
|
||||
result=CreateContextStackFor(aChildTag);
|
||||
else result=kCantPropagate;
|
||||
if(NS_OK!=result) {
|
||||
//if you're here, then the new topmost container can't contain aToken.
|
||||
//You must determine what container hierarchy you need to hold aToken,
|
||||
|
@ -1687,6 +1679,29 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to determine whether or not
|
||||
* the necessary intermediate tags should be propagated
|
||||
* between the given parent and given child.
|
||||
*
|
||||
* @update gess 4/8/98
|
||||
* @param aParent -- tag enum of parent container
|
||||
* @param aChild -- tag enum of child container
|
||||
* @return PR_TRUE if propagation should occur
|
||||
*/
|
||||
PRBool CNavDTD::CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const {
|
||||
PRBool result=PR_TRUE;
|
||||
|
||||
switch(aParent) {
|
||||
case eHTMLTag_td:
|
||||
result=CanContain(aParent,aChild);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}//switch
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to determine whether or not a tag
|
||||
|
@ -2182,18 +2197,43 @@ PRBool CNavDTD::IsGatedFromClosing(eHTMLTags aChildTag) const {
|
|||
|
||||
case eHTMLTag_td:
|
||||
case eHTMLTag_tr:
|
||||
theGatePos=GetTopmostIndexOf(gTableTags);
|
||||
{
|
||||
/***************************************************************************
|
||||
* This code may seem confusing, so let me explain it.
|
||||
* We're trying to handle the case where a child tag may be prevented from
|
||||
* closing a tag already on the stack. Here's a case:
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>
|
||||
* <table>
|
||||
* </tr>
|
||||
*
|
||||
* In this case, the bottom </tr> is "gated" from closing the bottommost
|
||||
* table.
|
||||
*
|
||||
* HOW THIS CODE WORKS:
|
||||
*
|
||||
* This block of code compares all the members of the default parent
|
||||
* hierarchy for the childtag against the open containers on our stack.
|
||||
* If they ever match, then the given child should be gated.
|
||||
***************************************************************************/
|
||||
|
||||
int theIndex;
|
||||
int theTopIndex=mContextStack.mCount-1;
|
||||
|
||||
eHTMLTags theParent=GetDefaultParentTagFor(aChildTag);
|
||||
while(eHTMLTag_unknown!=theParent) {
|
||||
for(theIndex=theTopIndex;theIndex>tagPos;theIndex--){
|
||||
if(mContextStack.mTags[theIndex]==theParent){
|
||||
theGatePos=theIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
theParent=GetDefaultParentTagFor(theParent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
eHTMLTag_table
|
||||
eHTMLTag_tbody
|
||||
eHTMLTag_thead
|
||||
eHTMLTag_tfoot
|
||||
eHTMLTag_caption
|
||||
eHTMLTag_col
|
||||
eHTMLTag_colgroup
|
||||
*/
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -2809,11 +2849,12 @@ nsresult CNavDTD::CreateContextStackFor(eHTMLTags aChildTag){
|
|||
|
||||
//now, build up the stack according to the tags
|
||||
//you have that aren't in the stack...
|
||||
static CStartToken theToken(gEmpty);
|
||||
if(PR_TRUE==bResult){
|
||||
while(kPropagationStack.mCount>0) {
|
||||
eHTMLTags theTag=kPropagationStack.Pop();
|
||||
CToken* theToken=gTokenRecycler.CreateTokenOfType(eToken_start,theTag,gEmpty);
|
||||
HandleStartToken(theToken);
|
||||
theToken.SetTypeID(theTag); //open the container...
|
||||
HandleStartToken(&theToken);
|
||||
}
|
||||
result=NS_OK;
|
||||
}
|
||||
|
|
|
@ -306,6 +306,17 @@ CLASS_EXPORT_HTMLPARS CNavDTD : public nsIDTD {
|
|||
*/
|
||||
virtual PRBool CanContain(PRInt32 aParent,PRInt32 aChild) const;
|
||||
|
||||
/**
|
||||
* This method is called to determine whether or not a tag
|
||||
* of one type can contain a tag of another type.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aParent -- int tag of parent container
|
||||
* @param aChild -- int tag of child container
|
||||
* @return PR_TRUE if parent can contain child
|
||||
*/
|
||||
virtual PRBool CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const;
|
||||
|
||||
/**
|
||||
* This method is called to determine whether a tag
|
||||
* of one of its children can contain a given child tag.
|
||||
|
|
|
@ -1154,33 +1154,67 @@ PRInt32 CSkippedContentToken::GetTokenType(void) {
|
|||
return eToken_skippedcontent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Consume content until you find an end sequence that matches
|
||||
/*
|
||||
* Consume content until you find an end sequence that matches
|
||||
* this objects current mTextValue. Note that this is complicated
|
||||
* by the fact that you can be parsing content that itself
|
||||
* contains quoted content of the same type (like <SCRIPT>).
|
||||
* That means we have to look for quote-pairs, and ignore the
|
||||
* content inside them.
|
||||
*
|
||||
* @update gess 7/25/98
|
||||
* @param aScanner -- controller of underlying input source
|
||||
* @return error result
|
||||
*/
|
||||
nsresult CSkippedContentToken::Consume(PRUnichar,CScanner& aScanner) {
|
||||
PRBool done=PR_FALSE;
|
||||
PRInt32 result=kNoError;
|
||||
nsString temp;
|
||||
* content inside them.
|
||||
*
|
||||
* @update gess 7/25/98
|
||||
* @param aScanner -- controller of underlying input source
|
||||
* @return error result
|
||||
*/
|
||||
nsresult CSkippedContentToken::Consume(PRUnichar aChar,CScanner& aScanner) {
|
||||
PRBool done=PR_FALSE;
|
||||
PRInt32 result=kNoError;
|
||||
nsString temp;
|
||||
|
||||
while((!done) && (kNoError==result)) {
|
||||
static nsAutoString terminals(">");
|
||||
result=aScanner.ReadUntil(temp,terminals,PR_TRUE);
|
||||
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
|
||||
}
|
||||
int len=temp.Length();
|
||||
temp.Truncate(len-mTextValue.Length());
|
||||
mTextKey=temp;
|
||||
return result;
|
||||
}
|
||||
//We're going to try a new algorithm here. Rather than scan for the matching
|
||||
//end tag like we used to do, we're now going to scan for whitespace and comments.
|
||||
//If we find either, just eat them. If we find text or a tag, then go to the
|
||||
//target endtag, or the start of another comment.
|
||||
|
||||
static nsAutoString kEndTerminal(">");
|
||||
static nsAutoString kStartTerminal("<");
|
||||
while((!done) && (kNoError==result)) {
|
||||
result=aScanner.GetChar(aChar);
|
||||
if((kNoError==result) && (kLessThan==aChar)) {
|
||||
//we're reading a tag or a comment...
|
||||
temp+=aChar;
|
||||
result=aScanner.GetChar(aChar);
|
||||
if((kNoError==result) && (kExclamation==aChar)) {
|
||||
//read a comment...
|
||||
static CCommentToken theComment;
|
||||
result=theComment.Consume(aChar,aScanner);
|
||||
if(kNoError==result) {
|
||||
temp.Append(theComment.GetStringValueXXX());
|
||||
}
|
||||
} else {
|
||||
//read a tag...
|
||||
temp+=aChar;
|
||||
result=aScanner.ReadUntil(temp,kEndTerminal,PR_TRUE);
|
||||
}
|
||||
}
|
||||
else if(0<=gWhitespace.Find(aChar)) {
|
||||
static CWhitespaceToken theWS;
|
||||
result=theWS.Consume(aChar,aScanner);
|
||||
if(kNoError==result) {
|
||||
temp.Append(theWS.GetStringValueXXX());
|
||||
}
|
||||
}
|
||||
else {
|
||||
temp+=aChar;
|
||||
result=aScanner.ReadUntil(temp,kStartTerminal,PR_FALSE);
|
||||
}
|
||||
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
|
||||
}
|
||||
int len=temp.Length();
|
||||
temp.Truncate(len-mTextValue.Length());
|
||||
mTextKey=temp;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -395,10 +395,8 @@ PRInt32 nsParser::DidBuildModel(PRInt32 anErrorCode) {
|
|||
if(mParserContext->mDTD) {
|
||||
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext));
|
||||
|
||||
//Now it's time to recycle our used tokens.
|
||||
//The current context has a deque full of them,
|
||||
//and the ones that preceed currentpos are no
|
||||
//longer needed. Let's recycle them.
|
||||
//Now recycle any tokens that are still hanging around.
|
||||
//Come to think of it, there really shouldn't be any.
|
||||
nsDeque& theDeque=mParserContext->mTokenDeque;
|
||||
nsITokenRecycler* theRecycler=mParserContext->mDTD->GetTokenRecycler();
|
||||
if(theRecycler) {
|
||||
|
@ -588,25 +586,25 @@ PRInt32 nsParser::BuildModel() {
|
|||
theRootDTD->Verify(kEmptyString);
|
||||
}
|
||||
|
||||
if(kInterrupted==result) {
|
||||
*mParserContext->mCurrentPos=theMarkPos;
|
||||
|
||||
//Now it's time to recycle our used tokens.
|
||||
//The current context has a deque full of them,
|
||||
//and the ones that preceed currentpos are no
|
||||
//longer needed. Let's recycle them.
|
||||
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
|
||||
if(theRecycler) {
|
||||
nsDeque& theDeque=mParserContext->mTokenDeque;
|
||||
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
|
||||
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
|
||||
if(theRecycler) {
|
||||
nsDeque& theDeque=mParserContext->mTokenDeque;
|
||||
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
|
||||
for(;;) {
|
||||
CToken* theToken=(CToken*)theDeque.Peek();
|
||||
while(theToken && (theToken!=theCurrentToken)) {
|
||||
if(theToken && (theToken!=theCurrentToken)){
|
||||
theDeque.Pop();
|
||||
theRecycler->RecycleToken(theToken);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
mParserContext->mCurrentPos->First();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -217,6 +217,20 @@ eHTMLTags CTagStack::Last() const {
|
|||
return eHTMLTag_unknown;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Now define the token deallocator class...
|
||||
**************************************************************/
|
||||
class CNavTokenDeallocator: public nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject) {
|
||||
CToken* aToken = (CToken*)anObject;
|
||||
delete aToken;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
static CNavTokenDeallocator gTokenKiller;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Now define the tokenrecycler class...
|
||||
**************************************************************/
|
||||
|
@ -230,7 +244,7 @@ eHTMLTags CTagStack::Last() const {
|
|||
class nsCTokenRecycler : public nsITokenRecycler {
|
||||
public:
|
||||
|
||||
enum {eCacheMaxSize=100};
|
||||
// enum {eCacheMaxSize=100};
|
||||
|
||||
nsCTokenRecycler();
|
||||
virtual ~nsCTokenRecycler();
|
||||
|
@ -238,9 +252,8 @@ public:
|
|||
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString);
|
||||
|
||||
protected:
|
||||
CToken* mTokenCache[eToken_last-1][eCacheMaxSize];
|
||||
PRInt32 mCount[eToken_last-1];
|
||||
PRInt32 mTotals[eToken_last-1];
|
||||
nsDeque* mTokenCache[eToken_last-1];
|
||||
// PRInt32 mTotals[eToken_last-1];
|
||||
};
|
||||
|
||||
|
||||
|
@ -250,9 +263,11 @@ protected:
|
|||
* @param
|
||||
*/
|
||||
nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
|
||||
nsCRT::zero(mTokenCache,sizeof(mTokenCache));
|
||||
nsCRT::zero(mCount,sizeof(mCount));
|
||||
nsCRT::zero(mTotals,sizeof(mTotals));
|
||||
int i=0;
|
||||
for(i=0;i<eToken_last-1;i++) {
|
||||
mTokenCache[i]=new nsDeque(gTokenKiller);
|
||||
// mTotals[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -260,13 +275,11 @@ nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
|
|||
* @update gess7/25/98
|
||||
*/
|
||||
nsCTokenRecycler::~nsCTokenRecycler() {
|
||||
//begin by deleting all the known (recycled tokens)...
|
||||
int index1,index2;
|
||||
for(index1=0;index1<eToken_last-1;index1++){
|
||||
for(index2=0;index2<mCount[index1];index2++){
|
||||
if(mTokenCache[index1][index2])
|
||||
delete mTokenCache[index1][index2];
|
||||
}
|
||||
//begin by deleting all the known (recycled) tokens...
|
||||
//We're also deleting the cache-deques themselves.
|
||||
int i;
|
||||
for(i=0;i<eToken_last-1;i++) {
|
||||
delete mTokenCache[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,15 +293,7 @@ nsCTokenRecycler::~nsCTokenRecycler() {
|
|||
void nsCTokenRecycler::RecycleToken(CToken* aToken) {
|
||||
if(aToken) {
|
||||
PRInt32 theType=aToken->GetTokenType();
|
||||
if(mCount[theType-1]<eCacheMaxSize) {
|
||||
mTokenCache[theType-1][mCount[theType-1]]=aToken;
|
||||
mCount[theType-1]++;
|
||||
} else {
|
||||
//this is an overflow condition. More tokens of a given
|
||||
//type have been created than we can store in our recycler.
|
||||
//In this case, just destroy the extra token.
|
||||
delete aToken;
|
||||
}
|
||||
mTokenCache[theType-1]->Push(aToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,17 +306,13 @@ void nsCTokenRecycler::RecycleToken(CToken* aToken) {
|
|||
*/
|
||||
CToken* nsCTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString) {
|
||||
|
||||
CToken* result;
|
||||
CToken* result=(CToken*)mTokenCache[aType-1]->Pop();
|
||||
|
||||
if(0<mCount[aType-1]) {
|
||||
int cnt=CToken::GetTokenCount();
|
||||
result=mTokenCache[aType-1][mCount[aType-1]-1];
|
||||
if(result) {
|
||||
result->Reinitialize(aTag,aString);
|
||||
mTokenCache[aType-1][mCount[aType-1]-1]=0;
|
||||
mCount[aType-1]--;
|
||||
}
|
||||
else {
|
||||
mTotals[aType-1]++;
|
||||
// mTotals[aType-1]++;
|
||||
switch(aType){
|
||||
case eToken_start: result=new CStartToken(aTag); break;
|
||||
case eToken_end: result=new CEndToken(aTag); break;
|
||||
|
@ -465,17 +466,6 @@ void CNavDTD::InitializeDefaultTokenHandlers() {
|
|||
}
|
||||
|
||||
|
||||
class CNavTokenDeallocator: public nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject) {
|
||||
CToken* aToken = (CToken*)anObject;
|
||||
delete aToken;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static CNavTokenDeallocator gTokenKiller;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
|
@ -530,7 +520,7 @@ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
|
|||
* @return
|
||||
*/
|
||||
nsITokenRecycler* CNavDTD::GetTokenRecycler(void){
|
||||
return 0;
|
||||
// return 0;
|
||||
return &gTokenRecycler;
|
||||
}
|
||||
|
||||
|
@ -704,12 +694,14 @@ nsresult CNavDTD::HandleToken(CToken* aToken){
|
|||
nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode) {
|
||||
NS_PRECONDITION(0!=aToken,kNullToken);
|
||||
|
||||
eHTMLTags parentTag=GetTopNode();
|
||||
nsresult result=NS_OK;
|
||||
PRBool contains=CanContain(parentTag,aChildTag);
|
||||
eHTMLTags theParentTag=GetTopNode();
|
||||
nsresult result=NS_OK;
|
||||
PRBool contains=CanContain(theParentTag,aChildTag);
|
||||
|
||||
if(PR_FALSE==contains){
|
||||
result=CreateContextStackFor(aChildTag);
|
||||
if(CanPropagate(theParentTag,aChildTag))
|
||||
result=CreateContextStackFor(aChildTag);
|
||||
else result=kCantPropagate;
|
||||
if(NS_OK!=result) {
|
||||
//if you're here, then the new topmost container can't contain aToken.
|
||||
//You must determine what container hierarchy you need to hold aToken,
|
||||
|
@ -1687,6 +1679,29 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to determine whether or not
|
||||
* the necessary intermediate tags should be propagated
|
||||
* between the given parent and given child.
|
||||
*
|
||||
* @update gess 4/8/98
|
||||
* @param aParent -- tag enum of parent container
|
||||
* @param aChild -- tag enum of child container
|
||||
* @return PR_TRUE if propagation should occur
|
||||
*/
|
||||
PRBool CNavDTD::CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const {
|
||||
PRBool result=PR_TRUE;
|
||||
|
||||
switch(aParent) {
|
||||
case eHTMLTag_td:
|
||||
result=CanContain(aParent,aChild);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}//switch
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to determine whether or not a tag
|
||||
|
@ -2182,18 +2197,43 @@ PRBool CNavDTD::IsGatedFromClosing(eHTMLTags aChildTag) const {
|
|||
|
||||
case eHTMLTag_td:
|
||||
case eHTMLTag_tr:
|
||||
theGatePos=GetTopmostIndexOf(gTableTags);
|
||||
{
|
||||
/***************************************************************************
|
||||
* This code may seem confusing, so let me explain it.
|
||||
* We're trying to handle the case where a child tag may be prevented from
|
||||
* closing a tag already on the stack. Here's a case:
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>
|
||||
* <table>
|
||||
* </tr>
|
||||
*
|
||||
* In this case, the bottom </tr> is "gated" from closing the bottommost
|
||||
* table.
|
||||
*
|
||||
* HOW THIS CODE WORKS:
|
||||
*
|
||||
* This block of code compares all the members of the default parent
|
||||
* hierarchy for the childtag against the open containers on our stack.
|
||||
* If they ever match, then the given child should be gated.
|
||||
***************************************************************************/
|
||||
|
||||
int theIndex;
|
||||
int theTopIndex=mContextStack.mCount-1;
|
||||
|
||||
eHTMLTags theParent=GetDefaultParentTagFor(aChildTag);
|
||||
while(eHTMLTag_unknown!=theParent) {
|
||||
for(theIndex=theTopIndex;theIndex>tagPos;theIndex--){
|
||||
if(mContextStack.mTags[theIndex]==theParent){
|
||||
theGatePos=theIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
theParent=GetDefaultParentTagFor(theParent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
eHTMLTag_table
|
||||
eHTMLTag_tbody
|
||||
eHTMLTag_thead
|
||||
eHTMLTag_tfoot
|
||||
eHTMLTag_caption
|
||||
eHTMLTag_col
|
||||
eHTMLTag_colgroup
|
||||
*/
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -2809,11 +2849,12 @@ nsresult CNavDTD::CreateContextStackFor(eHTMLTags aChildTag){
|
|||
|
||||
//now, build up the stack according to the tags
|
||||
//you have that aren't in the stack...
|
||||
static CStartToken theToken(gEmpty);
|
||||
if(PR_TRUE==bResult){
|
||||
while(kPropagationStack.mCount>0) {
|
||||
eHTMLTags theTag=kPropagationStack.Pop();
|
||||
CToken* theToken=gTokenRecycler.CreateTokenOfType(eToken_start,theTag,gEmpty);
|
||||
HandleStartToken(theToken);
|
||||
theToken.SetTypeID(theTag); //open the container...
|
||||
HandleStartToken(&theToken);
|
||||
}
|
||||
result=NS_OK;
|
||||
}
|
||||
|
|
|
@ -306,6 +306,17 @@ CLASS_EXPORT_HTMLPARS CNavDTD : public nsIDTD {
|
|||
*/
|
||||
virtual PRBool CanContain(PRInt32 aParent,PRInt32 aChild) const;
|
||||
|
||||
/**
|
||||
* This method is called to determine whether or not a tag
|
||||
* of one type can contain a tag of another type.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aParent -- int tag of parent container
|
||||
* @param aChild -- int tag of child container
|
||||
* @return PR_TRUE if parent can contain child
|
||||
*/
|
||||
virtual PRBool CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const;
|
||||
|
||||
/**
|
||||
* This method is called to determine whether a tag
|
||||
* of one of its children can contain a given child tag.
|
||||
|
|
|
@ -1154,33 +1154,67 @@ PRInt32 CSkippedContentToken::GetTokenType(void) {
|
|||
return eToken_skippedcontent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Consume content until you find an end sequence that matches
|
||||
/*
|
||||
* Consume content until you find an end sequence that matches
|
||||
* this objects current mTextValue. Note that this is complicated
|
||||
* by the fact that you can be parsing content that itself
|
||||
* contains quoted content of the same type (like <SCRIPT>).
|
||||
* That means we have to look for quote-pairs, and ignore the
|
||||
* content inside them.
|
||||
*
|
||||
* @update gess 7/25/98
|
||||
* @param aScanner -- controller of underlying input source
|
||||
* @return error result
|
||||
*/
|
||||
nsresult CSkippedContentToken::Consume(PRUnichar,CScanner& aScanner) {
|
||||
PRBool done=PR_FALSE;
|
||||
PRInt32 result=kNoError;
|
||||
nsString temp;
|
||||
* content inside them.
|
||||
*
|
||||
* @update gess 7/25/98
|
||||
* @param aScanner -- controller of underlying input source
|
||||
* @return error result
|
||||
*/
|
||||
nsresult CSkippedContentToken::Consume(PRUnichar aChar,CScanner& aScanner) {
|
||||
PRBool done=PR_FALSE;
|
||||
PRInt32 result=kNoError;
|
||||
nsString temp;
|
||||
|
||||
while((!done) && (kNoError==result)) {
|
||||
static nsAutoString terminals(">");
|
||||
result=aScanner.ReadUntil(temp,terminals,PR_TRUE);
|
||||
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
|
||||
}
|
||||
int len=temp.Length();
|
||||
temp.Truncate(len-mTextValue.Length());
|
||||
mTextKey=temp;
|
||||
return result;
|
||||
}
|
||||
//We're going to try a new algorithm here. Rather than scan for the matching
|
||||
//end tag like we used to do, we're now going to scan for whitespace and comments.
|
||||
//If we find either, just eat them. If we find text or a tag, then go to the
|
||||
//target endtag, or the start of another comment.
|
||||
|
||||
static nsAutoString kEndTerminal(">");
|
||||
static nsAutoString kStartTerminal("<");
|
||||
while((!done) && (kNoError==result)) {
|
||||
result=aScanner.GetChar(aChar);
|
||||
if((kNoError==result) && (kLessThan==aChar)) {
|
||||
//we're reading a tag or a comment...
|
||||
temp+=aChar;
|
||||
result=aScanner.GetChar(aChar);
|
||||
if((kNoError==result) && (kExclamation==aChar)) {
|
||||
//read a comment...
|
||||
static CCommentToken theComment;
|
||||
result=theComment.Consume(aChar,aScanner);
|
||||
if(kNoError==result) {
|
||||
temp.Append(theComment.GetStringValueXXX());
|
||||
}
|
||||
} else {
|
||||
//read a tag...
|
||||
temp+=aChar;
|
||||
result=aScanner.ReadUntil(temp,kEndTerminal,PR_TRUE);
|
||||
}
|
||||
}
|
||||
else if(0<=gWhitespace.Find(aChar)) {
|
||||
static CWhitespaceToken theWS;
|
||||
result=theWS.Consume(aChar,aScanner);
|
||||
if(kNoError==result) {
|
||||
temp.Append(theWS.GetStringValueXXX());
|
||||
}
|
||||
}
|
||||
else {
|
||||
temp+=aChar;
|
||||
result=aScanner.ReadUntil(temp,kStartTerminal,PR_FALSE);
|
||||
}
|
||||
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
|
||||
}
|
||||
int len=temp.Length();
|
||||
temp.Truncate(len-mTextValue.Length());
|
||||
mTextKey=temp;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -395,10 +395,8 @@ PRInt32 nsParser::DidBuildModel(PRInt32 anErrorCode) {
|
|||
if(mParserContext->mDTD) {
|
||||
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext));
|
||||
|
||||
//Now it's time to recycle our used tokens.
|
||||
//The current context has a deque full of them,
|
||||
//and the ones that preceed currentpos are no
|
||||
//longer needed. Let's recycle them.
|
||||
//Now recycle any tokens that are still hanging around.
|
||||
//Come to think of it, there really shouldn't be any.
|
||||
nsDeque& theDeque=mParserContext->mTokenDeque;
|
||||
nsITokenRecycler* theRecycler=mParserContext->mDTD->GetTokenRecycler();
|
||||
if(theRecycler) {
|
||||
|
@ -588,25 +586,25 @@ PRInt32 nsParser::BuildModel() {
|
|||
theRootDTD->Verify(kEmptyString);
|
||||
}
|
||||
|
||||
if(kInterrupted==result) {
|
||||
*mParserContext->mCurrentPos=theMarkPos;
|
||||
|
||||
//Now it's time to recycle our used tokens.
|
||||
//The current context has a deque full of them,
|
||||
//and the ones that preceed currentpos are no
|
||||
//longer needed. Let's recycle them.
|
||||
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
|
||||
if(theRecycler) {
|
||||
nsDeque& theDeque=mParserContext->mTokenDeque;
|
||||
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
|
||||
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
|
||||
if(theRecycler) {
|
||||
nsDeque& theDeque=mParserContext->mTokenDeque;
|
||||
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
|
||||
for(;;) {
|
||||
CToken* theToken=(CToken*)theDeque.Peek();
|
||||
while(theToken && (theToken!=theCurrentToken)) {
|
||||
if(theToken && (theToken!=theCurrentToken)){
|
||||
theDeque.Pop();
|
||||
theRecycler->RecycleToken(theToken);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
mParserContext->mCurrentPos->First();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче