This commit is contained in:
rickg%netscape.com 1999-02-01 04:24:37 +00:00
Родитель 9f4f989790
Коммит 06970832e3
18 изменённых файлов: 1620 добавлений и 1222 удалений

Просмотреть файл

@ -1268,7 +1268,7 @@ nsHTMLDocument::WriteCommon(JSContext *cx,
str.Append('\n');
}
result = mParser->Parse(str, PR_TRUE,PR_FALSE,PR_FALSE);
result = mParser->Parse(str, PR_TRUE,PR_FALSE,PR_TRUE);
if (NS_OK != result) {
return result;
}

Просмотреть файл

@ -696,23 +696,31 @@ PRInt32 GetTopmostIndexOf(eHTMLTags aTag,nsTagStack& aTagStack) {
*/
eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack) {
int theTopIndex=aTagStack.mCount;
eHTMLTags aPrevTag=aTagStack.mTags[theTopIndex-1];
eHTMLTags thePrevTag=aTagStack.Last();
if(nsHTMLElement::IsContainer(aCurrentTag)){
if(aPrevTag==aCurrentTag) {
if(thePrevTag==aCurrentTag) {
return (gHTMLElements[aCurrentTag].CanContainSelf()) ? eHTMLTag_unknown: aCurrentTag;
}
if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
PRInt32 theRootIndex=kNotFound;
CTagList* theRootTags=gHTMLElements[aCurrentTag].GetRootTags();
if(theRootTags) {
PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack);
theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack);
CTagList* theStartTags=gHTMLElements[aCurrentTag].GetAutoCloseStartTags();
PRInt32 thePeerIndex=kNotFound;
if(theStartTags){
thePeerIndex=theStartTags->GetBottommostIndexOf(aTagStack,theRootIndex+1);
}
else thePeerIndex=GetTopmostIndexOf(aCurrentTag,aTagStack);
else {
//this extra check is need to handle case like this: <DIV><P><DIV>
//the new div can close the P,but doesn't close the top DIV.
thePeerIndex=GetTopmostIndexOf(aCurrentTag,aTagStack);
if(gHTMLElements[aCurrentTag].CanContainSelf()) {
thePeerIndex++;
}
}
if(theRootIndex<thePeerIndex) {
return aTagStack.mTags[thePeerIndex]; //return the tag that was used in peer test.
}
@ -724,14 +732,19 @@ eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagS
if(kNotFound!=thePeerIndex){
if(thePeerIndex==theTopIndex-1) {
//the guy you can autoclose is on the top of the stack...
return aPrevTag;
return thePrevTag;
} //if
} //if
}//if
else if(kNotFound<theRootIndex) {
//This block handles our fallback cases like: <html><body><center><p> <- <table>
while((theRootIndex<--theTopIndex) && (!gHTMLElements[aTagStack.mTags[theTopIndex]].CanContain(aCurrentTag))) {
}
return aTagStack.mTags[theTopIndex+1];
//return aTagStack.mTags[theRootIndex+1];
}
} //if
else if(nsHTMLElement::IsInlineElement(aCurrentTag)) {
}//if
} //if
return eHTMLTag_unknown;
}
@ -748,6 +761,24 @@ eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagS
*/
PRBool CanBeContained(eHTMLTags aChildTag,nsTagStack& aTagStack) {
PRBool result=PR_TRUE;
CTagList* theRootTags=gHTMLElements[aChildTag].GetRootTags();
if(theRootTags) {
PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack);
PRInt32 theChildIndex=aTagStack.GetTopmostIndexOf(aChildTag);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(aTagStack);
}
}
if(theRootIndex<theChildIndex){
eHTMLTags thePrevTag=aTagStack.Last();
result=gHTMLElements[thePrevTag].CanContainType(gHTMLElements[aChildTag].mParentBits);
return result;
}
}
return result;
}
@ -977,6 +1008,114 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) {
return result;
}
/**
* Call this to see if you have a closeable peer on the stack that
* is ABOVE one of its root tags.
*
* @update gess 3/25/98
* @param aRootTagList -- list of root tags for aTag
* @param aTag -- tag to test for containership
* @return PR_TRUE if given tag can contain other tags
*/
PRBool HasCloseablePeerAboveRoot(CTagList& aRootTagList,nsTagStack& aTagStack,eHTMLTags aTag) {
PRInt32 theRootIndex=aRootTagList.GetTopmostIndexOf(aTagStack);
CTagList* theCloseTags=gHTMLElements[aTag].GetAutoCloseStartTags();
PRInt32 theChildIndex=-1;
PRBool result=PR_FALSE;
if(theCloseTags) {
theChildIndex=theCloseTags->GetTopmostIndexOf(aTagStack);
}
else {
theChildIndex=aTagStack.GetTopmostIndexOf(aTag);
}
return PRBool(theRootIndex<theChildIndex);
}
/**
* Call this to find the index of a given child, or (if not found)
* the index of its nearest synonym.
*
* @update gess 3/25/98
* @param aTagStack -- list of open tags
* @param aTag -- tag to test for containership
* @return index of kNotFound
*/
PRInt32 GetIndexOfChildOrSynonym(nsTagStack& aTagStack,eHTMLTags aChildTag) {
PRInt32 theChildIndex=aTagStack.GetTopmostIndexOf(aChildTag);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(aTagStack);
}
}
return theChildIndex;
}
/**
* This method is called to determine whether or not an END tag
* can be autoclosed. This means that based on the current
* context, the stack should be closed to the nearest matching
* tag.
*
* @param aTag -- tag enum of child to be tested
* @return PR_TRUE if autoclosure should occur
*/
eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack) {
int theTopIndex=aTagStack.mCount;
eHTMLTags thePrevTag=aTagStack.Last();
if(nsHTMLElement::IsContainer(aCurrentTag)){
PRInt32 theChildIndex=GetIndexOfChildOrSynonym(aTagStack,aCurrentTag);
if(kNotFound<theChildIndex) {
if(thePrevTag==aTagStack.mTags[theChildIndex]){
return aTagStack.mTags[theChildIndex];
}
if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
/*here's what to do:
Our here is sitting at aChildIndex. There are other tags above it
on the stack. We have to try to close them out, but we may encounter
one that can block us. The way to tell is by comparing each tag on
the stack against our closeTag and rootTag list.
For each tag above our hero on the stack, ask 3 questions:
1. Is it in the closeTag list? If so, the we can skip over it
2. Is it in the rootTag list? If so, then we're gated by it
3. Otherwise its non-specified and we simply presume we can close it.
*/
CTagList* theCloseTags=gHTMLElements[aCurrentTag].GetAutoCloseEndTags();
CTagList* theRootTags=gHTMLElements[aCurrentTag].GetEndRootTags();
if(theCloseTags){
//at a min., this code is needed for H1..H6
while(theChildIndex<--theTopIndex) {
eHTMLTags theNextTag=aTagStack.mTags[theTopIndex];
if(PR_FALSE==theCloseTags->Contains(theNextTag)) {
if(PR_TRUE==theRootTags->Contains(theNextTag)) {
return eHTMLTag_unknown; //we encountered a tag in root list so fail (because we're gated).
}
//otherwise presume it's something we can simply ignore and continue search...
}
//otherwise its in the close list so skip to next tag...
}
return aCurrentTag; //if you make it here, we're ungated and found a target!
}//if
else if(theRootTags) {
//since we didn't find any close tags, see if there is an instance of aCurrentTag
//above the stack from the roottag.
if(HasCloseablePeerAboveRoot(*theRootTags,aTagStack,aCurrentTag))
return aCurrentTag;
else return eHTMLTag_unknown;
}
} //if
}//if
} //if
return eHTMLTag_unknown;
}
/**
* This method gets called when an end token has been
@ -995,23 +1134,7 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) {
NS_PRECONDITION(0!=aToken,kNullToken);
nsresult result=NS_OK;
CEndToken* et = (CEndToken*)(aToken);
eHTMLTags theChildTag=(eHTMLTags)et->GetTypeID();
// 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 the explicit style tag (goofy, huh?)
//now check to see if this token should be omitted, or
//if it's gated from closing by the presence of another tag.
if(PR_TRUE==CanOmitEndTag(mBodyContext->Last(),theChildTag)) {
UpdateStyleStackForCloseTag(theChildTag,theChildTag);
return result;
}
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
nsCParserNode theNode((CHTMLToken*)aToken,mLineNumber);
switch(theChildTag) {
@ -1029,26 +1152,20 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) {
result=CloseContainer(theNode,theChildTag,PR_FALSE);
break;
case eHTMLTag_td:
case eHTMLTag_th:
//result=CloseContainersTo(theChildTag,PR_TRUE);
// Empty the transient style stack (we just closed any extra
// ones off so it's safe to do it now) because they don't carry
// forward across table cell boundaries.
//mBodyContext->mStyles->mCount=0;
//break;
default:
if(IsContainer(theChildTag)){
CTagList* theCloseTags=gHTMLElements[theChildTag].GetAutoCloseEndTags();
if(theCloseTags){
PRInt32 thePeerIndex=theCloseTags->GetTopmostIndexOf(mBodyContext->mTags);
theChildTag=(kNotFound<thePeerIndex) ? mBodyContext->mTags[thePeerIndex] : theChildTag;
{
//now check to see if this token should be omitted, or
//if it's gated from closing by the presence of another tag.
if(PR_TRUE==CanOmitEndTag(mBodyContext->Last(),theChildTag)) {
UpdateStyleStackForCloseTag(theChildTag,theChildTag);
}
else {
eHTMLTags theTarget=FindAutoCloseTargetForEndTag(theChildTag,mBodyContext->mTags);
if(eHTMLTag_unknown!=theTarget) {
result=CloseContainersTo(theTarget,PR_TRUE);
}
}
result=CloseContainersTo(theChildTag,PR_TRUE);
}
//
break;
}
return result;
@ -1145,11 +1262,6 @@ nsresult CNavDTD::HandleScriptToken(nsCParserNode& aNode) {
PRInt32 attrCount=aNode.GetAttributeCount(PR_TRUE);
nsresult result=AddLeaf(aNode);
CParserContext* theContext=mParser->PeekContext();
if(theContext && theContext->mPrevContext && (CParserContext::eCTString==theContext->mContextType)) {
mParser->PopContext();
delete theContext;
}
return result;
}
@ -1337,28 +1449,6 @@ PRBool CNavDTD::CanPropagate(eHTMLTags aParentTag,eHTMLTags aChildTag) const {
return result;
}
/**
* Call this to see if you have a closeable peer on the stack that
* is ABOVE one of its root tags.
*
* @update gess 3/25/98
* @param aRootTagList -- list of root tags for aTag
* @param aTag -- tag to test for containership
* @return PR_TRUE if given tag can contain other tags
*/
PRBool HasCloseablePeerAboveRoot(CTagList& aRootTagList,nsTagStack& aTagStack,eHTMLTags aTag) {
PRInt32 theRootIndex=aRootTagList.GetTopmostIndexOf(aTagStack);
CTagList* theCloseTags=gHTMLElements[aTag].GetAutoCloseStartTags();
PRInt32 theChildIndex=-1;
PRBool result=PR_FALSE;
if(theCloseTags) {
theChildIndex=theCloseTags->GetTopmostIndexOf(aTagStack);
}
else {
theChildIndex=aTagStack.GetTopmostIndexOf(aTag);
}
return PRBool(theRootIndex<theChildIndex);
}
/**
* This method gets called to determine whether a given
@ -1407,7 +1497,9 @@ PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const {
default:
if(FindTagInSet(aChild,gFormElementTags,sizeof(gFormElementTags)/sizeof(eHTMLTag_unknown)))
result=!HasOpenContainer(eHTMLTag_form);
else result=FindTagInSet(aChild,gWhitespaceTags,sizeof(gWhitespaceTags)/sizeof(eHTMLTag_unknown));
else if(!gHTMLElements[aParent].CanContain(aChild)) {
result=PR_TRUE;
}
}
break;
@ -1431,6 +1523,9 @@ PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const {
//ok, since no parent claimed it, test based on the child...
switch(aChild) {
case eHTMLTag_textarea:
break;
case eHTMLTag_userdefined:
case eHTMLTag_comment:
result=PR_TRUE;
@ -1443,7 +1538,7 @@ PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const {
// case eHTMLTag_input:
case eHTMLTag_fieldset: case eHTMLTag_isindex:
case eHTMLTag_label: case eHTMLTag_legend:
case eHTMLTag_select: case eHTMLTag_textarea:
case eHTMLTag_select: //case eHTMLTag_textarea:
case eHTMLTag_option:
result=!HasOpenContainer(eHTMLTag_form);
break;
@ -1542,65 +1637,6 @@ PRBool IsCompatibleTag(eHTMLTags aTag1,eHTMLTags aTag2) {
return result;
}
/**
* This method is called to determine whether or not an END tag
* can be autoclosed. This means that based on the current
* context, the stack should be closed to the nearest matching
* tag.
*
* @param aTag -- tag enum of child to be tested
* @return PR_TRUE if autoclosure should occur
*/
eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack,PRInt32 aChildIndex) {
int theTopIndex=aTagStack.mCount;
eHTMLTags aPrevTag=aTagStack.mTags[theTopIndex-1];
if(nsHTMLElement::IsContainer(aCurrentTag)){
if(aPrevTag==aCurrentTag){
return aCurrentTag;
}
if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
/*here's what to do:
Our here is sitting at aChildIndex. There are other tags above it
on the stack. We have to try to close them out, but we may encounter
one that can block us. The way to tell is by comparing each tag on
the stack against our closeTag and rootTag list.
For each tag above our here on the stack, ask 3 questions:
1. Is it in the closeTag list? If so, the we can skip over it
2. Is it in the rootTag list? If so, then we're gated by it
3. Otherwise its non-specified and we simply presume we can close it.
*/
CTagList* theCloseTags=gHTMLElements[aCurrentTag].GetAutoCloseEndTags();
CTagList* theRootTags=gHTMLElements[aCurrentTag].GetRootTags();
if(theCloseTags){
while(aChildIndex<--theTopIndex) {
eHTMLTags theNextTag=aTagStack.mTags[theTopIndex];
if(PR_FALSE==theCloseTags->Contains(theNextTag)) {
if(PR_TRUE==theRootTags->Contains(theNextTag)) {
return eHTMLTag_unknown; //we encountered a tag in root list so fail (because we're gated).
}
//otherwise presume it's something we can simply ignore and continue search...
}
//otherwise its in the close list so skip to next tag...
}
return aCurrentTag; //if you make it here, we're ungated and found a target!
}//if
else if(theRootTags) {
//since we didn't find any close tags, see if there is an instance of aCurrentTag
//above the stack from the roottag.
if(HasCloseablePeerAboveRoot(*theRootTags,aTagStack,aCurrentTag))
return aCurrentTag;
else return eHTMLTag_unknown;
}
} //if
} //if
return eHTMLTag_unknown;
}
/**
* This method gets called to determine whether a given
@ -1613,62 +1649,34 @@ eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsTagStack& aTagSta
PRBool CNavDTD::CanOmitEndTag(eHTMLTags aParent,eHTMLTags aChild) const {
PRBool result=PR_FALSE;
//begin with some simple (and obvious) cases...
switch((eHTMLTags)aChild) {
if(gHTMLElements[aChild].CanOmitEndTag(aParent)) {
return PR_TRUE;
}
case eHTMLTag_userdefined:
case eHTMLTag_comment:
result=PR_TRUE;
break;
case eHTMLTag_a:
result=!HasOpenContainer(aChild);
break;
case eHTMLTag_html:
case eHTMLTag_body:
result=PR_TRUE;
break;
case eHTMLTag_newline:
case eHTMLTag_whitespace:
switch(aParent) {
case eHTMLTag_html: case eHTMLTag_head:
case eHTMLTag_title: case eHTMLTag_map:
case eHTMLTag_tr: case eHTMLTag_table:
case eHTMLTag_thead: case eHTMLTag_tfoot:
case eHTMLTag_tbody: case eHTMLTag_col:
case eHTMLTag_colgroup: case eHTMLTag_unknown:
result=PR_TRUE;
default:
break;
} //switch
break;
//It turns out that a <Hn> can be closed by any other <H?>
//This code makes them all seem compatible.
case eHTMLTag_h1: case eHTMLTag_h2:
case eHTMLTag_h3: case eHTMLTag_h4:
case eHTMLTag_h5: case eHTMLTag_h6:
if(FindTagInSet(aParent,gHeadingTags,sizeof(gHeadingTags)/sizeof(eHTMLTag_unknown))) {
result=PR_FALSE;
break;
/*
CTagList* theRootTags=gHTMLElements[aChild].GetRootTags();
if(theRootTags) {
PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(mBodyContext->mTags);
PRInt32 theChildIndex=GetTopmostIndexOf(aChild);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChild].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(mBodyContext->mTags);
}
//Otherwise, IT's OK TO FALL THROUGH HERE...
}
result=!PRBool(theRootIndex<theChildIndex);
}
*/
PRInt32 theChildIndex=GetTopmostIndexOf(aChild);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChild].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(mBodyContext->mTags);
}
}
result=PRBool(kNotFound==theChildIndex);
default:
{
PRInt32 theTagPos=GetTopmostIndexOf(aChild);
if(kNotFound!=theTagPos) {
eHTMLTags theTarget=FindAutoCloseTargetForEndTag(aChild,mBodyContext->mTags,theTagPos);
result=PRBool(eHTMLTag_unknown==theTarget);
}
else result=PR_TRUE;
}
break;
} //switch
return result;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -48,7 +48,7 @@ public:
PRInt32 GetTopmostIndexOf(nsTagStack& aTagStack);
PRInt32 GetBottommostIndexOf(nsTagStack& aTagStack,PRInt32 aStartOffset);
PRBool Contains(eHTMLTags aTag);
inline PRBool Contains(eHTMLTags aTag);
eHTMLTags mTags[5];
eHTMLTags* mTagList;
@ -76,8 +76,10 @@ struct nsHTMLElement {
static PRBool IsBlockCloser(eHTMLTags aTag);
CTagList* GetRootTags(void) const {return mRootNodes;}
CTagList* GetEndRootTags(void) const {return mEndRootNodes;}
CTagList* GetAutoCloseStartTags(void) const {return mAutocloseStart;}
CTagList* GetAutoCloseEndTags(void) const {return mAutocloseEnd;}
CTagList* GetSynonymousTags(void) const {return mSynonymousTags;}
static PRBool IsBlockParent(eHTMLTags aTag);
static PRBool IsInlineParent(eHTMLTags aTag);
@ -85,11 +87,14 @@ struct nsHTMLElement {
CTagList* GetSpecialChildren(void) const {return mSpecialKids;}
CTagList* GetSpecialParents(void) const {return mSpecialParents;}
PRBool IsMemberOf(PRInt32 aType) const;
PRBool CanContainType(PRInt32 aType) const;
eHTMLTags GetTag(void) const {return mTagID;}
PRBool CanContain(eHTMLTags aChild) const;
PRBool CanOmitStartTag(eHTMLTags aChild) const;
PRBool CanOmitEndTag(eHTMLTags aChild) const;
PRBool CanOmitEndTag(eHTMLTags aParent) const;
PRBool CanContainSelf() const;
PRBool HasSpecialProperty(PRInt32 aProperty) const;
@ -101,9 +106,11 @@ struct nsHTMLElement {
static PRBool IsTextTag(eHTMLTags aTag);
eHTMLTags mTagID;
CTagList* mRootNodes; //These are the tags above which you many not autoclose
CTagList* mRootNodes; //These are the tags above which you many not autoclose a START tag
CTagList* mEndRootNodes; //These are the tags above which you many not autoclose an END tag
CTagList* mAutocloseStart; //these are the start tags that you can automatically close with this START tag
CTagList* mAutocloseEnd; //these are the start tags that you can automatically close with this END tag
CTagList* mSynonymousTags; //These are morally equivalent; an end tag for one can close a start tag for another (like <Hn>)
int mParentBits; //defines groups that can contain this element
int mInclusionBits; //defines parental and containment rules
int mExclusionBits; //defines things you CANNOT contain
@ -118,6 +125,7 @@ extern nsHTMLElement gHTMLElements[];
//special property bits...
static const int kDiscardTag = 0x0001; //tells us to toss this tag
static const int kOmitEndTag = 0x0002; //safely ignore end tag
#endif

Просмотреть файл

@ -580,7 +580,7 @@ nsresult CCDATASectionToken::Consume(PRUnichar aChar, nsScanner& aScanner) {
/*
* default constructor
* Default constructor
*
* @update gess 3/25/98
* @param aName -- string to init token name with
@ -591,7 +591,7 @@ CCommentToken::CCommentToken() : CHTMLToken(eHTMLTag_comment) {
/*
* Default constructor
* Copy constructor
*
* @update gess 3/25/98
* @param
@ -601,47 +601,140 @@ CCommentToken::CCommentToken(const nsString& aName) : CHTMLToken(aName) {
mTypeID=eHTMLTag_comment;
}
/*
* This method consumes a comment using the (CORRECT) comment parsing
* algorithm supplied by W3C.
*
* @update gess 01/04/99
* @param
* @param
* @return
*/
nsresult ConsumeStrictComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString) {
static nsAutoString gMinus("-");
nsresult result=NS_OK;
/*********************************************************
NOTE: This algorithm does a fine job of handling comments
when they're formatted per spec, but if they're not
we don't handle them well. For example, we gack
on the following:
<!-- xx -- xx -->
*********************************************************/
aString="<!";
while(NS_OK==result) {
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
aString+=aChar;
if(kMinus==aChar) {
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
if(kMinus==aChar) {
//in this case, we're reading a long-form comment <-- xxx -->
aString+=aChar;
result=aScanner.ReadWhile(aString,gMinus,PR_TRUE,PR_FALSE); //get all available '---'
if(NS_OK==result) {
PRInt32 findpos=-1;
nsAutoString temp("");
//Read to the first ending sequence '--'
while((kNotFound==findpos) && (NS_OK==result)) {
result=aScanner.ReadUntil(temp,kMinus,PR_TRUE);
findpos=temp.RFind("--");
}
aString+=temp;
if(NS_OK==result) {
result=aScanner.ReadWhile(aString,gMinus,PR_TRUE,PR_FALSE); //get all available '---'
if(NS_OK==result) {
temp="->";
result=aScanner.ReadUntil(aString,temp,PR_FALSE,PR_FALSE);
}
}
}
} //
else break; //go find '>'
}
}//if
else if(kGreaterThan==aChar) {
return result;
}
else break; //go find '>'
}//if
}//while
if(NS_OK==result) {
//if you're here, we're consuming a "short-form" comment
result=aScanner.ReadUntil(aString,kGreaterThan,PR_TRUE);
}
return result;
}
/*
* This method consumes a comment using common (actually non-standard)
* algorithm that seems to work against the content on the web.
*
* @update gess 01/04/99
* @param
* @param
* @return
*/
nsresult ConsumeComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString) {
static nsAutoString gMinus("-");
nsresult result=NS_OK;
/*********************************************************
NOTE: This algorithm does a fine job of handling comments
commonly used, but it doesn't really consume them
per spec (But then, neither does IE or Nav).
*********************************************************/
aString="<!";
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
aString+=aChar;
if(kMinus==aChar) {
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
if(kMinus==aChar) {
//in this case, we're reading a long-form comment <-- xxx -->
aString+=aChar;
nsAutoString temp("");
PRBool done=PR_FALSE;
PRInt32 findpos=kNotFound;
result=aScanner.ReadWhile(temp,gMinus,PR_TRUE,PR_TRUE); //get all available '---'
while((kNotFound==findpos) && (NS_OK==result)) {
result=aScanner.ReadUntil(temp,kMinus,PR_TRUE);
if(NS_OK==result) {
result=aScanner.ReadWhile(temp,gMinus,PR_TRUE,PR_TRUE); //get all available '---'
}
findpos=temp.RFind("->");
aString+=temp;
temp="";
} //while
return result;
} //if
}//if
}//if
}//if
if(NS_OK==result) {
//Read up to the closing '>'
result=aScanner.ReadUntil(aString,kGreaterThan,PR_TRUE);
}
return result;
}
/*
* Consume the identifier portion of the comment.
* Note that we've already eaten the "<!" portion.
*
* @update gess 3/25/98
* @update gess 1/27/99
* @param aChar -- last char consumed from stream
* @param aScanner -- controller of underlying input source
* @return error result
*/
nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner) {
nsresult result=NS_OK;
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
mTextValue="<!";
if(kMinus==aChar) {
mTextValue+="-";
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
if(kMinus==aChar) {
//in this case, we're reading a long-form comment <-- xxx -->
mTextValue+="-";
PRInt32 findpos=-1;
while((findpos<3) && (NS_OK==result)) {
result=aScanner.ReadUntil(mTextValue,kMinus,PR_TRUE);
findpos=mTextValue.RFind("--");
}
if(NS_OK==result) {
result=aScanner.ReadUntil(mTextValue,kGreaterThan,PR_TRUE); //now skip to '>'
}
return result;
}
}
}
}
if(NS_OK==result) {
//if you're here, we're consuming a "short-form" comment
mTextValue+=aChar;
result=aScanner.ReadUntil(mTextValue,kGreaterThan,PR_TRUE);
}
PRBool theStrictForm=PR_FALSE;
nsresult result=(theStrictForm) ? ConsumeStrictComment(aChar,aScanner,mTextValue) : ConsumeComment(aChar,aScanner,mTextValue);
return result;
}
@ -842,7 +935,7 @@ void CAttributeToken::DebugDumpToken(ostream& out) {
mTextValue.ToCString(buffer,sizeof(buffer)-1);
out << buffer << ": " << mTypeID << endl;
}
/*
* This general purpose method is used when you want to
@ -872,6 +965,7 @@ nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScann
PRUnichar ch=aString.Last();
if(ch!=aChar)
aString+=aChar;
aString.StripChars("\r\n");
return result;
}

Просмотреть файл

@ -141,7 +141,7 @@ CSharedParserObjects gSharedParserObjects;
* @param
* @return
*/
nsParser::nsParser(nsITokenObserver* anObserver) : mCommand("") {
nsParser::nsParser(nsITokenObserver* anObserver) : mCommand(""), mUnusedInput("") {
NS_INIT_REFCNT();
mParserFilter = 0;
mObserver = 0;
@ -519,7 +519,21 @@ CParserContext* nsParser::PopContext() {
* and tokenize input (TRUE), or whether it just caches input to be
* parsed later (FALSE).
*
* @update vidur 12/11/98
* @update gess 1/29/99
* @param aState determines whether we parse/tokenize or just cache.
* @return current state
*/
void nsParser::SetUnusedInput(nsString& aBuffer) {
mUnusedInput=aBuffer;
}
/**
* Call this when you want control whether or not the parser will parse
* and tokenize input (TRUE), or whether it just caches input to be
* parsed later (FALSE).
*
* @update gess 1/29/99
* @param aState determines whether we parse/tokenize or just cache.
* @return current state
*/
@ -629,32 +643,36 @@ nsresult nsParser::Parse(nsString& aSourceBuffer,PRBool anHTMLString,PRBool aEna
//NOTE: Make sure that updates to this method don't cause
// bug #2361 to break again!
mDTDVerification=aEnableVerify;
nsresult result=NS_OK;
CParserContext* pc=0;
if(aSourceBuffer.Length() || mUnusedInput.Length()) {
mDTDVerification=aEnableVerify;
CParserContext* pc=0;
if((!mParserContext) || (mParserContext->mKey!=&aSourceBuffer)) {
//only make a new context if we dont have one, OR if we do, but has a different context key...
pc=new CParserContext(new nsScanner(aSourceBuffer),&aSourceBuffer,0);
if(pc) {
PushContext(*pc);
pc->mStreamListenerState=eOnStart;
pc->mContextType=CParserContext::eCTString;
if(PR_TRUE==anHTMLString)
pc->mSourceType="text/html";
}
else return NS_ERROR_OUT_OF_MEMORY;
}
else {
pc=mParserContext;
if((!mParserContext) || (mParserContext->mKey!=&aSourceBuffer)) {
//only make a new context if we dont have one, OR if we do, but has a different context key...
pc=new CParserContext(new nsScanner(mUnusedInput),&aSourceBuffer,0);
if(pc) {
PushContext(*pc);
pc->mStreamListenerState=eOnStart;
pc->mContextType=CParserContext::eCTString;
if(PR_TRUE==anHTMLString)
pc->mSourceType="text/html";
}
else return NS_ERROR_OUT_OF_MEMORY;
}
else {
pc=mParserContext;
pc->mScanner->Append(mUnusedInput);
}
pc->mScanner->Append(aSourceBuffer);
}
pc->mMultipart=!aLastCall;
result=ResumeParse();
if(aLastCall) {
pc=PopContext();
delete pc;
}
pc->mMultipart=!aLastCall;
result=ResumeParse();
if(aLastCall) {
pc->mScanner->CopyUnusedData(mUnusedInput);
pc=PopContext();
delete pc;
}//if
}//if
return result;
}

Просмотреть файл

@ -177,6 +177,19 @@ friend class CTokenHandler;
*/
virtual PRBool EnableParser(PRBool aState);
/**
* This rather arcane method (hack) is used as a signal between the
* DTD and the parser. It allows the DTD to tell the parser that content
* that comes through (parser::parser(string)) but not consumed should
* propagate into the next string based parse call.
*
* @update gess 9/1/98
* @param aState determines whether we propagate unused string content.
* @return current state
*/
void SetUnusedInput(nsString& aBuffer);
/**
* This method gets called (automatically) during incremental parsing
* @update gess5/11/98
@ -304,6 +317,7 @@ protected:
nsString mCommand;
PRInt32 mStreamStatus;
nsITokenObserver* mTokenObserver;
nsString mUnusedInput;
};

Просмотреть файл

@ -520,6 +520,21 @@ nsString& nsScanner::GetBuffer(void) {
return mBuffer;
}
/**
* Call this to copy bytes out of the scanner that have not yet been consumed
* by the tokenization process.
*
* @update gess 5/12/98
* @param aCopyBuffer is where the scanner buffer will be copied to
* @return nada
*/
void nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
PRInt32 theLen=mBuffer.Length();
if(0<theLen) {
mBuffer.Right(aCopyBuffer,theLen-mOffset);
}
}
/**
* Retrieve the name of the file that the scanner is reading from.
* In some cases, it's just a given name, because the scanner isn't

Просмотреть файл

@ -243,6 +243,16 @@ class nsScanner {
*/
nsString& GetBuffer(void);
/**
* Call this to copy bytes out of the scanner that have not yet been consumed
* by the tokenization process.
*
* @update gess 5/12/98
* @param aCopyBuffer is where the scanner buffer will be copied to
* @return nada
*/
void CopyUnusedData(nsString& aCopyBuffer);
/**
* Retrieve the name of the file that the scanner is reading from.
* In some cases, it's just a given name, because the scanner isn't

Просмотреть файл

@ -1268,7 +1268,7 @@ nsHTMLDocument::WriteCommon(JSContext *cx,
str.Append('\n');
}
result = mParser->Parse(str, PR_TRUE,PR_FALSE,PR_FALSE);
result = mParser->Parse(str, PR_TRUE,PR_FALSE,PR_TRUE);
if (NS_OK != result) {
return result;
}

Просмотреть файл

@ -696,23 +696,31 @@ PRInt32 GetTopmostIndexOf(eHTMLTags aTag,nsTagStack& aTagStack) {
*/
eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack) {
int theTopIndex=aTagStack.mCount;
eHTMLTags aPrevTag=aTagStack.mTags[theTopIndex-1];
eHTMLTags thePrevTag=aTagStack.Last();
if(nsHTMLElement::IsContainer(aCurrentTag)){
if(aPrevTag==aCurrentTag) {
if(thePrevTag==aCurrentTag) {
return (gHTMLElements[aCurrentTag].CanContainSelf()) ? eHTMLTag_unknown: aCurrentTag;
}
if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
PRInt32 theRootIndex=kNotFound;
CTagList* theRootTags=gHTMLElements[aCurrentTag].GetRootTags();
if(theRootTags) {
PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack);
theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack);
CTagList* theStartTags=gHTMLElements[aCurrentTag].GetAutoCloseStartTags();
PRInt32 thePeerIndex=kNotFound;
if(theStartTags){
thePeerIndex=theStartTags->GetBottommostIndexOf(aTagStack,theRootIndex+1);
}
else thePeerIndex=GetTopmostIndexOf(aCurrentTag,aTagStack);
else {
//this extra check is need to handle case like this: <DIV><P><DIV>
//the new div can close the P,but doesn't close the top DIV.
thePeerIndex=GetTopmostIndexOf(aCurrentTag,aTagStack);
if(gHTMLElements[aCurrentTag].CanContainSelf()) {
thePeerIndex++;
}
}
if(theRootIndex<thePeerIndex) {
return aTagStack.mTags[thePeerIndex]; //return the tag that was used in peer test.
}
@ -724,14 +732,19 @@ eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagS
if(kNotFound!=thePeerIndex){
if(thePeerIndex==theTopIndex-1) {
//the guy you can autoclose is on the top of the stack...
return aPrevTag;
return thePrevTag;
} //if
} //if
}//if
else if(kNotFound<theRootIndex) {
//This block handles our fallback cases like: <html><body><center><p> <- <table>
while((theRootIndex<--theTopIndex) && (!gHTMLElements[aTagStack.mTags[theTopIndex]].CanContain(aCurrentTag))) {
}
return aTagStack.mTags[theTopIndex+1];
//return aTagStack.mTags[theRootIndex+1];
}
} //if
else if(nsHTMLElement::IsInlineElement(aCurrentTag)) {
}//if
} //if
return eHTMLTag_unknown;
}
@ -748,6 +761,24 @@ eHTMLTags FindAutoCloseTargetForStartTag(eHTMLTags aCurrentTag,nsTagStack& aTagS
*/
PRBool CanBeContained(eHTMLTags aChildTag,nsTagStack& aTagStack) {
PRBool result=PR_TRUE;
CTagList* theRootTags=gHTMLElements[aChildTag].GetRootTags();
if(theRootTags) {
PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(aTagStack);
PRInt32 theChildIndex=aTagStack.GetTopmostIndexOf(aChildTag);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(aTagStack);
}
}
if(theRootIndex<theChildIndex){
eHTMLTags thePrevTag=aTagStack.Last();
result=gHTMLElements[thePrevTag].CanContainType(gHTMLElements[aChildTag].mParentBits);
return result;
}
}
return result;
}
@ -977,6 +1008,114 @@ nsresult CNavDTD::HandleStartToken(CToken* aToken) {
return result;
}
/**
* Call this to see if you have a closeable peer on the stack that
* is ABOVE one of its root tags.
*
* @update gess 3/25/98
* @param aRootTagList -- list of root tags for aTag
* @param aTag -- tag to test for containership
* @return PR_TRUE if given tag can contain other tags
*/
PRBool HasCloseablePeerAboveRoot(CTagList& aRootTagList,nsTagStack& aTagStack,eHTMLTags aTag) {
PRInt32 theRootIndex=aRootTagList.GetTopmostIndexOf(aTagStack);
CTagList* theCloseTags=gHTMLElements[aTag].GetAutoCloseStartTags();
PRInt32 theChildIndex=-1;
PRBool result=PR_FALSE;
if(theCloseTags) {
theChildIndex=theCloseTags->GetTopmostIndexOf(aTagStack);
}
else {
theChildIndex=aTagStack.GetTopmostIndexOf(aTag);
}
return PRBool(theRootIndex<theChildIndex);
}
/**
* Call this to find the index of a given child, or (if not found)
* the index of its nearest synonym.
*
* @update gess 3/25/98
* @param aTagStack -- list of open tags
* @param aTag -- tag to test for containership
* @return index of kNotFound
*/
PRInt32 GetIndexOfChildOrSynonym(nsTagStack& aTagStack,eHTMLTags aChildTag) {
PRInt32 theChildIndex=aTagStack.GetTopmostIndexOf(aChildTag);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(aTagStack);
}
}
return theChildIndex;
}
/**
* This method is called to determine whether or not an END tag
* can be autoclosed. This means that based on the current
* context, the stack should be closed to the nearest matching
* tag.
*
* @param aTag -- tag enum of child to be tested
* @return PR_TRUE if autoclosure should occur
*/
eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack) {
int theTopIndex=aTagStack.mCount;
eHTMLTags thePrevTag=aTagStack.Last();
if(nsHTMLElement::IsContainer(aCurrentTag)){
PRInt32 theChildIndex=GetIndexOfChildOrSynonym(aTagStack,aCurrentTag);
if(kNotFound<theChildIndex) {
if(thePrevTag==aTagStack.mTags[theChildIndex]){
return aTagStack.mTags[theChildIndex];
}
if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
/*here's what to do:
Our here is sitting at aChildIndex. There are other tags above it
on the stack. We have to try to close them out, but we may encounter
one that can block us. The way to tell is by comparing each tag on
the stack against our closeTag and rootTag list.
For each tag above our hero on the stack, ask 3 questions:
1. Is it in the closeTag list? If so, the we can skip over it
2. Is it in the rootTag list? If so, then we're gated by it
3. Otherwise its non-specified and we simply presume we can close it.
*/
CTagList* theCloseTags=gHTMLElements[aCurrentTag].GetAutoCloseEndTags();
CTagList* theRootTags=gHTMLElements[aCurrentTag].GetEndRootTags();
if(theCloseTags){
//at a min., this code is needed for H1..H6
while(theChildIndex<--theTopIndex) {
eHTMLTags theNextTag=aTagStack.mTags[theTopIndex];
if(PR_FALSE==theCloseTags->Contains(theNextTag)) {
if(PR_TRUE==theRootTags->Contains(theNextTag)) {
return eHTMLTag_unknown; //we encountered a tag in root list so fail (because we're gated).
}
//otherwise presume it's something we can simply ignore and continue search...
}
//otherwise its in the close list so skip to next tag...
}
return aCurrentTag; //if you make it here, we're ungated and found a target!
}//if
else if(theRootTags) {
//since we didn't find any close tags, see if there is an instance of aCurrentTag
//above the stack from the roottag.
if(HasCloseablePeerAboveRoot(*theRootTags,aTagStack,aCurrentTag))
return aCurrentTag;
else return eHTMLTag_unknown;
}
} //if
}//if
} //if
return eHTMLTag_unknown;
}
/**
* This method gets called when an end token has been
@ -995,23 +1134,7 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) {
NS_PRECONDITION(0!=aToken,kNullToken);
nsresult result=NS_OK;
CEndToken* et = (CEndToken*)(aToken);
eHTMLTags theChildTag=(eHTMLTags)et->GetTypeID();
// 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 the explicit style tag (goofy, huh?)
//now check to see if this token should be omitted, or
//if it's gated from closing by the presence of another tag.
if(PR_TRUE==CanOmitEndTag(mBodyContext->Last(),theChildTag)) {
UpdateStyleStackForCloseTag(theChildTag,theChildTag);
return result;
}
eHTMLTags theChildTag=(eHTMLTags)aToken->GetTypeID();
nsCParserNode theNode((CHTMLToken*)aToken,mLineNumber);
switch(theChildTag) {
@ -1029,26 +1152,20 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) {
result=CloseContainer(theNode,theChildTag,PR_FALSE);
break;
case eHTMLTag_td:
case eHTMLTag_th:
//result=CloseContainersTo(theChildTag,PR_TRUE);
// Empty the transient style stack (we just closed any extra
// ones off so it's safe to do it now) because they don't carry
// forward across table cell boundaries.
//mBodyContext->mStyles->mCount=0;
//break;
default:
if(IsContainer(theChildTag)){
CTagList* theCloseTags=gHTMLElements[theChildTag].GetAutoCloseEndTags();
if(theCloseTags){
PRInt32 thePeerIndex=theCloseTags->GetTopmostIndexOf(mBodyContext->mTags);
theChildTag=(kNotFound<thePeerIndex) ? mBodyContext->mTags[thePeerIndex] : theChildTag;
{
//now check to see if this token should be omitted, or
//if it's gated from closing by the presence of another tag.
if(PR_TRUE==CanOmitEndTag(mBodyContext->Last(),theChildTag)) {
UpdateStyleStackForCloseTag(theChildTag,theChildTag);
}
else {
eHTMLTags theTarget=FindAutoCloseTargetForEndTag(theChildTag,mBodyContext->mTags);
if(eHTMLTag_unknown!=theTarget) {
result=CloseContainersTo(theTarget,PR_TRUE);
}
}
result=CloseContainersTo(theChildTag,PR_TRUE);
}
//
break;
}
return result;
@ -1145,11 +1262,6 @@ nsresult CNavDTD::HandleScriptToken(nsCParserNode& aNode) {
PRInt32 attrCount=aNode.GetAttributeCount(PR_TRUE);
nsresult result=AddLeaf(aNode);
CParserContext* theContext=mParser->PeekContext();
if(theContext && theContext->mPrevContext && (CParserContext::eCTString==theContext->mContextType)) {
mParser->PopContext();
delete theContext;
}
return result;
}
@ -1337,28 +1449,6 @@ PRBool CNavDTD::CanPropagate(eHTMLTags aParentTag,eHTMLTags aChildTag) const {
return result;
}
/**
* Call this to see if you have a closeable peer on the stack that
* is ABOVE one of its root tags.
*
* @update gess 3/25/98
* @param aRootTagList -- list of root tags for aTag
* @param aTag -- tag to test for containership
* @return PR_TRUE if given tag can contain other tags
*/
PRBool HasCloseablePeerAboveRoot(CTagList& aRootTagList,nsTagStack& aTagStack,eHTMLTags aTag) {
PRInt32 theRootIndex=aRootTagList.GetTopmostIndexOf(aTagStack);
CTagList* theCloseTags=gHTMLElements[aTag].GetAutoCloseStartTags();
PRInt32 theChildIndex=-1;
PRBool result=PR_FALSE;
if(theCloseTags) {
theChildIndex=theCloseTags->GetTopmostIndexOf(aTagStack);
}
else {
theChildIndex=aTagStack.GetTopmostIndexOf(aTag);
}
return PRBool(theRootIndex<theChildIndex);
}
/**
* This method gets called to determine whether a given
@ -1407,7 +1497,9 @@ PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const {
default:
if(FindTagInSet(aChild,gFormElementTags,sizeof(gFormElementTags)/sizeof(eHTMLTag_unknown)))
result=!HasOpenContainer(eHTMLTag_form);
else result=FindTagInSet(aChild,gWhitespaceTags,sizeof(gWhitespaceTags)/sizeof(eHTMLTag_unknown));
else if(!gHTMLElements[aParent].CanContain(aChild)) {
result=PR_TRUE;
}
}
break;
@ -1431,6 +1523,9 @@ PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const {
//ok, since no parent claimed it, test based on the child...
switch(aChild) {
case eHTMLTag_textarea:
break;
case eHTMLTag_userdefined:
case eHTMLTag_comment:
result=PR_TRUE;
@ -1443,7 +1538,7 @@ PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild) const {
// case eHTMLTag_input:
case eHTMLTag_fieldset: case eHTMLTag_isindex:
case eHTMLTag_label: case eHTMLTag_legend:
case eHTMLTag_select: case eHTMLTag_textarea:
case eHTMLTag_select: //case eHTMLTag_textarea:
case eHTMLTag_option:
result=!HasOpenContainer(eHTMLTag_form);
break;
@ -1542,65 +1637,6 @@ PRBool IsCompatibleTag(eHTMLTags aTag1,eHTMLTags aTag2) {
return result;
}
/**
* This method is called to determine whether or not an END tag
* can be autoclosed. This means that based on the current
* context, the stack should be closed to the nearest matching
* tag.
*
* @param aTag -- tag enum of child to be tested
* @return PR_TRUE if autoclosure should occur
*/
eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsTagStack& aTagStack,PRInt32 aChildIndex) {
int theTopIndex=aTagStack.mCount;
eHTMLTags aPrevTag=aTagStack.mTags[theTopIndex-1];
if(nsHTMLElement::IsContainer(aCurrentTag)){
if(aPrevTag==aCurrentTag){
return aCurrentTag;
}
if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
/*here's what to do:
Our here is sitting at aChildIndex. There are other tags above it
on the stack. We have to try to close them out, but we may encounter
one that can block us. The way to tell is by comparing each tag on
the stack against our closeTag and rootTag list.
For each tag above our here on the stack, ask 3 questions:
1. Is it in the closeTag list? If so, the we can skip over it
2. Is it in the rootTag list? If so, then we're gated by it
3. Otherwise its non-specified and we simply presume we can close it.
*/
CTagList* theCloseTags=gHTMLElements[aCurrentTag].GetAutoCloseEndTags();
CTagList* theRootTags=gHTMLElements[aCurrentTag].GetRootTags();
if(theCloseTags){
while(aChildIndex<--theTopIndex) {
eHTMLTags theNextTag=aTagStack.mTags[theTopIndex];
if(PR_FALSE==theCloseTags->Contains(theNextTag)) {
if(PR_TRUE==theRootTags->Contains(theNextTag)) {
return eHTMLTag_unknown; //we encountered a tag in root list so fail (because we're gated).
}
//otherwise presume it's something we can simply ignore and continue search...
}
//otherwise its in the close list so skip to next tag...
}
return aCurrentTag; //if you make it here, we're ungated and found a target!
}//if
else if(theRootTags) {
//since we didn't find any close tags, see if there is an instance of aCurrentTag
//above the stack from the roottag.
if(HasCloseablePeerAboveRoot(*theRootTags,aTagStack,aCurrentTag))
return aCurrentTag;
else return eHTMLTag_unknown;
}
} //if
} //if
return eHTMLTag_unknown;
}
/**
* This method gets called to determine whether a given
@ -1613,62 +1649,34 @@ eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsTagStack& aTagSta
PRBool CNavDTD::CanOmitEndTag(eHTMLTags aParent,eHTMLTags aChild) const {
PRBool result=PR_FALSE;
//begin with some simple (and obvious) cases...
switch((eHTMLTags)aChild) {
if(gHTMLElements[aChild].CanOmitEndTag(aParent)) {
return PR_TRUE;
}
case eHTMLTag_userdefined:
case eHTMLTag_comment:
result=PR_TRUE;
break;
case eHTMLTag_a:
result=!HasOpenContainer(aChild);
break;
case eHTMLTag_html:
case eHTMLTag_body:
result=PR_TRUE;
break;
case eHTMLTag_newline:
case eHTMLTag_whitespace:
switch(aParent) {
case eHTMLTag_html: case eHTMLTag_head:
case eHTMLTag_title: case eHTMLTag_map:
case eHTMLTag_tr: case eHTMLTag_table:
case eHTMLTag_thead: case eHTMLTag_tfoot:
case eHTMLTag_tbody: case eHTMLTag_col:
case eHTMLTag_colgroup: case eHTMLTag_unknown:
result=PR_TRUE;
default:
break;
} //switch
break;
//It turns out that a <Hn> can be closed by any other <H?>
//This code makes them all seem compatible.
case eHTMLTag_h1: case eHTMLTag_h2:
case eHTMLTag_h3: case eHTMLTag_h4:
case eHTMLTag_h5: case eHTMLTag_h6:
if(FindTagInSet(aParent,gHeadingTags,sizeof(gHeadingTags)/sizeof(eHTMLTag_unknown))) {
result=PR_FALSE;
break;
/*
CTagList* theRootTags=gHTMLElements[aChild].GetRootTags();
if(theRootTags) {
PRInt32 theRootIndex=theRootTags->GetTopmostIndexOf(mBodyContext->mTags);
PRInt32 theChildIndex=GetTopmostIndexOf(aChild);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChild].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(mBodyContext->mTags);
}
//Otherwise, IT's OK TO FALL THROUGH HERE...
}
result=!PRBool(theRootIndex<theChildIndex);
}
*/
PRInt32 theChildIndex=GetTopmostIndexOf(aChild);
if(kNotFound==theChildIndex) {
CTagList* theSynTags=gHTMLElements[aChild].GetSynonymousTags(); //get the list of tags that THIS tag can close
if(theSynTags) {
theChildIndex=theSynTags->GetTopmostIndexOf(mBodyContext->mTags);
}
}
result=PRBool(kNotFound==theChildIndex);
default:
{
PRInt32 theTagPos=GetTopmostIndexOf(aChild);
if(kNotFound!=theTagPos) {
eHTMLTags theTarget=FindAutoCloseTargetForEndTag(aChild,mBodyContext->mTags,theTagPos);
result=PRBool(eHTMLTag_unknown==theTarget);
}
else result=PR_TRUE;
}
break;
} //switch
return result;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -48,7 +48,7 @@ public:
PRInt32 GetTopmostIndexOf(nsTagStack& aTagStack);
PRInt32 GetBottommostIndexOf(nsTagStack& aTagStack,PRInt32 aStartOffset);
PRBool Contains(eHTMLTags aTag);
inline PRBool Contains(eHTMLTags aTag);
eHTMLTags mTags[5];
eHTMLTags* mTagList;
@ -76,8 +76,10 @@ struct nsHTMLElement {
static PRBool IsBlockCloser(eHTMLTags aTag);
CTagList* GetRootTags(void) const {return mRootNodes;}
CTagList* GetEndRootTags(void) const {return mEndRootNodes;}
CTagList* GetAutoCloseStartTags(void) const {return mAutocloseStart;}
CTagList* GetAutoCloseEndTags(void) const {return mAutocloseEnd;}
CTagList* GetSynonymousTags(void) const {return mSynonymousTags;}
static PRBool IsBlockParent(eHTMLTags aTag);
static PRBool IsInlineParent(eHTMLTags aTag);
@ -85,11 +87,14 @@ struct nsHTMLElement {
CTagList* GetSpecialChildren(void) const {return mSpecialKids;}
CTagList* GetSpecialParents(void) const {return mSpecialParents;}
PRBool IsMemberOf(PRInt32 aType) const;
PRBool CanContainType(PRInt32 aType) const;
eHTMLTags GetTag(void) const {return mTagID;}
PRBool CanContain(eHTMLTags aChild) const;
PRBool CanOmitStartTag(eHTMLTags aChild) const;
PRBool CanOmitEndTag(eHTMLTags aChild) const;
PRBool CanOmitEndTag(eHTMLTags aParent) const;
PRBool CanContainSelf() const;
PRBool HasSpecialProperty(PRInt32 aProperty) const;
@ -101,9 +106,11 @@ struct nsHTMLElement {
static PRBool IsTextTag(eHTMLTags aTag);
eHTMLTags mTagID;
CTagList* mRootNodes; //These are the tags above which you many not autoclose
CTagList* mRootNodes; //These are the tags above which you many not autoclose a START tag
CTagList* mEndRootNodes; //These are the tags above which you many not autoclose an END tag
CTagList* mAutocloseStart; //these are the start tags that you can automatically close with this START tag
CTagList* mAutocloseEnd; //these are the start tags that you can automatically close with this END tag
CTagList* mSynonymousTags; //These are morally equivalent; an end tag for one can close a start tag for another (like <Hn>)
int mParentBits; //defines groups that can contain this element
int mInclusionBits; //defines parental and containment rules
int mExclusionBits; //defines things you CANNOT contain
@ -118,6 +125,7 @@ extern nsHTMLElement gHTMLElements[];
//special property bits...
static const int kDiscardTag = 0x0001; //tells us to toss this tag
static const int kOmitEndTag = 0x0002; //safely ignore end tag
#endif

Просмотреть файл

@ -580,7 +580,7 @@ nsresult CCDATASectionToken::Consume(PRUnichar aChar, nsScanner& aScanner) {
/*
* default constructor
* Default constructor
*
* @update gess 3/25/98
* @param aName -- string to init token name with
@ -591,7 +591,7 @@ CCommentToken::CCommentToken() : CHTMLToken(eHTMLTag_comment) {
/*
* Default constructor
* Copy constructor
*
* @update gess 3/25/98
* @param
@ -601,47 +601,140 @@ CCommentToken::CCommentToken(const nsString& aName) : CHTMLToken(aName) {
mTypeID=eHTMLTag_comment;
}
/*
* This method consumes a comment using the (CORRECT) comment parsing
* algorithm supplied by W3C.
*
* @update gess 01/04/99
* @param
* @param
* @return
*/
nsresult ConsumeStrictComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString) {
static nsAutoString gMinus("-");
nsresult result=NS_OK;
/*********************************************************
NOTE: This algorithm does a fine job of handling comments
when they're formatted per spec, but if they're not
we don't handle them well. For example, we gack
on the following:
<!-- xx -- xx -->
*********************************************************/
aString="<!";
while(NS_OK==result) {
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
aString+=aChar;
if(kMinus==aChar) {
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
if(kMinus==aChar) {
//in this case, we're reading a long-form comment <-- xxx -->
aString+=aChar;
result=aScanner.ReadWhile(aString,gMinus,PR_TRUE,PR_FALSE); //get all available '---'
if(NS_OK==result) {
PRInt32 findpos=-1;
nsAutoString temp("");
//Read to the first ending sequence '--'
while((kNotFound==findpos) && (NS_OK==result)) {
result=aScanner.ReadUntil(temp,kMinus,PR_TRUE);
findpos=temp.RFind("--");
}
aString+=temp;
if(NS_OK==result) {
result=aScanner.ReadWhile(aString,gMinus,PR_TRUE,PR_FALSE); //get all available '---'
if(NS_OK==result) {
temp="->";
result=aScanner.ReadUntil(aString,temp,PR_FALSE,PR_FALSE);
}
}
}
} //
else break; //go find '>'
}
}//if
else if(kGreaterThan==aChar) {
return result;
}
else break; //go find '>'
}//if
}//while
if(NS_OK==result) {
//if you're here, we're consuming a "short-form" comment
result=aScanner.ReadUntil(aString,kGreaterThan,PR_TRUE);
}
return result;
}
/*
* This method consumes a comment using common (actually non-standard)
* algorithm that seems to work against the content on the web.
*
* @update gess 01/04/99
* @param
* @param
* @return
*/
nsresult ConsumeComment(PRUnichar aChar, nsScanner& aScanner,nsString& aString) {
static nsAutoString gMinus("-");
nsresult result=NS_OK;
/*********************************************************
NOTE: This algorithm does a fine job of handling comments
commonly used, but it doesn't really consume them
per spec (But then, neither does IE or Nav).
*********************************************************/
aString="<!";
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
aString+=aChar;
if(kMinus==aChar) {
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
if(kMinus==aChar) {
//in this case, we're reading a long-form comment <-- xxx -->
aString+=aChar;
nsAutoString temp("");
PRBool done=PR_FALSE;
PRInt32 findpos=kNotFound;
result=aScanner.ReadWhile(temp,gMinus,PR_TRUE,PR_TRUE); //get all available '---'
while((kNotFound==findpos) && (NS_OK==result)) {
result=aScanner.ReadUntil(temp,kMinus,PR_TRUE);
if(NS_OK==result) {
result=aScanner.ReadWhile(temp,gMinus,PR_TRUE,PR_TRUE); //get all available '---'
}
findpos=temp.RFind("->");
aString+=temp;
temp="";
} //while
return result;
} //if
}//if
}//if
}//if
if(NS_OK==result) {
//Read up to the closing '>'
result=aScanner.ReadUntil(aString,kGreaterThan,PR_TRUE);
}
return result;
}
/*
* Consume the identifier portion of the comment.
* Note that we've already eaten the "<!" portion.
*
* @update gess 3/25/98
* @update gess 1/27/99
* @param aChar -- last char consumed from stream
* @param aScanner -- controller of underlying input source
* @return error result
*/
nsresult CCommentToken::Consume(PRUnichar aChar, nsScanner& aScanner) {
nsresult result=NS_OK;
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
mTextValue="<!";
if(kMinus==aChar) {
mTextValue+="-";
result=aScanner.GetChar(aChar);
if(NS_OK==result) {
if(kMinus==aChar) {
//in this case, we're reading a long-form comment <-- xxx -->
mTextValue+="-";
PRInt32 findpos=-1;
while((findpos<3) && (NS_OK==result)) {
result=aScanner.ReadUntil(mTextValue,kMinus,PR_TRUE);
findpos=mTextValue.RFind("--");
}
if(NS_OK==result) {
result=aScanner.ReadUntil(mTextValue,kGreaterThan,PR_TRUE); //now skip to '>'
}
return result;
}
}
}
}
if(NS_OK==result) {
//if you're here, we're consuming a "short-form" comment
mTextValue+=aChar;
result=aScanner.ReadUntil(mTextValue,kGreaterThan,PR_TRUE);
}
PRBool theStrictForm=PR_FALSE;
nsresult result=(theStrictForm) ? ConsumeStrictComment(aChar,aScanner,mTextValue) : ConsumeComment(aChar,aScanner,mTextValue);
return result;
}
@ -842,7 +935,7 @@ void CAttributeToken::DebugDumpToken(ostream& out) {
mTextValue.ToCString(buffer,sizeof(buffer)-1);
out << buffer << ": " << mTypeID << endl;
}
/*
* This general purpose method is used when you want to
@ -872,6 +965,7 @@ nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScann
PRUnichar ch=aString.Last();
if(ch!=aChar)
aString+=aChar;
aString.StripChars("\r\n");
return result;
}

Просмотреть файл

@ -141,7 +141,7 @@ CSharedParserObjects gSharedParserObjects;
* @param
* @return
*/
nsParser::nsParser(nsITokenObserver* anObserver) : mCommand("") {
nsParser::nsParser(nsITokenObserver* anObserver) : mCommand(""), mUnusedInput("") {
NS_INIT_REFCNT();
mParserFilter = 0;
mObserver = 0;
@ -519,7 +519,21 @@ CParserContext* nsParser::PopContext() {
* and tokenize input (TRUE), or whether it just caches input to be
* parsed later (FALSE).
*
* @update vidur 12/11/98
* @update gess 1/29/99
* @param aState determines whether we parse/tokenize or just cache.
* @return current state
*/
void nsParser::SetUnusedInput(nsString& aBuffer) {
mUnusedInput=aBuffer;
}
/**
* Call this when you want control whether or not the parser will parse
* and tokenize input (TRUE), or whether it just caches input to be
* parsed later (FALSE).
*
* @update gess 1/29/99
* @param aState determines whether we parse/tokenize or just cache.
* @return current state
*/
@ -629,32 +643,36 @@ nsresult nsParser::Parse(nsString& aSourceBuffer,PRBool anHTMLString,PRBool aEna
//NOTE: Make sure that updates to this method don't cause
// bug #2361 to break again!
mDTDVerification=aEnableVerify;
nsresult result=NS_OK;
CParserContext* pc=0;
if(aSourceBuffer.Length() || mUnusedInput.Length()) {
mDTDVerification=aEnableVerify;
CParserContext* pc=0;
if((!mParserContext) || (mParserContext->mKey!=&aSourceBuffer)) {
//only make a new context if we dont have one, OR if we do, but has a different context key...
pc=new CParserContext(new nsScanner(aSourceBuffer),&aSourceBuffer,0);
if(pc) {
PushContext(*pc);
pc->mStreamListenerState=eOnStart;
pc->mContextType=CParserContext::eCTString;
if(PR_TRUE==anHTMLString)
pc->mSourceType="text/html";
}
else return NS_ERROR_OUT_OF_MEMORY;
}
else {
pc=mParserContext;
if((!mParserContext) || (mParserContext->mKey!=&aSourceBuffer)) {
//only make a new context if we dont have one, OR if we do, but has a different context key...
pc=new CParserContext(new nsScanner(mUnusedInput),&aSourceBuffer,0);
if(pc) {
PushContext(*pc);
pc->mStreamListenerState=eOnStart;
pc->mContextType=CParserContext::eCTString;
if(PR_TRUE==anHTMLString)
pc->mSourceType="text/html";
}
else return NS_ERROR_OUT_OF_MEMORY;
}
else {
pc=mParserContext;
pc->mScanner->Append(mUnusedInput);
}
pc->mScanner->Append(aSourceBuffer);
}
pc->mMultipart=!aLastCall;
result=ResumeParse();
if(aLastCall) {
pc=PopContext();
delete pc;
}
pc->mMultipart=!aLastCall;
result=ResumeParse();
if(aLastCall) {
pc->mScanner->CopyUnusedData(mUnusedInput);
pc=PopContext();
delete pc;
}//if
}//if
return result;
}

Просмотреть файл

@ -177,6 +177,19 @@ friend class CTokenHandler;
*/
virtual PRBool EnableParser(PRBool aState);
/**
* This rather arcane method (hack) is used as a signal between the
* DTD and the parser. It allows the DTD to tell the parser that content
* that comes through (parser::parser(string)) but not consumed should
* propagate into the next string based parse call.
*
* @update gess 9/1/98
* @param aState determines whether we propagate unused string content.
* @return current state
*/
void SetUnusedInput(nsString& aBuffer);
/**
* This method gets called (automatically) during incremental parsing
* @update gess5/11/98
@ -304,6 +317,7 @@ protected:
nsString mCommand;
PRInt32 mStreamStatus;
nsITokenObserver* mTokenObserver;
nsString mUnusedInput;
};

Просмотреть файл

@ -520,6 +520,21 @@ nsString& nsScanner::GetBuffer(void) {
return mBuffer;
}
/**
* Call this to copy bytes out of the scanner that have not yet been consumed
* by the tokenization process.
*
* @update gess 5/12/98
* @param aCopyBuffer is where the scanner buffer will be copied to
* @return nada
*/
void nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
PRInt32 theLen=mBuffer.Length();
if(0<theLen) {
mBuffer.Right(aCopyBuffer,theLen-mOffset);
}
}
/**
* Retrieve the name of the file that the scanner is reading from.
* In some cases, it's just a given name, because the scanner isn't

Просмотреть файл

@ -243,6 +243,16 @@ class nsScanner {
*/
nsString& GetBuffer(void);
/**
* Call this to copy bytes out of the scanner that have not yet been consumed
* by the tokenization process.
*
* @update gess 5/12/98
* @param aCopyBuffer is where the scanner buffer will be copied to
* @return nada
*/
void CopyUnusedData(nsString& aCopyBuffer);
/**
* Retrieve the name of the file that the scanner is reading from.
* In some cases, it's just a given name, because the scanner isn't