fixed a few nsbeta2+ bugs; r=harishd and kmcclusk

git-svn-id: svn://10.0.0.236/trunk@72354 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rickg%netscape.com
2000-06-16 07:28:02 +00:00
parent c2d42fa98d
commit de64f8f668
16 changed files with 980 additions and 576 deletions

View File

@@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
@@ -17,15 +17,15 @@
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): rickg@netscape.com
* Contributor(s): rickg@netscape.com
*/
//#define ENABLE_CRC
//#define RICKG_DEBUG
//#define ENABLE_CRC
//#define RICKG_DEBUG
#include "nsDebug.h"
#include "nsIDTDDebug.h"
#include "nsIDTDDebug.h"
#include "COtherDTD.h"
#include "nsHTMLTokens.h"
#include "nsCRT.h"
@@ -148,7 +148,6 @@ COtherDTD::COtherDTD() : nsIDTD(), mSharedNodes(0) {
mHadFrameset=PR_FALSE;
mHadBody=PR_FALSE;
mHasOpenScript=PR_FALSE;
mTokenRecycler=0;
mParserCommand=eViewNormal;
#if 1 //set this to 1 if you want strictDTD to be based on the environment setting.
@@ -206,67 +205,6 @@ nsCParserNode* COtherDTD::CreateNode(void) {
}
/**
* This method recycles a given node
* @update gess1/8/99
* @param
* @return
*/
void COtherDTD::RecycleNode(nsCParserNode* aNode) {
if(aNode && (!aNode->mUseCount)) {
if(aNode->mToken) {
if(!aNode->mToken->mUseCount) {
mTokenRecycler->RecycleToken(aNode->mToken);
}
}
CToken* theToken=0;
while((theToken=(CToken*)aNode->PopAttributeToken())){
if(!theToken->mUseCount) {
mTokenRecycler->RecycleToken(theToken);
}
}
mSharedNodes.Push(aNode);
}
}
/**
* This method recycles the nodes on a nodestack.
* NOTE: Unlike recycleNode(), we force the usecount
* to 0 of all nodes, then force them to recycle.
* @update gess1/8/99
* @param aNodeStack
* @return nothing
*/
void COtherDTD::RecycleNodes(nsEntryStack *aNodeStack) {
if(aNodeStack) {
PRInt32 theCount=aNodeStack->mCount;
PRInt32 theIndex=0;
for(theIndex=0;theIndex<theCount;theIndex++) {
nsCParserNode* theNode=(nsCParserNode*)aNodeStack->NodeAt(theIndex);
if(theNode) {
theNode->mUseCount=0;
if(theNode->mToken) {
theNode->mToken->mUseCount=0;
mTokenRecycler->RecycleToken(theNode->mToken);
}
CToken* theToken=0;
while((theToken=(CToken*)theNode->PopAttributeToken())){
theNode->mToken->mUseCount=0;
mTokenRecycler->RecycleToken(theToken);
}
mSharedNodes.Push(theNode);
} //if
} //while
} //if
}
/**
*
* @update gess1/8/99
@@ -476,10 +414,10 @@ nsresult COtherDTD::WillBuildModel( const CParserContext& aParserContext,nsICon
STOP_TIMER();
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillBuildModel(), this=%p\n", this));
mTokenRecycler=0;
mDocType=aParserContext.mDocType;
mBodyContext->mTransitional=PRBool(aParserContext.mDTDMode==eDTDMode_transitional);
mBodyContext->GetTokenRecycler();
if(aSink && (!mSink)) {
result=aSink->QueryInterface(kIHTMLContentSinkIID, (void **)&mSink);
}
@@ -521,12 +459,11 @@ nsresult COtherDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITo
if(mTokenizer) {
mTokenRecycler=(CTokenRecycler*)mTokenizer->GetTokenRecycler();
if(mSink) {
if(!mBodyContext->GetCount()) {
//if the content model is empty, then begin by opening <html>...
CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_html,NS_ConvertToString("html"));
CStartToken *theToken=(CStartToken*)mBodyContext->gTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_html,NS_ConvertToString("html"));
HandleStartToken(theToken); //this token should get pushed on the context stack, don't recycle it.
}
@@ -593,11 +530,13 @@ nsresult COtherDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIPar
nsEntryStack *theChildStyles=0;
nsCParserNode* theNode=(nsCParserNode*)mBodyContext->Pop(theChildStyles);
theNode->mUseCount=0;
RecycleNode(theNode);
if(theChildStyles) {
delete theChildStyles;
}
if(theNode) {
theNode->mUseCount=0;
mBodyContext->RecycleNode(theNode);
if(theChildStyles) {
delete theChildStyles;
}
}
}
}
@@ -653,7 +592,7 @@ nsresult COtherDTD::HandleToken(CToken* aToken,nsIParser* aParser){
if(NS_SUCCEEDED(result) || (NS_ERROR_HTMLPARSER_BLOCK==result)) {
if(0>=theToken->mUseCount)
mTokenRecycler->RecycleToken(theToken);
mBodyContext->gTokenRecycler->RecycleToken(theToken);
}
else if(result==NS_ERROR_HTMLPARSER_STOPPARSING)
mDTDState=result;
@@ -796,7 +735,7 @@ nsresult COtherDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNo
* to be stored in
* 2) close the top container, and add this to
* whatever container ends up on top.
*
*
* @update gess 1/04/99
* @param aToken -- next (start) token to be handled
* @param aNode -- CParserNode representing this start token
@@ -809,49 +748,54 @@ nsresult COtherDTD::HandleStartToken(CToken* aToken) {
//Begin by gathering up attributes...
nsresult result=NS_OK;
nsCParserNode* theNode=CreateNode();
theNode->Init(aToken,mLineNumber,mTokenRecycler);
if(theNode) {
theNode->Init(aToken,mLineNumber,mBodyContext->gTokenRecycler);
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
PRInt16 attrCount=aToken->GetAttributeCount();
eHTMLTags theParent=mBodyContext->Last();
nsresult result=(0==attrCount) ? NS_OK : CollectAttributes(*theNode,theChildTag,attrCount);
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
PRInt16 attrCount=aToken->GetAttributeCount();
eHTMLTags theParent=mBodyContext->Last();
result=(0==attrCount) ? NS_OK : CollectAttributes(*theNode,theChildTag,attrCount);
if(NS_OK==result) {
result=WillHandleStartTag(aToken,theChildTag,*theNode);
if(NS_OK==result) {
result=WillHandleStartTag(aToken,theChildTag,*theNode);
if(NS_OK==result) {
mLineNumber += aToken->mNewlineCount;
mLineNumber += aToken->mNewlineCount;
PRBool theTagWasHandled=PR_FALSE;
PRBool theTagWasHandled=PR_FALSE;
switch(theChildTag) {
switch(theChildTag) {
case eHTMLTag_html:
if(!mBodyContext->HasOpenContainer(theChildTag)){
mSink->OpenHTML(*theNode);
mBodyContext->Push(theNode,0);
}
theTagWasHandled=PR_TRUE;
break;
default:
CElement* theElement=gElementTable->mElements[theParent];
if(theElement) {
result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink);
theTagWasHandled=PR_TRUE;
}
break;
}//switch
if(theTagWasHandled) {
DidHandleStartTag(*theNode,theChildTag);
}
case eHTMLTag_html:
if(!mBodyContext->HasOpenContainer(theChildTag)){
mSink->OpenHTML(*theNode);
mBodyContext->Push(theNode,0);
}
theTagWasHandled=PR_TRUE;
break;
default:
CElement* theElement=gElementTable->mElements[theParent];
if(theElement) {
result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink);
theTagWasHandled=PR_TRUE;
}
break;
}//switch
if(theTagWasHandled) {
DidHandleStartTag(*theNode,theChildTag);
}
} //if
}//if
RecycleNode(theNode);
} //if
}//if
mBodyContext->RecycleNode(theNode);
}
else result=NS_ERROR_OUT_OF_MEMORY;
return result;
}
@@ -872,18 +816,18 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
nsresult result=NS_OK;
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
#ifdef RICKG_DEBUG
#ifdef RICKG_DEBUG
WriteTokenToLog(aToken);
#endif
#endif
switch(theChildTag) {
case eHTMLTag_body: //we intentionally don't let the user close HTML or BODY
case eHTMLTag_html:
break;
break;
case eHTMLTag_script:
mHasOpenScript=PR_FALSE;
case eHTMLTag_script:
mHasOpenScript=PR_FALSE;
default:
PRInt32 theCount=mBodyContext->GetCount();
@@ -898,10 +842,10 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
}
break;
}
return result;
}
return result;
}
/**
* Retrieve the attributes for this node, and add then into
* the node.
@@ -955,11 +899,12 @@ nsresult COtherDTD::HandleEntityToken(CToken* aToken) {
nsString& theStr=aToken->GetStringValueXXX();
PRUnichar theChar=theStr.CharAt(0);
CToken *theToken=0;
if((kHashsign!=theChar) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){
//before we just toss this away as a bogus entity, let's check...
CNamedEntity *theEntity=mBodyContext->GetEntity(theStr);
CToken *theToken=0;
if(theEntity) {
theToken=new CTextToken(theEntity->mValue);
}
@@ -972,6 +917,16 @@ nsresult COtherDTD::HandleEntityToken(CToken* aToken) {
}
result=HandleStartToken(theToken);
}
else {
//add this code to fix bug 42629 (entities were getting dropped).
eHTMLTags theParent=mBodyContext->Last();
CElement* theElement=gElementTable->mElements[theParent];
if(theElement) {
nsCParserNode theNode(aToken,mLineNumber,0);
result=theElement->HandleStartToken(&theNode,eHTMLTag_text,mBodyContext,mSink);
}
}
return result;
}
@@ -1084,22 +1039,6 @@ nsresult COtherDTD::GetTokenizer(nsITokenizer*& aTokenizer) {
return result;
}
/**
*
* @update gess8/4/98
* @param
* @return
*/
nsITokenRecycler* COtherDTD::GetTokenRecycler(void){
if(!mTokenRecycler) {
nsresult result=GetTokenizer(mTokenizer);
if (NS_SUCCEEDED(result)) {
mTokenRecycler=(CTokenRecycler*)mTokenizer->GetTokenRecycler();
}
}
return mTokenRecycler;
}
/**
*

View File

@@ -225,12 +225,13 @@ CLASS_EXPORT_HTMLPARS COtherDTD : public nsIDTD {
NS_IMETHOD GetTokenizer(nsITokenizer*& aTokenizer);
/**
*
* @update gess12/28/98
* @param
* @return
* Note that the otherDTD get's it's recycler from
* the body context.
*
* @update rickg 16June2000
* @return always 0
*/
virtual nsITokenRecycler* GetTokenRecycler(void);
virtual nsITokenRecycler* GetTokenRecycler(void) {return 0;}
/**
* If the parse process gets interrupted, this method gets called
@@ -318,8 +319,6 @@ protected:
nsresult WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsCParserNode& aNode);
nsresult DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag);
nsCParserNode* CreateNode(void);
void RecycleNode(nsCParserNode* aNode);
void RecycleNodes(nsEntryStack *aNodeStack);
nsIHTMLContentSink* mSink;
@@ -335,7 +334,6 @@ protected:
PRInt32 mLineNumber;
nsParser* mParser;
nsITokenizer* mTokenizer;
CTokenRecycler* mTokenRecycler;
PRBool mHasOpenScript;
eHTMLTags mSkipTarget;
nsDeque mSharedNodes;

View File

@@ -161,7 +161,7 @@ public:
static PRBool HasOptionalEndTag(CElement* anElement) {
static eHTMLTags gContainersWithOptionalEndTag[]={eHTMLTag_body,eHTMLTag_colgroup,eHTMLTag_dd,eHTMLTag_dt,
eHTMLTag_head,eHTMLTag_html,eHTMLTag_li,eHTMLTag_option,
eHTMLTag_head,eHTMLTag_li,eHTMLTag_option,
eHTMLTag_p,eHTMLTag_tbody,eHTMLTag_td,eHTMLTag_tfoot,
eHTMLTag_th,eHTMLTag_thead,eHTMLTag_tr,eHTMLTag_unknown};
if(anElement) {
@@ -174,9 +174,29 @@ public:
inline CElement* GetDefaultContainerFor(CElement* anElement);
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext);
virtual PRBool CanBeClosedByStartTag(CElement* anElement,nsDTDContext* aContext);
virtual PRInt32 FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aParentIndex,nsDTDContext* aContext);
virtual PRBool CanBeClosedByEndTag(CElement* anElement,nsDTDContext* aContext);
//This tells us whether this tag can potentially close other blocks.
//That DOES NOT mean that this tag is necessarily a block itself (condsider TBODY,TR,TD...)
virtual PRBool IsBlockCloser(void) {
PRBool result=IsBlockElement(eHTMLTag_body);
if(!result) {
if(IsInlineElement(eHTMLTag_body) ||
mGroup.mBits.mHead ||
mGroup.mBits.mHeadMisc ||
mGroup.mBits.mFormControl ||
mGroup.mBits.mFrame ||
mGroup.mBits.mLeaf ||
mGroup.mBits.mComment ||
mGroup.mBits.mTextContainer ||
mGroup.mBits.mWhiteSpace)
result=PR_FALSE;
else result=PR_TRUE;
}
return result;
}
//this tells us whether this tag is a block tag within the given parent
virtual PRBool IsBlockElement(eHTMLTags aParentID);
@@ -305,11 +325,13 @@ public:
this gets called to close a tag in the given context
**********************************************************/
virtual nsresult CloseContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsEntryStack* theStack=0;
aContext->Pop(theStack);
nsEntryStack *theStack=0;
nsIParserNode *theNode=aContext->Pop(theStack);
CElement *theElement=(aTag==mTag) ? this : GetElement(aTag);
theElement->NotifyClose(aNode,aTag,aContext,aSink);
theElement->NotifyClose(theNode,aTag,aContext,aSink);
aContext->RecycleNode((nsCParserNode*)theNode);
return NS_OK;
}
@@ -585,6 +607,13 @@ public:
return result;
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsresult result=aSink->OpenForm(*aNode);
return result;
}
};
@@ -673,6 +702,39 @@ public:
CElement::Initialize(*this,aTag,CBlockElement::GetGroup(),CTableElement::GetContainedGroups());
}
PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=PR_FALSE;
switch(anElement->mTag) {
case eHTMLTag_caption:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenCaption());
break;
case eHTMLTag_colgroup:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenCols());
break;
case eHTMLTag_thead: //nothing to do for these empty tags...
result=(aContext->mTableStates && aContext->mTableStates->CanOpenTHead());
break;
case eHTMLTag_tfoot:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenTFoot());
break;
case eHTMLTag_tr:
case eHTMLTag_th:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenTBody());
break;
default:
result=CElement::CanContain(anElement,aContext);
break;
}
return result;
}
/**********************************************************
Table needs to be notified so it can manage table states.
**********************************************************/
@@ -806,7 +868,8 @@ public:
end tags, can't deal with the given tag, and want you
to handle it.
**********************************************************/
virtual PRInt32 FindAutoCloseTargetForEndTag(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink, PRInt32& anIndex) {
virtual PRInt32 FindAutoCloseTargetForEndTag(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink, PRInt32& anIndex) {
PRInt32 result=kNotFound;
switch(aTag) {
case eHTMLTag_table:
@@ -818,14 +881,20 @@ public:
case eHTMLTag_tbody:
case eHTMLTag_tr:
case eHTMLTag_td:
return anIndex;
{
PRInt32 theTablePos=aContext->LastOf(eHTMLTag_table);
PRInt32 theTagPos=aContext->LastOf(aTag);
if((kNotFound!=theTagPos) && (theTablePos<=theTagPos)) {
result=theTagPos;
}
}
break;
default:
break;
} //switch
return -1;
return result;
}
};
@@ -846,6 +915,7 @@ public:
CTableRowElement(eHTMLTags aTag=eHTMLTag_tr) : CElement(aTag) {
CTableRowElement::Initialize(*this,aTag);
mContainsGroups.mBits.mSelf=0;
}
virtual nsresult HandleEndTokenForChild(CElement *aChild,nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
@@ -925,6 +995,11 @@ public:
return CElement::HandleStartToken(aNode,aTag,aContext,aSink);
}
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=(mTag==anElement->mTag) ? result=PR_FALSE : CElement::CanContain(anElement,aContext);
return result;
}
/**********************************************************
LI handles the closing of it's own children
**********************************************************/
@@ -1051,11 +1126,13 @@ public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
anElement.mProperties.mIsContainer=1;
anElement.mProperties.mIsSinkContainer=1;
anElement.mTag=aTag;
anElement.mGroup.mAllBits=0;
anElement.mGroup.mBits.mFrame=1;
anElement.mContainsGroups.mAllBits=0;
anElement.mContainsGroups.mBits.mFrame=1;
anElement.mContainsGroups.mBits.mSelf=1;
}
CFrameElement(eHTMLTags aTag) : CElement(aTag) {
@@ -1167,11 +1244,16 @@ public:
virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
if(aNode) {
#if 0
CStartToken theToken(aTag);
PRInt32 theLineNumber=0;
nsCParserNode theNode(&theToken,theLineNumber);
theNode.SetSkippedContent(mText);
result=aSink->AddLeaf(theNode);
#endif
nsCParserNode *theNode=(nsCParserNode*)aNode;
theNode->SetSkippedContent(mText);
result=aSink->AddLeaf(*theNode);
}
mText.Truncate(0);
return result;
@@ -1333,6 +1415,19 @@ public:
return NS_OK;
}
/**********************************************************
this gets called to close a tag in the given context
**********************************************************/
virtual nsresult CloseContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsEntryStack* theStack=0;
nsIParserNode *theNode=aContext->Pop(theStack);
CElement *theElement=(aTag==mTag) ? this : GetElement(aTag);
theElement->NotifyClose(theNode,aTag,aContext,aSink);
return NS_OK;
}
/**********************************************************
Call this for each element as it get's closed
**********************************************************/
@@ -1345,7 +1440,9 @@ public:
PRInt32 theLineNumber=0;
nsCParserNode theNode(&theToken,theLineNumber);
theNode.SetSkippedContent(mText);
result=aSink->AddLeaf(theNode);
//result=aSink->AddLeaf(theNode);
result=aSink->AddLeaf(*aNode);
}
else {
//add it to the head...
@@ -1363,14 +1460,14 @@ public:
/**********************************************************
This defines the preformatted element group, (PRE).
**********************************************************/
class CPreformattedElement: public CInlineElement {
class CPreformattedElement: public CBlockElement {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CInlineElement::Initialize(anElement,aTag);
CBlockElement::Initialize(anElement,aTag);
}
CPreformattedElement(eHTMLTags aTag) : CInlineElement(aTag) {
CPreformattedElement(eHTMLTags aTag) : CBlockElement(aTag) {
mGroup=GetGroup();
mContainsGroups=GetContainedGroups();
mProperties.mIsContainer=1;
@@ -1810,7 +1907,10 @@ public:
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
//for now, let's drop other elements onto the floor.
nsresult result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
CElement *theElement=GetElement(aTag);
if(NS_SUCCEEDED(result)) {
nsCParserNode *theNode=(nsCParserNode*)aNode;
CStartToken *theToken=(CStartToken*)theNode->mToken;
@@ -1879,8 +1979,8 @@ public:
memset(mElements,0,sizeof(mElements));
InitializeElements();
//DebugDumpBlockElements();
//DebugDumpInlineElements();
//DebugDumpBlockElements("test");
//DebugDumpInlineElements("test");
//DebugDumpContainment("all elements");
}
@@ -2053,7 +2153,7 @@ void CElementTable::InitializeElements() {
CFrameElement::Initialize( mDfltElements[eHTMLTag_frameset], eHTMLTag_frameset);
mDfltElements[eHTMLTag_frameset].mIncludeKids=kFramesetKids;
CBlockElement::Initialize( mDfltElements[eHTMLTag_h1], eHTMLTag_h1);
CBlockElement::Initialize( mDfltElements[eHTMLTag_h2], eHTMLTag_h2);
CBlockElement::Initialize( mDfltElements[eHTMLTag_h3], eHTMLTag_h3);
@@ -2174,7 +2274,7 @@ void CElementTable::InitializeElements() {
mDfltElements[eHTMLTag_tfoot].mIncludeKids=kTBodyKids;
mDfltElements[eHTMLTag_tfoot].mContainsGroups.mBits.mSelf=0;
CTableRowElement::Initialize( mDfltElements[eHTMLTag_th], eHTMLTag_th);
CElement::Initialize( mDfltElements[eHTMLTag_th], eHTMLTag_th, CElement::GetEmptyGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_th].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_thead], eHTMLTag_thead, CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
@@ -2388,27 +2488,35 @@ void CElementTable::DebugDumpContainment(const char* aTitle){
Yes, I know it's inconvenient to find this methods here, but it's easier
for the compiler -- and making it's life easier is my top priority.
******************************************************************************/
PRBool CElement::CanBeClosedByStartTag(CElement* anElement,nsDTDContext* aContext) {
PRBool result=PR_FALSE;
PRInt32 CElement::FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aParentIndex,nsDTDContext* aContext) {
PRInt32 result=kNotFound;
//first, let's see if we can contain the given tag based on group info...
if(anElement) {
if(ListContainsTag(mAutoClose,anElement->mTag)) {
return PR_TRUE;
}
else if((this==anElement) && (!mContainsGroups.mBits.mSelf)){
return PR_TRUE;
}
else {
eHTMLTags theTag=aContext->Last();
CElement* theElement=gElementTable->mElements[theTag];
if(HasOptionalEndTag(theElement)) {
if(anElement->CanContain(theElement,aContext)){
result=PR_TRUE;
eHTMLTags theParentTag=aContext->TagAt(aParentIndex);
if(eHTMLTag_unknown!=theParentTag) {
CElement* theParent=gElementTable->mElements[theParentTag];
if(!theParent->CanContain(anElement,aContext)) {
if(HasOptionalEndTag(theParent)) {
if(ListContainsTag(theParent->mAutoClose,anElement->mTag)) {
result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
}
else if((theParent->mTag==anElement->mTag) && (!theParent->mContainsGroups.mBits.mSelf)){
result=aParentIndex;
}
else if(eHTMLTag_body!=theParent->mTag) {
result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
}
else result=aParentIndex+1;
}
}
else result=kNotFound;
}
else result=aParentIndex+1;
}
}
return result;
}
@@ -2473,7 +2581,7 @@ PRBool CElement::CanContain(CElement* anElement,nsDTDContext* aContext) {
***************************************************/
if((!result) && (aContext->mTransitional)) {
switch(anElement->mTag) {
switch(mTag) {
case eHTMLTag_address:
if(eHTMLTag_p==anElement->mTag)
result=PR_TRUE;
@@ -2540,29 +2648,43 @@ nsresult CElement::HandleStartToken( nsIParserNode* aNode,
result=aSink->AddLeaf(*aNode);
}
}
else if(theElement->IsContainer()){
else if(theElement->IsBlockCloser()){
//Ok, so we have a start token that is misplaced. Before handing this off
//to a default container (parent), let's check the autoclose condition.
if(ListContainsTag(mAutoClose,theElement->mTag) || (aTag==mTag)) {
if(HasOptionalEndTag(theElement)) {
//aha! We have a case where this tag is autoclosed by anElement.
//Let's close this container, then try to open theElement.
eHTMLTags theParentTag=aContext->Last();
CElement* theParent=gElementTable->mElements[theParentTag];
while(NS_SUCCEEDED(result) && theParent->CanBeClosedByStartTag(this,aContext)) {
result=theParent->HandleEndToken(aNode,theParentTag,aContext,aSink);
if(HasOptionalEndTag(this)) {
//aha! We have a case where this tag is autoclosed by anElement.
//Let's close this container, then try to open theElement.
PRInt32 theCount=aContext->GetCount();
PRInt32 theIndex=FindAutoCloseIndexForStartTag(theElement,theCount-2,aContext);
//continue ripping code out here...
if(kNotFound!=theIndex) {
eHTMLTags theParentTag=eHTMLTag_unknown;
CElement* theParent=0;
while(NS_SUCCEEDED(result) && (theCount>theIndex)) {
theParentTag=aContext->Last();
theParent=gElementTable->mElements[theParentTag];
nsIParserNode *theNode=aContext->PeekNode(); //this will get popped later...
if(theParent->IsSinkContainer()) {
CloseContainerInContext(theNode,theParentTag,aContext,aSink);
}
else CloseContext(theNode,theParentTag,aContext,aSink);
theCount--;
}
if(NS_SUCCEEDED(result)){
theParentTag=aContext->Last();
theParent=gElementTable->mElements[theParentTag];
return theParent->HandleStartToken(aNode,aTag,aContext,aSink);
result=theParent->HandleStartToken(aNode,aTag,aContext,aSink);
}
else return result;
}
return result;
}
else {
@@ -2630,7 +2752,7 @@ nsresult CElement::HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDConte
result=theGrandParent->HandleEndToken(aNode,theTag,aContext,aSink);
theCount--;
}
return result;
//return result;
}
return result;
}

View File

@@ -357,7 +357,9 @@ eHTMLTags nsEntryStack::Last() const {
/***************************************************************
Now define the dtdcontext class
***************************************************************/
CNodeRecycler* nsDTDContext::mNodeRecycler=0;
CNodeRecycler *nsDTDContext::gNodeRecycler=0;
CTokenRecycler *nsDTDContext::gTokenRecycler=0;
/**
*
@@ -499,6 +501,15 @@ public:
}
/**
* Get a counter string in the given style for the given value.
*
* @update rickg 6June2000
*
* @param aFormat -- format of choice
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void GetFormattedString(eNumFormat aFormat,PRInt32 aValue, nsString& aString,const char* aCharSet, int anOffset, int aBase) {
switch (aFormat) {
case eDecimal: DecimalString(aValue,aString); break;
@@ -514,6 +525,14 @@ public:
}
}
/**
* Compute a counter string in the casted-series style for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void SeriesString(PRInt32 aValue,nsString& aString,const char* aCharSet, int offset, int base) {
int ndex=0;
int root=1;
@@ -539,6 +558,14 @@ public:
}
}
/**
* Compute a counter string in the spelled style for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void SpelledString(PRInt32 aValue,nsString& aString) {
static char ones[][12]= {"zero","one ","two ","three ","four ","five ","six ","seven ","eight ","nine ","ten "};
@@ -553,26 +580,26 @@ public:
PRInt32 root=1000000000;
PRInt32 expn=4;
PRInt32 modu=0;
PRInt32 temp=0;
aValue=abs(aValue);
if(0<aValue) {
while(root && aValue) {
if(temp=aValue/root) {
PRInt32 div=temp/100;
if (div) {//start with hundreds part
aString.AppendWithConversion(ones[div]);
PRInt32 temp=aValue/root;
if(temp) {
PRInt32 theDiv=temp/100;
if (theDiv) {//start with hundreds part
aString.AppendWithConversion(ones[theDiv]);
aString.AppendWithConversion(bases[1]);
}
modu=(temp%10);
div=(temp%100)/10;
if (div) {
if (div<2) {
theDiv=(temp%100)/10;
if (theDiv) {
if (theDiv<2) {
aString.AppendWithConversion(teens[modu]);
modu=0;
}
else aString.AppendWithConversion(tens[div]);
else aString.AppendWithConversion(tens[theDiv]);
}
if (modu)
aString.AppendWithConversion(ones[modu]); //do remainder
@@ -587,11 +614,27 @@ public:
else aString.AppendWithConversion(ones[0]);
}
/**
* Compute a counter string in the decimal format for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void DecimalString(PRInt32 aValue,nsString& aString) {
aString.Truncate();
aString.AppendInt(aValue);
}
/**
* Compute a counter string in binary format for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void BinaryString(PRInt32 aValue,nsString& aString) {
static char kBinarySet[]="01";
@@ -600,6 +643,14 @@ public:
SeriesString(aValue,aString,kBinarySet,0,2);
}
/**
* Compute a counter string in hex format for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void HexString(PRInt32 aValue,nsString& aString) {
static char kHexSet[]="0123456789ABCDEF";
@@ -608,6 +659,14 @@ public:
SeriesString(aValue,aString,kHexSet,0,16);
}
/**
* Compute a counter string in the roman style for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void RomanString(PRInt32 aValue,nsString& aString) {
static char digitsA[] = "ixcm";
static char digitsB[] = "vld?";
@@ -648,6 +707,14 @@ public:
}
}
/**
* Compute a counter string in the alpha style for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void AlphaString(PRInt32 aValue,nsString& aString) {
static const char kAlphaSet[]="abcdefghijklmnopqrstuvwxyz";
@@ -655,6 +722,14 @@ public:
SeriesString(aValue-1,aString,kAlphaSet,-1,26);
}
/**
* Compute a counter string in the footnote style for the given value.
*
* @update rickg 6June2000
*
* @param aValue -- cardinal value of string
* @param aString -- will hold result
*/
static void FootnoteString(PRInt32 aValue,nsString& aString) {
static char kFootnoteSet[]="abcdefg";
@@ -822,7 +897,7 @@ nsIParserNode* nsDTDContext::Pop(nsEntryStack *&aChildStyleStack) {
return result;
}
/**
*
* @update harishd 04/07/00
@@ -1024,21 +1099,67 @@ nsIParserNode* nsDTDContext::RemoveStyle(eHTMLTags aTag){
*/
nsresult nsDTDContext::GetNodeRecycler(CNodeRecycler*& aNodeRecycler){
nsresult result=NS_OK;
if(!mNodeRecycler) {
mNodeRecycler=new CNodeRecycler();
if(mNodeRecycler==0) result=NS_ERROR_OUT_OF_MEMORY;
if(!gNodeRecycler) {
gNodeRecycler=new CNodeRecycler();
if(gNodeRecycler==0) result=NS_ERROR_OUT_OF_MEMORY;
}
aNodeRecycler=mNodeRecycler;
aNodeRecycler=gNodeRecycler;
return result;
}
/**
* This gets called someone wants to create a token of the given type.
*
* @update hairshd 04/10/00
* @update rickg 16June2000
* @param aType
* @param aTag
* @param aString
* @return new CToken* or 0.
*/
void nsDTDContext::FreeNodeRecycler(){
if(mNodeRecycler) {
delete mNodeRecycler;
CTokenRecycler* nsDTDContext::GetTokenRecycler(void) {
if(!gTokenRecycler) {
gTokenRecycler = new CTokenRecycler();
}
return gTokenRecycler;
}
/**
*
* @update rickg 16June2000
*/
void nsDTDContext::RecycleNode(nsCParserNode* aNode) {
nsresult result=NS_OK;
if(aNode) {
if(!gNodeRecycler)
result=nsDTDContext::GetNodeRecycler(gNodeRecycler);
if(NS_SUCCEEDED(result)) {
if(!gTokenRecycler)
GetTokenRecycler();
gNodeRecycler->RecycleNode(aNode,gTokenRecycler);
}
else {
delete aNode;
}
}
}
/**
* This gets called when the parser module is getting unloaded
*
* @return nada
*/
void nsDTDContext::ReleaseGlobalObjects(){
if(gNodeRecycler) {
delete gNodeRecycler;
gNodeRecycler=0;
}
if(gTokenRecycler) {
delete gTokenRecycler;
gTokenRecycler=0;
}
}
@@ -1124,10 +1245,14 @@ void CTokenRecycler::RecycleToken(CToken* aToken) {
/**
* Let's get this code ready to be reused by all the contexts.
*
* @update vidur 11/12/98
* @param
* @return
* @update rickg 12June2000
* @param aType -- tells you the type of token to create
* @param aTag -- tells you the type of tag to init with this token
* @param aString -- gives a default string value for the token
*
* @return ptr to new token (or 0).
*/
CToken* CTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString) {
@@ -1164,10 +1289,13 @@ CToken* CTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag,
}
/**
* Let's get this code ready to be reused by all the contexts.
*
* @update vidur 11/12/98
* @param
* @return
* @update rickg 12June2000
* @param aType -- tells you the type of token to create
* @param aTag -- tells you the type of tag to init with this token
*
* @return ptr to new token (or 0).
*/
CToken* CTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag) {

View File

@@ -206,6 +206,56 @@ public:
PRInt32 mOrdinal;
};
/************************************************************************
CTokenRecycler class implementation.
This class is used to recycle tokens.
By using this simple class, we cut WAY down on the number of tokens
that get created during the run of the system.
************************************************************************/
class CTokenRecycler : public nsITokenRecycler {
public:
// enum {eCacheMaxSize=100};
CTokenRecycler();
virtual ~CTokenRecycler();
virtual void RecycleToken(CToken* aToken);
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString);
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag);
protected:
nsDeque* mTokenCache[eToken_last-1];
nsString mEmpty;
#ifdef NS_DEBUG
int mTotals[eToken_last-1];
#endif
};
/************************************************************************
CNodeRecycler class implementation.
This class is used to recycle nodes.
By using this simple class, we cut down on the number of nodes
that get created during the run of the system.
************************************************************************/
class CNodeRecycler {
public:
CNodeRecycler();
virtual ~CNodeRecycler();
virtual nsCParserNode* CreateNode(void);
virtual void RecycleNode(nsCParserNode* aNode,nsITokenRecycler* aTokenRecycler=0);
protected:
nsDeque mSharedNodes;
#ifdef NS_DEBUG
PRInt32 gNodeCount;
#endif
};
/************************************************************************
The dtdcontext class defines an ordered list of tags (a context).
@@ -240,7 +290,9 @@ public:
nsIParserNode* RemoveStyle(eHTMLTags aTag);
nsresult GetNodeRecycler(CNodeRecycler*& aNodeRecycler);
static void FreeNodeRecycler(void);
void RecycleNode(nsCParserNode *aNode);
CTokenRecycler* GetTokenRecycler(void);
static void ReleaseGlobalObjects(void);
CNamedEntity* RegisterEntity(const nsString& aName,const nsString& aValue);
CNamedEntity* GetEntity(const nsString& aName)const;
@@ -256,7 +308,8 @@ public:
PRBool mTransitional;
PRBool mHadDocTypeDecl;
static CNodeRecycler* mNodeRecycler;
static CNodeRecycler *gNodeRecycler;
static CTokenRecycler *gTokenRecycler;
CTableState *mTableStates;
PRInt32 mCounters[NS_HTML_TAG_MAX];
@@ -282,55 +335,6 @@ public:
};
/************************************************************************
CTokenRecycler class implementation.
This class is used to recycle tokens.
By using this simple class, we cut WAY down on the number of tokens
that get created during the run of the system.
************************************************************************/
class CTokenRecycler : public nsITokenRecycler {
public:
// enum {eCacheMaxSize=100};
CTokenRecycler();
virtual ~CTokenRecycler();
virtual void RecycleToken(CToken* aToken);
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString);
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag);
protected:
nsDeque* mTokenCache[eToken_last-1];
nsString mEmpty;
#ifdef NS_DEBUG
int mTotals[eToken_last-1];
#endif
};
/************************************************************************
CNodeRecycler class implementation.
This class is used to recycle nodes.
By using this simple class, we cut down on the number of nodes
that get created during the run of the system.
************************************************************************/
class CNodeRecycler {
public:
CNodeRecycler();
virtual ~CNodeRecycler();
virtual nsCParserNode* CreateNode(void);
virtual void RecycleNode(nsCParserNode* aNode,nsITokenRecycler* aTokenRecycler=0);
protected:
nsDeque mSharedNodes;
#ifdef NS_DEBUG
PRInt32 gNodeCount;
#endif
};
/************************************************************************
ITagHandler class offers an API for taking care of specific tokens.
************************************************************************/

View File

@@ -900,7 +900,7 @@ nsresult ConsumeComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString)
while((NS_OK==result)) {
theCurrOffset=theBuffer.FindChar(kGreaterThan,PR_TRUE,theCurrOffset);
if(theCurrOffset>kNotFound) {
if(kNotFound!=theCurrOffset) {
theCurrOffset++;
aChar=theBuffer[theCurrOffset-3];
if(kMinus==aChar) {
@@ -955,7 +955,7 @@ nsresult ConsumeComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString)
* Consume the identifier portion of the comment.
* Note that we've already eaten the "<!" portion.
*
* @update gess 1/27/99
* @update gess 16June2000
* @param aChar -- last char consumed from stream
* @param aScanner -- controller of underlying input source
* @return error result
@@ -965,11 +965,11 @@ nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMo
switch(aMode) {
case eDTDMode_strict:
ConsumeStrictComment(aChar,aScanner,mTextValue);
result=ConsumeStrictComment(aChar,aScanner,mTextValue);
break;
case eDTDMode_transitional:
default:
ConsumeComment(aChar,aScanner,mTextValue);
result=ConsumeComment(aChar,aScanner,mTextValue);
break;
} //switch
@@ -977,7 +977,7 @@ nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMo
}
/*
/*
*
*
* @update gess 3/25/98

View File

@@ -104,10 +104,8 @@ public:
nsIDTD* theDTD;
#if 1
NS_NewNavHTMLDTD(&theDTD); //do this as a default HTML DTD...
mDTDDeque.Push(theDTD);
#endif
NS_NewOtherHTMLDTD(&mOtherDTD); //do this as the default DTD for strict documents...
mDTDDeque.Push(mOtherDTD);
@@ -627,16 +625,6 @@ void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType&
}
} //if
else {
PRInt32 thePos=aBuffer.Find("HTML",PR_TRUE,1,50);
if(kNotFound!=thePos) {
aDocType=eHTML4Text;
PRInt32 theIDPos=aBuffer.Find("PublicID",thePos);
if(kNotFound==theIDPos)
theIDPos=aBuffer.Find("SystemID",thePos);
aParseMode=(kNotFound==theIDPos) ? eDTDMode_quirks : eDTDMode_strict;
}
}
}
else if(kNotFound<(theIndex=aBuffer.Find("?XML",PR_TRUE,0,128))) {
aParseMode=eDTDMode_strict;
@@ -731,6 +719,13 @@ PRBool FindSuitableDTD( CParserContext& aParserContext,nsString& aBuffer) {
}
if(theBestDTD) {
//#define FORCE_HTML_THROUGH_STRICT_DTD
#if FORCE_HTML_THROUGH_STRICT_DTD
if(theBestDTD==gSharedObjects.mDTDDeque.ObjectAt(0))
theBestDTD=(nsIDTD*)gSharedObjects.mDTDDeque.ObjectAt(1);
#endif
theBestDTD->CreateNewInstance(&aParserContext.mDTD);
return PR_TRUE;
}
@@ -755,7 +750,7 @@ nsresult nsParser::CreateCompatibleDTD(nsIDTD** aDTD,
const nsString* aMimeType,
nsDTDMode aDTDMode)
{
nsresult result=NS_OK;
nsresult result=NS_OK;
const nsCID* theDTDClassID=0;
/**
@@ -1026,6 +1021,22 @@ nsresult nsParser::WillBuildModel(nsString& aFilename){
nsString& theBuffer=mParserContext->mScanner->GetBuffer();
DetermineParseMode(theBuffer,mParserContext->mDTDMode,mParserContext->mDocType,mParserContext->mMimeType);
#define DISABLE_TRANSITIONAL_MODE
#ifdef DISABLE_TRANSITIONAL_MODE
/********************************************************************************************
The following code is here because to deal with a nasty backward compatibility problem.
The composer product emits <doctype HTML 4.0 Transitional> for the documents it creates,
but the documents aren't really compliant. To prevent lots of pages from breaking, well
disable proper handling of Transitional doctypes and use quirks mode instead. If lucky,
we'll get to add a pref to allow power users to get the right answer.
********************************************************************************************/
if(eDTDMode_transitional==mParserContext->mDTDMode) {
mParserContext->mDTDMode=eDTDMode_quirks;
}
#endif
if(PR_TRUE==FindSuitableDTD(*mParserContext,theBuffer)) {
mParserContext->mDTD->WillBuildModel( *mParserContext,mSink);
}//if

View File

@@ -211,7 +211,7 @@ nsParserModule::Shutdown()
nsHTMLTokenizer::FreeTokenRecycler();
nsXMLTokenizer::FreeTokenRecycler();
nsExpatTokenizer::FreeTokenRecycler();
nsDTDContext::FreeNodeRecycler();
nsDTDContext::ReleaseGlobalObjects();
nsParser::FreeSharedObjects();
mInitialized = PR_FALSE;
COtherDTD::ReleaseTable();