fixed beta2 bugs: 38203, 38228, 39520, 40060, and WIP for bug 40190; also enabled debug code for automated regression testing of content models.

This commit is contained in:
rickg%netscape.com 2000-05-25 06:19:32 +00:00
Родитель 8be92fb914
Коммит 8c6a6b0cb1
16 изменённых файлов: 1208 добавлений и 328 удалений

Просмотреть файл

@ -22,9 +22,10 @@
//#define ENABLE_CRC //#define ENABLE_CRC
//#define RICKG_DEBUG //#define RICKG_DEBUG
#define ENABLE_RESIDUALSTYLE
//#define ALLOW_TR_AS_CHILD_OF_TABLE //by setting this to true, TR is allowable directly in TABLE. //#define ALLOW_TR_AS_CHILD_OF_TABLE //by setting this to true, TR is allowable directly in TABLE.
#define ENABLE_RESIDUALSTYLE
#ifdef RICKG_DEBUG #ifdef RICKG_DEBUG
#include <fstream.h> #include <fstream.h>
#endif #endif
@ -266,12 +267,24 @@ CNavDTD::~CNavDTD(){
/** /**
* Call this method if you want the DTD to construct a fresh * Call this method if you want the DTD to construct a fresh
* instance of itself. * instance of itself.
* @update gess7/23/98 * @update gess 25May2000
* @param * @param
* @return * @return
*/ */
nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
return NS_NewNavHTMLDTD(aInstancePtrResult);
nsresult result=NS_NewNavHTMLDTD(aInstancePtrResult);
if(aInstancePtrResult) {
CNavDTD *theOtherDTD=(CNavDTD*)*aInstancePtrResult;
if(theOtherDTD) {
theOtherDTD->mDTDMode=mDTDMode;
theOtherDTD->mParserCommand=mParserCommand;
theOtherDTD->mDocType=mDocType;
}
}
return result;
} }
/** /**
@ -827,10 +840,9 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){
{ {
PRInt32 theCount=mBodyContext->GetCount(); PRInt32 theCount=mBodyContext->GetCount();
eHTMLTags theGrandParentTag=mBodyContext->TagAt(theCount-2); eHTMLTags theGrandParentTag=mBodyContext->TagAt(theCount-2);
PRInt32 theCounter=mBodyContext->IncrementCounter(theGrandParentTag);
nsAutoString theNumber;
nsString theNumber; PRInt32 theCounter=mBodyContext->IncrementCounter(theGrandParentTag,aNode,theNumber);
theNumber.AppendInt(theCounter);
CTextToken theToken(theNumber); CTextToken theToken(theNumber);
PRInt32 theLineNumber=0; PRInt32 theLineNumber=0;
nsCParserNode theNode(&theToken,theLineNumber); nsCParserNode theNode(&theToken,theLineNumber);
@ -838,6 +850,35 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){
} }
break; break;
case eHTMLTag_meta:
{
//we should only enable user-defined entities in debug builds...
PRInt32 theCount=aNode.GetAttributeCount();
const nsString* theNamePtr=0;
const nsString* theValuePtr=0;
if(theCount) {
PRInt32 theIndex=0;
for(theIndex=0;theIndex<theCount;theIndex++){
const nsString& theKey=aNode.GetKeyAt(theIndex);
if(theKey.EqualsWithConversion("ENTITY",PR_TRUE)) {
const nsString& theName=aNode.GetValueAt(theIndex);
theNamePtr=&theName;
}
else if(theKey.EqualsWithConversion("VALUE",PR_TRUE)) {
//store the named enity with the context...
const nsString& theValue=aNode.GetValueAt(theIndex);
theValuePtr=&theValue;
}
}
}
if(theNamePtr && theValuePtr) {
mBodyContext->RegisterEntity(*theNamePtr,*theValuePtr);
}
}
break;
default: default:
break; break;
}//switch }//switch
@ -1846,6 +1887,27 @@ nsresult CNavDTD::HandleEntityToken(CToken* aToken) {
NS_PRECONDITION(0!=aToken,kNullToken); NS_PRECONDITION(0!=aToken,kNullToken);
nsresult result=NS_OK; nsresult result=NS_OK;
nsString& theStr=aToken->GetStringValueXXX();
PRUnichar theChar=theStr.CharAt(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);
}
else {
//if you're here we have a bogus entity.
//convert it into a text token.
nsAutoString temp; temp.AssignWithConversion("&");
temp.Append(theStr);
theToken=new CTextToken(temp);
}
return HandleStartToken(theToken);
}
eHTMLTags theParentTag=mBodyContext->Last(); eHTMLTags theParentTag=mBodyContext->Last();
nsCParserNode* theNode=mNodeRecycler->CreateNode(); nsCParserNode* theNode=mNodeRecycler->CreateNode();

Просмотреть файл

@ -4,24 +4,24 @@
* License Version 1.1 (the "License"); you may not use this file * License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of * except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/ * the License at http://www.mozilla.org/NPL/
* *
* Software distributed under the License is distributed on an "AS * Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing * implied. See the License for the specific language governing
* rights and limitations under the License. * rights and limitations under the License.
* *
* The Original Code is mozilla.org code. * The Original Code is mozilla.org code.
* *
* The Initial Developer of the Original Code is Netscape * The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are * Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All * Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved. * Rights Reserved.
* *
* Contributor(s): * Contributor(s):
*/ */
//#define ENABLE_CRC //#define ENABLE_CRC
//#define RICKG_DEBUG //#define RICKG_DEBUG
#include "nsDebug.h" #include "nsDebug.h"
@ -131,7 +131,7 @@ NS_IMPL_RELEASE(COtherDTD)
* @param * @param
* @return * @return
*/ */
COtherDTD::COtherDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSharedNodes(0) { COtherDTD::COtherDTD() : nsIDTD(), mSharedNodes(0) {
NS_INIT_REFCNT(); NS_INIT_REFCNT();
mSink = 0; mSink = 0;
mParser=0; mParser=0;
@ -141,14 +141,17 @@ COtherDTD::COtherDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSh
mHasOpenHead=0; mHasOpenHead=0;
mHasOpenForm=PR_FALSE; mHasOpenForm=PR_FALSE;
mHasOpenMap=PR_FALSE; mHasOpenMap=PR_FALSE;
mHeadContext=new nsDTDContext();
mBodyContext=new nsDTDContext(); mBodyContext=new nsDTDContext();
mFormContext=0;
mTokenizer=0; mTokenizer=0;
mComputedCRC32=0; mComputedCRC32=0;
mExpectedCRC32=0; mExpectedCRC32=0;
mDTDState=NS_OK; mDTDState=NS_OK;
mDocType=ePlainText; mDocType=eHTML4Text;
mHadFrameset=PR_FALSE;
mHadBody=PR_FALSE;
mHasOpenScript=PR_FALSE;
mTokenRecycler=0;
mParserCommand=eViewNormal;
char* theEnvString = PR_GetEnv("ENABLE_STRICT"); char* theEnvString = PR_GetEnv("ENABLE_STRICT");
mEnableStrict=PRBool(theEnvString!=0); mEnableStrict=PRBool(theEnvString!=0);
@ -280,7 +283,6 @@ const nsIID& COtherDTD::GetMostDerivedIID(void)const {
* @return * @return
*/ */
COtherDTD::~COtherDTD(){ COtherDTD::~COtherDTD(){
delete mHeadContext;
delete mBodyContext; delete mBodyContext;
NS_IF_RELEASE(mTokenizer); NS_IF_RELEASE(mTokenizer);
@ -336,7 +338,19 @@ NS_HTMLPARS nsresult NS_NewOtherHTMLDTD(nsIDTD** aInstancePtrResult) {
* @return * @return
*/ */
nsresult COtherDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){ nsresult COtherDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
return NS_NewOtherHTMLDTD(aInstancePtrResult); nsresult result=NS_NewOtherHTMLDTD(aInstancePtrResult);
if(aInstancePtrResult) {
COtherDTD *theOtherDTD=(COtherDTD*)*aInstancePtrResult;
if(theOtherDTD) {
theOtherDTD->mDTDMode=mDTDMode;
theOtherDTD->mParserCommand=mParserCommand;
theOtherDTD->mDocType=mDocType;
theOtherDTD->mEnableStrict=mEnableStrict;
}
}
return result;
} }
/** /**
@ -608,6 +622,7 @@ nsresult COtherDTD::HandleToken(CToken* aToken,nsIParser* aParser){
case eToken_start: case eToken_start:
case eToken_whitespace: case eToken_whitespace:
case eToken_newline: case eToken_newline:
case eToken_doctypeDecl:
result=HandleStartToken(theToken); break; result=HandleStartToken(theToken); break;
case eToken_end: case eToken_end:
@ -722,7 +737,7 @@ nsresult COtherDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNo
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this)); MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this));
START_TIMER() START_TIMER()
return result; return result;
} }
@ -762,20 +777,20 @@ nsresult COtherDTD::HandleStartToken(CToken* aToken) {
if(NS_OK==result) { 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: case eHTMLTag_html:
if(!HasOpenContainer(theChildTag)) { if(!HasOpenContainer(theChildTag)) {
mSink->OpenHTML(*theNode); mSink->OpenHTML(*theNode);
mBodyContext->Push(theNode,0); mBodyContext->Push(theNode,0);
} }
theTagWasHandled=PR_TRUE; theTagWasHandled=PR_TRUE;
break; break;
default: default:
CElement* theElement=gElementTable->mElements[theParent]; CElement* theElement=gElementTable->mElements[theParent];
if(theElement) { if(theElement) {
result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink); result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink);
@ -788,7 +803,7 @@ nsresult COtherDTD::HandleStartToken(CToken* aToken) {
DidHandleStartTag(*theNode,theChildTag); DidHandleStartTag(*theNode,theChildTag);
} }
} //if } //if
}//if }//if
RecycleNode(theNode); RecycleNode(theNode);
@ -814,7 +829,7 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
nsresult result=NS_OK; nsresult result=NS_OK;
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID(); eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
#ifdef RICKG_DEBUG #ifdef RICKG_DEBUG
WriteTokenToLog(aToken); WriteTokenToLog(aToken);
#endif #endif
@ -825,7 +840,7 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
break; break;
case eHTMLTag_script: case eHTMLTag_script:
mHasOpenScript=PR_FALSE; mHasOpenScript=PR_FALSE;
default: default:
PRInt32 theCount=mBodyContext->GetCount(); PRInt32 theCount=mBodyContext->GetCount();
@ -838,7 +853,7 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
nsCParserNode theNode((CHTMLToken*)aToken,mLineNumber); nsCParserNode theNode((CHTMLToken*)aToken,mLineNumber);
result=theElement->HandleEndToken(&theNode,theChildTag,mBodyContext,mSink); result=theElement->HandleEndToken(&theNode,theChildTag,mBodyContext,mSink);
} }
break; break;
} }
return result; return result;
@ -857,14 +872,12 @@ nsresult COtherDTD::CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt3
int attr=0; int attr=0;
nsresult result=NS_OK; nsresult result=NS_OK;
int theAvailTokenCount=mTokenizer->GetCount() + mSkippedContent.GetSize(); int theAvailTokenCount=mTokenizer->GetCount();
if(aCount<=theAvailTokenCount) { if(aCount<=theAvailTokenCount) {
CToken* theToken=0; CToken* theToken=0;
eHTMLTags theSkipTarget=gElementTable->mElements[aTag]->GetSkipTarget(); eHTMLTags theSkipTarget=gElementTable->mElements[aTag]->GetSkipTarget();
for(attr=0;attr<aCount;attr++){ for(attr=0;attr<aCount;attr++){
if((eHTMLTag_unknown!=theSkipTarget) && mSkippedContent.GetSize()) theToken=mTokenizer->PopToken();
theToken=(CToken*)mSkippedContent.PopFront();
else theToken=mTokenizer->PopToken();
if(theToken) { if(theToken) {
// Sanitize the key for it might contain some non-alpha-non-digit characters // Sanitize the key for it might contain some non-alpha-non-digit characters
// at its end. Ex. <OPTION SELECTED/> - This will be tokenized as "<" "OPTION", // at its end. Ex. <OPTION SELECTED/> - This will be tokenized as "<" "OPTION",
@ -886,77 +899,6 @@ nsresult COtherDTD::CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt3
return result; return result;
} }
/**
* Causes the next skipped-content token (if any) to
* be consumed by this node.
* @update gess5/11/98
* @param node to consume skipped-content
* @param holds the number of skipped content elements encountered
* @return Error condition.
*/
nsresult COtherDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) {
eHTMLTags theNodeTag=(eHTMLTags)aNode.GetNodeType();
int aIndex=0;
int aMax=mSkippedContent.GetSize();
// XXX rickg This linefeed conversion stuff should be moved out of
// the parser and into the form element code
PRBool aMustConvertLinebreaks = PR_FALSE;
mScratch.SetLength(0);
aNode.SetSkippedContent(mScratch);
for(aIndex=0;aIndex<aMax;aIndex++){
CHTMLToken* theNextToken=(CHTMLToken*)mSkippedContent.PopFront();
eHTMLTokenTypes theTokenType=(eHTMLTokenTypes)theNextToken->GetTokenType();
mScratch.Truncate();
// Dont worry about attributes here because it's already stored in
// 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)) {
((CEntityToken*)theNextToken)->TranslateToUnicodeStr(mScratch);
// since this is an entity, we know that it's only one character.
// check to see if it's a CR, in which case we'll need to do line
// termination conversion at the end.
aMustConvertLinebreaks |= (mScratch[0] == kCR);
}
}
else theNextToken->GetSource(mScratch);
aNode.mSkippedContent->Append(mScratch);
}
mTokenRecycler->RecycleToken(theNextToken);
}
// if the string contained CRs (hence is either CR, or CRLF terminated)
// we need to convert line breaks
if (aMustConvertLinebreaks)
{
/*
PRInt32 offset;
while ((offset = aNode.mSkippedContent.Find("\r\n")) != kNotFound)
aNode.mSkippedContent.Cut(offset, 1); // remove the CR
// now replace remaining CRs with LFs
aNode.mSkippedContent.ReplaceChar("\r", kNewLine);
*/
#if 1
nsLinebreakConverter::ConvertStringLineBreaks(*aNode.mSkippedContent,
nsLinebreakConverter::eLinebreakAny, nsLinebreakConverter::eLinebreakContent);
#endif
}
// Let's hope that this does not hamper the PERFORMANCE!!
mLineNumber += aNode.mSkippedContent->CountChar(kNewLine);
return NS_OK;
}
/*********************************************************************************** /***********************************************************************************
The preceeding tables determine the set of elements each tag can contain... The preceeding tables determine the set of elements each tag can contain...

Просмотреть файл

@ -340,7 +340,6 @@ CLASS_EXPORT_HTMLPARS COtherDTD : public nsIDTD {
protected: protected:
nsresult CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt32 aCount); nsresult CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt32 aCount);
nsresult CollectSkippedContent(nsCParserNode& aNode,PRInt32& aCount);
nsresult WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsCParserNode& aNode); nsresult WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsCParserNode& aNode);
nsresult DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag); nsresult DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag);
nsCParserNode* CreateNode(void); nsCParserNode* CreateNode(void);
@ -349,9 +348,7 @@ protected:
nsIHTMLContentSink* mSink; nsIHTMLContentSink* mSink;
nsDTDContext* mHeadContext;
nsDTDContext* mBodyContext; nsDTDContext* mBodyContext;
nsDTDContext* mFormContext;
PRBool mHasOpenForm; PRBool mHasOpenForm;
PRBool mHasOpenMap; PRBool mHasOpenMap;
PRInt32 mHasOpenHead; PRInt32 mHasOpenHead;
@ -364,10 +361,7 @@ protected:
nsParser* mParser; nsParser* mParser;
nsITokenizer* mTokenizer; nsITokenizer* mTokenizer;
CTokenRecycler* mTokenRecycler; CTokenRecycler* mTokenRecycler;
nsDeque mMisplacedContent;
nsDeque mSkippedContent;
PRBool mHasOpenScript; PRBool mHasOpenScript;
PRBool mSaveBadTokens;
eHTMLTags mSkipTarget; eHTMLTags mSkipTarget;
nsDeque mSharedNodes; nsDeque mSharedNodes;
nsresult mDTDState; nsresult mDTDState;
@ -377,9 +371,8 @@ protected:
PRUint32 mComputedCRC32; PRUint32 mComputedCRC32;
PRUint32 mExpectedCRC32; PRUint32 mExpectedCRC32;
nsAutoString mScratch; //used for various purposes; non-persistent nsAutoString mScratch; //used for various purposes; non-persistent
PRBool mStyleHandlingEnabled;
PRBool mEnableStrict;
eParserDocType mDocType; eParserDocType mDocType;
PRBool mEnableStrict;
#ifdef NS_DEBUG #ifdef NS_DEBUG
PRInt32 gNodeCount; PRInt32 gNodeCount;

Просмотреть файл

@ -705,17 +705,19 @@ public:
case eHTMLTag_tr: case eHTMLTag_tr:
case eHTMLTag_th: case eHTMLTag_th:
if(!aContext->HasOpenContainer(eHTMLTag_tbody)) { if(aContext->mTableStates) {
nsCParserNode* theNode=new nsCParserNode(); if(aContext->mTableStates->CanOpenTBody()) {
CToken* theToken=new CStartToken(eHTMLTag_tbody); nsCParserNode* theNode=new nsCParserNode();
theNode->Init(theToken,0,0); //this will likely leak... CToken* theToken=new CStartToken(eHTMLTag_tbody);
theNode->Init(theToken,0,0); //this will likely leak...
result=HandleStartToken(theNode,eHTMLTag_tbody,aContext,aSink); result=HandleStartToken(theNode,eHTMLTag_tbody,aContext,aSink);
} }
if(NS_SUCCEEDED(result)) { if(NS_SUCCEEDED(result)) {
CElement *theElement=GetElement(eHTMLTag_tbody); CElement *theElement=GetElement(eHTMLTag_tbody);
if(theElement) { if(theElement) {
result=theElement->HandleStartToken(aNode,aTag,aContext,aSink); result=theElement->HandleStartToken(aNode,aTag,aContext,aSink);
}
} }
} }
@ -738,6 +740,7 @@ public:
case eHTMLTag_caption: case eHTMLTag_caption:
case eHTMLTag_col: case eHTMLTag_col:
case eHTMLTag_colgroup: case eHTMLTag_colgroup:
case eHTMLTag_tr:
case eHTMLTag_thead: case eHTMLTag_thead:
case eHTMLTag_tfoot: case eHTMLTag_tfoot:
case eHTMLTag_tbody: case eHTMLTag_tbody:
@ -928,23 +931,26 @@ public:
return CElement::HandleStartToken(aNode,aTag,aContext,aSink); return CElement::HandleStartToken(aNode,aTag,aContext,aSink);
} }
/********************************************************** /**********************************************************
this gets called after each tag is opened in the given context this gets called after each tag is opened in the given context
**********************************************************/ **********************************************************/
virtual nsresult OpenContainerInContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) { virtual nsresult OpenContainerInContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
OpenContext(aNode,aTag,aContext,aSink); OpenContext(aNode,aTag,aContext,aSink);
nsresult result=OpenContainer(aNode,aTag,aContext,aSink); nsresult result=OpenContainer(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) { if(NS_SUCCEEDED(result)) {
PRInt32 theCount=aContext->GetCount(); PRInt32 theCount=aContext->GetCount();
eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2); eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2);
PRInt32 theCounter=aContext->IncrementCounter(theGrandParentTag);
nsString theNumber; nsCParserNode *theNode=(nsCParserNode*)aNode;
theNumber.AppendInt(theCounter); nsAutoString theNumber;
PRInt32 theCounter=aContext->IncrementCounter(theGrandParentTag,*theNode,theNumber);
CTextToken theToken(theNumber); CTextToken theToken(theNumber);
PRInt32 theLineNumber=0; PRInt32 theLineNumber=0;
nsCParserNode theNode(&theToken,theLineNumber); nsCParserNode theNewNode(&theToken,theLineNumber);
result=aSink->AddLeaf(theNode); result=aSink->AddLeaf(theNewNode);
} }
return result; return result;
} }
@ -1284,12 +1290,7 @@ public:
virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) { virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK; nsresult result=NS_OK;
if(aContext->HasOpenContainer(eHTMLTag_html)) { if(aContext->HasOpenContainer(eHTMLTag_body)) {
aSink->OpenHead(*aNode);
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
aSink->CloseHead(*aNode);
}
else {
//add the script to the body //add the script to the body
CScriptToken theToken(mText); CScriptToken theToken(mText);
PRInt32 theLineNumber=0; PRInt32 theLineNumber=0;
@ -1297,6 +1298,12 @@ public:
theNode.SetSkippedContent(mText); theNode.SetSkippedContent(mText);
result=aSink->AddLeaf(theNode); result=aSink->AddLeaf(theNode);
} }
else {
//add it to the head...
aSink->OpenHead(*aNode);
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
aSink->CloseHead(*aNode);
}
mText.Truncate(0); mText.Truncate(0);
return result; return result;
} }
@ -1628,6 +1635,28 @@ public:
CElement::Initialize(*this,aTag,CHTMLElement::GetGroup(),CHTMLElement::GetContainedGroups()); CElement::Initialize(*this,aTag,CHTMLElement::GetGroup(),CHTMLElement::GetContainedGroups());
} }
/**********************************************************
HTML handles the opening of it's own children
**********************************************************/
nsresult HandleDoctypeDecl( nsIParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
nsCParserNode *theNode=(nsCParserNode*)aNode;
nsresult result=NS_OK;
if(theNode) {
nsString theStr=theNode->mToken->GetStringValueXXX();
PRInt32 theLen=theStr.Length();
PRInt32 thePos=theStr.RFindChar(kGreaterThan);
theStr.Truncate(theLen-1);
theStr.Cut(0,2);
result = aSink->AddDocTypeDecl(*aNode,eDTDMode_strict);
}
return result;
}
/********************************************************** /**********************************************************
HTML handles the opening of it's own children HTML handles the opening of it's own children
@ -1639,6 +1668,10 @@ public:
nsresult result=NS_OK; nsresult result=NS_OK;
switch(aTag) { switch(aTag) {
case eHTMLTag_markupDecl:
result=HandleDoctypeDecl(aNode,aTag,aContext,aSink);
break;
case eHTMLTag_body: case eHTMLTag_body:
result=aSink->OpenBody(*aNode); result=aSink->OpenBody(*aNode);
result=OpenContext(aNode,aTag,aContext,aSink); result=OpenContext(aNode,aTag,aContext,aSink);
@ -1794,7 +1827,9 @@ public:
switch(aTag) { switch(aTag) {
case eHTMLTag_div: case eHTMLTag_script:
result=OpenContext(aNode,aTag,aContext,aSink);
break;
default: default:
//for now, let's drop other elements onto the floor. //for now, let's drop other elements onto the floor.
@ -1802,7 +1837,7 @@ public:
if(NS_SUCCEEDED(result)) { if(NS_SUCCEEDED(result)) {
nsCParserNode *theNode=(nsCParserNode*)aNode; nsCParserNode *theNode=(nsCParserNode*)aNode;
CStartToken *theToken=(CStartToken*)theNode->mToken; CStartToken *theToken=(CStartToken*)theNode->mToken;
if(theToken->IsEmpty()){ if(theToken->IsEmpty() && (aTag==aContext->Last())){
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink); result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
} }
} }
@ -1817,7 +1852,15 @@ public:
a really convenient break point for debugging purposes. a really convenient break point for debugging purposes.
**********************************************************/ **********************************************************/
virtual nsresult HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) { virtual nsresult HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
return CElement::HandleEndToken(aNode,aTag,aContext,aSink); nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_script:
result=CloseContext(aNode,aTag,aContext,aSink);
break;
default:
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
}
return result;
} }
/********************************************************** /**********************************************************

Просмотреть файл

@ -21,7 +21,7 @@
* Pierre Phaneuf <pp@ludusdesign.com> * Pierre Phaneuf <pp@ludusdesign.com>
*/ */
#include "nsDTDUtils.h" #include "nsDTDUtils.h"
#include "CNavDTD.h" #include "CNavDTD.h"
#include "nsIParserNode.h" #include "nsIParserNode.h"
@ -363,7 +363,7 @@ CNodeRecycler* nsDTDContext::mNodeRecycler=0;
* *
* @update gess 04.21.2000 * @update gess 04.21.2000
*/ */
nsDTDContext::nsDTDContext() : mStack() { nsDTDContext::nsDTDContext() : mStack(), mEntities(0){
MOZ_COUNT_CTOR(nsDTDContext); MOZ_COUNT_CTOR(nsDTDContext);
mResidualStyleCount=0; mResidualStyleCount=0;
@ -379,6 +379,17 @@ nsDTDContext::nsDTDContext() : mStack() {
} }
class CEntityDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
CNamedEntity *theEntity=(CNamedEntity*)anObject;
delete theEntity;
return 0;
}
};
/** /**
* *
* @update gess9/10/98 * @update gess9/10/98
@ -391,9 +402,284 @@ nsDTDContext::~nsDTDContext() {
CTableState *theState=mTableStates; CTableState *theState=mTableStates;
mTableStates=theState->mPrevious; mTableStates=theState->mPrevious;
delete theState; delete theState;
} }
CEntityDeallocator theDeallocator;
mEntities.ForEach(theDeallocator);
} }
CNamedEntity* nsDTDContext::GetEntity(const nsString& aName)const {
PRInt32 theCount=mEntities.GetSize();
PRInt32 theIndex=0;
PRInt32 theLen=aName.Length();
PRUnichar theChar=aName.Last();
if(theLen>2) {
if(kSemicolon==theChar) {
theLen--;
}
const PRUnichar *theBuf=aName.GetUnicode();
if(kQuote==theBuf[0]) {
theBuf++;
theLen--;
}
if(kQuote==theChar) {
theLen--;
}
for(theIndex=0;theIndex<theCount;theIndex++) {
CNamedEntity *theResult=(CNamedEntity*)mEntities.ObjectAt(theIndex);
if(theResult && theResult->mName.EqualsWithConversion(theBuf,PR_TRUE,theLen)){
return theResult;
}
}
}
return 0;
}
CNamedEntity* nsDTDContext::RegisterEntity(const nsString& aName,const nsString& aValue) {
CNamedEntity *theEntity=GetEntity(aName);
if(!GetEntity(aName)){
theEntity=new CNamedEntity(aName,aValue);
mEntities.Push(theEntity);
}
return theEntity;
}
/****************************************************************
The abacus class is useful today for debug purposes, but it
will eventually serve as the implementation for css counters.
This implementation is fine for static documents, but woefully
inadequate for dynamic documents. (This about what happens if
someone inserts a new counter using the DOM? -- The other
numbers in that "group" should be renumbered.)
In order to be dynamic, we need a counter "group" manager that
is aware of layout (geometry at least) -- and that has a
mechanism for notifying markers that need to be updated, along
with the ability to cause incremental reflow to occur in a
localized context (so the counters display correctly).
****************************************************************/
class CAbacus {
public:
enum eNumFormat {eUnknown,eAlpha,eDecimal,eRoman,eSpoken,eHex,eBinary,eFootnote,eUserSeries};
CAbacus(PRInt32 aDefaultValue=0,eNumFormat aFormat=eDecimal) {
mUserSeries=0;
mFormat=aFormat;
mCase=false;
mValue=0;
mUserBase=0;
}
~CAbacus() {
}
void SetValue(int aStartValue) {mValue=aStartValue;}
void SetNumberingStyle(eNumFormat aFormat) {mFormat=aFormat;}
void SetUserSeries(const char* aSeries,int aUserBase) {mUserSeries=aSeries; mUserBase=aUserBase;}
void SetCase(PRBool alwaysUpper) {mCase=alwaysUpper;}
void GetNextValueAsString(nsString& aString) {
GetFormattedString(mFormat,mValue++,aString,mUserSeries,0,mUserBase);
}
void GetValueAsString(nsString& aString) {
GetFormattedString(mFormat,mValue,aString,mUserSeries,0,mUserBase);
}
static void GetFormattedString(eNumFormat aFormat,PRInt32 aValue, nsString& aString,const char* aCharSet, int anOffset, int aBase) {
switch (aFormat) {
case eDecimal: DecimalString(aValue,aString); break;
case eHex: HexString(aValue,aString); break;
case eBinary: BinaryString(aValue,aString); break;
case eAlpha: AlphaString(aValue,aString); break;
case eSpoken: SpokenString(aValue,aString); break;
case eRoman: RomanString(aValue,aString); break;
case eFootnote: FootnoteString(aValue,aString); break;
case eUserSeries: SeriesString(aValue,aString,aCharSet,anOffset,aBase);
}
}
static void SeriesString(PRInt32 aValue,nsString& aString,const char* aCharSet, int offset, int base) {
int ndex=0;
int root=1;
int next=base;
int expn=1;
aString.Truncate();
if(aValue<0)
aString.AppendWithConversion('-');
aValue=abs(aValue); // must be positive here...
while(next<=aValue) { // scale up in baseN; exceed current value.
root=next;
next*=base;
expn++;
}
while(expn--) {
ndex = ((root<=aValue) && (root)) ? (aValue/root): 0;
aValue%=root;
aString.AppendWithConversion(aCharSet[ndex+((root>1)*offset)]);
root/=base;
}
}
static void SpokenString(PRInt32 aValue,nsString& aString) {
static char ones[][12]= {"zero","one ","two ","three ","four ","five ","six ","seven ","eight ","nine ","ten "};
static char teens[][12]= {"ten ","eleven ","twelve ","thirteen ","fourteen ","fifteen ","sixteen ","seventeen ","eighteen ","nineteen "};
static char tens[][12]= {"","ten ","twenty ","thirty ","fourty ","fifty ","sixty ","seventy ","eighty ","ninety ","hundred "};
static char bases[][20]= {"","hundred ","thousand ","million ","billion ","trillion ","quadrillion ","quintillion ","bajillion "};
aString.Truncate();
if(aValue<0)
aString.AppendWithConversion('-');
PRInt32 root=1000000000;
PRInt32 expn=4;
PRInt32 modu=0;
PRInt32 div=0;
PRInt32 temp=0;
aValue=abs(aValue);
if(0<aValue) {
while(root && aValue) {
if(temp=aValue/root) {
if (div=temp/100) {//start with hundreds part
aString.AppendWithConversion(ones[div]);
aString.AppendWithConversion(bases[1]);
}
modu=(temp%10);
if (div=((temp%100)/10)) {
if (div<2) {
aString.AppendWithConversion(teens[modu]);
modu=0;
}
else aString.AppendWithConversion(tens[div]);
}
if (modu)
aString.AppendWithConversion(ones[modu]); //do remainder
aValue-=(temp*root);
if (expn>1)
aString.AppendWithConversion(bases[expn]);
}
expn--;
root/=1000;
}
}
else aString.AppendWithConversion(ones[0]);
}
static void DecimalString(PRInt32 aValue,nsString& aString) {
aString.Truncate();
aString.AppendInt(aValue);
}
static void BinaryString(PRInt32 aValue,nsString& aString) {
static char kBinarySet[]="01";
if (aValue<0)
aValue=65536-abs(aValue);
SeriesString(aValue,aString,kBinarySet,0,2);
}
static void HexString(PRInt32 aValue,nsString& aString) {
static char kHexSet[]="0123456789ABCDEF";
if (aValue<0)
aValue=65536-abs(aValue);
SeriesString(aValue,aString,kHexSet,0,16);
}
static void RomanString(PRInt32 aValue,nsString& aString) {
static char digitsA[] = "ixcm";
static char digitsB[] = "vld?";
aString.Truncate();
if(aValue<0)
aString.AppendWithConversion('-');
aValue=abs(aValue);
char decStr[20];
sprintf(decStr,"%d", aValue);
int len=strlen(decStr);
int romanPos=len;
int digitPos=0;
int n=0;
for(digitPos=0;digitPos<len;digitPos++) {
romanPos--;
switch(decStr[digitPos]) {
case '0': break;
case '3': aString.AppendWithConversion(digitsA[romanPos]);
case '2': aString.AppendWithConversion(digitsA[romanPos]);
case '1': aString.AppendWithConversion(digitsA[romanPos]);
break;
case '4': aString.AppendWithConversion(digitsA[romanPos]);
case '5': case '6':
case '7': case '8':
aString.AppendWithConversion(digitsB[romanPos]);
for(n=0;n<(decStr[digitPos]-'5');n++)
aString.AppendWithConversion(digitsA[romanPos]);
break;
case '9':
aString.AppendWithConversion(digitsA[romanPos]);
aString.AppendWithConversion(digitsA[romanPos]);
break;
}
}
}
static void AlphaString(PRInt32 aValue,nsString& aString) {
static const char kAlphaSet[]="abcdefghijklmnopqrstuvwxyz";
if (0<aValue)
SeriesString(aValue-1,aString,kAlphaSet,-1,26);
}
static void FootnoteString(PRInt32 aValue,nsString& aString) {
static char kFootnoteSet[]="abcdefg";
PRBool negative=(aValue<0);
int seriesLen = strlen (kFootnoteSet) - 1;
int count=0;
int repCount=0;
int modChar=0;
aString.Truncate();
aValue=abs(aValue);
repCount=((aValue-1)/seriesLen);
modChar=aValue-(repCount*seriesLen);
for(count=0;count<=repCount;count++) {
aString.AppendWithConversion(kFootnoteSet[modChar]);
}
}
protected:
const char* mUserSeries;
eNumFormat mFormat;
PRBool mCase;
PRInt32 mValue;
int mUserBase;
};
/** /**
* *
* @update gess 11May2000 * @update gess 11May2000
@ -402,22 +688,81 @@ void nsDTDContext::ResetCounters(void) {
memset(mCounters,0,sizeof(mCounters)); memset(mCounters,0,sizeof(mCounters));
} }
/** /**********************************************************
* @update: rickg 17May2000
* @update gess 11May2000
*/ Call this to handle counter attributes:
PRInt32 nsDTDContext::IncrementCounter(eHTMLTags aTag) { name="group"
PRInt32 result=++mCounters[aTag]; value="nnn"
noincr="?"
format="alpha|dec|footnote|hex|roman|spoken"
returns the newly incremented value for the (determined) group.
**********************************************************/
PRInt32 nsDTDContext::IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsString& aResult) {
PRInt32 result=0;
PRInt32 theIndex=0;
PRInt32 theNewValue=-1; //-1 is interpreted to mean "don't reset the counter sequence.
PRInt32 theIncrValue=1; //this may get set to 0 if we see a "noincr" key.
PRInt32 theCount=aNode.GetAttributeCount();
CNamedEntity *theEntity=0;
CAbacus::eNumFormat theNumFormat=CAbacus::eDecimal;
for(theIndex=0;theIndex<theCount;theIndex++){
const nsString& theKey=aNode.GetKeyAt(theIndex);
const nsString& theValue=aNode.GetValueAt(theIndex);
if(theKey.EqualsWithConversion("name",PR_TRUE)){
theEntity=GetEntity(theValue);
if(!theEntity) {
theEntity=RegisterEntity(theValue,theValue);
theEntity->mOrdinal=0;
}
aTag=eHTMLTag_userdefined;
}
else if(theKey.EqualsWithConversion("noincr",PR_TRUE)){
theIncrValue=0;
}
else if(theKey.EqualsWithConversion("format",PR_TRUE)){
PRUnichar theChar=theValue.CharAt(0);
if('"'==theChar)
theChar=theValue.CharAt(1);
switch(theChar){
case 'A': case 'a': theNumFormat=CAbacus::eAlpha; break;
case 'B': case 'b': theNumFormat=CAbacus::eBinary; break;
case 'D': case 'd': theNumFormat=CAbacus::eDecimal; break;
case 'H': case 'h': theNumFormat=CAbacus::eHex; break;
case 'R': case 'r': theNumFormat=CAbacus::eRoman; break;
case 'S': case 's': theNumFormat=CAbacus::eSpoken; break;
default:
theNumFormat=CAbacus::eDecimal;
break;
}
//determine numbering style
}
else if(theKey.EqualsWithConversion("value",PR_TRUE)){
PRInt32 err=0;
theNewValue=theValue.ToInteger(&err);
if(!err) {
theIncrValue=0;
mCounters[aTag]=theNewValue;
}
else theNewValue=-1;
}
}
if(theEntity && (eHTMLTag_userdefined==aTag)) {
result=theEntity->mOrdinal+=theIncrValue;
}
else result=mCounters[aTag]+=theIncrValue;
CAbacus::GetFormattedString(theNumFormat,result,aResult,0,0,0);
return result; return result;
} }
/**
*
* @update gess 11May2000
*/
void nsDTDContext::ResetCounter(eHTMLTags aTag,PRInt32 aValue) {
mCounters[aTag]=aValue;
}
/** /**
* *

Просмотреть файл

@ -155,6 +155,11 @@ public:
return result; return result;
} }
PRBool CanOpenTBody() {
PRBool result=!(mHasTBody);
return result;
}
PRBool CanOpenTHead() { PRBool CanOpenTHead() {
PRBool result=!(mHasTHead || mHasTFoot || mHasTBody); PRBool result=!(mHasTHead || mHasTFoot || mHasTBody);
return result; return result;
@ -174,14 +179,42 @@ public:
}; };
//used for named entities and counters (XXX debug only)
class CNamedEntity {
public:
CNamedEntity(const nsString& aName,const nsString& aValue) : mName(), mValue() {
PRUnichar theFirst=aName.First();
PRUnichar theLast=aName.Last();
PRInt32 theLen=aName.Length();
if((2<theLen) && (theFirst==theLast) && (kQuote==theFirst)) {
aName.Mid(mName,1,theLen-2);
}
else mName=aName;
theFirst=aValue.First();
theLast=aValue.Last();
theLen=aValue.Length();
if((2<theLen) && (theFirst==theLast) && (kQuote==theFirst)) {
aValue.Mid(mValue,1,theLen-2);
}
else mValue=aValue;
}
nsAutoString mName;
nsAutoString mValue;
PRInt32 mOrdinal;
};
/************************************************************************ /************************************************************************
The dtdcontext class defines an ordered list of tags (a context). The dtdcontext class defines an ordered list of tags (a context).
************************************************************************/ ************************************************************************/
class nsDTDContext { class nsDTDContext {
public: public:
nsDTDContext(); nsDTDContext();
~nsDTDContext(); ~nsDTDContext();
void Push(const nsIParserNode* aNode,nsEntryStack* aStyleStack=0); void Push(const nsIParserNode* aNode,nsEntryStack* aStyleStack=0);
nsIParserNode* Pop(nsEntryStack*& aChildStack); nsIParserNode* Pop(nsEntryStack*& aChildStack);
@ -209,9 +242,11 @@ public:
nsresult GetNodeRecycler(CNodeRecycler*& aNodeRecycler); nsresult GetNodeRecycler(CNodeRecycler*& aNodeRecycler);
static void FreeNodeRecycler(void); static void FreeNodeRecycler(void);
CNamedEntity* RegisterEntity(const nsString& aName,const nsString& aValue);
CNamedEntity* GetEntity(const nsString& aName)const;
void ResetCounters(void); void ResetCounters(void);
void ResetCounter(eHTMLTags aTag,PRInt32 aNewValue); PRInt32 IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsString& aResult);
PRInt32 IncrementCounter(eHTMLTags aTag);
nsEntryStack mStack; //this will hold a list of tagentries... nsEntryStack mStack; //this will hold a list of tagentries...
PRInt32 mResidualStyleCount; PRInt32 mResidualStyleCount;
@ -221,8 +256,10 @@ public:
static CNodeRecycler* mNodeRecycler; static CNodeRecycler* mNodeRecycler;
CTableState *mTableStates; CTableState *mTableStates;
PRInt32 mCounters[NS_HTML_TAG_MAX]; PRInt32 mCounters[NS_HTML_TAG_MAX];
nsString mDefaultEntity;
nsDeque mEntities;
#ifdef NS_DEBUG #ifdef NS_DEBUG
enum { eMaxTags = 100 }; enum { eMaxTags = 100 };

Просмотреть файл

@ -630,7 +630,9 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne
return ConsumeText(temp,aToken,aScanner); return ConsumeText(temp,aToken,aScanner);
}//if }//if
if(aToken){ if(aToken){
#if 0
nsString& theStr=aToken->GetStringValueXXX(); nsString& theStr=aToken->GetStringValueXXX();
if((kHashsign!=theChar) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){ if((kHashsign!=theChar) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){
//if you're here we have a bogus entity. //if you're here we have a bogus entity.
//convert it into a text token. //convert it into a text token.
@ -640,6 +642,7 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne
theRecycler->RecycleToken(aToken); theRecycler->RecycleToken(aToken);
aToken=theToken; aToken=theToken;
} }
#endif
AddToken(aToken,result,&mTokenDeque,theRecycler); AddToken(aToken,result,&mTokenDeque,theRecycler);
} }
}//if }//if

Просмотреть файл

@ -102,12 +102,13 @@ public:
//Note: To cut down on startup time/overhead, we defer the construction of non-html DTD's. //Note: To cut down on startup time/overhead, we defer the construction of non-html DTD's.
nsIDTD* theDTD; nsIDTD* theDTD;
NS_NewNavHTMLDTD(&theDTD); //do this as a default HTML DTD... NS_NewNavHTMLDTD(&theDTD); //do this as a default HTML DTD...
mDTDDeque.Push(theDTD); mDTDDeque.Push(theDTD);
#if 1
NS_NewOtherHTMLDTD(&theDTD); //do this as the default DTD for strict documents... NS_NewOtherHTMLDTD(&theDTD); //do this as the default DTD for strict documents...
mDTDDeque.Push(theDTD); mDTDDeque.Push(theDTD);
#endif
mHasViewSourceDTD=PR_FALSE; mHasViewSourceDTD=PR_FALSE;
mHasRTFDTD=mHasXMLDTD=PR_FALSE; mHasRTFDTD=mHasXMLDTD=PR_FALSE;
} }
@ -485,7 +486,7 @@ nsDTDMode nsParser::GetParseMode(void){
* @return parsermode (define in nsIParser.h) * @return parsermode (define in nsIParser.h)
*/ */
static static
void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType& aDocType) { void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType& aDocType,const nsString& aMimeType) {
const char* theModeStr= PR_GetEnv("PARSE_MODE"); const char* theModeStr= PR_GetEnv("PARSE_MODE");
aParseMode = eDTDMode_unknown; aParseMode = eDTDMode_unknown;
@ -613,8 +614,18 @@ void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType&
} }
} }
else if(kNotFound<(theIndex=aBuffer.Find("?XML",PR_TRUE,0,128))) { else if(kNotFound<(theIndex=aBuffer.Find("?XML",PR_TRUE,0,128))) {
aDocType=eXMLText;
aParseMode=eDTDMode_strict; aParseMode=eDTDMode_strict;
if(aMimeType.EqualsWithConversion(kHTMLTextContentType)) {
//this is here to prevent a crash if someone gives us an XML document,
//but necko tells us it's a text/html mimetype.
aDocType=eHTML4Text;
aParseMode=eDTDMode_strict;
}
else aDocType=eXMLText;
}
else if(aMimeType.EqualsWithConversion(kPlainTextContentType)) {
aDocType=ePlainText;
aParseMode=eDTDMode_quirks;
} }
if(theModeStr) { if(theModeStr) {
@ -754,7 +765,11 @@ nsresult nsParser::CreateCompatibleDTD(nsIDTD** aDTD,
nsDTDMode theDTDMode=eDTDMode_unknown; nsDTDMode theDTDMode=eDTDMode_unknown;
eParserDocType theDocType=ePlainText; eParserDocType theDocType=ePlainText;
DetermineParseMode(*aDocTypeStr,theDTDMode,theDocType); if(!aMimeType) {
nsAutoString temp;
DetermineParseMode(*aDocTypeStr,theDTDMode,theDocType,temp);
}
else DetermineParseMode(*aDocTypeStr,theDTDMode,theDocType,*aMimeType);
NS_ASSERTION(aDTDMode==eDTDMode_unknown || aDTDMode==theDTDMode,"aDTDMode overrides the mode selected from the DOCTYPE "); NS_ASSERTION(aDTDMode==eDTDMode_unknown || aDTDMode==theDTDMode,"aDTDMode overrides the mode selected from the DOCTYPE ");
@ -945,7 +960,7 @@ nsresult nsParser::WillBuildModel(nsString& aFilename){
while(*theDocType) { while(*theDocType) {
nsAutoString theType; nsAutoString theType;
theType.AssignWithConversion(*theDocType); theType.AssignWithConversion(*theDocType);
DetermineParseMode(theType,theParseMode,theDocumentType); DetermineParseMode(theType,theParseMode,theDocumentType,mParserContext->mMimeType);
theDocType++; theDocType++;
} }
} }
@ -957,7 +972,7 @@ nsresult nsParser::WillBuildModel(nsString& aFilename){
mMinorIteration=-1; mMinorIteration=-1;
nsString& theBuffer=mParserContext->mScanner->GetBuffer(); nsString& theBuffer=mParserContext->mScanner->GetBuffer();
DetermineParseMode(theBuffer,mParserContext->mDTDMode,mParserContext->mDocType); DetermineParseMode(theBuffer,mParserContext->mDTDMode,mParserContext->mDocType,mParserContext->mMimeType);
if(PR_TRUE==FindSuitableDTD(*mParserContext,theBuffer)) { if(PR_TRUE==FindSuitableDTD(*mParserContext,theBuffer)) {
mParserContext->mDTD->WillBuildModel( *mParserContext,mSink); mParserContext->mDTD->WillBuildModel( *mParserContext,mSink);

Просмотреть файл

@ -22,9 +22,10 @@
//#define ENABLE_CRC //#define ENABLE_CRC
//#define RICKG_DEBUG //#define RICKG_DEBUG
#define ENABLE_RESIDUALSTYLE
//#define ALLOW_TR_AS_CHILD_OF_TABLE //by setting this to true, TR is allowable directly in TABLE. //#define ALLOW_TR_AS_CHILD_OF_TABLE //by setting this to true, TR is allowable directly in TABLE.
#define ENABLE_RESIDUALSTYLE
#ifdef RICKG_DEBUG #ifdef RICKG_DEBUG
#include <fstream.h> #include <fstream.h>
#endif #endif
@ -266,12 +267,24 @@ CNavDTD::~CNavDTD(){
/** /**
* Call this method if you want the DTD to construct a fresh * Call this method if you want the DTD to construct a fresh
* instance of itself. * instance of itself.
* @update gess7/23/98 * @update gess 25May2000
* @param * @param
* @return * @return
*/ */
nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
return NS_NewNavHTMLDTD(aInstancePtrResult);
nsresult result=NS_NewNavHTMLDTD(aInstancePtrResult);
if(aInstancePtrResult) {
CNavDTD *theOtherDTD=(CNavDTD*)*aInstancePtrResult;
if(theOtherDTD) {
theOtherDTD->mDTDMode=mDTDMode;
theOtherDTD->mParserCommand=mParserCommand;
theOtherDTD->mDocType=mDocType;
}
}
return result;
} }
/** /**
@ -827,10 +840,9 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){
{ {
PRInt32 theCount=mBodyContext->GetCount(); PRInt32 theCount=mBodyContext->GetCount();
eHTMLTags theGrandParentTag=mBodyContext->TagAt(theCount-2); eHTMLTags theGrandParentTag=mBodyContext->TagAt(theCount-2);
PRInt32 theCounter=mBodyContext->IncrementCounter(theGrandParentTag);
nsAutoString theNumber;
nsString theNumber; PRInt32 theCounter=mBodyContext->IncrementCounter(theGrandParentTag,aNode,theNumber);
theNumber.AppendInt(theCounter);
CTextToken theToken(theNumber); CTextToken theToken(theNumber);
PRInt32 theLineNumber=0; PRInt32 theLineNumber=0;
nsCParserNode theNode(&theToken,theLineNumber); nsCParserNode theNode(&theToken,theLineNumber);
@ -838,6 +850,35 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){
} }
break; break;
case eHTMLTag_meta:
{
//we should only enable user-defined entities in debug builds...
PRInt32 theCount=aNode.GetAttributeCount();
const nsString* theNamePtr=0;
const nsString* theValuePtr=0;
if(theCount) {
PRInt32 theIndex=0;
for(theIndex=0;theIndex<theCount;theIndex++){
const nsString& theKey=aNode.GetKeyAt(theIndex);
if(theKey.EqualsWithConversion("ENTITY",PR_TRUE)) {
const nsString& theName=aNode.GetValueAt(theIndex);
theNamePtr=&theName;
}
else if(theKey.EqualsWithConversion("VALUE",PR_TRUE)) {
//store the named enity with the context...
const nsString& theValue=aNode.GetValueAt(theIndex);
theValuePtr=&theValue;
}
}
}
if(theNamePtr && theValuePtr) {
mBodyContext->RegisterEntity(*theNamePtr,*theValuePtr);
}
}
break;
default: default:
break; break;
}//switch }//switch
@ -1846,6 +1887,27 @@ nsresult CNavDTD::HandleEntityToken(CToken* aToken) {
NS_PRECONDITION(0!=aToken,kNullToken); NS_PRECONDITION(0!=aToken,kNullToken);
nsresult result=NS_OK; nsresult result=NS_OK;
nsString& theStr=aToken->GetStringValueXXX();
PRUnichar theChar=theStr.CharAt(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);
}
else {
//if you're here we have a bogus entity.
//convert it into a text token.
nsAutoString temp; temp.AssignWithConversion("&");
temp.Append(theStr);
theToken=new CTextToken(temp);
}
return HandleStartToken(theToken);
}
eHTMLTags theParentTag=mBodyContext->Last(); eHTMLTags theParentTag=mBodyContext->Last();
nsCParserNode* theNode=mNodeRecycler->CreateNode(); nsCParserNode* theNode=mNodeRecycler->CreateNode();

Просмотреть файл

@ -4,24 +4,24 @@
* License Version 1.1 (the "License"); you may not use this file * License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of * except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/ * the License at http://www.mozilla.org/NPL/
* *
* Software distributed under the License is distributed on an "AS * Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing * implied. See the License for the specific language governing
* rights and limitations under the License. * rights and limitations under the License.
* *
* The Original Code is mozilla.org code. * The Original Code is mozilla.org code.
* *
* The Initial Developer of the Original Code is Netscape * The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are * Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All * Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved. * Rights Reserved.
* *
* Contributor(s): * Contributor(s):
*/ */
//#define ENABLE_CRC //#define ENABLE_CRC
//#define RICKG_DEBUG //#define RICKG_DEBUG
#include "nsDebug.h" #include "nsDebug.h"
@ -131,7 +131,7 @@ NS_IMPL_RELEASE(COtherDTD)
* @param * @param
* @return * @return
*/ */
COtherDTD::COtherDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSharedNodes(0) { COtherDTD::COtherDTD() : nsIDTD(), mSharedNodes(0) {
NS_INIT_REFCNT(); NS_INIT_REFCNT();
mSink = 0; mSink = 0;
mParser=0; mParser=0;
@ -141,14 +141,17 @@ COtherDTD::COtherDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSh
mHasOpenHead=0; mHasOpenHead=0;
mHasOpenForm=PR_FALSE; mHasOpenForm=PR_FALSE;
mHasOpenMap=PR_FALSE; mHasOpenMap=PR_FALSE;
mHeadContext=new nsDTDContext();
mBodyContext=new nsDTDContext(); mBodyContext=new nsDTDContext();
mFormContext=0;
mTokenizer=0; mTokenizer=0;
mComputedCRC32=0; mComputedCRC32=0;
mExpectedCRC32=0; mExpectedCRC32=0;
mDTDState=NS_OK; mDTDState=NS_OK;
mDocType=ePlainText; mDocType=eHTML4Text;
mHadFrameset=PR_FALSE;
mHadBody=PR_FALSE;
mHasOpenScript=PR_FALSE;
mTokenRecycler=0;
mParserCommand=eViewNormal;
char* theEnvString = PR_GetEnv("ENABLE_STRICT"); char* theEnvString = PR_GetEnv("ENABLE_STRICT");
mEnableStrict=PRBool(theEnvString!=0); mEnableStrict=PRBool(theEnvString!=0);
@ -280,7 +283,6 @@ const nsIID& COtherDTD::GetMostDerivedIID(void)const {
* @return * @return
*/ */
COtherDTD::~COtherDTD(){ COtherDTD::~COtherDTD(){
delete mHeadContext;
delete mBodyContext; delete mBodyContext;
NS_IF_RELEASE(mTokenizer); NS_IF_RELEASE(mTokenizer);
@ -336,7 +338,19 @@ NS_HTMLPARS nsresult NS_NewOtherHTMLDTD(nsIDTD** aInstancePtrResult) {
* @return * @return
*/ */
nsresult COtherDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){ nsresult COtherDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
return NS_NewOtherHTMLDTD(aInstancePtrResult); nsresult result=NS_NewOtherHTMLDTD(aInstancePtrResult);
if(aInstancePtrResult) {
COtherDTD *theOtherDTD=(COtherDTD*)*aInstancePtrResult;
if(theOtherDTD) {
theOtherDTD->mDTDMode=mDTDMode;
theOtherDTD->mParserCommand=mParserCommand;
theOtherDTD->mDocType=mDocType;
theOtherDTD->mEnableStrict=mEnableStrict;
}
}
return result;
} }
/** /**
@ -608,6 +622,7 @@ nsresult COtherDTD::HandleToken(CToken* aToken,nsIParser* aParser){
case eToken_start: case eToken_start:
case eToken_whitespace: case eToken_whitespace:
case eToken_newline: case eToken_newline:
case eToken_doctypeDecl:
result=HandleStartToken(theToken); break; result=HandleStartToken(theToken); break;
case eToken_end: case eToken_end:
@ -722,7 +737,7 @@ nsresult COtherDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNo
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this)); MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this));
START_TIMER() START_TIMER()
return result; return result;
} }
@ -762,20 +777,20 @@ nsresult COtherDTD::HandleStartToken(CToken* aToken) {
if(NS_OK==result) { 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: case eHTMLTag_html:
if(!HasOpenContainer(theChildTag)) { if(!HasOpenContainer(theChildTag)) {
mSink->OpenHTML(*theNode); mSink->OpenHTML(*theNode);
mBodyContext->Push(theNode,0); mBodyContext->Push(theNode,0);
} }
theTagWasHandled=PR_TRUE; theTagWasHandled=PR_TRUE;
break; break;
default: default:
CElement* theElement=gElementTable->mElements[theParent]; CElement* theElement=gElementTable->mElements[theParent];
if(theElement) { if(theElement) {
result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink); result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink);
@ -788,7 +803,7 @@ nsresult COtherDTD::HandleStartToken(CToken* aToken) {
DidHandleStartTag(*theNode,theChildTag); DidHandleStartTag(*theNode,theChildTag);
} }
} //if } //if
}//if }//if
RecycleNode(theNode); RecycleNode(theNode);
@ -814,7 +829,7 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
nsresult result=NS_OK; nsresult result=NS_OK;
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID(); eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
#ifdef RICKG_DEBUG #ifdef RICKG_DEBUG
WriteTokenToLog(aToken); WriteTokenToLog(aToken);
#endif #endif
@ -825,7 +840,7 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
break; break;
case eHTMLTag_script: case eHTMLTag_script:
mHasOpenScript=PR_FALSE; mHasOpenScript=PR_FALSE;
default: default:
PRInt32 theCount=mBodyContext->GetCount(); PRInt32 theCount=mBodyContext->GetCount();
@ -838,7 +853,7 @@ nsresult COtherDTD::HandleEndToken(CToken* aToken) {
nsCParserNode theNode((CHTMLToken*)aToken,mLineNumber); nsCParserNode theNode((CHTMLToken*)aToken,mLineNumber);
result=theElement->HandleEndToken(&theNode,theChildTag,mBodyContext,mSink); result=theElement->HandleEndToken(&theNode,theChildTag,mBodyContext,mSink);
} }
break; break;
} }
return result; return result;
@ -857,14 +872,12 @@ nsresult COtherDTD::CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt3
int attr=0; int attr=0;
nsresult result=NS_OK; nsresult result=NS_OK;
int theAvailTokenCount=mTokenizer->GetCount() + mSkippedContent.GetSize(); int theAvailTokenCount=mTokenizer->GetCount();
if(aCount<=theAvailTokenCount) { if(aCount<=theAvailTokenCount) {
CToken* theToken=0; CToken* theToken=0;
eHTMLTags theSkipTarget=gElementTable->mElements[aTag]->GetSkipTarget(); eHTMLTags theSkipTarget=gElementTable->mElements[aTag]->GetSkipTarget();
for(attr=0;attr<aCount;attr++){ for(attr=0;attr<aCount;attr++){
if((eHTMLTag_unknown!=theSkipTarget) && mSkippedContent.GetSize()) theToken=mTokenizer->PopToken();
theToken=(CToken*)mSkippedContent.PopFront();
else theToken=mTokenizer->PopToken();
if(theToken) { if(theToken) {
// Sanitize the key for it might contain some non-alpha-non-digit characters // Sanitize the key for it might contain some non-alpha-non-digit characters
// at its end. Ex. <OPTION SELECTED/> - This will be tokenized as "<" "OPTION", // at its end. Ex. <OPTION SELECTED/> - This will be tokenized as "<" "OPTION",
@ -886,77 +899,6 @@ nsresult COtherDTD::CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt3
return result; return result;
} }
/**
* Causes the next skipped-content token (if any) to
* be consumed by this node.
* @update gess5/11/98
* @param node to consume skipped-content
* @param holds the number of skipped content elements encountered
* @return Error condition.
*/
nsresult COtherDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) {
eHTMLTags theNodeTag=(eHTMLTags)aNode.GetNodeType();
int aIndex=0;
int aMax=mSkippedContent.GetSize();
// XXX rickg This linefeed conversion stuff should be moved out of
// the parser and into the form element code
PRBool aMustConvertLinebreaks = PR_FALSE;
mScratch.SetLength(0);
aNode.SetSkippedContent(mScratch);
for(aIndex=0;aIndex<aMax;aIndex++){
CHTMLToken* theNextToken=(CHTMLToken*)mSkippedContent.PopFront();
eHTMLTokenTypes theTokenType=(eHTMLTokenTypes)theNextToken->GetTokenType();
mScratch.Truncate();
// Dont worry about attributes here because it's already stored in
// 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)) {
((CEntityToken*)theNextToken)->TranslateToUnicodeStr(mScratch);
// since this is an entity, we know that it's only one character.
// check to see if it's a CR, in which case we'll need to do line
// termination conversion at the end.
aMustConvertLinebreaks |= (mScratch[0] == kCR);
}
}
else theNextToken->GetSource(mScratch);
aNode.mSkippedContent->Append(mScratch);
}
mTokenRecycler->RecycleToken(theNextToken);
}
// if the string contained CRs (hence is either CR, or CRLF terminated)
// we need to convert line breaks
if (aMustConvertLinebreaks)
{
/*
PRInt32 offset;
while ((offset = aNode.mSkippedContent.Find("\r\n")) != kNotFound)
aNode.mSkippedContent.Cut(offset, 1); // remove the CR
// now replace remaining CRs with LFs
aNode.mSkippedContent.ReplaceChar("\r", kNewLine);
*/
#if 1
nsLinebreakConverter::ConvertStringLineBreaks(*aNode.mSkippedContent,
nsLinebreakConverter::eLinebreakAny, nsLinebreakConverter::eLinebreakContent);
#endif
}
// Let's hope that this does not hamper the PERFORMANCE!!
mLineNumber += aNode.mSkippedContent->CountChar(kNewLine);
return NS_OK;
}
/*********************************************************************************** /***********************************************************************************
The preceeding tables determine the set of elements each tag can contain... The preceeding tables determine the set of elements each tag can contain...

Просмотреть файл

@ -340,7 +340,6 @@ CLASS_EXPORT_HTMLPARS COtherDTD : public nsIDTD {
protected: protected:
nsresult CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt32 aCount); nsresult CollectAttributes(nsCParserNode& aNode,eHTMLTags aTag,PRInt32 aCount);
nsresult CollectSkippedContent(nsCParserNode& aNode,PRInt32& aCount);
nsresult WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsCParserNode& aNode); nsresult WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsCParserNode& aNode);
nsresult DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag); nsresult DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag);
nsCParserNode* CreateNode(void); nsCParserNode* CreateNode(void);
@ -349,9 +348,7 @@ protected:
nsIHTMLContentSink* mSink; nsIHTMLContentSink* mSink;
nsDTDContext* mHeadContext;
nsDTDContext* mBodyContext; nsDTDContext* mBodyContext;
nsDTDContext* mFormContext;
PRBool mHasOpenForm; PRBool mHasOpenForm;
PRBool mHasOpenMap; PRBool mHasOpenMap;
PRInt32 mHasOpenHead; PRInt32 mHasOpenHead;
@ -364,10 +361,7 @@ protected:
nsParser* mParser; nsParser* mParser;
nsITokenizer* mTokenizer; nsITokenizer* mTokenizer;
CTokenRecycler* mTokenRecycler; CTokenRecycler* mTokenRecycler;
nsDeque mMisplacedContent;
nsDeque mSkippedContent;
PRBool mHasOpenScript; PRBool mHasOpenScript;
PRBool mSaveBadTokens;
eHTMLTags mSkipTarget; eHTMLTags mSkipTarget;
nsDeque mSharedNodes; nsDeque mSharedNodes;
nsresult mDTDState; nsresult mDTDState;
@ -377,9 +371,8 @@ protected:
PRUint32 mComputedCRC32; PRUint32 mComputedCRC32;
PRUint32 mExpectedCRC32; PRUint32 mExpectedCRC32;
nsAutoString mScratch; //used for various purposes; non-persistent nsAutoString mScratch; //used for various purposes; non-persistent
PRBool mStyleHandlingEnabled;
PRBool mEnableStrict;
eParserDocType mDocType; eParserDocType mDocType;
PRBool mEnableStrict;
#ifdef NS_DEBUG #ifdef NS_DEBUG
PRInt32 gNodeCount; PRInt32 gNodeCount;

Просмотреть файл

@ -705,17 +705,19 @@ public:
case eHTMLTag_tr: case eHTMLTag_tr:
case eHTMLTag_th: case eHTMLTag_th:
if(!aContext->HasOpenContainer(eHTMLTag_tbody)) { if(aContext->mTableStates) {
nsCParserNode* theNode=new nsCParserNode(); if(aContext->mTableStates->CanOpenTBody()) {
CToken* theToken=new CStartToken(eHTMLTag_tbody); nsCParserNode* theNode=new nsCParserNode();
theNode->Init(theToken,0,0); //this will likely leak... CToken* theToken=new CStartToken(eHTMLTag_tbody);
theNode->Init(theToken,0,0); //this will likely leak...
result=HandleStartToken(theNode,eHTMLTag_tbody,aContext,aSink); result=HandleStartToken(theNode,eHTMLTag_tbody,aContext,aSink);
} }
if(NS_SUCCEEDED(result)) { if(NS_SUCCEEDED(result)) {
CElement *theElement=GetElement(eHTMLTag_tbody); CElement *theElement=GetElement(eHTMLTag_tbody);
if(theElement) { if(theElement) {
result=theElement->HandleStartToken(aNode,aTag,aContext,aSink); result=theElement->HandleStartToken(aNode,aTag,aContext,aSink);
}
} }
} }
@ -738,6 +740,7 @@ public:
case eHTMLTag_caption: case eHTMLTag_caption:
case eHTMLTag_col: case eHTMLTag_col:
case eHTMLTag_colgroup: case eHTMLTag_colgroup:
case eHTMLTag_tr:
case eHTMLTag_thead: case eHTMLTag_thead:
case eHTMLTag_tfoot: case eHTMLTag_tfoot:
case eHTMLTag_tbody: case eHTMLTag_tbody:
@ -928,23 +931,26 @@ public:
return CElement::HandleStartToken(aNode,aTag,aContext,aSink); return CElement::HandleStartToken(aNode,aTag,aContext,aSink);
} }
/********************************************************** /**********************************************************
this gets called after each tag is opened in the given context this gets called after each tag is opened in the given context
**********************************************************/ **********************************************************/
virtual nsresult OpenContainerInContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) { virtual nsresult OpenContainerInContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
OpenContext(aNode,aTag,aContext,aSink); OpenContext(aNode,aTag,aContext,aSink);
nsresult result=OpenContainer(aNode,aTag,aContext,aSink); nsresult result=OpenContainer(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) { if(NS_SUCCEEDED(result)) {
PRInt32 theCount=aContext->GetCount(); PRInt32 theCount=aContext->GetCount();
eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2); eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2);
PRInt32 theCounter=aContext->IncrementCounter(theGrandParentTag);
nsString theNumber; nsCParserNode *theNode=(nsCParserNode*)aNode;
theNumber.AppendInt(theCounter); nsAutoString theNumber;
PRInt32 theCounter=aContext->IncrementCounter(theGrandParentTag,*theNode,theNumber);
CTextToken theToken(theNumber); CTextToken theToken(theNumber);
PRInt32 theLineNumber=0; PRInt32 theLineNumber=0;
nsCParserNode theNode(&theToken,theLineNumber); nsCParserNode theNewNode(&theToken,theLineNumber);
result=aSink->AddLeaf(theNode); result=aSink->AddLeaf(theNewNode);
} }
return result; return result;
} }
@ -1284,12 +1290,7 @@ public:
virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) { virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK; nsresult result=NS_OK;
if(aContext->HasOpenContainer(eHTMLTag_html)) { if(aContext->HasOpenContainer(eHTMLTag_body)) {
aSink->OpenHead(*aNode);
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
aSink->CloseHead(*aNode);
}
else {
//add the script to the body //add the script to the body
CScriptToken theToken(mText); CScriptToken theToken(mText);
PRInt32 theLineNumber=0; PRInt32 theLineNumber=0;
@ -1297,6 +1298,12 @@ public:
theNode.SetSkippedContent(mText); theNode.SetSkippedContent(mText);
result=aSink->AddLeaf(theNode); result=aSink->AddLeaf(theNode);
} }
else {
//add it to the head...
aSink->OpenHead(*aNode);
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
aSink->CloseHead(*aNode);
}
mText.Truncate(0); mText.Truncate(0);
return result; return result;
} }
@ -1628,6 +1635,28 @@ public:
CElement::Initialize(*this,aTag,CHTMLElement::GetGroup(),CHTMLElement::GetContainedGroups()); CElement::Initialize(*this,aTag,CHTMLElement::GetGroup(),CHTMLElement::GetContainedGroups());
} }
/**********************************************************
HTML handles the opening of it's own children
**********************************************************/
nsresult HandleDoctypeDecl( nsIParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
nsCParserNode *theNode=(nsCParserNode*)aNode;
nsresult result=NS_OK;
if(theNode) {
nsString theStr=theNode->mToken->GetStringValueXXX();
PRInt32 theLen=theStr.Length();
PRInt32 thePos=theStr.RFindChar(kGreaterThan);
theStr.Truncate(theLen-1);
theStr.Cut(0,2);
result = aSink->AddDocTypeDecl(*aNode,eDTDMode_strict);
}
return result;
}
/********************************************************** /**********************************************************
HTML handles the opening of it's own children HTML handles the opening of it's own children
@ -1639,6 +1668,10 @@ public:
nsresult result=NS_OK; nsresult result=NS_OK;
switch(aTag) { switch(aTag) {
case eHTMLTag_markupDecl:
result=HandleDoctypeDecl(aNode,aTag,aContext,aSink);
break;
case eHTMLTag_body: case eHTMLTag_body:
result=aSink->OpenBody(*aNode); result=aSink->OpenBody(*aNode);
result=OpenContext(aNode,aTag,aContext,aSink); result=OpenContext(aNode,aTag,aContext,aSink);
@ -1794,7 +1827,9 @@ public:
switch(aTag) { switch(aTag) {
case eHTMLTag_div: case eHTMLTag_script:
result=OpenContext(aNode,aTag,aContext,aSink);
break;
default: default:
//for now, let's drop other elements onto the floor. //for now, let's drop other elements onto the floor.
@ -1802,7 +1837,7 @@ public:
if(NS_SUCCEEDED(result)) { if(NS_SUCCEEDED(result)) {
nsCParserNode *theNode=(nsCParserNode*)aNode; nsCParserNode *theNode=(nsCParserNode*)aNode;
CStartToken *theToken=(CStartToken*)theNode->mToken; CStartToken *theToken=(CStartToken*)theNode->mToken;
if(theToken->IsEmpty()){ if(theToken->IsEmpty() && (aTag==aContext->Last())){
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink); result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
} }
} }
@ -1817,7 +1852,15 @@ public:
a really convenient break point for debugging purposes. a really convenient break point for debugging purposes.
**********************************************************/ **********************************************************/
virtual nsresult HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) { virtual nsresult HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
return CElement::HandleEndToken(aNode,aTag,aContext,aSink); nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_script:
result=CloseContext(aNode,aTag,aContext,aSink);
break;
default:
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
}
return result;
} }
/********************************************************** /**********************************************************

Просмотреть файл

@ -21,7 +21,7 @@
* Pierre Phaneuf <pp@ludusdesign.com> * Pierre Phaneuf <pp@ludusdesign.com>
*/ */
#include "nsDTDUtils.h" #include "nsDTDUtils.h"
#include "CNavDTD.h" #include "CNavDTD.h"
#include "nsIParserNode.h" #include "nsIParserNode.h"
@ -363,7 +363,7 @@ CNodeRecycler* nsDTDContext::mNodeRecycler=0;
* *
* @update gess 04.21.2000 * @update gess 04.21.2000
*/ */
nsDTDContext::nsDTDContext() : mStack() { nsDTDContext::nsDTDContext() : mStack(), mEntities(0){
MOZ_COUNT_CTOR(nsDTDContext); MOZ_COUNT_CTOR(nsDTDContext);
mResidualStyleCount=0; mResidualStyleCount=0;
@ -379,6 +379,17 @@ nsDTDContext::nsDTDContext() : mStack() {
} }
class CEntityDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
CNamedEntity *theEntity=(CNamedEntity*)anObject;
delete theEntity;
return 0;
}
};
/** /**
* *
* @update gess9/10/98 * @update gess9/10/98
@ -391,9 +402,284 @@ nsDTDContext::~nsDTDContext() {
CTableState *theState=mTableStates; CTableState *theState=mTableStates;
mTableStates=theState->mPrevious; mTableStates=theState->mPrevious;
delete theState; delete theState;
} }
CEntityDeallocator theDeallocator;
mEntities.ForEach(theDeallocator);
} }
CNamedEntity* nsDTDContext::GetEntity(const nsString& aName)const {
PRInt32 theCount=mEntities.GetSize();
PRInt32 theIndex=0;
PRInt32 theLen=aName.Length();
PRUnichar theChar=aName.Last();
if(theLen>2) {
if(kSemicolon==theChar) {
theLen--;
}
const PRUnichar *theBuf=aName.GetUnicode();
if(kQuote==theBuf[0]) {
theBuf++;
theLen--;
}
if(kQuote==theChar) {
theLen--;
}
for(theIndex=0;theIndex<theCount;theIndex++) {
CNamedEntity *theResult=(CNamedEntity*)mEntities.ObjectAt(theIndex);
if(theResult && theResult->mName.EqualsWithConversion(theBuf,PR_TRUE,theLen)){
return theResult;
}
}
}
return 0;
}
CNamedEntity* nsDTDContext::RegisterEntity(const nsString& aName,const nsString& aValue) {
CNamedEntity *theEntity=GetEntity(aName);
if(!GetEntity(aName)){
theEntity=new CNamedEntity(aName,aValue);
mEntities.Push(theEntity);
}
return theEntity;
}
/****************************************************************
The abacus class is useful today for debug purposes, but it
will eventually serve as the implementation for css counters.
This implementation is fine for static documents, but woefully
inadequate for dynamic documents. (This about what happens if
someone inserts a new counter using the DOM? -- The other
numbers in that "group" should be renumbered.)
In order to be dynamic, we need a counter "group" manager that
is aware of layout (geometry at least) -- and that has a
mechanism for notifying markers that need to be updated, along
with the ability to cause incremental reflow to occur in a
localized context (so the counters display correctly).
****************************************************************/
class CAbacus {
public:
enum eNumFormat {eUnknown,eAlpha,eDecimal,eRoman,eSpoken,eHex,eBinary,eFootnote,eUserSeries};
CAbacus(PRInt32 aDefaultValue=0,eNumFormat aFormat=eDecimal) {
mUserSeries=0;
mFormat=aFormat;
mCase=false;
mValue=0;
mUserBase=0;
}
~CAbacus() {
}
void SetValue(int aStartValue) {mValue=aStartValue;}
void SetNumberingStyle(eNumFormat aFormat) {mFormat=aFormat;}
void SetUserSeries(const char* aSeries,int aUserBase) {mUserSeries=aSeries; mUserBase=aUserBase;}
void SetCase(PRBool alwaysUpper) {mCase=alwaysUpper;}
void GetNextValueAsString(nsString& aString) {
GetFormattedString(mFormat,mValue++,aString,mUserSeries,0,mUserBase);
}
void GetValueAsString(nsString& aString) {
GetFormattedString(mFormat,mValue,aString,mUserSeries,0,mUserBase);
}
static void GetFormattedString(eNumFormat aFormat,PRInt32 aValue, nsString& aString,const char* aCharSet, int anOffset, int aBase) {
switch (aFormat) {
case eDecimal: DecimalString(aValue,aString); break;
case eHex: HexString(aValue,aString); break;
case eBinary: BinaryString(aValue,aString); break;
case eAlpha: AlphaString(aValue,aString); break;
case eSpoken: SpokenString(aValue,aString); break;
case eRoman: RomanString(aValue,aString); break;
case eFootnote: FootnoteString(aValue,aString); break;
case eUserSeries: SeriesString(aValue,aString,aCharSet,anOffset,aBase);
}
}
static void SeriesString(PRInt32 aValue,nsString& aString,const char* aCharSet, int offset, int base) {
int ndex=0;
int root=1;
int next=base;
int expn=1;
aString.Truncate();
if(aValue<0)
aString.AppendWithConversion('-');
aValue=abs(aValue); // must be positive here...
while(next<=aValue) { // scale up in baseN; exceed current value.
root=next;
next*=base;
expn++;
}
while(expn--) {
ndex = ((root<=aValue) && (root)) ? (aValue/root): 0;
aValue%=root;
aString.AppendWithConversion(aCharSet[ndex+((root>1)*offset)]);
root/=base;
}
}
static void SpokenString(PRInt32 aValue,nsString& aString) {
static char ones[][12]= {"zero","one ","two ","three ","four ","five ","six ","seven ","eight ","nine ","ten "};
static char teens[][12]= {"ten ","eleven ","twelve ","thirteen ","fourteen ","fifteen ","sixteen ","seventeen ","eighteen ","nineteen "};
static char tens[][12]= {"","ten ","twenty ","thirty ","fourty ","fifty ","sixty ","seventy ","eighty ","ninety ","hundred "};
static char bases[][20]= {"","hundred ","thousand ","million ","billion ","trillion ","quadrillion ","quintillion ","bajillion "};
aString.Truncate();
if(aValue<0)
aString.AppendWithConversion('-');
PRInt32 root=1000000000;
PRInt32 expn=4;
PRInt32 modu=0;
PRInt32 div=0;
PRInt32 temp=0;
aValue=abs(aValue);
if(0<aValue) {
while(root && aValue) {
if(temp=aValue/root) {
if (div=temp/100) {//start with hundreds part
aString.AppendWithConversion(ones[div]);
aString.AppendWithConversion(bases[1]);
}
modu=(temp%10);
if (div=((temp%100)/10)) {
if (div<2) {
aString.AppendWithConversion(teens[modu]);
modu=0;
}
else aString.AppendWithConversion(tens[div]);
}
if (modu)
aString.AppendWithConversion(ones[modu]); //do remainder
aValue-=(temp*root);
if (expn>1)
aString.AppendWithConversion(bases[expn]);
}
expn--;
root/=1000;
}
}
else aString.AppendWithConversion(ones[0]);
}
static void DecimalString(PRInt32 aValue,nsString& aString) {
aString.Truncate();
aString.AppendInt(aValue);
}
static void BinaryString(PRInt32 aValue,nsString& aString) {
static char kBinarySet[]="01";
if (aValue<0)
aValue=65536-abs(aValue);
SeriesString(aValue,aString,kBinarySet,0,2);
}
static void HexString(PRInt32 aValue,nsString& aString) {
static char kHexSet[]="0123456789ABCDEF";
if (aValue<0)
aValue=65536-abs(aValue);
SeriesString(aValue,aString,kHexSet,0,16);
}
static void RomanString(PRInt32 aValue,nsString& aString) {
static char digitsA[] = "ixcm";
static char digitsB[] = "vld?";
aString.Truncate();
if(aValue<0)
aString.AppendWithConversion('-');
aValue=abs(aValue);
char decStr[20];
sprintf(decStr,"%d", aValue);
int len=strlen(decStr);
int romanPos=len;
int digitPos=0;
int n=0;
for(digitPos=0;digitPos<len;digitPos++) {
romanPos--;
switch(decStr[digitPos]) {
case '0': break;
case '3': aString.AppendWithConversion(digitsA[romanPos]);
case '2': aString.AppendWithConversion(digitsA[romanPos]);
case '1': aString.AppendWithConversion(digitsA[romanPos]);
break;
case '4': aString.AppendWithConversion(digitsA[romanPos]);
case '5': case '6':
case '7': case '8':
aString.AppendWithConversion(digitsB[romanPos]);
for(n=0;n<(decStr[digitPos]-'5');n++)
aString.AppendWithConversion(digitsA[romanPos]);
break;
case '9':
aString.AppendWithConversion(digitsA[romanPos]);
aString.AppendWithConversion(digitsA[romanPos]);
break;
}
}
}
static void AlphaString(PRInt32 aValue,nsString& aString) {
static const char kAlphaSet[]="abcdefghijklmnopqrstuvwxyz";
if (0<aValue)
SeriesString(aValue-1,aString,kAlphaSet,-1,26);
}
static void FootnoteString(PRInt32 aValue,nsString& aString) {
static char kFootnoteSet[]="abcdefg";
PRBool negative=(aValue<0);
int seriesLen = strlen (kFootnoteSet) - 1;
int count=0;
int repCount=0;
int modChar=0;
aString.Truncate();
aValue=abs(aValue);
repCount=((aValue-1)/seriesLen);
modChar=aValue-(repCount*seriesLen);
for(count=0;count<=repCount;count++) {
aString.AppendWithConversion(kFootnoteSet[modChar]);
}
}
protected:
const char* mUserSeries;
eNumFormat mFormat;
PRBool mCase;
PRInt32 mValue;
int mUserBase;
};
/** /**
* *
* @update gess 11May2000 * @update gess 11May2000
@ -402,22 +688,81 @@ void nsDTDContext::ResetCounters(void) {
memset(mCounters,0,sizeof(mCounters)); memset(mCounters,0,sizeof(mCounters));
} }
/** /**********************************************************
* @update: rickg 17May2000
* @update gess 11May2000
*/ Call this to handle counter attributes:
PRInt32 nsDTDContext::IncrementCounter(eHTMLTags aTag) { name="group"
PRInt32 result=++mCounters[aTag]; value="nnn"
noincr="?"
format="alpha|dec|footnote|hex|roman|spoken"
returns the newly incremented value for the (determined) group.
**********************************************************/
PRInt32 nsDTDContext::IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsString& aResult) {
PRInt32 result=0;
PRInt32 theIndex=0;
PRInt32 theNewValue=-1; //-1 is interpreted to mean "don't reset the counter sequence.
PRInt32 theIncrValue=1; //this may get set to 0 if we see a "noincr" key.
PRInt32 theCount=aNode.GetAttributeCount();
CNamedEntity *theEntity=0;
CAbacus::eNumFormat theNumFormat=CAbacus::eDecimal;
for(theIndex=0;theIndex<theCount;theIndex++){
const nsString& theKey=aNode.GetKeyAt(theIndex);
const nsString& theValue=aNode.GetValueAt(theIndex);
if(theKey.EqualsWithConversion("name",PR_TRUE)){
theEntity=GetEntity(theValue);
if(!theEntity) {
theEntity=RegisterEntity(theValue,theValue);
theEntity->mOrdinal=0;
}
aTag=eHTMLTag_userdefined;
}
else if(theKey.EqualsWithConversion("noincr",PR_TRUE)){
theIncrValue=0;
}
else if(theKey.EqualsWithConversion("format",PR_TRUE)){
PRUnichar theChar=theValue.CharAt(0);
if('"'==theChar)
theChar=theValue.CharAt(1);
switch(theChar){
case 'A': case 'a': theNumFormat=CAbacus::eAlpha; break;
case 'B': case 'b': theNumFormat=CAbacus::eBinary; break;
case 'D': case 'd': theNumFormat=CAbacus::eDecimal; break;
case 'H': case 'h': theNumFormat=CAbacus::eHex; break;
case 'R': case 'r': theNumFormat=CAbacus::eRoman; break;
case 'S': case 's': theNumFormat=CAbacus::eSpoken; break;
default:
theNumFormat=CAbacus::eDecimal;
break;
}
//determine numbering style
}
else if(theKey.EqualsWithConversion("value",PR_TRUE)){
PRInt32 err=0;
theNewValue=theValue.ToInteger(&err);
if(!err) {
theIncrValue=0;
mCounters[aTag]=theNewValue;
}
else theNewValue=-1;
}
}
if(theEntity && (eHTMLTag_userdefined==aTag)) {
result=theEntity->mOrdinal+=theIncrValue;
}
else result=mCounters[aTag]+=theIncrValue;
CAbacus::GetFormattedString(theNumFormat,result,aResult,0,0,0);
return result; return result;
} }
/**
*
* @update gess 11May2000
*/
void nsDTDContext::ResetCounter(eHTMLTags aTag,PRInt32 aValue) {
mCounters[aTag]=aValue;
}
/** /**
* *

Просмотреть файл

@ -155,6 +155,11 @@ public:
return result; return result;
} }
PRBool CanOpenTBody() {
PRBool result=!(mHasTBody);
return result;
}
PRBool CanOpenTHead() { PRBool CanOpenTHead() {
PRBool result=!(mHasTHead || mHasTFoot || mHasTBody); PRBool result=!(mHasTHead || mHasTFoot || mHasTBody);
return result; return result;
@ -174,14 +179,42 @@ public:
}; };
//used for named entities and counters (XXX debug only)
class CNamedEntity {
public:
CNamedEntity(const nsString& aName,const nsString& aValue) : mName(), mValue() {
PRUnichar theFirst=aName.First();
PRUnichar theLast=aName.Last();
PRInt32 theLen=aName.Length();
if((2<theLen) && (theFirst==theLast) && (kQuote==theFirst)) {
aName.Mid(mName,1,theLen-2);
}
else mName=aName;
theFirst=aValue.First();
theLast=aValue.Last();
theLen=aValue.Length();
if((2<theLen) && (theFirst==theLast) && (kQuote==theFirst)) {
aValue.Mid(mValue,1,theLen-2);
}
else mValue=aValue;
}
nsAutoString mName;
nsAutoString mValue;
PRInt32 mOrdinal;
};
/************************************************************************ /************************************************************************
The dtdcontext class defines an ordered list of tags (a context). The dtdcontext class defines an ordered list of tags (a context).
************************************************************************/ ************************************************************************/
class nsDTDContext { class nsDTDContext {
public: public:
nsDTDContext(); nsDTDContext();
~nsDTDContext(); ~nsDTDContext();
void Push(const nsIParserNode* aNode,nsEntryStack* aStyleStack=0); void Push(const nsIParserNode* aNode,nsEntryStack* aStyleStack=0);
nsIParserNode* Pop(nsEntryStack*& aChildStack); nsIParserNode* Pop(nsEntryStack*& aChildStack);
@ -209,9 +242,11 @@ public:
nsresult GetNodeRecycler(CNodeRecycler*& aNodeRecycler); nsresult GetNodeRecycler(CNodeRecycler*& aNodeRecycler);
static void FreeNodeRecycler(void); static void FreeNodeRecycler(void);
CNamedEntity* RegisterEntity(const nsString& aName,const nsString& aValue);
CNamedEntity* GetEntity(const nsString& aName)const;
void ResetCounters(void); void ResetCounters(void);
void ResetCounter(eHTMLTags aTag,PRInt32 aNewValue); PRInt32 IncrementCounter(eHTMLTags aTag,nsCParserNode& aNode,nsString& aResult);
PRInt32 IncrementCounter(eHTMLTags aTag);
nsEntryStack mStack; //this will hold a list of tagentries... nsEntryStack mStack; //this will hold a list of tagentries...
PRInt32 mResidualStyleCount; PRInt32 mResidualStyleCount;
@ -221,8 +256,10 @@ public:
static CNodeRecycler* mNodeRecycler; static CNodeRecycler* mNodeRecycler;
CTableState *mTableStates; CTableState *mTableStates;
PRInt32 mCounters[NS_HTML_TAG_MAX]; PRInt32 mCounters[NS_HTML_TAG_MAX];
nsString mDefaultEntity;
nsDeque mEntities;
#ifdef NS_DEBUG #ifdef NS_DEBUG
enum { eMaxTags = 100 }; enum { eMaxTags = 100 };

Просмотреть файл

@ -630,7 +630,9 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne
return ConsumeText(temp,aToken,aScanner); return ConsumeText(temp,aToken,aScanner);
}//if }//if
if(aToken){ if(aToken){
#if 0
nsString& theStr=aToken->GetStringValueXXX(); nsString& theStr=aToken->GetStringValueXXX();
if((kHashsign!=theChar) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){ if((kHashsign!=theChar) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){
//if you're here we have a bogus entity. //if you're here we have a bogus entity.
//convert it into a text token. //convert it into a text token.
@ -640,6 +642,7 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne
theRecycler->RecycleToken(aToken); theRecycler->RecycleToken(aToken);
aToken=theToken; aToken=theToken;
} }
#endif
AddToken(aToken,result,&mTokenDeque,theRecycler); AddToken(aToken,result,&mTokenDeque,theRecycler);
} }
}//if }//if

Просмотреть файл

@ -102,12 +102,13 @@ public:
//Note: To cut down on startup time/overhead, we defer the construction of non-html DTD's. //Note: To cut down on startup time/overhead, we defer the construction of non-html DTD's.
nsIDTD* theDTD; nsIDTD* theDTD;
NS_NewNavHTMLDTD(&theDTD); //do this as a default HTML DTD... NS_NewNavHTMLDTD(&theDTD); //do this as a default HTML DTD...
mDTDDeque.Push(theDTD); mDTDDeque.Push(theDTD);
#if 1
NS_NewOtherHTMLDTD(&theDTD); //do this as the default DTD for strict documents... NS_NewOtherHTMLDTD(&theDTD); //do this as the default DTD for strict documents...
mDTDDeque.Push(theDTD); mDTDDeque.Push(theDTD);
#endif
mHasViewSourceDTD=PR_FALSE; mHasViewSourceDTD=PR_FALSE;
mHasRTFDTD=mHasXMLDTD=PR_FALSE; mHasRTFDTD=mHasXMLDTD=PR_FALSE;
} }
@ -485,7 +486,7 @@ nsDTDMode nsParser::GetParseMode(void){
* @return parsermode (define in nsIParser.h) * @return parsermode (define in nsIParser.h)
*/ */
static static
void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType& aDocType) { void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType& aDocType,const nsString& aMimeType) {
const char* theModeStr= PR_GetEnv("PARSE_MODE"); const char* theModeStr= PR_GetEnv("PARSE_MODE");
aParseMode = eDTDMode_unknown; aParseMode = eDTDMode_unknown;
@ -613,8 +614,18 @@ void DetermineParseMode(nsString& aBuffer,nsDTDMode& aParseMode,eParserDocType&
} }
} }
else if(kNotFound<(theIndex=aBuffer.Find("?XML",PR_TRUE,0,128))) { else if(kNotFound<(theIndex=aBuffer.Find("?XML",PR_TRUE,0,128))) {
aDocType=eXMLText;
aParseMode=eDTDMode_strict; aParseMode=eDTDMode_strict;
if(aMimeType.EqualsWithConversion(kHTMLTextContentType)) {
//this is here to prevent a crash if someone gives us an XML document,
//but necko tells us it's a text/html mimetype.
aDocType=eHTML4Text;
aParseMode=eDTDMode_strict;
}
else aDocType=eXMLText;
}
else if(aMimeType.EqualsWithConversion(kPlainTextContentType)) {
aDocType=ePlainText;
aParseMode=eDTDMode_quirks;
} }
if(theModeStr) { if(theModeStr) {
@ -754,7 +765,11 @@ nsresult nsParser::CreateCompatibleDTD(nsIDTD** aDTD,
nsDTDMode theDTDMode=eDTDMode_unknown; nsDTDMode theDTDMode=eDTDMode_unknown;
eParserDocType theDocType=ePlainText; eParserDocType theDocType=ePlainText;
DetermineParseMode(*aDocTypeStr,theDTDMode,theDocType); if(!aMimeType) {
nsAutoString temp;
DetermineParseMode(*aDocTypeStr,theDTDMode,theDocType,temp);
}
else DetermineParseMode(*aDocTypeStr,theDTDMode,theDocType,*aMimeType);
NS_ASSERTION(aDTDMode==eDTDMode_unknown || aDTDMode==theDTDMode,"aDTDMode overrides the mode selected from the DOCTYPE "); NS_ASSERTION(aDTDMode==eDTDMode_unknown || aDTDMode==theDTDMode,"aDTDMode overrides the mode selected from the DOCTYPE ");
@ -945,7 +960,7 @@ nsresult nsParser::WillBuildModel(nsString& aFilename){
while(*theDocType) { while(*theDocType) {
nsAutoString theType; nsAutoString theType;
theType.AssignWithConversion(*theDocType); theType.AssignWithConversion(*theDocType);
DetermineParseMode(theType,theParseMode,theDocumentType); DetermineParseMode(theType,theParseMode,theDocumentType,mParserContext->mMimeType);
theDocType++; theDocType++;
} }
} }
@ -957,7 +972,7 @@ nsresult nsParser::WillBuildModel(nsString& aFilename){
mMinorIteration=-1; mMinorIteration=-1;
nsString& theBuffer=mParserContext->mScanner->GetBuffer(); nsString& theBuffer=mParserContext->mScanner->GetBuffer();
DetermineParseMode(theBuffer,mParserContext->mDTDMode,mParserContext->mDocType); DetermineParseMode(theBuffer,mParserContext->mDTDMode,mParserContext->mDocType,mParserContext->mMimeType);
if(PR_TRUE==FindSuitableDTD(*mParserContext,theBuffer)) { if(PR_TRUE==FindSuitableDTD(*mParserContext,theBuffer)) {
mParserContext->mDTD->WillBuildModel( *mParserContext,mSink); mParserContext->mDTD->WillBuildModel( *mParserContext,mSink);