fixed nsbeta3 bugs (crash and compatibility), an FMM, reduced memory usage. Top100+Regression tests ok. R=harishd/buster

git-svn-id: svn://10.0.0.236/trunk@78537 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rickg%netscape.com
2000-09-08 23:06:13 +00:00
parent 06a7d511c9
commit ece465da5b
36 changed files with 886 additions and 218 deletions

View File

@@ -26,9 +26,6 @@
#define ENABLE_RESIDUALSTYLE
#ifdef RICKG_DEBUG
#include <fstream.h>
#endif
#include "nsDebug.h"
#include "nsIDTDDebug.h"
@@ -183,7 +180,7 @@ CNavDTD::CNavDTD() : nsIDTD(),
void CNavDTD::ReleaseTable(void) {
if(gHTMLElements) {
delete gHTMLElements;
delete [] gHTMLElements; //fixed bug 49564
gHTMLElements=0;
}
}
@@ -540,7 +537,7 @@ nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParse
result=HandleToken(theEndToken,mParser);
}
}
if(!mBodyContext->mHadDocTypeDecl) {
if(!mBodyContext->mFlags.mHadDocTypeDecl) {
CToken* theDocTypeToken=mTokenAllocator->CreateTokenOfType(eToken_doctypeDecl,eHTMLTag_markupDecl);
if(theDocTypeToken) {
nsAutoString theDocTypeStr;
@@ -1003,7 +1000,7 @@ PRBool CanBeContained(eHTMLTags aChildTag,nsDTDContext& aContext) {
return result;
}
enum eProcessRule {eIgnore,eTest};
enum eProcessRule {eNormalOp,eLetInlineContainBlock};
/**
* This method gets called when a start token has been
@@ -1039,9 +1036,24 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI
return result;
}
eProcessRule theRule=eTest;
eProcessRule theRule=eNormalOp;
if((!theParentContains) &&
(nsHTMLElement::IsResidualStyleTag(theParentTag)) &&
(IsBlockElement(aChildTag,theParentTag))) {
if(eHTMLTag_table!=aChildTag) {
nsCParserNode* theParentNode= NS_STATIC_CAST(nsCParserNode*, mBodyContext->PeekNode());
if(theParentNode->mToken->IsWellFormed()) {
theRule=eLetInlineContainBlock;
}
}
}
switch(theRule){
case eTest:
case eNormalOp:
theChildAgrees=PR_TRUE;
if(theParentContains) {
@@ -1115,7 +1127,11 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI
}
}//if
break;
case eIgnore:
case eLetInlineContainBlock:
theParentContains=theChildAgrees=PR_TRUE; //cause us to fall out of loop and open the block.
break;
default:
break;
@@ -1171,6 +1187,19 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode
}
}
/**************************************************************************************
*
* Now a little code to deal with bug #49687 (crash when layout stack gets too deep)
*
**************************************************************************************/
if(MAX_REFLOW_DEPTH<mBodyContext->GetCount()) {
if(gHTMLElements[aTag].IsMemberOf(kInlineEntity)) {
if(!gHTMLElements[aTag].IsMemberOf(kFormControl)) {
return kHierarchyTooDeep;
}
}
}
STOP_TIMER()
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this));
@@ -1547,6 +1576,12 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) {
}//if
} //if
if(kHierarchyTooDeep==result) {
//reset this error to ok; all that happens here is that given inline tag
//gets dropped because the stack is too deep. Don't terminate parsing.
result=NS_OK;
}
mNodeRecycler->RecycleNode(theNode);
return result;
}
@@ -1929,8 +1964,12 @@ nsresult CNavDTD::HandleEntityToken(CToken* aToken) {
//if you're here we have a bogus entity.
//convert it into a text token.
theToken=(CTextToken*)mTokenAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text,NS_ConvertToString("&"));
if(theToken) {
nsString &theTokenStr=theToken->GetStringValueXXX();
theTokenStr.Append(theStr); //should append the entity name; fix bug 51161.
}
}
return HandleToken(theToken,mParser);
return HandleToken(theToken,mParser); //theToken should get recycled automagically...
}
eHTMLTags theParentTag=mBodyContext->Last();
@@ -2086,7 +2125,7 @@ nsresult CNavDTD::HandleDocTypeDeclToken(CToken* aToken){
nsresult result=NS_OK;
if(mBodyContext) {
mBodyContext->mHadDocTypeDecl=PR_TRUE;
mBodyContext->mFlags.mHadDocTypeDecl=PR_TRUE;
}
#ifdef RICKG_DEBUG
@@ -2182,7 +2221,8 @@ nsresult CNavDTD::CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt32
/**
* Causes the next skipped-content token (if any) to
* be consumed by this node.
* @update gess5/11/98
*
* @update gess 4Sep2000
* @param node to consume skipped-content
* @param holds the number of skipped content elements encountered
* @return Error condition.
@@ -2199,7 +2239,7 @@ nsresult CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) {
PRBool aMustConvertLinebreaks = PR_FALSE;
mScratch.Truncate();
aNode.SetSkippedContent(mScratch);
aNode.SetSkippedContent(mScratch); //this guarantees us some skipped content storage.
for(aIndex=0;aIndex<aMax;aIndex++){
CHTMLToken* theNextToken=(CHTMLToken*)mSkippedContent.PopFront();
@@ -2210,8 +2250,8 @@ nsresult CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) {
// the start token as mTrailing content and will get appended in
// start token's GetSource();
if(eToken_attribute!=theTokenType) {
if (eToken_entity==theTokenType) {
if((eHTMLTag_textarea==theNodeTag) || (eHTMLTag_title==theNodeTag)) {
if ((eToken_entity==theTokenType) &&
((eHTMLTag_textarea==theNodeTag) || (eHTMLTag_title==theNodeTag))) {
mScratch.Truncate();
((CEntityToken*)theNextToken)->TranslateToUnicodeStr(mScratch);
// since this is an entity, we know that it's only one character.
@@ -2222,10 +2262,10 @@ nsresult CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) {
aNode.mSkippedContent->Append(mScratch);
}
}
}
else {
theNextToken->AppendSource(*aNode.mSkippedContent);
}
else theNextToken->AppendSource(*aNode.mSkippedContent);
}
else {
theNextToken->AppendSource(*aNode.mSkippedContent);
}
IF_FREE(theNextToken);
}

View File

@@ -513,7 +513,7 @@ protected:
PRInt32 mLineNumber;
nsParser* mParser;
nsITokenizer* mTokenizer;
nsTokenAllocator* mTokenAllocator;
nsTokenAllocator* mTokenAllocator;
CNodeRecycler* mNodeRecycler;
nsDeque mMisplacedContent;
nsDeque mSkippedContent;
@@ -528,11 +528,11 @@ protected:
PRUint32 mComputedCRC32;
PRUint32 mExpectedCRC32;
nsAutoString mScratch; //used for various purposes; non-persistent
nsString mScratch; //used for various purposes; non-persistent
PRBool mStyleHandlingEnabled;
PRBool mRequestedHead;
PRBool mIsFormContainer;
nsAutoString mMimeType;
nsAutoString mMimeType; //ok as an autostring; these are short.
};

View File

@@ -416,7 +416,7 @@ nsresult COtherDTD::WillBuildModel( const CParserContext& aParserContext,nsICon
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillBuildModel(), this=%p\n", this));
mDocType=aParserContext.mDocType;
mBodyContext->mTransitional=PRBool(aParserContext.mDTDMode==eDTDMode_transitional);
mBodyContext->mFlags.mTransitional=PRBool(aParserContext.mDTDMode==eDTDMode_transitional);
if(aSink && (!mSink)) {
result=aSink->QueryInterface(kIHTMLContentSinkIID, (void **)&mSink);

View File

@@ -344,7 +344,7 @@ protected:
PRUint32 mComputedCRC32;
PRUint32 mExpectedCRC32;
nsAutoString mScratch; //used for various purposes; non-persistent
nsString mScratch; //used for various purposes; non-persistent
eParserDocType mDocType;
PRBool mEnableStrict;

View File

@@ -159,17 +159,6 @@ public:
anElement.mContainsGroups.mAllBits=aContainsGroups.mAllBits;
}
static PRBool HasOptionalEndTag(CElement* anElement) {
static eHTMLTags gContainersWithOptionalEndTag[]={eHTMLTag_body,eHTMLTag_colgroup,eHTMLTag_dd,eHTMLTag_dt,
eHTMLTag_head,eHTMLTag_li,eHTMLTag_option,
eHTMLTag_p,eHTMLTag_tbody,eHTMLTag_td,eHTMLTag_tfoot,
eHTMLTag_th,eHTMLTag_thead,eHTMLTag_tr,eHTMLTag_unknown};
if(anElement) {
return ListContainsTag(gContainersWithOptionalEndTag,anElement->mTag);
}
return PR_FALSE;
}
inline CElement* GetDelegate(void);
inline CElement* GetDefaultContainerFor(CElement* anElement);
@@ -236,7 +225,7 @@ public:
PRInt32 result=-1;
if(mTag!=aTag) {
if(HasOptionalEndTag(this) && (0<anIndex)) {
if(HasOptionalEndTag(mTag) && (0<anIndex)) {
eHTMLTags theGrandParentTag=aContext->TagAt(--anIndex);
CElement *theGrandParent=GetElement(theGrandParentTag);
if(theGrandParent) {
@@ -340,7 +329,7 @@ public:
/**********************************************************
this gets called to close a tag in the sink and in the context
**********************************************************/
virtual nsresult CloseContainerInContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
virtual nsresult CloseContainerInContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsresult result=NS_OK;
if(mTag!=aTag) {
CElement *theElement=GetElement(aTag);
@@ -600,7 +589,7 @@ public:
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=CElement::CanContain(anElement,aContext);
if((!result) && (aContext->mTransitional)) {
if((!result) && (aContext->mFlags.mTransitional)) {
//If we're in transitional mode, then also allow inline elements...
@@ -1209,9 +1198,9 @@ public:
nsresult result=NS_OK;
if(aSink && aContext) {
if(aContext->mHasOpenHead==PR_FALSE) {
if(aContext->mFlags.mHasOpenHead==PR_FALSE) {
result=aSink->OpenHead(*aNode);
aContext->mHasOpenHead=PR_TRUE;
aContext->mFlags.mHasOpenHead=PR_TRUE;
}
}
return result;
@@ -1222,9 +1211,9 @@ public:
nsresult result=NS_OK;
if(aSink && aContext) {
if(aContext->mHasOpenHead==PR_TRUE) {
if(aContext->mFlags.mHasOpenHead==PR_TRUE) {
result=aSink->CloseHead(*aNode);
aContext->mHasOpenHead=PR_FALSE;
aContext->mFlags.mHasOpenHead=PR_FALSE;
}
}
return result;
@@ -1809,7 +1798,7 @@ public:
case eHTMLTag_frameset:
result=aSink->OpenFrameset(*aNode);
result=OpenContext(aNode,aTag,aContext,aSink);
aContext->mHadFrameset=PR_TRUE;
aContext->mFlags.mHadFrameset=PR_TRUE;
break;
case eHTMLTag_base: //nothing to do for these empty tags...
@@ -1943,7 +1932,7 @@ public:
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=CElement::CanContain(anElement,aContext);
if((!result) && (aContext->mTransitional)) {
if((!result) && (aContext->mFlags.mTransitional)) {
//let's try so additions that are specific to the body tag,
//and only work in transitional mode...
@@ -1979,9 +1968,9 @@ public:
// If that's the case then make sure that we don't open up multiple contexts, however,
// don't forget to inform the sink because it needs to account for the BODY attributes.
if(aContext) {
if(!aContext->mHadBody) {
if(!aContext->mFlags.mHadBody) {
result=OpenContext(aNode,aTag,aContext,aSink);
aContext->mHadBody=PR_TRUE;
aContext->mFlags.mHadBody=PR_TRUE;
}
}
return (NS_SUCCEEDED(result))? OpenContainer(aNode,aTag,aContext,aSink):result;
@@ -2596,7 +2585,7 @@ PRInt32 CElement::FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aPar
CElement* theParent=gElementTable->mElements[theParentTag];
if(!theParent->CanContain(anElement,aContext)) {
if(HasOptionalEndTag(theParent)) {
if(HasOptionalEndTag(theParentTag)) {
if(ListContainsTag(theParent->mAutoClose,anElement->mTag)) {
result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
@@ -2636,7 +2625,7 @@ PRBool CElement::CanBeClosedByEndTag(CElement* anElement,nsDTDContext* aContext)
else {
eHTMLTags theTag=aContext->Last();
CElement* theElement=gElementTable->mElements[theTag];
if(HasOptionalEndTag(theElement)) {
if(HasOptionalEndTag(theTag)) {
if(anElement->CanContain(theElement,aContext)){
result=PR_TRUE;
}
@@ -2678,7 +2667,7 @@ PRBool CElement::CanContain(CElement* anElement,nsDTDContext* aContext) {
this table, and to override CanContain() there.
***************************************************/
if((!result) && (aContext->mTransitional)) {
if((!result) && (aContext->mFlags.mTransitional)) {
switch(mTag) {
case eHTMLTag_address:
if(eHTMLTag_p==anElement->mTag)
@@ -2750,7 +2739,7 @@ nsresult CElement::HandleStartToken( nsIParserNode* aNode,
//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(HasOptionalEndTag(this)) {
if(HasOptionalEndTag(mTag)) {
//aha! We have a case where this tag is autoclosed by anElement.
//Let's close this container, then try to open theElement.

View File

@@ -115,7 +115,7 @@ public:
virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,PRInt32 aMode);
eRTFTags mTag;
nsAutoString mArgument;
nsString mArgument;
};

View File

@@ -367,13 +367,9 @@ nsDTDContext::nsDTDContext() : mStack(), mEntities(0){
mResidualStyleCount=0;
mContextTopIndex=0;
mTableStates=0;
mHadBody=PR_FALSE;
mHadFrameset=PR_TRUE;
mTransitional=PR_FALSE;
ResetCounters();
mHadDocTypeDecl=PR_FALSE;
mHasOpenHead=PR_FALSE;
mCounters=0;
mTokenAllocator=0;
mAllBits=0;
#ifdef NS_DEBUG
memset(mXTags,0,sizeof(mXTags));
@@ -408,6 +404,10 @@ nsDTDContext::~nsDTDContext() {
CEntityDeallocator theDeallocator;
mEntities.ForEach(theDeallocator);
if(mCounters) {
delete [] mCounters;
mCounters = 0;
}
}
@@ -757,12 +757,25 @@ protected:
};
/**
*
* @update gess 11May2000
*/
void nsDTDContext::AllocateCounters(void) {
if(!mCounters) {
mCounters = new PRInt32 [NS_HTML_TAG_MAX]; //in addition to reseting, you may need to allocate.
ResetCounters();
}
}
/**
*
* @update gess 11May2000
*/
void nsDTDContext::ResetCounters(void) {
memset(mCounters,0,sizeof(mCounters));
if(mCounters) {
memset(mCounters,0,NS_HTML_TAG_MAX*sizeof(PRInt32));
}
}
/**********************************************************
@@ -824,8 +837,13 @@ PRInt32 nsDTDContext::IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsStr
PRInt32 err=0;
theNewValue=theValue.ToInteger(&err);
if(!err) {
theIncrValue=0;
mCounters[aTag]=theNewValue;
AllocateCounters();
if(mCounters) {
mCounters[aTag]=theNewValue;
}
}
else theNewValue=-1;
}
@@ -834,7 +852,13 @@ PRInt32 nsDTDContext::IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsStr
if(theEntity && (eHTMLTag_userdefined==aTag)) {
result=theEntity->mOrdinal+=theIncrValue;
}
else result=mCounters[aTag]+=theIncrValue;
else {
AllocateCounters();
if(mCounters) {
result=mCounters[aTag]+=theIncrValue;
}
else result=0;
}
CAbacus::GetFormattedString(theNumFormat,result,aResult,0,0,0);
return result;

View File

@@ -206,9 +206,9 @@ public:
}
nsAutoString mName;
nsAutoString mValue;
PRInt32 mOrdinal;
nsString mName;
nsString mValue;
PRInt32 mOrdinal;
};
/************************************************************************
@@ -304,6 +304,7 @@ public:
CNamedEntity* GetEntity(const nsString& aName)const;
void ResetCounters(void);
void AllocateCounters(void);
PRInt32 IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsString& aResult);
void SetTokenAllocator(nsTokenAllocator* aTokenAllocator) { mTokenAllocator=aTokenAllocator; }
@@ -311,19 +312,29 @@ public:
nsEntryStack mStack; //this will hold a list of tagentries...
PRInt32 mResidualStyleCount;
PRInt32 mContextTopIndex;
PRBool mHadBody;
PRBool mHadFrameset;
PRBool mHasOpenHead;
PRBool mTransitional;
PRBool mHadDocTypeDecl;
//break this struct out seperately so that lame compilers don't gack.
//By using these bits instead of bools, we have a bit-o-memory.
struct CFlags {
PRUint8 mHadBody:1;
PRUint8 mHadFrameset:1;
PRUint8 mHasOpenHead:1;
PRUint8 mTransitional:1;
PRUint8 mHadDocTypeDecl:1;
};
union {
PRUint32 mAllBits;
CFlags mFlags;
};
static CNodeRecycler *gNodeRecycler;
nsTokenAllocator *mTokenAllocator;
CTableState *mTableStates;
PRInt32 mCounters[NS_HTML_TAG_MAX];
nsString mDefaultEntity;
nsDeque mEntities;
nsTokenAllocator *mTokenAllocator;
CTableState *mTableStates;
PRInt32 *mCounters;
nsDeque mEntities;
#ifdef NS_DEBUG
enum { eMaxTags = 100 };
@@ -589,6 +600,21 @@ inline PRInt32 FirstOf(nsDTDContext& aContext,PRInt32 aStartOffset,TagList& aTag
return kNotFound;
}
/**
* Call this to find out whether the DTD thinks the tag requires an END tag </xxx>
* @update gess 01/04/99
* @param id of tag
* @return TRUE of the element's end tag is optional
*/
static PRBool HasOptionalEndTag(eHTMLTags aTag) {
static eHTMLTags gHasOptionalEndTags[]={eHTMLTag_body,eHTMLTag_colgroup,eHTMLTag_dd,eHTMLTag_dt,
eHTMLTag_head,eHTMLTag_li,eHTMLTag_option,
eHTMLTag_p,eHTMLTag_tbody,eHTMLTag_td,eHTMLTag_tfoot,
eHTMLTag_th,eHTMLTag_thead,eHTMLTag_tr,eHTMLTag_unknown};
return FindTagInSet(aTag,gHasOptionalEndTags,sizeof(gHasOptionalEndTags)/sizeof(eHTMLTag_body));
}
#endif

View File

@@ -122,7 +122,7 @@ TagList gCaptionAutoClose={1,{eHTMLTag_tbody}};
TagList gLIAutoClose={2,{eHTMLTag_p,eHTMLTag_li}};
TagList gPAutoClose={2,{eHTMLTag_p,eHTMLTag_li}};
TagList gHRAutoClose={1,{eHTMLTag_p}};
TagList gOLAutoClose={3,{eHTMLTag_p,eHTMLTag_ol,eHTMLTag_ul}};
TagList gOLAutoClose={2,{eHTMLTag_p,eHTMLTag_ol}};
TagList gDivAutoClose={1,{eHTMLTag_p}};
TagList gHeadingTags={6,{eHTMLTag_h1,eHTMLTag_h2,eHTMLTag_h3,eHTMLTag_h4,eHTMLTag_h5,eHTMLTag_h6}};
@@ -132,6 +132,7 @@ TagList gTRCloseTags={3,{eHTMLTag_tr,eHTMLTag_td,eHTMLTag_th}};
TagList gTDCloseTags={2,{eHTMLTag_td,eHTMLTag_th}};
TagList gDTCloseTags={3,{eHTMLTag_dt,eHTMLTag_dd,eHTMLTag_p}};
TagList gULCloseTags={1,{eHTMLTag_li}};
TagList gULAutoClose={2,{eHTMLTag_p,eHTMLTag_ul}}; //fix bug 50261..
TagList gExcludableParents={1,{eHTMLTag_pre}}; // Ref Bug 22913
@@ -948,7 +949,7 @@ void InitializeElementTable(void) {
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
/*autoclose starttags and endtags*/ 0,0,0,0,
/*parent,incl,exclgroups*/ kPreformatted, kFlowEntity, kNone, //I'm allowing WAY too much in here. Spec says inline.
/*parent,incl,exclgroups*/ kPreformatted, (kSelf|kFlowEntity), kNone, //I'm allowing WAY too much in here. Spec says inline.
/*special props, prop-range*/ 0, kDefaultPropRange,
/*special parents,kids,skip*/ 0,&gPreKids,eHTMLTag_unknown);
@@ -1209,7 +1210,7 @@ void InitializeElementTable(void) {
/*tag*/ eHTMLTag_ul,
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
/*rootnodes,endrootnodes*/ &gOLRootTags,&gOLRootTags,
/*autoclose starttags and endtags*/ &gOLAutoClose,&gULCloseTags,0,0,
/*autoclose starttags and endtags*/ &gULAutoClose,&gULCloseTags,0,0,
/*parent,incl,exclgroups*/ kList, (kFlowEntity|kSelf), kNone,
/*special props, prop-range*/ 0,kDefaultPropRange,
/*special parents,kids,skip*/ 0,&gULKids,eHTMLTag_unknown);
@@ -1888,10 +1889,22 @@ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32
int theCount=aContext.GetCount();
int theIndex=theCount;
if(IsMemberOf(kPhrase)){
while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){
eHTMLTags theTag=aContext.TagAt(theIndex);
if(theTag!=mTagID) {
//fixes a derivative of bug 22842...
if(CanContainType(kBlock)) { //INS/DEL can contain blocks.
if(gHTMLElements[eHTMLTags(theTag)].IsMemberOf(kBlockEntity)) {
if(HasOptionalEndTag(theTag)) {
continue; //then I can close it.
}
}
}
//phrasal elements can close other phrasals, along with fontstyle and special tags...
if(!gHTMLElements[theTag].IsMemberOf(kSpecial|kFontStyle|kPhrase)) {
break; //it's not something I can close
@@ -1903,17 +1916,27 @@ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32
}
}
}
else if(IsMemberOf(kSpecial)){
while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){
eHTMLTags theTag=aContext.TagAt(theIndex);
if(theTag!=mTagID) {
//phrasal elements can close other phrasals, along with fontstyle and special tags...
if(gHTMLElements[theTag].IsSpecialEntity() || gHTMLElements[theTag].IsFontStyleEntity()) {
// if(TestBits(gHTMLElements[theTag].mParentBits,kSpecial) ||
// TestBits(gHTMLElements[theTag].mParentBits,kFontStyle)) {
continue;
}
else {
//fixes bug 22842...
if(CanContainType(kBlock)) {
if(gHTMLElements[eHTMLTags(theTag)].IsMemberOf(kBlockEntity)) {
if(HasOptionalEndTag(theTag)) {
continue; //then I can close it.
}
}
}
break; //it's not something I can close
}
}
@@ -1923,7 +1946,9 @@ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32
}
}
}
else if(IsMemberOf(kFormControl|kExtensions|kPreformatted)){
while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){
eHTMLTags theTag=aContext.TagAt(theIndex);
if(theTag!=mTagID) {
@@ -1937,7 +1962,9 @@ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32
}
}
}
else if(IsMemberOf(kList)){
while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){
eHTMLTags theTag=aContext.TagAt(theIndex);
if(theTag!=mTagID) {
@@ -1951,6 +1978,7 @@ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32
}
}
}
else if(IsResidualStyleTag(mTagID)){
// Ref. bug 37618

View File

@@ -119,6 +119,7 @@ NS_IMPL_RELEASE(nsHTMLTokenizer)
mRecordTrailingContent=PR_FALSE;
mParserCommand=aCommand;
mTokenAllocator=nsnull;
mTokenScanPos=0;
}
@@ -237,6 +238,8 @@ CToken* nsHTMLTokenizer::GetTokenAt(PRInt32 anIndex){
nsresult nsHTMLTokenizer::WillTokenize(PRBool aIsFinalChunk,nsTokenAllocator* aTokenAllocator)
{
mTokenAllocator=aTokenAllocator;
mIsFinalChunk=aIsFinalChunk;
mTokenScanPos=mTokenDeque.GetSize()+1; //cause scanDocStructure to search from here for new tokens...
return NS_OK;
}
@@ -260,9 +263,160 @@ void nsHTMLTokenizer::PrependTokens(nsDeque& aDeque){
}
nsresult nsHTMLTokenizer::DidTokenize(PRBool aIsFinalChunk)
{
return NS_OK;
static nsDeque& GetTempStack() {
static nsDeque theTempStack(0);
return theTempStack;
}
/**
* This is a utilty method for ScanDocStructure, which finds a given
* tag in the stack.
*
* @update gess 08/30/00
* @param aTag -- the ID of the tag we're seeking
* @param aTagStack -- the stack to be searched
* @return index pos of tag in stack if found, otherwise kNotFound
*/
static PRInt32 FindLastIndexOfTag(eHTMLTags aTag,nsDeque &aTagStack) {
PRInt32 theCount=aTagStack.GetSize();
while(0<theCount) {
CHTMLToken *theToken=(CHTMLToken*)aTagStack.ObjectAt(--theCount);
if(theToken) {
eHTMLTags theTag=(eHTMLTags)theToken->GetTypeID();
if(theTag==aTag) {
return theCount;
}
}
}
return kNotFound;
}
/**
* This method scans the sequence of tokens to determine the
* well formedness of each tag structure. This is used to
* disable residual-style handling in well formed cases.
*
* @update gess 1Sep2000
* @param
* @return
*/
nsresult nsHTMLTokenizer::ScanDocStructure(PRBool aFinalChunk) {
nsresult result=NS_OK;
CHTMLToken *theRootToken=0;
//*** start by finding the first start tag that hasn't been reviewed.
while(mTokenScanPos>0) {
theRootToken=(CHTMLToken*)mTokenDeque.ObjectAt(mTokenScanPos);
if(theRootToken) {
eHTMLTokenTypes theType=eHTMLTokenTypes(theRootToken->GetTokenType());
if(eToken_start==theType) {
if(eFormUnknown==theRootToken->GetContainerInfo()) {
break;
}
}
}
mTokenScanPos--;
}
/*----------------------------------------------------------------------
* Now that we know where to start, let's walk through the
* tokens to see which are well-formed. Stop when you run out
* of fresh tokens.
*---------------------------------------------------------------------*/
theRootToken=(CHTMLToken*)mTokenDeque.ObjectAt(mTokenScanPos); //init to root
nsDeque &theStack=GetTempStack();
eHTMLTags theRootTag=eHTMLTag_unknown;
CHTMLToken *theToken=theRootToken; //init to root
PRInt32 theStackDepth=0;
static const PRInt32 theMaxStackDepth=200; //dont bother if we get ridiculously deep.
while(theToken && (theStackDepth<theMaxStackDepth)) {
eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType());
eHTMLTags theTag=(eHTMLTags)theToken->GetTypeID();
PRBool theTagIsBlock=gHTMLElements[theTag].IsMemberOf(kBlockEntity);
PRBool theTagIsInline= (theTagIsBlock) ? PR_FALSE : gHTMLElements[theTag].IsMemberOf(kInlineEntity);
if(theTagIsBlock || theTagIsInline || (eHTMLTag_table==theTag)) {
switch(theType) {
case eToken_start:
if(0==theStack.GetSize()) {
//track the tag on the top of the stack...
theRootToken=theToken;
theRootTag=theTag;
}
theStack.Push(theToken);
theStackDepth++;
break;
case eToken_end:
{
CHTMLToken *theLastToken= NS_STATIC_CAST(CHTMLToken*, theStack.Peek());
if(theLastToken) {
if(theTag==theLastToken->GetTypeID()) {
theStack.Pop(); //yank it for real
theStackDepth--;
theLastToken->SetContainerInfo(eWellFormed);
//in addition, let's look above this container to see if we can find
//any tags that are already marked malformed. If so, pop them too!
theLastToken= NS_STATIC_CAST(CHTMLToken*, theStack.Peek());
while(theLastToken) {
if(eMalformed==theRootToken->GetContainerInfo()) {
theStack.Pop(); //yank the malformed token for real.
theLastToken= NS_STATIC_CAST(CHTMLToken*, theStack.Peek());
continue;
}
break;
}
}
else {
//the topmost token isn't what we expected, so that container must
//be malformed. If the tag is a block, we don't really care (but we'll
//mark it anyway). If it's an inline we DO care, especially if the
//inline tried to contain a block (that's when RS handling kicks in).
if(theTagIsInline) {
PRInt32 theIndex=FindLastIndexOfTag(theTag,theStack);
if(kNotFound!=theIndex) {
theToken=(CHTMLToken*)theStack.ObjectAt(theIndex);
theToken->SetContainerInfo(eMalformed);
}
//otherwise we ignore an out-of-place end tag.
}
else {
}
}
}
}
break;
default:
break;
} //switch
}
theToken=(CHTMLToken*)mTokenDeque.ObjectAt(++mTokenScanPos);
}
theStack.Empty();
return result;
}
nsresult nsHTMLTokenizer::DidTokenize(PRBool aFinalChunk) {
return ScanDocStructure(aFinalChunk);
}
/**
@@ -475,6 +629,12 @@ nsresult nsHTMLTokenizer::ConsumeScriptContent(nsScanner& aScanner,CToken*& aTok
return result;
}
nsString& GetScratchString(void) {
static nsString gScratchString;
gScratchString.Truncate(0);
return gScratchString;
}
/**
*
* @update gess12/28/98
@@ -500,10 +660,10 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan
//Good. Now, let's see if the next char is ">".
//If so, we have a complete tag, otherwise, we have attributes.
mScratch.Truncate(0);
nsString &theScratchStr=GetScratchString();
PRBool theTagHasAttributes=PR_FALSE;
if(NS_OK==result) {
result=(eViewSource==mParserCommand) ? aScanner.ReadWhitespace(mScratch) : aScanner.SkipWhitespace();
result=(eViewSource==mParserCommand) ? aScanner.ReadWhitespace(theScratchStr) : aScanner.SkipWhitespace();
aToken->mNewlineCount += aScanner.GetNewlinesSkipped();
if(NS_OK==result) {
result=aScanner.GetChar(aChar);
@@ -518,7 +678,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan
}
if(theTagHasAttributes) {
result=ConsumeAttributes(aChar,(CStartToken*)aToken,aScanner,mScratch);
result=ConsumeAttributes(aChar,(CStartToken*)aToken,aScanner,theScratchStr);
}
/* Now that that's over with, we have one more problem to solve.
@@ -528,7 +688,8 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan
if(NS_SUCCEEDED(result)) {
//XXX - Find a better soution to record content
if((theTag==eHTMLTag_textarea || theTag==eHTMLTag_xmp) && !mRecordTrailingContent) {
//Added _plaintext to fix bug 46054.
if((eHTMLTag_textarea==theTag || eHTMLTag_xmp==theTag || eHTMLTag_plaintext==theTag) && !mRecordTrailingContent) {
mRecordTrailingContent=PR_TRUE;
}
@@ -633,6 +794,10 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne
aToken=theToken;
}
#endif
if(mIsFinalChunk && (kEOF==result)) {
result=NS_OK; //use as much of the entity as you can get.
}
AddToken(aToken,result,&mTokenDeque,theAllocator);
}
}//if

View File

@@ -68,10 +68,10 @@ public:
virtual CToken* PushTokenFront(CToken* theToken);
virtual CToken* PushToken(CToken* theToken);
virtual CToken* PopToken(void);
virtual CToken* PeekToken(void);
virtual CToken* GetTokenAt(PRInt32 anIndex);
virtual PRInt32 GetCount(void);
virtual CToken* PopToken(void);
virtual CToken* PeekToken(void);
virtual CToken* GetTokenAt(PRInt32 anIndex);
virtual PRInt32 GetCount(void);
virtual void PrependTokens(nsDeque& aDeque);
@@ -89,7 +89,9 @@ protected:
virtual nsresult ConsumeText(const nsString& aString,CToken*& aToken,nsScanner& aScanner);
virtual nsresult ConsumeSpecialMarkup(PRUnichar aChar,CToken*& aToken,nsScanner& aScanner);
virtual nsresult ConsumeProcessingInstruction(PRUnichar aChar,CToken*& aToken,nsScanner& aScanner);
nsresult ScanDocStructure(PRBool aIsFinalChunk);
virtual void RecordTrailingContent(CStartToken* aStartToken,nsScanner& aScanner);
static void AddToken(CToken*& aToken,nsresult aResult,nsDeque* aDeque,nsTokenAllocator* aTokenAllocator);
@@ -100,8 +102,9 @@ protected:
eParserDocType mDocType;
PRBool mRecordTrailingContent;
eParserCommands mParserCommand; //tells us to viewcontent/viewsource/viewerrors...
nsAutoString mScratch;
nsTokenAllocator* mTokenAllocator;
PRInt32 mTokenScanPos;
PRBool mIsFinalChunk;
};
extern NS_HTMLPARS nsresult NS_NewHTMLTokenizer( nsITokenizer** aInstancePtrResult,

View File

@@ -61,9 +61,9 @@ CHTMLToken::CHTMLToken(const nsString& aName,eHTMLTags aTag) : CToken(aName) {
* @return
*/
CHTMLToken::CHTMLToken(eHTMLTags aTag) : CToken(aTag) {
}
CHTMLToken::~CHTMLToken() {
}
@@ -108,6 +108,7 @@ CStartToken::CStartToken(eHTMLTags aTag) : CHTMLToken(aTag) {
mAttributed=PR_FALSE;
mEmpty=PR_FALSE;
mOrigin=-1;
mContainerInfo=eFormUnknown;
}
/*
@@ -121,12 +122,14 @@ CStartToken::CStartToken(const nsString& aString) : CHTMLToken(aString) {
mAttributed=PR_FALSE;
mEmpty=PR_FALSE;
mOrigin=-1;
mContainerInfo=eFormUnknown;
}
CStartToken::CStartToken(const nsString& aName,eHTMLTags aTag) : CHTMLToken(aName,aTag) {
mAttributed=PR_FALSE;
mEmpty=PR_FALSE;
mOrigin=-1;
mContainerInfo=eFormUnknown;
}
/**
@@ -142,6 +145,7 @@ void CStartToken::Reinitialize(PRInt32 aTag, const nsString& aString){
mEmpty=PR_FALSE;
mOrigin=-1;
mTrailingContent.Truncate();
mContainerInfo=eFormUnknown;
}
nsresult CStartToken::GetIDAttributeAtom(nsIAtom** aResult)
@@ -271,7 +275,12 @@ nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode
}
else {
mTextValue.Assign(aChar);
result=aScanner.ReadIdentifier(mTextValue);
//added PR_TRUE to readId() call below to fix bug 46083. The problem was that the tag given
//was written <title_> but since we didn't respect the '_', we only saw <title>. Then
//we searched for end title, which never comes (they give </title_>).
result=aScanner.ReadIdentifier(mTextValue,PR_TRUE);
mTypeID = nsHTMLTags::LookupTag(mTextValue);
}

View File

@@ -89,18 +89,22 @@ const char* GetTagName(PRInt32 aTag);
//PRInt32 FindEntityIndex(nsString& aString,PRInt32 aCount=-1);
/**
* This declares the basic token type used in the HTML DTD's.
* @update gess 3/25/98
*/
class CHTMLToken : public CToken {
public:
virtual ~CHTMLToken();
CHTMLToken(eHTMLTags aTag);
CHTMLToken(const nsString& aString,eHTMLTags aTag=eHTMLTag_unknown);
virtual void SetCStringValue(const char* name);
virtual nsString& GetStringValueXXX(void);
virtual ~CHTMLToken();
virtual eContainerInfo GetContainerInfo(void) const {return eFormUnknown;}
virtual void SetContainerInfo(eContainerInfo aInfo) { }
protected:
};
@@ -129,6 +133,12 @@ class CStartToken: public CHTMLToken {
virtual void DebugDumpSource(nsOutputStream& out);
virtual void GetSource(nsString& anOutputString);
virtual void AppendSource(nsString& anOutputString);
//the following info is used to set well-formedness state on start tags...
virtual eContainerInfo GetContainerInfo(void) const {return mContainerInfo;}
virtual void SetContainerInfo(eContainerInfo aContainerInfo) {mContainerInfo=aContainerInfo;}
virtual PRBool IsWellFormed(void) const {return PRBool(eWellFormed==mContainerInfo);}
virtual void Reinitialize(PRInt32 aTag, const nsString& aString);
/*
@@ -140,11 +150,13 @@ class CStartToken: public CHTMLToken {
virtual nsresult GetIDAttributeAtom(nsIAtom** aResult);
virtual nsresult SetIDAttributeAtom(nsIAtom* aID);
nsString mTrailingContent;
PRInt32 mOrigin;
nsString mTrailingContent;
PRInt32 mOrigin;
protected:
PRBool mAttributed;
PRBool mEmpty;
PRBool mAttributed;
PRBool mEmpty;
eContainerInfo mContainerInfo;
nsCOMPtr<nsIAtom> mIDAttributeAtom;
};

View File

@@ -72,6 +72,10 @@
#define NS_IHTML_CONTENT_SINK_IID \
{ 0xa6cf9051, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
#define MAX_REFLOW_DEPTH 200
class nsIHTMLContentSink : public nsIContentSink {
public:

View File

@@ -291,6 +291,8 @@ class nsIParser : public nsISupports {
#define NS_ERROR_HTMLPARSER_BADCONTEXT NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1014)
#define NS_ERROR_HTMLPARSER_STOPPARSING NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1015)
#define NS_ERROR_HTMLPARSER_UNTERMINATEDSTRINGLITERAL NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1016)
#define NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1017)
#define NS_HTMLPARSER_ALTERNATECONTENT NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_HTMLPARSER,1)
@@ -306,6 +308,7 @@ const PRUint32 kBadURL = NS_ERROR_HTMLPARSER_BADURL;
const PRUint32 kInvalidParserContext = NS_ERROR_HTMLPARSER_INVALIDPARSERCONTEXT;
const PRUint32 kBlocked = NS_ERROR_HTMLPARSER_BLOCK;
const PRUint32 kBadStringLiteral = NS_ERROR_HTMLPARSER_UNTERMINATEDSTRINGLITERAL;
const PRUint32 kHierarchyTooDeep = NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP;
const PRUnichar kNewLine = '\n';
const PRUnichar kCR = '\r';

View File

@@ -109,8 +109,17 @@ public:
NS_NewNavHTMLDTD(&theDTD); //do this as a default HTML DTD...
mDTDDeque.Push(theDTD);
NS_NewOtherHTMLDTD(&mOtherDTD); //do this as the default DTD for strict documents...
mDTDDeque.Push(mOtherDTD);
#if 1 //to fix bug 50070.
const char* theStrictDTDEnabled="true";
#else
const char* theStrictDTDEnabled=PR_GetEnv("ENABLE_STRICT"); //always false (except rickg's machine)
#endif
if(theStrictDTDEnabled) {
NS_NewOtherHTMLDTD(&mOtherDTD); //do this as the default DTD for strict documents...
mDTDDeque.Push(mOtherDTD);
}
mHasViewSourceDTD=PR_FALSE;
mHasRTFDTD=mHasXMLDTD=PR_FALSE;
@@ -673,16 +682,17 @@ void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType&
//now let's see if we have HTML or XHTML...
PRInt32 theLTPos=aBuffer.FindChar(kLessThan);
PRInt32 theGTPos=aBuffer.FindChar(kGreaterThan);
if(kNotFound!=theGTPos) {
if((kNotFound!=theGTPos) && (kNotFound!=theLTPos)) {
const PRUnichar* theBuffer=aBuffer.GetUnicode();
CWordTokenizer theTokenizer(aBuffer,1,theGTPos);
CWordTokenizer theTokenizer(aBuffer,theLTPos,theGTPos);
PRInt32 theOffset=theTokenizer.GetNextWord(); //try to find ?xml, !doctype, etc...
if((kNotFound!=theOffset) &&
(0==nsCRT::strncasecmp(theBuffer+theOffset,"DOCTYPE",theTokenizer.mLength))) {
(0==nsCRT::strncasecmp(theBuffer+theOffset,"!DOCTYPE",theTokenizer.mLength))) {
//Ok -- so assume it's (X)HTML; now figure out the flavor...
@@ -2285,16 +2295,18 @@ theContext->mTransferBufferSize;
}
#endif
theContext->mScanner->Append(theContext->mTransferBuffer,theNumRead);
#if 0
#if 1
static int dump=0;
if(dump) {
theContext->mTransferBuffer[theNumRead]=0;
printf("\n-----------------\n%s",theContext->mTransferBuffer);
printf("\n\n-----------------------------------------------------%s\n",theContext->mTransferBuffer);
}
#endif
theContext->mScanner->Append(theContext->mTransferBuffer,theNumRead);
#ifdef rickgdebug
theContext->mTransferBuffer[theNumRead]=0;
theContext->mTransferBuffer[theNumRead+1]=0;

View File

@@ -40,7 +40,7 @@
class nsTagHandler : public nsITagHandler {
public:
nsAutoString mTheTagName;
nsAutoString mTheTagName; //ok as autostring; VERY few if any get used.
public:

View File

@@ -49,6 +49,14 @@
class nsScanner;
enum eContainerInfo {
eWellFormed,
eMalformed,
eFormUnknown
};
/**
* Token objects represent sequences of characters as they
* are consumed from the input stream (URL). While they're
@@ -242,6 +250,17 @@ class CToken {
*/
virtual const char* GetClassName(void);
/**
* For tokens who care, this can tell us whether the token is
* well formed or not.
*
* @update gess 8/30/00
* @return PR_FALSE; subclasses MUST override if they care.
*/
virtual PRBool IsWellFormed(void) const {return PR_FALSE;}
/**
* perform self test.
* @update gess5/11/98