Back to index

lightning-sunbird  0.9+nobinonly
CNavDTD.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim: set sw=2 ts=2 et tw=80: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 //#define ALLOW_TR_AS_CHILD_OF_TABLE  //by setting this to true, TR is allowable directly in TABLE.
00040 
00041 #define ENABLE_RESIDUALSTYLE  
00042 
00043      
00044 #include "nsDebug.h"
00045 #include "nsIAtom.h"
00046 #include "CNavDTD.h" 
00047 #include "nsHTMLTokens.h"
00048 #include "nsCRT.h"
00049 #include "nsParser.h"
00050 #include "nsIParser.h"
00051 #include "nsIHTMLContentSink.h" 
00052 #include "nsScanner.h"
00053 #include "prenv.h"  //this is here for debug reasons...
00054 #include "prtypes.h"  //this is here for debug reasons...
00055 #include "prio.h"
00056 #include "plstr.h"
00057 #include "nsDTDUtils.h"
00058 #include "nsHTMLTokenizer.h"
00059 #include "nsTime.h"
00060 #include "nsParserNode.h"
00061 #include "nsHTMLEntities.h"
00062 #include "nsLinebreakConverter.h"
00063 #include "nsIFormProcessor.h"
00064 #include "nsVoidArray.h"
00065 #include "nsReadableUtils.h"
00066 #include "nsUnicharUtils.h"
00067 #include "prmem.h"
00068 #include "nsIServiceManager.h"
00069 
00070 #ifdef NS_DEBUG
00071 #include "nsLoggingSink.h"
00072 #endif
00073 
00074 /*
00075  * Ignore kFontStyle and kPhrase tags when the stack is deep, bug 58917.
00076  */
00077 #define FONTSTYLE_IGNORE_DEPTH (MAX_REFLOW_DEPTH*80/100)
00078 #define PHRASE_IGNORE_DEPTH    (MAX_REFLOW_DEPTH*90/100)
00079   
00080 
00081 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);                 
00082 static NS_DEFINE_IID(kIDTDIID,      NS_IDTD_IID);
00083 static NS_DEFINE_IID(kClassIID,     NS_INAVHTML_DTD_IID); 
00084 
00085 static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID); 
00086  
00087 #ifdef DEBUG
00088 static const  char kNullToken[] = "Error: Null token given";
00089 static const  char kInvalidTagStackPos[] = "Error: invalid tag stack position";
00090 #endif
00091 
00092 #include "nsElementTable.h"
00093 
00094 #ifdef MOZ_PERF_METRICS
00095 #  define START_TIMER()                    \
00096     if(mParser) MOZ_TIMER_START(mParser->mParseTime); \
00097     if(mParser) MOZ_TIMER_START(mParser->mDTDTime); 
00098 
00099 #  define STOP_TIMER()                     \
00100     if(mParser) MOZ_TIMER_STOP(mParser->mParseTime); \
00101     if(mParser) MOZ_TIMER_STOP(mParser->mDTDTime); 
00102 #else
00103 #  define STOP_TIMER() 
00104 #  define START_TIMER()
00105 #endif
00106 
00107 /************************************************************************
00108   And now for the main class -- CNavDTD...
00109  ************************************************************************/
00110 
00111 
00112 #define NS_DTD_FLAG_NONE                   0x00000000
00113 #define NS_DTD_FLAG_HAS_OPEN_HEAD          0x00000001
00114 #define NS_DTD_FLAG_HAS_OPEN_BODY          0x00000002
00115 #define NS_DTD_FLAG_HAS_OPEN_FORM          0x00000004
00116 #define NS_DTD_FLAG_HAS_OPEN_SCRIPT        0x00000008
00117 #define NS_DTD_FLAG_HAD_BODY               0x00000010
00118 #define NS_DTD_FLAG_HAD_FRAMESET           0x00000020
00119 #define NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE  0x00000040
00120 #define NS_DTD_FLAG_ALTERNATE_CONTENT      0x00000080 // NOFRAMES, NOSCRIPT 
00121 #define NS_DTD_FLAG_MISPLACED_CONTENT      0x00000100
00122 #define NS_DTD_FLAG_IN_MISPLACED_CONTENT   0x00000200
00123 #define NS_DTD_FLAG_STOP_PARSING           0x00000400
00124 
00135 nsresult CNavDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr)  
00136 {                                                                        
00137   if (NULL == aInstancePtr) {                                            
00138     return NS_ERROR_NULL_POINTER;                                        
00139   }                                                                      
00140 
00141   if(aIID.Equals(kISupportsIID))    {  //do IUnknown...
00142     *aInstancePtr = (nsIDTD*)(this);                                        
00143   }
00144   else if(aIID.Equals(kIDTDIID)) {  //do IParser base class...
00145     *aInstancePtr = (nsIDTD*)(this);                                        
00146   }
00147   else if(aIID.Equals(kClassIID)) {  //do this class...
00148     *aInstancePtr = (CNavDTD*)(this);                                        
00149   }                 
00150   else {
00151     *aInstancePtr=0;
00152     return NS_NOINTERFACE;
00153   }
00154   NS_ADDREF_THIS();
00155   return NS_OK;                                                        
00156 }
00157 
00158 NS_IMPL_ADDREF(CNavDTD)
00159 NS_IMPL_RELEASE(CNavDTD)
00160 
00168 CNavDTD::CNavDTD() : nsIDTD(), 
00169     mMisplacedContent(0), 
00170     mSkippedContent(0),
00171     mSink(0),
00172     mTokenAllocator(0),
00173     mTempContext(0),
00174     mParser(0),       
00175     mTokenizer(0),
00176     mDTDMode(eDTDMode_quirks),
00177     mDocType(eHTML3_Quirks), // why not eHTML_Quirks?
00178     mParserCommand(eViewNormal),
00179     mSkipTarget(eHTMLTag_unknown),
00180     mLineNumber(1),
00181     mOpenMapCount(0),
00182     mFlags(NS_DTD_FLAG_NONE)
00183 {
00184   mBodyContext=new nsDTDContext();
00185 }
00186 
00193 const nsIID& CNavDTD::GetMostDerivedIID(void)const {
00194   return kClassIID;
00195 }
00196 
00197 
00198 #ifdef NS_DEBUG
00199 
00200 nsLoggingSink* GetLoggingSink() {
00201 
00202   //these are used when you want to generate a log file for contentsink construction...
00203 
00204   static  PRBool checkForPath=PR_TRUE;
00205   static  nsLoggingSink *theSink=0;
00206   static  const char* gLogPath=0; 
00207 
00208   if(checkForPath) {
00209     
00210     // we're only going to check the environment once per session.
00211 
00212     gLogPath = /* "c:/temp/parse.log"; */ PR_GetEnv("PARSE_LOGFILE"); 
00213     checkForPath=PR_FALSE;
00214   }
00215   
00216 
00217   if(gLogPath && (!theSink)) {
00218     static  nsLoggingSink gLoggingSink;
00219 
00220     PRIntn theFlags = 0;
00221 
00222      // create the file exists, only open for read/write
00223      // otherwise, create it
00224     if(PR_Access(gLogPath,PR_ACCESS_EXISTS) != PR_SUCCESS)
00225       theFlags = PR_CREATE_FILE;
00226     theFlags |= PR_RDWR;
00227 
00228      // open the record file
00229     PRFileDesc *theLogFile = PR_Open(gLogPath,theFlags,0);
00230     gLoggingSink.SetOutputStream(theLogFile,PR_TRUE);
00231     theSink=&gLoggingSink;
00232   }
00233 
00234   return theSink;
00235 }
00236  
00237 #endif
00238 
00246 CNavDTD::~CNavDTD(){
00247   if(mBodyContext) {
00248     delete mBodyContext;
00249     mBodyContext=0;
00250   }
00251 
00252   if(mTempContext) {
00253     delete mTempContext;
00254     mTempContext=0;
00255   }
00256 
00257   
00258 #ifdef NS_DEBUG
00259   if(mSink) {
00260     nsLoggingSink *theLogSink=GetLoggingSink();
00261     if(mSink==theLogSink) {
00262       theLogSink->ReleaseProxySink();
00263     }
00264   }
00265 #endif
00266 
00267   NS_IF_RELEASE(mSink);
00268 }
00269  
00270 
00278 nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult)
00279 {
00280   nsresult result = NS_NewNavHTMLDTD(aInstancePtrResult);
00281   NS_ENSURE_SUCCESS(result, result);
00282 
00283   CNavDTD* dtd = NS_STATIC_CAST(CNavDTD*, *aInstancePtrResult);
00284     
00285   dtd->mDTDMode = mDTDMode;
00286   dtd->mParserCommand = mParserCommand;
00287   dtd->mDocType = mDocType;
00288 
00289   return result;
00290 }
00291 
00303 NS_IMETHODIMP_(eAutoDetectResult)
00304 CNavDTD::CanParse(CParserContext& aParserContext)
00305 {
00306   NS_ASSERTION(!aParserContext.mMimeType.IsEmpty(),
00307                "How'd we get here with an unknown type?");
00308   
00309   if (aParserContext.mParserCommand != eViewSource &&
00310       aParserContext.mDocType != eXML) {
00311     // This means that we're
00312     // 1) Looking at a type the parser claimed to know how to handle (so XML
00313     //    or HTML or a plaintext type)
00314     // 2) Not looking at XML
00315     //
00316     // Therefore, we want to handle this data with this DTD
00317     return ePrimaryDetect;
00318   }
00319 
00320   return eUnknownDetect;
00321 }
00322 
00332 nsresult CNavDTD::WillBuildModel(const CParserContext& aParserContext,
00333                                  nsITokenizer* aTokenizer,
00334                                  nsIContentSink* aSink) {
00335   nsresult result=NS_OK;
00336 
00337   mFilename=aParserContext.mScanner->GetFilename();
00338   mFlags = NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE; // residual style is always on. This will also reset the flags
00339   mLineNumber = 1;
00340   mDTDMode = aParserContext.mDTDMode;
00341   mParserCommand = aParserContext.mParserCommand;
00342   mMimeType = aParserContext.mMimeType;
00343   mDocType = aParserContext.mDocType;
00344   mSkipTarget = eHTMLTag_unknown;
00345   mTokenizer = aTokenizer;
00346   mBodyContext->SetNodeAllocator(&mNodeAllocator);
00347 
00348   if(!aParserContext.mPrevContext && aSink) {
00349 
00350     STOP_TIMER();
00351     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this));
00352     
00353     result = aSink->WillBuildModel();
00354     
00355     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this));
00356     START_TIMER();
00357 
00358     if (NS_SUCCEEDED(result) && !mSink) {
00359       result = CallQueryInterface(aSink, &mSink);
00360       if (NS_FAILED(result)) {
00361         mFlags |= NS_DTD_FLAG_STOP_PARSING;
00362         return result;
00363       }
00364     }
00365     
00366     //let's see if the environment is set up for us to write output to
00367     //a logging sink. If so, then we'll create one, and make it the
00368     //proxy for the real sink we're given from the parser.
00369 #ifdef NS_DEBUG
00370     nsLoggingSink *theLogSink=GetLoggingSink();
00371     if(theLogSink) {   
00372       theLogSink->SetProxySink(mSink);
00373       mSink=theLogSink;
00374     }
00375 #endif    
00376 
00377    if(mSink) {
00378       PRBool enabled = PR_TRUE;
00379       mSink->IsEnabled(eHTMLTag_frameset, &enabled);
00380       if(enabled) {
00381         mFlags |= NS_IPARSER_FLAG_FRAMES_ENABLED;
00382       }
00383       
00384       mSink->IsEnabled(eHTMLTag_script, &enabled);
00385       if(enabled) {
00386         mFlags |= NS_IPARSER_FLAG_SCRIPT_ENABLED;
00387       }
00388     }
00389   }
00390 
00391   return result;
00392 }
00393 
00394 
00404 nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITokenObserver* anObserver,nsIContentSink* aSink) {
00405   NS_PRECONDITION(mBodyContext!=nsnull,"Create a context before calling build model");
00406 
00407   nsresult result = NS_OK;
00408 
00409   if (aTokenizer && aParser) {
00410     nsITokenizer*  oldTokenizer = mTokenizer;
00411 
00412     mTokenizer      = aTokenizer;
00413     mParser         = (nsParser*)aParser;
00414     mTokenAllocator = mTokenizer->GetTokenAllocator();
00415     
00416     if (mSink) {
00417       if (mBodyContext->GetCount() == 0) {
00418         CStartToken* theToken=nsnull;
00419         if(ePlainText==mDocType) {
00420           //we do this little trick for text files, in both normal and viewsource mode...
00421           theToken=NS_STATIC_CAST(CStartToken*,mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_pre));
00422           if(theToken) {
00423             mTokenizer->PushTokenFront(theToken);
00424           }
00425         }
00426 
00427         // always open a body if frames are disabled....
00428         if(!(mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED)) {
00429           theToken=NS_STATIC_CAST(CStartToken*,mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_body,NS_LITERAL_STRING("body")));
00430           mTokenizer->PushTokenFront(theToken);
00431         }
00432           //if the content model is empty, then begin by opening <html>...
00433         theToken = (CStartToken*)mTokenizer->GetTokenAt(0);
00434         if (theToken) {
00435           eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID();
00436           eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType());
00437           if (theTag != eHTMLTag_html || theType != eToken_start) {
00438             theToken = NS_STATIC_CAST(CStartToken*,mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_html,NS_LITERAL_STRING("html")));             
00439             if (theToken) {
00440               mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack.
00441             }
00442           }
00443         }
00444         else {
00445           theToken = NS_STATIC_CAST(CStartToken*,mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_html,NS_LITERAL_STRING("html")));
00446           if (theToken) {
00447             mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack.
00448           }
00449         }
00450       }
00451     
00452       mSink->WillProcessTokens();
00453 
00454       while (NS_SUCCEEDED(result)) {
00455         if (!(mFlags & NS_DTD_FLAG_STOP_PARSING)) {
00456           CToken* theToken = mTokenizer->PopToken();
00457           if (theToken) { 
00458             result = HandleToken(theToken,aParser);
00459           }
00460           else break;
00461         }
00462         else {
00463           result = NS_ERROR_HTMLPARSER_STOPPARSING;
00464           break;
00465         }
00466 
00467         if ((NS_ERROR_HTMLPARSER_INTERRUPTED == mSink->DidProcessAToken())) {
00468           // The content sink has requested that DTD interrupt processing tokens
00469           // So we need to make sure the parser is in a state where it can be
00470           // interrupted. 
00471           // The mParser->CanInterrupt will return TRUE if BuildModel was called
00472           // from a place in the parser where it prepared to handle a return value of
00473           // NS_ERROR_HTMLPARSER_INTERRUPTED.
00474           // If the parser has mPrevContext then it may be processing
00475           // Script so we should not allow it to be interrupted.
00476           // We also need to make sure that an interruption does not override
00477           // a request to block the parser.
00478           if ((mParser->CanInterrupt()) && 
00479             (nsnull == mParser->PeekContext()->mPrevContext) && 
00480             (eHTMLTag_unknown==mSkipTarget) &&
00481             NS_SUCCEEDED(result)) {
00482             result = NS_ERROR_HTMLPARSER_INTERRUPTED;
00483             break;
00484           }
00485         }
00486       }//while
00487       mTokenizer = oldTokenizer;
00488     }
00489     else {
00490       result = mFlags & NS_DTD_FLAG_STOP_PARSING ? NS_ERROR_HTMLPARSER_STOPPARSING : result;
00491     }
00492   }
00493 
00494   return result;
00495 }
00496 
00503 nsresult
00504 CNavDTD::BuildNeglectedTarget(eHTMLTags aTarget,
00505                               eHTMLTokenTypes aType,
00506                               nsIParser* aParser,
00507                               nsIContentSink* aSink)
00508 { 
00509   NS_ASSERTION(mTokenizer, "tokenizer is null! unable to build target.");
00510   NS_ASSERTION(mTokenAllocator, "unable to create tokens without an allocator.");
00511   if (!mTokenizer || !mTokenAllocator)
00512     return NS_OK;
00513   CHTMLToken* target = 
00514       NS_STATIC_CAST(CHTMLToken*, mTokenAllocator->CreateTokenOfType(aType, aTarget));
00515   mTokenizer->PushTokenFront(target);
00516   return BuildModel(aParser, mTokenizer, 0, aSink);
00517 }
00518 
00525 nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,
00526                                 PRBool aNotifySink,
00527                                 nsIParser* aParser,
00528                                 nsIContentSink* aSink)
00529 {
00530   if (!aSink)
00531     return NS_OK;
00532   nsresult result = NS_OK;
00533   if (aParser && aNotifySink) { 
00534     if (NS_OK == anErrorCode) {
00535       if (eHTMLTag_unknown != mSkipTarget) {
00536         // Looks like there is an open target ( ex. <title> ).
00537         // Create a matching target to handle the unclosed target.
00538         result = BuildNeglectedTarget(mSkipTarget, eToken_end, aParser, aSink);
00539         NS_ENSURE_SUCCESS(result , result);
00540       }
00541       if (!(mFlags & (NS_DTD_FLAG_HAD_FRAMESET | NS_DTD_FLAG_HAD_BODY))) {
00542         // This document is not a frameset document, however, it did not contain
00543         // a body tag either. So, make one!. Note: Body tag is optional per spec..
00544         result = BuildNeglectedTarget(eHTMLTag_body, eToken_start, aParser, aSink);
00545         NS_ENSURE_SUCCESS(result , result);
00546       }
00547       if (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT) {
00548         // Looks like the misplaced contents are not processed yet.
00549         // Here is our last chance to handle the misplaced content.
00550 
00551         // Keep track of the top index.
00552         PRInt32 topIndex = mBodyContext->mContextTopIndex;
00553         
00554         // Loop until we've really consumed all of our misplaced content.
00555         do {
00556           mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT; 
00557 
00558           // mContextTopIndex refers to the misplaced content's legal parent index.
00559           result = HandleSavedTokens(mBodyContext->mContextTopIndex);
00560           NS_ENSURE_SUCCESS(result, result);
00561 
00562           // If we start handling misplaced content while handling misplaced
00563           // content, mContextTopIndex gets modified. However, this new index
00564           // necessarily points to the middle of a closed tag (since we close
00565           // new tags after handling the misplaced content). So we restore the
00566           // insertion point after every iteration.
00567           mBodyContext->mContextTopIndex = topIndex;
00568         } while (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT);
00569 
00570         mBodyContext->mContextTopIndex = -1; 
00571       }          
00572       //now let's disable style handling to save time when closing remaining stack members...
00573       mFlags &= ~NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
00574       while (mBodyContext->GetCount() > 0) { 
00575         result = CloseContainersTo(mBodyContext->Last(), PR_FALSE);
00576         if (NS_FAILED(result)) {
00577           //No matter what, you need to call did build model.
00578           aSink->DidBuildModel();
00579           return result;
00580         }
00581       } 
00582     } 
00583     else {
00584       //If you're here, then an error occured, but we still have nodes on the stack.
00585       //At a minimum, we should grab the nodes and recycle them.
00586       //Just to be correct, we'll also recycle the nodes.
00587       while (mBodyContext->GetCount() > 0) { 
00588         nsEntryStack* theChildStyles = 0;
00589         nsCParserNode* theNode = mBodyContext->Pop(theChildStyles);
00590         IF_DELETE(theChildStyles,&mNodeAllocator);
00591         IF_FREE(theNode, &mNodeAllocator);
00592       } 
00593     }
00594 
00595     //Now make sure the misplaced content list is empty,
00596     //by forcefully recycling any tokens we might find there.
00597     CToken* theToken = 0;
00598     while ((theToken = (CToken*)mMisplacedContent.Pop())) {
00599       IF_FREE(theToken, mTokenAllocator);
00600     }
00601   } //if aparser
00602 
00603   //No matter what, you need to call did build model.
00604   return aSink->DidBuildModel(); 
00605 }
00606 
00607 NS_IMETHODIMP_(void) 
00608 CNavDTD::Terminate() 
00609 { 
00610   mFlags |= NS_DTD_FLAG_STOP_PARSING; 
00611 }
00612 
00613 
00614 NS_IMETHODIMP_(PRInt32) 
00615 CNavDTD::GetType() 
00616 { 
00617   return NS_IPARSER_FLAG_HTML; 
00618 }
00619 
00625 static 
00626 PRBool DoesRequireBody(CToken* aToken,nsITokenizer* aTokenizer) {
00627 
00628   PRBool result=PR_FALSE;
00629 
00630   if(aToken) {
00631     eHTMLTags theTag=(eHTMLTags)aToken->GetTypeID();
00632     if(gHTMLElements[theTag].HasSpecialProperty(kRequiresBody)) {
00633       if(theTag==eHTMLTag_input) {
00634         // IE & Nav4x opens up a body for type=text - Bug 66985
00635         PRInt32 ac=aToken->GetAttributeCount();
00636         for(PRInt32 i=0; i<ac; ++i) {
00637           CAttributeToken* attr=NS_STATIC_CAST(CAttributeToken*,aTokenizer->GetTokenAt(i));
00638           const nsSubstring& name=attr->GetKey();
00639           const nsAString& value=attr->GetValue();
00640 
00641           if((name.EqualsLiteral("type") || 
00642               name.EqualsLiteral("TYPE"))    
00643              && 
00644              !(value.EqualsLiteral("hidden") || 
00645              value.EqualsLiteral("HIDDEN"))) {
00646             result=PR_TRUE; 
00647             break;
00648           }
00649         }//for
00650       }
00651       else {
00652         result=PR_TRUE;
00653       }
00654     }
00655   }
00656  
00657   return result;
00658 }
00659 
00663 static
00664 PRBool HasOpenTagOfType(PRInt32 aType, const nsDTDContext& aContext) {
00665   PRInt32 count = aContext.GetCount();
00666 
00667   while (--count >= 0) {
00668     if (gHTMLElements[aContext.TagAt(count)].IsMemberOf(aType)) {
00669       return PR_TRUE;
00670     }
00671   }
00672 
00673   return PR_FALSE;
00674 }
00675 
00676 static void
00677 InPlaceConvertLineEndings( nsAString& aString )
00678 {
00679     // go from '\r\n' or '\r' to '\n'
00680   nsAString::iterator iter;
00681   aString.BeginWriting(iter);
00682 
00683   PRUnichar* S = iter.get();
00684   size_t N = iter.size_forward();
00685 
00686     // this fragment must be the entire string because
00687     //  (a) no multi-fragment string is writable, so only an illegal cast could give us one, and
00688     //  (b) else we would have to do more work (watching for |to| to fall off the end)
00689   NS_ASSERTION(aString.Length() == N, "You cheated... multi-fragment strings are never writable!");
00690 
00691     // we scan/convert in two phases (but only one pass over the string)
00692     // until we have to skip a character, we only need to touch end-of-line chars
00693     // after that, we'll have to start moving every character we want to keep
00694 
00695     // use array indexing instead of pointers, because compilers optimize that better
00696 
00697 
00698     // this first loop just converts line endings... no characters get moved
00699   size_t i = 0;
00700   PRBool just_saw_cr = PR_FALSE;
00701   for ( ; i < N; ++i )
00702     {
00703         // if it's something we need to convert...
00704       if ( S[i] == '\r' )
00705         {
00706           S[i] = '\n';
00707           just_saw_cr = PR_TRUE;
00708         }
00709       else
00710         {
00711             // else, if it's something we need to skip...
00712             //   i.e., a '\n' immediately following a '\r',
00713             //   then we need to start moving any character we want to keep
00714             //   and we have a second loop for that, so get out of this one
00715           if ( S[i] == '\n' && just_saw_cr )
00716             break;
00717 
00718           just_saw_cr = PR_FALSE;
00719         }
00720     }
00721 
00722 
00723     // this second loop handles the rest of the buffer, moving characters down
00724     //  _and_ converting line-endings as it goes
00725     //  start the loop at |from = i| so that that |just_saw_cr| gets cleared automatically
00726   size_t to = i;
00727   for ( size_t from = i; from < N; ++from )
00728     {
00729         // if it's something we need to convert...
00730       if ( S[from] == '\r' )
00731         {
00732           S[to++] = '\n';
00733           just_saw_cr = PR_TRUE;
00734         }
00735       else
00736         {
00737             // else, if it's something we need to copy...
00738             //  i.e., NOT a '\n' immediately following a '\r'
00739           if ( S[from] != '\n' || !just_saw_cr )
00740             S[to++] = S[from];
00741 
00742           just_saw_cr = PR_FALSE;
00743         }
00744     }
00745 
00746     // if we chopped characters out of the string, we need to shorten it logically
00747   if ( to < N )
00748     aString.SetLength(to);
00749 }
00750 
00761 nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){
00762   nsresult  result=NS_OK;
00763 
00764   if(aToken) {
00765     CHTMLToken*     theToken= NS_STATIC_CAST(CHTMLToken*, aToken);
00766     eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType());
00767     eHTMLTags       theTag=(eHTMLTags)theToken->GetTypeID();
00768     PRBool          execSkipContent=PR_FALSE;
00769 
00770     aToken->SetLineNumber(mLineNumber);
00771     
00772     mLineNumber += aToken->GetNewlineCount();
00773    
00774     /* ---------------------------------------------------------------------------------
00775        To understand this little piece of code, you need to look below too.
00776        In essence, this code caches "skipped content" until we find a given skiptarget.
00777        Once we find the skiptarget, we take all skipped content up to that point and
00778        coallate it. Then we push those tokens back onto the tokenizer deque.
00779        ---------------------------------------------------------------------------------
00780      */
00781 
00782       // printf("token: %p\n",aToken);
00783 
00784    if(mSkipTarget){  //handle a preexisting target...
00785       if((theTag==mSkipTarget) && (eToken_end==theType)){
00786         mSkipTarget=eHTMLTag_unknown; //stop skipping.  
00787         //mTokenizer->PushTokenFront(aToken); //push the end token...
00788         execSkipContent=PR_TRUE;
00789         IF_FREE(aToken, mTokenAllocator);
00790         theToken=(CHTMLToken*)mSkippedContent.PopFront();
00791         theType=eToken_start;
00792       }
00793       else {
00794         mSkippedContent.Push(theToken);
00795         return result;
00796       }
00797     }
00798     else if(mFlags & NS_DTD_FLAG_MISPLACED_CONTENT) {
00799       // Included TD & TH to fix Bug# 20797
00800       static eHTMLTags gLegalElements[]={eHTMLTag_table,eHTMLTag_thead,eHTMLTag_tbody,
00801                                          eHTMLTag_tr,eHTMLTag_td,eHTMLTag_th,eHTMLTag_tfoot};
00802       if(theToken) {
00803         // Don't even try processing misplaced tokens if we're already
00804         // handling misplaced content. See bug 269095
00805         if (mFlags & NS_DTD_FLAG_IN_MISPLACED_CONTENT) {
00806           PushIntoMisplacedStack(theToken);
00807           return result;  
00808         }
00809 
00810         eHTMLTags theParentTag=mBodyContext->Last();
00811         theTag=(eHTMLTags)theToken->GetTypeID();
00812         if(FindTagInSet(theTag, gLegalElements,
00813                         NS_ARRAY_LENGTH(gLegalElements)) ||
00814            (gHTMLElements[theParentTag].CanContain(theTag,mDTDMode) &&
00815             // Here's a problem.  If theTag is legal in here, we don't move it
00816             // out.  So if we're moving stuff out of here, the parent of theTag
00817             // gets closed at this point.  But some things are legal
00818             // _everywhere_ and hence would effectively close out misplaced
00819             // content in tables.  This is undesirable, so treat them as
00820             // illegal here so they'll be shipped out with their parents and
00821             // siblings.  See bug 40855 for an explanation (that bug was for
00822             // comments, but the same issues arise with whitespace, newlines,
00823             // noscript, etc).  Script is special, though.  Shipping it out
00824             // breaks document.write stuff.  See bug 243064.
00825             (!gHTMLElements[theTag].HasSpecialProperty(kLegalOpen) ||
00826              theTag == eHTMLTag_script))) {
00827             
00828           mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT; // reset the state since all the misplaced tokens are about to get handled.
00829 
00830           result = HandleSavedTokens(mBodyContext->mContextTopIndex);
00831           NS_ENSURE_SUCCESS(result, result);
00832 
00833           mBodyContext->mContextTopIndex = -1; 
00834 
00835           if (mSkipTarget) {
00836             mSkippedContent.Push(theToken);
00837             return result;
00838           }
00839           // Fall through if the skipped content collection is |not| in progress - bug 124788
00840         }
00841         else {
00842           PushIntoMisplacedStack(theToken);
00843           return result;
00844         }
00845       }
00846     }
00847   
00848    
00849     /* ---------------------------------------------------------------------------------
00850        This section of code is used to "move" misplaced content from one location in 
00851        our document model to another. (Consider what would happen if we found a <P> tag
00852        and text in the head.) To move content, we throw it onto the misplacedcontent 
00853        deque until we can deal with it.
00854        ---------------------------------------------------------------------------------
00855      */
00856     if(!execSkipContent) {
00857 
00858       switch(theTag) {
00859         case eHTMLTag_html:
00860         case eHTMLTag_noframes:
00861         case eHTMLTag_noscript:
00862         case eHTMLTag_script:
00863         case eHTMLTag_doctypeDecl:
00864         case eHTMLTag_instruction:
00865           break;
00866 
00867         default:
00868           if(!gHTMLElements[eHTMLTag_html].SectionContains(theTag,PR_FALSE)) {
00869             if(!(mFlags & (NS_DTD_FLAG_HAD_BODY |
00870                            NS_DTD_FLAG_HAD_FRAMESET |
00871                            NS_DTD_FLAG_ALTERNATE_CONTENT))) {
00872 
00873               //For bug examples from this code, see bugs: 18928, 20989.
00874               //At this point we know the body/frameset aren't open. 
00875               //If the child belongs in the head, then handle it (which may open the head);
00876               //otherwise, push it onto the misplaced stack.
00877 
00878               PRBool isExclusive=PR_FALSE;
00879               PRBool theChildBelongsInHead=gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag,isExclusive);
00880               if(theChildBelongsInHead && !isExclusive) {
00881                 if (mMisplacedContent.GetSize() == 0) {
00882                   // This tag can either be in the body or the head. Since
00883                   // there is no indication that the body should be open,
00884                   // put this token in the head.
00885                   break;
00886                 }
00887 
00888                 // Otherwise, we have received some indication that the body is
00889                 // "open", so push this token onto the misplaced content stack.
00890                 theChildBelongsInHead = PR_FALSE;
00891               }
00892 
00893               if(!theChildBelongsInHead) {
00894 
00895                 //If you're here then we found a child of the body that was out of place.
00896                 //We're going to move it to the body by storing it temporarily on the misplaced stack.
00897                 //However, in quirks mode, a few tags request, ambiguosly, for a BODY. - Bugs 18928, 24204.-
00898                 PushIntoMisplacedStack(aToken);
00899                 
00900                 if (IsAlternateTag(theTag)) {
00901                   // These tags' contents are consumed as CDATA. If we simply
00902                   // pushed them on the misplaced content stack, the CDATA
00903                   // contents would force us to open a body, which could be
00904                   // wrong. So we collect the whole tag as misplaced in one
00905                   // gulp. Note that the tokenizer guarantees that there will
00906                   // be an end tag.
00907                   CToken *current = aToken;
00908                   while (current->GetTokenType() != eToken_end ||
00909                          current->GetTypeID() != theTag) {
00910                     current = NS_STATIC_CAST(CToken *, mTokenizer->PopToken());
00911                     NS_ASSERTION(current, "The tokenizer is not creating good "
00912                                           "alternate tags");
00913                     PushIntoMisplacedStack(current);
00914                   }
00915 
00916                   // XXX Add code to also collect incorrect attributes on the
00917                   // end tag.
00918                 }
00919 
00920                 if(DoesRequireBody(aToken,mTokenizer)) {
00921                   CToken* theBodyToken=NS_STATIC_CAST(CToken*,mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_body,NS_LITERAL_STRING("body")));
00922                   result=HandleToken(theBodyToken,aParser);
00923                 }
00924                 return result;
00925               }
00926             } //if
00927           } //if
00928       }//switch
00929 
00930     } //if
00931     
00932     if(theToken){
00933       //Before dealing with the token normally, we need to deal with skip targets
00934      CStartToken* theStartToken=NS_STATIC_CAST(CStartToken*,aToken);
00935      if((!execSkipContent)                  && 
00936         (theType!=eToken_end)               &&
00937         (eHTMLTag_unknown==mSkipTarget)     && 
00938         (gHTMLElements[theTag].mSkipTarget) && 
00939         (!theStartToken->IsEmpty())) { // added empty token check for bug 44186
00940         //create a new target
00941         NS_ASSERTION(mSkippedContent.GetSize() == 0, "all the skipped content tokens did not get handled");
00942         mSkippedContent.Empty();
00943         mSkipTarget=gHTMLElements[theTag].mSkipTarget;
00944         mSkippedContent.Push(theToken);
00945       }
00946       else {
00947 
00948         mParser=(nsParser*)aParser;
00949 
00950         switch(theType) {
00951           case eToken_text:
00952           case eToken_start:
00953           case eToken_whitespace: 
00954           case eToken_newline:
00955             result=HandleStartToken(theToken); break;
00956 
00957           case eToken_end:
00958             result=HandleEndToken(theToken); break;
00959           
00960           case eToken_cdatasection:
00961           case eToken_comment:
00962           case eToken_markupDecl:
00963             result=HandleCommentToken(theToken); break;
00964 
00965           case eToken_entity:
00966             result=HandleEntityToken(theToken); break;
00967 
00968           case eToken_attribute:
00969             result=HandleAttributeToken(theToken); break;
00970 
00971           case eToken_instruction:
00972             result=HandleProcessingInstructionToken(theToken); break;
00973 
00974           case eToken_doctypeDecl:
00975             result=HandleDocTypeDeclToken(theToken); break;
00976 
00977           default:
00978             break;
00979         }//switch
00980 
00981 
00982         if(NS_SUCCEEDED(result) || (NS_ERROR_HTMLPARSER_BLOCK==result)) {
00983            IF_FREE(theToken, mTokenAllocator);
00984         }
00985         else if(result==NS_ERROR_HTMLPARSER_STOPPARSING) {
00986           mFlags |= NS_DTD_FLAG_STOP_PARSING;
00987         }
00988         else {
00989           return NS_OK;
00990         }
00991       }
00992     }
00993 
00994   }//if
00995   return result;
00996 }
00997  
01005 nsresult CNavDTD::DidHandleStartTag(nsIParserNode& aNode,eHTMLTags aChildTag){
01006   nsresult result=NS_OK;
01007 
01008   switch(aChildTag){
01009 
01010     case eHTMLTag_pre:
01011     case eHTMLTag_listing:
01012       {
01013         CToken* theNextToken=mTokenizer->PeekToken();
01014         if(theNextToken)  {
01015           eHTMLTokenTypes theType=eHTMLTokenTypes(theNextToken->GetTokenType());
01016           if(eToken_newline==theType){
01017             mLineNumber += theNextToken->GetNewlineCount();
01018             theNextToken=mTokenizer->PopToken();  //skip 1st newline inside PRE and LISTING
01019             IF_FREE(theNextToken, mTokenAllocator); // fix for Bug 29379
01020           }//if
01021         }//if
01022       }
01023       break;
01024     default:
01025       break;
01026   }//switch 
01027 
01028   //handle <empty/> tags by generating a close tag...
01029   //added this to fix bug 48351, which contains XHTML and uses empty tags.
01030   nsCParserNode* theNode=NS_STATIC_CAST(nsCParserNode*,&aNode);
01031   if(nsHTMLElement::IsContainer(aChildTag) && theNode && theNode->mToken) {  //nullptr test fixes bug 56085
01032     CStartToken *theToken=NS_STATIC_CAST(CStartToken*,theNode->mToken);
01033     if(theToken->IsEmpty()){
01034 
01035       CToken *theEndToken=mTokenAllocator->CreateTokenOfType(eToken_end,aChildTag); 
01036       if(theEndToken) {
01037         result=HandleEndToken(theEndToken);
01038         IF_FREE(theEndToken, mTokenAllocator);
01039       }
01040     }
01041   }
01042 
01043   return result;
01044 } 
01045  
01054 PRInt32 CNavDTD::LastOf(eHTMLTags aTagSet[],PRInt32 aCount) const {
01055   int theIndex=0;
01056   for(theIndex=mBodyContext->GetCount()-1;theIndex>=0;theIndex--){
01057     if(FindTagInSet((*mBodyContext)[theIndex],aTagSet,aCount)) { 
01058       return theIndex;
01059     } 
01060   } 
01061   return kNotFound;
01062 }
01063 
01074 static
01075 PRBool CanBeContained(eHTMLTags aChildTag,nsDTDContext& aContext) {
01076 
01077   /* #    Interesting test cases:       Result:
01078    * 1.   <UL><LI>..<B>..<LI>           inner <LI> closes outer <LI>
01079    * 2.   <CENTER><DL><DT><A><CENTER>   allow nested <CENTER>
01080    * 3.   <TABLE><TR><TD><TABLE>...     allow nested <TABLE>
01081    * 4.   <FRAMESET> ... <FRAMESET>
01082    */
01083 
01084   //Note: This method is going away. First we need to get the elementtable to do closures right, and
01085   //      therefore we must get residual style handling to work.
01086 
01087   //the changes to this method were added to fix bug 54651...
01088 
01089   PRBool  result=PR_TRUE;
01090   PRInt32 theCount=aContext.GetCount();
01091 
01092   if(0<theCount){
01093     const TagList* theRootTags=gHTMLElements[aChildTag].GetRootTags();
01094     const TagList* theSpecialParents=gHTMLElements[aChildTag].GetSpecialParents();
01095     if(theRootTags) {
01096       PRInt32 theRootIndex=LastOf(aContext,*theRootTags);
01097       PRInt32 theSPIndex=(theSpecialParents) ? LastOf(aContext,*theSpecialParents) : kNotFound;  
01098       PRInt32 theChildIndex=nsHTMLElement::GetIndexOfChildOrSynonym(aContext,aChildTag);
01099       PRInt32 theTargetIndex=(theRootIndex>theSPIndex) ? theRootIndex : theSPIndex;
01100 
01101       if((theTargetIndex==theCount-1) ||
01102         ((theTargetIndex==theChildIndex) && gHTMLElements[aChildTag].CanContainSelf())) {
01103         result=PR_TRUE;
01104       }
01105       else {
01106         
01107         result=PR_FALSE;
01108 
01109         static eHTMLTags gTableElements[]={eHTMLTag_td,eHTMLTag_th};
01110 
01111         PRInt32 theIndex=theCount-1;
01112         while(theChildIndex<theIndex) {
01113           eHTMLTags theParentTag=aContext.TagAt(theIndex--);
01114           if (gHTMLElements[theParentTag].IsMemberOf(kBlockEntity)  || 
01115               gHTMLElements[theParentTag].IsMemberOf(kHeading)      || 
01116               gHTMLElements[theParentTag].IsMemberOf(kPreformatted) || 
01117               gHTMLElements[theParentTag].IsMemberOf(kFormControl)  ||  //fixes bug 44479
01118               gHTMLElements[theParentTag].IsMemberOf(kList)) {
01119             if(!HasOptionalEndTag(theParentTag)) {
01120               result=PR_TRUE;
01121               break;
01122             }
01123           }
01124           else if(FindTagInSet(theParentTag,gTableElements,sizeof(gTableElements)/sizeof(eHTMLTag_unknown))){
01125             result=PR_TRUE;  //added this to catch a case we missed; bug 57173.
01126             break;
01127           }
01128         }
01129       }
01130     }
01131   }
01132 
01133   return result;
01134 
01135 }
01136 
01137 enum eProcessRule {eNormalOp,eLetInlineContainBlock};
01138 
01153 nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsCParserNode *aNode) {
01154   NS_PRECONDITION(0!=aToken,kNullToken);
01155 
01156   nsresult  result=NS_OK;
01157   PRBool  theChildIsContainer=nsHTMLElement::IsContainer(aChildTag);
01158 
01159   // client of parser is spefically trying to parse a fragment that 
01160   // may lack required context.  Suspend containment rules if so.
01161   if (mParserCommand != eViewFragment)
01162   {
01163     PRBool  theChildAgrees=PR_TRUE;
01164     PRInt32 theIndex=mBodyContext->GetCount();
01165     PRBool  theParentContains=-1;
01166     
01167     do {
01168    
01169       eHTMLTags theParentTag=mBodyContext->TagAt(--theIndex);
01170       theParentContains=CanContain(theParentTag,aChildTag);  //precompute containment, and pass it to CanOmit()...
01171 
01172       if(CanOmit(theParentTag,aChildTag,theParentContains)) {
01173         result=HandleOmittedTag(aToken,aChildTag,theParentTag,aNode);
01174         return result;
01175       }
01176 
01177       eProcessRule theRule=eNormalOp; 
01178 
01179       if (!theParentContains &&
01180           (IsBlockElement(aChildTag,theParentTag) &&
01181            IsInlineElement(theParentTag,theParentTag))) { //broaden this to fix <inline><block></block></inline>
01182         if (eHTMLTag_li != aChildTag) {  //remove test for table to fix 57554
01183           nsCParserNode* theParentNode = NS_STATIC_CAST(nsCParserNode*, mBodyContext->PeekNode());
01184           if (theParentNode && theParentNode->mToken->IsWellFormed()) {
01185             theRule = eLetInlineContainBlock;
01186           }
01187         }
01188       }
01189 
01190       switch(theRule){
01191 
01192         case eNormalOp:        
01193 
01194           theChildAgrees=PR_TRUE;
01195           if(theParentContains) {
01196 
01197             eHTMLTags theAncestor=gHTMLElements[aChildTag].mRequiredAncestor;
01198             if(eHTMLTag_unknown!=theAncestor){
01199               theChildAgrees=HasOpenContainer(theAncestor);
01200             }
01201             
01202             if(theChildAgrees && theChildIsContainer) {
01203               if(theParentTag!=aChildTag) {             
01204                 // Double check the power structure a
01205                 // Note: The bit is currently set on <A> and <LI>.
01206                 if(gHTMLElements[aChildTag].ShouldVerifyHierarchy()){
01207                   PRInt32 theChildIndex=nsHTMLElement::GetIndexOfChildOrSynonym(*mBodyContext,aChildTag);
01208               
01209                   if((kNotFound<theChildIndex) && (theChildIndex<theIndex)) {
01210                    
01211                   /*-------------------------------------------------------------------------------------
01212                      1  Here's a tricky case from bug 22596:  <h5><li><h5>
01213                         How do we know that the 2nd <h5> should close the <LI> rather than nest inside the <LI>?
01214                         (Afterall, the <h5> is a legal child of the <LI>).
01215               
01216                         The way you know is that there is no root between the two, so the <h5> binds more
01217                         tightly to the 1st <h5> than to the <LI>.
01218                      2.  Also, bug 6148 shows this case: <SPAN><DIV><SPAN>
01219                         From this case we learned not to execute this logic if the parent is a block.
01220                     
01221                      3. Fix for 26583
01222                         Ex. <A href=foo.html><B>foo<A href-bar.html>bar</A></B></A>  <-- A legal HTML
01223                         In the above example clicking on "foo" or "bar" should link to
01224                         foo.html or bar.html respectively. That is, the inner <A> should be informed
01225                         about the presence of an open <A> above <B>..so that the inner <A> can close out
01226                         the outer <A>. The following code does it for us.
01227                      
01228                      4. Fix for 27865 [ similer to 22596 ]. Ex: <DL><DD><LI>one<DD><LI>two
01229                    -------------------------------------------------------------------------------------*/
01230                      
01231                     theChildAgrees=CanBeContained(aChildTag,*mBodyContext);
01232                   } //if
01233                 }//if
01234               } //if
01235             } //if
01236           } //if parentcontains
01237 
01238           if(!(theParentContains && theChildAgrees)) {
01239             if (!CanPropagate(theParentTag,aChildTag,theParentContains)) { 
01240               if(theChildIsContainer || (!theParentContains)){ 
01241                 if(!theChildAgrees && 
01242                    !gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext,theIndex,aChildTag)) {
01243                   // Closing the tags above might cause non-compatible results.
01244                   // Ex. <TABLE><TR><TD><TBODY>Text</TD></TR></TABLE>. 
01245                   // In the example above <TBODY> is badly misplaced, but 
01246                   // we should not attempt to close the tags above it, 
01247                   // The safest thing to do is to discard this tag.
01248                   return result;
01249                 }
01250                 else if (mBodyContext->mContextTopIndex > 0 && theIndex <= mBodyContext->mContextTopIndex) {
01251                   // Looks like the parent tag does not want to contain the current tag ( aChildTag ). 
01252                   // However, we have to force the containment, when handling misplaced content, to avoid data loss.
01253                   // Ref. bug 138577.
01254                   theParentContains = PR_TRUE;
01255                 }
01256                 else {
01257                   CloseContainersTo(theIndex,aChildTag,PR_TRUE);
01258                 }
01259               }//if
01260               else break;
01261             }//if
01262             else {
01263               CreateContextStackFor(aChildTag);
01264               theIndex=mBodyContext->GetCount();
01265             }
01266           }//if
01267           break;
01268 
01269         case eLetInlineContainBlock:
01270           theParentContains=theChildAgrees=PR_TRUE; //cause us to fall out of loop and open the block.
01271           break;
01272 
01273         default:
01274           break;
01275 
01276       }//switch
01277     } while(!(theParentContains && theChildAgrees));
01278   }
01279   
01280   if(theChildIsContainer){
01281     result=OpenContainer(aNode,aChildTag,PR_TRUE);
01282   }
01283   else {  //we're writing a leaf...
01284     result=AddLeaf(aNode);
01285   }
01286 
01287   return result;
01288 }
01289  
01298 nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsIParserNode& aNode) 
01299 { 
01300   nsresult result = NS_OK;
01301 
01302   //this little gem creates a special attribute for the editor team to use.
01303   //The attribute only get's applied to unknown tags, and is used by ender
01304   //(during editing) to display a special icon for unknown tags.
01305   if(eHTMLTag_userdefined == aTag) {
01306     CAttributeToken* theToken= NS_STATIC_CAST(CAttributeToken*,mTokenAllocator->CreateTokenOfType(eToken_attribute,aTag));
01307     if(theToken) {
01308       theToken->SetKey(NS_LITERAL_STRING("_moz-userdefined"));
01309       aNode.AddAttribute(theToken);    
01310     }
01311   }
01312 
01313   PRInt32 stackDepth = mBodyContext->GetCount();
01314   if (stackDepth >= FONTSTYLE_IGNORE_DEPTH &&
01315       gHTMLElements[aTag].IsMemberOf(kFontStyle)) {
01316     // Prevent bug 58917 by tossing the new kFontStyle start tag
01317     return kHierarchyTooDeep;
01318   }
01319 
01320   if (stackDepth >= PHRASE_IGNORE_DEPTH &&
01321       gHTMLElements[aTag].IsMemberOf(kPhrase)) {
01322     // Prevent bug 58917 by tossing the new kPhrase start tag
01323     return kHierarchyTooDeep;
01324   }
01325 
01326     /**************************************************************************************
01327      *
01328      * Now a little code to deal with bug #49687 (crash when layout stack gets too deep)
01329      * I've also opened this up to any container (not just inlines): re bug 55095
01330      * Improved to handle bug 55980 (infinite loop caused when DEPTH is exceeded and
01331      * </P> is encountered by itself (<P>) is continuously produced.
01332      *
01333      **************************************************************************************/
01334   
01335   if (stackDepth > MAX_REFLOW_DEPTH) {
01336     if (nsHTMLElement::IsContainer(aTag) &&
01337         !gHTMLElements[aTag].HasSpecialProperty(kHandleStrayTag)) {
01338       // Ref. bug 98261,49678,55095,55980
01339       // Instead of throwing away the current tag close it's parent
01340       // such that the stack level does not go beyond the max_reflow_depth.
01341       // This would allow leaf tags, that follow the current tag, to find
01342       // the correct node. 
01343       while (stackDepth != MAX_REFLOW_DEPTH && NS_SUCCEEDED(result)) {
01344         result = CloseContainersTo(mBodyContext->Last(),PR_FALSE);
01345         --stackDepth;
01346       }
01347     }        
01348   }
01349 
01350   STOP_TIMER()
01351   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this));
01352 
01353   if (aTag <= NS_HTML_TAG_MAX) {
01354     result = mSink->NotifyTagObservers(&aNode);
01355   }
01356 
01357   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this));
01358   START_TIMER()
01359 
01360   if(NS_SUCCEEDED(result)) {
01361     // This code is here to make sure the head is closed before we deal 
01362     // with any tags that don't belong in the head. If the tag is not exclusive
01363     // then we do not have enough information, and we have to trust the logic
01364     // in HandleToken() to not hand us non-exclusive tokens  
01365     PRBool isExclusive = PR_FALSE;
01366     PRBool isChildOfHead = 
01367       gHTMLElements[eHTMLTag_head].IsChildOfHead(aTag, isExclusive);
01368 
01369     if (NS_SUCCEEDED(result) && ((mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) &&
01370                                   isExclusive &&
01371                                   !isChildOfHead)) {
01372       result = CloseHead();
01373     }
01374   }
01375 
01376   return result;
01377 }
01378 
01379 static void PushMisplacedAttributes(nsIParserNode& aNode,nsDeque& aDeque,PRInt32& aCount) {
01380   if(aCount > 0) {
01381     CToken* theAttrToken=nsnull;
01382     nsCParserNode* theAttrNode = (nsCParserNode*)&aNode;
01383     if(theAttrNode) {
01384       while(aCount){ 
01385         theAttrToken=theAttrNode->PopAttributeTokenFront();
01386         if(theAttrToken) {
01387           theAttrToken->SetNewlineCount(0);
01388           aDeque.Push(theAttrToken);
01389         }
01390         aCount--;
01391       }//while
01392     }//if
01393   }//if
01394 }
01395 
01407 nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags aParent,nsIParserNode* aNode) {
01408   NS_PRECONDITION(mBodyContext != nsnull,"need a context to work with");
01409 
01410   nsresult  result=NS_OK;
01411 
01412   //The trick here is to see if the parent can contain the child, but prefers not to.
01413   //Only if the parent CANNOT contain the child should we look to see if it's potentially a child
01414   //of another section. If it is, the cache it for later.
01415   //  1. Get the root node for the child. See if the ultimate node is the BODY, FRAMESET, HEAD or HTML
01416   PRInt32   theTagCount = mBodyContext->GetCount();
01417 
01418   if(aToken) {
01419     PRInt32   attrCount = aToken->GetAttributeCount();
01420     if((gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch)) &&
01421        (!nsHTMLElement::IsWhitespaceTag(aChildTag))) {
01422       eHTMLTags theTag=eHTMLTag_unknown;
01423     
01424       // Determine the insertion point
01425       while(theTagCount > 0) {
01426         theTag = mBodyContext->TagAt(--theTagCount);
01427         if(!gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) {
01428           mBodyContext->mContextTopIndex = theTagCount; // This is our insertion point
01429           break;
01430         }
01431       }
01432 
01433       if(mBodyContext->mContextTopIndex>-1) {
01434                   
01435         PushIntoMisplacedStack(aToken);  
01436 
01437         IF_HOLD(aToken);  // Hold on to this token for later use.
01438 
01439         // If the token is attributed then save those attributes too.    
01440         if(attrCount > 0) PushMisplacedAttributes(*aNode,mMisplacedContent,attrCount);
01441 
01442         if(gHTMLElements[aChildTag].mSkipTarget) {
01443           nsAutoString theString;
01444           PRInt32 lineNo = 0;
01445           
01446           result = CollectSkippedContent(aChildTag, theString, lineNo);
01447           NS_ENSURE_SUCCESS(result, result);
01448 
01449           PushIntoMisplacedStack(mTokenAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text,theString));
01450           PushIntoMisplacedStack(mTokenAllocator->CreateTokenOfType(eToken_end,aChildTag));      
01451         }
01452               
01453         mFlags |= NS_DTD_FLAG_MISPLACED_CONTENT; // This state would help us in gathering all the misplaced elements
01454       }//if
01455     }//if
01456 
01457     if((aChildTag!=aParent) && (gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced))) {
01458       
01459       IF_HOLD(aToken);  // Hold on to this token for later use. Ref Bug. 53695
01460       
01461       PushIntoMisplacedStack(aToken);
01462       // If the token is attributed then save those attributes too.
01463        if(attrCount > 0) PushMisplacedAttributes(*aNode,mMisplacedContent,attrCount);
01464     }
01465   }
01466   return result;
01467 }
01468 
01476 nsresult CNavDTD::HandleKeyGen(nsIParserNode* aNode) { 
01477   nsresult result=NS_OK; 
01478 
01479   if(aNode) { 
01480   
01481     nsCOMPtr<nsIFormProcessor> theFormProcessor = 
01482              do_GetService(kFormProcessorCID, &result);
01483   
01484     if(NS_SUCCEEDED(result)) { 
01485       PRInt32      theAttrCount=aNode->GetAttributeCount(); 
01486       nsVoidArray  theContent; 
01487       nsAutoString theAttribute; 
01488       nsAutoString theFormType; 
01489       CToken*      theToken=nsnull; 
01490 
01491       theFormType.AssignLiteral("select"); 
01492   
01493       result=theFormProcessor->ProvideContent(theFormType,theContent,theAttribute); 
01494 
01495       if(NS_SUCCEEDED(result)) {
01496         nsString* theTextValue=nsnull; 
01497         PRInt32   theIndex=nsnull; 
01498   
01499         if(mTokenizer && mTokenAllocator) {
01500           // Populate the tokenizer with the fabricated elements in the reverse order 
01501           // such that <SELECT> is on the top fo the tokenizer followed by <OPTION>s 
01502           // and </SELECT> 
01503           theToken=mTokenAllocator->CreateTokenOfType(eToken_end,eHTMLTag_select); 
01504           mTokenizer->PushTokenFront(theToken); 
01505   
01506           for(theIndex=theContent.Count()-1;theIndex>-1;theIndex--) { 
01507             theTextValue=(nsString*)theContent[theIndex]; 
01508             theToken=mTokenAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text,*theTextValue); 
01509             mTokenizer->PushTokenFront(theToken); 
01510             theToken=mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_option); 
01511             mTokenizer->PushTokenFront(theToken); 
01512           } 
01513   
01514           // The attribute ( provided by the form processor ) should be a part of the SELECT.
01515           // Placing the attribute token on the tokenizer to get picked up by the SELECT.
01516           theToken=mTokenAllocator->CreateTokenOfType(eToken_attribute,eHTMLTag_unknown,theAttribute);
01517 
01518           ((CAttributeToken*)theToken)->SetKey(NS_LITERAL_STRING("_moz-type")); 
01519           mTokenizer->PushTokenFront(theToken); 
01520   
01521           // Pop out NAME and CHALLENGE attributes ( from the keygen NODE ) 
01522           // and place it in the tokenizer such that the attribtues get 
01523           // sucked into SELECT node. 
01524           for(theIndex=theAttrCount;theIndex>0;theIndex--) { 
01525             mTokenizer->PushTokenFront(((nsCParserNode*)aNode)->PopAttributeToken()); 
01526           } 
01527   
01528           theToken=mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_select); 
01529           // Increament the count because of the additional attribute from the form processor.
01530           theToken->SetAttributeCount(theAttrCount+1); 
01531           mTokenizer->PushTokenFront(theToken); 
01532         }//if(mTokenizer && mTokenAllocator)
01533       }//if(NS_SUCCEEDED(result))
01534     }// if(NS_SUCCEEDED(result)) 
01535   } //if(aNode) 
01536   return result; 
01537 } 
01538 
01539 PRBool CNavDTD::IsAlternateTag(eHTMLTags aTag) {
01540   switch (aTag) {
01541     case eHTMLTag_noembed:
01542       return PR_TRUE;
01543     case eHTMLTag_noscript:
01544       return (mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED) != 0;
01545     case eHTMLTag_iframe:
01546     case eHTMLTag_noframes:
01547       return (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED) != 0;
01548     default:
01549       return PR_FALSE;
01550   }
01551 }
01552 
01567 nsresult CNavDTD::HandleStartToken(CToken* aToken) {
01568   NS_PRECONDITION(0!=aToken,kNullToken);
01569 
01570   //Begin by gathering up attributes...
01571 
01572   nsCParserNode* theNode=mNodeAllocator.CreateNode(aToken, mTokenAllocator);
01573   
01574   eHTMLTags     theChildTag=(eHTMLTags)aToken->GetTypeID();
01575   PRInt16       attrCount=aToken->GetAttributeCount();
01576   eHTMLTags     theParent=mBodyContext->Last();
01577   nsresult      result=(0==attrCount) ? NS_OK : CollectAttributes(theNode,theChildTag,attrCount);
01578 
01579   if(NS_OK==result) {
01580     result=WillHandleStartTag(aToken,theChildTag,*theNode);
01581     if(NS_OK==result) {
01582       PRBool isTokenHandled =PR_FALSE;
01583       PRBool theHeadIsParent=PR_FALSE;
01584 
01585       if(nsHTMLElement::IsSectionTag(theChildTag)){
01586         switch(theChildTag){
01587           case eHTMLTag_html:
01588             if(mBodyContext->GetCount()>0) {
01589               result=OpenContainer(theNode,theChildTag,PR_FALSE);
01590               isTokenHandled=PR_TRUE;
01591             }
01592             break;
01593           case eHTMLTag_body:
01594             if(mFlags & NS_DTD_FLAG_HAS_OPEN_BODY) {
01595               result=OpenContainer(theNode,theChildTag,PR_FALSE);
01596               isTokenHandled=PR_TRUE;
01597             }
01598             break;
01599           case eHTMLTag_head:
01600             if(mFlags & (NS_DTD_FLAG_HAD_BODY | NS_DTD_FLAG_HAD_FRAMESET)) {
01601               result=HandleOmittedTag(aToken,theChildTag,theParent,theNode);
01602               isTokenHandled=PR_TRUE;
01603             }
01604             break;
01605           default:
01606             break;
01607         }
01608       }
01609 
01610       PRBool isExclusive=PR_FALSE;
01611       theHeadIsParent=nsHTMLElement::IsChildOfHead(theChildTag,isExclusive);
01612       
01613       switch(theChildTag) { 
01614         case eHTMLTag_area:
01615           if(!mOpenMapCount) isTokenHandled=PR_TRUE;
01616 
01617           STOP_TIMER();
01618           MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleStartToken(), this=%p\n", this));
01619           
01620           if (mOpenMapCount>0 && mSink) {
01621             result=mSink->AddLeaf(*theNode);
01622             isTokenHandled=PR_TRUE;
01623           }
01624           
01625           MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleStartToken(), this=%p\n", this));
01626           START_TIMER();
01627           break;
01628 
01629         case eHTMLTag_image:
01630           aToken->SetTypeID(theChildTag=eHTMLTag_img);
01631           break;
01632 
01633         case eHTMLTag_keygen:
01634           result=HandleKeyGen(theNode);
01635           isTokenHandled=PR_TRUE;
01636           break;
01637 
01638         case eHTMLTag_script:
01639           // Script isn't really exclusively in the head. However, we treat it
01640           // as such to make sure that we don't pull scripts outside the head
01641           // into the body.
01642           isExclusive = !(mFlags & NS_DTD_FLAG_HAD_BODY);
01643           mFlags |= NS_DTD_FLAG_HAS_OPEN_SCRIPT;
01644 
01645         default:
01646             break;
01647       }//switch
01648 
01649       if(!isTokenHandled) {
01650         PRBool prefersBody =
01651           gHTMLElements[theChildTag].HasSpecialProperty(kPreferBody);
01652 
01653         // If this tag prefers to be in the head (when neither the head nor the
01654         // body have been explicitly opened) then check that we haven't seen the
01655         // body (true until the <body> tag has really been seen). Otherwise,
01656         // check if the head has been explicitly opened. See bug 307122.
01657         theHeadIsParent = theHeadIsParent &&
01658           (isExclusive ||
01659            (prefersBody
01660             ? (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)
01661             : !(mFlags & (NS_DTD_FLAG_HAD_BODY | NS_DTD_FLAG_HAD_FRAMESET))));
01662 
01663         if(theHeadIsParent) {
01664           // These tokens prefer to be in the head.
01665           result = AddHeadLeaf(theNode);
01666         }
01667         else {
01668           result = HandleDefaultStartToken(aToken,theChildTag,theNode); 
01669         }
01670       }
01671 
01672       //now do any post processing necessary on the tag...
01673       if(NS_OK==result)
01674         DidHandleStartTag(*theNode,theChildTag);
01675     }//if
01676   } //if
01677 
01678   if(kHierarchyTooDeep==result) {
01679     //reset this error to ok; all that happens here is that given inline tag
01680     //gets dropped because the stack is too deep. Don't terminate parsing.
01681     result=NS_OK;
01682   }
01683 
01684   IF_FREE(theNode, &mNodeAllocator);
01685   return result;
01686 }
01687 
01697 static
01698 PRBool HasCloseablePeerAboveRoot(const TagList& aRootTagList,nsDTDContext& aContext,eHTMLTags aTag,PRBool anEndTag) {
01699   PRInt32   theRootIndex=LastOf(aContext,aRootTagList);  
01700   const TagList*  theCloseTags=(anEndTag) ? gHTMLElements[aTag].GetAutoCloseEndTags() : gHTMLElements[aTag].GetAutoCloseStartTags();
01701   PRInt32 theChildIndex=-1;
01702 
01703   if(theCloseTags) {
01704     theChildIndex=LastOf(aContext,*theCloseTags);
01705   }
01706   else {
01707     if((anEndTag) || (!gHTMLElements[aTag].CanContainSelf()))
01708       theChildIndex=aContext.LastOf(aTag);
01709   }
01710     // I changed this to theRootIndex<=theChildIndex so to handle this case:
01711     //  <SELECT><OPTGROUP>...</OPTGROUP>
01712     //
01713   return PRBool(theRootIndex<=theChildIndex);  
01714 }
01715 
01716 
01726 static
01727 eHTMLTags FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag,nsDTDContext& aContext,nsDTDMode aMode) {
01728   int theTopIndex=aContext.GetCount();
01729   eHTMLTags thePrevTag=aContext.Last();
01730  
01731   if(nsHTMLElement::IsContainer(aCurrentTag)){
01732     PRInt32 theChildIndex=nsHTMLElement::GetIndexOfChildOrSynonym(aContext,aCurrentTag);
01733     
01734     if(kNotFound<theChildIndex) {
01735       if(thePrevTag==aContext[theChildIndex]){
01736         return aContext[theChildIndex];
01737       } 
01738     
01739       if(nsHTMLElement::IsBlockCloser(aCurrentTag)) {
01740 
01741           /*here's what to do: 
01742               Our here is sitting at aChildIndex. There are other tags above it
01743               on the stack. We have to try to close them out, but we may encounter
01744               one that can block us. The way to tell is by comparing each tag on
01745               the stack against our closeTag and rootTag list. 
01746 
01747               For each tag above our hero on the stack, ask 3 questions:
01748                 1. Is it in the closeTag list? If so, the we can skip over it
01749                 2. Is it in the rootTag list? If so, then we're gated by it
01750                 3. Otherwise its non-specified and we simply presume we can close it.
01751           */
01752  
01753         const TagList* theCloseTags=gHTMLElements[aCurrentTag].GetAutoCloseEndTags();
01754         const TagList* theRootTags=gHTMLElements[aCurrentTag].GetEndRootTags();
01755       
01756         if(theCloseTags){  
01757             //at a min., this code is needed for H1..H6
01758         
01759           while(theChildIndex<--theTopIndex) {
01760             eHTMLTags theNextTag=aContext[theTopIndex];
01761             if(PR_FALSE==FindTagInSet(theNextTag,theCloseTags->mTags,theCloseTags->mCount)) {
01762               if(PR_TRUE==FindTagInSet(theNextTag,theRootTags->mTags,theRootTags->mCount)) {
01763                 return eHTMLTag_unknown; //we encountered a tag in root list so fail (because we're gated).
01764               }
01765               //otherwise presume it's something we can simply ignore and continue search...
01766             }
01767             //otherwise its in the close list so skip to next tag...
01768           } 
01769           eHTMLTags theTarget=aContext.TagAt(theChildIndex);
01770           if(aCurrentTag!=theTarget) {
01771             aCurrentTag=theTarget; //use the synonym.
01772           }
01773           return aCurrentTag; //if you make it here, we're ungated and found a target!
01774         }//if
01775         else if(theRootTags) {
01776           //since we didn't find any close tags, see if there is an instance of aCurrentTag
01777           //above the stack from the roottag.
01778           if(HasCloseablePeerAboveRoot(*theRootTags,aContext,aCurrentTag,PR_TRUE))
01779             return aCurrentTag;
01780           else return eHTMLTag_unknown;
01781         }
01782       } //if blockcloser
01783       else{
01784         //Ok, a much more sensible approach for non-block closers; use the tag group to determine closure:
01785         //For example: %phrasal closes %phrasal, %fontstyle and %special
01786         return gHTMLElements[aCurrentTag].GetCloseTargetForEndTag(aContext,theChildIndex,aMode);
01787       }
01788     }//if
01789   } //if
01790   return eHTMLTag_unknown;
01791 }
01792 
01800 static void StripWSFollowingTag(eHTMLTags aChildTag,nsITokenizer* aTokenizer,nsTokenAllocator* aTokenAllocator, PRInt32& aNewlineCount){ 
01801   CToken* theToken= (aTokenizer)? aTokenizer->PeekToken():nsnull; 
01802 
01803   if(aTokenAllocator) { 
01804     while(theToken) { 
01805       eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType()); 
01806       switch(theType) { 
01807         case eToken_newline: ++aNewlineCount; 
01808         case eToken_whitespace: 
01809           theToken=aTokenizer->PopToken();
01810           IF_FREE(theToken, aTokenAllocator);
01811           theToken=aTokenizer->PeekToken(); 
01812           break; 
01813         default: 
01814           theToken=0; 
01815           break; 
01816       } 
01817     } 
01818   } 
01819 }
01820 
01834 nsresult CNavDTD::HandleEndToken(CToken* aToken) {
01835   NS_PRECONDITION(0!=aToken,kNullToken);
01836 
01837   nsresult    result=NS_OK;
01838   eHTMLTags   theChildTag=(eHTMLTags)aToken->GetTypeID();
01839 
01840   //Begin by dumping any attributes (bug 143512)
01841   PRInt16     attrCount=aToken->GetAttributeCount();
01842   CollectAttributes(nsnull,theChildTag,attrCount);
01843 
01844   switch(theChildTag) {
01845 
01846     case eHTMLTag_script:
01847       mFlags &= ~NS_DTD_FLAG_HAS_OPEN_SCRIPT;
01848     case eHTMLTag_style:
01849     case eHTMLTag_link:
01850     case eHTMLTag_meta:
01851     case eHTMLTag_title:
01852       break;
01853 
01854     case eHTMLTag_head:
01855       StripWSFollowingTag(theChildTag,mTokenizer, mTokenAllocator, mLineNumber);
01856       result = CloseContainer(eHTMLTag_head, theChildTag, PR_FALSE);
01857       break;
01858 
01859     case eHTMLTag_form:
01860       result = CloseContainer(eHTMLTag_form, theChildTag, PR_FALSE);
01861       break;
01862 
01863     case eHTMLTag_br:
01864       {
01865           //This is special NAV-QUIRKS code that allows users
01866           //to use </BR>, even though that isn't a legitimate tag.
01867         if(eDTDMode_quirks==mDTDMode) {
01868           // Use recycler and pass the token thro' HandleToken() to fix bugs like 32782.
01869           CHTMLToken* theToken = NS_STATIC_CAST(CHTMLToken*,mTokenAllocator->CreateTokenOfType(eToken_start,theChildTag));
01870           result=HandleToken(theToken,mParser);
01871         }
01872       }
01873       break;
01874 
01875     case eHTMLTag_body:
01876     case eHTMLTag_html:
01877       StripWSFollowingTag(theChildTag,mTokenizer,mTokenAllocator,mLineNumber);
01878       break;
01879 
01880     default:
01881      {
01882         //now check to see if this token should be omitted, or 
01883         //if it's gated from closing by the presence of another tag.
01884         if(gHTMLElements[theChildTag].CanOmitEndTag()) {
01885           PopStyle(theChildTag);
01886         }
01887         else {
01888           eHTMLTags theParentTag=mBodyContext->Last();
01889 
01890           if(kNotFound==nsHTMLElement::GetIndexOfChildOrSynonym(*mBodyContext,theChildTag)) {
01891 
01892             // Ref: bug 30487
01893             // Make sure that we don't cross boundaries, of certain elements,
01894             // to close stylistic information.
01895             // Ex. <font face="helvetica"><table><tr><td></font></td></tr></table> some text...
01896             // In the above ex. the orphaned FONT tag, inside TD, should cross TD boundaryto 
01897             // close the FONT tag above TABLE. 
01898             static eHTMLTags gBarriers[]={eHTMLTag_thead,eHTMLTag_tbody,eHTMLTag_tfoot,eHTMLTag_table};
01899 
01900             if(!FindTagInSet(theParentTag,gBarriers,sizeof(gBarriers)/sizeof(theParentTag))) {
01901               if(nsHTMLElement::IsResidualStyleTag(theChildTag)) {
01902                 mBodyContext->RemoveStyle(theChildTag); // fix bug 77746
01903               }
01904             }
01905 
01906             // If the bit kHandleStrayTag is set then we automatically open up a matching
01907             // start tag ( compatibility ).  Currently this bit is set on P tag.
01908             // This also fixes Bug: 22623
01909             if(gHTMLElements[theChildTag].HasSpecialProperty(kHandleStrayTag) &&
01910                mDTDMode != eDTDMode_full_standards &&
01911                mDTDMode != eDTDMode_almost_standards) {
01912               // Oh boy!! we found a "stray" tag. Nav4.x and IE introduce line break in
01913               // such cases. So, let's simulate that effect for compatibility.
01914               // Ex. <html><body>Hello</P>There</body></html>
01915               PRBool theParentContains=-1; //set to -1 to force canomit to recompute.
01916               if(!CanOmit(theParentTag,theChildTag,theParentContains)) {
01917                 CHTMLToken* theStartToken = NS_STATIC_CAST(CHTMLToken*,mTokenAllocator->CreateTokenOfType(eToken_start,theChildTag));
01918 
01919                 // This check for NS_DTD_FLAG_IN_MISPLACED_CONTENT was added
01920                 // to fix bug 142965.
01921                 if (!(mFlags & NS_DTD_FLAG_IN_MISPLACED_CONTENT)) {
01922                   // We're not handling misplaced content right now, just push
01923                   // these new tokens back on the stack and handle them in the
01924                   // regular flow of HandleToken.
01925                   IF_HOLD(aToken);
01926                   mTokenizer->PushTokenFront(aToken); //put this end token back...
01927                   mTokenizer->PushTokenFront(theStartToken); //put the new token onto the stack...
01928                 }
01929                 else {
01930                   // Oops, we're in misplaced content. Handle these tokens 
01931                   // directly instead of trying to push them onto the tokenizer
01932                   // stack.
01933                   result = HandleToken(theStartToken, mParser);
01934                   NS_ENSURE_SUCCESS(result, result);
01935 
01936                   result = HandleToken(aToken, mParser);
01937                 }
01938               }
01939             }
01940             return result;
01941           }
01942           if(result==NS_OK) {
01943             eHTMLTags theTarget=FindAutoCloseTargetForEndTag(theChildTag,*mBodyContext,mDTDMode);
01944             if(eHTMLTag_unknown!=theTarget) {
01945               if (nsHTMLElement::IsResidualStyleTag(theChildTag)) {
01946                 result=OpenTransientStyles(theChildTag); 
01947                 if(NS_FAILED(result)) {
01948                   return result;
01949                 }
01950               }
01951               result=CloseContainersTo(theTarget,PR_FALSE);
01952             }
01953           }
01954         }
01955       }
01956       break;
01957   }
01958 
01959   return result;
01960 }
01961 
01972 nsresult CNavDTD::HandleSavedTokens(PRInt32 anIndex) {
01973     NS_PRECONDITION(mBodyContext != nsnull && mBodyContext->GetCount() > 0,"invalid context");
01974 
01975     nsresult  result      = NS_OK;
01976 
01977     if(anIndex>kNotFound) {
01978       PRInt32  theBadTokenCount   = mMisplacedContent.GetSize();
01979 
01980       if(theBadTokenCount > 0) {
01981         mFlags |= NS_DTD_FLAG_IN_MISPLACED_CONTENT;
01982 
01983         if(mTempContext==nsnull) mTempContext=new nsDTDContext();
01984 
01985         CToken*   theToken;
01986         eHTMLTags theTag;
01987         PRInt32   attrCount;
01988         PRInt32   theTopIndex = anIndex + 1;
01989         PRInt32   theTagCount = mBodyContext->GetCount();
01990                
01991         if (mSink && mSink->IsFormOnStack()) {
01992           // Do this to synchronize dtd stack and the sink stack.
01993           // Note: FORM is never on the dtd stack because its always 
01994           // considered as a leaf. However, in the sink FORM can either
01995           // be a container or a leaf. Therefore, we have to check
01996           // with the sink -- Ref: Bug 20087.
01997           ++anIndex;
01998         }
01999 
02000         STOP_TIMER()
02001         MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));     
02002         // Pause the main context and switch to the new context.
02003         mSink->BeginContext(anIndex);
02004         MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));
02005         START_TIMER()
02006       
02007         // The body context should contain contents only upto the marked position.  
02008         mBodyContext->MoveEntries(*mTempContext, theTagCount - theTopIndex);
02009      
02010         // Now flush out all the bad contents.
02011         while(theBadTokenCount-- > 0){
02012           theToken=(CToken*)mMisplacedContent.PopFront();
02013           if(theToken) {
02014             theTag       = (eHTMLTags)theToken->GetTypeID();
02015             attrCount    = (gHTMLElements[theTag].mSkipTarget)? 0:theToken->GetAttributeCount();
02016             // Put back attributes, which once got popped out, into the
02017             // tokenizer.  Make sure we preserve their ordering, however!
02018             // XXXbz would it be faster to get the tokens out with ObjectAt and
02019             // put them in the tokenizer and then PopFront them all from
02020             // mMisplacedContent?
02021             nsDeque temp(nsnull);
02022             // Put back attributes, which once got popped out, into the tokenizer
02023             for(PRInt32 j=0;j<attrCount; ++j){
02024               CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront();
02025               if(theAttrToken) {
02026                 temp.Push(theAttrToken);
02027               }
02028               theBadTokenCount--;
02029             }
02030             mTokenizer->PrependTokens(temp);
02031             
02032             if(eToken_end==theToken->GetTokenType()) {
02033               // Ref: Bug 25202
02034               // Make sure that the BeginContext() is ended only by the call to
02035               // EndContext(). Ex: <center><table><a></center>.
02036               // In the Ex. above </center> should not close <center> above table.
02037               // Doing so will cause the current context to get closed prematurely. 
02038               eHTMLTags closed = FindAutoCloseTargetForEndTag(theTag, *mBodyContext,
02039                                                               mDTDMode);
02040               PRInt32 theIndex = closed != eHTMLTag_unknown
02041                                  ? mBodyContext->LastOf(closed)
02042                                  : kNotFound;
02043               
02044               if(theIndex!=kNotFound && theIndex<=mBodyContext->mContextTopIndex) {
02045                 IF_FREE(theToken, mTokenAllocator);
02046                 continue;
02047               }
02048             }
02049             result=HandleToken(theToken,mParser);
02050           }
02051         }//while
02052         if(theTopIndex != mBodyContext->GetCount()) {
02053            CloseContainersTo(theTopIndex,mBodyContext->TagAt(theTopIndex),PR_TRUE);
02054         }
02055      
02056         // Bad-contents were successfully processed. Now, itz time to get
02057         // back to the original body context state.
02058         mTempContext->MoveEntries(*mBodyContext, theTagCount - theTopIndex);
02059 
02060         STOP_TIMER()
02061         MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));     
02062         // Terminate the new context and switch back to the main context
02063         mSink->EndContext(anIndex);
02064         MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));
02065         START_TIMER()
02066 
02067         mFlags &= ~NS_DTD_FLAG_IN_MISPLACED_CONTENT;
02068       }
02069     }
02070     return result;
02071 }
02072 
02073 
02082 nsresult CNavDTD::HandleEntityToken(CToken* aToken) {
02083   NS_PRECONDITION(0!=aToken,kNullToken);
02084 
02085   nsresult  result=NS_OK;
02086 
02087   const nsSubstring& theStr = aToken->GetStringValue();
02088 
02089   if((kHashsign!=theStr.First()) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){
02090     //if you're here we have a bogus entity.
02091     //convert it into a text token.
02092     CToken *theToken=0;
02093 
02094     nsAutoString entityName;
02095     entityName.AssignLiteral("&");
02096     entityName.Append(theStr); //should append the entity name; fix bug 51161.
02097     theToken = mTokenAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text,entityName);
02098 
02099     return HandleToken(theToken,mParser); //theToken should get recycled automagically...
02100   }
02101 
02102   eHTMLTags theParentTag=mBodyContext->Last();
02103 
02104   nsCParserNode* theNode=mNodeAllocator.CreateNode(aToken, mTokenAllocator);
02105   if(theNode) {
02106     PRBool theParentContains=-1; //set to -1 to force CanOmit to recompute...
02107     if(CanOmit(theParentTag,eHTMLTag_entity,theParentContains)) {
02108       eHTMLTags theCurrTag=(eHTMLTags)aToken->GetTypeID();
02109       result=HandleOmittedTag(aToken,theCurrTag,theParentTag,theNode);
02110     }
02111     else {
02112       result=AddLeaf(theNode);
02113     }
02114     IF_FREE(theNode, &mNodeAllocator);
02115   }  
02116   return result;
02117 }
02118 
02129 nsresult CNavDTD::HandleCommentToken(CToken* aToken) {
02130   NS_PRECONDITION(0!=aToken,kNullToken);
02131   
02132   nsresult  result=NS_OK;
02133 
02134   nsCParserNode* theNode=mNodeAllocator.CreateNode(aToken, mTokenAllocator);
02135 
02136   if(theNode) {
02137 
02138     STOP_TIMER();
02139     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleCommentToken(), this=%p\n", this));
02140 
02141     result=(mSink) ? mSink->AddComment(*theNode) : NS_OK;  
02142 
02143     IF_FREE(theNode, &mNodeAllocator);
02144 
02145     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleCommentToken(), this=%p\n", this));
02146     START_TIMER();
02147   }
02148 
02149   return result;
02150 }
02151 
02152 
02163 nsresult CNavDTD::HandleAttributeToken(CToken* aToken) {
02164   NS_PRECONDITION(0!=aToken,kNullToken);
02165   NS_ERROR("attribute encountered -- this shouldn't happen unless the attribute was not part of a start tag!");
02166 
02167   return NS_OK;
02168 }
02169 
02178 nsresult CNavDTD::HandleScriptToken(const nsIParserNode *aNode) {
02179   // PRInt32 attrCount=aNode.GetAttributeCount(PR_TRUE);
02180 
02181   STOP_TIMER();
02182   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleScriptToken(), this=%p\n", this));
02183 
02184   nsresult result=AddLeaf(aNode);
02185 
02186   mParser->SetCanInterrupt(PR_FALSE);
02187 
02188   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleScriptToken(), this=%p\n", this));
02189   START_TIMER();
02190 
02191   return result;
02192 }
02193 
02194 
02203 nsresult CNavDTD::HandleProcessingInstructionToken(CToken* aToken){
02204   NS_PRECONDITION(0!=aToken,kNullToken);
02205 
02206   nsresult  result=NS_OK;
02207 
02208   nsCParserNode* theNode=mNodeAllocator.CreateNode(aToken, mTokenAllocator);
02209   if(theNode) {
02210 
02211     STOP_TIMER();
02212     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleProcessingInstructionToken(), this=%p\n", this));
02213 
02214     result=(mSink) ? mSink->AddProcessingInstruction(*theNode) : NS_OK; 
02215 
02216     IF_FREE(theNode, &mNodeAllocator);
02217 
02218     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleProcessingInstructionToken(), this=%p\n", this));
02219     START_TIMER();
02220 
02221   }
02222   return result;
02223 }
02224 
02233 nsresult CNavDTD::HandleDocTypeDeclToken(CToken* aToken){
02234   NS_PRECONDITION(0!=aToken,kNullToken);
02235 
02236   nsresult result=NS_OK;
02237 
02238   CDoctypeDeclToken* theToken = NS_STATIC_CAST(CDoctypeDeclToken*,aToken);
02239   nsAutoString docTypeStr(theToken->GetStringValue());
02240   mLineNumber += docTypeStr.CountChar(kNewLine);
02241   
02242   PRInt32 len=docTypeStr.Length();
02243   PRInt32 pos=docTypeStr.RFindChar(kGreaterThan);
02244   if(pos>-1) {
02245     docTypeStr.Cut(pos,len-pos);// First remove '>' from the end.
02246   }
02247   docTypeStr.Cut(0,2); // Now remove "<!" from the begining
02248   theToken->SetStringValue(docTypeStr);
02249 
02250   nsCParserNode* theNode=mNodeAllocator.CreateNode(aToken, mTokenAllocator);
02251   if(theNode) {
02252 
02253   STOP_TIMER();
02254   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleDocTypeDeclToken(), this=%p\n", this));
02255   
02256   result = (mSink)? mSink->AddDocTypeDecl(*theNode):NS_OK;
02257     
02258   IF_FREE(theNode, &mNodeAllocator);
02259   
02260   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleDocTypeDeclToken(), this=%p\n", this));
02261   START_TIMER();
02262 
02263   }
02264   return result;
02265 }
02266 
02276 nsresult CNavDTD::CollectAttributes(nsIParserNode *aNode, eHTMLTags aTag,
02277                                     PRInt32 aCount)
02278 {
02279   int attr=0;
02280 
02281   nsresult result=NS_OK;
02282   int theAvailTokenCount=mTokenizer->GetCount() + mSkippedContent.GetSize();
02283   if(aCount<=theAvailTokenCount) {
02284     CToken* theToken=0;
02285     eHTMLTags theSkipTarget=gHTMLElements[aTag].mSkipTarget;
02286     for(attr=0;attr<aCount;++attr){
02287       if((eHTMLTag_unknown!=theSkipTarget) && mSkippedContent.GetSize())
02288         theToken=NS_STATIC_CAST(CToken*,mSkippedContent.PopFront());
02289       else 
02290         theToken=mTokenizer->PopToken();
02291       if(theToken)  {
02292         eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType());
02293         if(theType!=eToken_attribute) {
02294           // If you're here then it means that the token does not
02295           // belong to this node. Put the token back into the tokenizer
02296           // and let it go thro' the regular path. Bug: 59189.
02297           mTokenizer->PushTokenFront(theToken);
02298           break;
02299         }
02300 
02301         mLineNumber += theToken->GetNewlineCount();
02302 
02303         if(aNode) {
02304           // If the key is empty, the attribute is unusable, so we should not
02305           // add it to the node.
02306           if (!((CAttributeToken*)theToken)->GetKey().IsEmpty()) {
02307             aNode->AddAttribute(theToken);
02308           } else {
02309             IF_FREE(theToken, mTokenAllocator);
02310           }
02311         } else {
02312           IF_FREE(theToken, mTokenAllocator);
02313         }
02314       }
02315     }
02316   }
02317   else {
02318     result=kEOF;
02319   }
02320   return result;
02321 }
02322 
02323 
02333 NS_IMETHODIMP
02334 CNavDTD::CollectSkippedContent(PRInt32 aTag, nsAString& aContent, PRInt32 &aLineNo) {
02335 
02336   NS_ASSERTION(aTag >= eHTMLTag_unknown && aTag <= NS_HTML_TAG_MAX, "tag array out of bounds");
02337 
02338   aContent.Truncate();
02339 
02340   NS_ASSERTION(eHTMLTag_unknown != gHTMLElements[aTag].mSkipTarget, "cannot collect content for this tag");
02341   if (eHTMLTag_unknown == gHTMLElements[aTag].mSkipTarget) {
02342     // This tag doesn't support skipped content.
02343     aLineNo = -1;
02344     return NS_OK;
02345   }
02346   
02347   aLineNo = mLineNumber;
02348   mScratch.Truncate();
02349   PRInt32 i = 0;
02350   PRInt32 tagCount = mSkippedContent.GetSize();
02351   for (i = 0; i< tagCount; ++i){
02352     CHTMLToken* theNextToken = (CHTMLToken*)mSkippedContent.PopFront();
02353     if (theNextToken) {
02354       theNextToken->AppendSourceTo(aContent);
02355     }
02356 
02357     IF_FREE(theNextToken, mTokenAllocator);
02358   }
02359   
02360   InPlaceConvertLineEndings(aContent);
02361 
02362   // Note: TITLE content is PCDATA and hence the newlines are already accounted for.
02363   mLineNumber += (aTag != eHTMLTag_title) ? aContent.CountChar(kNewLine) : 0;
02364   
02365   return NS_OK;
02366 }
02367 
02368  /***********************************************************************************
02369    The preceeding tables determine the set of elements each tag can contain...
02370   ***********************************************************************************/
02371      
02381 PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const 
02382 {
02383   PRBool result=gHTMLElements[aParent].CanContain((eHTMLTags)aChild,mDTDMode);
02384 
02385 #ifdef ALLOW_TR_AS_CHILD_OF_TABLE
02386   if(!result) {
02387       //XXX This vile hack is here to support bug 30378, which allows
02388       //table to contain tr directly in an html32 document.
02389     if((eHTMLTag_tr==aChild) && (eHTMLTag_table==aParent)) {
02390       result=PR_TRUE;
02391     }
02392   }
02393 #endif
02394 
02395   if(eHTMLTag_nobr==aChild) {
02396     if(IsInlineElement(aParent,aParent)){
02397       if(HasOpenContainer((eHTMLTags)aChild)) {
02398         return PR_FALSE;
02399       }
02400     }
02401   }
02402 
02403   return result;
02404 } 
02405 
02415 PRBool CNavDTD::IsBlockElement(PRInt32 aTagID,PRInt32 aParentID) const {
02416   PRBool result=PR_FALSE;
02417   eHTMLTags theTag=(eHTMLTags)aTagID;
02418 
02419   if((theTag>eHTMLTag_unknown) && (theTag<eHTMLTag_userdefined)) {
02420     result=((gHTMLElements[theTag].IsMemberOf(kBlock))       || 
02421             (gHTMLElements[theTag].IsMemberOf(kBlockEntity)) || 
02422             (gHTMLElements[theTag].IsMemberOf(kHeading))     || 
02423             (gHTMLElements[theTag].IsMemberOf(kPreformatted))|| 
02424             (gHTMLElements[theTag].IsMemberOf(kList))); 
02425   }
02426 
02427   return result;
02428 }
02429 
02439 PRBool CNavDTD::IsInlineElement(PRInt32 aTagID,PRInt32 aParentID) const {
02440   PRBool result=PR_FALSE;
02441   eHTMLTags theTag=(eHTMLTags)aTagID;
02442 
02443   if((theTag>eHTMLTag_unknown) && (theTag<eHTMLTag_userdefined)) {
02444     result=((gHTMLElements[theTag].IsMemberOf(kInlineEntity))|| 
02445             (gHTMLElements[theTag].IsMemberOf(kFontStyle))   || 
02446             (gHTMLElements[theTag].IsMemberOf(kPhrase))      || 
02447             (gHTMLElements[theTag].IsMemberOf(kSpecial))     || 
02448             (gHTMLElements[theTag].IsMemberOf(kFormControl)));
02449   }
02450 
02451   return result;
02452 }
02453 
02464 PRBool CNavDTD::CanPropagate(eHTMLTags aParent,eHTMLTags aChild,PRBool aParentContains)  {
02465   PRBool    result=PR_FALSE;
02466   PRBool    theParentContains=(-1==aParentContains) ? CanContain(aParent,aChild) : aParentContains;
02467 
02468   if(aParent==aChild) {
02469     return result;
02470   }
02471 
02472   if(nsHTMLElement::IsContainer(aChild)){
02473     mScratch.Truncate();
02474     if(!gHTMLElements[aChild].HasSpecialProperty(kNoPropagate)){
02475       if(nsHTMLElement::IsBlockParent(aParent) || (gHTMLElements[aParent].GetSpecialChildren())) {
02476 
02477         result=ForwardPropagate(mScratch,aParent,aChild);
02478 
02479         if(PR_FALSE==result){
02480 
02481           if(eHTMLTag_unknown!=aParent) {
02482             if(aParent!=aChild) //dont even bother if we're already inside a similar element...
02483               result=BackwardPropagate(mScratch,aParent,aChild);
02484           } //if
02485           else result=BackwardPropagate(mScratch,eHTMLTag_html,aChild);
02486 
02487         } //elseif
02488 
02489       }//if
02490     }//if
02491     if(mScratch.Length()-1>gHTMLElements[aParent].mPropagateRange)
02492       result=PR_FALSE;
02493   }//if
02494   else result=theParentContains;
02495 
02496 
02497   return result;
02498 }
02499 
02500 
02511 PRBool CNavDTD::CanOmit(eHTMLTags aParent,eHTMLTags aChild,PRBool& aParentContains)  {
02512 
02513   eHTMLTags theAncestor=gHTMLElements[aChild].mExcludingAncestor;
02514   if (eHTMLTag_unknown!=theAncestor){
02515     if (HasOpenContainer(theAncestor)) {
02516       return PR_TRUE;
02517     }
02518   }
02519 
02520   theAncestor=gHTMLElements[aChild].mRequiredAncestor;
02521   if(eHTMLTag_unknown!=theAncestor){
02522     if(!HasOpenContainer(theAncestor)) {
02523       if(!CanPropagate(aParent,aChild,aParentContains)) {
02524         return PR_TRUE;
02525       }
02526     }
02527     return PR_FALSE;
02528   }
02529 
02530 
02531   if(gHTMLElements[aParent].CanExclude(aChild)){
02532     return PR_TRUE;
02533   }
02534 
02535     //Now the obvious test: if the parent can contain the child, don't omit.
02536   if(-1==aParentContains)
02537     aParentContains=CanContain(aParent,aChild);
02538 
02539   if(aParentContains || (aChild==aParent)){
02540     return PR_FALSE;
02541   }
02542 
02543   if(gHTMLElements[aParent].IsBlockEntity()) {
02544     if(nsHTMLElement::IsInlineEntity(aChild)) {  //feel free to drop inlines that a block doesn't contain.
02545       return PR_TRUE;
02546     }
02547   }
02548 
02549   if(gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch)) {
02550 
02551     if(-1==aParentContains) {    
02552       //we need to compute parent containment here, since it wasn't given...
02553       if(!gHTMLElements[aParent].CanContain(aChild,mDTDMode)){
02554         return PR_TRUE;
02555       }
02556     }
02557     else if (!aParentContains) {
02558       if(!gHTMLElements[aChild].HasSpecialProperty(kBadContentWatch)) {
02559         return PR_TRUE; 
02560       }
02561       return PR_FALSE; // Ref. Bug 25658
02562     }
02563   }
02564 
02565   if(gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced)) {
02566     return PR_TRUE;
02567   }
02568 
02569   return PR_FALSE;
02570 }
02571      
02572 
02581 PRBool CNavDTD::IsContainer(PRInt32 aTag) const {
02582   return nsHTMLElement::IsContainer((eHTMLTags)aTag);
02583 }
02584 
02585 
02598 PRBool CNavDTD::ForwardPropagate(nsString& aSequence,eHTMLTags aParent,eHTMLTags aChild)  {
02599   PRBool result=PR_FALSE;
02600 
02601   switch(aParent) {
02602     case eHTMLTag_table:
02603       {
02604         if((eHTMLTag_tr==aChild) || (eHTMLTag_td==aChild)) {
02605           return BackwardPropagate(aSequence,aParent,aChild);
02606         }
02607       }
02608       //otherwise, intentionally fall through...
02609 
02610     case eHTMLTag_tr:
02611       {  
02612         PRBool theCanContainResult=CanContain(eHTMLTag_td,aChild);
02613         if(PR_TRUE==theCanContainResult) {
02614           aSequence.Append((PRUnichar)eHTMLTag_td);
02615           result=BackwardPropagate(aSequence,aParent,eHTMLTag_td);
02616         }
02617       }
02618       break;
02619 
02620     case eHTMLTag_th:
02621       break;
02622 
02623     default:
02624       break;
02625   }//switch
02626   return result;
02627 }
02628 
02629 
02641 PRBool CNavDTD::BackwardPropagate(nsString& aSequence,eHTMLTags aParent,eHTMLTags aChild) const {
02642 
02643   eHTMLTags theParent=aParent; //just init to get past first condition...
02644 
02645   do {
02646     const TagList* theRootTags=gHTMLElements[aChild].GetRootTags();
02647     if(theRootTags) {
02648       theParent=theRootTags->mTags[0];
02649       if(CanContain(theParent,aChild)) {
02650         //we've found a complete sequence, so push the parent...
02651         aChild=theParent;
02652         aSequence.Append((PRUnichar)theParent);
02653       }
02654     }
02655     else break;
02656   } 
02657   while((theParent!=eHTMLTag_unknown) && (theParent!=aParent));
02658 
02659   return PRBool(aParent==theParent);
02660 }
02661 
02662 
02671 PRBool CNavDTD::HasOpenContainer(eHTMLTags aContainer) const {
02672   PRBool result=PR_FALSE;
02673 
02674   switch(aContainer) {
02675     case eHTMLTag_form:
02676       result= !(~mFlags & NS_DTD_FLAG_HAS_OPEN_FORM); break;
02677     case eHTMLTag_map: 
02678       result=mOpenMapCount>0; break; 
02679     default:
02680       result=mBodyContext->HasOpenContainer(aContainer);
02681       break;
02682   }
02683   return result;
02684 }
02685 
02694 PRBool CNavDTD::HasOpenContainer(const eHTMLTags aTagSet[],PRInt32 aCount) const {
02695 
02696   int theIndex; 
02697   int theTopIndex=mBodyContext->GetCount()-1;
02698 
02699   for(theIndex=theTopIndex;theIndex>0;theIndex--){
02700     if(FindTagInSet((*mBodyContext)[theIndex],aTagSet,aCount))
02701       return PR_TRUE;
02702   }
02703   return PR_FALSE;
02704 }
02705 
02713 eHTMLTags CNavDTD::GetTopNode() const {
02714   return mBodyContext->Last();
02715 }
02716 
02717 /*********************************************
02718   Here comes code that handles the interface
02719   to our content sink.
02720  *********************************************/
02721  
02722 
02734 nsresult CNavDTD::OpenTransientStyles(eHTMLTags aChildTag, PRBool aCloseInvalid){
02735   nsresult result=NS_OK;
02736 
02737   // No need to open transient styles in head context - Fix for 41427
02738   if((mFlags & NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE) && 
02739      eHTMLTag_newline!=aChildTag && 
02740      !(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) {
02741 
02742 #ifdef  ENABLE_RESIDUALSTYLE
02743 
02744     if(CanContain(eHTMLTag_font,aChildTag)) {
02745 
02746       PRUint32 theCount=mBodyContext->GetCount();
02747       PRUint32 theLevel=theCount;
02748 
02749         //this first loop is used to determine how far up the containment
02750         //hierarchy we go looking for residual styles.
02751       while ( 1<theLevel) {
02752         eHTMLTags theParentTag = mBodyContext->TagAt(--theLevel);
02753         if(gHTMLElements[theParentTag].HasSpecialProperty(kNoStyleLeaksIn)) {
02754           break;
02755         }
02756       }
02757 
02758       mFlags &= ~NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
02759       for(;theLevel<theCount;++theLevel){
02760         nsEntryStack* theStack=mBodyContext->GetStylesAt(theLevel);
02761         if(theStack){
02762           // Don't open transient styles if it makes the stack deep, bug 58917.
02763           if (theCount + theStack->mCount >= FONTSTYLE_IGNORE_DEPTH) {
02764             break;
02765           }
02766 
02767           PRInt32 sindex=0;
02768 
02769           nsTagEntry *theEntry=theStack->mEntries;
02770           PRBool isHeadingOpen = HasOpenTagOfType(kHeading, *mBodyContext);
02771           for(sindex=0;sindex<theStack->mCount;++sindex){            
02772             nsCParserNode* theNode=(nsCParserNode*)theEntry->mNode;
02773             if(1==theNode->mUseCount) {
02774               eHTMLTags theNodeTag=(eHTMLTags)theNode->GetNodeType();
02775               if(gHTMLElements[theNodeTag].CanContain(aChildTag,mDTDMode)) {
02776                 theEntry->mParent = theStack;  //we do this too, because this entry differs from the new one we're pushing...
02777                 if(isHeadingOpen) {
02778                   // Bug 77352
02779                   // The style system needs to identify residual style tags
02780                   // within heading tags so that heading tags' size can take
02781                   // precedence over the residual style tags' size info.. 
02782                   // *Note: Make sure that this attribute is transient since it
02783                   // should not get carried over to cases other than heading.
02784                   CAttributeToken theAttrToken(NS_LITERAL_STRING("_moz-rs-heading"), EmptyString());
02785                   theNode->AddAttribute(&theAttrToken);
02786                   result = OpenContainer(theNode,theNodeTag,PR_FALSE,theStack);
02787                   theNode->PopAttributeToken();
02788                 }
02789                 else { 
02790                   result = OpenContainer(theNode,theNodeTag,PR_FALSE,theStack);
02791                 }
02792               }
02793               else if (aCloseInvalid) {
02794                 //if the node tag can't contain the child tag, then remove the child tag from the style stack
02795                 nsCParserNode* node=theStack->Remove(sindex,theNodeTag);
02796                 IF_FREE(node, &mNodeAllocator);
02797                 --theEntry; //back up by one
02798               }
02799             } //if
02800             ++theEntry;
02801           } //for
02802         } //if
02803       } //for
02804       mFlags |= NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
02805 
02806     } //if
02807 
02808 #endif
02809   }//if
02810   return result;
02811 }
02812 
02825 nsresult CNavDTD::CloseTransientStyles(eHTMLTags aChildTag){
02826   return NS_OK;
02827 }
02828 
02837 nsresult CNavDTD::PopStyle(eHTMLTags aTag){
02838   nsresult result=0;
02839 
02840   if(mFlags & NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE) {
02841 #ifdef  ENABLE_RESIDUALSTYLE
02842     if(nsHTMLElement::IsResidualStyleTag(aTag)) {
02843       nsCParserNode* node=mBodyContext->PopStyle(aTag);
02844       IF_FREE(node, &mNodeAllocator);  
02845     }
02846 #endif
02847   } //if
02848   return result;
02849 }
02850 
02851 
02860 nsresult CNavDTD::OpenHTML(const nsCParserNode *aNode){
02861   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
02862 
02863   STOP_TIMER();
02864   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenHTML(), this=%p\n", this));
02865 
02866   nsresult result = (mSink) ? mSink->OpenHTML(*aNode) : NS_OK; 
02867 
02868   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenHTML(), this=%p\n", this));
02869   START_TIMER();
02870 
02871   // Don't push more than one HTML tag into the stack...
02872   if (mBodyContext->GetCount() == 0) 
02873     mBodyContext->Push(NS_CONST_CAST(nsCParserNode*, aNode), 0, PR_FALSE); 
02874 
02875   return result;
02876 }
02877 
02887 nsresult CNavDTD::CloseHTML(){
02888 
02889   STOP_TIMER();
02890   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseHTML(), this=%p\n", this));
02891 
02892   nsresult result = (mSink) ? mSink->CloseHTML() : NS_OK; 
02893 
02894   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseHTML(), this=%p\n", this));
02895   START_TIMER();
02896 
02897   return result;
02898 }
02899 
02900 
02909 nsresult CNavDTD::OpenHead(const nsIParserNode *aNode)
02910 {
02911   nsresult result = NS_OK;
02912 
02913   STOP_TIMER();
02914   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenHead(), this=%p\n", this));
02915 
02916   if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) {
02917     mFlags |= NS_DTD_FLAG_HAS_OPEN_HEAD;
02918     result = mSink ? mSink->OpenHead(*aNode) : NS_OK;
02919   }
02920 
02921   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenHead(), this=%p\n", this));
02922   START_TIMER();
02923 
02924   return result;
02925 }
02926 
02935 nsresult CNavDTD::CloseHead()
02936 {
02937   nsresult result = NS_OK;
02938 
02939   if (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) {
02940     mFlags &= ~NS_DTD_FLAG_HAS_OPEN_HEAD;
02941 
02942     STOP_TIMER();
02943     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseHead(), this=%p\n", this));
02944 
02945     result = mSink ? mSink->CloseHead() : NS_OK;
02946 
02947     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseHead(), this=%p\n", this));
02948     START_TIMER();
02949   }
02950 
02951   return result;
02952 }
02953 
02962 nsresult CNavDTD::OpenBody(const nsCParserNode *aNode)
02963 {
02964   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
02965 
02966   nsresult result = NS_OK;
02967   
02968   if (!(mFlags & NS_DTD_FLAG_HAD_FRAMESET)) {
02969 
02970     mFlags |= NS_DTD_FLAG_HAD_BODY;
02971 
02972     STOP_TIMER();
02973     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenBody(), this=%p\n", this));
02974 
02975     result = (mSink) ? mSink->OpenBody(*aNode) : NS_OK; 
02976 
02977     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenBody(), this=%p\n", this));
02978     START_TIMER();
02979 
02980     if (!HasOpenContainer(eHTMLTag_body)) {
02981       mBodyContext->Push(NS_CONST_CAST(nsCParserNode*, aNode), 0, PR_FALSE);
02982       mTokenizer->PrependTokens(mMisplacedContent);
02983     }
02984   }
02985 
02986   return result;
02987 }
02988 
02997 nsresult CNavDTD::CloseBody()
02998 {
02999   STOP_TIMER();
03000   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseBody(), this=%p\n", this));
03001 
03002   nsresult result= (mSink) ? mSink->CloseBody() : NS_OK; 
03003 
03004   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseBody(), this=%p\n", this));
03005   START_TIMER();
03006 
03007   return result;
03008 }
03009 
03018 nsresult CNavDTD::OpenForm(const nsIParserNode *aNode)
03019 {
03020   nsresult result = NS_OK;
03021   if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_FORM)) { // discard nested forms - bug 72639
03022     STOP_TIMER();
03023     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenForm(), this=%p\n", this));
03024 
03025     result = (mSink) ? mSink->OpenForm(*aNode) : NS_OK; 
03026 
03027     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenForm(), this=%p\n", this));
03028     START_TIMER();
03029     if (NS_OK == result) {
03030       mFlags |= NS_DTD_FLAG_HAS_OPEN_FORM;
03031     }
03032   }
03033 
03034   return result;
03035 }
03036 
03045 nsresult CNavDTD::CloseForm()
03046 {
03047   nsresult result = NS_OK;
03048   if (mFlags & NS_DTD_FLAG_HAS_OPEN_FORM) {
03049     mFlags &= ~NS_DTD_FLAG_HAS_OPEN_FORM;
03050     STOP_TIMER();
03051     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseForm(), this=%p\n", this));
03052 
03053     result = (mSink) ? mSink->CloseForm() : NS_OK; 
03054 
03055     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseForm(), this=%p\n", this));
03056     START_TIMER();
03057   }
03058   return result;
03059 }
03060 
03069 nsresult CNavDTD::OpenMap(const nsCParserNode *aNode)
03070 {
03071   STOP_TIMER();
03072   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenMap(), this=%p\n", this));
03073 
03074   nsresult result = (mSink) ? mSink->OpenMap(*aNode) : NS_OK; 
03075 
03076   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenMap(), this=%p\n", this));
03077   START_TIMER();
03078 
03079   if (NS_OK == result) {
03080     mBodyContext->Push(NS_CONST_CAST(nsCParserNode*, aNode), 0, PR_FALSE);
03081     ++mOpenMapCount;
03082   }
03083   return result;
03084 }
03085 
03094 nsresult CNavDTD::CloseMap()
03095 {
03096   nsresult result = NS_OK;
03097   if (mOpenMapCount) {
03098     mOpenMapCount--;
03099     STOP_TIMER();
03100     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseMap(), this=%p\n", this));
03101 
03102     result = (mSink) ? mSink->CloseMap() : NS_OK; 
03103 
03104     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseMap(), this=%p\n", this));
03105     START_TIMER();
03106   }
03107   return result;
03108 }
03109 
03118 nsresult CNavDTD::OpenFrameset(const nsCParserNode *aNode)
03119 {
03120   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
03121 
03122   mFlags |= NS_DTD_FLAG_HAD_FRAMESET;
03123   STOP_TIMER();
03124   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenFrameset(), this=%p\n", this));
03125 
03126   nsresult result =( mSink) ? mSink->OpenFrameset(*aNode) : NS_OK; 
03127 
03128   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenFrameset(), this=%p\n", this));
03129   START_TIMER();
03130   mBodyContext->Push(NS_CONST_CAST(nsCParserNode*, aNode), 0, PR_FALSE);
03131 
03132   return result;
03133 }
03134 
03143 nsresult CNavDTD::CloseFrameset()
03144 {
03145   STOP_TIMER();
03146   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseFrameset(), this=%p\n", this));
03147 
03148   nsresult result = (mSink) ? mSink->CloseFrameset() : NS_OK; 
03149 
03150   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseFrameset(), this=%p\n", this));
03151   START_TIMER();
03152 
03153   return result;
03154 }
03155 
03165 nsresult
03166 CNavDTD::OpenContainer(const nsCParserNode *aNode,
03167                        eHTMLTags aTag,
03168                        PRBool aClosedByStartTag,
03169                        nsEntryStack* aStyleStack)
03170 {
03171   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
03172   
03173   nsresult   result = NS_OK; 
03174   PRBool     done   = PR_TRUE;
03175   PRBool     rs_tag = nsHTMLElement::IsResidualStyleTag(aTag);
03176   // We need to open transient styles to encompass the <li> so that the bullets
03177   // inherit the proper colors.
03178   PRBool     li_tag = aTag == eHTMLTag_li;
03179 
03180   if (rs_tag || li_tag) {
03181     /***********************************************************************
03182      *  Here's an interesting problem:
03183      *
03184      *  If there's an <a> on the RS-stack, and you're trying to open 
03185      *  another <a>, the one on the RS-stack should be discarded.
03186      *
03187      *  I'm updating OpenTransientStyles to throw old <a>'s away.
03188      *
03189      ***********************************************************************/
03190 
03191     OpenTransientStyles(aTag, !li_tag); 
03192   }
03193 
03194   switch (aTag) {
03195     case eHTMLTag_html:
03196       result=OpenHTML(aNode); break;
03197 
03198     case eHTMLTag_head:
03199       result=OpenHead(aNode); 
03200       break;
03201 
03202     case eHTMLTag_body:
03203       {
03204         eHTMLTags theParent=mBodyContext->Last();
03205         if (!gHTMLElements[aTag].IsSpecialParent(theParent)) {
03206           mFlags |= NS_DTD_FLAG_HAS_OPEN_BODY;
03207           result = OpenBody(aNode); 
03208         }
03209         else {
03210           done = PR_FALSE;
03211         }
03212       }
03213       break;
03214 
03215     case eHTMLTag_style:
03216     case eHTMLTag_title:
03217       break;
03218 
03219     case eHTMLTag_map:
03220       result = OpenMap(aNode);
03221       break;
03222 
03223     case eHTMLTag_form:
03224       result = OpenForm(aNode); 
03225       break;
03226 
03227     case eHTMLTag_frameset:
03228       result = OpenFrameset(aNode); 
03229       break;
03230 
03231     case eHTMLTag_script:
03232       result = HandleScriptToken(aNode);
03233       break;
03234     
03235     case eHTMLTag_noembed:
03236       // <noembed> is unconditionally alternate content.
03237       done = PR_FALSE;
03238       mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT;
03239       break;
03240 
03241     case eHTMLTag_noscript:
03242       // we want to make sure that OpenContainer gets called below since we're
03243       // not doing it here
03244       done=PR_FALSE;
03245       // If the script is disabled noscript should not be
03246       // in the content model until the layout can somehow
03247       // turn noscript's display property to block <-- bug 67899
03248       if(mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED) {
03249         mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT;
03250       }
03251       break;
03252        
03253     case eHTMLTag_iframe: // Bug 84491 
03254     case eHTMLTag_noframes:
03255       done=PR_FALSE;
03256       if(mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED) {
03257         mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT;
03258       }
03259       break;
03260 
03261     default:
03262       done=PR_FALSE;
03263       break;
03264   }
03265 
03266   if (!done) {
03267     STOP_TIMER();
03268     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenContainer(), this=%p\n", this));
03269 
03270     result=(mSink) ? mSink->OpenContainer(*aNode) : NS_OK; 
03271 
03272     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::OpenContainer(), this=%p\n", this));
03273     START_TIMER();
03274     // For residual style tags rs_tag will be true and hence
03275     // the body context will hold an extra reference to the node.
03276     mBodyContext->Push(NS_CONST_CAST(nsCParserNode*, aNode), aStyleStack, rs_tag); 
03277   }
03278 
03279   return result;
03280 }
03281 
03292 nsresult
03293 CNavDTD::CloseContainer(const eHTMLTags aTag, eHTMLTags aTarget,PRBool aClosedByStartTag)
03294 {
03295   nsresult   result = NS_OK;
03296 
03297   switch (aTag) {
03298 
03299     case eHTMLTag_html:
03300       result=CloseHTML(); break;
03301 
03302     case eHTMLTag_style:
03303       break;
03304 
03305     case eHTMLTag_head:
03306       result=CloseHead(); 
03307       break;
03308 
03309     case eHTMLTag_body:
03310       result=CloseBody(); 
03311       break;
03312 
03313     case eHTMLTag_map:
03314       result=CloseMap();
03315       break;
03316 
03317     case eHTMLTag_form:
03318       result=CloseForm(); 
03319       break;
03320 
03321     case eHTMLTag_frameset:
03322       result=CloseFrameset(); 
03323       break;
03324     
03325     case eHTMLTag_iframe:
03326     case eHTMLTag_noembed:
03327     case eHTMLTag_noscript:
03328     case eHTMLTag_noframes:
03329       // switch from alternate content state to regular state
03330       mFlags &= ~NS_DTD_FLAG_ALTERNATE_CONTENT;
03331       // falling thro' intentionally....
03332     case eHTMLTag_title:
03333     default:
03334       STOP_TIMER();
03335       MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::CloseContainer(), this=%p\n", this));
03336 
03337       result=(mSink) ? mSink->CloseContainer(aTag) : NS_OK; 
03338 
03339       MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseContainer(), this=%p\n", this));
03340       START_TIMER();
03341       break;
03342   }
03343 
03344   return result;
03345 }
03346 
03357 nsresult CNavDTD::CloseContainersTo(PRInt32 anIndex,eHTMLTags aTarget, PRBool aClosedByStartTag)
03358 {
03359   NS_PRECONDITION(mBodyContext->GetCount() > 0, kInvalidTagStackPos);
03360   nsresult result = NS_OK;
03361   
03362   if ((anIndex<mBodyContext->GetCount()) && (anIndex>=0)) {
03363 
03364     PRInt32 count = 0;
03365     while ((count = mBodyContext->GetCount()) > anIndex) {
03366       nsEntryStack* theChildStyleStack = 0;      
03367       eHTMLTags theTag = mBodyContext->Last();
03368       nsCParserNode* theNode = mBodyContext->Pop(theChildStyleStack);
03369       result = CloseContainer(theTag, aTarget,aClosedByStartTag);  
03370 
03371 #ifdef  ENABLE_RESIDUALSTYLE
03372 
03373         PRBool theTagIsStyle=nsHTMLElement::IsResidualStyleTag(theTag);
03374         // If the current tag cannot leak out then we shouldn't leak out of the target - Fix 40713
03375         PRBool theStyleDoesntLeakOut = gHTMLElements[theTag].HasSpecialProperty(kNoStyleLeaksOut);
03376         if(!theStyleDoesntLeakOut) {
03377           theStyleDoesntLeakOut = gHTMLElements[aTarget].HasSpecialProperty(kNoStyleLeaksOut);
03378         }
03379       
03380         /*************************************************************
03381           Do not invoke residual style handling when dealing with
03382           alternate content. This fixes bug 25214.
03383          *************************************************************/
03384 
03385         if(theTagIsStyle && !(mFlags & NS_DTD_FLAG_ALTERNATE_CONTENT)) {
03386           NS_ASSERTION(theNode, "residual style node should not be null");
03387           if (!theNode) {
03388             if (theChildStyleStack)
03389               mBodyContext->PushStyles(theChildStyleStack);
03390             return NS_OK;
03391           }
03392           PRBool theTargetTagIsStyle = nsHTMLElement::IsResidualStyleTag(aTarget);
03393           if(aClosedByStartTag) { 
03394 
03395             /***********************************************************
03396               Handle closure due to new start tag.          
03397 
03398               The cases we're handing here:
03399                 1. <body><b><DIV>       //<b> gets pushed onto <body>.mStyles.
03400                 2. <body><a>text<a>     //in this case, the target matches, so don't push style
03401              ***************************************************************************/
03402 
03403             if (theNode->mUseCount == 0){
03404               if (theTag != aTarget) {
03405                   //don't push if thechild==theTarget
03406                 if (theChildStyleStack)
03407                   theChildStyleStack->PushFront(theNode);
03408                 else 
03409                   mBodyContext->PushStyle(theNode);
03410               }
03411             } 
03412             else if (theTag == aTarget && !gHTMLElements[aTarget].CanContainSelf()) {
03413               //here's a case we missed:  <a><div>text<a>text</a></div>
03414               //The <div> pushes the 1st <a> onto the rs-stack, then the 2nd <a>
03415               //pops the 1st <a> from the rs-stack altogether.
03416               nsCParserNode* node = mBodyContext->PopStyle(theTag);
03417               IF_FREE(node, &mNodeAllocator);
03418             }
03419 
03420             if (theChildStyleStack) {
03421               mBodyContext->PushStyles(theChildStyleStack);
03422             }
03423           }
03424           else { //Handle closure due to another close tag.      
03425 
03426             /***********************************************************             
03427               if you're here, then we're dealing with the closure of tags
03428               caused by a close tag (as opposed to an open tag).
03429               At a minimum, we should consider pushing residual styles up 
03430               up the stack or popping and recycling displaced nodes.
03431 
03432               Known cases: 
03433                 1. <body><b><div>text</DIV> 
03434                       Here the <b> will leak into <div> (see case given above), and 
03435                       when <div> closes the <b> is dropped since it's already residual.
03436 
03437                 2. <body><div><b>text</div>
03438                       Here the <b> will leak out of the <div> and get pushed onto
03439                       the RS stack for the <body>, since it originated in the <div>.
03440 
03441                 3. <body><span><b>text</span>
03442                       In this case, the the <b> get's pushed onto the style stack.
03443                       Later we deal with RS styles stored on the <span>
03444 
03445                 4. <body><span><b>text</i>
03446                       Here we the <b>is closed by a (synonymous) style tag. 
03447                       In this case, the <b> is simply closed.
03448              ***************************************************************************/
03449 
03450             if (theChildStyleStack) {
03451               if (!theStyleDoesntLeakOut) {
03452                 if (theTag != aTarget) {
03453                   if (theNode->mUseCount == 0) {
03454                     theChildStyleStack->PushFront(theNode);
03455                   }
03456                 }
03457                 else if (theNode->mUseCount == 1) {
03458                   // This fixes bug 30885,29626.
03459                   // Make sure that the node, which is about to
03460                   // get released does not stay on the style stack...
03461                   // Also be sure to remove the correct style off the
03462                   // style stack. -  Ref. bug 94208.
03463                   // Ex <FONT><B><I></FONT><FONT></B></I></FONT>
03464                   // Make sure that </B> removes B off the style stack.
03465                   mBodyContext->RemoveStyle(theTag);
03466                 }
03467                 mBodyContext->PushStyles(theChildStyleStack);
03468               }
03469               else{
03470                 IF_DELETE(theChildStyleStack,&mNodeAllocator);
03471               }
03472             }
03473             else if (theNode->mUseCount == 0) {
03474 
03475               //The old version of this only pushed if the targettag wasn't style.
03476               //But that misses this case: <font><b>text</font>, where the b should leak
03477               if (aTarget != theTag) {
03478                 mBodyContext->PushStyle(theNode);
03479               }
03480             } 
03481             else {
03482               //Ah, at last, the final case. If you're here, then we just popped a 
03483               //style tag that got onto that tag stack from a stylestack somewhere.
03484               //Pop it from the stylestack if the target is also a style tag.
03485               //Make sure to remove the matching style. In the following example
03486               //<FONT><B><I></FONT><FONT color=red></B></I></FONT> make sure that 
03487               //</I> does not remove <FONT color=red> off the style stack. - bug 94208
03488               if (theTargetTagIsStyle && theTag == aTarget) {
03489                 mBodyContext->RemoveStyle(theTag);
03490               }
03491             }
03492           }
03493         } //if
03494         else { 
03495           //the tag is not a style tag...
03496           if (theChildStyleStack) {
03497             if (theStyleDoesntLeakOut)
03498               IF_DELETE(theChildStyleStack,&mNodeAllocator);
03499             else 
03500               mBodyContext->PushStyles(theChildStyleStack);
03501           }
03502         }
03503 #endif
03504         IF_FREE(theNode, &mNodeAllocator);
03505     }
03506 
03507   } //if
03508   return result;
03509 }
03510 
03520 nsresult CNavDTD::CloseContainersTo(eHTMLTags aTag,PRBool aClosedByStartTag){
03521   NS_PRECONDITION(mBodyContext->GetCount() > 0, kInvalidTagStackPos);
03522 
03523   PRInt32 pos=mBodyContext->LastOf(aTag);
03524 
03525   if(kNotFound!=pos) {
03526     //the tag is indeed open, so close it.
03527     return CloseContainersTo(pos,aTag,aClosedByStartTag);
03528   }
03529 
03530   eHTMLTags theTopTag=mBodyContext->Last();
03531 
03532   PRBool theTagIsSynonymous=((nsHTMLElement::IsResidualStyleTag(aTag)) && (nsHTMLElement::IsResidualStyleTag(theTopTag)));
03533   if(!theTagIsSynonymous){
03534     theTagIsSynonymous=(gHTMLElements[aTag].IsMemberOf(kHeading) && 
03535                         gHTMLElements[theTopTag].IsMemberOf(kHeading));  
03536   }
03537 
03538   if(theTagIsSynonymous) {
03539     //if you're here, it's because we're trying to close one tag,
03540     //but a different (synonymous) one is actually open. Because this is NAV4x
03541     //compatibililty mode, we must close the one that's really open.
03542     aTag=theTopTag;    
03543     pos=mBodyContext->LastOf(aTag);
03544     if(kNotFound!=pos) {
03545       //the tag is indeed open, so close it.
03546       return CloseContainersTo(pos,aTag,aClosedByStartTag);
03547     }
03548   }
03549   
03550   nsresult result=NS_OK;
03551   const TagList* theRootTags=gHTMLElements[aTag].GetRootTags();
03552   eHTMLTags theParentTag=(theRootTags) ? theRootTags->mTags[0] : eHTMLTag_unknown;
03553   pos=mBodyContext->LastOf(theParentTag);
03554   if(kNotFound!=pos) {
03555     //the parent container is open, so close it instead
03556     result=CloseContainersTo(pos+1,aTag,aClosedByStartTag);
03557   }
03558   return result;
03559 }
03560 
03569 nsresult CNavDTD::AddLeaf(const nsIParserNode *aNode){
03570   nsresult result=NS_OK;
03571   
03572   if(mSink){
03573     eHTMLTags theTag=(eHTMLTags)aNode->GetNodeType();
03574     OpenTransientStyles(theTag); 
03575 
03576     STOP_TIMER();
03577     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::AddLeaf(), this=%p\n", this));
03578     
03579     result=mSink->AddLeaf(*aNode);
03580 
03581     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::AddLeaf(), this=%p\n", this));
03582     START_TIMER();
03583 
03584   }
03585   return result;
03586 }
03587 
03596 nsresult CNavDTD::AddHeadLeaf(nsIParserNode *aNode){
03597   nsresult result=NS_OK;
03598 
03599   static eHTMLTags gNoXTags[] = {eHTMLTag_noembed,eHTMLTag_noframes};
03600 
03601   eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
03602   
03603   // XXX - SCRIPT inside NOTAGS should not get executed unless the pref.
03604   // says so.  Since we don't have this support yet..lets ignore the
03605   // SCRIPT inside NOTAGS.  Ref Bug 25880.
03606   if (eHTMLTag_meta == theTag || eHTMLTag_script == theTag) {
03607     if (HasOpenContainer(gNoXTags,sizeof(gNoXTags)/sizeof(eHTMLTag_unknown))) {
03608       return result;
03609     }
03610   }
03611   
03612   if (mSink) {
03613     STOP_TIMER();
03614     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::AddHeadLeaf(), this=%p\n", this));
03615     
03616     result = mSink->AddHeadContent(*aNode);
03617           
03618     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::AddHeadLeaf(), this=%p\n", this));
03619     START_TIMER();
03620   }
03621   return result;
03622 }
03623 
03635 nsresult CNavDTD::CreateContextStackFor(eHTMLTags aChild){
03636   
03637   mScratch.Truncate();
03638   
03639   nsresult  result=(nsresult)kContextMismatch;
03640   eHTMLTags theTop=mBodyContext->Last();
03641   PRBool    bResult=ForwardPropagate(mScratch,theTop,aChild);
03642   
03643   if(PR_FALSE==bResult){
03644 
03645     if(eHTMLTag_unknown!=theTop) {
03646       if(theTop!=aChild) //dont even bother if we're already inside a similar element...
03647         bResult=BackwardPropagate(mScratch,theTop,aChild);      
03648     } //if
03649     else bResult=BackwardPropagate(mScratch,eHTMLTag_html,aChild);
03650   } //elseif
03651 
03652   PRInt32   theLen=mScratch.Length();
03653   eHTMLTags theTag=(eHTMLTags)mScratch[--theLen];
03654 
03655   if((0==mBodyContext->GetCount()) || (mBodyContext->Last()==theTag))
03656     result=NS_OK;
03657 
03658   //now, build up the stack according to the tags 
03659   //you have that aren't in the stack...
03660   if(PR_TRUE==bResult){
03661     while(theLen) {
03662       theTag=(eHTMLTags)mScratch[--theLen];
03663 
03664 #ifdef ALLOW_TR_AS_CHILD_OF_TABLE
03665       if((eHTML3_Quirks==mDocType) && (eHTMLTag_tbody==theTag)) {
03666         //the prev. condition prevents us from emitting tbody in html3.2 docs; fix bug 30378
03667         continue;
03668       }
03669 #endif
03670       CStartToken *theToken=(CStartToken*)mTokenAllocator->CreateTokenOfType(eToken_start,theTag);
03671       HandleToken(theToken,mParser);  //these should all wind up on contextstack, so don't recycle.
03672     }
03673     result=NS_OK;
03674   }
03675   return result;
03676 }
03677 
03684 nsresult CNavDTD::WillResumeParse(nsIContentSink* aSink){
03685 
03686   STOP_TIMER();
03687   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillResumeParse(), this=%p\n", this));
03688 
03689   nsresult result=(aSink) ? aSink->WillResume() : NS_OK; 
03690 
03691   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillResumeParse(), this=%p\n", this));
03692   START_TIMER();
03693 
03694   return result;
03695 }
03696 
03703 nsresult CNavDTD::WillInterruptParse(nsIContentSink* aSink){
03704 
03705   STOP_TIMER();
03706   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillInterruptParse(), this=%p\n", this));
03707 
03708   nsresult result=(aSink) ? aSink->WillInterrupt() : NS_OK; 
03709 
03710   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillInterruptParse(), this=%p\n", this));
03711   START_TIMER();
03712 
03713   return result;
03714 }
03715