diff --git a/htmlparser/src/CNavDTD.cpp b/htmlparser/src/CNavDTD.cpp index 1e7a1ff8336b..2e6df3916216 100644 --- a/htmlparser/src/CNavDTD.cpp +++ b/htmlparser/src/CNavDTD.cpp @@ -19,7 +19,7 @@ * * Contributor(s): */ - + #include "nsDebug.h" #include "nsIDTDDebug.h" #include "CNavDTD.h" @@ -48,8 +48,9 @@ #endif #include "prmem.h" -#undef ENABLE_RESIDUALSTYLE +//#define ENABLE_RESIDUALSTYLE //#define RICKG_DEBUG +//#define ENABLE_CRC #ifdef RICKG_DEBUG #include #endif @@ -63,11 +64,11 @@ static NS_DEFINE_IID(kClassIID, NS_INAVHTML_DTD_IID); static const char* kNullToken = "Error: Null token given"; static const char* kInvalidTagStackPos = "Error: invalid tag stack position"; static char* kVerificationDir = "c:/temp"; -static CTokenRecycler* gRecycler=0; -#ifdef RICKG_DEBUG -static char gShowCRC=0; -#endif + +#ifdef ENABLE_CRC +static char gShowCRC; +#endif static eHTMLTags gFormElementTags[]= { eHTMLTag_button, eHTMLTag_fieldset, eHTMLTag_input, @@ -75,10 +76,6 @@ static eHTMLTags gFormElementTags[]= { eHTMLTag_option, eHTMLTag_optgroup, eHTMLTag_select, eHTMLTag_textarea}; - -static eHTMLTags gWhitespaceTags[]={ - eHTMLTag_newline, eHTMLTag_whitespace}; - #include "nsElementTable.h" @@ -92,7 +89,6 @@ static eHTMLTags gWhitespaceTags[]={ # define STOP_TIMER() \ if(mParser) MOZ_TIMER_STOP(mParser->mParseTime); \ if(mParser) MOZ_TIMER_STOP(mParser->mDTDTime); - #else # define STOP_TIMER() # define START_TIMER() @@ -223,11 +219,9 @@ nsresult CNavDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr) return NS_OK; } - NS_IMPL_ADDREF(CNavDTD) NS_IMPL_RELEASE(CNavDTD) - /** * Default constructor * @@ -235,7 +229,7 @@ NS_IMPL_RELEASE(CNavDTD) * @param * @return */ -CNavDTD::CNavDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSharedNodes(0) { +CNavDTD::CNavDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mSharedNodes(0), mScratch("") { NS_INIT_REFCNT(); mSink = 0; mParser=0; @@ -249,6 +243,7 @@ CNavDTD::CNavDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mShared mBodyContext=new nsDTDContext(); mFormContext=0; mMapContext=0; + mTempContext=0; mTokenizer=0; mComputedCRC32=0; mExpectedCRC32=0; @@ -265,32 +260,64 @@ CNavDTD::CNavDTD() : nsIDTD(), mMisplacedContent(0), mSkippedContent(0), mShared 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* CNavDTD::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())){ - gRecycler->RecycleToken(theToken); + if(!theToken->mUseCount) { + mTokenRecycler->RecycleToken(theToken); + } } mSharedNodes.Push(aNode); } } + /** * * @update gess1/8/99 @@ -311,12 +338,34 @@ const nsIID& CNavDTD::GetMostDerivedIID(void)const { CNavDTD::~CNavDTD(){ delete mHeadContext; delete mBodyContext; + if(mTokenizer) delete (nsHTMLTokenizer*)mTokenizer; + + if(mTempContext) + delete mTempContext; + nsCParserNode* theNode=0; + +#ifdef NS_DEBUG +#if 1 + 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); } @@ -376,17 +425,20 @@ 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(PR_TRUE==aContentType.Equals(kHTMLTextContentType)) { result=ePrimaryDetect; } else { //otherwise, look into the buffer to see if you recognize anything... - if(BufferContainsHTML(aBuffer)){ - result=ePrimaryDetect; - if(0==aContentType.Length()) + PRBool theBufHasXML=PR_FALSE; + if(BufferContainsHTML(aBuffer,theBufHasXML)){ + result = eValidDetect ; + if(0==aContentType.Length()) { aContentType=kHTMLTextContentType; + result = (theBufHasXML) ? eValidDetect : ePrimaryDetect; + } } } } @@ -400,7 +452,9 @@ eAutoDetectResult CNavDTD::CanParse(nsString& aContentType, nsString& aCommand, * @param * @return */ -nsresult CNavDTD::WillBuildModel(nsString& aFilename,PRBool aNotifySink,nsString& aSourceType,eParseMode aParseMode,nsIContentSink* aSink){ +nsresult CNavDTD::WillBuildModel(nsString& aFilename, + PRBool aNotifySink,nsString& aSourceType,eParseMode aParseMode, + nsString& aCommand,nsIContentSink* aSink){ nsresult result=NS_OK; mFilename=aFilename; @@ -412,8 +466,11 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename,PRBool aNotifySink,nsString mParseMode=aParseMode; if((aNotifySink) && (aSink)) { - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this)); + STOP_TIMER(); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this)); + + mTokenRecycler=0; if(aSink && (!mSink)) { result=aSink->QueryInterface(kIHTMLContentSinkIID, (void **)&mSink); @@ -423,10 +480,6 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename,PRBool aNotifySink,nsString MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this)); START_TIMER(); - nsAutoString theTagName("html"); - CStartToken theToken(theTagName,eHTMLTag_html); - HandleStartToken(&theToken); - mSkipTarget=eHTMLTag_unknown; mComputedCRC32=0; mExpectedCRC32=0; @@ -446,28 +499,40 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename,PRBool aNotifySink,nsString */ nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITokenObserver* anObserver,nsIContentSink* aSink) { nsresult result=NS_OK; - + if(aTokenizer) { nsITokenizer* oldTokenizer=mTokenizer; mTokenizer=aTokenizer; mParser=(nsParser*)aParser; - if(mSink) { - gRecycler=(CTokenRecycler*)mTokenizer->GetTokenRecycler(); - while(NS_SUCCEEDED(result)){ - if(mDTDState!=NS_ERROR_HTMLPARSER_STOPPARSING) { - CToken* theToken=mTokenizer->PopToken(); - if(theToken) { - result=HandleToken(theToken,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); + HandleStartToken(theToken); //this token should get pushed on the context stack, don't recycle it. + } + + while(NS_SUCCEEDED(result)){ + if(mDTDState!=NS_ERROR_HTMLPARSER_STOPPARSING) { + CToken* theToken=mTokenizer->PopToken(); + if(theToken) { + result=HandleToken(theToken,aParser); + } + else break; } - else break; - } - else { - result=mDTDState; - break; - } - }//while - mTokenizer=oldTokenizer; + else { + result=mDTDState; + break; + } + }//while + mTokenizer=oldTokenizer; + } } } else result=NS_ERROR_HTMLPARSER_BADTOKENIZER; @@ -485,34 +550,35 @@ nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParse if(aSink) { if((NS_OK==anErrorCode) && (!mHadBody) && (!mHadFrameset)) { - CStartToken theToken(eHTMLTag_body); //open the body container... - result=HandleStartToken(&theToken); + + CStartToken *theToken=(CStartToken*)mTokenRecycler->CreateTokenOfType(eToken_start,eHTMLTag_body); + mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack, don't recycle it mTokenizer->PrependTokens(mMisplacedContent); //push misplaced content - result=BuildModel(aParser,mTokenizer,0,aSink); + result=BuildModel(aParser,mTokenizer,0,aSink); } - if(aParser){ + if(aParser && (NS_OK==result)){ if(aNotifySink){ if((NS_OK==anErrorCode) && (mBodyContext->GetCount()>0)) { if(mSkipTarget) { CHTMLToken* theEndToken=nsnull; - theEndToken=(CHTMLToken*)gRecycler->CreateTokenOfType(eToken_end,mSkipTarget); - if(theEndToken) result=HandleToken(theEndToken,mParser); + theEndToken=(CHTMLToken*)mTokenRecycler->CreateTokenOfType(eToken_end,mSkipTarget); + if(theEndToken) { + result=HandleToken(theEndToken,mParser); + } } if(result==NS_OK) { eHTMLTags theTarget; while(mBodyContext->GetCount() > 0) { theTarget = mBodyContext->Last(); - if(gHTMLElements[theTarget].HasSpecialProperty(kBadContentWatch)) - result = HandleSavedTokensAbove(theTarget); CloseContainersTo(theTarget,PR_FALSE); } } } - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::DidBuildModel(), this=%p\n", this)); STOP_TIMER(); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::DidBuildModel(), this=%p\n", this)); -#ifdef RICKG_DEBUG +#ifdef ENABLE_CRC //let's only grab this state once! if(!gShowCRC) { @@ -574,7 +640,7 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ eHTMLTags theTag=(eHTMLTags)theToken->GetTypeID(); PRBool execSkipContent=PR_FALSE; - theToken->mRecycle=PR_TRUE; //assume every token coming into this system needs recycling. + 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. @@ -583,15 +649,17 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ 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; - gRecycler->RecycleToken(aToken); + mTokenRecycler->RecycleToken(aToken); theToken=(CHTMLToken*)mSkippedContent.PopFront(); theType=eToken_start; - // result=HandleStartToken(theToken); } else { mSkippedContent.Push(theToken); @@ -607,10 +675,13 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ --------------------------------------------------------------------------------- */ if(!execSkipContent) { + static eHTMLTags passThru[]= { eHTMLTag_html,eHTMLTag_comment,eHTMLTag_newline, eHTMLTag_whitespace,eHTMLTag_script,eHTMLTag_noscript, - eHTMLTag_nolayer,eHTMLTag_markupDecl,eHTMLTag_userdefined}; + eHTMLTag_nolayer,eHTMLTag_markupDecl,eHTMLTag_userdefined + }; + if(!FindTagInSet(theTag,passThru,sizeof(passThru)/sizeof(eHTMLTag_unknown))){ if(!gHTMLElements[eHTMLTag_html].SectionContains(theTag,PR_FALSE)) { if((!mHadBody) && (!mHadFrameset)){ @@ -618,7 +689,7 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ //just fall through and handle current token if(!gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag)){ mMisplacedContent.Push(aToken); - aToken->mRecycle=PR_FALSE; + aToken->mUseCount++; return result; } } @@ -626,15 +697,15 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ if(gHTMLElements[eHTMLTag_body].SectionContains(theTag,PR_TRUE)){ mTokenizer->PushTokenFront(aToken); //put this token back... mTokenizer->PrependTokens(mMisplacedContent); //push misplaced content - theToken=(CHTMLToken*)gRecycler->CreateTokenOfType(eToken_start,theTag=eHTMLTag_body); + theToken=(CHTMLToken*)mTokenRecycler->CreateTokenOfType(eToken_start,theTag=eHTMLTag_body); theType=eToken_start; //now open a body... } } } - } - } - } + } //if + } //if + } //if if(theToken){ //Before dealing with the token normally, we need to deal with skip targets @@ -650,10 +721,10 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ mParser=(nsParser*)aParser; switch(theType) { + case eToken_text: case eToken_start: case eToken_whitespace: case eToken_newline: - case eToken_text: result=HandleStartToken(theToken); break; case eToken_end: result=HandleEndToken(theToken); break; @@ -675,11 +746,11 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ if(NS_SUCCEEDED(result) || (NS_ERROR_HTMLPARSER_BLOCK==result)) { - if(theToken->mRecycle) - gRecycler->RecycleToken(theToken); + if(0>=theToken->mUseCount) + mTokenRecycler->RecycleToken(theToken); } else if(result==NS_ERROR_HTMLPARSER_STOPPARSING) - return result; + mDTDState=result; else return NS_OK; /*************************************************************/ @@ -746,6 +817,7 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){ if(theNextToken) { eHTMLTokenTypes theType=eHTMLTokenTypes(theNextToken->GetTokenType()); if(eToken_newline==theType){ + mLineNumber++; mTokenizer->PopToken(); //skip 1st newline inside PRE and LISTING }//if }//if @@ -756,8 +828,8 @@ nsresult CNavDTD::DidHandleStartTag(nsCParserNode& aNode,eHTMLTags aChildTag){ case eHTMLTag_xmp: //grab the skipped content and dump it out as text... { - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::DidHandleStartTag(), this=%p\n", this)); STOP_TIMER() + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::DidHandleStartTag(), this=%p\n", this)); const nsString& theText=aNode.GetSkippedContent(); if(0=0;i--){ - if(aTagStack[i]==aTag) - return i; - } - return kNotFound; -} -#endif /** * Call this to find the index of a given child, or (if not found) @@ -803,23 +856,22 @@ PRInt32 GetTopmostIndexOf(eHTMLTags aTag,nsEntryStack& aTagStack) { * @return index of kNotFound */ static -PRInt32 GetIndexOfChildOrSynonym(nsEntryStack& aTagStack,eHTMLTags aChildTag) { - PRInt32 theChildIndex=aTagStack.GetTopmostIndexOf(aChildTag); +PRInt32 GetIndexOfChildOrSynonym(nsDTDContext& aContext,eHTMLTags aChildTag) { + PRInt32 theChildIndex=aContext.GetTopmostIndexOf(aChildTag); if(kNotFound==theChildIndex) { TagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close if(theSynTags) { - theChildIndex=GetTopmostIndexOf(aTagStack,*theSynTags); + theChildIndex=GetTopmostIndexOf(aContext,*theSynTags); } else{ - theChildIndex=aTagStack.GetCount(); - PRInt32 theGroup=nsHTMLElement::GetSynonymousGroups(gHTMLElements[aChildTag].mParentBits); + theChildIndex=aContext.GetCount(); + PRInt32 theGroup=nsHTMLElement::GetSynonymousGroups(aChildTag); while(-1<--theChildIndex) { - eHTMLTags theTag=aTagStack[theChildIndex]; + eHTMLTags theTag=aContext[theChildIndex]; if(gHTMLElements[theTag].IsMemberOf(theGroup)) { break; } } - } } return theChildIndex; @@ -836,7 +888,7 @@ PRInt32 GetIndexOfChildOrSynonym(nsEntryStack& aTagStack,eHTMLTags aChildTag) { * @return PR_TRUE if child agrees to be opened here. */ static -PRBool CanBeContained(eHTMLTags aChildTag,nsEntryStack& aTagStack) { +PRBool CanBeContained(eHTMLTags aChildTag,nsDTDContext& aContext) { /* # Interesting test cases: Result: * 1.
  • ....
  • inner
  • closes outer
  • @@ -849,13 +901,13 @@ PRBool CanBeContained(eHTMLTags aChildTag,nsEntryStack& aTagStack) { // therefore we must get residual style handling to work. PRBool result=PR_TRUE; - if(aTagStack.GetCount()){ + if(aContext.GetCount()){ TagList* theRootTags=gHTMLElements[aChildTag].GetRootTags(); TagList* theSpecialParents=gHTMLElements[aChildTag].GetSpecialParents(); if(theRootTags) { - PRInt32 theRootIndex=GetTopmostIndexOf(aTagStack,*theRootTags); - PRInt32 theSPIndex=(theSpecialParents) ? GetTopmostIndexOf(aTagStack,*theSpecialParents) : kNotFound; - PRInt32 theChildIndex=GetIndexOfChildOrSynonym(aTagStack,aChildTag); + PRInt32 theRootIndex=GetTopmostIndexOf(aContext,*theRootTags); + PRInt32 theSPIndex=(theSpecialParents) ? GetTopmostIndexOf(aContext,*theSpecialParents) : kNotFound; + PRInt32 theChildIndex=GetIndexOfChildOrSynonym(aContext,aChildTag); PRInt32 theBaseIndex=(theRootIndex>theSPIndex) ? theRootIndex : theSPIndex; if((theBaseIndex==theChildIndex) && (gHTMLElements[aChildTag].CanContainSelf())) @@ -869,38 +921,6 @@ PRBool CanBeContained(eHTMLTags aChildTag,nsEntryStack& aTagStack) { enum eProcessRule {eIgnore,eTest}; -eProcessRule GetProcessRule(eHTMLTags aParentTag,eHTMLTags aChildTag){ - int mParentGroup=gHTMLElements[aParentTag].mParentBits; - int mChildGroup=gHTMLElements[aChildTag].mParentBits; - - eProcessRule result=eTest; - - switch(mParentGroup){ - case kSpecial: - case kPhrase: - case kFontStyle: - case kFormControl: - switch(mChildGroup){ - case kBlock: - case kHTMLContent: - case kExtensions: - //case kFlowEntity: - case kList: - case kBlockEntity: - case kHeading: - case kHeadMisc: - case kPreformatted: - case kNone: - result=eIgnore; - } - break; - - default: - break; - } - return result; -} - /** * This method gets called when a start token has been * encountered in the parse process. If the current container @@ -915,29 +935,31 @@ eProcessRule GetProcessRule(eHTMLTags aParentTag,eHTMLTags aChildTag){ * @param aNode -- CParserNode representing this start token * @return PR_TRUE if all went well; PR_FALSE if error occured */ -nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode) { +nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsIParserNode *aNode) { NS_PRECONDITION(0!=aToken,kNullToken); nsresult result=NS_OK; - PRBool theCanContainResult=PR_FALSE; PRBool theChildAgrees=PR_TRUE; PRInt32 theIndex=mBodyContext->GetCount(); + PRBool theChildIsContainer=nsHTMLElement::IsContainer(aChildTag); + PRBool theParentContains=-1; do { eHTMLTags theParentTag=mBodyContext->TagAt(--theIndex); - if(CanOmit(theParentTag,aChildTag)) { + theParentContains=CanContain(theParentTag,aChildTag); //precompute containment, and pass it to CanOmit()... + + if(CanOmit(theParentTag,aChildTag,theParentContains)) { result=HandleOmittedTag(aToken,aChildTag,theParentTag,aNode); return result; } - eProcessRule theRule=eTest; //GetProcessRule(theParentTag,aChildTag); + eProcessRule theRule=eTest; switch(theRule){ - case eTest: - theCanContainResult=CanContain(theParentTag,aChildTag); + case eTest: theChildAgrees=PR_TRUE; - if(theCanContainResult) { + if(theParentContains) { eHTMLTags theAncestor=gHTMLElements[aChildTag].mExcludingAncestor; if(eHTMLTag_unknown!=theAncestor){ @@ -956,14 +978,14 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI //this instance and a prior one on the stack. I had to add this because //(for now) DT is inline, and fontstyle's can contain them (until Res-style code works) if(gHTMLElements[aChildTag].HasSpecialProperty(kMustCloseSelf)){ - theChildAgrees=CanBeContained(aChildTag,mBodyContext->mStack); + theChildAgrees=CanBeContained(aChildTag,*mBodyContext); } } } - if(!(theCanContainResult && theChildAgrees)) { - if (!CanPropagate(theParentTag,aChildTag)) { - if(nsHTMLElement::IsContainer(aChildTag)){ + if(!(theParentContains && theChildAgrees)) { + if (!CanPropagate(theParentTag,aChildTag,theParentContains)) { + if(theChildIsContainer || (!theParentContains)){ if(!gHTMLElements[aChildTag].CanAutoCloseTag(theParentTag)) { // Closing the tags above might cause non-compatible results. // Ex. Text
    . @@ -988,11 +1010,10 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI break; }//switch - } while(!(theCanContainResult && theChildAgrees)); + } while(!(theParentContains && theChildAgrees)); - - if(nsHTMLElement::IsContainer(aChildTag)){ - result=OpenContainer(aNode,PR_TRUE); + if(theChildIsContainer){ + result=OpenContainer(aNode,aChildTag,PR_TRUE); } else { //we're writing a leaf... result=AddLeaf(aNode); @@ -1028,20 +1049,16 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode result=CollectSkippedContent(aNode,theAttrCount); } - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this)); STOP_TIMER() + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this)); if(mParser) { - nsAutoString charsetValue; - nsCharsetSource charsetSource; CObserverService& theService=mParser->GetObserverService(); CParserContext* pc=mParser->PeekContext(); void* theDocID=(pc)? pc->mKey:0; - mParser->GetDocumentCharset(charsetValue,charsetSource); - result=theService.Notify(aTag,aNode,(PRUint32)theDocID,kHTMLTextContentType, - charsetValue,charsetSource); + result=theService.Notify(aTag,aNode,(PRUint32)theDocID,kHTMLTextContentType,mParser); } MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this)); @@ -1049,7 +1066,7 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode if(NS_SUCCEEDED(result)) { -#ifdef RICKG_DEBUG +#ifdef ENABLE_CRC STOP_TIMER() @@ -1077,7 +1094,6 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode #endif - if(NS_OK==result) { result=gHTMLElements[aTag].HasSpecialProperty(kDiscardTag) ? 1 : NS_OK; } @@ -1091,9 +1107,11 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode static eHTMLTags skip2[]={eHTMLTag_newline,eHTMLTag_whitespace}; if(!FindTagInSet(aTag,skip2,sizeof(skip2)/sizeof(eHTMLTag_unknown))){ if(!isHeadChild){ + + //because this code calls CloseHead() directly, stack-based token/nodes are ok. CEndToken theToken(eHTMLTag_head); nsCParserNode theNode(&theToken,mLineNumber); - result=CloseHead(theNode); + result=CloseHead(&theNode); } } } @@ -1102,6 +1120,23 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode return result; } +void PushMisplacedAttributes(nsIParserNode& aNode,nsDeque& aDeque,PRInt32 aCount) { + if(aCount > 0) { + CToken* theAttrToken=nsnull; + nsCParserNode* theAttrNode = (nsCParserNode*)&aNode; + if(theAttrNode) { + while(aCount){ + theAttrToken=theAttrNode->PopAttributeToken(); + if(theAttrToken) { + aDeque.Push(theAttrToken); + theAttrToken->mUseCount=0; + } + aCount--; + }//while + }//if + }//if +} + /** * This method gets called when a start token has been encountered that the parent * wants to omit. @@ -1113,7 +1148,7 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsCParserNode * @param aNode -- CParserNode representing this start token * @return PR_TRUE if all went well; PR_FALSE if error occured */ -nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags aParent,nsIParserNode& aNode) { +nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags aParent,nsIParserNode* aNode) { NS_PRECONDITION(mBodyContext != nsnull,"need a context to work with"); nsresult result=NS_OK; @@ -1123,7 +1158,7 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags //of another section. If it is, the cache it for later. // 1. Get the root node for the child. See if the ultimate node is the BODY, FRAMESET, HEAD or HTML PRInt32 theTagCount = mBodyContext->GetCount(); - CToken* theToken = &*aToken; + CToken* theToken = aToken; if(aToken) { PRInt32 attrCount = aToken->GetAttributeCount(); @@ -1140,54 +1175,44 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags break; } } + PRBool done=PR_FALSE; if(theIndex>kNotFound) { while(!done){ - theToken->mRecycle=PR_FALSE; - mBodyContext->SaveToken(theToken,theIndex); + mMisplacedContent.Push(theToken); + theToken->mUseCount++; + // If the token is attributed then save those attributes too. - // NOTE: This might happen only on the first entry into the loop. - if(attrCount > 0) { - nsCParserNode* theAttrNode = (nsCParserNode*)&aNode; - while(attrCount > 0){ - CToken* theAttrToken=theAttrNode->PopAttributeToken(); - if(theAttrToken) { - mBodyContext->SaveToken(theAttrToken,theIndex); - theAttrToken->mRecycle=PR_FALSE; - } - attrCount--; - } - } + if(attrCount > 0) PushMisplacedAttributes(*aNode,mMisplacedContent,attrCount); + theToken=mTokenizer->PeekToken(); + PRBool theParentContains=-1; //set to -1 so that CanCmit will recompute. + if(theToken) { + theToken->mUseCount=0; theTag=(eHTMLTags)theToken->GetTypeID(); - if((gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) || - (!CanOmit(aParent,theTag))) done=PR_TRUE; - else if((!gHTMLElements[mBodyContext->TagAt(theIndex)].CanContain(theTag)) && - (theTag !=eHTMLTag_unknown)) done=PR_TRUE; - else theToken=mTokenizer->PopToken(); + if(!nsHTMLElement::IsWhitespaceTag(theTag) && theTag!=eHTMLTag_unknown) { + if((gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) || + (!gHTMLElements[mBodyContext->TagAt(theIndex)].CanContain(theTag))|| + (!CanOmit(aParent,theTag,theParentContains))) { + done=PR_TRUE; + } + } + if(!done) theToken=mTokenizer->PopToken(); } else done=PR_TRUE; + }//while + if(result==NS_OK) { + result=HandleSavedTokens(theIndex); } - } - } + }//if + }//if if((aChildTag!=aParent) && (gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced))) { mMisplacedContent.Push(aToken); - aToken->mRecycle=PR_FALSE; - + aToken->mUseCount++; // If the token is attributed then save those attributes too. - if(attrCount > 0) { - nsCParserNode* theAttrNode = (nsCParserNode*)&aNode; - while(attrCount > 0){ - CToken* theAttrToken=theAttrNode->PopAttributeToken(); - if(theAttrToken){ - mMisplacedContent.Push(theAttrToken); - theAttrToken->mRecycle=PR_FALSE; - } - attrCount--; - } - } + if(attrCount > 0) PushMisplacedAttributes(*aNode,mMisplacedContent,attrCount); } } return result; @@ -1210,6 +1235,7 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags nsresult CNavDTD::HandleStartToken(CToken* aToken) { NS_PRECONDITION(0!=aToken,kNullToken); + #ifdef RICKG_DEBUG WriteTokenToLog(aToken); #endif @@ -1217,33 +1243,31 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) { //Begin by gathering up attributes... nsCParserNode* theNode=CreateNode(); - theNode->Init(aToken,mLineNumber,GetTokenRecycler()); + theNode->Init(aToken,mLineNumber,mTokenRecycler); eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID(); PRInt16 attrCount=aToken->GetAttributeCount(); - nsresult result=(0==attrCount) ? NS_OK : CollectAttributes(*theNode,theChildTag,attrCount); eHTMLTags theParent=mBodyContext->Last(); + nsresult result=(0==attrCount) ? NS_OK : CollectAttributes(*theNode,theChildTag,attrCount); if(NS_OK==result) { result=WillHandleStartTag(aToken,theChildTag,*theNode); if(NS_OK==result) { + PRBool isTokenHandled =PR_FALSE; + PRBool theHeadIsParent=PR_FALSE; if(nsHTMLElement::IsSectionTag(theChildTag)){ switch(theChildTag){ case eHTMLTag_body: if(mHasOpenBody) { - result=OpenContainer(*theNode,PR_FALSE); - RecycleNode(theNode); - return result; + result=OpenContainer(theNode,theChildTag,PR_FALSE); + isTokenHandled=PR_TRUE; } break; case eHTMLTag_head: if(mHadBody || mHadFrameset) { - result=HandleOmittedTag(aToken,theChildTag,theParent,*theNode); - if(result == NS_OK) { - RecycleNode(theNode); - return result; - } + result=HandleOmittedTag(aToken,theChildTag,theParent,theNode); + isTokenHandled=PR_TRUE; } break; default: @@ -1251,56 +1275,56 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) { } } - PRBool theHeadIsParent=nsHTMLElement::IsChildOfHead(theChildTag); + mLineNumber += aToken->mNewlineCount; + theHeadIsParent=nsHTMLElement::IsChildOfHead(theChildTag); + switch(theChildTag) { + case eHTMLTag_newline: + mLineNumber++; + break; case eHTMLTag_area: + if(!mHasOpenMap) isTokenHandled=PR_TRUE; - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleStartToken(), this=%p\n", this)); STOP_TIMER(); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleStartToken(), this=%p\n", this)); if (mHasOpenMap && mSink) result=mSink->AddLeaf(*theNode); MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleStartToken(), this=%p\n", this)); START_TIMER(); - break; case eHTMLTag_image: aToken->SetTypeID(theChildTag=eHTMLTag_img); - result=HandleDefaultStartToken(aToken,theChildTag,*theNode); break; case eHTMLTag_userdefined: + isTokenHandled=PR_TRUE; break; case eHTMLTag_script: - theHeadIsParent=(!mHasOpenBody); //intentionally fall through... + theHeadIsParent=(!mHasOpenBody); mHasOpenScript=PR_TRUE; default: - { - if(theHeadIsParent || - (mHasOpenHead && ((eHTMLTag_newline==theChildTag) || (eHTMLTag_whitespace==theChildTag)))) { - result=AddHeadLeaf(*theNode); - } - else result=HandleDefaultStartToken(aToken,theChildTag,*theNode); - } - break; - } //switch + break; + }//switch + + if(!isTokenHandled) { + if(theHeadIsParent || + (mHasOpenHead && ((eHTMLTag_newline==theChildTag) || (eHTMLTag_whitespace==theChildTag)))) { + result=AddHeadLeaf(theNode); + } + else result=HandleDefaultStartToken(aToken,theChildTag,theNode); + } //now do any post processing necessary on the tag... if(NS_OK==result) DidHandleStartTag(*theNode,theChildTag); - } + }//if } //if - if(eHTMLTag_newline==theChildTag) { - // Don't count the newline if the token has not been used. - if(aToken->mRecycle) - mLineNumber++; - } - RecycleNode(theNode); return result; } @@ -1315,17 +1339,17 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) { * @return PR_TRUE if given tag can contain other tags */ static -PRBool HasCloseablePeerAboveRoot(TagList& aRootTagList,nsEntryStack& aTagStack,eHTMLTags aTag,PRBool anEndTag) { - PRInt32 theRootIndex=GetTopmostIndexOf(aTagStack,aRootTagList); - TagList* theCloseTags=(anEndTag) ? gHTMLElements[aTag].GetAutoCloseEndTags() : gHTMLElements[aTag].GetAutoCloseStartTags(); +PRBool HasCloseablePeerAboveRoot(TagList& aRootTagList,nsDTDContext& aContext,eHTMLTags aTag,PRBool anEndTag) { + PRInt32 theRootIndex=GetTopmostIndexOf(aContext,aRootTagList); + TagList* theCloseTags=(anEndTag) ? gHTMLElements[aTag].GetAutoCloseEndTags() : gHTMLElements[aTag].GetAutoCloseStartTags(); PRInt32 theChildIndex=-1; if(theCloseTags) { - theChildIndex=GetTopmostIndexOf(aTagStack,*theCloseTags); + theChildIndex=GetTopmostIndexOf(aContext,*theCloseTags); } else { if((anEndTag) || (!gHTMLElements[aTag].CanContainSelf())) - theChildIndex=aTagStack.GetTopmostIndexOf(aTag); + theChildIndex=aContext.GetTopmostIndexOf(aTag); } // I changed this to theRootIndex<=theChildIndex so to handle this case: //