diff --git a/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp index 0758053c0a7..2217af19cbc 100644 --- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -551,115 +551,6 @@ GetEntityTerminator(nsString& aSource,PRUnichar& aChar,PRInt32 aStartOffset=0) { return -1; } - -void HTMLContentSink::ReduceEntities(nsString& aString) { - if (mParser) { - nsCOMPtr dtd; - - nsresult rv = mParser->GetDTD(getter_AddRefs(dtd)); - - if (NS_SUCCEEDED(rv)) { - - // XXX Note: as coded today, this will only convert well formed - // entities. This may not be compatible enough. - // XXX there is a table in navigator that translates some numeric entities - // should we be doing that? If so then it needs to live in two places (bad) - // so we should add a translate numeric entity method from the parser... - - nsAutoString theOutString; - nsAutoString theNCRStr; - - PRInt32 theLen=aString.Length(); - PRInt32 theAmpPos = aString.FindChar('&'); - PRInt32 theStartPos=0; - PRInt32 theTermPos=-1; - PRUnichar theTermChar='\0'; - const PRUnichar *theBuf=aString.GetUnicode(); - - nsDTDMode mode; - mHTMLDocument->GetDTDMode(mode); - - while(-1!=theAmpPos) { - - if(theStartPostheAmpPos+1) ? aString.CharAt(theAmpPos+1) : '\0'; - PRUnichar theEntity=0; - PRInt32 theErr=0; - PRInt32 theNCRValue=0; - - switch(theChar) { - case '#': - theNCRValue=theNCRStr.ToInteger(&theErr,kAutoDetect); - theEntity=PRUnichar(theNCRValue); - break; - case '{': - //XXX Write ME! - break; - default: - if(nsCRT::IsAsciiAlpha(theChar)) { - dtd->ConvertEntityToUnicode(theNCRStr, &theNCRValue); - if (eDTDMode_strict!=mode) { - // XXX - Hack - Nav. does not support entity values > 255 - // on the other hand IE supports entity values > 255 with a - // semicolon. I think it's reasonable to emulate IE than Nav. - if(theNCRValue>255 && theTermChar!=';') break; - } - if(-1!=theNCRValue) { - theEntity=PRUnichar(theNCRValue); - } - } - break; - } //switch - - if(theEntity) { - theOutString.Append(theEntity); - if(theTermChar!='\0' && theTermChar!='&' && theTermChar!=';') { - theOutString.Append(theTermChar); - } - } - else { - //what looked like an entity is not really one. - //so let's copy the ncrstring back to the output string - if(theTermChar!='&') { theTermPos++; } - aString.Mid(theNCRStr,theAmpPos,theTermPos-theAmpPos); - theOutString.Append(theNCRStr); - } - theAmpPos = aString.FindChar('&',PR_FALSE,theTermPos); - } //while - - if(0CompressWhitespace(PR_TRUE, PR_TRUE); nsCOMPtr domDoc(do_QueryInterface(mHTMLDocument)); diff --git a/content/html/document/src/nsHTMLFragmentContentSink.cpp b/content/html/document/src/nsHTMLFragmentContentSink.cpp index b5df48cd06f..0ffa2f14331 100644 --- a/content/html/document/src/nsHTMLFragmentContentSink.cpp +++ b/content/html/document/src/nsHTMLFragmentContentSink.cpp @@ -860,117 +860,6 @@ nsHTMLFragmentContentSink::GetAttributeValueAt(const nsIParserNode& aNode, } } } - - if (mParser) { - nsCOMPtr dtd; - - nsresult rv = mParser->GetDTD(getter_AddRefs(dtd)); - - if (NS_SUCCEEDED(rv)) { - // Reduce any entities - // XXX Note: as coded today, this will only convert well formed - // entities. This may not be compatible enough. - // XXX there is a table in navigator that translates some numeric entities - // should we be doing that? If so then it needs to live in two places (bad) - // so we should add a translate numeric entity method from the parser... - char cbuf[100]; - PRInt32 indx = 0; - while (indx < aResult.Length()) { - // If we have the start of an entity (and it's not at the end of - // our string) then translate the entity into it's unicode value. - if ((aResult.CharAt(indx++) == '&') && (indx < aResult.Length())) { - PRInt32 start = indx - 1; - PRUnichar e = aResult.CharAt(indx); - if (e == '#') { - // Convert a numeric character reference - indx++; - char* cp = cbuf; - char* limit = cp + sizeof(cbuf) - 1; - PRBool ok = PR_FALSE; - PRInt32 slen = aResult.Length(); - while ((indx < slen) && (cp < limit)) { - e = aResult.CharAt(indx); - if (e == ';') { - indx++; - ok = PR_TRUE; - break; - } - if ((e >= '0') && (e <= '9')) { - *cp++ = char(e); - indx++; - continue; - } - break; - } - if (!ok || (cp == cbuf)) { - continue; - } - *cp = '\0'; - if (cp - cbuf > 5) { - continue; - } - PRInt32 ch = PRInt32( ::atoi(cbuf) ); - if (ch > 65535) { - continue; - } - - // Remove entity from string and replace it with the integer - // value. - aResult.Cut(start, indx - start); - aResult.Insert(PRUnichar(ch), start); - indx = start + 1; - } - else if (((e >= 'A') && (e <= 'Z')) || - ((e >= 'a') && (e <= 'z'))) { - // Convert a named entity - indx++; - char* cp = cbuf; - char* limit = cp + sizeof(cbuf) - 1; - *cp++ = char(e); - PRBool ok = PR_FALSE; - PRInt32 slen = aResult.Length(); - while ((indx < slen) && (cp < limit)) { - e = aResult.CharAt(indx); - if (e == ';') { - indx++; - ok = PR_TRUE; - break; - } - if (((e >= '0') && (e <= '9')) || - ((e >= 'A') && (e <= 'Z')) || - ((e >= 'a') && (e <= 'z'))) { - *cp++ = char(e); - indx++; - continue; - } - break; - } - if (!ok || (cp == cbuf)) { - continue; - } - *cp = '\0'; - PRInt32 ch; - nsAutoString str; str.AssignWithConversion(cbuf); - dtd->ConvertEntityToUnicode(str, &ch); - - if (ch < 0) { - continue; - } - - // Remove entity from string and replace it with the integer - // value. - aResult.Cut(start, indx - start); - aResult.Insert(PRUnichar(ch), start); - indx = start + 1; - } - else if (e == '{') { - // Convert a script entity - // XXX write me! - } - } - } - } - } } // XXX Code copied from nsHTMLContentSink. It should be shared. diff --git a/htmlparser/src/CNavDTD.cpp b/htmlparser/src/CNavDTD.cpp index df96e56b787..6621c1bd9e7 100644 --- a/htmlparser/src/CNavDTD.cpp +++ b/htmlparser/src/CNavDTD.cpp @@ -189,26 +189,6 @@ CNavDTD::CNavDTD() : nsIDTD(), } -/** - * This method recycles the nodes on a nodestack. - * NOTE: Unlike recycleNode(), we force the usecount - * to 0 of all nodes, then force them to recycle. - * @update gess1/8/99 - * @param aNodeStack - * @return nothing - */ -void CNavDTD::RecycleNodes(nsEntryStack *aNodeStack) { - if(aNodeStack) { - PRInt32 theCount=aNodeStack->mCount; - PRInt32 theIndex=0; - - for(theIndex=0;theIndexNodeAt(theIndex); - IF_FREE(node, &mNodeAllocator); - } - } -} - /** * * @update gess1/8/99 @@ -631,12 +611,9 @@ nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParse nsEntryStack *theChildStyles=0; nsCParserNode* theNode=mBodyContext->Pop(theChildStyles); - if(theNode) { - if(theChildStyles) { - delete theChildStyles; - } - IF_FREE(theNode, &mNodeAllocator); - } + + IF_DELETE(theChildStyles,&mNodeAllocator); + IF_FREE(theNode, &mNodeAllocator); } } @@ -2926,8 +2903,22 @@ nsresult CNavDTD::OpenTransientStyles(eHTMLTags aChildTag){ if(1==theNode->mUseCount) { eHTMLTags theNodeTag=(eHTMLTags)theNode->GetNodeType(); if(gHTMLElements[theNodeTag].CanContain(aChildTag)) { - theEntry->mParent=theStack; //we do this too, because this entry differs from the new one we're pushing... - result=OpenContainer(theNode,theNodeTag,PR_FALSE,theStack); + theEntry->mParent = theStack; //we do this too, because this entry differs from the new one we're pushing... + if(gHTMLElements[mBodyContext->Last()].IsMemberOf(kHeading)) { + // Bug 77352 + // The style system needs to identify residual style tags + // within heading tags so that heading tags' size can take + // precedence over the residual style tags' size info.. + // *Note: Make sure that this attribute is transient since it + // should not get carried over to cases other than heading. + CAttributeToken theAttrToken(NS_LITERAL_STRING("_moz-rs-heading"),NS_LITERAL_STRING("")); + theNode->AddAttribute(&theAttrToken); + result = OpenContainer(theNode,theNodeTag,PR_FALSE,theStack); + theNode->PopAttributeToken(); + } + else { + result = OpenContainer(theNode,theNodeTag,PR_FALSE,theStack); + } } else { //if the node tag can't contain the child tag, then remove the child tag from the style stack @@ -3658,10 +3649,7 @@ nsresult CNavDTD::CloseContainersTo(PRInt32 anIndex,eHTMLTags aTarget, PRBool aC mBodyContext->PushStyles(theChildStyleStack); } else{ - //add code here to recycle styles... - RecycleNodes(theChildStyleStack); - delete theChildStyleStack; // XXX try to recycle this... - theChildStyleStack=0; + IF_DELETE(theChildStyleStack,&mNodeAllocator); } } else if (0==theNode->mUseCount) { @@ -3687,9 +3675,7 @@ nsresult CNavDTD::CloseContainersTo(PRInt32 anIndex,eHTMLTags aTarget, PRBool aC //the tag is not a style tag... if(theChildStyleStack) { if(theStyleDoesntLeakOut) { - RecycleNodes(theChildStyleStack); - delete theChildStyleStack; // XXX try to recycle this... - theChildStyleStack=0; + IF_DELETE(theChildStyleStack,&mNodeAllocator); } else mBodyContext->PushStyles(theChildStyleStack); } @@ -3726,7 +3712,8 @@ nsresult CNavDTD::CloseContainersTo(eHTMLTags aTarget,PRBool aClosedByStartTag){ PRBool theTagIsSynonymous=((nsHTMLElement::IsResidualStyleTag(aTarget)) && (nsHTMLElement::IsResidualStyleTag(theTopTag))); if(!theTagIsSynonymous){ - theTagIsSynonymous=((nsHTMLElement::IsHeadingTag(aTarget)) && (nsHTMLElement::IsHeadingTag(theTopTag))); + theTagIsSynonymous=(gHTMLElements[aTarget].IsMemberOf(kHeading) && + gHTMLElements[theTopTag].IsMemberOf(kHeading)); } if(theTagIsSynonymous) { diff --git a/htmlparser/src/CNavDTD.h b/htmlparser/src/CNavDTD.h index b740511cc28..9bb624aeeb5 100644 --- a/htmlparser/src/CNavDTD.h +++ b/htmlparser/src/CNavDTD.h @@ -490,7 +490,6 @@ protected: nsresult HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags aParent,nsIParserNode *aNode); nsresult HandleSavedTokens(PRInt32 anIndex); nsresult HandleKeyGen(nsIParserNode *aNode); - void RecycleNodes(nsEntryStack *aNodeStack); nsDeque mMisplacedContent; nsDeque mSkippedContent; diff --git a/htmlparser/src/nsDTDUtils.cpp b/htmlparser/src/nsDTDUtils.cpp index 68799060cb7..fcccbe937a8 100644 --- a/htmlparser/src/nsDTDUtils.cpp +++ b/htmlparser/src/nsDTDUtils.cpp @@ -83,6 +83,23 @@ nsEntryStack::~nsEntryStack() { mCount=mCapacity=0; } +/** + * Release all objects in the entry stack + */ +void +nsEntryStack::ReleaseAll(nsNodeAllocator* aNodeAllocator) +{ + NS_WARN_IF_FALSE(aNodeAllocator,"no allocator? - potential leak!"); + + if(aNodeAllocator) { + NS_WARN_IF_FALSE(mCount >= 0,"count should not be negative"); + while(mCount > 0) { + nsCParserNode* node=this->Pop(); + IF_FREE(node,aNodeAllocator); + } + } +} + /** * Resets state of stack to be empty. * @update harishd 04/04/99 @@ -1045,10 +1062,7 @@ void nsDTDContext::PushStyles(nsEntryStack *aStyles){ // If you're here it means that we have hit the rock bottom // ,of the stack, and there's no need to handle anymore styles. // Fix for bug 29048 - nsCParserNode* theNode=aStyles->Pop(); - IF_HOLD(theNode); - delete aStyles; - aStyles=0; + IF_DELETE(aStyles,mNodeAllocator); } }//if(aStyles) } diff --git a/htmlparser/src/nsDTDUtils.h b/htmlparser/src/nsDTDUtils.h index 5c154cd6d10..66480905d1c 100644 --- a/htmlparser/src/nsDTDUtils.h +++ b/htmlparser/src/nsDTDUtils.h @@ -45,8 +45,31 @@ #include "nsFixedSizeAllocator.h" #include "nsVoidArray.h" -#define IF_HOLD(_ptr) if(_ptr) { _ptr->AddRef(); } -#define IF_FREE(_ptr, _allocator) if(_ptr) { _ptr->Release((_allocator)->GetArenaPool()); _ptr=0; } // recycles _ptr +#define IF_HOLD(_ptr) \ + PR_BEGIN_MACRO \ + if(_ptr) { \ + _ptr->AddRef(); \ + } \ + PR_END_MACRO + +// recycles _ptr +#define IF_FREE(_ptr, _allocator) \ + PR_BEGIN_MACRO \ + if(_ptr) { \ + _ptr->Release((_allocator)->GetArenaPool()); \ + _ptr=0; \ + } \ + PR_END_MACRO + +// release objects and destroy _ptr +#define IF_DELETE(_ptr, _allocator) \ + PR_BEGIN_MACRO \ + if(_ptr) { \ + _ptr->ReleaseAll(_allocator); \ + delete(_ptr); \ + _ptr=0; \ + } \ + PR_END_MACRO class nsIParserNode; class nsCParserNode; @@ -73,6 +96,7 @@ struct nsTagEntry { }; class nsEntryStack { + public: nsEntryStack(); ~nsEntryStack(); @@ -91,6 +115,11 @@ public: eHTMLTags Last() const; void Empty(void); + /* + * Release all objects in the entry stack + */ + void ReleaseAll(nsNodeAllocator* aNodeAllocator); + /** * Find the first instance of given tag on the stack. * @update gess 12/14/99 diff --git a/htmlparser/src/nsElementTable.cpp b/htmlparser/src/nsElementTable.cpp index 958986ca0d9..b04398c98ef 100644 --- a/htmlparser/src/nsElementTable.cpp +++ b/htmlparser/src/nsElementTable.cpp @@ -104,7 +104,7 @@ TagList gULKids={2,{eHTMLTag_li,eHTMLTag_p}}; //********************************************************************************************* TagList gRootTags={4,{eHTMLTag_body,eHTMLTag_td,eHTMLTag_table,eHTMLTag_applet}}; -TagList gTableRootTags={7,{eHTMLTag_applet,eHTMLTag_body,eHTMLTag_dl,eHTMLTag_ol,eHTMLTag_td,eHTMLTag_th,eHTMLTag_ul}}; +TagList gTableRootTags={6,{eHTMLTag_applet,eHTMLTag_body,eHTMLTag_dl,eHTMLTag_ol,eHTMLTag_td,eHTMLTag_th}}; TagList gHTMLRootTags={1,{eHTMLTag_unknown}}; TagList gLIRootTags={8,{eHTMLTag_ul,eHTMLTag_ol,eHTMLTag_dir,eHTMLTag_menu,eHTMLTag_p,eHTMLTag_body,eHTMLTag_td,eHTMLTag_th}}; @@ -1956,17 +1956,6 @@ PRBool nsHTMLElement::IsResidualStyleTag(eHTMLTags aChild) { return result; } -/** - * - * @update gess12/13/98 - * @param - * @return - */ -PRBool nsHTMLElement::IsHeadingTag(eHTMLTags aChild) { - return FindTagInSet(aChild,gHeadingTags.mTags,gHeadingTags.mCount); -} - - /** * * @update gess12/13/98 diff --git a/htmlparser/src/nsElementTable.h b/htmlparser/src/nsElementTable.h index b6af72e5056..eb376f57886 100644 --- a/htmlparser/src/nsElementTable.h +++ b/htmlparser/src/nsElementTable.h @@ -209,7 +209,6 @@ struct nsHTMLElement { static PRBool CanContain(eHTMLTags aParent,eHTMLTags aChild); static PRBool IsContainer(eHTMLTags aTag) ; static PRBool IsResidualStyleTag(eHTMLTags aTag) ; - static PRBool IsHeadingTag(eHTMLTags aTag) ; static PRBool IsTextTag(eHTMLTags aTag); static PRBool IsWhitespaceTag(eHTMLTags aTag); diff --git a/htmlparser/src/nsHTMLTokenizer.cpp b/htmlparser/src/nsHTMLTokenizer.cpp index d6dd2eaba70..b54d09d9dfe 100644 --- a/htmlparser/src/nsHTMLTokenizer.cpp +++ b/htmlparser/src/nsHTMLTokenizer.cpp @@ -28,7 +28,6 @@ */ #include "nsHTMLTokenizer.h" -#include "nsParser.h" #include "nsScanner.h" #include "nsElementTable.h" #include "nsHTMLEntities.h" @@ -85,12 +84,17 @@ nsresult nsHTMLTokenizer::QueryInterface(const nsIID& aIID, void** aInstancePtr) * @return NS_xxx error result */ -NS_HTMLPARS nsresult NS_NewHTMLTokenizer(nsITokenizer** aInstancePtrResult,PRInt32 aMode,eParserDocType aDocType, eParserCommands aCommand) { +NS_HTMLPARS +nsresult NS_NewHTMLTokenizer(nsITokenizer** aInstancePtrResult, + PRInt32 aFlag, + eParserDocType aDocType, + eParserCommands aCommand) +{ NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } - nsHTMLTokenizer* it = new nsHTMLTokenizer(aMode,aDocType,aCommand); + nsHTMLTokenizer* it = new nsHTMLTokenizer(aFlag,aDocType,aCommand); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } @@ -112,13 +116,45 @@ NS_IMPL_RELEASE(nsHTMLTokenizer) nsHTMLTokenizer::nsHTMLTokenizer(PRInt32 aParseMode, eParserDocType aDocType, eParserCommands aCommand) : - nsITokenizer(), mTokenDeque(0), mParseMode(aParseMode) + nsITokenizer(), mTokenDeque(0) { NS_INIT_REFCNT(); - mDoXMLEmptyTags=((eDTDMode_strict==aParseMode) || (eDTDMode_transitional==aParseMode)); - mDocType=aDocType; + + if (aParseMode==eDTDMode_strict) { + mFlags = NS_IPARSER_FLAG_STRICT_MODE; + } + else if (aParseMode==eDTDMode_transitional) { + mFlags = NS_IPARSER_FLAG_TRANSITIONAL_MODE; + } + else if (aParseMode==eDTDMode_quirks) { + mFlags = NS_IPARSER_FLAG_QUIRKS_MODE; + } + else if (aParseMode==eDTDMode_autodetect) { + mFlags = NS_IPARSER_FLAG_AUTO_DETECT_MODE; + } + else { + mFlags = NS_IPARSER_FLAG_UNKNOWN_MODE; + } + + if (aDocType==ePlainText) { + mFlags |= NS_IPARSER_FLAG_PLAIN_TEXT; + } + else if (aDocType==eXMLText) { + mFlags |= NS_IPARSER_FLAG_XML_TEXT; + } + else if (aDocType==eXHTMLText) { + mFlags |= NS_IPARSER_FLAG_XHTML_TEXT; + } + else if (aDocType==eHTML3Text) { + mFlags |= NS_IPARSER_FLAG_HTML3_TEXT; + } + else if (aDocType==eHTML4Text) { + mFlags |= NS_IPARSER_FLAG_HTML4_TEXT; + } + + mFlags |= (aCommand==eViewSource)? NS_IPARSER_FLAG_VIEW_SOURCE:NS_IPARSER_FLAG_VIEW_NORMAL; + mRecordTrailingContent=PR_FALSE; - mParserCommand=aCommand; mTokenAllocator=nsnull; mTokenScanPos=0; } @@ -448,7 +484,7 @@ nsresult nsHTMLTokenizer::ConsumeToken(nsScanner& aScanner,PRBool& aFlushTokens) case NS_OK: default: - if(ePlainText!=mDocType) { + if(!(mFlags & NS_IPARSER_FLAG_PLAIN_TEXT)) { if(kLessThan==theChar) { return ConsumeTag(theChar,theToken,aScanner,aFlushTokens); } @@ -505,7 +541,7 @@ nsresult nsHTMLTokenizer::ConsumeTag(PRUnichar aChar,CToken*& aToken,nsScanner& result=aScanner.Peek(theNextChar, 1); if(NS_OK==result) { // xml allow non ASCII tag name, consume as end tag. need to make xml view source work - PRBool isXML=((eXMLText==mDocType) || (eXHTMLText==mDocType)); + PRBool isXML=(mFlags & (NS_IPARSER_FLAG_XML_TEXT | NS_IPARSER_FLAG_XHTML_TEXT)); if(nsCRT::IsAsciiAlpha(theNextChar)||(kGreaterThan==theNextChar)|| (isXML && (! nsCRT::IsAscii(theNextChar)))) { result=ConsumeEndTag(aChar,aToken,aScanner); @@ -571,7 +607,7 @@ nsresult nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar,CStartToken* aToken, while((!done) && (result==NS_OK)) { CAttributeToken* theToken= NS_STATIC_CAST(CAttributeToken*, theAllocator->CreateTokenOfType(eToken_attribute,eHTMLTag_unknown)); if(theToken){ - result=theToken->Consume(aChar,aScanner,PRBool(eViewSource==mParserCommand)); //tell new token to finish consuming text... + result=theToken->Consume(aChar,aScanner,mFlags); //tell new token to finish consuming text... //Much as I hate to do this, here's some special case code. //This handles the case of empty-tags in XML. Our last @@ -585,7 +621,7 @@ nsresult nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar,CStartToken* aToken, // support XML like syntax to fix bugs like 44186 if(!key.IsEmpty() && kForwardSlash==key.First() && text.IsEmpty()) { aToken->SetEmpty(PR_TRUE); - isUsableAttr=!mDoXMLEmptyTags; + isUsableAttr = !(mFlags & (NS_IPARSER_FLAG_STRICT_MODE|NS_IPARSER_FLAG_TRANSITIONAL_MODE)); } if(isUsableAttr) { theAttrCount++; @@ -655,8 +691,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan nsReadingIterator origin; aScanner.CurrentPosition(origin); - PRBool isHTML=((eHTML3Text==mDocType) || (eHTML4Text==mDocType)); - result= aToken->Consume(aChar,aScanner,isHTML); //tell new token to finish consuming text... + result= aToken->Consume(aChar,aScanner,mFlags); //tell new token to finish consuming text... if(NS_SUCCEEDED(result)) { @@ -668,7 +703,12 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan PRBool theTagHasAttributes=PR_FALSE; nsReadingIterator start, end; if(NS_OK==result) { - result=(eViewSource==mParserCommand) ? aScanner.ReadWhitespace(start, end) : aScanner.SkipWhitespace(); + if (mFlags & NS_IPARSER_FLAG_VIEW_SOURCE) { + result = aScanner.ReadWhitespace(start, end); + } + else { + result = aScanner.SkipWhitespace(); + } aToken->mNewlineCount += aScanner.GetNewlinesSkipped(); if(NS_OK==result) { result=aScanner.Peek(aChar); @@ -686,7 +726,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan CStartToken* theStartToken=NS_STATIC_CAST(CStartToken*,aToken); if(theTagHasAttributes) { - if (eViewSource==mParserCommand) { + if (mFlags & NS_IPARSER_FLAG_VIEW_SOURCE) { // Since we conserve whitespace in view-source mode, // go back to the beginning of the whitespace section // and let the first attribute grab it. @@ -719,7 +759,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan CToken* text=theAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text); CTextToken* textToken=NS_STATIC_CAST(CTextToken*,text); - result=textToken->ConsumeUntil(0,theTag!=eHTMLTag_script,aScanner,endText,mParseMode,aFlushTokens); //tell new token to finish consuming text... + result=textToken->ConsumeUntil(0,theTag!=eHTMLTag_script,aScanner,endText,mFlags,aFlushTokens); //tell new token to finish consuming text... // Fix bug 44186 // Support XML like syntax, i.e., @@ -770,8 +810,7 @@ nsresult nsHTMLTokenizer::ConsumeEndTag(PRUnichar aChar,CToken*& aToken,nsScanne nsresult result=NS_OK; if(aToken) { - PRBool isHTML=((eHTML3Text==mDocType) || (eHTML4Text==mDocType)); - result= aToken->Consume(aChar,aScanner,isHTML); //tell new token to finish consuming text... + result= aToken->Consume(aChar,aScanner,mFlags); //tell new token to finish consuming text... AddToken(aToken,result,&mTokenDeque,theAllocator); if(NS_SUCCEEDED(result)) { @@ -810,7 +849,7 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne // Get the first entity character aScanner.GetChar(theChar); - result = aToken->Consume(theChar,aScanner,mParseMode); //tell new token to finish consuming text... + result = aToken->Consume(theChar,aScanner,mFlags); //tell new token to finish consuming text... } else if(kHashsign==theChar) { // Get the "&" @@ -819,7 +858,7 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne // Get the first numerical entity character aScanner.GetChar(theChar); - result=aToken->Consume(theChar,aScanner,mParseMode); + result=aToken->Consume(theChar,aScanner,mFlags); } else { //oops, we're actually looking at plain text... @@ -854,7 +893,7 @@ nsresult nsHTMLTokenizer::ConsumeWhitespace(PRUnichar aChar,CToken*& aToken,nsSc aToken = theAllocator->CreateTokenOfType(eToken_whitespace,eHTMLTag_whitespace); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -878,7 +917,7 @@ nsresult nsHTMLTokenizer::ConsumeComment(PRUnichar aChar,CToken*& aToken,nsScann aToken = theAllocator->CreateTokenOfType(eToken_comment,eHTMLTag_comment); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -900,7 +939,7 @@ nsresult nsHTMLTokenizer::ConsumeText(CToken*& aToken,nsScanner& aScanner){ CTextToken* theToken = (CTextToken*)theAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text); if(theToken) { PRUnichar ch=0; - result=theToken->Consume(ch,aScanner,mParseMode); + result=theToken->Consume(ch,aScanner,mFlags); if(!NS_SUCCEEDED(result)) { if(0==theToken->GetTextLength()){ IF_FREE(aToken, mTokenAllocator); @@ -953,7 +992,7 @@ nsresult nsHTMLTokenizer::ConsumeSpecialMarkup(PRUnichar aChar,CToken*& aToken,n aToken = theAllocator->CreateTokenOfType(eToken_doctypeDecl,eHTMLTag_doctypeDecl); if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -976,7 +1015,7 @@ nsresult nsHTMLTokenizer::ConsumeNewline(PRUnichar aChar,CToken*& aToken,nsScann aToken=theAllocator->CreateTokenOfType(eToken_newline,eHTMLTag_newline); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -1001,7 +1040,7 @@ nsresult nsHTMLTokenizer::ConsumeProcessingInstruction(PRUnichar aChar,CToken*& aToken=theAllocator->CreateTokenOfType(eToken_instruction,eHTMLTag_unknown); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; diff --git a/htmlparser/src/nsHTMLTokenizer.h b/htmlparser/src/nsHTMLTokenizer.h index a22553eeaa7..005dc2e8ebf 100644 --- a/htmlparser/src/nsHTMLTokenizer.h +++ b/htmlparser/src/nsHTMLTokenizer.h @@ -97,11 +97,8 @@ protected: static void AddToken(CToken*& aToken,nsresult aResult,nsDeque* aDeque,nsTokenAllocator* aTokenAllocator); nsDeque mTokenDeque; - PRBool mDoXMLEmptyTags; - PRInt32 mParseMode; - eParserDocType mDocType; + PRInt32 mFlags; PRBool mRecordTrailingContent; - eParserCommands mParserCommand; //tells us to viewcontent/viewsource/viewerrors... nsTokenAllocator* mTokenAllocator; PRInt32 mTokenScanPos; PRBool mIsFinalChunk; diff --git a/htmlparser/src/nsHTMLTokens.cpp b/htmlparser/src/nsHTMLTokens.cpp index e320cf3b281..e41f4aca1ca 100644 --- a/htmlparser/src/nsHTMLTokens.cpp +++ b/htmlparser/src/nsHTMLTokens.cpp @@ -26,7 +26,6 @@ #include "nsScanner.h" #include "nsToken.h" #include "nsHTMLTokens.h" -#include "nsIParser.h" #include "prtypes.h" #include "nsDebug.h" #include "nsHTMLTags.h" @@ -38,6 +37,13 @@ static const char* gUserdefined = "userdefined"; +static const PRUnichar kAttributeTerminalChars[] = { + PRUnichar('&'), PRUnichar('\b'), PRUnichar('\t'), + PRUnichar('\n'), PRUnichar('\r'), PRUnichar(' '), + PRUnichar('>'), + PRUnichar(0) +}; + /************************************************************** And now for the token classes... @@ -194,10 +200,10 @@ PRBool CStartToken::IsEmpty(void) { * @update gess 3/25/98 * @param aChar -- last char consumed from stream * @param aScanner -- controller of underlying input source - * @param aMode -- 1=HTML; 0=text (or other ML) + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... * @return error result */ -nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { //if you're here, we've already Consumed the < char, and are //ready to Consume the rest of the open tag identifier. @@ -205,7 +211,7 @@ nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode //NOTE: We don't Consume the tag attributes here, nor do we eat the ">" nsresult result=NS_OK; - if(1==aMode) { + if(aFlag & (NS_IPARSER_FLAG_HTML3_TEXT | NS_IPARSER_FLAG_HTML4_TEXT)) { nsAutoString theSubstr; result=aScanner.GetIdentifier(theSubstr,PR_TRUE); mTypeID = (PRInt32)nsHTMLTags::LookupTag(theSubstr); @@ -321,10 +327,10 @@ CEndToken::CEndToken(const nsAReadableString& aName,eHTMLTags aTag) : CHTMLToken * @update gess 3/25/98 * @param aChar -- last char consumed from stream * @param aScanner -- controller of underlying input source - * @param aMode -- 1=HTML; 0=text (or other ML) + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... * @return error result */ -nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { //if you're here, we've already Consumed the '. @@ -333,7 +339,7 @@ nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) nsresult result=NS_OK; nsAutoString buffer; PRInt32 offset; - if(1==aMode) { + if(aFlag & (NS_IPARSER_FLAG_HTML3_TEXT | NS_IPARSER_FLAG_HTML4_TEXT)) { nsAutoString theSubstr; result=aScanner.ReadUntil(theSubstr,kGreaterThan,PR_FALSE); if (NS_FAILED(result)) { @@ -526,7 +532,7 @@ PRInt32 CTextToken::GetTextLength(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CTextToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CTextToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { static const PRUnichar theTerminalsChars[] = { PRUnichar('\n'), PRUnichar('\r'), PRUnichar('&'), PRUnichar('<'), PRUnichar(0) }; @@ -593,7 +599,7 @@ nsresult CTextToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) * @return error result */ nsresult CTextToken::ConsumeUntil(PRUnichar aChar,PRBool aIgnoreComments,nsScanner& aScanner, - nsString& aTerminalString,PRInt32 aMode,PRBool& aFlushTokens){ + nsString& aTerminalString,PRInt32 aFlag,PRBool& aFlushTokens){ nsresult result=NS_OK; nsReadingIterator theStartOffset, theCurrOffset, theTermStrPos, theStartCommentPos, theAltTermStrPos, endPos; PRBool done=PR_FALSE; @@ -659,7 +665,8 @@ nsresult CTextToken::ConsumeUntil(PRUnichar aChar,PRBool aIgnoreComments,nsScann } if (theTermStrPos != endPos) { - if((aMode != eDTDMode_strict) && (aMode != eDTDMode_transitional) && + if(!(aFlag & NS_IPARSER_FLAG_STRICT_MODE) && + !(aFlag & NS_IPARSER_FLAG_TRANSITIONAL_MODE) && !theLastIteration && !aIgnoreComments) { nsReadingIterator endComment(theCurrOffset); endComment.advance(5); @@ -798,7 +805,7 @@ PRInt32 CCDATASectionToken::GetTokenType(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CCDATASectionToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CCDATASectionToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { static const char* theTerminals="\r]"; nsresult result=NS_OK; PRBool done=PR_FALSE; @@ -900,7 +907,7 @@ PRInt32 CMarkupDeclToken::GetTokenType(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CMarkupDeclToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CMarkupDeclToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { static const PRUnichar theTerminalsChars[] = { PRUnichar('\n'), PRUnichar('\r'), PRUnichar('\''), PRUnichar('"'), PRUnichar('>'), @@ -1180,23 +1187,16 @@ nsresult ConsumeComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString) * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { nsresult result=PR_TRUE; - switch(aMode) { - -#if 1 //set to 1 if you want strict comments. Bug 53011 and 2749 contradicts!!!! - case eDTDMode_strict: - result=ConsumeStrictComment(aChar,aScanner,mTextValue); - break; -#endif - - case eDTDMode_transitional: - default: - result=ConsumeComment(aChar,aScanner,mTextValue); - break; - } //switch - + if (aFlag & NS_IPARSER_FLAG_STRICT_MODE) { + //Enabling strict comment parsing for Bug 53011 and 2749 contradicts!!!! + result=ConsumeStrictComment(aChar,aScanner,mTextValue); + } + else { + result=ConsumeComment(aChar,aScanner,mTextValue); + } return result; } @@ -1293,7 +1293,7 @@ const nsAReadableString& CNewlineToken::GetStringValue(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CNewlineToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CNewlineToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { /******************************************************************* @@ -1473,37 +1473,133 @@ void CAttributeToken::AppendSource(nsString& anOutputString){ // anOutputString.AppendWithConversion(";"); } +/* + * @param aScanner -- controller of underlying input source + * @param aFlag -- If NS_IPARSER_FLAG_VIEW_SOURCE do not reduce entities... + * @return error result + * + */ +static +nsresult ConsumeAttributeEntity(nsString& aString, + nsScanner& aScanner, + PRInt32 aFlag) +{ + + nsresult result=NS_OK; + + PRUnichar ch; + result=aScanner.Peek(ch, 1); + + if (NS_SUCCEEDED(result)) { + PRUnichar amp=0; + PRInt32 theNCRValue=0; + nsAutoString entity; + + if (nsCRT::IsAsciiAlpha(ch) && !(aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) { + aScanner.GetChar(amp); // Get '&' + result=CEntityToken::ConsumeEntity(ch,entity,aScanner); + if (NS_SUCCEEDED(result)) { + theNCRValue = nsHTMLEntities::EntityToUnicode(entity); + PRUnichar theTermChar=entity.Last(); + // If an entity value is greater than 255 then: + // Nav 4.x does not treat it as an entity, + // IE treats it as an entity if terminated with a semicolon. + // Resembling IE!! + if(theNCRValue < 0 || (theNCRValue > 255 && theTermChar != ';')) { + // Looks like we're not dealing with an entity + aString.Append(amp); + aString.Append(entity); + } + else { + // A valid entity so reduce it. + aString.Append(PRUnichar(theNCRValue)); + } + } + } + else if (ch==kHashsign && !(aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) { + aScanner.GetChar(amp); // Discard '&' + PRInt32 err; + result=CEntityToken::ConsumeEntity(ch,entity,aScanner); + if (NS_SUCCEEDED(result)) { + theNCRValue=entity.ToInteger(&err,kAutoDetect); + aString.Append(PRUnichar(theNCRValue)); + } + } + else { + // What we thought as entity is not really an entity... + aScanner.GetChar(amp); + aString.Append(amp); + }//if + } + + return result; +} + +/* + * This general purpose method is used when you want to + * consume attributed text value. + * Note: It also reduces entities within attributes. + * + * @param aScanner -- controller of underlying input source + * @param aTerminalChars -- characters that stop consuming attribute. + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... + * @return error result + */ +static +nsresult ConsumeAttributeValueText(nsString& aString, + nsScanner& aScanner, + const PRUnichar *aTerminalChars, + PRInt32 aFlag) +{ + const nsLocalString theTerminals(aTerminalChars, + sizeof(aTerminalChars)/sizeof(aTerminalChars[0]) - 1); + + nsresult result=aScanner.ReadUntil(aString,theTerminals,PR_FALSE); + + if(NS_SUCCEEDED(result)) { + PRUnichar ch; + aScanner.Peek(ch); + if(ch==kAmpersand) { + result=ConsumeAttributeEntity(aString,aScanner,aFlag); + if (NS_SUCCEEDED(result)) { + result=ConsumeAttributeValueText(aString,aScanner,aTerminalChars,aFlag); + } + } + } + + return result; +} + /* * This general purpose method is used when you want to * consume a known quoted string. * - * @update gess 3/25/98 - * @param aChar -- last char consumed from stream * @param aScanner -- controller of underlying input source + * @param aTerminalChars -- characters that stop consuming attribute. + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... * @return error result */ -nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScanner,PRBool aRetainQuote=PR_FALSE){ +static +nsresult ConsumeQuottedString(PRUnichar aChar, + nsString& aString, + nsScanner& aScanner, + PRInt32 aFlag) +{ + NS_ASSERTION(aChar==kQuote || aChar==kApostrophe,"char is neither quote nor apostrophe"); + + const PRUnichar theTerminalChars[] = { + aChar, PRUnichar('&'), + PRUnichar(0) + }; + nsresult result=NS_OK; nsReadingIterator theOffset; aScanner.CurrentPosition(theOffset); - if(aRetainQuote) { - aString.Append(aChar); - } + result=ConsumeAttributeValueText(aString,aScanner,theTerminalChars,aFlag); - switch(aChar) { - case kQuote: - result=aScanner.ReadUntil(aString,kQuote,aRetainQuote); - if(NS_OK==result) - result=aScanner.SkipOver(kQuote); //this code is here in case someone mistakenly adds multiple quotes... - break; - case kApostrophe: - result=aScanner.ReadUntil(aString,kApostrophe,aRetainQuote); - if(NS_OK==result) - result=aScanner.SkipOver(kApostrophe); //this code is here in case someone mistakenly adds multiple apostrophes... - break; - default: - break; + if(NS_SUCCEEDED(result)) { + result = aScanner.SkipOver(aChar); // aChar should be " or ' } // Ref: Bug 35806 @@ -1511,59 +1607,23 @@ nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScann // Ex QueryInterface(kClassIID, (void **) aInstancePtrResult); -} - - -NS_IMPL_ADDREF(nsXMLTokenizer) -NS_IMPL_RELEASE(nsXMLTokenizer) - - -/** - * Default constructor - * - * @update gess 4/9/98 - * @param - * @return - */ -nsXMLTokenizer::nsXMLTokenizer() : nsHTMLTokenizer() { - NS_INIT_REFCNT(); - mDoXMLEmptyTags=PR_TRUE; - mDocType=eXMLText; -} - -/** - * Default constructor - * - * @update gess 4/9/98 - * @param - * @return - */ -nsXMLTokenizer::~nsXMLTokenizer(){ -} - - -/******************************************************************* - Here begins the real working methods for the tokenizer. - *******************************************************************/ - -/** - * This method repeatedly called by the tokenizer. - * Each time, we determine the kind of token were about to - * read, and then we call the appropriate method to handle - * that token type. - * - * @update gess 3/25/98 - * @param aChar: last char read - * @param aScanner: see nsScanner.h - * @param anErrorCode: arg that will hold error condition - * @return new token or null - */ -nsresult nsXMLTokenizer::ConsumeToken(nsScanner& aScanner,PRBool& aFlushTokens) { - return nsHTMLTokenizer::ConsumeToken(aScanner,aFlushTokens); -} - - -nsTokenAllocator* nsXMLTokenizer::GetTokenAllocator(void) { - return nsHTMLTokenizer::GetTokenAllocator(); -} - -/* - * Consume characters as long as they match the string passed in. - * If they don't match, put them all back. - * XXX The scanner should be able to do this. - * - * @update vidur 11/12/98 - */ -static -nsresult ConsumeConditional(nsScanner& aScanner,const nsString& aMatchString,PRBool& aMatch) { - nsresult result=NS_OK; - nsAutoString str; - PRUint32 len = aMatchString.Length(); - - result = aScanner.Peek(str, len); - if ((NS_OK == result) && str.Equals(aMatchString)) { - aMatch = PR_TRUE; - nsReadingIterator curPos; - aScanner.CurrentPosition(curPos); - curPos.advance(len); - aScanner.SetPosition(curPos); - } - else { - aMatch = PR_FALSE; - } - - return result; -} - -/** - * This method is called just after a "GetTokenAllocator(); - - if(theAllocator) { - nsAutoString theEmpty; - aToken=theAllocator->CreateTokenOfType(eToken_comment,eHTMLTag_comment,theEmpty); - if(aToken) { - result=aToken->Consume(aChar,aScanner,eDTDMode_strict); - AddToken(aToken,result,&mTokenDeque,theAllocator); - } - } - - return result; -} - -/** - * This method is called just after a "GetTokenAllocator(); - - if(theAllocator) { - PRUnichar theChar; - aScanner.Peek(theChar); - PRBool isComment=PR_TRUE; - nsAutoString theEmpty; - if(theChar==kLeftSquareBracket) { - nsAutoString CDATAString; CDATAString.AssignWithConversion("[CDATA["); - PRBool isCDATA = PR_FALSE; - result = ConsumeConditional(aScanner, CDATAString, isCDATA); - if (NS_OK == result) { - if (isCDATA) { - aToken=theAllocator->CreateTokenOfType(eToken_cdatasection,eHTMLTag_unknown,theEmpty); - isComment=PR_FALSE; - } - } - } - - if(isComment) aToken = theAllocator->CreateTokenOfType(eToken_comment,eHTMLTag_comment,theEmpty); - - if(aToken) { - result=aToken->Consume(aChar,aScanner,eDTDMode_strict); - AddToken(aToken,result,&mTokenDeque,theAllocator); - } - } - return result; -} - - -/** - * - * @update gess12/28/98 - * @param - * @return - */ -nsresult nsXMLTokenizer::HandleSkippedContent(nsScanner& aScanner,CToken*& aToken) { - nsresult result=NS_OK; - return result; -} diff --git a/layout/html/document/src/quirk.css b/layout/html/document/src/quirk.css index 41e6ebe8eca..baba06708c4 100644 --- a/layout/html/document/src/quirk.css +++ b/layout/html/document/src/quirk.css @@ -205,3 +205,13 @@ img[align=right] { margin-left: 3px; } +/* Quirk: Make sure that the residual style tags' size info. + * does not take precedence over heading tags' size. (b=77352) + * Note: This special attribute is set only for a residual + * style tag within a heading tag. + */ +*[_moz-rs-heading] { + font-size: inherit !important; +} + + diff --git a/layout/style/quirk.css b/layout/style/quirk.css index 41e6ebe8eca..baba06708c4 100644 --- a/layout/style/quirk.css +++ b/layout/style/quirk.css @@ -205,3 +205,13 @@ img[align=right] { margin-left: 3px; } +/* Quirk: Make sure that the residual style tags' size info. + * does not take precedence over heading tags' size. (b=77352) + * Note: This special attribute is set only for a residual + * style tag within a heading tag. + */ +*[_moz-rs-heading] { + font-size: inherit !important; +} + + diff --git a/parser/htmlparser/src/CNavDTD.cpp b/parser/htmlparser/src/CNavDTD.cpp index df96e56b787..6621c1bd9e7 100644 --- a/parser/htmlparser/src/CNavDTD.cpp +++ b/parser/htmlparser/src/CNavDTD.cpp @@ -189,26 +189,6 @@ CNavDTD::CNavDTD() : nsIDTD(), } -/** - * This method recycles the nodes on a nodestack. - * NOTE: Unlike recycleNode(), we force the usecount - * to 0 of all nodes, then force them to recycle. - * @update gess1/8/99 - * @param aNodeStack - * @return nothing - */ -void CNavDTD::RecycleNodes(nsEntryStack *aNodeStack) { - if(aNodeStack) { - PRInt32 theCount=aNodeStack->mCount; - PRInt32 theIndex=0; - - for(theIndex=0;theIndexNodeAt(theIndex); - IF_FREE(node, &mNodeAllocator); - } - } -} - /** * * @update gess1/8/99 @@ -631,12 +611,9 @@ nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParse nsEntryStack *theChildStyles=0; nsCParserNode* theNode=mBodyContext->Pop(theChildStyles); - if(theNode) { - if(theChildStyles) { - delete theChildStyles; - } - IF_FREE(theNode, &mNodeAllocator); - } + + IF_DELETE(theChildStyles,&mNodeAllocator); + IF_FREE(theNode, &mNodeAllocator); } } @@ -2926,8 +2903,22 @@ nsresult CNavDTD::OpenTransientStyles(eHTMLTags aChildTag){ if(1==theNode->mUseCount) { eHTMLTags theNodeTag=(eHTMLTags)theNode->GetNodeType(); if(gHTMLElements[theNodeTag].CanContain(aChildTag)) { - theEntry->mParent=theStack; //we do this too, because this entry differs from the new one we're pushing... - result=OpenContainer(theNode,theNodeTag,PR_FALSE,theStack); + theEntry->mParent = theStack; //we do this too, because this entry differs from the new one we're pushing... + if(gHTMLElements[mBodyContext->Last()].IsMemberOf(kHeading)) { + // Bug 77352 + // The style system needs to identify residual style tags + // within heading tags so that heading tags' size can take + // precedence over the residual style tags' size info.. + // *Note: Make sure that this attribute is transient since it + // should not get carried over to cases other than heading. + CAttributeToken theAttrToken(NS_LITERAL_STRING("_moz-rs-heading"),NS_LITERAL_STRING("")); + theNode->AddAttribute(&theAttrToken); + result = OpenContainer(theNode,theNodeTag,PR_FALSE,theStack); + theNode->PopAttributeToken(); + } + else { + result = OpenContainer(theNode,theNodeTag,PR_FALSE,theStack); + } } else { //if the node tag can't contain the child tag, then remove the child tag from the style stack @@ -3658,10 +3649,7 @@ nsresult CNavDTD::CloseContainersTo(PRInt32 anIndex,eHTMLTags aTarget, PRBool aC mBodyContext->PushStyles(theChildStyleStack); } else{ - //add code here to recycle styles... - RecycleNodes(theChildStyleStack); - delete theChildStyleStack; // XXX try to recycle this... - theChildStyleStack=0; + IF_DELETE(theChildStyleStack,&mNodeAllocator); } } else if (0==theNode->mUseCount) { @@ -3687,9 +3675,7 @@ nsresult CNavDTD::CloseContainersTo(PRInt32 anIndex,eHTMLTags aTarget, PRBool aC //the tag is not a style tag... if(theChildStyleStack) { if(theStyleDoesntLeakOut) { - RecycleNodes(theChildStyleStack); - delete theChildStyleStack; // XXX try to recycle this... - theChildStyleStack=0; + IF_DELETE(theChildStyleStack,&mNodeAllocator); } else mBodyContext->PushStyles(theChildStyleStack); } @@ -3726,7 +3712,8 @@ nsresult CNavDTD::CloseContainersTo(eHTMLTags aTarget,PRBool aClosedByStartTag){ PRBool theTagIsSynonymous=((nsHTMLElement::IsResidualStyleTag(aTarget)) && (nsHTMLElement::IsResidualStyleTag(theTopTag))); if(!theTagIsSynonymous){ - theTagIsSynonymous=((nsHTMLElement::IsHeadingTag(aTarget)) && (nsHTMLElement::IsHeadingTag(theTopTag))); + theTagIsSynonymous=(gHTMLElements[aTarget].IsMemberOf(kHeading) && + gHTMLElements[theTopTag].IsMemberOf(kHeading)); } if(theTagIsSynonymous) { diff --git a/parser/htmlparser/src/CNavDTD.h b/parser/htmlparser/src/CNavDTD.h index b740511cc28..9bb624aeeb5 100644 --- a/parser/htmlparser/src/CNavDTD.h +++ b/parser/htmlparser/src/CNavDTD.h @@ -490,7 +490,6 @@ protected: nsresult HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags aParent,nsIParserNode *aNode); nsresult HandleSavedTokens(PRInt32 anIndex); nsresult HandleKeyGen(nsIParserNode *aNode); - void RecycleNodes(nsEntryStack *aNodeStack); nsDeque mMisplacedContent; nsDeque mSkippedContent; diff --git a/parser/htmlparser/src/nsDTDUtils.cpp b/parser/htmlparser/src/nsDTDUtils.cpp index 68799060cb7..fcccbe937a8 100644 --- a/parser/htmlparser/src/nsDTDUtils.cpp +++ b/parser/htmlparser/src/nsDTDUtils.cpp @@ -83,6 +83,23 @@ nsEntryStack::~nsEntryStack() { mCount=mCapacity=0; } +/** + * Release all objects in the entry stack + */ +void +nsEntryStack::ReleaseAll(nsNodeAllocator* aNodeAllocator) +{ + NS_WARN_IF_FALSE(aNodeAllocator,"no allocator? - potential leak!"); + + if(aNodeAllocator) { + NS_WARN_IF_FALSE(mCount >= 0,"count should not be negative"); + while(mCount > 0) { + nsCParserNode* node=this->Pop(); + IF_FREE(node,aNodeAllocator); + } + } +} + /** * Resets state of stack to be empty. * @update harishd 04/04/99 @@ -1045,10 +1062,7 @@ void nsDTDContext::PushStyles(nsEntryStack *aStyles){ // If you're here it means that we have hit the rock bottom // ,of the stack, and there's no need to handle anymore styles. // Fix for bug 29048 - nsCParserNode* theNode=aStyles->Pop(); - IF_HOLD(theNode); - delete aStyles; - aStyles=0; + IF_DELETE(aStyles,mNodeAllocator); } }//if(aStyles) } diff --git a/parser/htmlparser/src/nsDTDUtils.h b/parser/htmlparser/src/nsDTDUtils.h index 5c154cd6d10..66480905d1c 100644 --- a/parser/htmlparser/src/nsDTDUtils.h +++ b/parser/htmlparser/src/nsDTDUtils.h @@ -45,8 +45,31 @@ #include "nsFixedSizeAllocator.h" #include "nsVoidArray.h" -#define IF_HOLD(_ptr) if(_ptr) { _ptr->AddRef(); } -#define IF_FREE(_ptr, _allocator) if(_ptr) { _ptr->Release((_allocator)->GetArenaPool()); _ptr=0; } // recycles _ptr +#define IF_HOLD(_ptr) \ + PR_BEGIN_MACRO \ + if(_ptr) { \ + _ptr->AddRef(); \ + } \ + PR_END_MACRO + +// recycles _ptr +#define IF_FREE(_ptr, _allocator) \ + PR_BEGIN_MACRO \ + if(_ptr) { \ + _ptr->Release((_allocator)->GetArenaPool()); \ + _ptr=0; \ + } \ + PR_END_MACRO + +// release objects and destroy _ptr +#define IF_DELETE(_ptr, _allocator) \ + PR_BEGIN_MACRO \ + if(_ptr) { \ + _ptr->ReleaseAll(_allocator); \ + delete(_ptr); \ + _ptr=0; \ + } \ + PR_END_MACRO class nsIParserNode; class nsCParserNode; @@ -73,6 +96,7 @@ struct nsTagEntry { }; class nsEntryStack { + public: nsEntryStack(); ~nsEntryStack(); @@ -91,6 +115,11 @@ public: eHTMLTags Last() const; void Empty(void); + /* + * Release all objects in the entry stack + */ + void ReleaseAll(nsNodeAllocator* aNodeAllocator); + /** * Find the first instance of given tag on the stack. * @update gess 12/14/99 diff --git a/parser/htmlparser/src/nsElementTable.cpp b/parser/htmlparser/src/nsElementTable.cpp index 958986ca0d9..b04398c98ef 100644 --- a/parser/htmlparser/src/nsElementTable.cpp +++ b/parser/htmlparser/src/nsElementTable.cpp @@ -104,7 +104,7 @@ TagList gULKids={2,{eHTMLTag_li,eHTMLTag_p}}; //********************************************************************************************* TagList gRootTags={4,{eHTMLTag_body,eHTMLTag_td,eHTMLTag_table,eHTMLTag_applet}}; -TagList gTableRootTags={7,{eHTMLTag_applet,eHTMLTag_body,eHTMLTag_dl,eHTMLTag_ol,eHTMLTag_td,eHTMLTag_th,eHTMLTag_ul}}; +TagList gTableRootTags={6,{eHTMLTag_applet,eHTMLTag_body,eHTMLTag_dl,eHTMLTag_ol,eHTMLTag_td,eHTMLTag_th}}; TagList gHTMLRootTags={1,{eHTMLTag_unknown}}; TagList gLIRootTags={8,{eHTMLTag_ul,eHTMLTag_ol,eHTMLTag_dir,eHTMLTag_menu,eHTMLTag_p,eHTMLTag_body,eHTMLTag_td,eHTMLTag_th}}; @@ -1956,17 +1956,6 @@ PRBool nsHTMLElement::IsResidualStyleTag(eHTMLTags aChild) { return result; } -/** - * - * @update gess12/13/98 - * @param - * @return - */ -PRBool nsHTMLElement::IsHeadingTag(eHTMLTags aChild) { - return FindTagInSet(aChild,gHeadingTags.mTags,gHeadingTags.mCount); -} - - /** * * @update gess12/13/98 diff --git a/parser/htmlparser/src/nsElementTable.h b/parser/htmlparser/src/nsElementTable.h index b6af72e5056..eb376f57886 100644 --- a/parser/htmlparser/src/nsElementTable.h +++ b/parser/htmlparser/src/nsElementTable.h @@ -209,7 +209,6 @@ struct nsHTMLElement { static PRBool CanContain(eHTMLTags aParent,eHTMLTags aChild); static PRBool IsContainer(eHTMLTags aTag) ; static PRBool IsResidualStyleTag(eHTMLTags aTag) ; - static PRBool IsHeadingTag(eHTMLTags aTag) ; static PRBool IsTextTag(eHTMLTags aTag); static PRBool IsWhitespaceTag(eHTMLTags aTag); diff --git a/parser/htmlparser/src/nsHTMLTokenizer.cpp b/parser/htmlparser/src/nsHTMLTokenizer.cpp index d6dd2eaba70..b54d09d9dfe 100644 --- a/parser/htmlparser/src/nsHTMLTokenizer.cpp +++ b/parser/htmlparser/src/nsHTMLTokenizer.cpp @@ -28,7 +28,6 @@ */ #include "nsHTMLTokenizer.h" -#include "nsParser.h" #include "nsScanner.h" #include "nsElementTable.h" #include "nsHTMLEntities.h" @@ -85,12 +84,17 @@ nsresult nsHTMLTokenizer::QueryInterface(const nsIID& aIID, void** aInstancePtr) * @return NS_xxx error result */ -NS_HTMLPARS nsresult NS_NewHTMLTokenizer(nsITokenizer** aInstancePtrResult,PRInt32 aMode,eParserDocType aDocType, eParserCommands aCommand) { +NS_HTMLPARS +nsresult NS_NewHTMLTokenizer(nsITokenizer** aInstancePtrResult, + PRInt32 aFlag, + eParserDocType aDocType, + eParserCommands aCommand) +{ NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } - nsHTMLTokenizer* it = new nsHTMLTokenizer(aMode,aDocType,aCommand); + nsHTMLTokenizer* it = new nsHTMLTokenizer(aFlag,aDocType,aCommand); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } @@ -112,13 +116,45 @@ NS_IMPL_RELEASE(nsHTMLTokenizer) nsHTMLTokenizer::nsHTMLTokenizer(PRInt32 aParseMode, eParserDocType aDocType, eParserCommands aCommand) : - nsITokenizer(), mTokenDeque(0), mParseMode(aParseMode) + nsITokenizer(), mTokenDeque(0) { NS_INIT_REFCNT(); - mDoXMLEmptyTags=((eDTDMode_strict==aParseMode) || (eDTDMode_transitional==aParseMode)); - mDocType=aDocType; + + if (aParseMode==eDTDMode_strict) { + mFlags = NS_IPARSER_FLAG_STRICT_MODE; + } + else if (aParseMode==eDTDMode_transitional) { + mFlags = NS_IPARSER_FLAG_TRANSITIONAL_MODE; + } + else if (aParseMode==eDTDMode_quirks) { + mFlags = NS_IPARSER_FLAG_QUIRKS_MODE; + } + else if (aParseMode==eDTDMode_autodetect) { + mFlags = NS_IPARSER_FLAG_AUTO_DETECT_MODE; + } + else { + mFlags = NS_IPARSER_FLAG_UNKNOWN_MODE; + } + + if (aDocType==ePlainText) { + mFlags |= NS_IPARSER_FLAG_PLAIN_TEXT; + } + else if (aDocType==eXMLText) { + mFlags |= NS_IPARSER_FLAG_XML_TEXT; + } + else if (aDocType==eXHTMLText) { + mFlags |= NS_IPARSER_FLAG_XHTML_TEXT; + } + else if (aDocType==eHTML3Text) { + mFlags |= NS_IPARSER_FLAG_HTML3_TEXT; + } + else if (aDocType==eHTML4Text) { + mFlags |= NS_IPARSER_FLAG_HTML4_TEXT; + } + + mFlags |= (aCommand==eViewSource)? NS_IPARSER_FLAG_VIEW_SOURCE:NS_IPARSER_FLAG_VIEW_NORMAL; + mRecordTrailingContent=PR_FALSE; - mParserCommand=aCommand; mTokenAllocator=nsnull; mTokenScanPos=0; } @@ -448,7 +484,7 @@ nsresult nsHTMLTokenizer::ConsumeToken(nsScanner& aScanner,PRBool& aFlushTokens) case NS_OK: default: - if(ePlainText!=mDocType) { + if(!(mFlags & NS_IPARSER_FLAG_PLAIN_TEXT)) { if(kLessThan==theChar) { return ConsumeTag(theChar,theToken,aScanner,aFlushTokens); } @@ -505,7 +541,7 @@ nsresult nsHTMLTokenizer::ConsumeTag(PRUnichar aChar,CToken*& aToken,nsScanner& result=aScanner.Peek(theNextChar, 1); if(NS_OK==result) { // xml allow non ASCII tag name, consume as end tag. need to make xml view source work - PRBool isXML=((eXMLText==mDocType) || (eXHTMLText==mDocType)); + PRBool isXML=(mFlags & (NS_IPARSER_FLAG_XML_TEXT | NS_IPARSER_FLAG_XHTML_TEXT)); if(nsCRT::IsAsciiAlpha(theNextChar)||(kGreaterThan==theNextChar)|| (isXML && (! nsCRT::IsAscii(theNextChar)))) { result=ConsumeEndTag(aChar,aToken,aScanner); @@ -571,7 +607,7 @@ nsresult nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar,CStartToken* aToken, while((!done) && (result==NS_OK)) { CAttributeToken* theToken= NS_STATIC_CAST(CAttributeToken*, theAllocator->CreateTokenOfType(eToken_attribute,eHTMLTag_unknown)); if(theToken){ - result=theToken->Consume(aChar,aScanner,PRBool(eViewSource==mParserCommand)); //tell new token to finish consuming text... + result=theToken->Consume(aChar,aScanner,mFlags); //tell new token to finish consuming text... //Much as I hate to do this, here's some special case code. //This handles the case of empty-tags in XML. Our last @@ -585,7 +621,7 @@ nsresult nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar,CStartToken* aToken, // support XML like syntax to fix bugs like 44186 if(!key.IsEmpty() && kForwardSlash==key.First() && text.IsEmpty()) { aToken->SetEmpty(PR_TRUE); - isUsableAttr=!mDoXMLEmptyTags; + isUsableAttr = !(mFlags & (NS_IPARSER_FLAG_STRICT_MODE|NS_IPARSER_FLAG_TRANSITIONAL_MODE)); } if(isUsableAttr) { theAttrCount++; @@ -655,8 +691,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan nsReadingIterator origin; aScanner.CurrentPosition(origin); - PRBool isHTML=((eHTML3Text==mDocType) || (eHTML4Text==mDocType)); - result= aToken->Consume(aChar,aScanner,isHTML); //tell new token to finish consuming text... + result= aToken->Consume(aChar,aScanner,mFlags); //tell new token to finish consuming text... if(NS_SUCCEEDED(result)) { @@ -668,7 +703,12 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan PRBool theTagHasAttributes=PR_FALSE; nsReadingIterator start, end; if(NS_OK==result) { - result=(eViewSource==mParserCommand) ? aScanner.ReadWhitespace(start, end) : aScanner.SkipWhitespace(); + if (mFlags & NS_IPARSER_FLAG_VIEW_SOURCE) { + result = aScanner.ReadWhitespace(start, end); + } + else { + result = aScanner.SkipWhitespace(); + } aToken->mNewlineCount += aScanner.GetNewlinesSkipped(); if(NS_OK==result) { result=aScanner.Peek(aChar); @@ -686,7 +726,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan CStartToken* theStartToken=NS_STATIC_CAST(CStartToken*,aToken); if(theTagHasAttributes) { - if (eViewSource==mParserCommand) { + if (mFlags & NS_IPARSER_FLAG_VIEW_SOURCE) { // Since we conserve whitespace in view-source mode, // go back to the beginning of the whitespace section // and let the first attribute grab it. @@ -719,7 +759,7 @@ nsresult nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,CToken*& aToken,nsScan CToken* text=theAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text); CTextToken* textToken=NS_STATIC_CAST(CTextToken*,text); - result=textToken->ConsumeUntil(0,theTag!=eHTMLTag_script,aScanner,endText,mParseMode,aFlushTokens); //tell new token to finish consuming text... + result=textToken->ConsumeUntil(0,theTag!=eHTMLTag_script,aScanner,endText,mFlags,aFlushTokens); //tell new token to finish consuming text... // Fix bug 44186 // Support XML like syntax, i.e., @@ -770,8 +810,7 @@ nsresult nsHTMLTokenizer::ConsumeEndTag(PRUnichar aChar,CToken*& aToken,nsScanne nsresult result=NS_OK; if(aToken) { - PRBool isHTML=((eHTML3Text==mDocType) || (eHTML4Text==mDocType)); - result= aToken->Consume(aChar,aScanner,isHTML); //tell new token to finish consuming text... + result= aToken->Consume(aChar,aScanner,mFlags); //tell new token to finish consuming text... AddToken(aToken,result,&mTokenDeque,theAllocator); if(NS_SUCCEEDED(result)) { @@ -810,7 +849,7 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne // Get the first entity character aScanner.GetChar(theChar); - result = aToken->Consume(theChar,aScanner,mParseMode); //tell new token to finish consuming text... + result = aToken->Consume(theChar,aScanner,mFlags); //tell new token to finish consuming text... } else if(kHashsign==theChar) { // Get the "&" @@ -819,7 +858,7 @@ nsresult nsHTMLTokenizer::ConsumeEntity(PRUnichar aChar,CToken*& aToken,nsScanne // Get the first numerical entity character aScanner.GetChar(theChar); - result=aToken->Consume(theChar,aScanner,mParseMode); + result=aToken->Consume(theChar,aScanner,mFlags); } else { //oops, we're actually looking at plain text... @@ -854,7 +893,7 @@ nsresult nsHTMLTokenizer::ConsumeWhitespace(PRUnichar aChar,CToken*& aToken,nsSc aToken = theAllocator->CreateTokenOfType(eToken_whitespace,eHTMLTag_whitespace); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -878,7 +917,7 @@ nsresult nsHTMLTokenizer::ConsumeComment(PRUnichar aChar,CToken*& aToken,nsScann aToken = theAllocator->CreateTokenOfType(eToken_comment,eHTMLTag_comment); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -900,7 +939,7 @@ nsresult nsHTMLTokenizer::ConsumeText(CToken*& aToken,nsScanner& aScanner){ CTextToken* theToken = (CTextToken*)theAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text); if(theToken) { PRUnichar ch=0; - result=theToken->Consume(ch,aScanner,mParseMode); + result=theToken->Consume(ch,aScanner,mFlags); if(!NS_SUCCEEDED(result)) { if(0==theToken->GetTextLength()){ IF_FREE(aToken, mTokenAllocator); @@ -953,7 +992,7 @@ nsresult nsHTMLTokenizer::ConsumeSpecialMarkup(PRUnichar aChar,CToken*& aToken,n aToken = theAllocator->CreateTokenOfType(eToken_doctypeDecl,eHTMLTag_doctypeDecl); if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -976,7 +1015,7 @@ nsresult nsHTMLTokenizer::ConsumeNewline(PRUnichar aChar,CToken*& aToken,nsScann aToken=theAllocator->CreateTokenOfType(eToken_newline,eHTMLTag_newline); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; @@ -1001,7 +1040,7 @@ nsresult nsHTMLTokenizer::ConsumeProcessingInstruction(PRUnichar aChar,CToken*& aToken=theAllocator->CreateTokenOfType(eToken_instruction,eHTMLTag_unknown); nsresult result=NS_OK; if(aToken) { - result=aToken->Consume(aChar,aScanner,mParseMode); + result=aToken->Consume(aChar,aScanner,mFlags); AddToken(aToken,result,&mTokenDeque,theAllocator); } return result; diff --git a/parser/htmlparser/src/nsHTMLTokenizer.h b/parser/htmlparser/src/nsHTMLTokenizer.h index a22553eeaa7..005dc2e8ebf 100644 --- a/parser/htmlparser/src/nsHTMLTokenizer.h +++ b/parser/htmlparser/src/nsHTMLTokenizer.h @@ -97,11 +97,8 @@ protected: static void AddToken(CToken*& aToken,nsresult aResult,nsDeque* aDeque,nsTokenAllocator* aTokenAllocator); nsDeque mTokenDeque; - PRBool mDoXMLEmptyTags; - PRInt32 mParseMode; - eParserDocType mDocType; + PRInt32 mFlags; PRBool mRecordTrailingContent; - eParserCommands mParserCommand; //tells us to viewcontent/viewsource/viewerrors... nsTokenAllocator* mTokenAllocator; PRInt32 mTokenScanPos; PRBool mIsFinalChunk; diff --git a/parser/htmlparser/src/nsHTMLTokens.cpp b/parser/htmlparser/src/nsHTMLTokens.cpp index e320cf3b281..e41f4aca1ca 100644 --- a/parser/htmlparser/src/nsHTMLTokens.cpp +++ b/parser/htmlparser/src/nsHTMLTokens.cpp @@ -26,7 +26,6 @@ #include "nsScanner.h" #include "nsToken.h" #include "nsHTMLTokens.h" -#include "nsIParser.h" #include "prtypes.h" #include "nsDebug.h" #include "nsHTMLTags.h" @@ -38,6 +37,13 @@ static const char* gUserdefined = "userdefined"; +static const PRUnichar kAttributeTerminalChars[] = { + PRUnichar('&'), PRUnichar('\b'), PRUnichar('\t'), + PRUnichar('\n'), PRUnichar('\r'), PRUnichar(' '), + PRUnichar('>'), + PRUnichar(0) +}; + /************************************************************** And now for the token classes... @@ -194,10 +200,10 @@ PRBool CStartToken::IsEmpty(void) { * @update gess 3/25/98 * @param aChar -- last char consumed from stream * @param aScanner -- controller of underlying input source - * @param aMode -- 1=HTML; 0=text (or other ML) + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... * @return error result */ -nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { //if you're here, we've already Consumed the < char, and are //ready to Consume the rest of the open tag identifier. @@ -205,7 +211,7 @@ nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode //NOTE: We don't Consume the tag attributes here, nor do we eat the ">" nsresult result=NS_OK; - if(1==aMode) { + if(aFlag & (NS_IPARSER_FLAG_HTML3_TEXT | NS_IPARSER_FLAG_HTML4_TEXT)) { nsAutoString theSubstr; result=aScanner.GetIdentifier(theSubstr,PR_TRUE); mTypeID = (PRInt32)nsHTMLTags::LookupTag(theSubstr); @@ -321,10 +327,10 @@ CEndToken::CEndToken(const nsAReadableString& aName,eHTMLTags aTag) : CHTMLToken * @update gess 3/25/98 * @param aChar -- last char consumed from stream * @param aScanner -- controller of underlying input source - * @param aMode -- 1=HTML; 0=text (or other ML) + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... * @return error result */ -nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { //if you're here, we've already Consumed the '. @@ -333,7 +339,7 @@ nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) nsresult result=NS_OK; nsAutoString buffer; PRInt32 offset; - if(1==aMode) { + if(aFlag & (NS_IPARSER_FLAG_HTML3_TEXT | NS_IPARSER_FLAG_HTML4_TEXT)) { nsAutoString theSubstr; result=aScanner.ReadUntil(theSubstr,kGreaterThan,PR_FALSE); if (NS_FAILED(result)) { @@ -526,7 +532,7 @@ PRInt32 CTextToken::GetTextLength(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CTextToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CTextToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { static const PRUnichar theTerminalsChars[] = { PRUnichar('\n'), PRUnichar('\r'), PRUnichar('&'), PRUnichar('<'), PRUnichar(0) }; @@ -593,7 +599,7 @@ nsresult CTextToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) * @return error result */ nsresult CTextToken::ConsumeUntil(PRUnichar aChar,PRBool aIgnoreComments,nsScanner& aScanner, - nsString& aTerminalString,PRInt32 aMode,PRBool& aFlushTokens){ + nsString& aTerminalString,PRInt32 aFlag,PRBool& aFlushTokens){ nsresult result=NS_OK; nsReadingIterator theStartOffset, theCurrOffset, theTermStrPos, theStartCommentPos, theAltTermStrPos, endPos; PRBool done=PR_FALSE; @@ -659,7 +665,8 @@ nsresult CTextToken::ConsumeUntil(PRUnichar aChar,PRBool aIgnoreComments,nsScann } if (theTermStrPos != endPos) { - if((aMode != eDTDMode_strict) && (aMode != eDTDMode_transitional) && + if(!(aFlag & NS_IPARSER_FLAG_STRICT_MODE) && + !(aFlag & NS_IPARSER_FLAG_TRANSITIONAL_MODE) && !theLastIteration && !aIgnoreComments) { nsReadingIterator endComment(theCurrOffset); endComment.advance(5); @@ -798,7 +805,7 @@ PRInt32 CCDATASectionToken::GetTokenType(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CCDATASectionToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CCDATASectionToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { static const char* theTerminals="\r]"; nsresult result=NS_OK; PRBool done=PR_FALSE; @@ -900,7 +907,7 @@ PRInt32 CMarkupDeclToken::GetTokenType(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CMarkupDeclToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CMarkupDeclToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { static const PRUnichar theTerminalsChars[] = { PRUnichar('\n'), PRUnichar('\r'), PRUnichar('\''), PRUnichar('"'), PRUnichar('>'), @@ -1180,23 +1187,16 @@ nsresult ConsumeComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString) * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { nsresult result=PR_TRUE; - switch(aMode) { - -#if 1 //set to 1 if you want strict comments. Bug 53011 and 2749 contradicts!!!! - case eDTDMode_strict: - result=ConsumeStrictComment(aChar,aScanner,mTextValue); - break; -#endif - - case eDTDMode_transitional: - default: - result=ConsumeComment(aChar,aScanner,mTextValue); - break; - } //switch - + if (aFlag & NS_IPARSER_FLAG_STRICT_MODE) { + //Enabling strict comment parsing for Bug 53011 and 2749 contradicts!!!! + result=ConsumeStrictComment(aChar,aScanner,mTextValue); + } + else { + result=ConsumeComment(aChar,aScanner,mTextValue); + } return result; } @@ -1293,7 +1293,7 @@ const nsAReadableString& CNewlineToken::GetStringValue(void) { * @param aScanner -- controller of underlying input source * @return error result */ -nsresult CNewlineToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aMode) { +nsresult CNewlineToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) { /******************************************************************* @@ -1473,37 +1473,133 @@ void CAttributeToken::AppendSource(nsString& anOutputString){ // anOutputString.AppendWithConversion(";"); } +/* + * @param aScanner -- controller of underlying input source + * @param aFlag -- If NS_IPARSER_FLAG_VIEW_SOURCE do not reduce entities... + * @return error result + * + */ +static +nsresult ConsumeAttributeEntity(nsString& aString, + nsScanner& aScanner, + PRInt32 aFlag) +{ + + nsresult result=NS_OK; + + PRUnichar ch; + result=aScanner.Peek(ch, 1); + + if (NS_SUCCEEDED(result)) { + PRUnichar amp=0; + PRInt32 theNCRValue=0; + nsAutoString entity; + + if (nsCRT::IsAsciiAlpha(ch) && !(aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) { + aScanner.GetChar(amp); // Get '&' + result=CEntityToken::ConsumeEntity(ch,entity,aScanner); + if (NS_SUCCEEDED(result)) { + theNCRValue = nsHTMLEntities::EntityToUnicode(entity); + PRUnichar theTermChar=entity.Last(); + // If an entity value is greater than 255 then: + // Nav 4.x does not treat it as an entity, + // IE treats it as an entity if terminated with a semicolon. + // Resembling IE!! + if(theNCRValue < 0 || (theNCRValue > 255 && theTermChar != ';')) { + // Looks like we're not dealing with an entity + aString.Append(amp); + aString.Append(entity); + } + else { + // A valid entity so reduce it. + aString.Append(PRUnichar(theNCRValue)); + } + } + } + else if (ch==kHashsign && !(aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) { + aScanner.GetChar(amp); // Discard '&' + PRInt32 err; + result=CEntityToken::ConsumeEntity(ch,entity,aScanner); + if (NS_SUCCEEDED(result)) { + theNCRValue=entity.ToInteger(&err,kAutoDetect); + aString.Append(PRUnichar(theNCRValue)); + } + } + else { + // What we thought as entity is not really an entity... + aScanner.GetChar(amp); + aString.Append(amp); + }//if + } + + return result; +} + +/* + * This general purpose method is used when you want to + * consume attributed text value. + * Note: It also reduces entities within attributes. + * + * @param aScanner -- controller of underlying input source + * @param aTerminalChars -- characters that stop consuming attribute. + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... + * @return error result + */ +static +nsresult ConsumeAttributeValueText(nsString& aString, + nsScanner& aScanner, + const PRUnichar *aTerminalChars, + PRInt32 aFlag) +{ + const nsLocalString theTerminals(aTerminalChars, + sizeof(aTerminalChars)/sizeof(aTerminalChars[0]) - 1); + + nsresult result=aScanner.ReadUntil(aString,theTerminals,PR_FALSE); + + if(NS_SUCCEEDED(result)) { + PRUnichar ch; + aScanner.Peek(ch); + if(ch==kAmpersand) { + result=ConsumeAttributeEntity(aString,aScanner,aFlag); + if (NS_SUCCEEDED(result)) { + result=ConsumeAttributeValueText(aString,aScanner,aTerminalChars,aFlag); + } + } + } + + return result; +} + /* * This general purpose method is used when you want to * consume a known quoted string. * - * @update gess 3/25/98 - * @param aChar -- last char consumed from stream * @param aScanner -- controller of underlying input source + * @param aTerminalChars -- characters that stop consuming attribute. + * @param aFlag - contains information such as |dtd mode|view mode|doctype|etc... * @return error result */ -nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScanner,PRBool aRetainQuote=PR_FALSE){ +static +nsresult ConsumeQuottedString(PRUnichar aChar, + nsString& aString, + nsScanner& aScanner, + PRInt32 aFlag) +{ + NS_ASSERTION(aChar==kQuote || aChar==kApostrophe,"char is neither quote nor apostrophe"); + + const PRUnichar theTerminalChars[] = { + aChar, PRUnichar('&'), + PRUnichar(0) + }; + nsresult result=NS_OK; nsReadingIterator theOffset; aScanner.CurrentPosition(theOffset); - if(aRetainQuote) { - aString.Append(aChar); - } + result=ConsumeAttributeValueText(aString,aScanner,theTerminalChars,aFlag); - switch(aChar) { - case kQuote: - result=aScanner.ReadUntil(aString,kQuote,aRetainQuote); - if(NS_OK==result) - result=aScanner.SkipOver(kQuote); //this code is here in case someone mistakenly adds multiple quotes... - break; - case kApostrophe: - result=aScanner.ReadUntil(aString,kApostrophe,aRetainQuote); - if(NS_OK==result) - result=aScanner.SkipOver(kApostrophe); //this code is here in case someone mistakenly adds multiple apostrophes... - break; - default: - break; + if(NS_SUCCEEDED(result)) { + result = aScanner.SkipOver(aChar); // aChar should be " or ' } // Ref: Bug 35806 @@ -1511,59 +1607,23 @@ nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScann // Ex
QueryInterface(kClassIID, (void **) aInstancePtrResult); -} - - -NS_IMPL_ADDREF(nsXMLTokenizer) -NS_IMPL_RELEASE(nsXMLTokenizer) - - -/** - * Default constructor - * - * @update gess 4/9/98 - * @param - * @return - */ -nsXMLTokenizer::nsXMLTokenizer() : nsHTMLTokenizer() { - NS_INIT_REFCNT(); - mDoXMLEmptyTags=PR_TRUE; - mDocType=eXMLText; -} - -/** - * Default constructor - * - * @update gess 4/9/98 - * @param - * @return - */ -nsXMLTokenizer::~nsXMLTokenizer(){ -} - - -/******************************************************************* - Here begins the real working methods for the tokenizer. - *******************************************************************/ - -/** - * This method repeatedly called by the tokenizer. - * Each time, we determine the kind of token were about to - * read, and then we call the appropriate method to handle - * that token type. - * - * @update gess 3/25/98 - * @param aChar: last char read - * @param aScanner: see nsScanner.h - * @param anErrorCode: arg that will hold error condition - * @return new token or null - */ -nsresult nsXMLTokenizer::ConsumeToken(nsScanner& aScanner,PRBool& aFlushTokens) { - return nsHTMLTokenizer::ConsumeToken(aScanner,aFlushTokens); -} - - -nsTokenAllocator* nsXMLTokenizer::GetTokenAllocator(void) { - return nsHTMLTokenizer::GetTokenAllocator(); -} - -/* - * Consume characters as long as they match the string passed in. - * If they don't match, put them all back. - * XXX The scanner should be able to do this. - * - * @update vidur 11/12/98 - */ -static -nsresult ConsumeConditional(nsScanner& aScanner,const nsString& aMatchString,PRBool& aMatch) { - nsresult result=NS_OK; - nsAutoString str; - PRUint32 len = aMatchString.Length(); - - result = aScanner.Peek(str, len); - if ((NS_OK == result) && str.Equals(aMatchString)) { - aMatch = PR_TRUE; - nsReadingIterator curPos; - aScanner.CurrentPosition(curPos); - curPos.advance(len); - aScanner.SetPosition(curPos); - } - else { - aMatch = PR_FALSE; - } - - return result; -} - -/** - * This method is called just after a "GetTokenAllocator(); - - if(theAllocator) { - nsAutoString theEmpty; - aToken=theAllocator->CreateTokenOfType(eToken_comment,eHTMLTag_comment,theEmpty); - if(aToken) { - result=aToken->Consume(aChar,aScanner,eDTDMode_strict); - AddToken(aToken,result,&mTokenDeque,theAllocator); - } - } - - return result; -} - -/** - * This method is called just after a "GetTokenAllocator(); - - if(theAllocator) { - PRUnichar theChar; - aScanner.Peek(theChar); - PRBool isComment=PR_TRUE; - nsAutoString theEmpty; - if(theChar==kLeftSquareBracket) { - nsAutoString CDATAString; CDATAString.AssignWithConversion("[CDATA["); - PRBool isCDATA = PR_FALSE; - result = ConsumeConditional(aScanner, CDATAString, isCDATA); - if (NS_OK == result) { - if (isCDATA) { - aToken=theAllocator->CreateTokenOfType(eToken_cdatasection,eHTMLTag_unknown,theEmpty); - isComment=PR_FALSE; - } - } - } - - if(isComment) aToken = theAllocator->CreateTokenOfType(eToken_comment,eHTMLTag_comment,theEmpty); - - if(aToken) { - result=aToken->Consume(aChar,aScanner,eDTDMode_strict); - AddToken(aToken,result,&mTokenDeque,theAllocator); - } - } - return result; -} - - -/** - * - * @update gess12/28/98 - * @param - * @return - */ -nsresult nsXMLTokenizer::HandleSkippedContent(nsScanner& aScanner,CToken*& aToken) { - nsresult result=NS_OK; - return result; -}