diff --git a/base/src/nsDeque.cpp b/base/src/nsDeque.cpp index 163913a69066..1185aa3c25ca 100644 --- a/base/src/nsDeque.cpp +++ b/base/src/nsDeque.cpp @@ -25,11 +25,10 @@ * @update gess4/18/98 * @return new deque */ -nsDeque::nsDeque(PRBool aOwnsMemory, DEQUE_FREEOBJECT pFreeProc ) { - mOwnsMemory=aOwnsMemory; +nsDeque::nsDeque(nsDequeFunctor& aMemDestroyer) : mMemDestroyer(aMemDestroyer) { + mMemDestroyer=aMemDestroyer; mCapacity=eGrowthDelta; mOrigin=mSize=0; - mFreeProc = pFreeProc; mData=new void*[mCapacity]; } @@ -39,11 +38,9 @@ nsDeque::nsDeque(PRBool aOwnsMemory, DEQUE_FREEOBJECT pFreeProc ) { * @update gess4/18/98 */ nsDeque::~nsDeque() { - if(mOwnsMemory) - Erase(); + Erase(); delete [] mData; mData=0; - mOwnsMemory=PR_FALSE; } @@ -73,19 +70,6 @@ nsDeque& nsDeque::Empty() { return *this; } -/** - * Sets the memory object free procedure. - * - * @update jevering6/10/98 - * @param pFreeProc is pointer to the free procedure - * @return - */ - -void nsDeque::SetFreeProc(DEQUE_FREEOBJECT pFreeProc) -{ - mFreeProc = pFreeProc; -} - /** * Remove and delete all items from container * @@ -93,16 +77,7 @@ void nsDeque::SetFreeProc(DEQUE_FREEOBJECT pFreeProc) * @return this */ nsDeque& nsDeque::Erase() { - nsDequeIterator iter1=Begin(); - nsDequeIterator iter2=End(); - void* temp; - while(iter1!=iter2) { - temp=(iter1++); - if (mFreeProc) - (*mFreeProc)(temp); - else - delete temp; - } + ForEach(mMemDestroyer); return Empty(); } diff --git a/base/src/nsDeque.h b/base/src/nsDeque.h index 893735399241..adc11f5dbf0d 100644 --- a/base/src/nsDeque.h +++ b/base/src/nsDeque.h @@ -50,10 +50,9 @@ */ class NS_BASE nsDequeFunctor{ public: - virtual nsDequeFunctor& operator()(void* anObject)=0; + virtual void operator()(void* anObject)=0; }; -typedef void (* DEQUE_FREEOBJECT)(void *); /****************************************************** * Here comes the nsDeque class itself... @@ -72,7 +71,7 @@ typedef void (* DEQUE_FREEOBJECT)(void *); class NS_BASE nsDeque { friend class nsDequeIterator; public: - nsDeque(PRBool aOwnsMemory=PR_TRUE,DEQUE_FREEOBJECT pFreeProc=0); + nsDeque(nsDequeFunctor& aMemDestroyer); ~nsDeque(); /** @@ -84,16 +83,7 @@ friend class nsDequeIterator; * @return int contains element count */ PRInt32 GetSize() const; - - /** - * Sets the memory object free procedure. - * - * @update jevering6/10/98 - * @param pFreeProc is pointer to the free procedure - * @return - */ - - void SetFreeProc(DEQUE_FREEOBJECT pFreeProc = 0); + /** * Pushes new member onto the end of the deque @@ -180,17 +170,26 @@ friend class nsDequeIterator; protected: - PRInt32 mSize; - PRInt32 mCapacity; - PRInt32 mOrigin; - PRBool mOwnsMemory; - void** mData; - DEQUE_FREEOBJECT mFreeProc; + PRInt32 mSize; + PRInt32 mCapacity; + PRInt32 mOrigin; + nsDequeFunctor& mMemDestroyer; + void** mData; + private: enum {eGrowthDelta=64}; + /** + * Simple default constructor (PRIVATE) + * + * @update gess4/18/98 + * @param + * @return + */ + nsDeque(); + /** * Copy constructor (PRIVATE) * @@ -198,7 +197,7 @@ private: * @param * @return */ - nsDeque(const nsDeque& other, DEQUE_FREEOBJECT pFreeProc); + nsDeque(const nsDeque& other); /** * Deque assignment operator (PRIVATE) diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 152eaf6cb361..9e2b7e3c9f59 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -31,6 +31,7 @@ #include "nsIDOMElement.h" #include "nsIDOMText.h" #include "nsIPostToServer.h" +#include "nsIURL.h" static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); diff --git a/htmlparser/src/CNavDTD.cpp b/htmlparser/src/CNavDTD.cpp index bc68356a870f..e9a6a80c99c2 100644 --- a/htmlparser/src/CNavDTD.cpp +++ b/htmlparser/src/CNavDTD.cpp @@ -23,16 +23,73 @@ * */ +/** + * TRANSIENT STYLE-HANDLING NOTES: + * @update gess 6/15/98 + * + * ...add comments here about transient style stack. + * + */ + #include "CNavDTD.h" #include "nsHTMLTokens.h" #include "nsCRT.h" #include "nsParserTypes.h" -#include "nsIParser.h" +#include "nsHTMLParser.h" +#include "nsHTMLContentSink.h" +#include "nsScanner.h" + +#include "prenv.h" //this is here for debug reasons... +#include "prtypes.h" //this is here for debug reasons... +#include "prio.h" +#include "plstr.h" +#include "prstrm.h" +#include + +#ifdef XP_PC +#include //this is here for debug reasons... +#endif +#include +#include "prmem.h" + 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* kNullTokenizer = "Error: Unable to construct tokenizer"; +static const char* kNullToken = "Error: Null token given"; +static const char* kInvalidTagStackPos = "Error: invalid tag stack position"; + +static char* gVerificationOutputDir=0; +static char* gURLRef=0; +static nsAutoString gEmpty; + +static char formElementTags[]= { + eHTMLTag_button, eHTMLTag_fieldset, eHTMLTag_input, + eHTMLTag_isindex, eHTMLTag_label, eHTMLTag_legend, + eHTMLTag_select, eHTMLTag_textarea,0}; + +static char gHeadingTags[]={ + eHTMLTag_h1, eHTMLTag_h2, eHTMLTag_h3, + eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6, + 0}; + +static char gStyleTags[]={ + eHTMLTag_a, eHTMLTag_bold, eHTMLTag_big, + eHTMLTag_blink, eHTMLTag_cite, eHTMLTag_em, + eHTMLTag_font, eHTMLTag_italic, eHTMLTag_kbd, + eHTMLTag_small, eHTMLTag_spell, eHTMLTag_strike, + eHTMLTag_strong, eHTMLTag_sub, eHTMLTag_sup, + eHTMLTag_tt, eHTMLTag_u, eHTMLTag_var, + 0}; + +static char gWhitespaceTags[]={ + eHTMLTag_newline, eHTMLTag_whitespace, + 0}; + /** * This method gets called as part of our COM-like interfaces. @@ -91,6 +148,84 @@ NS_IMPL_ADDREF(CNavDTD) NS_IMPL_RELEASE(CNavDTD) + +/** + * + * + * @update gess 6/9/98 + * @param + * @return + */ +PRInt32 NavDispatchTokenHandler(CToken* aToken,nsIDTD* aDTD) { + PRInt32 result=0; + CHTMLToken* theToken= (CHTMLToken*)(aToken); + eHTMLTokenTypes theType= (eHTMLTokenTypes)theToken->GetTokenType(); + CNavDTD* theDTD=(CNavDTD*)aDTD; + + if(aDTD) { + switch(theType) { + case eToken_start: + result=theDTD->HandleStartToken(aToken); break; + case eToken_end: + result=theDTD->HandleEndToken(aToken); break; + case eToken_comment: + result=theDTD->HandleCommentToken(aToken); break; + case eToken_entity: + result=theDTD->HandleEntityToken(aToken); break; + case eToken_whitespace: + result=theDTD->HandleStartToken(aToken); break; + case eToken_newline: + result=theDTD->HandleStartToken(aToken); break; + case eToken_text: + result=theDTD->HandleStartToken(aToken); break; + case eToken_attribute: + result=theDTD->HandleAttributeToken(aToken); break; + case eToken_style: + result=theDTD->HandleStyleToken(aToken); break; + case eToken_skippedcontent: + result=theDTD->HandleSkippedContentToken(aToken); break; + default: + result=0; + }//switch + }//if + return result; +} + +/** + * init the set of default token handlers... + * + * @update gess 3/25/98 + * @param + * @return + */ +void CNavDTD::InitializeDefaultTokenHandlers() { + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_start)); + + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_end)); + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_comment)); + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_entity)); + + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_whitespace)); + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_newline)); + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_text)); + + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_attribute)); +// AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_script)); + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_style)); + AddTokenHandler(new CTokenHandler(NavDispatchTokenHandler,eToken_skippedcontent)); +} + + +class CNavTokenDeallocator: public nsDequeFunctor{ +public: + virtual void operator()(void* anObject) { + CToken* aToken = (CToken*)anObject; + delete aToken; + } +}; + +CNavTokenDeallocator gTokenKiller; + /** * Default constructor * @@ -98,8 +233,19 @@ NS_IMPL_RELEASE(CNavDTD) * @param * @return */ -CNavDTD::CNavDTD() : nsIDTD() { +CNavDTD::CNavDTD() : nsIDTD(), mTokenDeque(gTokenKiller) { mParser=0; + nsCRT::zero(mLeafBits,sizeof(mLeafBits)); + nsCRT::zero(mContextStack,sizeof(mContextStack)); + nsCRT::zero(mStyleStack,sizeof(mStyleStack)); + nsCRT::zero(mTokenHandlers,sizeof(mTokenHandlers)); + mContextStackPos=0; + mStyleStackPos=0; + gURLRef = 0; + mHasOpenForm=PR_FALSE; + mHasOpenMap=PR_FALSE; + gVerificationOutputDir = PR_GetEnv("VERIFY_PARSER"); + InitializeDefaultTokenHandlers(); } /** @@ -110,6 +256,505 @@ CNavDTD::CNavDTD() : nsIDTD() { * @return */ CNavDTD::~CNavDTD(){ + DeleteTokenHandlers(); + if (gURLRef) + { + PL_strfree(gURLRef); + gURLRef = 0; + } +// NS_RELEASE(mSink); +} + +/** + * + * @update gess5/18/98 + * @param + * @return + */ +PRInt32 CNavDTD::WillBuildModel(void){ + PRInt32 result=0; + + if(mSink) + mSink->WillBuildModel(); + + return result; +} + +/** + * + * @update gess5/18/98 + * @param + * @return + */ +PRInt32 CNavDTD::DidBuildModel(PRInt32 anErrorCode){ + PRInt32 result=0; + + if((kNoError==anErrorCode) && (mContextStackPos>0)) { + CloseContainersTo(0,eHTMLTag_unknown,PR_FALSE); + } + if(mSink) { + mSink->DidBuildModel(); + } + + 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 5/21/98 + * @param aType + * @param aToken + * @param aParser + * @return + */ +PRInt32 CNavDTD::HandleToken(CToken* aToken){ + PRInt32 result=0; + + if(aToken) { + CHTMLToken* theToken= (CHTMLToken*)(aToken); + eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType()); + CTokenHandler* aHandler=GetTokenHandler(theType); + + if(aHandler) { + result=(*aHandler)(theToken,this); + Verify("xxx",PR_TRUE); + } + + }//if + return result; +} + + + +/** + * 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 + * two choices: 1) create an implicit container for this tag + * 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 + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsCParserNode& aNode) { + NS_PRECONDITION(0!=aToken,kNullToken); + + eHTMLTags parentTag=(eHTMLTags)GetTopNode(); + PRInt32 result=kNoError; + PRBool contains=CanContain(parentTag,aChildTag); + + if(PR_FALSE==contains){ + result=CreateContextStackFor(aChildTag); + if(kNoError!=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); + if(PR_FALSE==CanContain(GetTopNode(),aChildTag)) { + //we unwound too far; now we have to recreate a valid context stack. + result=CreateContextStackFor(aChildTag); + } + } + } + + if(IsContainer(aChildTag)){ + if(PR_TRUE==mLeafBits[mContextStackPos-1]) { + CloseTransientStyles(aChildTag); + } + result=OpenContainer(aNode,PR_TRUE); + } + else { + if(PR_FALSE==mLeafBits[mContextStackPos-1]) { + OpenTransientStyles(aChildTag); + } + result=AddLeaf(aNode); + } + return result; +} + +/** + * 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 + * two choices: 1) create an implicit container for this tag + * 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 + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleStartToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + + CStartToken* st= (CStartToken*)(aToken); + eHTMLTags tokenTagType=st->GetHTMLTag(); + + //Begin by gathering up attributes... + nsCParserNode attrNode((CHTMLToken*)aToken); + PRInt16 attrCount=aToken->GetAttributeCount(); + PRInt32 result=(0==attrCount) ? kNoError : mParser->CollectAttributes(attrNode,attrCount); + + if(kNoError==result) { + //now check to see if this token should be omitted... + if(PR_FALSE==CanOmit(GetTopNode(),tokenTagType)) { + + switch(tokenTagType) { + + case eHTMLTag_html: + result=OpenHTML(attrNode); break; + + case eHTMLTag_title: + { + nsCParserNode theNode(st); + result=OpenHead(theNode); //open the head... + if(kNoError==result) { + mParser->CollectSkippedContent(attrNode); + mSink->SetTitle(attrNode.GetSkippedContent()); + result=CloseHead(theNode); //close the head... + } + } + break; + + case eHTMLTag_textarea: + { + mParser->CollectSkippedContent(attrNode); + result=AddLeaf(attrNode); + } + break; + + case eHTMLTag_form: + result = OpenForm(attrNode); + break; + + case eHTMLTag_meta: + case eHTMLTag_link: + { + nsCParserNode theNode((CHTMLToken*)aToken); + result=OpenHead(theNode); + if(kNoError==result) + result=AddLeaf(theNode); + if(kNoError==result) + result=CloseHead(theNode); + } + break; + + case eHTMLTag_style: + { + nsCParserNode theNode((CHTMLToken*)aToken); + result=OpenHead(theNode); + if(kNoError==result) { + mParser->CollectSkippedContent(attrNode); + if(kNoError==result) { + result=AddLeaf(attrNode); + if(kNoError==result) + result=CloseHead(theNode); + } + } + } + break; + + case eHTMLTag_script: + result=HandleScriptToken(st); break; + + + case eHTMLTag_head: + break; //ignore head tags... + + case eHTMLTag_base: + result=OpenHead(attrNode); + if(kNoError==result) { + result=AddLeaf(attrNode); + if(kNoError==result) + result=CloseHead(attrNode); + } + break; + + case eHTMLTag_nobr: + result=PR_TRUE; + + case eHTMLTag_map: + result=PR_TRUE; + + default: + result=HandleDefaultStartToken(aToken,tokenTagType,attrNode); + break; + } //switch + } //if + } //if + return result; +} + + +/** + * This method gets called when an end token has been + * encountered in the parse process. If the end tag matches + * the start tag on the stack, then simply close it. Otherwise, + * we have a erroneous state condition. This can be because we + * have a close tag with no prior open tag (user error) or because + * we screwed something up in the parse process. I'm not sure + * yet how to tell the difference. + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleEndToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + + PRInt32 result=kNoError; + CEndToken* et = (CEndToken*)(aToken); + eHTMLTags tokenTagType=et->GetHTMLTag(); + + // 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, + // we should see if it is an explicit style tag. If so, we can + // close AND explicit style tag (goofy, huh?) + +/* + if(0!=strchr(gStyleTags,tokenTagType)){ + eHTMLTags topTag=(eHTMLTags)GetTopNode(); + if(0!=strchr(gStyleTags,topTag)){ + tokenTagType=topTag; + } + } +*/ + + //now check to see if this token should be omitted... + if(PR_TRUE==CanOmitEndTag(GetTopNode(),tokenTagType)) { + UpdateStyleStackForCloseTag(tokenTagType,tokenTagType); + return result; + } + + nsCParserNode theNode((CHTMLToken*)aToken); + switch(tokenTagType) { + + case eHTMLTag_style: + case eHTMLTag_link: + case eHTMLTag_meta: + case eHTMLTag_textarea: + case eHTMLTag_title: + case eHTMLTag_head: + case eHTMLTag_script: + break; + + case eHTMLTag_map: + result=CloseContainer(theNode,tokenTagType,PR_TRUE); + break; + + case eHTMLTag_form: + { + nsCParserNode aNode((CHTMLToken*)aToken); + result=CloseForm(aNode); + } + break; + + default: + if(IsContainer(tokenTagType)){ + result=CloseContainersTo(tokenTagType,PR_TRUE); + } + // + break; + } + return result; +} + +/** + * This method gets called when an entity token has been + * encountered in the parse process. + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleEntityToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + + CEntityToken* et = (CEntityToken*)(aToken); + PRInt32 result=kNoError; + eHTMLTags tokenTagType=et->GetHTMLTag(); + + if(PR_FALSE==CanOmit(GetTopNode(),tokenTagType)) { + nsCParserNode aNode((CHTMLToken*)aToken); + result=AddLeaf(aNode); + } + return result; +} + +/** + * This method gets called when a comment token has been + * encountered in the parse process. After making sure + * we're somewhere in the body, we handle the comment + * in the same code that we use for text. + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleCommentToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + return kNoError; +} + +/** + * This method gets called when a skippedcontent token has + * been encountered in the parse process. After verifying + * that the topmost container can contain text, we call + * AddLeaf to store this token in the top container. + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleSkippedContentToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + + PRInt32 result=kNoError; + + if(HasOpenContainer(eHTMLTag_body)) { + nsCParserNode aNode((CHTMLToken*)aToken); + result=AddLeaf(aNode); + } + return result; +} + +/** + * This method gets called when an attribute token has been + * encountered in the parse process. This is an error, since + * all attributes should have been accounted for in the prior + * start or end tokens + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleAttributeToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + NS_ERROR("attribute encountered -- this shouldn't happen!"); + + CAttributeToken* at = (CAttributeToken*)(aToken); + PRInt32 result=kNoError; + return result; +} + +/** + * This method gets called when a script token has been + * encountered in the parse process. + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleScriptToken(CToken* aToken) { + NS_PRECONDITION(0!=aToken,kNullToken); + + /* + CScriptToken* st = (CScriptToken*)(aToken); + + eHTMLTokenTypes subtype=eToken_attribute; + nsDeque& deque=mTokenizer->GetDeque(); + nsDequeIterator end=deque.End(); + + if(*mCurrentPos!=end) { + CHTMLToken* tkn=(CHTMLToken*)(++(*mCurrentPos)); + subtype=eHTMLTokenTypes(tkn->GetTokenType()); + if(eToken_skippedcontent==subtype) { + //WE INTENTIONALLY DROP THE TOKEN ON THE FLOOR! + //LATER, we'll pass this onto the javascript system. + return kNoError; + } + else (*mCurrentPos)--; + } + */ + return kInterrupted; + +} + +/** + * This method gets called when a style token has been + * encountered in the parse process. + * + * @update gess 3/25/98 + * @param aToken -- next (start) token to be handled + * @return PR_TRUE if all went well; PR_FALSE if error occured + */ +PRInt32 CNavDTD::HandleStyleToken(CToken* aToken){ + NS_PRECONDITION(0!=aToken,kNullToken); + + CStyleToken* st = (CStyleToken*)(aToken); + PRInt32 result=kNoError; + return result; +} + + +/** + * Finds a tag handler for the given tag type, given in string. + * + * @update gess 4/2/98 + * @param aString contains name of tag to be handled + * @return valid tag handler (if found) or null + */ +void CNavDTD::DeleteTokenHandlers(void) { + int i=0; + for(i=eToken_unknown;i0) && (aTypeGetTokenType(); + if(typeHasOpenContainer(eHTMLTag_form) : PR_FALSE; +PRBool CNavDTD::CanContainFormElement(eHTMLTags aParent,eHTMLTags aChild) const { + PRBool result=(mParser) ? HasOpenContainer(eHTMLTag_form) : PR_FALSE; return result; } @@ -159,11 +807,11 @@ PRBool CNavDTD::CanContainFormElement(PRInt32 aParent,PRInt32 aChild) const { * @param aChild -- tag enum of child container * @return PR_TRUE if parent can contain child */ -PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { +PRBool CNavDTD::CanContain(eHTMLTags aParent,eHTMLTags aChild) const { PRBool result=PR_FALSE; - //tagset1 has 67 members...in case anybody cares + //tagset1 has 65 members... static char gTagSet1[]={ eHTMLTag_a, eHTMLTag_acronym, eHTMLTag_address, eHTMLTag_applet, eHTMLTag_bold, eHTMLTag_basefont, eHTMLTag_bdo, eHTMLTag_big, @@ -175,7 +823,7 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { eHTMLTag_hr, eHTMLTag_italic, eHTMLTag_iframe, eHTMLTag_img, eHTMLTag_input, eHTMLTag_isindex, - eHTMLTag_kbd, eHTMLTag_label, + eHTMLTag_kbd, eHTMLTag_label, eHTMLTag_listitem, eHTMLTag_map, eHTMLTag_menu, eHTMLTag_newline, eHTMLTag_nobr, eHTMLTag_noframes, eHTMLTag_noscript, eHTMLTag_object, eHTMLTag_ol, eHTMLTag_paragraph, eHTMLTag_pre, @@ -186,8 +834,6 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { eHTMLTag_textarea, eHTMLTag_tt, eHTMLTag_u, eHTMLTag_ul, eHTMLTag_userdefined, eHTMLTag_var, eHTMLTag_whitespace, //JUST ADDED! - eHTMLTag_spacer, - eHTMLTag_blink, 0}; //tagset2 has 44 members... @@ -205,7 +851,6 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { eHTMLTag_sub, eHTMLTag_sup, eHTMLTag_text, eHTMLTag_textarea, eHTMLTag_tt, eHTMLTag_u, eHTMLTag_userdefined, eHTMLTag_var, eHTMLTag_whitespace,//JUST ADDED! - eHTMLTag_spacer, 0}; //tagset3 has 57 members... @@ -230,7 +875,6 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { eHTMLTag_th, eHTMLTag_tt, eHTMLTag_u, eHTMLTag_userdefined, eHTMLTag_var, eHTMLTag_whitespace, //JUST ADDED! - eHTMLTag_spacer, 0}; //This hack code is here because we don't yet know what to do @@ -242,11 +886,10 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { if(0!=strchr(formElementTags,aChild)){ return CanContainFormElement(aParent,aChild); } + switch(aParent) { case eHTMLTag_a: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; - case eHTMLTag_acronym: result=PRBool(0!=strchr(gTagSet1,aChild)); break; @@ -280,7 +923,7 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { case eHTMLTag_big: case eHTMLTag_blink: case eHTMLTag_bold: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; + result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_blockquote: case eHTMLTag_body: @@ -299,7 +942,7 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_cite: case eHTMLTag_code: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; + result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_col: case eHTMLTag_colgroup: @@ -325,7 +968,7 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { break; //singletons can't contain anything... case eHTMLTag_em: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; + result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_fieldset: if(eHTMLTag_legend==aChild) @@ -334,8 +977,6 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { break; case eHTMLTag_font: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; - case eHTMLTag_form: result=PRBool(0!=strchr(gTagSet1,aChild)); break; @@ -392,7 +1033,7 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { case eHTMLTag_kbd: case eHTMLTag_label: case eHTMLTag_legend: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; + result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_layer: break; @@ -465,9 +1106,6 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { case eHTMLTag_quotation: result=PRBool(0!=strchr(gTagSet2,aChild)); break; - case eHTMLTag_strike: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; - case eHTMLTag_script: break; //unadorned script text... @@ -475,20 +1113,14 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { result=PR_TRUE; break; //for now, allow select to contain anything... case eHTMLTag_small: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; - case eHTMLTag_span: + case eHTMLTag_spell: + case eHTMLTag_strike: result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_style: break; //singletons can't contain other tags - case eHTMLTag_strong: - case eHTMLTag_samp: - case eHTMLTag_sub: - case eHTMLTag_sup: - result=PRBool(0!=strchr(gTagSet1,aChild)); break; - case eHTMLTag_table: { static char okTags[]={ @@ -529,10 +1161,8 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { case eHTMLTag_tt: case eHTMLTag_u: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; - case eHTMLTag_var: - result=PRBool(0!=strchr(gTagSet2,aChild)); break; + result=PRBool(0!=strchr(gTagSet1,aChild)); break; case eHTMLTag_userdefined: result=PR_TRUE; break; //XXX for now... @@ -554,7 +1184,7 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const { * @param aChild -- tag enum of child container * @return PR_TRUE if parent can contain child */ -PRBool CNavDTD::CanContainIndirect(PRInt32 aParent,PRInt32 aChild) const { +PRBool CNavDTD::CanContainIndirect(eHTMLTags aParent,eHTMLTags aChild) const { PRBool result=PR_FALSE; switch(aParent) { @@ -599,29 +1229,34 @@ PRBool CNavDTD::CanContainIndirect(PRInt32 aParent,PRInt32 aChild) const { * @param aTag -- tag to test for containership * @return PR_TRUE if given tag can contain other tags */ -PRBool CNavDTD::CanOmit(PRInt32 aParent,PRInt32 aChild) const { +PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const { PRBool result=PR_FALSE; //begin with some simple (and obvious) cases... - switch((eHTMLTags)aChild) { + switch(aChild) { case eHTMLTag_userdefined: case eHTMLTag_comment: result=PR_TRUE; break; + case eHTMLTag_html: + case eHTMLTag_body: + result=HasOpenContainer(aChild); //don't bother if they're already open... + break; + case eHTMLTag_button: case eHTMLTag_fieldset: case eHTMLTag_input: case eHTMLTag_isindex: case eHTMLTag_label: case eHTMLTag_legend: case eHTMLTag_select: case eHTMLTag_textarea: - if(PR_FALSE==mParser->HasOpenContainer(eHTMLTag_form)) + if(PR_FALSE==HasOpenContainer(eHTMLTag_form)) result=PR_TRUE; break; case eHTMLTag_newline: case eHTMLTag_whitespace: - switch((eHTMLTags)aParent) { + switch(aParent) { case eHTMLTag_html: case eHTMLTag_head: case eHTMLTag_title: case eHTMLTag_map: case eHTMLTag_tr: case eHTMLTag_table: @@ -653,6 +1288,22 @@ PRBool CNavDTD::CanOmit(PRInt32 aParent,PRInt32 aChild) const { return result; } + +/** + * + * @update gess6/16/98 + * @param + * @return + */ +PRBool IsCompatibleStyleTag(eHTMLTags aTag1,eHTMLTags aTag2) { + PRBool result=PR_FALSE; + + if(0!=strchr(gStyleTags,aTag1)) { + result=PRBool(0!=strchr(gStyleTags,aTag2)); + } + return result; +} + /** * This method gets called to determine whether a given * ENDtag can be omitted. Admittedly,this is a gross simplification. @@ -661,7 +1312,7 @@ PRBool CNavDTD::CanOmit(PRInt32 aParent,PRInt32 aChild) const { * @param aTag -- tag to test for containership * @return PR_TRUE if given tag can contain other tags */ -PRBool CNavDTD::CanOmitEndTag(PRInt32 aParent,PRInt32 aChild) const { +PRBool CNavDTD::CanOmitEndTag(eHTMLTags aParent,eHTMLTags aChild) const { PRBool result=PR_FALSE; //begin with some simple (and obvious) cases... @@ -672,26 +1323,6 @@ PRBool CNavDTD::CanOmitEndTag(PRInt32 aParent,PRInt32 aChild) const { result=PR_TRUE; break; - case eHTMLTag_h1: case eHTMLTag_h2: - case eHTMLTag_h3: case eHTMLTag_h4: - case eHTMLTag_h5: case eHTMLTag_h6: - { - if(0!=strchr(gHeadingTags,aParent)) - result=PR_FALSE; - //Actually, we probably need to walk the stack here... - else result=PR_TRUE; - } - break; - - case eHTMLTag_select: case eHTMLTag_option: - case eHTMLTag_button: case eHTMLTag_fieldset: - case eHTMLTag_input: case eHTMLTag_isindex: - case eHTMLTag_label: case eHTMLTag_legend: - case eHTMLTag_textarea: - if(PR_FALSE==mParser->HasOpenContainer(aChild)) - result=PR_TRUE; - break; - case eHTMLTag_newline: case eHTMLTag_whitespace: @@ -709,7 +1340,9 @@ PRBool CNavDTD::CanOmitEndTag(PRInt32 aParent,PRInt32 aChild) const { break; default: - result=(!mParser->HasOpenContainer(aChild)); + if(IsCompatibleStyleTag(aChild,(eHTMLTags)GetTopNode())) + result=PR_FALSE; + else result=(!HasOpenContainer(aChild)); break; } //switch return result; @@ -723,7 +1356,7 @@ PRBool CNavDTD::CanOmitEndTag(PRInt32 aParent,PRInt32 aChild) const { * @param aTag -- tag to test for containership * @return PR_TRUE if given tag can contain other tags */ -PRBool CNavDTD::IsContainer(PRInt32 aTag) const { +PRBool CNavDTD::IsContainer(eHTMLTags aTag) const { PRBool result=PR_FALSE; switch(aTag){ @@ -760,7 +1393,7 @@ PRBool CNavDTD::IsContainer(PRInt32 aTag) const { * @param aNode -- next node to be added to model * @return TRUE if ok, FALSE if error */ -PRInt32 CNavDTD::GetDefaultParentTagFor(PRInt32 aTag) const{ +eHTMLTags CNavDTD::GetDefaultParentTagFor(eHTMLTags aTag) const{ eHTMLTags result=eHTMLTag_unknown; switch(aTag) { @@ -830,30 +1463,6 @@ PRInt32 CNavDTD::GetDefaultParentTagFor(PRInt32 aTag) const{ } -/** - * This method gets called at various times by the parser - * whenever we want to verify a valid context stack. This - * method also gives us a hook to add debugging metrics. - * - * @update gess4/6/98 - * @param aStack[] array of ints (tokens) - * @param aCount number of elements in given array - * @return TRUE if stack is valid, else FALSE - */ -PRBool CNavDTD::VerifyContextVector(PRInt32* aVector,PRInt32 aCount) const { - PRBool result=PR_TRUE; - - if(aCount>1) { - for (int i = 0; i < aCount-1; i++) - if (!CanContain(aVector[i],aVector[i+1])) { - result = PR_FALSE; - break; - } - } - return result; -} - - /** * This method tries to design a context vector (without actually * changing our parser state) from the parent down to the @@ -866,7 +1475,7 @@ PRBool CNavDTD::VerifyContextVector(PRInt32* aVector,PRInt32 aCount) const { * @param aChild -- tag type of child * @return TRUE if propagation closes; false otherwise */ -PRBool CNavDTD::ForwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 aChildTag) const { +PRBool CNavDTD::ForwardPropagate(nsString& aVector,eHTMLTags aParentTag,eHTMLTags aChildTag) const { PRBool result=PR_FALSE; switch(aParentTag) { @@ -875,10 +1484,10 @@ PRBool CNavDTD::ForwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 aC static char tableTags[]={eHTMLTag_tr,eHTMLTag_td,0}; if(strchr(tableTags,aChildTag)) { //if you're here, we know we can correctly backward propagate. - result=BackwardPropagate(aVector,aParentTag,aChildTag); + return BackwardPropagate(aVector,aParentTag,aChildTag); } } - break; + //otherwise, intentionally fall through... case eHTMLTag_tr: if(PR_TRUE==CanContain(eHTMLTag_td,aChildTag)) { @@ -910,7 +1519,7 @@ PRBool CNavDTD::ForwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 aC * @param aChild -- tag type of child * @return TRUE if propagation closes; false otherwise */ -PRBool CNavDTD::BackwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 aChildTag) const { +PRBool CNavDTD::BackwardPropagate(nsString& aVector,eHTMLTags aParentTag,eHTMLTags aChildTag) const { PRBool result=PR_FALSE; eHTMLTags theParentTag=(eHTMLTags)aChildTag; @@ -931,5 +1540,1616 @@ PRBool CNavDTD::BackwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 a return PRBool(aParentTag==theParentTag); } +/** + * + * @update gess6/4/98 + * @param aTag is the id of the html container being opened + * @return 0 if all is well. + */ +PRInt32 CNavDTD::DidOpenContainer(eHTMLTags aTag,PRBool /*anExplicitOpen*/){ + PRInt32 result=0; + + switch (aTag) { + + case eHTMLTag_a: + case eHTMLTag_bold: + case eHTMLTag_big: + case eHTMLTag_blink: + case eHTMLTag_cite: + case eHTMLTag_em: + case eHTMLTag_font: + case eHTMLTag_italic: + case eHTMLTag_kbd: + case eHTMLTag_small: + case eHTMLTag_spell: + case eHTMLTag_strike: + case eHTMLTag_strong: + case eHTMLTag_sub: + case eHTMLTag_sup: + case eHTMLTag_tt: + case eHTMLTag_u: + case eHTMLTag_var: + break; + + default: + break; + } + + return result; +} + +/** + * + * @update gess6/4/98 + * @param + * @return + */ +PRInt32 CNavDTD::DidCloseContainer(eHTMLTags aTag,PRBool/*anExplicitClosure*/){ + PRInt32 result=0; + return result; +} +/** + * This method allows the caller to determine if a form + * element is currently open. + * + * @update gess 4/2/98 + * @param + * @return + */ +PRBool CNavDTD::HasOpenContainer(eHTMLTags aContainer) const { + PRBool result=PR_FALSE; + + switch(aContainer) { + case eHTMLTag_form: + result=mHasOpenForm; break; + + default: + result=(kNotFound!=GetTopmostIndexOf(aContainer)); break; + } + return result; +} + +/** + * This method retrieves the HTMLTag type of the topmost + * container on the stack. + * + * @update gess 4/2/98 + * @return tag id of topmost node in contextstack + */ +eHTMLTags CNavDTD::GetTopNode() const { + if(mContextStackPos) + return mContextStack[mContextStackPos-1]; + return eHTMLTag_unknown; +} + + +/** + * 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 CNavDTD::GetTopmostIndexOf(eHTMLTags aTag) const { + int i=0; + for(i=mContextStackPos-1;i>=0;i--){ + if(mContextStack[i]==aTag) + return i; + } + return kNotFound; +} + +/********************************************* + Here comes code that handles the interface + to our content sink. + *********************************************/ + + +/** + * It is with great trepidation that I offer this method (privately of course). + * The gets called whenever a container gets opened. This methods job is to + * take a look at the (transient) style stack, and open any style containers that + * are there. Of course, we shouldn't bother to open styles that are incompatible + * with our parent container. + * + * @update gess6/4/98 + * @param tag of the container just opened + * @return 0 (for now) + */ +PRInt32 CNavDTD::OpenTransientStyles(eHTMLTags aTag){ + PRInt32 result=0; + + if(0==strchr(gWhitespaceTags,aTag)){ + PRInt32 pos=0; + for(pos=0;posclose any style containers + * that are there. Of course, we shouldn't bother to open styles that are incompatible + * with our parent container. + * SEE THE TOP OF THIS FILE for more information about how the transient style stack works. + * + * @update gess6/4/98 + * @param tag of the container just opened + * @return 0 (for now) + */ +PRInt32 CNavDTD::CloseTransientStyles(eHTMLTags aTag){ + PRInt32 result=0; + + if((mStyleStackPos>0) && (mLeafBits[mContextStackPos-1])) { + if(0==strchr(gWhitespaceTags,aTag)){ + + result=CloseContainersTo(mStyleStack[0],PR_FALSE); + mLeafBits[mContextStackPos-1]=PR_FALSE; + + }//if + }//if + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * + * @update gess4/22/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenHTML(const nsIParserNode& aNode){ + NS_PRECONDITION(mContextStackPos >= 0, kInvalidTagStackPos); + + PRInt32 result=mSink->OpenHTML(aNode); + mContextStack[mContextStackPos++]=(eHTMLTags)aNode.GetNodeType(); + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseHTML(const nsIParserNode& aNode){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + PRInt32 result=mSink->CloseHTML(aNode); + mContextStack[--mContextStackPos]=eHTMLTag_unknown; + return result; +} + + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenHead(const nsIParserNode& aNode){ + mContextStack[mContextStackPos++]=eHTMLTag_head; + PRInt32 result=mSink->OpenHead(aNode); + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseHead(const nsIParserNode& aNode){ + PRInt32 result=mSink->CloseHead(aNode); + mContextStack[--mContextStackPos]=eHTMLTag_unknown; + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenBody(const nsIParserNode& aNode){ + NS_PRECONDITION(mContextStackPos >= 0, kInvalidTagStackPos); + + PRInt32 result=kNoError; + eHTMLTags topTag=(eHTMLTags)CNavDTD::GetTopNode(); + + if(eHTMLTag_html!=topTag) { + + //ok, there are two cases: + // 1. Nobody opened the html container + // 2. Someone left the head (or other) open + PRInt32 pos=GetTopmostIndexOf(eHTMLTag_html); + if(kNotFound!=pos) { + //if you're here, it means html is open, + //but some other tag(s) are in the way. + //So close other tag(s). + result=CloseContainersTo(pos+1,eHTMLTag_body,PR_TRUE); + } else { + //if you're here, it means that there is + //no HTML tag in document. Let's open it. + + result=CloseContainersTo(0,eHTMLTag_html,PR_TRUE); //close current stack containers. + + CHTMLToken token(gEmpty); + nsCParserNode htmlNode(&token); + + token.SetHTMLTag(eHTMLTag_html); //open the html container... + result=OpenHTML(htmlNode); + } + } + + if(kNoError==result) { + result=mSink->OpenBody(aNode); + mContextStack[mContextStackPos++]=(eHTMLTags)aNode.GetNodeType(); + } + return result; +} + +/** + * This method does two things: 1st, help close + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseBody(const nsIParserNode& aNode){ + NS_PRECONDITION(mContextStackPos >= 0, kInvalidTagStackPos); + PRInt32 result=mSink->CloseBody(aNode); + mContextStack[--mContextStackPos]=eHTMLTag_unknown; + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenForm(const nsIParserNode& aNode){ + if(mHasOpenForm) + CloseForm(aNode); + PRInt32 result=mSink->OpenForm(aNode); + if(kNoError==result) + mHasOpenForm=PR_TRUE; + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseForm(const nsIParserNode& aNode){ + PRInt32 result=kNoError; + if(mHasOpenForm) { + mHasOpenForm=PR_FALSE; + result=mSink->CloseForm(aNode); + } + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenMap(const nsIParserNode& aNode){ + if(mHasOpenMap) + CloseMap(aNode); + + //NOTE: We need to change to method so that it opens a MAP, + // instead of a FORM. This was copy/paste coding at its best. + + PRInt32 result=mSink->OpenForm(aNode); + if(kNoError==result) + mHasOpenMap=PR_TRUE; + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseMap(const nsIParserNode& aNode){ + PRInt32 result=kNoError; + if(mHasOpenMap) { + mHasOpenMap=PR_FALSE; + + //NOTE: We need to change to method so that it closes a MAP, + // instead of a FORM. This was copy/paste coding at its best. + + result=mSink->CloseForm(aNode); + } + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenFrameset(const nsIParserNode& aNode){ + NS_PRECONDITION(mContextStackPos >= 0, kInvalidTagStackPos); + PRInt32 result=mSink->OpenFrameset(aNode); + mContextStack[mContextStackPos++]=(eHTMLTags)aNode.GetNodeType(); + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseFrameset(const nsIParserNode& aNode){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + PRInt32 result=mSink->CloseFrameset(aNode); + mContextStack[--mContextStackPos]=eHTMLTag_unknown; + return result; +} + + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::OpenContainer(const nsIParserNode& aNode,PRBool aUpdateStyleStack){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + + PRInt32 result=kNoError; + eHTMLTags nodeType=(eHTMLTags)aNode.GetNodeType(); + +// CloseTransientStyles(nodeType); + + switch(nodeType) { + + case eHTMLTag_html: + result=OpenHTML(aNode); break; + + case eHTMLTag_body: + result=OpenBody(aNode); break; + + case eHTMLTag_style: + case eHTMLTag_textarea: + case eHTMLTag_head: + case eHTMLTag_title: + break; + + case eHTMLTag_form: + result=OpenForm(aNode); break; + + default: + result=mSink->OpenContainer(aNode); + mContextStack[mContextStackPos++]=nodeType; + break; + } + + if((kNoError==result) && (PR_TRUE==aUpdateStyleStack)){ + UpdateStyleStackForOpenTag(nodeType,nodeType); + } + + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be removed from our model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseContainer(const nsIParserNode& aNode,eHTMLTags aTag,PRBool aUpdateStyles){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + PRInt32 result=kNoError; //was false + eHTMLTags nodeType=(eHTMLTags)aNode.GetNodeType(); + + //XXX Hack! We know this is wrong, but it works + //for the general case until we get it right. + switch(nodeType) { + + case eHTMLTag_html: + result=CloseHTML(aNode); break; + + case eHTMLTag_style: + case eHTMLTag_textarea: + break; + + case eHTMLTag_head: + //result=CloseHead(aNode); + break; + + case eHTMLTag_body: + result=CloseBody(aNode); break; + + case eHTMLTag_form: + result=CloseForm(aNode); break; + + case eHTMLTag_title: + default: + result=mSink->CloseContainer(aNode); + mContextStack[--mContextStackPos]=eHTMLTag_unknown; + break; + } + + mLeafBits[mContextStackPos]=PR_FALSE; + if((kNoError==result) && (PR_TRUE==aUpdateStyles)){ + UpdateStyleStackForCloseTag(nodeType,aTag); + } + + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseContainersTo(PRInt32 anIndex,eHTMLTags aTag,PRBool aUpdateStyles){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + PRInt32 result=kNoError; + + CEndToken aToken(gEmpty); + nsCParserNode theNode(&aToken); + + if((anIndex=0)) { + while(mContextStackPos>anIndex) { + eHTMLTags theTag=mContextStack[mContextStackPos-1]; + aToken.SetHTMLTag(theTag); + result=CloseContainer(theNode,aTag,aUpdateStyles); + } + } + return result; +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseContainersTo(eHTMLTags aTag,PRBool aUpdateStyles){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + + PRInt32 pos=GetTopmostIndexOf(aTag); + + if(kNotFound!=pos) { + //the tag is indeed open, so close it. + return CloseContainersTo(pos,aTag,aUpdateStyles); + } + + eHTMLTags theTopTag=(eHTMLTags)GetTopNode(); + if(IsCompatibleStyleTag(aTag,theTopTag)) { + //if you're here, it's because we're trying to close one style tag, + //but a different one is actually open. Because this is NAV4x + //compatibililty mode, we must close the one that's really open. + aTag=theTopTag; + pos=GetTopmostIndexOf(aTag); + if(kNotFound!=pos) { + //the tag is indeed open, so close it. + return CloseContainersTo(pos,aTag,aUpdateStyles); + } + } + + PRInt32 result=kNoError; + eHTMLTags theParentTag=GetDefaultParentTagFor(aTag); + pos=GetTopmostIndexOf(theParentTag); + if(kNotFound!=pos) { + //the parent container is open, so close it instead + result=CloseContainersTo(pos+1,aTag,aUpdateStyles); + } + return result; +} + +/** + * This method causes the topmost container on the stack + * to be closed. + * @update gess4/6/98 + * @see CloseContainer() + * @param + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::CloseTopmostContainer(){ + NS_PRECONDITION(mContextStackPos > 0, kInvalidTagStackPos); + + CEndToken aToken(gEmpty); + eHTMLTags theTag=(eHTMLTags)mContextStack[mContextStackPos-1]; + aToken.SetHTMLTag(theTag); + nsCParserNode theNode(&aToken); + return CloseContainer(theNode,theTag,PR_TRUE); +} + +/** + * This method does two things: 1st, help construct + * our own internal model of the content-stack; and + * 2nd, pass this message on to the sink. + * @update gess4/6/98 + * @param aNode -- next node to be added to model + * @return TRUE if ok, FALSE if error + */ +PRInt32 CNavDTD::AddLeaf(const nsIParserNode& aNode){ + PRInt32 result=mSink->AddLeaf(aNode); + return result; +} + +/** + * This method gets called to create a valid context stack + * for the given child. We compare the current stack to the + * default needs of the child, and push new guys onto the + * stack until the child can be properly placed. + * + * @update gess 4/8/98 + * @param aChildTag is the child for whom we need to + * create a new context vector + * @return true if we succeeded, otherwise false + */ +PRInt32 CNavDTD::CreateContextStackFor(eHTMLTags aChildTag){ + nsAutoString theVector; + + PRInt32 result=kNoError; + PRInt32 pos=0; + PRInt32 cnt=0; + eHTMLTags theTop=GetTopNode(); + + if(PR_TRUE==ForwardPropagate(theVector,theTop,aChildTag)){ + //add code here to build up context stack based on forward propagated context vector... + pos=0; + cnt=theVector.Length()-1; + if(mContextStack[mContextStackPos-1]==theVector[cnt]) + result=kNoError; + else result=kContextMismatch; + } + else { + PRBool tempResult; + if(eHTMLTag_unknown!=theTop) { + tempResult=BackwardPropagate(theVector,theTop,aChildTag); + if(eHTMLTag_html!=theTop) + BackwardPropagate(theVector,eHTMLTag_html,theTop); + } + else tempResult=BackwardPropagate(theVector,eHTMLTag_html,aChildTag); + + if(PR_TRUE==tempResult) { + + //propagation worked, so pop unwanted containers, push new ones, then exit... + pos=0; + cnt=theVector.Length(); + result=kNoError; + while(pos