diff --git a/htmlparser/src/CNavDTD.cpp b/htmlparser/src/CNavDTD.cpp index 5689727bb709..f4fddf881d0a 100644 --- a/htmlparser/src/CNavDTD.cpp +++ b/htmlparser/src/CNavDTD.cpp @@ -1,30 +1,30 @@ /* -*- 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.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ - * + * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. - * + * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. - */ - -#include "nsDebug.h" -#include "nsIDTDDebug.h" + */ + +#include "nsDebug.h" +#include "nsIDTDDebug.h" #include "CNavDTD.h" #include "nsHTMLTokens.h" #include "nsCRT.h" #include "nsParser.h" +#include "nsIParser.h" #include "nsIHTMLContentSink.h" #include "nsScanner.h" -#include "nsParserTypes.h" #include "nsVoidArray.h" #include "nsTokenHandler.h" #include "nsIDTDDebug.h" @@ -35,6 +35,7 @@ #include "nsDTDUtils.h" #include "nsTagHandler.h" #include "nsViewSourceHTML.h" +#include "nsHTMLTokenizer.h" #ifdef XP_PC #include //this is here for debug reasons... @@ -45,7 +46,7 @@ static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kIDTDIID, NS_IDTD_IID); static NS_DEFINE_IID(kClassIID, NS_INAVHTML_DTD_IID); - + //static const char* kNullURL = "Error: Null URL given"; //static const char* kNullFilename= "Error: Null filename given"; static const char* kNullToken = "Error: Null token given"; @@ -53,7 +54,7 @@ static const char* kInvalidTagStackPos = "Error: invalid tag stack position"; static const char* kHTMLTextContentType = "text/html"; static char* kVerificationDir = "c:/temp"; static const char* kViewSourceCommand= "view-source"; - + static nsAutoString gEmpty; static eHTMLTags gFormElementTags[]= { @@ -66,6 +67,7 @@ static eHTMLTags gHeadingTags[]={ eHTMLTag_h1, eHTMLTag_h2, eHTMLTag_h3, eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6}; + static eHTMLTags gStyleTags[]={ eHTMLTag_a, eHTMLTag_acronym, eHTMLTag_b, eHTMLTag_bdo, eHTMLTag_big, eHTMLTag_blink, @@ -78,210 +80,23 @@ static eHTMLTags gStyleTags[]={ eHTMLTag_sub, eHTMLTag_sup, eHTMLTag_tt, eHTMLTag_u, eHTMLTag_var}; -static eHTMLTags gNonContainers[]={ - eHTMLTag_area, eHTMLTag_base, eHTMLTag_basefont, - eHTMLTag_bgsound, eHTMLTag_br, eHTMLTag_col, - eHTMLTag_embed, eHTMLTag_frame, eHTMLTag_img, - eHTMLTag_keygen, eHTMLTag_hr, eHTMLTag_input, - eHTMLTag_link, eHTMLTag_isindex, - eHTMLTag_meta, eHTMLTag_param, eHTMLTag_plaintext, - eHTMLTag_sound, eHTMLTag_style, eHTMLTag_spacer, - eHTMLTag_wbr, - eHTMLTag_newline, eHTMLTag_text, eHTMLTag_whitespace, - eHTMLTag_unknown, eHTMLTag_xmp}; -static eHTMLTags gTableTags[]={ +static eHTMLTags gTableChildTags[]={ eHTMLTag_caption, eHTMLTag_col, eHTMLTag_colgroup, eHTMLTag_tbody, eHTMLTag_tfoot, eHTMLTag_tr, eHTMLTag_thead, eHTMLTag_td}; static eHTMLTags gWhitespaceTags[]={ eHTMLTag_newline, eHTMLTag_whitespace}; +static eHTMLTags gHeadChildTags[]={ + eHTMLTag_caption, eHTMLTag_col, eHTMLTag_colgroup, eHTMLTag_tbody, + eHTMLTag_tfoot, eHTMLTag_tr, eHTMLTag_thead, eHTMLTag_td}; -static eHTMLTags gBlockParentTags []={ - eHTMLTag_applet, eHTMLTag_basefont, eHTMLTag_blockquote, - eHTMLTag_body, eHTMLTag_center, eHTMLTag_dd, - eHTMLTag_div, eHTMLTag_embed, eHTMLTag_fieldset, - eHTMLTag_form, eHTMLTag_iframe, eHTMLTag_layer, - eHTMLTag_li, eHTMLTag_listing, eHTMLTag_multicol, - eHTMLTag_noembed, eHTMLTag_noframes, eHTMLTag_nolayer, - eHTMLTag_noscript, eHTMLTag_object, eHTMLTag_plaintext, - eHTMLTag_pre, eHTMLTag_td, eHTMLTag_th, - eHTMLTag_ul, - eHTMLTag_xmp, -}; - -static eHTMLTags gBlockChildTags []={ - eHTMLTag_a, eHTMLTag_abbr, eHTMLTag_acronym, eHTMLTag_address, eHTMLTag_applet, - eHTMLTag_b, eHTMLTag_basefont, eHTMLTag_bdo, eHTMLTag_bgsound, eHTMLTag_big, - eHTMLTag_blink, eHTMLTag_blockquote, eHTMLTag_br, eHTMLTag_button, - eHTMLTag_center, eHTMLTag_cite, eHTMLTag_code, - eHTMLTag_del, eHTMLTag_dfn, eHTMLTag_dir, eHTMLTag_div, eHTMLTag_dl, - eHTMLTag_em, eHTMLTag_embed, - eHTMLTag_fieldset, eHTMLTag_font, eHTMLTag_form, - eHTMLTag_h1, eHTMLTag_h2, eHTMLTag_h3, - eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6, - eHTMLTag_hr, - - eHTMLTag_i, eHTMLTag_iframe, eHTMLTag_ilayer, eHTMLTag_img, - eHTMLTag_ins, eHTMLTag_isindex, eHTMLTag_input, - - eHTMLTag_kbd, - - eHTMLTag_label, eHTMLTag_layer, eHTMLTag_listing, - - eHTMLTag_map, /*eHTMLTag_marque,*/ eHTMLTag_menu, eHTMLTag_multicol, - eHTMLTag_nobr, eHTMLTag_noembed, eHTMLTag_noframes, eHTMLTag_nolayer, eHTMLTag_noscript, - - eHTMLTag_object, eHTMLTag_ol, - eHTMLTag_p, eHTMLTag_plaintext, eHTMLTag_pre, - eHTMLTag_q, - eHTMLTag_s, eHTMLTag_samp, eHTMLTag_script, eHTMLTag_select, eHTMLTag_small, - eHTMLTag_sound, eHTMLTag_spacer, eHTMLTag_span, eHTMLTag_strike, eHTMLTag_strong, - eHTMLTag_sub, eHTMLTag_sup, - - eHTMLTag_table, eHTMLTag_textarea, eHTMLTag_tt, - eHTMLTag_u, eHTMLTag_ul, eHTMLTag_userdefined, - eHTMLTag_var, eHTMLTag_wbr, eHTMLTag_xmp, - - //a few special cases... - eHTMLTag_newline, - eHTMLTag_whitespace, +static eHTMLTags gNonPropagatedTags[]={ + eHTMLTag_head, eHTMLTag_html, eHTMLTag_body}; -}; - -static eHTMLTags gInlineParentTags []={ - eHTMLTag_a, eHTMLTag_abbr, eHTMLTag_address, - eHTMLTag_b, eHTMLTag_bdo, eHTMLTag_big, - eHTMLTag_blink, eHTMLTag_button, eHTMLTag_caption, - eHTMLTag_cite, eHTMLTag_code, eHTMLTag_dfn, - eHTMLTag_dt, eHTMLTag_em, eHTMLTag_font, - eHTMLTag_h1, eHTMLTag_h2, eHTMLTag_h3, - eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6, - eHTMLTag_i, eHTMLTag_ilayer, eHTMLTag_kbd, - eHTMLTag_label, eHTMLTag_legend, /*eHTMLTag_marquee,*/ - eHTMLTag_nobr, eHTMLTag_ol, eHTMLTag_p, - eHTMLTag_q, - eHTMLTag_s, eHTMLTag_samp, eHTMLTag_small, - eHTMLTag_span, eHTMLTag_strike, eHTMLTag_strong, - eHTMLTag_sub, eHTMLTag_sup, - eHTMLTag_td, eHTMLTag_th, eHTMLTag_tt, - eHTMLTag_u, eHTMLTag_ul, eHTMLTag_var -}; - -static eHTMLTags gInlineChildTags []={ - eHTMLTag_a, eHTMLTag_abbr, eHTMLTag_acronym, eHTMLTag_applet, - eHTMLTag_b, eHTMLTag_bdo, eHTMLTag_bgsound, eHTMLTag_big, eHTMLTag_blink, - eHTMLTag_br, eHTMLTag_button, - - eHTMLTag_cite, eHTMLTag_code, - eHTMLTag_dfn, - eHTMLTag_em, eHTMLTag_embed, - eHTMLTag_font, - - eHTMLTag_form, //Added this for backward compatibility... - - eHTMLTag_i, eHTMLTag_iframe, eHTMLTag_ilayer, eHTMLTag_img, eHTMLTag_input, - eHTMLTag_kbd, - eHTMLTag_label, - - eHTMLTag_layer, //Added this for backward compatibility... - - - eHTMLTag_li, - eHTMLTag_map, - eHTMLTag_nobr, - eHTMLTag_object, - eHTMLTag_p, - eHTMLTag_pre, - eHTMLTag_q, - eHTMLTag_s, eHTMLTag_samp, eHTMLTag_script, eHTMLTag_select, eHTMLTag_small, - eHTMLTag_sound, eHTMLTag_spacer, eHTMLTag_span, eHTMLTag_strike, eHTMLTag_strong, - eHTMLTag_sub, eHTMLTag_sup, - - eHTMLTag_table, //Added this for backward compatibility... - - eHTMLTag_textarea,eHTMLTag_tt, - eHTMLTag_u, eHTMLTag_userdefined, - eHTMLTag_var, - eHTMLTag_wbr, - eHTMLTag_text, - eHTMLTag_newline, - eHTMLTag_whitespace, -}; - -//This is a convenience set, which combines block AND inline child lists... -static eHTMLTags gBlockAndInlineChildTags []={ - eHTMLTag_a, eHTMLTag_abbr, eHTMLTag_acronym, eHTMLTag_address, eHTMLTag_applet, - eHTMLTag_b, eHTMLTag_basefont, eHTMLTag_bdo, eHTMLTag_bgsound, eHTMLTag_big, - eHTMLTag_blink, eHTMLTag_blockquote, eHTMLTag_br, eHTMLTag_button, - eHTMLTag_center, eHTMLTag_cite, eHTMLTag_code, - eHTMLTag_dfn, eHTMLTag_del, eHTMLTag_dir, eHTMLTag_div, eHTMLTag_dl, - eHTMLTag_em, eHTMLTag_embed, - eHTMLTag_fieldset, eHTMLTag_font, eHTMLTag_form, - eHTMLTag_h1, eHTMLTag_h2, eHTMLTag_h3, - eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6, - eHTMLTag_hr, - - eHTMLTag_i, eHTMLTag_iframe, eHTMLTag_ilayer, eHTMLTag_img, - eHTMLTag_ins, eHTMLTag_isindex, eHTMLTag_input, - - eHTMLTag_kbd, - - eHTMLTag_label, eHTMLTag_layer, eHTMLTag_li, eHTMLTag_listing, - - eHTMLTag_map, /*eHTMLTag_marque,*/ eHTMLTag_menu, eHTMLTag_multicol, - eHTMLTag_nobr, eHTMLTag_noembed, eHTMLTag_noframes, eHTMLTag_nolayer, eHTMLTag_noscript, - - eHTMLTag_object, eHTMLTag_ol, - eHTMLTag_p, eHTMLTag_plaintext, eHTMLTag_pre, - eHTMLTag_q, - eHTMLTag_s, eHTMLTag_samp, eHTMLTag_script, eHTMLTag_select, eHTMLTag_small, - eHTMLTag_sound, eHTMLTag_spacer, eHTMLTag_span, eHTMLTag_strike, eHTMLTag_strong, - eHTMLTag_sub, eHTMLTag_sup, - - eHTMLTag_table, eHTMLTag_textarea, - eHTMLTag_tt, eHTMLTag_u, eHTMLTag_ul, eHTMLTag_userdefined, - eHTMLTag_var, eHTMLTag_wbr, eHTMLTag_xmp, - - //a few special cases... - eHTMLTag_text, - eHTMLTag_newline, - eHTMLTag_whitespace, -}; - - -static eHTMLTags gPREChildTags []={ - eHTMLTag_a, eHTMLTag_abbr, eHTMLTag_acronym, - eHTMLTag_b, eHTMLTag_bdo, eHTMLTag_bgsound, - eHTMLTag_br, eHTMLTag_button, - eHTMLTag_cite, eHTMLTag_code, eHTMLTag_dfn, - eHTMLTag_em, eHTMLTag_embed, - eHTMLTag_i, eHTMLTag_ilayer, eHTMLTag_input, - eHTMLTag_kbd, eHTMLTag_label, eHTMLTag_li, - eHTMLTag_map, eHTMLTag_q, - eHTMLTag_s, eHTMLTag_samp, eHTMLTag_script, eHTMLTag_select, - eHTMLTag_sound, eHTMLTag_spacer, eHTMLTag_span, eHTMLTag_strike, eHTMLTag_strong, - eHTMLTag_textarea,eHTMLTag_tt, - eHTMLTag_u, eHTMLTag_var, eHTMLTag_wbr, - eHTMLTag_text, eHTMLTag_newline, eHTMLTag_whitespace, -}; - - -static eHTMLTags gHeadChildTags []={ - eHTMLTag_base, eHTMLTag_bgsound, eHTMLTag_isindex, - eHTMLTag_link, eHTMLTag_meta, /*eHTMLTag_nextid,*/ - eHTMLTag_script, eHTMLTag_sound, eHTMLTag_style, - eHTMLTag_title -}; - -static eHTMLTags gFormChildTags []={ - eHTMLTag_button, eHTMLTag_input, eHTMLTag_keygen, - eHTMLTag_label, eHTMLTag_select, eHTMLTag_textarea -}; - -static CTokenRecycler gTokenRecycler; +#include "nsElementTable.h" /*************************************************************** @@ -440,7 +255,7 @@ PRInt32 NavDispatchTokenHandler(CToken* aToken,nsIDTD* aDTD) { if(aDTD) { switch(theType) { case eToken_start: - case eToken_whitespace: + case eToken_whitespace: case eToken_newline: case eToken_text: result=theDTD->HandleStartToken(aToken); break; @@ -491,21 +306,19 @@ void CNavDTD::InitializeDefaultTokenHandlers() { } -static CTokenDeallocator gTokenKiller; - /** * Default constructor - * + * * @update gess 4/9/98 * @param * @return */ -CNavDTD::CNavDTD() : nsIDTD(), mTokenDeque(gTokenKiller) { +CNavDTD::CNavDTD() : nsIDTD(){ NS_INIT_REFCNT(); - mSink = 0; - mParser=0; - mDTDDebug=0; - mLineNumber=1; + mSink = 0; + mParser=0; + mDTDDebug=0; + mLineNumber=1; mHasOpenBody=PR_FALSE; nsCRT::zero(mTokenHandlers,sizeof(mTokenHandlers)); mHasOpenForm=PR_FALSE; @@ -516,7 +329,20 @@ CNavDTD::CNavDTD() : nsIDTD(), mTokenDeque(gTokenKiller) { mBodyContext=new nsDTDContext(); mFormContext=0; mMapContext=0; -// DebugDumpContainmentRules(*this,"c:/temp/DTDRules1.out","New CNavDTD Containment Rules"); + mTokenizer=0; + +// DebugDumpContainmentRules2(*this,"c:/temp/DTDRules.new","New CNavDTD Containment Rules"); +} + + +/** + * + * @update gess1/8/99 + * @param + * @return + */ +const nsIID& CNavDTD::GetMostDerivedIID(void)const { + return kClassIID; } /** @@ -544,18 +370,6 @@ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){ return NS_NewNavHTMLDTD(aInstancePtrResult); } - -/** - * - * @update gess8/4/98 - * @param - * @return - */ -nsITokenRecycler* CNavDTD::GetTokenRecycler(void){ -// return 0; - return &gTokenRecycler; -} - /** * Called by the parser to initiate dtd verification of the * internal context stack. @@ -575,7 +389,7 @@ PRBool CNavDTD::Verify(nsString& aURLRef,nsIParser* aParser){ else mDTDDebug->SetVerificationDirectory(kVerificationDir); } if(mDTDDebug) { - mDTDDebug->Verify(this,aParser,mBodyContext->mElements.mCount,mBodyContext->mElements.mTags,aURLRef); + // mDTDDebug->Verify(this,aParser,mBodyContext->GetCount(),mBodyContext->mTags,aURLRef); } return result; } @@ -632,6 +446,7 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename,PRBool aNotifySink,nsIParse mSink=(nsIHTMLContentSink*)aParser->GetContentSink(); if((aNotifySink) && (mSink)) { mHasOpenBody=PR_FALSE; + mHadBodyOrFrameset=PR_FALSE; mLineNumber=1; result = mSink->WillBuildModel(); } @@ -639,16 +454,49 @@ nsresult CNavDTD::WillBuildModel(nsString& aFilename,PRBool aNotifySink,nsIParse 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 0) + */ +nsresult CNavDTD::BuildModel(nsIParser* aParser) { + nsresult result=NS_OK; + + nsHTMLTokenizer* theTokenizer=(nsHTMLTokenizer*)GetTokenizer(); + nsITokenRecycler* theRecycler=GetTokenRecycler(); + if(theTokenizer) { + while(NS_OK==result){ + CToken* theToken=theTokenizer->PopToken(); + if(theToken) { + result=HandleToken(theToken,aParser); + if(NS_SUCCEEDED(result)) { + theRecycler->RecycleToken(theToken); + } + else if(NS_ERROR_HTMLPARSER_BLOCK!=result){ + theTokenizer->PushTokenFront(theToken); + } + // theRootDTD->Verify(kEmptyString,aParser); + } + else break; + } + } + return result; +} + /** * * @update gess5/18/98 * @param * @return */ -nsresult CNavDTD::DidBuildModel(PRInt32 anErrorCode,PRBool aNotifySink,nsIParser* aParser){ +nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParser* aParser){ nsresult result= NS_OK; - if((kNoError==anErrorCode) && (!mHasOpenBody)) { + if((NS_OK==anErrorCode) && (!mHadBodyOrFrameset)) { CStartToken theToken(eHTMLTag_body); //open the body container... result=HandleStartToken(&theToken); } @@ -657,7 +505,7 @@ nsresult CNavDTD::DidBuildModel(PRInt32 anErrorCode,PRBool aNotifySink,nsIParser mSink=(nsIHTMLContentSink*)aParser->GetContentSink(); if(aNotifySink && mSink){ - if((kNoError==anErrorCode) && (mBodyContext->mElements.mCount>0)) { + if((NS_OK==anErrorCode) && (mBodyContext->GetCount()>0)) { result = CloseContainersTo(0,eHTMLTag_unknown,PR_FALSE); } @@ -695,8 +543,9 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){ mParser=(nsParser*)aParser; mSink=(nsIHTMLContentSink*)mParser->GetContentSink(); result=(*theHandler)(theToken,this); - if (mDTDDebug) - mDTDDebug->Verify(this, mParser, mBodyContext->mElements.mCount, mBodyContext->mElements.mTags, mFilename); + if (mDTDDebug) { + //mDTDDebug->Verify(this, mParser, mBodyContext->GetCount(), mBodyContext->mTags, mFilename); + } } }//if @@ -734,12 +583,18 @@ nsresult CNavDTD::ReleaseTokenPump(nsITagHandler* aHandler){ * @param aChildTag is the tag itself. * @return status */ -PRInt32 CNavDTD::DidHandleStartTag(CToken* aToken,eHTMLTags aChildTag){ - PRInt32 result=kNoError; - CToken* theNextToken=mParser->PeekToken(); +nsresult CNavDTD::DidHandleStartTag(CToken* aToken,eHTMLTags aChildTag){ + nsresult result=NS_OK; + CToken* theNextToken=mTokenizer->PeekToken(); if(theNextToken){ switch(aChildTag){ + case eHTMLTag_body: + case eHTMLTag_frameset: + mHadBodyOrFrameset=PR_TRUE; + break; + + case eHTMLTag_pre: case eHTMLTag_listing: { @@ -751,7 +606,7 @@ PRInt32 CNavDTD::DidHandleStartTag(CToken* aToken,eHTMLTags aChildTag){ case eHTMLTag_pre: case eHTMLTag_listing: //we skip the first newline token inside PRE and LISTING - mParser->PopToken(); + mTokenizer->PopToken(); break; default: break; @@ -775,23 +630,75 @@ PRInt32 CNavDTD::DidHandleStartTag(CToken* aToken,eHTMLTags aChildTag){ break; default: break; - }//switch + }//switch } return result; -} - - -void CompareResults(PRBool canContain,eHTMLTags aParentTag,eHTMLTags aChildTag){ -/* - PRBool theNewResult=CanContainEx(aParentTag,aChildTag); - if(canContain!=theNewResult){ - printf("%s(child:%i,parent:%i)\n","can contain!=can containex",aChildTag,aParentTag); - } -*/ -} - - +} + /** + * Determine whether the given tag is open anywhere + * in our context stack. + * + * @update gess 4/2/98 + * @param eHTMLTags tag to be searched for in stack + * @return topmost index of tag on stack + */ +PRInt32 GetTopmostIndexOf(eHTMLTags aTag,nsTagStack& aTagStack) { + int i=0; + for(i=aTagStack.mCount-1;i>=0;i--){ + if(aTagStack.mTags[i]==aTag) + return i; + } + return kNotFound; +} + +/** + * This method is called to determine whether or not a START tag + * can be autoclosed. This means that based on the current + * context, the stack should be closed to the nearest matching + * tag. + * + * @param aTag -- tag enum of child to be tested + * @return PR_TRUE if autoclosure should occur + */ +eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack) { + int theTopIndex=aTagStack.mCount; + eHTMLTags aPrevTag=aTagStack.mTags[theTopIndex-1]; + + if(nsHTMLElement::IsContainer(aCurrentTag)){ + if((aPrevTag==aCurrentTag) && (!gHTMLElements[aCurrentTag].CanSelfContain())){ + return aCurrentTag; + } + if(nsHTMLElement::IsBlockCloser(aCurrentTag)) { + + CTagList* theRootTags=gHTMLElements[aCurrentTag].GetRootTags(); + if(theRootTags) { + PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack); + if(theRootIndexGetTopmostIndexOf(aTagStack); + if(kNotFound!=thePeerIndex){ + if(thePeerIndex==theTopIndex-1) { + //the guy you can autoclose is on the top of the stack... + return aPrevTag; + } //if + } //if + }//if + + } //if + else if(nsHTMLElement::IsInlineElement(aCurrentTag)) { + }//if + } //if + return eHTMLTag_unknown; +} + + +/** * This method gets called when a start token has been * encountered in the parse process. If the current container * can contain this tag, then add it. Otherwise, you have @@ -799,7 +706,7 @@ void CompareResults(PRBool canContain,eHTMLTags aParentTag,eHTMLTags aChildTag){ * to be stored in * 2) close the top container, and add this to * whatever container ends up on top. - * + * * @update gess 3/25/98 * @param aToken -- next (start) token to be handled * @param aNode -- CParserNode representing this start token @@ -809,27 +716,40 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI NS_PRECONDITION(0!=aToken,kNullToken); nsresult result=NS_OK; - eHTMLTags theParentTag=mBodyContext->mElements.Last(); - if(RequiresAutomaticClosure(theParentTag,aChildTag)){ - result=CloseContainersTo(aChildTag,PR_TRUE); + //Sick as it sounds, I have to make sure the body has been + //opened before other tags can be added to the content sink... + + static eHTMLTags gBodyBlockers[]={eHTMLTag_body,eHTMLTag_frameset,eHTMLTag_head}; + PRInt32 theBodyBlocker=GetTopmostIndexOf(gBodyBlockers,sizeof(gStyleTags)/sizeof(eHTMLTag_unknown)); + if(!theBodyBlocker) { + if(CanPropagate(eHTMLTag_body,aChildTag)) { + mHasOpenBody=PR_TRUE; + CStartToken theToken(eHTMLTag_body); //open the body container... + result=HandleStartToken(&theToken); + } + }//if + + eHTMLTags theParentTag=mBodyContext->Last(); + PRBool theCanContainResult=CanContain(theParentTag,aChildTag); + + eHTMLTags theTarget=FindAutoCloseTargetForStartTag(aChildTag,mBodyContext->mTags); + if(eHTMLTag_unknown!=theTarget){ + result=CloseContainersTo(theTarget,PR_TRUE); } - PRBool theCanContainResult=CanContain(theParentTag,aChildTag); - CompareResults(theCanContainResult,theParentTag,aChildTag); if(PR_FALSE==theCanContainResult){ if(CanPropagate(theParentTag,aChildTag)) result=CreateContextStackFor(aChildTag); else result=kCantPropagate; - if(NS_OK!=result) { + if(NS_OK!=result) { //if you're here, then the new topmost container can't contain aToken. //You must determine what container hierarchy you need to hold aToken, //and create that on the parsestack. result=ReduceContextStackFor(aChildTag); - PRBool theCanContainResult=CanContain(mBodyContext->mElements.Last(),aChildTag); - CompareResults(theCanContainResult,mBodyContext->mElements.Last(),aChildTag); + PRBool theCanContainResult=CanContain(mBodyContext->Last(),aChildTag); if(PR_FALSE==theCanContainResult) { //we unwound too far; now we have to recreate a valid context stack. @@ -839,15 +759,17 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI } if(IsContainer(aChildTag)){ - if(PR_TRUE==mBodyContext->mElements.mBits[mBodyContext->mElements.mCount-1]) { - CloseTransientStyles(aChildTag); + //first, let's see if it's a style element... + if(!FindTagInSet(aChildTag,gStyleTags,sizeof(gStyleTags)/sizeof(eHTMLTag_unknown))) { + //it wasn't a style container, so open the element container... + if(mBodyContext->mOpenStyles) { + CloseTransientStyles(aChildTag); + } } result=OpenContainer(aNode,PR_TRUE); } - else { - if(PR_FALSE==mBodyContext->mElements.mBits[mBodyContext->mElements.mCount-1]) { - OpenTransientStyles(aChildTag); - } + else { //we're writing a leaf... + OpenTransientStyles(aChildTag); result=AddLeaf(aNode); } @@ -870,80 +792,81 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI * @param aToken -- next (start) token to be handled * @param aNode -- CParserNode representing this start token * @return PR_TRUE if all went well; PR_FALSE if error occured - */ + */ nsresult CNavDTD::HandleStartToken(CToken* aToken) { NS_PRECONDITION(0!=aToken,kNullToken); //Begin by gathering up attributes... - nsCParserNode attrNode((CHTMLToken*)aToken,mLineNumber); + eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID(); + nsCParserNode attrNode((CHTMLToken*)aToken,mLineNumber,GetTokenRecycler()); PRInt16 attrCount=aToken->GetAttributeCount(); nsresult result=(0==attrCount) ? NS_OK : CollectAttributes(attrNode,attrCount); - eHTMLTags theParent=mBodyContext->mElements.Last(); - eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID(); + eHTMLTags theParent=mBodyContext->Last(); PRInt32 theAttrCount; - + if(NS_OK==result) { - //now check to see if this token should be omitted... + switch(theChildTag) { - if(PR_FALSE==CanOmit(theParent,theChildTag)) { - - switch(theChildTag) { - - case eHTMLTag_title: - { - result=OpenHead(attrNode); //open the head... - if(NS_OK==result) { - - result=CollectSkippedContent(attrNode,theAttrCount); - mSink->SetTitle(attrNode.GetSkippedContent()); - result=CloseHead(attrNode); //close the head... - } - } - break; - - case eHTMLTag_link: - case eHTMLTag_base: - case eHTMLTag_meta: - result=AddHeadLeaf(attrNode); - break; - - case eHTMLTag_style: - { + case eHTMLTag_title: + { + PRBool headOpen=mHasOpenHead; + if(!headOpen) result=OpenHead(attrNode); + if(NS_OK==result) { + result=CollectSkippedContent(attrNode,theAttrCount); + mSink->SetTitle(attrNode.GetSkippedContent()); + if((NS_OK==result) && (!headOpen)) + result=CloseHead(attrNode); + } + } + break; + + case eHTMLTag_base: + case eHTMLTag_link: + case eHTMLTag_meta: + result=AddHeadLeaf(attrNode); + break; + + case eHTMLTag_style: + { + PRBool headOpen=mHasOpenHead; + if(!headOpen) + result=OpenHead(attrNode); + if(NS_OK==result) { + PRInt32 theCount; + CollectSkippedContent(attrNode,theCount); if(NS_OK==result) { - PRInt32 theCount; - CollectSkippedContent(attrNode,theCount); - if(NS_OK==result) { - result=AddLeaf(attrNode); - // XXX If the return value tells us to block, go - // ahead and close the tag out anyway, since its - // contents will be consumed. - if (NS_SUCCEEDED(result)) { - nsresult rv = CloseHead(attrNode); - // XXX Only send along a failure. If the close - // succeeded we still may need to indicate that the - // parser has blocked (i.e. return the result of - // the AddLeaf. - if (rv != NS_OK) { - result = rv; - } + result=AddLeaf(attrNode); + // XXX If the return value tells us to block, go + // ahead and close the tag out anyway, since its + // contents will be consumed. + if (NS_SUCCEEDED(result)) { + nsresult rv = CloseHead(attrNode); + // XXX Only send along a failure. If the close + // succeeded we still may need to indicate that the + // parser has blocked (i.e. return the result of + // the AddLeaf. + if (rv != NS_OK) { + result = rv; } } } - } - break; + } + } + break; - case eHTMLTag_area: - if (mHasOpenMap) { - result = mSink->AddLeaf(attrNode); - } - break; + case eHTMLTag_area: + if (mHasOpenMap) { + result = mSink->AddLeaf(attrNode); + } + break; - default: + default: + if(PR_FALSE==CanOmit(theParent,theChildTag)) { result=HandleDefaultStartToken(aToken,theChildTag,attrNode); - break; - } //switch - } //if + } + break; + } //switch } //if if(eHTMLTag_newline==theChildTag) @@ -953,8 +876,6 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) { } - - /** * This method gets called when an end token has been * encountered in the parse process. If the end tag matches @@ -974,9 +895,9 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) { nsresult result=NS_OK; CEndToken* et = (CEndToken*)(aToken); eHTMLTags tokenTagType=(eHTMLTags)et->GetTypeID(); + - - // Here's the hacky part: + // Here's the hacky part: // Because we're trying to be backward compatible with Nav4/5, // we have to handle explicit styles the way it does. That means // that we keep an internal style stack.When an EndToken occurs, @@ -986,7 +907,7 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) { //now check to see if this token should be omitted, or //if it's gated from closing by the presence of another tag. - if(PR_TRUE==CanOmitEndTag(mBodyContext->mElements.Last(),tokenTagType)) { + if(PR_TRUE==CanOmitEndTag(mBodyContext->Last(),tokenTagType)) { UpdateStyleStackForCloseTag(tokenTagType,tokenTagType); return result; } @@ -999,16 +920,12 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) { case eHTMLTag_meta: case eHTMLTag_textarea: case eHTMLTag_title: - case eHTMLTag_head: case eHTMLTag_script: break; case eHTMLTag_map: case eHTMLTag_form: - { - nsCParserNode aNode((CHTMLToken*)aToken,mLineNumber); - result=CloseContainer(aNode,tokenTagType,PR_FALSE); - } + result=CloseContainer(theNode,tokenTagType,PR_FALSE); break; case eHTMLTag_td: @@ -1017,7 +934,7 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) { // Empty the transient style stack (we just closed any extra // ones off so it's safe to do it now) because they don't carry // forward across table cell boundaries. - mBodyContext->mStyles->mCount=0; + //mBodyContext->mStyles->mCount=0; break; default: @@ -1044,7 +961,7 @@ nsresult CNavDTD::HandleEntityToken(CToken* aToken) { CEntityToken* et = (CEntityToken*)(aToken); nsresult result=NS_OK; - if(PR_FALSE==CanOmit(mBodyContext->mElements.Last(),eHTMLTag_entity)) { + if(PR_FALSE==CanOmit(mBodyContext->Last(),eHTMLTag_entity)) { nsCParserNode aNode((CHTMLToken*)aToken,mLineNumber); result=AddLeaf(aNode); } @@ -1106,7 +1023,7 @@ nsresult CNavDTD::HandleAttributeToken(CToken* aToken) { return NS_OK; } - + /** * This method gets called when a script token has been * encountered in the parse process. @@ -1176,20 +1093,22 @@ nsresult CNavDTD::HandleProcessingInstructionToken(CToken* aToken){ * @param aCount is the # of attributes you're expecting * @return error code (should be 0) */ -PRInt32 CNavDTD::CollectAttributes(nsCParserNode& aNode,PRInt32 aCount){ +nsresult CNavDTD::CollectAttributes(nsCParserNode& aNode,PRInt32 aCount){ int attr=0; - for(attr=0;attrPeekToken(); - if(theToken) { - eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType()); - if(eToken_attribute==theType){ - mParser->PopToken(); //pop it for real... + + nsresult result=NS_OK; + if(aCount<=mTokenizer->GetCount()) { + for(attr=0;attrPopToken(); + if(theToken) { aNode.AddAttribute(theToken); - } + } } - else return kInterrupted; } - return kNoError; + else { + result=kEOF; + } + return result; } @@ -1201,22 +1120,22 @@ PRInt32 CNavDTD::CollectAttributes(nsCParserNode& aNode,PRInt32 aCount){ * @param holds the number of skipped content elements encountered * @return Error condition. */ -PRInt32 CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32& aCount) { - PRInt32 result=kNoError; - eHTMLTokenTypes theType; - CToken* theToken; +nsresult CNavDTD::CollectSkippedContent(nsCParserNode& aNode,PRInt32& aCount) { + nsresult result=NS_OK; + eHTMLTokenTypes theType=eToken_unknown; aCount=0; - do{ - theToken=mParser->PeekToken(); - if(theToken) { - theType=eHTMLTokenTypes(theToken->GetTokenType()); - if(eToken_skippedcontent==theType) { - mParser->PopToken(); - aNode.SetSkippedContent(theToken); - aCount++; - } - } - } while(theToken && (eToken_skippedcontent==theType)); + + CToken* theToken=mTokenizer->PopToken(); + if(theToken) { + theType=eHTMLTokenTypes(theToken->GetTokenType()); + if(eToken_skippedcontent==theType) { + aNode.SetSkippedContent(theToken); + aCount++; + } + } + else { + result=kEOF; + } return result; } @@ -1294,14 +1213,14 @@ PRBool CNavDTD::CanContainStyles(eHTMLTags aParent) const { result=PR_FALSE; break; default: break; - } - return result; -} - + } + return result; +} + /*********************************************************************************** The preceeding tables determine the set of elements each tag can contain... ***********************************************************************************/ - + /** * This method is called to determine whether or not a tag * of one type can contain a tag of another type. @@ -1312,426 +1231,13 @@ PRBool CNavDTD::CanContainStyles(eHTMLTags aParent) const { * @return PR_TRUE if parent can contain child */ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { - - PRBool result=PR_FALSE; - if((!IsContainer(aParent)) && (eHTMLTag_unknown!=aParent)) - return result; - - - /*************************************************************************** - * Handle form elements here. Why? Because as long as a form is open, - * almost any form element is allowed. (Except