Back to index

lightning-sunbird  0.9+nobinonly
COtherDTD.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */   
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   rickg@netscape.com
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 ENABLE_CRC              
00040           
00041 #include "nsDebug.h"      
00042 #include "nsIAtom.h"
00043 #include "COtherDTD.h"
00044 #include "nsHTMLTokens.h"
00045 #include "nsCRT.h"     
00046 #include "nsParser.h"  
00047 #include "nsIParser.h"
00048 #include "nsIHTMLContentSink.h"  
00049 #include "nsScanner.h"
00050 #include "prenv.h"  //this is here for debug reasons...
00051 #include "prtypes.h"  //this is here for debug reasons...
00052 #include "prio.h"
00053 #include "plstr.h"  
00054 #include "nsDTDUtils.h"
00055 #include "nsHTMLTokenizer.h"
00056 #include "nsTime.h"
00057 #include "nsParserNode.h"
00058 #include "nsHTMLEntities.h"
00059 #include "nsLinebreakConverter.h"
00060 #include "nsUnicharUtils.h"
00061 
00062 #include "prmem.h" 
00063 
00064 static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTML_CONTENT_SINK_IID);
00065 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);                 
00066 static NS_DEFINE_IID(kIDTDIID,      NS_IDTD_IID);
00067 static NS_DEFINE_IID(kClassIID,     NS_IOTHERHTML_DTD_IID); 
00068 static const char kVerificationDir[] = "c:/temp";
00069  
00070 
00071 #ifdef  ENABLE_CRC
00072 static char gShowCRC;
00073 #endif
00074 
00075    
00076  
00077 #ifdef MOZ_PERF_METRICS 
00078 #  define START_TIMER()                    \
00079     if(mParser) MOZ_TIMER_START(mParser->mParseTime); \
00080     if(mParser) MOZ_TIMER_START(mParser->mDTDTime); 
00081 
00082 #  define STOP_TIMER()                     \
00083     if(mParser) MOZ_TIMER_STOP(mParser->mParseTime); \
00084     if(mParser) MOZ_TIMER_STOP(mParser->mDTDTime); 
00085 #else
00086 #  define STOP_TIMER() 
00087 #  define START_TIMER()
00088 #endif
00089 
00090 
00091 #include "COtherElements.h"
00092 
00093 
00094 /************************************************************************
00095   And now for the main class -- COtherDTD...
00096  ************************************************************************/
00097 
00108 nsresult COtherDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr)  
00109 {                                                                         
00110   if (NULL == aInstancePtr) {                                            
00111     return NS_ERROR_NULL_POINTER;                                        
00112   }                                                                      
00113 
00114   if(aIID.Equals(kISupportsIID))    {  //do IUnknown...
00115     *aInstancePtr = (nsIDTD*)(this);                                        
00116   }
00117   else if(aIID.Equals(kIDTDIID)) {  //do IParser base class...
00118     *aInstancePtr = (nsIDTD*)(this);                                        
00119   }
00120   else if(aIID.Equals(kClassIID)) {  //do this class...
00121     *aInstancePtr = (COtherDTD*)(this);                                        
00122   }                 
00123   else {
00124     *aInstancePtr=0;
00125     return NS_NOINTERFACE;
00126   }
00127   NS_ADDREF_THIS();
00128   return NS_OK;                                                        
00129 }
00130 
00131 NS_IMPL_ADDREF(COtherDTD)
00132 NS_IMPL_RELEASE(COtherDTD)
00133 
00141 COtherDTD::COtherDTD() : nsIDTD() {
00142   mSink = 0; 
00143   mParser=0;        
00144   mLineNumber=1;  
00145   mHasOpenBody=PR_FALSE;
00146   mHasOpenHead=0;
00147   mHasOpenForm=PR_FALSE;
00148   mHasOpenMap=PR_FALSE;
00149   mTokenizer=0;
00150   mTokenAllocator=0;
00151   mComputedCRC32=0;
00152   mExpectedCRC32=0;
00153   mDTDState=NS_OK;
00154   mDocType=eHTML_Strict;
00155   mHadFrameset=PR_FALSE;
00156   mHadBody=PR_FALSE;
00157   mHasOpenScript=PR_FALSE;
00158   mParserCommand=eViewNormal;
00159   mNodeAllocator=new nsNodeAllocator();
00160   mBodyContext=new nsDTDContext();
00161 
00162 #if 0 //set this to 1 if you want strictDTD to be based on the environment setting.
00163   char* theEnvString = PR_GetEnv("MOZ_DISABLE_STRICT"); 
00164   mEnableStrict=PRBool(0==theEnvString);
00165 #else
00166   mEnableStrict=PR_TRUE;
00167 #endif
00168 
00169   if(!gElementTable) {
00170     gElementTable = new CElementTable();
00171   }
00172 }
00173 
00180 const nsIID& COtherDTD::GetMostDerivedIID(void)const {
00181   return kClassIID;
00182 }
00183  
00191 COtherDTD::~COtherDTD(){
00192   delete mBodyContext;
00193 
00194   if(mNodeAllocator) {
00195     delete mNodeAllocator;
00196     mNodeAllocator=nsnull;
00197   }
00198 
00199   NS_IF_RELEASE(mSink);
00200 }
00201  
00210 nsresult NS_NewOtherHTMLDTD(nsIDTD** aInstancePtrResult) {
00211   COtherDTD* it = new COtherDTD();
00212 
00213   if (it == 0) {
00214     return NS_ERROR_OUT_OF_MEMORY;
00215   }
00216 
00217   return it->QueryInterface(kClassIID, (void **) aInstancePtrResult);
00218 }
00219 
00227 NS_IMETHODIMP
00228 COtherDTD::CreateNewInstance(nsIDTD** aInstancePtrResult)
00229 {
00230   nsresult result=NS_NewOtherHTMLDTD(aInstancePtrResult);
00231 
00232   if(aInstancePtrResult) {
00233     COtherDTD *theOtherDTD=(COtherDTD*)*aInstancePtrResult;
00234     if(theOtherDTD) {
00235       theOtherDTD->mDTDMode=mDTDMode;
00236       theOtherDTD->mParserCommand=mParserCommand;
00237       theOtherDTD->mDocType=mDocType;
00238       theOtherDTD->mEnableStrict=mEnableStrict;
00239     }
00240   }
00241 
00242   return result;
00243 }
00244 
00256 NS_IMETHODIMP_(eAutoDetectResult)
00257 COtherDTD::CanParse(CParserContext& aParserContext)
00258 {
00259   eAutoDetectResult result=eUnknownDetect;
00260 
00261   if(mEnableStrict) {
00262     if(aParserContext.mParserCommand != eViewSource) {
00263       if(PR_TRUE==aParserContext.mMimeType.Equals(kPlainTextContentType)) {
00264         result=eValidDetect;
00265       }
00266       else if(PR_TRUE==aParserContext.mMimeType.Equals(kHTMLTextContentType)) {
00267         switch(aParserContext.mDTDMode) {
00268           case eDTDMode_full_standards:
00269           case eDTDMode_almost_standards:
00270             result=ePrimaryDetect;
00271             break;
00272           default:
00273             result=eValidDetect;
00274             break;
00275         }
00276       }
00277     }
00278   }
00279   return result; 
00280 }
00281 
00282  
00292 nsresult COtherDTD::WillBuildModel(const CParserContext& aParserContext,
00293                                    nsITokenizer* aTokenizer,
00294                                    nsIContentSink* aSink){
00295   nsresult result=NS_OK;
00296 
00297   mFilename=aParserContext.mScanner->GetFilename();
00298   mHasOpenBody=PR_FALSE;
00299   mHadFrameset=PR_FALSE;
00300   mLineNumber=1;
00301   mHasOpenScript=PR_FALSE;
00302   mDTDMode=aParserContext.mDTDMode;
00303   mParserCommand=aParserContext.mParserCommand;
00304   mTokenizer = aTokenizer;
00305 
00306   if((!aParserContext.mPrevContext) && (aSink)) {
00307 
00308     STOP_TIMER();
00309     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillBuildModel(), this=%p\n", this));
00310 
00311     mDocType=aParserContext.mDocType;
00312     mBodyContext->mFlags.mTransitional=PR_FALSE;
00313 
00314     if(aSink && (!mSink)) {
00315       result=aSink->QueryInterface(kIHTMLContentSinkIID, (void **)&mSink);
00316     }
00317 
00318     if(result==NS_OK) {
00319       result = aSink->WillBuildModel();
00320 
00321       MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillBuildModel(), this=%p\n", this));
00322       START_TIMER();
00323 
00324       mSkipTarget=eHTMLTag_unknown;
00325       mComputedCRC32=0;
00326       mExpectedCRC32=0;
00327     }
00328   }
00329 
00330   return result;
00331 }
00332 
00333 
00343 nsresult COtherDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITokenObserver* anObserver,nsIContentSink* aSink) {
00344   nsresult result=NS_OK;
00345 
00346   if(aTokenizer) {
00347     nsITokenizer*  oldTokenizer=mTokenizer;
00348     mTokenizer=aTokenizer;
00349     mParser=(nsParser*)aParser;
00350 
00351     if(mTokenizer) {
00352 
00353       mTokenAllocator=mTokenizer->GetTokenAllocator();
00354       
00355       mBodyContext->SetTokenAllocator(mTokenAllocator);
00356       mBodyContext->SetNodeAllocator(mNodeAllocator);
00357 
00358       if(mSink) {
00359 
00360         if(!mBodyContext->GetCount()) {
00361             //if the content model is empty, then begin by opening <html>...
00362           CStartToken *theToken=(CStartToken*)mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_html,NS_LITERAL_STRING("html"));
00363           HandleStartToken(theToken); //this token should get pushed on the context stack, don't recycle it.
00364         }
00365 
00366         while(NS_SUCCEEDED(result)){
00367 
00368           if(mDTDState!=NS_ERROR_HTMLPARSER_STOPPARSING) {
00369             CToken* theToken=mTokenizer->PopToken();
00370             if(theToken) { 
00371               result=HandleToken(theToken,aParser);
00372             }
00373             else break;
00374           }
00375           else {
00376             result=mDTDState;
00377             break;
00378           }
00379         }//while
00380         mTokenizer=oldTokenizer; 
00381       }
00382     } 
00383   }
00384   else result=NS_ERROR_HTMLPARSER_BADTOKENIZER;
00385   return result;
00386 }
00387  
00394 nsresult COtherDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParser* aParser,nsIContentSink* aSink){
00395   nsresult result=NS_OK;
00396 
00397   if(aSink) {  
00398 
00399     if(aParser && (NS_OK==result)){ 
00400       if(aNotifySink){ 
00401         if((NS_OK==anErrorCode) && (mBodyContext->GetCount()>0)) {
00402 
00403           PRInt32 theIndex=mBodyContext->GetCount()-1;
00404           eHTMLTags theChild = mBodyContext->TagAt(theIndex); 
00405           while (theIndex>0) {             
00406             eHTMLTags theParent = mBodyContext->TagAt(--theIndex);
00407             CElement *theElement = gElementTable->mElements[theParent];
00408             nsCParserNode *theNode = mBodyContext->PeekNode();
00409             theElement->HandleEndToken(theNode,theChild,mBodyContext,mSink);
00410             theChild = theParent;
00411           }
00412 
00413           nsEntryStack*  theChildStyles = 0;
00414           nsCParserNode* theNode = (nsCParserNode*)mBodyContext->Pop(theChildStyles);   
00415           if (theNode) {
00416             mSink->CloseHTML();
00417           }
00418           NS_ASSERTION(!theChildStyles, "there should no residual style information in this dtd");
00419           IF_DELETE(theChildStyles, mNodeAllocator);
00420         }       
00421         else {
00422           //If you're here, then an error occured, but we still have nodes on the stack.
00423           //At a minimum, we should grab the nodes and recycle them.
00424           //Just to be correct, we'll also recycle the nodes. 
00425   
00426           while (mBodyContext->GetCount() > 0) {  
00427  
00428             nsEntryStack *theChildStyles = 0;
00429             nsCParserNode* theNode = (nsCParserNode*)mBodyContext->Pop(theChildStyles);
00430             if (theNode) {
00431               theNode->mUseCount = 0;
00432               if (theChildStyles) {
00433                 delete theChildStyles;
00434               } 
00435               IF_FREE(theNode, mNodeAllocator);
00436             }
00437             NS_ASSERTION(!theChildStyles, "there should no residual style information in this dtd");
00438             IF_DELETE(theChildStyles, mNodeAllocator);
00439           }    
00440         }    
00441   
00442       } 
00443     } //if aparser  
00444 
00445       //No matter what, you need to call did build model.
00446     result = aSink->DidBuildModel(); 
00447 
00448   } //if asink
00449   return result; 
00450 }  
00451 
00452 NS_IMETHODIMP_(void)  
00453 COtherDTD::Terminate() 
00454 { 
00455   mDTDState = NS_ERROR_HTMLPARSER_STOPPARSING; 
00456 }
00457 
00458 NS_IMETHODIMP_(PRInt32)  
00459 COtherDTD::GetType() 
00460 { 
00461   return NS_IPARSER_FLAG_HTML; 
00462 }
00463 
00464 NS_IMETHODIMP 
00465 COtherDTD::CollectSkippedContent(PRInt32 aTag, nsAString& aContent, PRInt32 &aLineNo)
00466 {
00467   return NS_OK;
00468 }
00469 
00480 nsresult COtherDTD::HandleToken(CToken* aToken,nsIParser* aParser){
00481   nsresult  result=NS_OK;
00482 
00483   if(aToken) {
00484     CHTMLToken*     theToken= (CHTMLToken*)(aToken);
00485     eHTMLTokenTypes theType=eHTMLTokenTypes(theToken->GetTokenType());
00486 
00487 //    theToken->mUseCount=0;  //assume every token coming into this system needs recycling.
00488 
00489     mParser=(nsParser*)aParser;
00490 
00491     switch(theType) {
00492       case eToken_text:
00493       case eToken_start:
00494       case eToken_whitespace: 
00495       case eToken_newline:
00496       case eToken_doctypeDecl:
00497       case eToken_markupDecl:
00498         result=HandleStartToken(theToken); break;
00499 
00500       case eToken_entity:
00501         result=HandleEntityToken(theToken); break;
00502 
00503       case eToken_end:
00504         result=HandleEndToken(theToken); break;
00505        
00506       default: 
00507         break; 
00508     }//switch
00509 
00510 
00511     if(NS_SUCCEEDED(result) || (NS_ERROR_HTMLPARSER_BLOCK==result)) {
00512       IF_FREE(theToken, mTokenAllocator);
00513     }
00514     else if(result==NS_ERROR_HTMLPARSER_STOPPARSING)
00515       mDTDState=result; 
00516     else return NS_OK;
00517 
00518   }//if
00519   return result;
00520 }
00521 
00522   
00530 nsresult COtherDTD::DidHandleStartTag(nsIParserNode& aNode,eHTMLTags aChildTag){
00531   nsresult result=NS_OK;
00532 
00533   switch(aChildTag){ 
00534 
00535     case eHTMLTag_script: 
00536       mHasOpenScript=PR_TRUE; 
00537       break;   
00538 
00539     case eHTMLTag_pre:
00540     case eHTMLTag_listing:
00541       {
00542         CToken* theNextToken=mTokenizer->PeekToken();
00543         if(theNextToken)  {
00544           eHTMLTokenTypes theType=eHTMLTokenTypes(theNextToken->GetTokenType());
00545           if(eToken_newline==theType){
00546             ++mLineNumber;
00547             mTokenizer->PopToken();  //skip 1st newline inside PRE and LISTING
00548           }//if
00549         }//if
00550       }
00551       break;
00552 
00553     default:
00554       break;
00555   }//switch 
00556 
00557   return result;
00558 } 
00559  
00568 nsresult COtherDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsIParserNode& aNode){
00569   nsresult result=NS_OK; 
00570 
00571     //first let's see if there's some skipped content to deal with... 
00572 #if 0
00573   PRInt32 theAttrCount  = aNode.GetAttributeCount(); 
00574   if(*gElementTable->mElements[aTag].mSkipTarget) { 
00575     result=CollectSkippedContent(aNode,theAttrCount); 
00576   } 
00577 #endif
00578   
00579   STOP_TIMER()
00580   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this));
00581 
00582   if(mParser) {
00583 
00584     switch(aTag) {
00585       case eHTMLTag_newline:
00586         ++mLineNumber;
00587         break;
00588       default:
00589         break; 
00590     }
00591     mSink->NotifyTagObservers(&aNode);
00592   }
00593 
00594   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this));
00595   START_TIMER()
00596 
00597   return result; 
00598 }
00599   
00600 
00615 nsresult COtherDTD::HandleStartToken(CToken* aToken) {  
00616 
00617   //Begin by gathering up attributes...  
00618  
00619   nsresult  result=NS_OK;
00620   nsCParserNode* theNode=mNodeAllocator->CreateNode(aToken, mTokenAllocator);
00621   if(theNode) {
00622    
00623     eHTMLTags     theChildTag=(eHTMLTags)aToken->GetTypeID();
00624     PRInt16       attrCount=aToken->GetAttributeCount();
00625     eHTMLTags     theParent=mBodyContext->Last();
00626     
00627     result=(0==attrCount) ? NS_OK : CollectAttributes(*theNode,theChildTag,attrCount);
00628  
00629     if(NS_OK==result) {
00630       result=WillHandleStartTag(aToken,theChildTag,*theNode);
00631       if(NS_OK==result) {
00632  
00633         mLineNumber += aToken->GetNewlineCount();
00634  
00635         PRBool theTagWasHandled=PR_FALSE; 
00636  
00637         switch(theChildTag) {        
00638             
00639           case eHTMLTag_html:  
00640             if(!mBodyContext->HasOpenContainer(theChildTag)){
00641               mSink->OpenHTML(*theNode);
00642               mBodyContext->Push(theNode, 0, PR_FALSE);
00643             } 
00644             theTagWasHandled=PR_TRUE;   
00645             break;         
00646                  
00647           default:    
00648             CElement* theElement=gElementTable->mElements[theParent];
00649             if(theElement) {
00650               result=theElement->HandleStartToken(theNode,theChildTag,mBodyContext,mSink);  
00651               theTagWasHandled=PR_TRUE;  
00652             }    
00653             break;   
00654         }//switch              
00655          
00656         if(theTagWasHandled) {
00657           DidHandleStartTag(*theNode,theChildTag);  
00658         }
00659    
00660       } //if             
00661     }//if           
00662     IF_FREE(theNode, mNodeAllocator);
00663   }
00664   else result=NS_ERROR_OUT_OF_MEMORY;
00665           
00666   return result;        
00667 }      
00668   
00682 nsresult COtherDTD::HandleEndToken(CToken* aToken) { 
00683   nsresult    result=NS_OK;
00684   eHTMLTags   theChildTag=(eHTMLTags)aToken->GetTypeID();
00685  
00686   switch(theChildTag) {    
00687  
00688     case eHTMLTag_body: //we intentionally don't let the user close HTML or BODY
00689     case eHTMLTag_html:   
00690       break;    
00691         
00692     case eHTMLTag_script:       
00693       mHasOpenScript=PR_FALSE;         
00694       
00695     default: 
00696       PRInt32 theCount=mBodyContext->GetCount();
00697       eHTMLTags theParent=mBodyContext->TagAt(theCount-1);
00698       if(theChildTag==theParent) {
00699         theParent=mBodyContext->TagAt(theCount-2);
00700       }
00701       CElement* theElement=gElementTable->mElements[theParent];
00702       if(theElement) { 
00703         nsCParserNode* theNode=mNodeAllocator->CreateNode(aToken, mTokenAllocator);
00704         if(theNode) {
00705           result=theElement->HandleEndToken(theNode,theChildTag,mBodyContext,mSink);
00706           IF_FREE(theNode, mNodeAllocator);
00707         }
00708       }   
00709       break; 
00710   }     
00711    
00712   return result;            
00713 }          
00714           
00724 nsresult COtherDTD::CollectAttributes(nsIParserNode& aNode,eHTMLTags aTag,PRInt32 aCount){
00725   int attr=0;
00726 
00727   nsresult result=NS_OK;
00728   int theAvailTokenCount=mTokenizer->GetCount();
00729   if(aCount<=theAvailTokenCount) {
00730     //gElementTable->mElements[aTag]->GetSkipTarget();
00731     CToken* theToken=0; 
00732     for(attr=0;attr<aCount;++attr){  
00733       theToken=mTokenizer->PopToken(); 
00734       if(theToken)  {
00735         aNode.AddAttribute(theToken); 
00736       }
00737     }
00738   }
00739   else { 
00740     result=kEOF; 
00741   }
00742   return result; 
00743 } 
00744 
00753 nsresult COtherDTD::HandleEntityToken(CToken* aToken) {
00754   nsresult  result=NS_OK;
00755 
00756   nsAutoString theStr;
00757   aToken->GetSource(theStr);
00758   PRUnichar theChar=theStr.CharAt(0);
00759   CToken    *theToken=0;
00760 
00761   if((kHashsign!=theChar) && (-1==nsHTMLEntities::EntityToUnicode(theStr))){
00762     //if you're here we have a bogus entity.
00763     //convert it into a text token.
00764     nsAutoString entityName;
00765     entityName.AssignLiteral("&");
00766     entityName.Append(theStr); //should append the entity name; fix bug 51161.
00767     theToken=(CTextToken*)mTokenAllocator->CreateTokenOfType(eToken_text,eHTMLTag_text,entityName);
00768     result=HandleStartToken(theToken);
00769   }
00770   else {
00771 
00772     //add this code to fix bug 42629 (entities were getting dropped).
00773     eHTMLTags theParent=mBodyContext->Last();
00774     CElement* theElement=gElementTable->mElements[theParent];
00775     if(theElement) {
00776       nsCParserNode theNode(aToken, 0);
00777       result=theElement->HandleStartToken(&theNode,eHTMLTag_text,mBodyContext,mSink);  
00778     }
00779   }
00780   return result;
00781 } 
00782             
00783  /***********************************************************************************
00784    The preceeding tables determine the set of elements each tag can contain...
00785   ***********************************************************************************/
00786      
00796 PRBool COtherDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const {
00797   CElement *theParent=gElementTable->mElements[eHTMLTags(aParent)];
00798   if(theParent) {
00799     CElement *theChild=gElementTable->mElements[eHTMLTags(aChild)];
00800     if(aChild) {
00801       if(eHTMLTag_userdefined == aChild)//bug #67007, dont strip userdefined tags
00802         return PR_TRUE;                 
00803       else
00804         return theParent->CanContain(theChild,mBodyContext);
00805     }
00806   }
00807   return PR_FALSE;
00808 } 
00809 
00818 PRBool COtherDTD::IsContainer(PRInt32 aTag) const {
00819   return gElementTable->mElements[eHTMLTags(aTag)]->IsContainer();
00820 }
00821  
00828 nsresult COtherDTD::WillResumeParse(nsIContentSink* aSink) {
00829 
00830   STOP_TIMER();
00831   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillResumeParse(), this=%p\n", this));
00832 
00833   nsresult result=(aSink) ? aSink->WillResume() : NS_OK; 
00834 
00835   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillResumeParse(), this=%p\n", this));
00836   START_TIMER();
00837 
00838   return result;
00839 }
00840 
00847 nsresult COtherDTD::WillInterruptParse(nsIContentSink* aSink){ 
00848 
00849   STOP_TIMER();
00850   MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: COtherDTD::WillInterruptParse(), this=%p\n", this));
00851 
00852   nsresult result=(aSink) ? aSink->WillInterrupt() : NS_OK; 
00853 
00854   MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillInterruptParse(), this=%p\n", this));
00855   START_TIMER();
00856 
00857   return result;
00858 }
00859 
00860 // CTransitionalDTD is a subclass of COtherDTD that defaults to transitional mode.  
00861 // Used by the editor
00862 
00863 CTransitionalDTD::CTransitionalDTD()
00864 {
00865   if (mBodyContext) mBodyContext->mFlags.mTransitional = PR_TRUE;
00866 }
00867 
00868 CTransitionalDTD::~CTransitionalDTD() {}
00869