From 0ab79b600b3fc650567f36509dbe1c2c4c08a73f Mon Sep 17 00:00:00 2001 From: "rickg%netscape.com" Date: Fri, 11 Feb 2000 12:11:29 +0000 Subject: [PATCH] fixed 22340, 23749, 23931, 24419, 25522, 25630, 25845 and 25895; r=harishd git-svn-id: svn://10.0.0.236/trunk@60478 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/htmlparser/src/CNavDTD.cpp | 231 +- mozilla/htmlparser/src/CNavDTD.h | 21 +- mozilla/htmlparser/src/COtherDTD.cpp | 3188 ++++++++++++++++- mozilla/htmlparser/src/COtherDTD.h | 515 ++- mozilla/htmlparser/src/CRtfDTD.cpp | 882 ++++- mozilla/htmlparser/src/CRtfDTD.h | 88 +- mozilla/htmlparser/src/nsDTDUtils.cpp | 67 +- mozilla/htmlparser/src/nsDTDUtils.h | 2 + mozilla/htmlparser/src/nsElementTable.cpp | 13 +- mozilla/htmlparser/src/nsExpatDTD.cpp | 24 - mozilla/htmlparser/src/nsExpatDTD.h | 18 - mozilla/htmlparser/src/nsHTMLTags.cpp | 11 + mozilla/htmlparser/src/nsHTMLTags.h | 1 + .../htmlparser/src/nsHTMLToTXTSinkStream.cpp | 10 +- mozilla/htmlparser/src/nsHTMLTokenizer.cpp | 2 +- mozilla/htmlparser/src/nsHTMLTokens.cpp | 39 +- mozilla/htmlparser/src/nsHTMLTokens.h | 7 +- mozilla/htmlparser/src/nsIDTD.h | 19 - mozilla/htmlparser/src/nsIParser.h | 2 +- mozilla/htmlparser/src/nsParser.cpp | 71 +- mozilla/htmlparser/src/nsParserNode.cpp | 21 +- mozilla/htmlparser/src/nsParserNode.h | 10 +- mozilla/htmlparser/src/nsScanner.cpp | 41 + mozilla/htmlparser/src/nsScanner.h | 1 + mozilla/htmlparser/src/nsTagHandler.h | 60 + mozilla/htmlparser/src/nsValidDTD.cpp | 25 - mozilla/htmlparser/src/nsValidDTD.h | 19 - mozilla/htmlparser/src/nsViewSourceHTML.cpp | 23 - mozilla/htmlparser/src/nsViewSourceHTML.h | 18 - mozilla/htmlparser/src/nsWellFormedDTD.cpp | 23 - mozilla/htmlparser/src/nsWellFormedDTD.h | 18 - mozilla/htmlparser/src/nsXIFDTD.cpp | 136 +- mozilla/htmlparser/src/nsXIFDTD.h | 21 - mozilla/parser/htmlparser/src/CNavDTD.cpp | 231 +- mozilla/parser/htmlparser/src/CNavDTD.h | 21 +- mozilla/parser/htmlparser/src/COtherDTD.cpp | 3188 ++++++++++++++++- mozilla/parser/htmlparser/src/COtherDTD.h | 515 ++- mozilla/parser/htmlparser/src/CRtfDTD.cpp | 882 ++++- mozilla/parser/htmlparser/src/CRtfDTD.h | 88 +- mozilla/parser/htmlparser/src/nsDTDUtils.cpp | 67 +- mozilla/parser/htmlparser/src/nsDTDUtils.h | 2 + .../parser/htmlparser/src/nsElementTable.cpp | 13 +- mozilla/parser/htmlparser/src/nsExpatDTD.cpp | 24 - mozilla/parser/htmlparser/src/nsExpatDTD.h | 18 - mozilla/parser/htmlparser/src/nsHTMLTags.cpp | 11 + mozilla/parser/htmlparser/src/nsHTMLTags.h | 1 + .../htmlparser/src/nsHTMLToTXTSinkStream.cpp | 10 +- .../parser/htmlparser/src/nsHTMLTokenizer.cpp | 2 +- .../parser/htmlparser/src/nsHTMLTokens.cpp | 39 +- mozilla/parser/htmlparser/src/nsHTMLTokens.h | 7 +- mozilla/parser/htmlparser/src/nsIDTD.h | 19 - mozilla/parser/htmlparser/src/nsIParser.h | 2 +- mozilla/parser/htmlparser/src/nsParser.cpp | 71 +- .../parser/htmlparser/src/nsParserNode.cpp | 21 +- mozilla/parser/htmlparser/src/nsParserNode.h | 10 +- mozilla/parser/htmlparser/src/nsScanner.cpp | 41 + mozilla/parser/htmlparser/src/nsScanner.h | 1 + mozilla/parser/htmlparser/src/nsTagHandler.h | 60 + mozilla/parser/htmlparser/src/nsValidDTD.cpp | 25 - mozilla/parser/htmlparser/src/nsValidDTD.h | 19 - .../htmlparser/src/nsViewSourceHTML.cpp | 23 - .../parser/htmlparser/src/nsViewSourceHTML.h | 18 - .../parser/htmlparser/src/nsWellFormedDTD.cpp | 23 - .../parser/htmlparser/src/nsWellFormedDTD.h | 18 - mozilla/parser/htmlparser/src/nsXIFDTD.cpp | 136 +- mozilla/parser/htmlparser/src/nsXIFDTD.h | 21 - 66 files changed, 9216 insertions(+), 2038 deletions(-) diff --git a/mozilla/htmlparser/src/CNavDTD.cpp b/mozilla/htmlparser/src/CNavDTD.cpp index f00f8596481..91535a08480 100644 --- a/mozilla/htmlparser/src/CNavDTD.cpp +++ b/mozilla/htmlparser/src/CNavDTD.cpp @@ -4,7 +4,7 @@ * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ - * + * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing @@ -89,91 +89,6 @@ static char gShowCRC; -/*************************************************************** - This the ITagHandler deque deallocator, needed by the - CTagHandlerRegister - ***************************************************************/ -class CTagHandlerDeallocator: public nsDequeFunctor{ -public: - virtual void* operator()(void* aObject) { - nsITagHandler* tagHandler = (nsITagHandler*)aObject; - delete tagHandler; - return 0; - } -}; - -/*************************************************************** - This funtor will be called for each item in the TagHandler que to - check for a Tag name, and setting the current TagHandler when it is reached - ***************************************************************/ -class CTagFinder: public nsDequeFunctor{ - -public: - CTagFinder(){} - void Initialize(const nsString &aTagName) {mTagName = aTagName;} - - virtual ~CTagFinder() { - } - - virtual void* operator()(void* aObject) { - nsString* theString = ((nsITagHandler*)aObject)->GetString(); - if( theString->Equals(mTagName)){ - return aObject; - } - return(0); - } - - nsAutoString mTagName; -}; - -/*************************************************************** - This a an object that will keep track of TagHandlers in - the DTD. Uses a factory pattern - ***************************************************************/ -class CTagHandlerRegister { -public: - - CTagHandlerRegister(); - - ~CTagHandlerRegister(); - - void RegisterTagHandler(nsITagHandler *aTagHandler){ - mTagHandlerDeque.Push(aTagHandler); - } - - nsITagHandler* FindTagHandler(const nsString &aTagName){ - nsITagHandler* foundHandler = nsnull; - - mTagFinder.Initialize(aTagName); - mTagHandlerDeque.Begin(); - foundHandler = (nsITagHandler*) mTagHandlerDeque.FirstThat(mTagFinder); - return foundHandler; - } - - nsDeque mTagHandlerDeque; - CTagFinder mTagFinder; -}; - -MOZ_DECL_CTOR_COUNTER(CTagHandlerRegister); - -CTagHandlerRegister::CTagHandlerRegister() : mTagHandlerDeque(new CTagHandlerDeallocator()) -{ - MOZ_COUNT_CTOR(CTagHandlerRegister); -} - -CTagHandlerRegister::~CTagHandlerRegister() -{ - MOZ_COUNT_DTOR(CTagHandlerRegister); -} - -/************************************************************************ - The CTagHandlerRegister for a CNavDTD. - This is where special taghanders for our tags can be managed and called from - Note: This can also be attached to some object so it can be refcounted - and destroyed if you want this to go away when not imbedded. - ************************************************************************/ -//CTagHandlerRegister gTagHandlerRegister; - /************************************************************************ And now for the main class -- CNavDTD... @@ -242,6 +157,8 @@ CNavDTD::CNavDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mShared mExpectedCRC32=0; mDTDState=NS_OK; mStyleHandlingEnabled=PR_TRUE; + mIsText=PR_FALSE; + mRequestedHead=PR_FALSE; if(!gHTMLElements) { InitializeElementTable(); @@ -452,11 +369,23 @@ PRBool CNavDTD::Verify(nsString& aURLRef,nsIParser* aParser){ */ eAutoDetectResult CNavDTD::CanParse(nsString& aContentType, nsString& aCommand, nsString& aBuffer, PRInt32 aVersion) { eAutoDetectResult result=eUnknownDetect; - - if(!aCommand.Equals(kViewSourceCommand)) { + + + if(aCommand.Equals(kViewSourceCommand)) { + if(PR_TRUE==aContentType.Equals(kPlainTextContentType)) { + result=ePrimaryDetect; + } + else if(aContentType.Equals(kRTFTextContentType)){ + result=ePrimaryDetect; + } + } + else { if(PR_TRUE==aContentType.Equals(kHTMLTextContentType)) { result=ePrimaryDetect; } + if(PR_TRUE==aContentType.Equals(kPlainTextContentType)) { + result=ePrimaryDetect; + } else { //otherwise, look into the buffer to see if you recognize anything... PRBool theBufHasXML=PR_FALSE; @@ -492,6 +421,7 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename, mHasOpenScript=PR_FALSE; mParseMode=aParseMode; mStyleHandlingEnabled=(eParseMode_quirks==mParseMode); + mRequestedHead=PR_FALSE; if((aNotifySink) && (aSink)) { @@ -501,6 +431,8 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename, mTokenRecycler=0; mStyleHandlingEnabled=PR_TRUE; + mIsText=aSourceType.Equals(kPlainTextContentType) || aSourceType.Equals(kRTFTextContentType); + if(aSink && (!mSink)) { result=aSink->QueryInterface(kIHTMLContentSinkIID, (void **)&mSink); } @@ -516,6 +448,7 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename, mExpectedCRC32=0; } } + return result; } @@ -542,12 +475,17 @@ nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsIToke mTokenRecycler=(CTokenRecycler*)mTokenizer->GetTokenRecycler(); if(mSink) { - - if(!mBodyContext->GetCount()) { //if the content model is empty, then begin by opening ... CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_html,"html"); HandleStartToken(theToken); //this token should get pushed on the context stack, don't recycle it. + + if(mIsText) { + //we do this little trick for text files, in both normal and viewsource mode... + CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_pre); + HandleStartToken(theToken); + } + } while(NS_SUCCEEDED(result)){ @@ -883,30 +821,6 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ }//if return result; } - -/** - * This method causes all tokens to be dispatched to the given tag handler. - * - * @update gess 3/25/98 - * @param aHandler -- object to receive subsequent tokens... - * @return error code (usually 0) - */ -nsresult CNavDTD::CaptureTokenPump(nsITagHandler* aHandler) { - nsresult result=NS_OK; - return result; -} - -/** - * This method releases the token-pump capture obtained in CaptureTokenPump() - * - * @update gess 3/25/98 - * @param aHandler -- object that received tokens... - * @return error code (usually 0) - */ -nsresult CNavDTD::ReleaseTokenPump(nsITagHandler* aHandler){ - nsresult result=NS_OK; - return result; -} /** * This gets called after we've handled a given start tag. @@ -940,9 +854,9 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){ { STOP_TIMER() MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::DidHandleStartTag(), this=%p\n", this)); - const nsString& theText=aNode.GetSkippedContent(); - if(0
  • + /*------------------------------------------------------------------------------------- + 1. Here's a tricky case from bug 22596:
  • - How do we know that the 2nd
    should close the
  • rather than nest inside the
  • ? - (Afterall, the
    is a legal child of the
  • ). + How do we know that the 2nd
    should close the
  • rather than nest inside the
  • ? + (Afterall, the
    is a legal child of the
  • ). - The way you know is that there is no root between the two, so the
    binds more - tightly to the 1st
    than to the
  • . - -------------------------------------------------------------------------------------*/ + The way you know is that there is no root between the two, so the
    binds more + tightly to the 1st
    than to the
  • . - theChildAgrees=CanBeContained(aChildTag,*mBodyContext); - } //if + 2. Also, bug 6148 shows this case:
    + From this case we learned not to execute this logic if the parent is a block. + -------------------------------------------------------------------------------------*/ + + theChildAgrees=CanBeContained(aChildTag,*mBodyContext); + } //if + }//if } //if } //if } //if parentcontains @@ -1417,6 +1336,7 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) { if(mHadBody || mHadFrameset) { result=HandleOmittedTag(aToken,theChildTag,theParent,theNode); isTokenHandled=PR_TRUE; + mRequestedHead=PR_TRUE; } break; default: @@ -1457,7 +1377,7 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) { break; case eHTMLTag_script: - theHeadIsParent=(!mHasOpenBody); + theHeadIsParent=((!mHasOpenBody) || mRequestedHead); mHasOpenScript=PR_TRUE; default: @@ -1645,6 +1565,7 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) { case eHTMLTag_head: StripWSFollowingTag(theChildTag,mTokenizer,mTokenRecycler,mLineNumber); + mRequestedHead=PR_FALSE; //ok to fall through... case eHTMLTag_form: @@ -2068,7 +1989,10 @@ nsresult CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) { // XXX rickg This linefeed conversion stuff should be moved out of // the parser and into the form element code PRBool aMustConvertLinebreaks = PR_FALSE; - + + mScratch.Truncate(); + aNode.SetSkippedContent(mScratch); + for(aIndex=0;aIndexTranslateToUnicodeStr(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); + 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+=mScratch; + aNode.mSkippedContent->Append(mScratch); } mTokenRecycler->RecycleToken(theNextToken); } @@ -2106,13 +2032,13 @@ nsresult CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32 &aCount) { aNode.mSkippedContent.ReplaceChar("\r", kNewLine); */ #if 1 - nsLinebreakConverter::ConvertStringLineBreaks(aNode.mSkippedContent, + nsLinebreakConverter::ConvertStringLineBreaks(*aNode.mSkippedContent, nsLinebreakConverter::eLinebreakAny, nsLinebreakConverter::eLinebreakContent); #endif } // Let's hope that this does not hamper the PERFORMANCE!! - mLineNumber += aNode.mSkippedContent.CountChar(kNewLine); + mLineNumber += aNode.mSkippedContent->CountChar(kNewLine); return NS_OK; } @@ -2879,8 +2805,19 @@ CNavDTD::OpenContainer(const nsIParserNode *aNode,eHTMLTags aTag,PRBool aClosedB PRBool isDefaultNode=PR_FALSE; - if (nsHTMLElement::IsResidualStyleTag(aTag)) + if (nsHTMLElement::IsResidualStyleTag(aTag)) { + /*********************************************************************** + * Here's an interesting problem: + * + * If there's an on the RS-stack, and you're trying to open + * another , the one on the RS-stack should be discarded. + * + * I'm updating OpenTransientStyles to throw old 's away. + * + ***********************************************************************/ + OpenTransientStyles(aTag); + } #ifdef ENABLE_CRC #define K_OPENOP 100 @@ -3362,16 +3299,16 @@ nsresult CNavDTD::AddHeadLeaf(nsIParserNode *aNode){ if(NS_OK==result) { if(eHTMLTag_title==theTag) { - ///XXX this evil hack is necessary only for beta. - //Post beta, lets make the GetSkippedContent() call non-const. - const nsString& theString=aNode->GetSkippedContent(); - nsString* theStr=(nsString*)&theString; - theStr->CompressWhitespace(); + PRInt32 theLen=theString.Length(); + CBufDescriptor theBD(theString.GetUnicode(), PR_TRUE, theLen+1, theLen); + nsAutoString theString2(theBD); + + theString2.CompressWhitespace(); STOP_TIMER() MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::AddHeadLeaf(), this=%p\n", this)); - mSink->SetTitle(theString); + mSink->SetTitle(theString2); MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::AddHeadLeaf(), this=%p\n", this)); START_TIMER() @@ -3454,7 +3391,7 @@ nsresult CNavDTD::CreateContextStackFor(eHTMLTags aChildTag){ nsresult CNavDTD::GetTokenizer(nsITokenizer*& aTokenizer) { nsresult result=NS_OK; if(!mTokenizer) { - result=NS_NewHTMLTokenizer(&mTokenizer,mParseMode,PR_FALSE); + result=NS_NewHTMLTokenizer(&mTokenizer,mParseMode,mIsText); } aTokenizer=mTokenizer; return result; diff --git a/mozilla/htmlparser/src/CNavDTD.h b/mozilla/htmlparser/src/CNavDTD.h index 838467dda60..0645fd2f980 100644 --- a/mozilla/htmlparser/src/CNavDTD.h +++ b/mozilla/htmlparser/src/CNavDTD.h @@ -90,6 +90,7 @@ #include "nsVoidArray.h" #include "nsDeque.h" #include "nsParserCIID.h" +#include "nsTime.h" #define NS_INAVHTML_DTD_IID \ {0x5c5cce40, 0xcfd6, 0x11d1, \ @@ -220,24 +221,6 @@ CLASS_EXPORT_HTMLPARS CNavDTD : public nsIDTD { */ NS_IMETHOD HandleToken(CToken* aToken,nsIParser* aParser); - /** - * This method causes all tokens to be dispatched to the given tag handler. - * - * @update gess 3/25/98 - * @param aHandler -- object to receive subsequent tokens... - * @return error code (usually 0) - */ - NS_IMETHOD CaptureTokenPump(nsITagHandler* aHandler); - - /** - * This method releases the token-pump capture obtained in CaptureTokenPump() - * - * @update gess 3/25/98 - * @param aHandler -- object that received tokens... - * @return error code (usually 0) - */ - NS_IMETHOD ReleaseTokenPump(nsITagHandler* aHandler); - /** * * @update gess12/28/98 @@ -541,6 +524,8 @@ protected: PRUint32 mExpectedCRC32; nsAutoString mScratch; //used for various purposes; non-persistent PRBool mStyleHandlingEnabled; + PRBool mIsText; + PRBool mRequestedHead; #ifdef NS_DEBUG PRInt32 gNodeCount; diff --git a/mozilla/htmlparser/src/COtherDTD.cpp b/mozilla/htmlparser/src/COtherDTD.cpp index 8909587144d..0c8111e820e 100644 --- a/mozilla/htmlparser/src/COtherDTD.cpp +++ b/mozilla/htmlparser/src/COtherDTD.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* +/* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of @@ -18,50 +18,167 @@ * Rights Reserved. * * Contributor(s): - */ + */ -/** - * MODULE NOTES: - * @update gess 4/8/98 - * - * - */ - -/** - * TRANSIENT STYLE-HANDLING NOTES: - * @update gess 6/15/98 - * - * See notes about transient style handling - * in the nsNavDTD.h file. - * - */ - -#include "COtherDTD.h" +//#define ENABLE_CRC +//#define RICKG_DEBUG +#define ENABLE_RESIDUALSTYLE +#ifdef RICKG_DEBUG +#include +#endif + +#include "nsDebug.h" +#include "nsIDTDDebug.h" +#include "COtherDTD.h" #include "nsHTMLTokens.h" #include "nsCRT.h" #include "nsParser.h" +#include "nsIParser.h" #include "nsIHTMLContentSink.h" #include "nsScanner.h" -#include "nsIParser.h" - +#include "nsIDTDDebug.h" #include "prenv.h" //this is here for debug reasons... -#include "prtypes.h" +#include "prtypes.h" //this is here for debug reasons... #include "prio.h" #include "plstr.h" - +#include "nsDTDUtils.h" +#include "nsTagHandler.h" +#include "nsHTMLTokenizer.h" +#include "nsTime.h" +#include "nsIElementObserver.h" +#include "nsViewSourceHTML.h" +#include "nsParserNode.h" +#include "nsHTMLEntities.h" +#include "nsLinebreakConverter.h" #ifdef XP_PC #include //this is here for debug reasons... #endif -#include #include "prmem.h" + +static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTML_CONTENT_SINK_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kIDTDIID, NS_IDTD_IID); -static NS_DEFINE_IID(kClassIID, NS_IOtherHTML_DTD_IID); -static NS_DEFINE_IID(kBaseClassIID, NS_INAVHTML_DTD_IID); +static NS_DEFINE_IID(kClassIID, NS_IOTHERHTML_DTD_IID); + +static const char* kNullToken = "Error: Null token given"; +static const char* kInvalidTagStackPos = "Error: invalid tag stack position"; +static char* kVerificationDir = "c:/temp"; +#ifdef ENABLE_CRC +static char gShowCRC; +#endif + +#include "nsElementTable.h" + + +#ifdef MOZ_PERF_METRICS +# define START_TIMER() \ + if(mParser) MOZ_TIMER_START(mParser->mParseTime); \ + if(mParser) MOZ_TIMER_START(mParser->mDTDTime); + +# define STOP_TIMER() \ + if(mParser) MOZ_TIMER_STOP(mParser->mParseTime); \ + if(mParser) MOZ_TIMER_STOP(mParser->mDTDTime); +#else +# define STOP_TIMER() +# define START_TIMER() +#endif + + + +/*************************************************************** + This the ITagHandler deque deallocator, needed by the + CTagHandlerRegister + ***************************************************************/ +class CTagHandlerDeallocator: public nsDequeFunctor{ +public: + virtual void* operator()(void* aObject) { + nsITagHandler* tagHandler = (nsITagHandler*)aObject; + delete tagHandler; + return 0; + } +}; + +/*************************************************************** + This funtor will be called for each item in the TagHandler que to + check for a Tag name, and setting the current TagHandler when it is reached + ***************************************************************/ +class CTagFinder: public nsDequeFunctor{ + +public: + CTagFinder(){} + void Initialize(const nsString &aTagName) {mTagName = aTagName;} + + virtual ~CTagFinder() { + } + + virtual void* operator()(void* aObject) { + nsString* theString = ((nsITagHandler*)aObject)->GetString(); + if( theString->Equals(mTagName)){ + return aObject; + } + return(0); + } + + nsAutoString mTagName; +}; + +/*************************************************************** + This a an object that will keep track of TagHandlers in + the DTD. Uses a factory pattern + ***************************************************************/ +class CTagHandlerRegister { +public: + + CTagHandlerRegister(); + + ~CTagHandlerRegister(); + + void RegisterTagHandler(nsITagHandler *aTagHandler){ + mTagHandlerDeque.Push(aTagHandler); + } + + nsITagHandler* FindTagHandler(const nsString &aTagName){ + nsITagHandler* foundHandler = nsnull; + + mTagFinder.Initialize(aTagName); + mTagHandlerDeque.Begin(); + foundHandler = (nsITagHandler*) mTagHandlerDeque.FirstThat(mTagFinder); + return foundHandler; + } + + + nsDeque mTagHandlerDeque; + CTagFinder mTagFinder; +}; + +MOZ_DECL_CTOR_COUNTER(CTagHandlerRegister); + +CTagHandlerRegister::CTagHandlerRegister() : mTagHandlerDeque(new CTagHandlerDeallocator()) +{ + MOZ_COUNT_CTOR(CTagHandlerRegister); +} + +CTagHandlerRegister::~CTagHandlerRegister() +{ + MOZ_COUNT_DTOR(CTagHandlerRegister); +} + +/************************************************************************ + The CTagHandlerRegister for a COtherDTD. + This is where special taghanders for our tags can be managed and called from + Note: This can also be attached to some object so it can be refcounted + and destroyed if you want this to go away when not imbedded. + ************************************************************************/ +//CTagHandlerRegister gTagHandlerRegister; + + +/************************************************************************ + And now for the main class -- COtherDTD... + ************************************************************************/ /** * This method gets called as part of our COM-like interfaces. @@ -82,9 +199,6 @@ nsresult COtherDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr) if(aIID.Equals(kISupportsIID)) { //do IUnknown... *aInstancePtr = (nsIDTD*)(this); } - else if(aIID.Equals(kBaseClassIID)) { //do nav dtd base class... - *aInstancePtr = (CNavDTD*)(this); - } else if(aIID.Equals(kIDTDIID)) { //do IParser base class... *aInstancePtr = (nsIDTD*)(this); } @@ -99,6 +213,192 @@ nsresult COtherDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr) return NS_OK; } +NS_IMPL_ADDREF(COtherDTD) +NS_IMPL_RELEASE(COtherDTD) + +/** + * Default constructor + * + * @update gess 4/9/98 + * @param + * @return + */ +COtherDTD::COtherDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSharedNodes(0), mScratch("") { + NS_INIT_REFCNT(); + mSink = 0; + mParser=0; + mDTDDebug=0; + mLineNumber=1; + mHasOpenBody=PR_FALSE; + mHasOpenHead=0; + mHasOpenForm=PR_FALSE; + mHasOpenMap=PR_FALSE; + mHeadContext=new nsDTDContext(); + mBodyContext=new nsDTDContext(); + mFormContext=0; + mMapContext=0; + mTempContext=0; + mTokenizer=0; + mComputedCRC32=0; + mExpectedCRC32=0; + mDTDState=NS_OK; + mStyleHandlingEnabled=PR_TRUE; + mIsText=PR_FALSE; + + if(!gHTMLElements) { + InitializeElementTable(); + } + +#ifdef RICKG_DEBUG + //DebugDumpContainmentRules2(*this,"c:/temp/DTDRules.new","New COtherDTD Containment Rules"); + nsHTMLElement::DebugDumpContainment("c:/temp/contain.new","ElementTable Rules"); + nsHTMLElement::DebugDumpMembership("c:/temp/membership.out"); + nsHTMLElement::DebugDumpContainType("c:/temp/ctnrules.out"); +#endif + +#ifdef NS_DEBUG + gNodeCount=0; +#endif +} + + +/** + * This method creates a new parser node. It tries to get one from + * the recycle list before allocating a new one. + * @update gess1/8/99 + * @param + * @return valid node* + */ + +nsCParserNode* COtherDTD::CreateNode(void) { + + nsCParserNode* result=0; + if(0mUseCount)) { + + if(aNode->mToken) { + if(!aNode->mToken->mUseCount) { + mTokenRecycler->RecycleToken(aNode->mToken); + } + } + + CToken* theToken=0; + while((theToken=(CToken*)aNode->PopAttributeToken())){ + if(!theToken->mUseCount) { + mTokenRecycler->RecycleToken(theToken); + } + } + + mSharedNodes.Push(aNode); + } +} + +/** + * This method recycles the nodes on a nodestack. + * NOTE: Unlike recycleNode(), we force the usecount + * to 0 of all nodes, then force them to recycle. + * @update gess1/8/99 + * @param aNodeStack + * @return nothing + */ +void COtherDTD::RecycleNodes(nsEntryStack *aNodeStack) { + if(aNodeStack) { + PRInt32 theCount=aNodeStack->mCount; + PRInt32 theIndex=0; + + for(theIndex=0;theIndexNodeAt(theIndex); + if(theNode) { + + theNode->mUseCount=0; + if(theNode->mToken) { + theNode->mToken->mUseCount=0; + mTokenRecycler->RecycleToken(theNode->mToken); + } + + CToken* theToken=0; + while((theToken=(CToken*)theNode->PopAttributeToken())){ + theNode->mToken->mUseCount=0; + mTokenRecycler->RecycleToken(theToken); + } + + mSharedNodes.Push(theNode); + } //if + } //while + } //if +} + +/** + * + * @update gess1/8/99 + * @param + * @return + */ +const nsIID& COtherDTD::GetMostDerivedIID(void)const { + return kClassIID; +} + +/** + * Default destructor + * + * @update gess 4/9/98 + * @param + * @return + */ +COtherDTD::~COtherDTD(){ + delete mHeadContext; + delete mBodyContext; + + NS_IF_RELEASE(mTokenizer); + + if(mTempContext) + delete mTempContext; + + nsCParserNode* theNode=0; + +#ifdef NS_DEBUG +#if 0 + PRInt32 count=gNodeCount-mSharedNodes.GetSize(); + if(count) { + printf("%i of %i nodes leaked!\n",count,gNodeCount); + } +#endif +#endif + +#if 1 + while((theNode=(nsCParserNode*)mSharedNodes.Pop())){ + delete theNode; + } +#endif + +#ifdef NS_DEBUG + gNodeCount=0; +#endif + + NS_IF_RELEASE(mSink); + NS_IF_RELEASE(mDTDDebug); +} + /** * This method is defined in nsIParser. It is used to * cause the COM-like construction of an nsParser. @@ -107,8 +407,7 @@ nsresult COtherDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr) * @param nsIParser** ptr to newly instantiated parser * @return NS_xxx error result */ -NS_HTMLPARS nsresult NS_NewOtherHTMLDTD(nsIDTD** aInstancePtrResult) -{ +NS_HTMLPARS nsresult NS_NewOtherHTMLDTD(nsIDTD** aInstancePtrResult) { COtherDTD* it = new COtherDTD(); if (it == 0) { @@ -118,45 +417,10 @@ NS_HTMLPARS nsresult NS_NewOtherHTMLDTD(nsIDTD** aInstancePtrResult) return it->QueryInterface(kClassIID, (void **) aInstancePtrResult); } - -NS_IMPL_ADDREF(COtherDTD) -NS_IMPL_RELEASE(COtherDTD) - /** - * Default constructor; parent does all the real work. - * - * @update gess 4/9/98 - * @param - * @return - */ -COtherDTD::COtherDTD() : CNavDTD() { -} - -/** - * Default destructor - * - * @update gess 4/9/98 - * @param - * @return - */ -COtherDTD::~COtherDTD(){ - //parent does all the real work of destruction. -} - -/** - * - * @update gess1/8/99 - * @param - * @return - */ -const nsIID& COtherDTD::GetMostDerivedIID(void) const{ - return kClassIID; -} - -/** - * Call this method if you want the DTD to construct a fresh instance - * of itself - * @update gess7/23/98 + * Call this method if you want the DTD to construct a fresh + * instance of itself. + * @update gess7/23/98 * @param * @return */ @@ -164,20 +428,629 @@ nsresult COtherDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){ return NS_NewOtherHTMLDTD(aInstancePtrResult); } +/** + * Called by the parser to initiate dtd verification of the + * internal context stack. + * @update gess 7/23/98 + * @param + * @return + */ +PRBool COtherDTD::Verify(nsString& aURLRef,nsIParser* aParser){ + PRBool result=PR_TRUE; + + /* + * Disable some DTD debugging code in the parser that + * breaks on some compilers because of some broken + * streams code in prstrm.cpp. + */ +#if !defined(MOZ_DISABLE_DTD_DEBUG) + if(!mDTDDebug){ + nsresult rval = NS_NewDTDDebug(&mDTDDebug); + if (NS_OK != rval) { + fputs("Cannot create parser debugger.\n", stdout); + result=-PR_FALSE; + } + else mDTDDebug->SetVerificationDirectory(kVerificationDir); + } +#endif + + if(mDTDDebug) { + // mDTDDebug->Verify(this,aParser,mBodyContext->GetCount(),mBodyContext->mStack,aURLRef); + } + return result; +} + /** * This method is called to determine if the given DTD can parse * a document in a given source-type. * NOTE: Parsing always assumes that the end result will involve * storing the result in the main content model. - * @update gess6/24/98 + * @update gess6/24/98 * @param * @return TRUE if this DTD can satisfy the request; FALSE otherwise. */ eAutoDetectResult COtherDTD::CanParse(nsString& aContentType, nsString& aCommand, nsString& aBuffer, PRInt32 aVersion) { - return CNavDTD::CanParse(aContentType,aCommand,aBuffer,aVersion); + eAutoDetectResult result=eUnknownDetect; + + + if(!aCommand.Equals(kViewSourceCommand)) { + if(PR_TRUE==(aContentType.Equals(kHTMLTextContentType) || aContentType.Equals(kPlainTextContentType))) { + result=ePrimaryDetect; + } + else { + //otherwise, look into the buffer to see if you recognize anything... + PRBool theBufHasXML=PR_FALSE; + if(BufferContainsHTML(aBuffer,theBufHasXML)){ + result = eValidDetect ; + if(0==aContentType.Length()) { + aContentType=kHTMLTextContentType; + result = (theBufHasXML) ? eValidDetect : ePrimaryDetect; + } + } + } + } + return result; +} + + +/** + * + * @update gess5/18/98 + * @param + * @return + */ +nsresult COtherDTD::WillBuildModel(nsString& aFilename, + PRBool aNotifySink,nsString& aSourceType,eParseMode aParseMode, + nsString& aCommand,nsIContentSink* aSink){ + nsresult result=NS_OK; + + mFilename=aFilename; + mHasOpenBody=PR_FALSE; + mHadBody=PR_FALSE; + mHadFrameset=PR_FALSE; + mLineNumber=1; + mHasOpenScript=PR_FALSE; + mParseMode=aParseMode; + mStyleHandlingEnabled=(eParseMode_quirks==mParseMode); + + if((aNotifySink) && (aSink)) { + + STOP_TIMER(); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillBuildModel(), this=%p\n", this)); + + mTokenRecycler=0; + mStyleHandlingEnabled=PR_TRUE; + + if(aSink && (!mSink)) { + result=aSink->QueryInterface(kIHTMLContentSinkIID, (void **)&mSink); + } + + if(result==NS_OK) { + result = aSink->WillBuildModel(); + + MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillBuildModel(), this=%p\n", this)); + START_TIMER(); + + mSkipTarget=eHTMLTag_unknown; + mComputedCRC32=0; + mExpectedCRC32=0; + } + } + + mIsText=aSourceType.Equals(kPlainTextContentType); + + return result; +} + + +/** + * This is called when it's time to read as many tokens from the tokenizer + * as you can. Not all tokens may make sense, so you may not be able to + * read them all (until more come in later). + * + * @update gess5/18/98 + * @param aParser is the parser object that's driving this process + * @return error code (almost always NS_OK) + */ +nsresult COtherDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITokenObserver* anObserver,nsIContentSink* aSink) { + nsresult result=NS_OK; + + if(aTokenizer) { + nsITokenizer* oldTokenizer=mTokenizer; + mTokenizer=aTokenizer; + mParser=(nsParser*)aParser; + + if(mTokenizer) { + + mTokenRecycler=(CTokenRecycler*)mTokenizer->GetTokenRecycler(); + if(mSink) { + + + + if(!mBodyContext->GetCount()) { + //if the content model is empty, then begin by opening ... + CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_html,"html"); + HandleStartToken(theToken); //this token should get pushed on the context stack, don't recycle it. + } + + while(NS_SUCCEEDED(result)){ + +#if 0 + int n=aTokenizer->GetCount(); + if(n>50) n=50; + for(int i=0;iGetTokenAt(i); + printf("\nToken[%i],%p",i,theToken); + } + printf("\n"); +#endif + + if(mDTDState!=NS_ERROR_HTMLPARSER_STOPPARSING) { + CToken* theToken=mTokenizer->PopToken(); + if(theToken) { + result=HandleToken(theToken,aParser); + } + else break; + } + else { + result=mDTDState; + break; + } + }//while + mTokenizer=oldTokenizer; + } + } + } + else result=NS_ERROR_HTMLPARSER_BADTOKENIZER; + return result; } /** + * + * @update gess5/18/98 + * @param + * @return + */ +nsresult COtherDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParser* aParser,nsIContentSink* aSink){ + nsresult result=NS_OK; + + if(aSink) { + + if((NS_OK==anErrorCode) && (!mHadBody) && (!mHadFrameset)) { + + mSkipTarget=eHTMLTag_unknown; //clear this in case we were searching earlier. + + mTokenizer->PrependTokens(mMisplacedContent); //push misplaced content + + if(mIsText) { + CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_pre,"pre"); + mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack, don't recycle it + } + + CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_body,"body"); + mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack, don't recycle it + + result=BuildModel(aParser,mTokenizer,0,aSink); + } + + if(aParser && (NS_OK==result)){ + if(aNotifySink){ + if((NS_OK==anErrorCode) && (mBodyContext->GetCount()>0)) { + if(mSkipTarget) { + CHTMLToken* theEndToken=nsnull; + theEndToken=(CHTMLToken*)mTokenRecycler->CreateTokenOfType(eToken_end,mSkipTarget); + if(theEndToken) { + result=HandleToken(theEndToken,mParser); + } + } + if(result==NS_OK) { + eHTMLTags theTarget; + + //now let's disable style handling to save time when closing remaining stack members... + mStyleHandlingEnabled=PR_FALSE; + + while(mBodyContext->GetCount() > 0) { + theTarget = mBodyContext->Last(); + CloseContainersTo(theTarget,PR_FALSE); + } + } + } + else { + //If you're here, then an error occured, but we still have nodes on the stack. + //At a minimum, we should grab the nodes and recycle them. + //Just to be correct, we'll also recycle the nodes. + + while(mBodyContext->GetCount() > 0) { + + nsEntryStack *theChildStyles=0; + nsCParserNode* theNode=(nsCParserNode*)mBodyContext->Pop(theChildStyles); + theNode->mUseCount=0; + RecycleNode(theNode); + if(theChildStyles) { + delete theChildStyles; + } + } + + } + + STOP_TIMER(); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::DidBuildModel(), this=%p\n", this)); + +#ifdef ENABLE_CRC + + //let's only grab this state once! + if(!gShowCRC) { + gShowCRC=1; //this only indicates we'll not initialize again. + char* theEnvString = PR_GetEnv("RICKG_CRC"); + if(theEnvString){ + if(('1'==theEnvString[0]) || ('Y'==theEnvString[0]) || ('y'==theEnvString[0])){ + gShowCRC=2; //this indicates that the CRC flag was found in the environment. + } + } + } + + if(2==gShowCRC) { + if(mComputedCRC32!=mExpectedCRC32) { + if(mExpectedCRC32!=0) { + printf("CRC Computed: %u Expected CRC: %u\n,",mComputedCRC32,mExpectedCRC32); + result = aSink->DidBuildModel(2); + } + else { + printf("Computed CRC: %u.\n",mComputedCRC32); + result = aSink->DidBuildModel(3); + } + } + else result = aSink->DidBuildModel(0); + } + else result=aSink->DidBuildModel(0); +#endif + + MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::DidBuildModel(), this=%p\n", this)); + START_TIMER(); + + //Now make sure the misplaced content list is empty, + //by forcefully recycling any tokens we might find there. + + CToken* theToken=0; + while((theToken=(CToken*)mMisplacedContent.Pop())) { + mTokenRecycler->RecycleToken(theToken); + } + + if(mDTDDebug) { + mDTDDebug->DumpVectorRecord(); + } + } + } //if aparser + + //No matter what, you need to call did build model. + result=aSink->DidBuildModel(0); + + } //if asink + return result; +} + +/** + * This big dispatch method is used to route token handler calls to the right place. + * What's wrong with it? This table, and the dispatch methods themselves need to be + * moved over to the delegate. Ah, so much to do... + * + * @update gess 12/1/99 + * @param aToken + * @param aParser + * @return + */ +nsresult COtherDTD::HandleToken(CToken* aToken,nsIParser* aParser){ + nsresult result=NS_OK; + + if(aToken) { + CHTMLToken* theToken= (CHTMLToken*)(aToken); + eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType()); + eHTMLTags theTag=(eHTMLTags)theToken->GetTypeID(); + PRBool execSkipContent=PR_FALSE; + + theToken->mUseCount=0; //assume every token coming into this system needs recycling. + + /* --------------------------------------------------------------------------------- + To understand this little piece of code, you need to look below too. + In essence, this code caches "skipped content" until we find a given skiptarget. + Once we find the skiptarget, we take all skipped content up to that point and + coallate it. Then we push those tokens back onto the tokenizer deque. + --------------------------------------------------------------------------------- + */ + + // printf("token: %p\n",aToken); + + if(mSkipTarget){ //handle a preexisting target... + if((theTag==mSkipTarget) && (eToken_end==theType)){ + mSkipTarget=eHTMLTag_unknown; //stop skipping. + //mTokenizer->PushTokenFront(aToken); //push the end token... + execSkipContent=PR_TRUE; + mTokenRecycler->RecycleToken(aToken); + theToken=(CHTMLToken*)mSkippedContent.PopFront(); + theType=eToken_start; + } + else { + mSkippedContent.Push(theToken); + return result; + } + } + + /* --------------------------------------------------------------------------------- + This section of code is used to "move" misplaced content from one location in + our document model to another. (Consider what would happen if we found a

    tag + and text in the head.) To move content, we throw it onto the misplacedcontent + deque until we can deal with it. + --------------------------------------------------------------------------------- + */ + if(!execSkipContent) { + + switch(theTag) { + case eHTMLTag_html: + case eHTMLTag_comment: + case eHTMLTag_script: + case eHTMLTag_markupDecl: + case eHTMLTag_userdefined: + break; //simply pass these through to token handler without further ado... + + default: + if(!gHTMLElements[eHTMLTag_html].SectionContains(theTag,PR_FALSE)) { + if((!mHadBody) && (!mHadFrameset)){ + + //For bug examples from this code, see bugs: 18928, 20989. + + //At this point we know the body/frameset aren't open. + //If the child belongs in the head, then handle it (which may open the head); + //otherwise, push it onto the misplaced stack. + + PRBool theChildBelongsInHead=gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag); + if(!theChildBelongsInHead) { + + //If you're here then we found a child of the body that was out of place. + //We're going to move it to the body by storing it temporarily on the misplaced stack. + mMisplacedContent.Push(aToken); + aToken->mUseCount++; + return result; + } + + } //if + } //if + }//switch + + } //if + + if(theToken){ + //Before dealing with the token normally, we need to deal with skip targets + if((!execSkipContent) && + (theType!=eToken_end) && + (eHTMLTag_unknown==mSkipTarget) && + (gHTMLElements[theTag].mSkipTarget)){ //create a new target + // Ref: Bug# 19977 + // For optimization, determine if the skipped content is well + // placed. This would avoid unnecessary node creation and + // extra string append. BTW, watch out in handling the head + // children ( especially the TITLE tag). + if(!gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag)) { + eHTMLTags theParentTag = mBodyContext->Last(); + PRBool theParentContains = -1; + if(CanOmit(theParentTag,theTag,theParentContains)) { + result=HandleOmittedTag(theToken,theTag,theParentTag,nsnull); + return result; + } + } + mSkipTarget=gHTMLElements[theTag].mSkipTarget; + mSkippedContent.Push(theToken); + } + else { + + mParser=(nsParser*)aParser; + + switch(theType) { + case eToken_text: + case eToken_start: + case eToken_whitespace: + case eToken_newline: + result=HandleStartToken(theToken); break; + + case eToken_end: + result=HandleEndToken(theToken); break; + + case eToken_cdatasection: + case eToken_comment: + result=HandleCommentToken(theToken); break; + + case eToken_entity: + result=HandleEntityToken(theToken); break; + + case eToken_attribute: + result=HandleAttributeToken(theToken); break; + + case eToken_style: + result=HandleStyleToken(theToken); break; + + case eToken_instruction: + result=HandleProcessingInstructionToken(theToken); break; + + case eToken_doctypeDecl: + result=HandleDocTypeDeclToken(theToken); break; + + default: + break; + }//switch + + + if(NS_SUCCEEDED(result) || (NS_ERROR_HTMLPARSER_BLOCK==result)) { + if(0>=theToken->mUseCount) + mTokenRecycler->RecycleToken(theToken); + } + else if(result==NS_ERROR_HTMLPARSER_STOPPARSING) + mDTDState=result; + else return NS_OK; + + /*************************************************************/ + // CAUTION: Here we are forgetting to push the ATTRIBUTE Tokens. + // So, before you uncomment this part please make sure + // that the attribute tokens are also accounted for. + + //else if(NS_ERROR_HTMLPARSER_MISPLACED!=result) + // mTokenizer->PushTokenFront(theToken); + //else result=NS_OK; + /***************************************************************/ +#if 0 + if (mDTDDebug) { + mDTDDebug->Verify(this, mParser, mBodyContext->GetCount(), mBodyContext->mStack, mFilename); + } +#endif + } + } + + }//if + return result; +} + + +/** + * This gets called after we've handled a given start tag. + * It's a generic hook to let us to post processing. + * @param aToken contains the tag in question + * @param aChildTag is the tag itself. + * @return status + */ +nsresult COtherDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){ + nsresult result=NS_OK; + + switch(aChildTag){ + + case eHTMLTag_pre: + case eHTMLTag_listing: + { + CToken* theNextToken=mTokenizer->PeekToken(); + if(theNextToken) { + eHTMLTokenTypes theType=eHTMLTokenTypes(theNextToken->GetTokenType()); + if(eToken_newline==theType){ + mLineNumber++; + mTokenizer->PopToken(); //skip 1st newline inside PRE and LISTING + }//if + }//if + } + break; + + case eHTMLTag_plaintext: + case eHTMLTag_xmp: + //grab the skipped content and dump it out as text... + { + STOP_TIMER() + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::DidHandleStartTag(), this=%p\n", this)); + const nsString& theString=aNode.GetSkippedContent(); + if(0GetCount()-1;theIndex>=0;theIndex--){ + if(FindTagInSet((*mBodyContext)[theIndex],aTagSet,aCount)) { + return theIndex; + } + } + return kNotFound; +} + +/** + * Call this to find the index of a given child, or (if not found) + * the index of its nearest synonym. + * + * @update gess 3/25/98 + * @param aTagStack -- list of open tags + * @param aTag -- tag to test for containership + * @return index of kNotFound + */ +static +PRInt32 GetIndexOfChildOrSynonym(nsDTDContext& aContext,eHTMLTags aChildTag) { + PRInt32 theChildIndex=aContext.LastOf(aChildTag); + if(kNotFound==theChildIndex) { + TagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close + if(theSynTags) { + theChildIndex=LastOf(aContext,*theSynTags); + } + else{ + PRInt32 theGroup=nsHTMLElement::GetSynonymousGroups(aChildTag); + if(theGroup) { + theChildIndex=aContext.GetCount(); + while(-1<--theChildIndex) { + eHTMLTags theTag=aContext[theChildIndex]; + if(gHTMLElements[theTag].IsMemberOf(theGroup)) { + break; + } + } + } + } + } + return theChildIndex; +} + +/** + * This method is called to determine whether or not the child + * tag is happy being OPENED in the context of the current + * tag stack. This is only called if the current parent thinks + * it wants to contain the given childtag. + * + * @param aChildTag -- tag enum of child to be opened + * @param aTagStack -- ref to current tag stack in DTD. + * @return PR_TRUE if child agrees to be opened here. + */ +static +PRBool CanBeContained(eHTMLTags aChildTag,nsDTDContext& aContext) { + + /* # Interesting test cases: Result: + * 1.